diff --git a/README.md b/README.md
index 0cd99b792..6f1ccfcaf 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-
+
diff --git a/config/custom-ue.yaml b/config/custom-ue.yaml
index 2600b37ae..4545e6a24 100644
--- a/config/custom-ue.yaml
+++ b/config/custom-ue.yaml
@@ -29,7 +29,6 @@ sessions:
slice:
sst: 1
sd: 1
- emergency: false
# Configured NSSAI for this UE by HPLMN
configured-nssai:
diff --git a/config/free5gc-ue.yaml b/config/free5gc-ue.yaml
index 9f2e7c8f1..28b0baa9c 100644
--- a/config/free5gc-ue.yaml
+++ b/config/free5gc-ue.yaml
@@ -29,7 +29,6 @@ sessions:
slice:
sst: 0x01
sd: 0x010203
- emergency: false
# Configured NSSAI for this UE by HPLMN
configured-nssai:
diff --git a/config/open5gs-ue.yaml b/config/open5gs-ue.yaml
index d6779ed65..49f60824b 100644
--- a/config/open5gs-ue.yaml
+++ b/config/open5gs-ue.yaml
@@ -28,8 +28,6 @@ sessions:
apn: 'internet'
slice:
sst: 1
- sd: 1
- emergency: false
# Configured NSSAI for this UE by HPLMN
configured-nssai:
diff --git a/src/gnb/app/cmd_handler.cpp b/src/gnb/app/cmd_handler.cpp
index a3b94ccde..5d40d4c69 100644
--- a/src/gnb/app/cmd_handler.cpp
+++ b/src/gnb/app/cmd_handler.cpp
@@ -66,7 +66,7 @@ bool GnbCmdHandler::isAllPaused()
return true;
}
-void GnbCmdHandler::handleCmd(NwGnbCliCommand &msg)
+void GnbCmdHandler::handleCmd(NmGnbCliCommand &msg)
{
pauseTasks();
@@ -97,7 +97,7 @@ void GnbCmdHandler::handleCmd(NwGnbCliCommand &msg)
unpauseTasks();
}
-void GnbCmdHandler::handleCmdImpl(NwGnbCliCommand &msg)
+void GnbCmdHandler::handleCmdImpl(NmGnbCliCommand &msg)
{
switch (msg.cmd->present)
{
diff --git a/src/gnb/app/cmd_handler.hpp b/src/gnb/app/cmd_handler.hpp
index 4341dbff7..354583d31 100644
--- a/src/gnb/app/cmd_handler.hpp
+++ b/src/gnb/app/cmd_handler.hpp
@@ -24,7 +24,7 @@ class GnbCmdHandler
{
}
- void handleCmd(NwGnbCliCommand &msg);
+ void handleCmd(NmGnbCliCommand &msg);
private:
void pauseTasks();
@@ -32,7 +32,7 @@ class GnbCmdHandler
bool isAllPaused();
private:
- void handleCmdImpl(NwGnbCliCommand &msg);
+ void handleCmdImpl(NmGnbCliCommand &msg);
private:
void sendResult(const InetAddress &address, const std::string &output);
diff --git a/src/gnb/app/task.cpp b/src/gnb/app/task.cpp
index 5ba5bc46f..aa6b39d07 100644
--- a/src/gnb/app/task.cpp
+++ b/src/gnb/app/task.cpp
@@ -32,17 +32,17 @@ void GnbAppTask::onLoop()
switch (msg->msgType)
{
case NtsMessageType::GNB_STATUS_UPDATE: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->what)
{
- case NwGnbStatusUpdate::NGAP_IS_UP:
+ case NmGnbStatusUpdate::NGAP_IS_UP:
m_statusInfo.isNgapUp = w->isNgapUp;
break;
}
break;
}
case NtsMessageType::GNB_CLI_COMMAND: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
GnbCmdHandler handler{m_base};
handler.handleCmd(*w);
break;
diff --git a/src/gnb/gnb.cpp b/src/gnb/gnb.cpp
index 2a0561763..284982312 100644
--- a/src/gnb/gnb.cpp
+++ b/src/gnb/gnb.cpp
@@ -70,7 +70,7 @@ void GNodeB::start()
void GNodeB::pushCommand(std::unique_ptr cmd, const InetAddress &address)
{
- taskBase->appTask->push(new NwGnbCliCommand(std::move(cmd), address));
+ taskBase->appTask->push(new NmGnbCliCommand(std::move(cmd), address));
}
} // namespace nr::gnb
diff --git a/src/gnb/gtp/task.cpp b/src/gnb/gtp/task.cpp
index d4cb91d12..6622fd961 100644
--- a/src/gnb/gtp/task.cpp
+++ b/src/gnb/gtp/task.cpp
@@ -55,22 +55,22 @@ void GtpTask::onLoop()
switch (msg->msgType)
{
case NtsMessageType::GNB_NGAP_TO_GTP: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbNgapToGtp::UE_CONTEXT_UPDATE: {
+ case NmGnbNgapToGtp::UE_CONTEXT_UPDATE: {
handleUeContextUpdate(*w->update);
break;
}
- case NwGnbNgapToGtp::UE_CONTEXT_RELEASE: {
+ case NmGnbNgapToGtp::UE_CONTEXT_RELEASE: {
handleUeContextDelete(w->ueId);
break;
}
- case NwGnbNgapToGtp::SESSION_CREATE: {
+ case NmGnbNgapToGtp::SESSION_CREATE: {
handleSessionCreate(w->resource);
break;
}
- case NwGnbNgapToGtp::SESSION_RELEASE: {
+ case NmGnbNgapToGtp::SESSION_RELEASE: {
handleSessionRelease(w->ueId, w->psi);
break;
}
@@ -78,10 +78,10 @@ void GtpTask::onLoop()
break;
}
case NtsMessageType::GNB_RLS_TO_GTP: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbRlsToGtp::DATA_PDU_DELIVERY: {
+ case NmGnbRlsToGtp::DATA_PDU_DELIVERY: {
handleUplinkData(w->ueId, w->psi, std::move(w->pdu));
break;
}
@@ -240,7 +240,7 @@ void GtpTask::handleUdpReceive(const udp::NwUdpServerReceive &msg)
if (m_rateLimiter->allowDownlinkPacket(sessionInd, gtp->payload.length()))
{
- auto *w = new NwGnbGtpToRls(NwGnbGtpToRls::DATA_PDU_DELIVERY);
+ auto *w = new NmGnbGtpToRls(NmGnbGtpToRls::DATA_PDU_DELIVERY);
w->ueId = GetUeId(sessionInd);
w->psi = GetPsi(sessionInd);
w->pdu = std::move(gtp->payload);
diff --git a/src/gnb/ngap/context.cpp b/src/gnb/ngap/context.cpp
index 330985c8e..32ea91bd8 100644
--- a/src/gnb/ngap/context.cpp
+++ b/src/gnb/ngap/context.cpp
@@ -53,7 +53,7 @@ void NgapTask::receiveInitialContextSetup(int amfId, ASN_NGAP_InitialContextSetu
if (ie)
deliverDownlinkNas(ue->ctxId, asn::GetOctetString(ie->NAS_PDU));
- auto *w = new NwGnbNgapToGtp(NwGnbNgapToGtp::UE_CONTEXT_UPDATE);
+ auto *w = new NmGnbNgapToGtp(NmGnbNgapToGtp::UE_CONTEXT_UPDATE);
w->update = std::make_unique(true, ue->ctxId, ue->ueAmbr);
m_base->gtpTask->push(w);
}
@@ -67,12 +67,12 @@ void NgapTask::receiveContextRelease(int amfId, ASN_NGAP_UEContextReleaseCommand
return;
// Notify RRC task
- auto *w1 = new NwGnbNgapToRrc(NwGnbNgapToRrc::AN_RELEASE);
+ auto *w1 = new NmGnbNgapToRrc(NmGnbNgapToRrc::AN_RELEASE);
w1->ueId = ue->ctxId;
m_base->rrcTask->push(w1);
// Notify GTP task
- auto *w2 = new NwGnbNgapToGtp(NwGnbNgapToGtp::UE_CONTEXT_RELEASE);
+ auto *w2 = new NmGnbNgapToGtp(NmGnbNgapToGtp::UE_CONTEXT_RELEASE);
w2->ueId = ue->ctxId;
m_base->gtpTask->push(w2);
@@ -108,7 +108,7 @@ void NgapTask::receiveContextModification(int amfId, ASN_NGAP_UEContextModificat
auto *response = asn::ngap::NewMessagePdu({});
sendNgapUeAssociated(ue->ctxId, response);
- auto *w = new NwGnbNgapToGtp(NwGnbNgapToGtp::UE_CONTEXT_UPDATE);
+ auto *w = new NmGnbNgapToGtp(NmGnbNgapToGtp::UE_CONTEXT_UPDATE);
w->update = std::make_unique(false, ue->ctxId, ue->ueAmbr);
m_base->gtpTask->push(w);
}
diff --git a/src/gnb/ngap/interface.cpp b/src/gnb/ngap/interface.cpp
index 87af38579..d6126486a 100644
--- a/src/gnb/ngap/interface.cpp
+++ b/src/gnb/ngap/interface.cpp
@@ -99,7 +99,7 @@ void NgapTask::handleAssociationShutdown(int amfId)
amf->state = EAmfState::NOT_CONNECTED;
- auto *w = new NwGnbSctp(NwGnbSctp::CONNECTION_CLOSE);
+ auto *w = new NmGnbSctp(NmGnbSctp::CONNECTION_CLOSE);
w->clientId = amfId;
m_base->sctpTask->push(w);
@@ -192,11 +192,11 @@ void NgapTask::receiveNgSetupResponse(int amfId, ASN_NGAP_NGSetupResponse *msg)
{
m_isInitialized = true;
- auto *update = new NwGnbStatusUpdate(NwGnbStatusUpdate::NGAP_IS_UP);
+ auto *update = new NmGnbStatusUpdate(NmGnbStatusUpdate::NGAP_IS_UP);
update->isNgapUp = true;
m_base->appTask->push(update);
- m_base->rrcTask->push(new NwGnbNgapToRrc(NwGnbNgapToRrc::RADIO_POWER_ON));
+ m_base->rrcTask->push(new NmGnbNgapToRrc(NmGnbNgapToRrc::RADIO_POWER_ON));
}
}
diff --git a/src/gnb/ngap/nas.cpp b/src/gnb/ngap/nas.cpp
index 9bbacec3a..307d09649 100644
--- a/src/gnb/ngap/nas.cpp
+++ b/src/gnb/ngap/nas.cpp
@@ -78,7 +78,7 @@ void NgapTask::handleInitialNasTransport(int ueId, const OctetString &nasPdu, lo
void NgapTask::deliverDownlinkNas(int ueId, OctetString &&nasPdu)
{
- auto *w = new NwGnbNgapToRrc(NwGnbNgapToRrc::NAS_DELIVERY);
+ auto *w = new NmGnbNgapToRrc(NmGnbNgapToRrc::NAS_DELIVERY);
w->ueId = ueId;
w->pdu = std::move(nasPdu);
m_base->rrcTask->push(w);
diff --git a/src/gnb/ngap/radio.cpp b/src/gnb/ngap/radio.cpp
index 52fecfd3c..01fa5bc9d 100644
--- a/src/gnb/ngap/radio.cpp
+++ b/src/gnb/ngap/radio.cpp
@@ -22,7 +22,7 @@ namespace nr::gnb
void NgapTask::handleRadioLinkFailure(int ueId)
{
// Notify GTP task
- auto *w2 = new NwGnbNgapToGtp(NwGnbNgapToGtp::UE_CONTEXT_RELEASE);
+ auto *w2 = new NmGnbNgapToGtp(NmGnbNgapToGtp::UE_CONTEXT_RELEASE);
w2->ueId = ueId;
m_base->gtpTask->push(w2);
@@ -48,7 +48,7 @@ void NgapTask::receivePaging(int amfId, ASN_NGAP_Paging *msg)
return;
}
- auto *w = new NwGnbNgapToRrc(NwGnbNgapToRrc::PAGING);
+ auto *w = new NmGnbNgapToRrc(NmGnbNgapToRrc::PAGING);
w->uePagingTmsi =
asn::UniqueCopy(*ieUePagingIdentity->UEPagingIdentity.choice.fiveG_S_TMSI, asn_DEF_ASN_NGAP_FiveG_S_TMSI);
w->taiListForPaging = asn::UniqueCopy(ieTaiListForPaging->TAIListForPaging, asn_DEF_ASN_NGAP_TAIListForPaging);
diff --git a/src/gnb/ngap/session.cpp b/src/gnb/ngap/session.cpp
index 0511da1f1..eb9bcff50 100644
--- a/src/gnb/ngap/session.cpp
+++ b/src/gnb/ngap/session.cpp
@@ -236,7 +236,7 @@ std::optional NgapTask::setupPduSessionResource(PduSessionResource *r
resource->downTunnel.address = utils::IpToOctetString(m_base->config->gtpIp);
resource->downTunnel.teid = ++m_downlinkTeidCounter;
- auto *w = new NwGnbNgapToGtp(NwGnbNgapToGtp::SESSION_CREATE);
+ auto *w = new NmGnbNgapToGtp(NmGnbNgapToGtp::SESSION_CREATE);
w->resource = resource;
m_base->gtpTask->push(w);
@@ -277,7 +277,7 @@ void NgapTask::receiveSessionResourceReleaseCommand(int amfId, ASN_NGAP_PDUSessi
// Perform release
for (auto &psi : psIds)
{
- auto *w = new NwGnbNgapToGtp(NwGnbNgapToGtp::SESSION_RELEASE);
+ auto *w = new NmGnbNgapToGtp(NmGnbNgapToGtp::SESSION_RELEASE);
w->ueId = ue->ctxId;
w->psi = psi;
m_base->gtpTask->push(w);
diff --git a/src/gnb/ngap/task.cpp b/src/gnb/ngap/task.cpp
index 34610ecb9..3623f4334 100644
--- a/src/gnb/ngap/task.cpp
+++ b/src/gnb/ngap/task.cpp
@@ -30,7 +30,7 @@ void NgapTask::onStart()
for (auto &amfCtx : m_amfCtx)
{
- auto *msg = new NwGnbSctp(NwGnbSctp::CONNECTION_REQUEST);
+ auto *msg = new NmGnbSctp(NmGnbSctp::CONNECTION_REQUEST);
msg->clientId = amfCtx.second->ctxId;
msg->localAddress = m_base->config->ngapIp;
msg->localPort = 0;
@@ -51,18 +51,18 @@ void NgapTask::onLoop()
switch (msg->msgType)
{
case NtsMessageType::GNB_RRC_TO_NGAP: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbRrcToNgap::INITIAL_NAS_DELIVERY: {
+ case NmGnbRrcToNgap::INITIAL_NAS_DELIVERY: {
handleInitialNasTransport(w->ueId, w->pdu, w->rrcEstablishmentCause);
break;
}
- case NwGnbRrcToNgap::UPLINK_NAS_DELIVERY: {
+ case NmGnbRrcToNgap::UPLINK_NAS_DELIVERY: {
handleUplinkNasTransport(w->ueId, w->pdu);
break;
}
- case NwGnbRrcToNgap::RADIO_LINK_FAILURE: {
+ case NmGnbRrcToNgap::RADIO_LINK_FAILURE: {
handleRadioLinkFailure(w->ueId);
break;
}
@@ -70,16 +70,16 @@ void NgapTask::onLoop()
break;
}
case NtsMessageType::GNB_SCTP: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbSctp::ASSOCIATION_SETUP:
+ case NmGnbSctp::ASSOCIATION_SETUP:
handleAssociationSetup(w->clientId, w->associationId, w->inStreams, w->outStreams);
break;
- case NwGnbSctp::RECEIVE_MESSAGE:
+ case NmGnbSctp::RECEIVE_MESSAGE:
handleSctpMessage(w->clientId, w->stream, w->buffer);
break;
- case NwGnbSctp::ASSOCIATION_SHUTDOWN:
+ case NmGnbSctp::ASSOCIATION_SHUTDOWN:
handleAssociationShutdown(w->clientId);
break;
default:
diff --git a/src/gnb/ngap/transport.cpp b/src/gnb/ngap/transport.cpp
index 29f4d8405..b6c0e2494 100644
--- a/src/gnb/ngap/transport.cpp
+++ b/src/gnb/ngap/transport.cpp
@@ -109,7 +109,7 @@ void NgapTask::sendNgapNonUe(int associatedAmf, ASN_NGAP_NGAP_PDU *pdu)
m_logger->err("NGAP APER encoding failed");
else
{
- auto *msg = new NwGnbSctp(NwGnbSctp::SEND_MESSAGE);
+ auto *msg = new NmGnbSctp(NmGnbSctp::SEND_MESSAGE);
msg->clientId = amf->ctxId;
msg->stream = 0;
msg->buffer = UniqueBuffer{buffer, static_cast(encoded)};
@@ -200,7 +200,7 @@ void NgapTask::sendNgapUeAssociated(int ueId, ASN_NGAP_NGAP_PDU *pdu)
m_logger->err("NGAP APER encoding failed");
else
{
- auto *msg = new NwGnbSctp(NwGnbSctp::SEND_MESSAGE);
+ auto *msg = new NmGnbSctp(NmGnbSctp::SEND_MESSAGE);
msg->clientId = amf->ctxId;
msg->stream = ue->uplinkStream;
msg->buffer = UniqueBuffer{buffer, static_cast(encoded)};
diff --git a/src/gnb/nts.hpp b/src/gnb/nts.hpp
index cb3176bce..3edde81ac 100644
--- a/src/gnb/nts.hpp
+++ b/src/gnb/nts.hpp
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -31,28 +32,28 @@ extern "C"
namespace nr::gnb
{
-struct NwGnbRlsToRrc : NtsMessage
+struct NmGnbRlsToRrc : NtsMessage
{
enum PR
{
- RRC_PDU_DELIVERY,
- SIGNAL_LOST
+ SIGNAL_DETECTED,
+ UPLINK_RRC,
} present;
- // RRC_PDU_DELIVERY
- // SIGNAL_LOST
+ // SIGNAL_DETECTED
+ // UPLINK_RRC
int ueId{};
- // RRC_PDU_DELIVERY
- rrc::RrcChannel channel{};
- OctetString pdu{};
+ // UPLINK_RRC
+ OctetString data;
+ rrc::RrcChannel rrcChannel{};
- explicit NwGnbRlsToRrc(PR present) : NtsMessage(NtsMessageType::GNB_RLS_TO_RRC), present(present)
+ explicit NmGnbRlsToRrc(PR present) : NtsMessage(NtsMessageType::GNB_RLS_TO_RRC), present(present)
{
}
};
-struct NwGnbRlsToGtp : NtsMessage
+struct NmGnbRlsToGtp : NtsMessage
{
enum PR
{
@@ -62,14 +63,14 @@ struct NwGnbRlsToGtp : NtsMessage
// DATA_PDU_DELIVERY
int ueId{};
int psi{};
- OctetString pdu{};
+ OctetString pdu;
- explicit NwGnbRlsToGtp(PR present) : NtsMessage(NtsMessageType::GNB_RLS_TO_GTP), present(present)
+ explicit NmGnbRlsToGtp(PR present) : NtsMessage(NtsMessageType::GNB_RLS_TO_GTP), present(present)
{
}
};
-struct NwGnbGtpToRls : NtsMessage
+struct NmGnbGtpToRls : NtsMessage
{
enum PR
{
@@ -81,16 +82,69 @@ struct NwGnbGtpToRls : NtsMessage
int psi{};
OctetString pdu{};
- explicit NwGnbGtpToRls(PR present) : NtsMessage(NtsMessageType::GNB_GTP_TO_RLS), present(present)
+ explicit NmGnbGtpToRls(PR present) : NtsMessage(NtsMessageType::GNB_GTP_TO_RLS), present(present)
{
}
};
-struct NwGnbRrcToRls : NtsMessage
+struct NmGnbRlsToRls : NtsMessage
+{
+ enum PR
+ {
+ SIGNAL_DETECTED,
+ SIGNAL_LOST,
+ RECEIVE_RLS_MESSAGE,
+ DOWNLINK_RRC,
+ DOWNLINK_DATA,
+ UPLINK_RRC,
+ UPLINK_DATA,
+ RADIO_LINK_FAILURE,
+ TRANSMISSION_FAILURE,
+ } present;
+
+ // SIGNAL_DETECTED
+ // SIGNAL_LOST
+ // DOWNLINK_RRC
+ // DOWNLINK_DATA
+ // UPLINK_DATA
+ // UPLINK_RRC
+ int ueId{};
+
+ // RECEIVE_RLS_MESSAGE
+ std::unique_ptr msg{};
+
+ // DOWNLINK_DATA
+ // UPLINK_DATA
+ int psi{};
+
+ // DOWNLINK_DATA
+ // DOWNLINK_RRC
+ // UPLINK_DATA
+ // UPLINK_RRC
+ OctetString data;
+
+ // DOWNLINK_RRC
+ uint32_t pduId{};
+
+ // DOWNLINK_RRC
+ // UPLINK_RRC
+ rrc::RrcChannel rrcChannel{};
+
+ // RADIO_LINK_FAILURE
+ rls::ERlfCause rlfCause{};
+
+ // TRANSMISSION_FAILURE
+ std::vector pduList;
+
+ explicit NmGnbRlsToRls(PR present) : NtsMessage(NtsMessageType::GNB_RLS_TO_RLS), present(present)
+ {
+ }
+};
+
+struct NmGnbRrcToRls : NtsMessage
{
enum PR
{
- RADIO_POWER_ON,
RRC_PDU_DELIVERY,
} present;
@@ -99,12 +153,12 @@ struct NwGnbRrcToRls : NtsMessage
rrc::RrcChannel channel{};
OctetString pdu{};
- explicit NwGnbRrcToRls(PR present) : NtsMessage(NtsMessageType::GNB_RRC_TO_RLS), present(present)
+ explicit NmGnbRrcToRls(PR present) : NtsMessage(NtsMessageType::GNB_RRC_TO_RLS), present(present)
{
}
};
-struct NwGnbNgapToRrc : NtsMessage
+struct NmGnbNgapToRrc : NtsMessage
{
enum PR
{
@@ -125,12 +179,12 @@ struct NwGnbNgapToRrc : NtsMessage
asn::Unique uePagingTmsi{};
asn::Unique taiListForPaging{};
- explicit NwGnbNgapToRrc(PR present) : NtsMessage(NtsMessageType::GNB_NGAP_TO_RRC), present(present)
+ explicit NmGnbNgapToRrc(PR present) : NtsMessage(NtsMessageType::GNB_NGAP_TO_RRC), present(present)
{
}
};
-struct NwGnbRrcToNgap : NtsMessage
+struct NmGnbRrcToNgap : NtsMessage
{
enum PR
{
@@ -151,12 +205,12 @@ struct NwGnbRrcToNgap : NtsMessage
// INITIAL_NAS_DELIVERY
long rrcEstablishmentCause{};
- explicit NwGnbRrcToNgap(PR present) : NtsMessage(NtsMessageType::GNB_RRC_TO_NGAP), present(present)
+ explicit NmGnbRrcToNgap(PR present) : NtsMessage(NtsMessageType::GNB_RRC_TO_NGAP), present(present)
{
}
};
-struct NwGnbNgapToGtp : NtsMessage
+struct NmGnbNgapToGtp : NtsMessage
{
enum PR
{
@@ -179,12 +233,12 @@ struct NwGnbNgapToGtp : NtsMessage
// SESSION_RELEASE
int psi{};
- explicit NwGnbNgapToGtp(PR present) : NtsMessage(NtsMessageType::GNB_NGAP_TO_GTP), present(present)
+ explicit NmGnbNgapToGtp(PR present) : NtsMessage(NtsMessageType::GNB_NGAP_TO_GTP), present(present)
{
}
};
-struct NwGnbSctp : NtsMessage
+struct NmGnbSctp : NtsMessage
{
enum PR
{
@@ -224,12 +278,12 @@ struct NwGnbSctp : NtsMessage
UniqueBuffer buffer{};
uint16_t stream{};
- explicit NwGnbSctp(PR present) : NtsMessage(NtsMessageType::GNB_SCTP), present(present)
+ explicit NmGnbSctp(PR present) : NtsMessage(NtsMessageType::GNB_SCTP), present(present)
{
}
};
-struct NwGnbStatusUpdate : NtsMessage
+struct NmGnbStatusUpdate : NtsMessage
{
static constexpr const int NGAP_IS_UP = 1;
@@ -238,17 +292,17 @@ struct NwGnbStatusUpdate : NtsMessage
// NGAP_IS_UP
bool isNgapUp{};
- explicit NwGnbStatusUpdate(const int what) : NtsMessage(NtsMessageType::GNB_STATUS_UPDATE), what(what)
+ explicit NmGnbStatusUpdate(const int what) : NtsMessage(NtsMessageType::GNB_STATUS_UPDATE), what(what)
{
}
};
-struct NwGnbCliCommand : NtsMessage
+struct NmGnbCliCommand : NtsMessage
{
std::unique_ptr cmd;
InetAddress address;
- NwGnbCliCommand(std::unique_ptr cmd, InetAddress address)
+ NmGnbCliCommand(std::unique_ptr cmd, InetAddress address)
: NtsMessage(NtsMessageType::GNB_CLI_COMMAND), cmd(std::move(cmd)), address(address)
{
}
diff --git a/src/gnb/rls/ctl_task.cpp b/src/gnb/rls/ctl_task.cpp
new file mode 100644
index 000000000..a2f72ea04
--- /dev/null
+++ b/src/gnb/rls/ctl_task.cpp
@@ -0,0 +1,260 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "ctl_task.hpp"
+
+#include
+#include
+
+static constexpr const size_t MAX_PDU_COUNT = 4096;
+static constexpr const int MAX_PDU_TTL = 3000;
+
+static constexpr const int TIMER_ID_ACK_CONTROL = 1;
+static constexpr const int TIMER_ID_ACK_SEND = 2;
+
+static constexpr const int TIMER_PERIOD_ACK_CONTROL = 1500;
+static constexpr const int TIMER_PERIOD_ACK_SEND = 2250;
+
+namespace nr::gnb
+{
+
+RlsControlTask::RlsControlTask(TaskBase *base, uint64_t sti)
+ : m_sti{sti}, m_mainTask{}, m_udpTask{}, m_pduMap{}, m_pendingAck{}
+{
+ m_logger = base->logBase->makeUniqueLogger("rls-ctl");
+}
+
+void RlsControlTask::initialize(NtsTask *mainTask, RlsUdpTask *udpTask)
+{
+ m_mainTask = mainTask;
+ m_udpTask = udpTask;
+}
+
+void RlsControlTask::onStart()
+{
+ setTimer(TIMER_ID_ACK_CONTROL, TIMER_PERIOD_ACK_CONTROL);
+ setTimer(TIMER_ID_ACK_SEND, TIMER_PERIOD_ACK_SEND);
+}
+
+void RlsControlTask::onLoop()
+{
+ NtsMessage *msg = take();
+ if (!msg)
+ return;
+
+ switch (msg->msgType)
+ {
+ case NtsMessageType::GNB_RLS_TO_RLS: {
+ auto *w = dynamic_cast(msg);
+ switch (w->present)
+ {
+ case NmGnbRlsToRls::SIGNAL_DETECTED:
+ handleSignalDetected(w->ueId);
+ break;
+ case NmGnbRlsToRls::SIGNAL_LOST:
+ handleSignalLost(w->ueId);
+ break;
+ case NmGnbRlsToRls::RECEIVE_RLS_MESSAGE:
+ handleRlsMessage(w->ueId, *w->msg);
+ break;
+ case NmGnbRlsToRls::DOWNLINK_DATA:
+ handleDownlinkDataDelivery(w->ueId, w->psi, std::move(w->data));
+ break;
+ case NmGnbRlsToRls::DOWNLINK_RRC:
+ handleDownlinkRrcDelivery(w->ueId, w->pduId, w->rrcChannel, std::move(w->data));
+ break;
+ default:
+ m_logger->unhandledNts(msg);
+ break;
+ }
+ break;
+ }
+ case NtsMessageType::TIMER_EXPIRED: {
+ auto *w = dynamic_cast(msg);
+ if (w->timerId == TIMER_ID_ACK_CONTROL)
+ {
+ setTimer(TIMER_ID_ACK_CONTROL, TIMER_PERIOD_ACK_CONTROL);
+ onAckControlTimerExpired();
+ }
+ else if (w->timerId == TIMER_ID_ACK_SEND)
+ {
+ setTimer(TIMER_ID_ACK_SEND, TIMER_PERIOD_ACK_SEND);
+ onAckSendTimerExpired();
+ }
+ break;
+ }
+ default:
+ m_logger->unhandledNts(msg);
+ break;
+ }
+
+ delete msg;
+}
+
+void RlsControlTask::onQuit()
+{
+}
+
+void RlsControlTask::handleSignalDetected(int ueId)
+{
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::SIGNAL_DETECTED);
+ w->ueId = ueId;
+ m_mainTask->push(w);
+}
+
+void RlsControlTask::handleSignalLost(int ueId)
+{
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::SIGNAL_LOST);
+ w->ueId = ueId;
+ m_mainTask->push(w);
+}
+
+void RlsControlTask::handleRlsMessage(int ueId, rls::RlsMessage &msg)
+{
+ if (msg.msgType == rls::EMessageType::PDU_TRANSMISSION_ACK)
+ {
+ auto &m = (rls::RlsPduTransmissionAck &)msg;
+ for (auto pduId : m.pduIds)
+ m_pduMap.erase(pduId);
+ }
+ else if (msg.msgType == rls::EMessageType::PDU_TRANSMISSION)
+ {
+ auto &m = (rls::RlsPduTransmission &)msg;
+ if (m.pduId != 0)
+ m_pendingAck[ueId].push_back(m.pduId);
+
+ if (m.pduType == rls::EPduType::DATA)
+ {
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::UPLINK_DATA);
+ w->ueId = ueId;
+ w->psi = static_cast(m.payload);
+ w->data = std::move(m.pdu);
+ m_mainTask->push(w);
+ }
+ else if (m.pduType == rls::EPduType::RRC)
+ {
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::UPLINK_RRC);
+ w->ueId = ueId;
+ w->rrcChannel = static_cast(m.payload);
+ w->data = std::move(m.pdu);
+ m_mainTask->push(w);
+ }
+ else
+ {
+ m_logger->err("Unhandled RLS PDU type");
+ }
+ }
+ else
+ {
+ m_logger->err("Unhandled RLS message type");
+ }
+}
+
+void RlsControlTask::handleDownlinkRrcDelivery(int ueId, uint32_t pduId, rrc::RrcChannel channel, OctetString &&data)
+{
+ if (ueId == 0 && pduId != 0)
+ {
+ // PDU ID must be not set in case of broadcast
+ throw std::runtime_error("");
+ }
+
+ if (pduId != 0)
+ {
+ if (m_pduMap.count(pduId))
+ {
+ m_pduMap.clear();
+
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::RADIO_LINK_FAILURE);
+ w->rlfCause = rls::ERlfCause::PDU_ID_EXISTS;
+ m_mainTask->push(w);
+ return;
+ }
+
+ if (m_pduMap.size() > MAX_PDU_COUNT)
+ {
+ m_pduMap.clear();
+
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::RADIO_LINK_FAILURE);
+ w->rlfCause = rls::ERlfCause::PDU_ID_FULL;
+ m_mainTask->push(w);
+ return;
+ }
+
+ m_pduMap[pduId].endPointId = ueId;
+ m_pduMap[pduId].id = pduId;
+ m_pduMap[pduId].pdu = data.copy();
+ m_pduMap[pduId].rrcChannel = channel;
+ m_pduMap[pduId].sentTime = utils::CurrentTimeMillis();
+ }
+
+ rls::RlsPduTransmission msg{m_sti};
+ msg.pduType = rls::EPduType::RRC;
+ msg.pdu = std::move(data);
+ msg.payload = static_cast(channel);
+ msg.pduId = pduId;
+
+ m_udpTask->send(ueId, msg);
+}
+
+void RlsControlTask::handleDownlinkDataDelivery(int ueId, int psi, OctetString &&data)
+{
+ rls::RlsPduTransmission msg{m_sti};
+ msg.pduType = rls::EPduType::DATA;
+ msg.pdu = std::move(data);
+ msg.payload = static_cast(psi);
+ msg.pduId = 0;
+
+ m_udpTask->send(ueId, msg);
+}
+
+void RlsControlTask::onAckControlTimerExpired()
+{
+ int64_t current = utils::CurrentTimeMillis();
+
+ std::vector transmissionFailureIds;
+ std::vector transmissionFailures;
+
+ for (auto &pdu : m_pduMap)
+ {
+ auto delta = current - pdu.second.sentTime;
+ if (delta > MAX_PDU_TTL)
+ {
+ transmissionFailureIds.push_back(pdu.first);
+ transmissionFailures.push_back(std::move(pdu.second));
+ }
+ }
+
+ for (auto id : transmissionFailureIds)
+ m_pduMap.erase(id);
+
+ if (!transmissionFailures.empty())
+ {
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::TRANSMISSION_FAILURE);
+ w->pduList = std::move(transmissionFailures);
+ m_mainTask->push(w);
+ }
+}
+
+void RlsControlTask::onAckSendTimerExpired()
+{
+ auto copy = m_pendingAck;
+ m_pendingAck.clear();
+
+ for (auto &item : copy)
+ {
+ if (!item.second.empty())
+ continue;
+
+ rls::RlsPduTransmissionAck msg{m_sti};
+ msg.pduIds = std::move(item.second);
+
+ m_udpTask->send(item.first, msg);
+ }
+}
+
+} // namespace nr::gnb
diff --git a/src/gnb/rls/ctl_task.hpp b/src/gnb/rls/ctl_task.hpp
new file mode 100644
index 000000000..1f8a01096
--- /dev/null
+++ b/src/gnb/rls/ctl_task.hpp
@@ -0,0 +1,52 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#pragma once
+
+#include "udp_task.hpp"
+
+#include
+#include
+#include
+
+namespace nr::gnb
+{
+
+class RlsControlTask : public NtsTask
+{
+ private:
+ std::unique_ptr m_logger;
+ uint64_t m_sti;
+ NtsTask *m_mainTask;
+ RlsUdpTask *m_udpTask;
+ std::unordered_map m_pduMap;
+ std::unordered_map> m_pendingAck;
+
+ public:
+ explicit RlsControlTask(TaskBase *base, uint64_t sti);
+ ~RlsControlTask() override = default;
+
+ protected:
+ void onStart() override;
+ void onLoop() override;
+ void onQuit() override;
+
+ public:
+ void initialize(NtsTask *mainTask, RlsUdpTask *udpTask);
+
+ private:
+ void handleSignalDetected(int ueId);
+ void handleSignalLost(int ueId);
+ void handleRlsMessage(int ueId, rls::RlsMessage &msg);
+ void handleDownlinkRrcDelivery(int ueId, uint32_t pduId, rrc::RrcChannel channel, OctetString &&data);
+ void handleDownlinkDataDelivery(int ueId, int psi, OctetString &&data);
+ void onAckControlTimerExpired();
+ void onAckSendTimerExpired();
+};
+
+} // namespace nr::gnb
\ No newline at end of file
diff --git a/src/gnb/rls/handler.cpp b/src/gnb/rls/handler.cpp
deleted file mode 100644
index 527d2be9a..000000000
--- a/src/gnb/rls/handler.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-// This file is a part of UERANSIM open source project.
-// Copyright (c) 2021 ALİ GÜNGÖR.
-//
-// The software and all associated files are licensed under GPL-3.0
-// and subject to the terms and conditions defined in LICENSE file.
-//
-
-#include "task.hpp"
-
-#include
-
-#include
-#include
-
-static int MIN_ALLOWED_DBM = -120;
-
-static int EstimateSimulatedDbm(const Vector3 &myPos, const Vector3 &uePos)
-{
- int deltaX = myPos.x - uePos.x;
- int deltaY = myPos.y - uePos.y;
- int deltaZ = myPos.z - uePos.z;
-
- int distance = static_cast(std::sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ));
- if (distance == 0)
- return -1; // 0 may be confusing for people
- return -distance;
-}
-
-namespace nr::gnb
-{
-
-void GnbRlsTask::handleCellInfoRequest(int ueId, const rls::RlsCellInfoRequest &msg)
-{
- int dbm = EstimateSimulatedDbm(m_base->config->phyLocation, msg.simPos);
- if (dbm < MIN_ALLOWED_DBM)
- {
- // if the simulated signal strength is such low, then do not send a response to this message
- return;
- }
-
- rls::RlsCellInfoResponse resp{m_sti};
- resp.cellId.nci = m_base->config->nci;
- resp.cellId.plmn = m_base->config->plmn;
- resp.tac = m_base->config->tac;
- resp.dbm = dbm;
- resp.gnbName = m_base->config->name;
- resp.linkIp = m_base->config->portalIp;
-
- sendRlsMessage(ueId, resp);
-}
-
-void GnbRlsTask::handleUplinkPduDelivery(int ueId, rls::RlsPduDelivery &msg)
-{
- if (msg.pduType == rls::EPduType::RRC)
- {
- auto *nw = new NwGnbRlsToRrc(NwGnbRlsToRrc::RRC_PDU_DELIVERY);
- nw->ueId = ueId;
- nw->channel = static_cast(msg.payload.get4I(0));
- nw->pdu = std::move(msg.pdu);
- m_base->rrcTask->push(nw);
- }
- else if (msg.pduType == rls::EPduType::DATA)
- {
- auto *nw = new NwGnbRlsToGtp(NwGnbRlsToGtp::DATA_PDU_DELIVERY);
- nw->ueId = ueId;
- nw->psi = msg.payload.get4I(0);
- nw->pdu = std::move(msg.pdu);
- m_base->gtpTask->push(nw);
- }
-}
-
-void GnbRlsTask::handleDownlinkDelivery(int ueId, rls::EPduType pduType, OctetString &&pdu, OctetString &&payload)
-{
- rls::RlsPduDelivery resp{m_sti};
- resp.pduType = pduType;
- resp.pdu = std::move(pdu);
- resp.payload = std::move(payload);
-
- if (ueId != 0)
- {
- sendRlsMessage(ueId, resp);
- }
- else
- {
- for (auto &ue : m_ueCtx)
- sendRlsMessage(ue.first, resp);
- }
-}
-
-} // namespace nr::gnb
diff --git a/src/gnb/rls/management.cpp b/src/gnb/rls/management.cpp
deleted file mode 100644
index fd64fa772..000000000
--- a/src/gnb/rls/management.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// This file is a part of UERANSIM open source project.
-// Copyright (c) 2021 ALİ GÜNGÖR.
-//
-// The software and all associated files are licensed under GPL-3.0
-// and subject to the terms and conditions defined in LICENSE file.
-//
-
-#include "task.hpp"
-
-#include
-
-#include
-#include
-
-static const int64_t LAST_SEEN_THRESHOLD = 3000;
-
-namespace nr::gnb
-{
-
-int GnbRlsTask::updateUeInfo(const InetAddress &addr, uint64_t sti)
-{
- if (m_stiToUeId.count(sti))
- {
- int ueId = m_stiToUeId[sti];
- auto &ctx = m_ueCtx[ueId];
- ctx->addr = addr;
- ctx->lastSeen = utils::CurrentTimeMillis();
- return ueId;
- }
- else
- {
- int ueId = ++m_ueIdCounter;
- m_stiToUeId[sti] = ueId;
- auto ctx = std::make_unique(ueId);
- ctx->sti = sti;
- ctx->addr = addr;
- ctx->lastSeen = utils::CurrentTimeMillis();
- m_ueCtx[ueId] = std::move(ctx);
-
- m_logger->debug("New UE signal detected, total [%d] UEs in coverage", static_cast(m_stiToUeId.size()));
- return ueId;
- }
-}
-
-void GnbRlsTask::onPeriodicLostControl()
-{
- int64_t current = utils::CurrentTimeMillis();
-
- std::set lostUeId{};
- std::set lostSti{};
-
- for (auto &item : m_ueCtx)
- {
- if (current - item.second->lastSeen > LAST_SEEN_THRESHOLD)
- {
- lostUeId.insert(item.second->ueId);
- lostSti.insert(item.second->sti);
- }
- }
-
- for (uint64_t sti : lostSti)
- m_stiToUeId.erase(sti);
- for (int ueId : lostUeId)
- {
- m_ueCtx.erase(ueId);
- m_logger->debug("Signal lost detected for UE[%d]", ueId);
-
- auto *w = new NwGnbRlsToRrc(NwGnbRlsToRrc::SIGNAL_LOST);
- w->ueId = ueId;
- m_base->rrcTask->push(w);
- }
-}
-
-} // namespace nr::gnb
diff --git a/src/gnb/rls/task.cpp b/src/gnb/rls/task.cpp
index dcb1e6eef..6f699b81a 100644
--- a/src/gnb/rls/task.cpp
+++ b/src/gnb/rls/task.cpp
@@ -9,40 +9,28 @@
#include "task.hpp"
#include
-#include
#include
#include
-#include
-#include
-
-static const int TIMER_ID_LOST_CONTROL = 1;
-static const int TIMER_PERIOD_LOST_CONTROL = 2000;
namespace nr::gnb
{
-GnbRlsTask::GnbRlsTask(TaskBase *base)
- : m_base{base}, m_udpTask{}, m_powerOn{}, m_ueCtx{}, m_stiToUeId{}, m_ueIdCounter{}
+GnbRlsTask::GnbRlsTask(TaskBase *base) : m_base{base}
{
m_logger = m_base->logBase->makeUniqueLogger("rls");
m_sti = utils::Random64();
+
+ m_udpTask = new RlsUdpTask(base, m_sti, base->config->phyLocation);
+ m_ctlTask = new RlsControlTask(base, m_sti);
+
+ m_udpTask->initialize(m_ctlTask);
+ m_ctlTask->initialize(this, m_udpTask);
}
void GnbRlsTask::onStart()
{
- try
- {
- m_udpTask = new udp::UdpServerTask(m_base->config->portalIp, cons::PortalPort, this);
- m_udpTask->start();
- }
- catch (const LibError &e)
- {
- m_logger->err("RLS failure [%s]", e.what());
- quit();
- return;
- }
-
- setTimer(TIMER_ID_LOST_CONTROL, TIMER_PERIOD_LOST_CONTROL);
+ m_udpTask->start();
+ m_ctlTask->start();
}
void GnbRlsTask::onLoop()
@@ -53,51 +41,79 @@ void GnbRlsTask::onLoop()
switch (msg->msgType)
{
- case NtsMessageType::GNB_RRC_TO_RLS: {
- auto *w = dynamic_cast(msg);
+ case NtsMessageType::GNB_RLS_TO_RLS: {
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbRrcToRls::RRC_PDU_DELIVERY: {
- handleDownlinkDelivery(w->ueId, rls::EPduType::RRC, std::move(w->pdu),
- OctetString::FromOctet4(static_cast(w->channel)));
+ case NmGnbRlsToRls::SIGNAL_DETECTED: {
+ auto *m = new NmGnbRlsToRrc(NmGnbRlsToRrc::SIGNAL_DETECTED);
+ m->ueId = w->ueId;
+ m_base->rrcTask->push(m);
break;
}
- case NwGnbRrcToRls::RADIO_POWER_ON: {
- m_powerOn = true;
+ case NmGnbRlsToRls::SIGNAL_LOST: {
+ m_logger->debug("UE[%d] signal lost", w->ueId);
+ break;
+ }
+ case NmGnbRlsToRls::UPLINK_DATA: {
+ auto *m = new NmGnbRlsToGtp(NmGnbRlsToGtp::DATA_PDU_DELIVERY);
+ m->ueId = w->ueId;
+ m->psi = w->psi;
+ m->pdu = std::move(w->data);
+ m_base->gtpTask->push(m);
+ break;
+ }
+ case NmGnbRlsToRls::UPLINK_RRC: {
+ auto *m = new NmGnbRlsToRrc(NmGnbRlsToRrc::UPLINK_RRC);
+ m->ueId = w->ueId;
+ m->rrcChannel = w->rrcChannel;
+ m->data = std::move(w->data);
+ m_base->rrcTask->push(m);
+ break;
+ }
+ case NmGnbRlsToRls::RADIO_LINK_FAILURE: {
+ m_logger->debug("radio link failure [%d]", (int)w->rlfCause);
+ break;
+ }
+ case NmGnbRlsToRls::TRANSMISSION_FAILURE: {
+ m_logger->debug("transmission failure [%s]", "");
+ break;
+ }
+ default: {
+ m_logger->unhandledNts(msg);
break;
}
}
break;
}
- case NtsMessageType::GNB_GTP_TO_RLS: {
- auto *w = dynamic_cast(msg);
+ case NtsMessageType::GNB_RRC_TO_RLS: {
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbGtpToRls::DATA_PDU_DELIVERY: {
- handleDownlinkDelivery(w->ueId, rls::EPduType::DATA, std::move(w->pdu),
- OctetString::FromOctet4(static_cast(w->psi)));
+ case NmGnbRrcToRls::RRC_PDU_DELIVERY: {
+ auto *m = new NmGnbRlsToRls(NmGnbRlsToRls::DOWNLINK_RRC);
+ m->ueId = w->ueId;
+ m->rrcChannel = w->channel;
+ m->pduId = 0;
+ m->data = std::move(w->pdu);
+ m_ctlTask->push(m);
break;
}
}
break;
}
- case NtsMessageType::UDP_SERVER_RECEIVE: {
- auto *w = dynamic_cast(msg);
- auto rlsMsg = rls::DecodeRlsMessage(OctetView{w->packet});
- if (rlsMsg == nullptr)
+ case NtsMessageType::GNB_GTP_TO_RLS: {
+ auto *w = dynamic_cast(msg);
+ switch (w->present)
{
- m_logger->err("Unable to decode RLS message");
+ case NmGnbGtpToRls::DATA_PDU_DELIVERY: {
+ auto *m = new NmGnbRlsToRls(NmGnbRlsToRls::DOWNLINK_DATA);
+ m->ueId = w->ueId;
+ m->psi = w->psi;
+ m->data = std::move(w->pdu);
+ m_ctlTask->push(m);
break;
}
- receiveRlsMessage(w->fromAddress, *rlsMsg);
- break;
- }
- case NtsMessageType::TIMER_EXPIRED: {
- auto *w = dynamic_cast(msg);
- if (w->timerId == TIMER_ID_LOST_CONTROL)
- {
- setTimer(TIMER_ID_LOST_CONTROL, TIMER_PERIOD_LOST_CONTROL);
- onPeriodicLostControl();
}
break;
}
@@ -111,9 +127,10 @@ void GnbRlsTask::onLoop()
void GnbRlsTask::onQuit()
{
- if (m_udpTask != nullptr)
- m_udpTask->quit();
+ m_udpTask->quit();
+ m_ctlTask->quit();
delete m_udpTask;
+ delete m_ctlTask;
}
} // namespace nr::gnb
diff --git a/src/gnb/rls/task.hpp b/src/gnb/rls/task.hpp
index 8ddaa14ce..969c89338 100644
--- a/src/gnb/rls/task.hpp
+++ b/src/gnb/rls/task.hpp
@@ -8,6 +8,9 @@
#pragma once
+#include "ctl_task.hpp"
+#include "udp_task.hpp"
+
#include
#include
#include
@@ -28,13 +31,11 @@ class GnbRlsTask : public NtsTask
private:
TaskBase *m_base;
std::unique_ptr m_logger;
- udp::UdpServerTask *m_udpTask;
- bool m_powerOn;
+ RlsUdpTask *m_udpTask;
+ RlsControlTask *m_ctlTask;
+
uint64_t m_sti;
- std::unordered_map> m_ueCtx;
- std::unordered_map m_stiToUeId;
- int m_ueIdCounter;
friend class GnbCmdHandler;
@@ -46,19 +47,6 @@ class GnbRlsTask : public NtsTask
void onStart() override;
void onLoop() override;
void onQuit() override;
-
- private: /* Transport */
- void receiveRlsMessage(const InetAddress &addr, rls::RlsMessage &msg);
- void sendRlsMessage(int ueId, const rls::RlsMessage &msg);
-
- private: /* Handler */
- void handleCellInfoRequest(int ueId, const rls::RlsCellInfoRequest &msg);
- void handleUplinkPduDelivery(int ueId, rls::RlsPduDelivery &msg);
- void handleDownlinkDelivery(int ueId, rls::EPduType pduType, OctetString &&pdu, OctetString &&payload);
-
- private: /* UE Management */
- int updateUeInfo(const InetAddress &addr, uint64_t sti);
- void onPeriodicLostControl();
};
-} // namespace nr::gnb
\ No newline at end of file
+} // namespace nr::gnb
diff --git a/src/gnb/rls/transport.cpp b/src/gnb/rls/transport.cpp
deleted file mode 100644
index 43eeaaa97..000000000
--- a/src/gnb/rls/transport.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// This file is a part of UERANSIM open source project.
-// Copyright (c) 2021 ALİ GÜNGÖR.
-//
-// The software and all associated files are licensed under GPL-3.0
-// and subject to the terms and conditions defined in LICENSE file.
-//
-
-#include "task.hpp"
-
-namespace nr::gnb
-{
-
-void GnbRlsTask::receiveRlsMessage(const InetAddress &addr, rls::RlsMessage &msg)
-{
- if (!m_powerOn)
- {
- // ignore received RLS message
- return;
- }
-
- int ueId = updateUeInfo(addr, msg.sti);
-
- switch (msg.msgType)
- {
- case rls::EMessageType::CELL_INFO_REQUEST: {
- handleCellInfoRequest(ueId, (const rls::RlsCellInfoRequest &)msg);
- break;
- }
- case rls::EMessageType::PDU_DELIVERY: {
- handleUplinkPduDelivery(ueId, (rls::RlsPduDelivery &)msg);
- break;
- }
- default:
- m_logger->err("Unhandled RLS message received with type[%d]", static_cast(msg.msgType));
- break;
- }
-}
-
-void GnbRlsTask::sendRlsMessage(int ueId, const rls::RlsMessage &msg)
-{
- if (!m_ueCtx.count(ueId))
- {
- m_logger->err("RLS message sending failure, UE[%d] not exists", ueId);
- return;
- }
-
- OctetString stream{};
- rls::EncodeRlsMessage(msg, stream);
- m_udpTask->send(m_ueCtx[ueId]->addr, stream);
-}
-
-} // namespace nr::gnb
diff --git a/src/gnb/rls/udp_task.cpp b/src/gnb/rls/udp_task.cpp
new file mode 100644
index 000000000..fbd83933f
--- /dev/null
+++ b/src/gnb/rls/udp_task.cpp
@@ -0,0 +1,201 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "udp_task.hpp"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+static constexpr const int BUFFER_SIZE = 16384;
+
+static constexpr const int LOOP_PERIOD = 1000;
+static constexpr const int RECEIVE_TIMEOUT = 200;
+static constexpr const int HEARTBEAT_THRESHOLD = 2000; // (LOOP_PERIOD + RECEIVE_TIMEOUT)'dan büyük olmalı
+
+static constexpr const int MIN_ALLOWED_DBM = -120;
+
+static int EstimateSimulatedDbm(const Vector3 &myPos, const Vector3 &uePos)
+{
+ int deltaX = myPos.x - uePos.x;
+ int deltaY = myPos.y - uePos.y;
+ int deltaZ = myPos.z - uePos.z;
+
+ int distance = static_cast(std::sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ));
+ if (distance == 0)
+ return -1; // 0 may be confusing for people
+ return -distance;
+}
+
+namespace nr::gnb
+{
+
+RlsUdpTask::RlsUdpTask(TaskBase *base, uint64_t sti, Vector3 phyLocation)
+ : m_server{}, m_ctlTask{}, m_sti{sti}, m_phyLocation{phyLocation}, m_lastLoop{}, m_stiToUe{}, m_ueMap{}, m_newIdCounter{}
+{
+ m_logger = base->logBase->makeUniqueLogger("rls-udp");
+
+ try
+ {
+ m_server = new udp::UdpServer(base->config->portalIp, cons::PortalPort);
+ }
+ catch (const LibError &e)
+ {
+ m_logger->err("RLS failure [%s]", e.what());
+ quit();
+ return;
+ }
+}
+
+void RlsUdpTask::onStart()
+{
+}
+
+void RlsUdpTask::onLoop()
+{
+ auto current = utils::CurrentTimeMillis();
+ if (current - m_lastLoop > LOOP_PERIOD)
+ {
+ m_lastLoop = current;
+ heartbeatCycle(current);
+ }
+
+ uint8_t buffer[BUFFER_SIZE];
+ InetAddress peerAddress;
+
+ int size = m_server->Receive(buffer, BUFFER_SIZE, RECEIVE_TIMEOUT, peerAddress);
+ if (size > 0)
+ {
+ auto rlsMsg = rls::DecodeRlsMessage(OctetView{buffer, static_cast(size)});
+ if (rlsMsg == nullptr)
+ m_logger->err("Unable to decode RLS message");
+ else
+ receiveRlsPdu(peerAddress, std::move(rlsMsg));
+ }
+}
+
+void RlsUdpTask::onQuit()
+{
+ delete m_server;
+}
+
+void RlsUdpTask::receiveRlsPdu(const InetAddress &addr, std::unique_ptr &&msg)
+{
+ if (msg->msgType == rls::EMessageType::HEARTBEAT)
+ {
+ int dbm = EstimateSimulatedDbm(m_phyLocation, ((const rls::RlsHeartBeat &)*msg).simPos);
+ if (dbm < MIN_ALLOWED_DBM)
+ {
+ // if the simulated signal strength is such low, then ignore this message
+ return;
+ }
+
+ if (m_stiToUe.count(msg->sti))
+ {
+ int ueId = m_stiToUe[msg->sti];
+ m_ueMap[ueId].address = addr;
+ m_ueMap[ueId].lastSeen = utils::CurrentTimeMillis();
+ }
+ else
+ {
+ int ueId = ++m_newIdCounter;
+
+ m_stiToUe[msg->sti] = ueId;
+ m_ueMap[ueId].address = addr;
+ m_ueMap[ueId].lastSeen = utils::CurrentTimeMillis();
+
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::SIGNAL_DETECTED);
+ w->ueId = ueId;
+ m_ctlTask->push(w);
+ }
+
+ rls::RlsHeartBeatAck ack{m_sti};
+ ack.dbm = dbm;
+
+ sendRlsPdu(addr, ack);
+ return;
+ }
+
+ if (!m_stiToUe.count(msg->sti))
+ {
+ // if no HB received yet, and the message is not HB, then ignore the message
+ return;
+ }
+
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::RECEIVE_RLS_MESSAGE);
+ w->ueId = m_stiToUe[msg->sti];
+ w->msg = std::move(msg);
+ m_ctlTask->push(w);
+}
+
+void RlsUdpTask::sendRlsPdu(const InetAddress &addr, const rls::RlsMessage &msg)
+{
+ OctetString stream;
+ rls::EncodeRlsMessage(msg, stream);
+
+ m_server->Send(addr, stream.data(), static_cast(stream.length()));
+}
+
+void RlsUdpTask::heartbeatCycle(int64_t time)
+{
+ std::set lostUeId{};
+ std::set lostSti{};
+
+ for (auto &item : m_ueMap)
+ {
+ if (time - item.second.lastSeen > HEARTBEAT_THRESHOLD)
+ {
+ lostUeId.insert(item.first);
+ lostSti.insert(item.second.sti);
+ }
+ }
+
+ for (uint64_t sti : lostSti)
+ m_stiToUe.erase(sti);
+
+ for (int ueId : lostUeId)
+ m_ueMap.erase(ueId);
+
+ for (int ueId : lostUeId)
+ {
+ auto *w = new NmGnbRlsToRls(NmGnbRlsToRls::SIGNAL_LOST);
+ w->ueId = ueId;
+ m_ctlTask->push(w);
+ }
+}
+
+void RlsUdpTask::initialize(NtsTask *ctlTask)
+{
+ m_ctlTask = ctlTask;
+}
+
+void RlsUdpTask::send(int ueId, const rls::RlsMessage &msg)
+{
+ if (ueId == 0)
+ {
+ for (auto &ue : m_ueMap)
+ send(ue.first, msg);
+ return;
+ }
+
+ if (!m_ueMap.count(ueId))
+ {
+ // ignore the message
+ return;
+ }
+
+ sendRlsPdu(m_ueMap[ueId].address, msg);
+}
+
+} // namespace nr::gnb
diff --git a/src/gnb/rls/udp_task.hpp b/src/gnb/rls/udp_task.hpp
new file mode 100644
index 000000000..5bcd41795
--- /dev/null
+++ b/src/gnb/rls/udp_task.hpp
@@ -0,0 +1,63 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace nr::gnb
+{
+
+class RlsUdpTask : public NtsTask
+{
+ private:
+ struct UeInfo
+ {
+ uint64_t sti{};
+ InetAddress address;
+ int64_t lastSeen{};
+ };
+
+ private:
+ std::unique_ptr m_logger;
+ udp::UdpServer *m_server;
+ NtsTask *m_ctlTask;
+ uint64_t m_sti;
+ Vector3 m_phyLocation;
+ int64_t m_lastLoop;
+ std::unordered_map m_stiToUe;
+ std::unordered_map m_ueMap;
+ int m_newIdCounter;
+
+ public:
+ explicit RlsUdpTask(TaskBase *base, uint64_t sti, Vector3 phyLocation);
+ ~RlsUdpTask() override = default;
+
+ protected:
+ void onStart() override;
+ void onLoop() override;
+ void onQuit() override;
+
+ private:
+ void receiveRlsPdu(const InetAddress &addr, std::unique_ptr &&msg);
+ void sendRlsPdu(const InetAddress &addr, const rls::RlsMessage &msg);
+ void heartbeatCycle(int64_t time);
+
+ public:
+ void initialize(NtsTask *ctlTask);
+ void send(int ueId, const rls::RlsMessage &msg);
+};
+
+} // namespace nr::gnb
diff --git a/src/gnb/rrc/broadcast.cpp b/src/gnb/rrc/broadcast.cpp
new file mode 100644
index 000000000..3a24d6804
--- /dev/null
+++ b/src/gnb/rrc/broadcast.cpp
@@ -0,0 +1,122 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "task.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace nr::gnb
+{
+
+static ASN_RRC_BCCH_BCH_Message *ConstructMibMessage(bool barred, bool intraFreqReselectAllowed)
+{
+ auto *pdu = asn::New();
+ pdu->message.present = ASN_RRC_BCCH_BCH_MessageType_PR_mib;
+ pdu->message.choice.mib = asn::New();
+
+ auto &mib = *pdu->message.choice.mib;
+
+ asn::SetBitStringInt<6>(0, mib.systemFrameNumber);
+ mib.subCarrierSpacingCommon = ASN_RRC_MIB__subCarrierSpacingCommon_scs15or60;
+ mib.ssb_SubcarrierOffset = 0;
+ mib.dmrs_TypeA_Position = ASN_RRC_MIB__dmrs_TypeA_Position_pos2;
+ mib.cellBarred = barred ? ASN_RRC_MIB__cellBarred_barred : ASN_RRC_MIB__cellBarred_notBarred;
+ mib.intraFreqReselection = intraFreqReselectAllowed ? ASN_RRC_MIB__intraFreqReselection_allowed
+ : ASN_RRC_MIB__intraFreqReselection_notAllowed;
+ asn::SetBitStringInt<1>(0, mib.spare);
+ mib.pdcch_ConfigSIB1.controlResourceSetZero = 0;
+ mib.pdcch_ConfigSIB1.searchSpaceZero = 0;
+ return pdu;
+}
+
+static ASN_RRC_BCCH_DL_SCH_Message *ConstructSib1Message(bool cellReserved, int tac, int64_t nci, const Plmn &plmn,
+ const UacAiBarringSet &aiBarringSet)
+{
+ auto *pdu = asn::New();
+ pdu->message.present = ASN_RRC_BCCH_DL_SCH_MessageType_PR_c1;
+ pdu->message.choice.c1 = asn::NewFor(pdu->message.choice.c1);
+ pdu->message.choice.c1->present = ASN_RRC_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1;
+ pdu->message.choice.c1->choice.systemInformationBlockType1 = asn::New();
+
+ auto &sib1 = *pdu->message.choice.c1->choice.systemInformationBlockType1;
+
+ if (cellReserved)
+ {
+ asn::MakeNew(sib1.cellAccessRelatedInfo.cellReservedForOtherUse);
+ *sib1.cellAccessRelatedInfo.cellReservedForOtherUse =
+ ASN_RRC_CellAccessRelatedInfo__cellReservedForOtherUse_true;
+ }
+
+ auto *plmnInfo = asn::New();
+ plmnInfo->cellReservedForOperatorUse = cellReserved
+ ? ASN_RRC_PLMN_IdentityInfo__cellReservedForOperatorUse_reserved
+ : ASN_RRC_PLMN_IdentityInfo__cellReservedForOperatorUse_notReserved;
+ asn::MakeNew(plmnInfo->trackingAreaCode);
+ asn::SetBitStringInt<24>(tac, *plmnInfo->trackingAreaCode);
+ asn::SetBitStringLong<36>(nci, plmnInfo->cellIdentity);
+ asn::SequenceAdd(plmnInfo->plmn_IdentityList, asn::rrc::NewPlmnId(plmn));
+ asn::SequenceAdd(sib1.cellAccessRelatedInfo.plmn_IdentityList, plmnInfo);
+
+ asn::MakeNew(sib1.uac_BarringInfo);
+
+ auto *info = asn::New();
+ info->uac_BarringFactor = ASN_RRC_UAC_BarringInfoSet__uac_BarringFactor_p50;
+ info->uac_BarringTime = ASN_RRC_UAC_BarringInfoSet__uac_BarringTime_s4;
+
+ asn::SetBitStringInt<7>(bits::Consequential8(false, aiBarringSet.ai1, aiBarringSet.ai2, aiBarringSet.ai11,
+ aiBarringSet.ai12, aiBarringSet.ai13, aiBarringSet.ai14,
+ aiBarringSet.ai15),
+ info->uac_BarringForAccessIdentity);
+
+ asn::SequenceAdd(sib1.uac_BarringInfo->uac_BarringInfoSetList, info);
+
+ asn::MakeNew(sib1.uac_BarringInfo->uac_BarringForCommon);
+
+ for (size_t i = 0; i < 63; i++)
+ {
+ auto *item = asn::New();
+ item->accessCategory = static_cast(i + 1);
+ item->uac_barringInfoSetIndex = 1;
+
+ asn::SequenceAdd(*sib1.uac_BarringInfo->uac_BarringForCommon, item);
+ }
+
+ return pdu;
+}
+
+void GnbRrcTask::onBroadcastTimerExpired()
+{
+ triggerSysInfoBroadcast();
+}
+
+void GnbRrcTask::triggerSysInfoBroadcast()
+{
+ auto *mib = ConstructMibMessage(m_isBarred, m_intraFreqReselectAllowed);
+ auto *sib1 = ConstructSib1Message(m_cellReserved, m_config->tac, m_config->nci, m_config->plmn, m_aiBarringSet);
+
+ sendRrcMessage(mib);
+ sendRrcMessage(sib1);
+
+ asn::Free(asn_DEF_ASN_RRC_BCCH_BCH_Message, mib);
+ asn::Free(asn_DEF_ASN_RRC_BCCH_DL_SCH_Message, sib1);
+}
+
+} // namespace nr::gnb
\ No newline at end of file
diff --git a/src/gnb/rrc/channel.cpp b/src/gnb/rrc/channel.cpp
index cf6c0635c..fc89756dc 100644
--- a/src/gnb/rrc/channel.cpp
+++ b/src/gnb/rrc/channel.cpp
@@ -65,7 +65,7 @@ void GnbRrcTask::handleUplinkRrc(int ueId, rrc::RrcChannel channel, const OctetS
}
}
-void GnbRrcTask::sendRrcMessage(int ueId, ASN_RRC_BCCH_BCH_Message *msg)
+void GnbRrcTask::sendRrcMessage(ASN_RRC_BCCH_BCH_Message *msg)
{
OctetString pdu = rrc::encode::EncodeS(asn_DEF_ASN_RRC_BCCH_BCH_Message, msg);
if (pdu.length() == 0)
@@ -74,14 +74,14 @@ void GnbRrcTask::sendRrcMessage(int ueId, ASN_RRC_BCCH_BCH_Message *msg)
return;
}
- auto *w = new NwGnbRrcToRls(NwGnbRrcToRls::RRC_PDU_DELIVERY);
- w->ueId = ueId;
+ auto *w = new NmGnbRrcToRls(NmGnbRrcToRls::RRC_PDU_DELIVERY);
+ w->ueId = 0;
w->channel = rrc::RrcChannel::BCCH_BCH;
w->pdu = std::move(pdu);
m_base->rlsTask->push(w);
}
-void GnbRrcTask::sendRrcMessage(int ueId, ASN_RRC_BCCH_DL_SCH_Message *msg)
+void GnbRrcTask::sendRrcMessage(ASN_RRC_BCCH_DL_SCH_Message *msg)
{
OctetString pdu = rrc::encode::EncodeS(asn_DEF_ASN_RRC_BCCH_DL_SCH_Message, msg);
if (pdu.length() == 0)
@@ -90,8 +90,8 @@ void GnbRrcTask::sendRrcMessage(int ueId, ASN_RRC_BCCH_DL_SCH_Message *msg)
return;
}
- auto *w = new NwGnbRrcToRls(NwGnbRrcToRls::RRC_PDU_DELIVERY);
- w->ueId = ueId;
+ auto *w = new NmGnbRrcToRls(NmGnbRrcToRls::RRC_PDU_DELIVERY);
+ w->ueId = 0;
w->channel = rrc::RrcChannel::BCCH_DL_SCH;
w->pdu = std::move(pdu);
m_base->rlsTask->push(w);
@@ -106,7 +106,7 @@ void GnbRrcTask::sendRrcMessage(int ueId, ASN_RRC_DL_CCCH_Message *msg)
return;
}
- auto *w = new NwGnbRrcToRls(NwGnbRrcToRls::RRC_PDU_DELIVERY);
+ auto *w = new NmGnbRrcToRls(NmGnbRrcToRls::RRC_PDU_DELIVERY);
w->ueId = ueId;
w->channel = rrc::RrcChannel::DL_CCCH;
w->pdu = std::move(pdu);
@@ -122,7 +122,7 @@ void GnbRrcTask::sendRrcMessage(int ueId, ASN_RRC_DL_DCCH_Message *msg)
return;
}
- auto *w = new NwGnbRrcToRls(NwGnbRrcToRls::RRC_PDU_DELIVERY);
+ auto *w = new NmGnbRrcToRls(NmGnbRrcToRls::RRC_PDU_DELIVERY);
w->ueId = ueId;
w->channel = rrc::RrcChannel::DL_DCCH;
w->pdu = std::move(pdu);
@@ -138,7 +138,7 @@ void GnbRrcTask::sendRrcMessage(ASN_RRC_PCCH_Message *msg)
return;
}
- auto *w = new NwGnbRrcToRls(NwGnbRrcToRls::RRC_PDU_DELIVERY);
+ auto *w = new NmGnbRrcToRls(NmGnbRrcToRls::RRC_PDU_DELIVERY);
w->ueId = 0;
w->channel = rrc::RrcChannel::PCCH;
w->pdu = std::move(pdu);
diff --git a/src/gnb/rrc/connection.cpp b/src/gnb/rrc/connection.cpp
new file mode 100644
index 000000000..e95c956c4
--- /dev/null
+++ b/src/gnb/rrc/connection.cpp
@@ -0,0 +1,110 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "task.hpp"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace nr::gnb
+{
+
+void GnbRrcTask::receiveRrcSetupRequest(int ueId, const ASN_RRC_RRCSetupRequest &msg)
+{
+ auto *ue = tryFindUe(ueId);
+ if (ue)
+ {
+ // TODO: handle this more properly
+ m_logger->warn("Discarding RRC Setup Request, UE context already exists");
+ return;
+ }
+
+ if (msg.rrcSetupRequest.ue_Identity.present == ASN_RRC_InitialUE_Identity_PR_ng_5G_S_TMSI_Part1)
+ {
+ m_logger->err("RRC Setup Request with TMSI not implemented yet");
+ return;
+ }
+
+ if (msg.rrcSetupRequest.ue_Identity.present != ASN_RRC_InitialUE_Identity_PR_randomValue)
+ {
+ m_logger->err("Bad constructed RRC message ignored");
+ return;
+ }
+
+ int64_t initialRandomId = asn::GetBitStringLong<39>(msg.rrcSetupRequest.ue_Identity.choice.randomValue);
+ if (tryFindByInitialRandomId(initialRandomId) != nullptr)
+ {
+ m_logger->err("Initial random ID conflict [%ld], discarding RRC Setup Request", initialRandomId);
+ return;
+ }
+
+ ue = createUe(ueId);
+ ue->initialRandomId = initialRandomId;
+ ue->establishmentCause = msg.rrcSetupRequest.establishmentCause;
+
+ // Prepare RRC Setup
+ auto *pdu = asn::New();
+ pdu->message.present = ASN_RRC_DL_CCCH_MessageType_PR_c1;
+ pdu->message.choice.c1 = asn::NewFor(pdu->message.choice.c1);
+ pdu->message.choice.c1->present = ASN_RRC_DL_CCCH_MessageType__c1_PR_rrcSetup;
+ auto &rrcSetup = pdu->message.choice.c1->choice.rrcSetup = asn::New();
+ rrcSetup->rrc_TransactionIdentifier = getNextTid();
+ rrcSetup->criticalExtensions.present = ASN_RRC_RRCSetup__criticalExtensions_PR_rrcSetup;
+ auto &rrcSetupIEs = rrcSetup->criticalExtensions.choice.rrcSetup = asn::New();
+
+ ASN_RRC_CellGroupConfig masterCellGroup{};
+ masterCellGroup.cellGroupId = 0;
+
+ asn::SetOctetString(rrcSetupIEs->masterCellGroup,
+ rrc::encode::EncodeS(asn_DEF_ASN_RRC_CellGroupConfig, &masterCellGroup));
+
+ m_logger->info("RRC Setup for UE[%d]", ueId);
+ sendRrcMessage(ueId, pdu);
+}
+
+void GnbRrcTask::receiveRrcSetupComplete(int ueId, const ASN_RRC_RRCSetupComplete &msg)
+{
+ auto *ue = findUe(ueId);
+ if (!ue)
+ return;
+
+ auto setupComplete = msg.criticalExtensions.choice.rrcSetupComplete;
+
+ auto *w = new NmGnbRrcToNgap(NmGnbRrcToNgap::INITIAL_NAS_DELIVERY);
+ w->ueId = ueId;
+ w->pdu = asn::GetOctetString(setupComplete->dedicatedNAS_Message);
+ w->rrcEstablishmentCause = ue->establishmentCause;
+ m_base->ngapTask->push(w);
+}
+
+} // namespace nr::gnb
diff --git a/src/gnb/rrc/handler.cpp b/src/gnb/rrc/handler.cpp
index 300e7b15c..04d42e6de 100644
--- a/src/gnb/rrc/handler.cpp
+++ b/src/gnb/rrc/handler.cpp
@@ -59,7 +59,7 @@ void GnbRrcTask::handleDownlinkNasDelivery(int ueId, const OctetString &nasPdu)
void GnbRrcTask::deliverUplinkNas(int ueId, OctetString &&nasPdu)
{
- auto *w = new NwGnbRrcToNgap(NwGnbRrcToNgap::UPLINK_NAS_DELIVERY);
+ auto *w = new NmGnbRrcToNgap(NmGnbRrcToNgap::UPLINK_NAS_DELIVERY);
w->ueId = ueId;
w->pdu = std::move(nasPdu);
m_base->ngapTask->push(w);
@@ -72,76 +72,6 @@ void GnbRrcTask::receiveUplinkInformationTransfer(int ueId, const ASN_RRC_ULInfo
ueId, asn::GetOctetString(*msg.criticalExtensions.choice.ulInformationTransfer->dedicatedNAS_Message));
}
-void GnbRrcTask::receiveRrcSetupRequest(int ueId, const ASN_RRC_RRCSetupRequest &msg)
-{
- auto *ue = tryFindUe(ueId);
- if (ue)
- {
- m_logger->warn("Discarding RRC Setup Request, UE context already exists");
- return;
- }
-
- if (msg.rrcSetupRequest.ue_Identity.present == ASN_RRC_InitialUE_Identity_PR_ng_5G_S_TMSI_Part1)
- {
- m_logger->err("RRC Setup Request with TMSI not implemented yet");
- return;
- }
-
- if (msg.rrcSetupRequest.ue_Identity.present != ASN_RRC_InitialUE_Identity_PR_randomValue)
- {
- m_logger->err("Bad message");
- return;
- }
-
- int64_t initialRandomId = asn::GetBitStringLong<39>(msg.rrcSetupRequest.ue_Identity.choice.randomValue);
- if (tryFindByInitialRandomId(initialRandomId) != nullptr)
- {
- m_logger->err("Initial random ID conflict [%ld], discarding RRC Setup Request", initialRandomId);
- return;
- }
-
- ue = createUe(ueId);
- ue->initialRandomId = initialRandomId;
- ue->establishmentCause = msg.rrcSetupRequest.establishmentCause;
-
- // Prepare RRC Setup
- auto *pdu = asn::New();
- pdu->message.present = ASN_RRC_DL_CCCH_MessageType_PR_c1;
- pdu->message.choice.c1 = asn::NewFor(pdu->message.choice.c1);
- pdu->message.choice.c1->present = ASN_RRC_DL_CCCH_MessageType__c1_PR_rrcSetup;
- auto &rrcSetup = pdu->message.choice.c1->choice.rrcSetup = asn::New();
- rrcSetup->rrc_TransactionIdentifier = getNextTid();
- rrcSetup->criticalExtensions.present = ASN_RRC_RRCSetup__criticalExtensions_PR_rrcSetup;
- auto &rrcSetupIEs = rrcSetup->criticalExtensions.choice.rrcSetup = asn::New();
-
- ASN_RRC_CellGroupConfig masterCellGroup{};
- masterCellGroup.cellGroupId = 0;
-
- asn::SetOctetString(rrcSetupIEs->masterCellGroup,
- rrc::encode::EncodeS(asn_DEF_ASN_RRC_CellGroupConfig, &masterCellGroup));
-
- m_logger->info("RRC Setup for UE[%d]", ueId);
- sendRrcMessage(ueId, pdu);
-}
-
-void GnbRrcTask::receiveRrcSetupComplete(int ueId, const ASN_RRC_RRCSetupComplete &msg)
-{
- if (msg.criticalExtensions.present != ASN_RRC_RRCSetupComplete__criticalExtensions_PR_rrcSetupComplete)
- return;
-
- auto *ue = findUe(ueId);
- if (!ue)
- return;
-
- auto setupComplete = msg.criticalExtensions.choice.rrcSetupComplete;
-
- auto *w = new NwGnbRrcToNgap(NwGnbRrcToNgap::INITIAL_NAS_DELIVERY);
- w->ueId = ueId;
- w->pdu = asn::GetOctetString(setupComplete->dedicatedNAS_Message);
- w->rrcEstablishmentCause = ue->establishmentCause;
- m_base->ngapTask->push(w);
-}
-
void GnbRrcTask::releaseConnection(int ueId)
{
m_logger->info("Releasing RRC connection for UE[%d]", ueId);
@@ -165,7 +95,7 @@ void GnbRrcTask::releaseConnection(int ueId)
void GnbRrcTask::handleRadioLinkFailure(int ueId)
{
// Notify NGAP task
- auto *w = new NwGnbRrcToNgap(NwGnbRrcToNgap::RADIO_LINK_FAILURE);
+ auto *w = new NmGnbRrcToNgap(NmGnbRrcToNgap::RADIO_LINK_FAILURE);
w->ueId = ueId;
m_base->ngapTask->push(w);
diff --git a/src/gnb/rrc/management.cpp b/src/gnb/rrc/management.cpp
index 7740317e1..d6765725c 100644
--- a/src/gnb/rrc/management.cpp
+++ b/src/gnb/rrc/management.cpp
@@ -11,31 +11,6 @@
namespace nr::gnb
{
-RrcUeContext *GnbRrcTask::tryFindUe(int id)
-{
- if (m_ueCtx.count(id))
- return m_ueCtx[id];
- return nullptr;
-}
-
-RrcUeContext *GnbRrcTask::findUe(int id)
-{
- auto *ue = tryFindUe(id);
- if (ue == nullptr)
- {
- m_logger->err("UE context with ID[%d] not found", id);
- return ue;
- }
- return ue;
-}
-
-RrcUeContext *GnbRrcTask::createUe(int id)
-{
- auto *ctx = new RrcUeContext(id);
- m_ueCtx[id] = ctx;
- return ctx;
-}
-
RrcUeContext *GnbRrcTask::tryFindByInitialRandomId(int64_t id)
{
if (id == -1)
diff --git a/src/gnb/rrc/sap.cpp b/src/gnb/rrc/sap.cpp
new file mode 100644
index 000000000..c21b96802
--- /dev/null
+++ b/src/gnb/rrc/sap.cpp
@@ -0,0 +1,33 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "task.hpp"
+
+#include
+#include
+
+namespace nr::gnb
+{
+
+void GnbRrcTask::handleRlsSapMessage(NmGnbRlsToRrc &msg)
+{
+ switch (msg.present)
+ {
+ case NmGnbRlsToRrc::SIGNAL_DETECTED: {
+ m_logger->debug("UE[%d] new signal detected", msg.ueId);
+ triggerSysInfoBroadcast();
+ break;
+ }
+ case NmGnbRlsToRrc::UPLINK_RRC: {
+ handleUplinkRrc(msg.ueId, msg.rrcChannel, msg.data);
+ break;
+ }
+ }
+}
+
+} // namespace nr::gnb
diff --git a/src/gnb/rrc/task.cpp b/src/gnb/rrc/task.cpp
index 1ef21ba3f..e10837c12 100644
--- a/src/gnb/rrc/task.cpp
+++ b/src/gnb/rrc/task.cpp
@@ -15,16 +15,21 @@
#include
#include
+static constexpr const int TIMER_ID_SI_BROADCAST = 1;
+static constexpr const int TIMER_PERIOD_SI_BROADCAST = 10'000;
+
namespace nr::gnb
{
GnbRrcTask::GnbRrcTask(TaskBase *base) : m_base{base}, m_ueCtx{}, m_tidCounter{}
{
m_logger = base->logBase->makeUniqueLogger("rrc");
+ m_config = m_base->config;
}
void GnbRrcTask::onStart()
{
+ setTimer(TIMER_ID_SI_BROADCAST, TIMER_PERIOD_SI_BROADCAST);
}
void GnbRrcTask::onQuit()
@@ -41,42 +46,41 @@ void GnbRrcTask::onLoop()
switch (msg->msgType)
{
case NtsMessageType::GNB_RLS_TO_RRC: {
- auto *w = dynamic_cast(msg);
- switch (w->present)
- {
- case NwGnbRlsToRrc::RRC_PDU_DELIVERY: {
- handleUplinkRrc(w->ueId, w->channel, w->pdu);
- break;
- }
- case NwGnbRlsToRrc::SIGNAL_LOST: {
- handleRadioLinkFailure(w->ueId);
- break;
- }
- }
+ handleRlsSapMessage(*dynamic_cast(msg));
break;
}
case NtsMessageType::GNB_NGAP_TO_RRC: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbNgapToRrc::RADIO_POWER_ON: {
- m_base->rlsTask->push(new NwGnbRrcToRls(NwGnbRrcToRls::RADIO_POWER_ON));
+ case NmGnbNgapToRrc::RADIO_POWER_ON: {
+ m_isBarred = false;
+ triggerSysInfoBroadcast();
break;
}
- case NwGnbNgapToRrc::NAS_DELIVERY: {
+ case NmGnbNgapToRrc::NAS_DELIVERY: {
handleDownlinkNasDelivery(w->ueId, w->pdu);
break;
}
- case NwGnbNgapToRrc::AN_RELEASE: {
+ case NmGnbNgapToRrc::AN_RELEASE: {
releaseConnection(w->ueId);
break;
}
- case NwGnbNgapToRrc::PAGING:
+ case NmGnbNgapToRrc::PAGING:
handlePaging(w->uePagingTmsi, w->taiListForPaging);
break;
}
break;
}
+ case NtsMessageType::TIMER_EXPIRED: {
+ auto *w = dynamic_cast(msg);
+ if (w->timerId == TIMER_ID_SI_BROADCAST)
+ {
+ setTimer(TIMER_ID_SI_BROADCAST, TIMER_PERIOD_SI_BROADCAST);
+ onBroadcastTimerExpired();
+ }
+ break;
+ }
default:
m_logger->unhandledNts(msg);
break;
diff --git a/src/gnb/rrc/task.hpp b/src/gnb/rrc/task.hpp
index acc3aaae3..e33ca4c11 100644
--- a/src/gnb/rrc/task.hpp
+++ b/src/gnb/rrc/task.hpp
@@ -42,10 +42,17 @@ class GnbRrcTask : public NtsTask
{
private:
TaskBase *m_base;
+ GnbConfig *m_config;
std::unique_ptr m_logger;
+
std::unordered_map m_ueCtx;
int m_tidCounter;
+ bool m_isBarred = true;
+ bool m_cellReserved = false;
+ UacAiBarringSet m_aiBarringSet = {};
+ bool m_intraFreqReselectAllowed = true;
+
friend class GnbCmdHandler;
public:
@@ -59,9 +66,6 @@ class GnbRrcTask : public NtsTask
private:
/* Management */
- RrcUeContext *tryFindUe(int id);
- RrcUeContext *findUe(int id);
- RrcUeContext *createUe(int id);
RrcUeContext *tryFindByInitialRandomId(int64_t id);
int getNextTid();
@@ -75,12 +79,10 @@ class GnbRrcTask : public NtsTask
const asn::Unique &taiList);
void receiveUplinkInformationTransfer(int ueId, const ASN_RRC_ULInformationTransfer &msg);
- void receiveRrcSetupRequest(int ueId, const ASN_RRC_RRCSetupRequest &msg);
- void receiveRrcSetupComplete(int ueId, const ASN_RRC_RRCSetupComplete &msg);
/* RRC channel send message */
- void sendRrcMessage(int ueId, ASN_RRC_BCCH_BCH_Message *msg);
- void sendRrcMessage(int ueId, ASN_RRC_BCCH_DL_SCH_Message *msg);
+ void sendRrcMessage(ASN_RRC_BCCH_BCH_Message *msg);
+ void sendRrcMessage(ASN_RRC_BCCH_DL_SCH_Message *msg);
void sendRrcMessage(int ueId, ASN_RRC_DL_CCCH_Message *msg);
void sendRrcMessage(int ueId, ASN_RRC_DL_DCCH_Message *msg);
void sendRrcMessage(ASN_RRC_PCCH_Message *msg);
@@ -90,6 +92,22 @@ class GnbRrcTask : public NtsTask
void receiveRrcMessage(int ueId, ASN_RRC_UL_CCCH_Message *msg);
void receiveRrcMessage(int ueId, ASN_RRC_UL_CCCH1_Message *msg);
void receiveRrcMessage(int ueId, ASN_RRC_UL_DCCH_Message *msg);
+
+ /* System Information Broadcast related */
+ void onBroadcastTimerExpired();
+ void triggerSysInfoBroadcast();
+
+ /* Service Access Point */
+ void handleRlsSapMessage(NmGnbRlsToRrc &msg);
+
+ /* UE Management */
+ RrcUeContext *createUe(int id);
+ RrcUeContext *tryFindUe(int id);
+ RrcUeContext *findUe(int id);
+
+ /* Connection Control */
+ void receiveRrcSetupRequest(int ueId, const ASN_RRC_RRCSetupRequest &msg);
+ void receiveRrcSetupComplete(int ueId, const ASN_RRC_RRCSetupComplete &msg);
};
} // namespace nr::gnb
diff --git a/src/gnb/rrc/ues.cpp b/src/gnb/rrc/ues.cpp
new file mode 100644
index 000000000..18a530c53
--- /dev/null
+++ b/src/gnb/rrc/ues.cpp
@@ -0,0 +1,42 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "task.hpp"
+
+#include
+#include
+
+namespace nr::gnb
+{
+
+RrcUeContext *GnbRrcTask::createUe(int id)
+{
+ auto *ctx = new RrcUeContext(id);
+ m_ueCtx[id] = ctx;
+ return ctx;
+}
+
+RrcUeContext *GnbRrcTask::tryFindUe(int id)
+{
+ if (m_ueCtx.count(id))
+ return m_ueCtx[id];
+ return nullptr;
+}
+
+RrcUeContext *GnbRrcTask::findUe(int id)
+{
+ auto *ue = tryFindUe(id);
+ if (ue == nullptr)
+ {
+ m_logger->err("UE context with ID[%d] not found", id);
+ return ue;
+ }
+ return ue;
+}
+
+} // namespace nr::gnb
diff --git a/src/gnb/sctp/task.cpp b/src/gnb/sctp/task.cpp
index 5cffa5e4e..18b71526b 100644
--- a/src/gnb/sctp/task.cpp
+++ b/src/gnb/sctp/task.cpp
@@ -55,7 +55,7 @@ class SctpHandler : public sctp::ISctpHandler
private:
void onAssociationSetup(int associationId, int inStreams, int outStreams) override
{
- auto *w = new NwGnbSctp(NwGnbSctp::ASSOCIATION_SETUP);
+ auto *w = new NmGnbSctp(NmGnbSctp::ASSOCIATION_SETUP);
w->clientId = clientId;
w->associationId = associationId;
w->inStreams = inStreams;
@@ -65,7 +65,7 @@ class SctpHandler : public sctp::ISctpHandler
void onAssociationShutdown() override
{
- auto *w = new NwGnbSctp(NwGnbSctp::ASSOCIATION_SHUTDOWN);
+ auto *w = new NmGnbSctp(NmGnbSctp::ASSOCIATION_SHUTDOWN);
w->clientId = clientId;
sctpTask->push(w);
}
@@ -75,7 +75,7 @@ class SctpHandler : public sctp::ISctpHandler
auto *data = new uint8_t[length];
std::memcpy(data, buffer, length);
- auto *w = new NwGnbSctp(NwGnbSctp::RECEIVE_MESSAGE);
+ auto *w = new NmGnbSctp(NmGnbSctp::RECEIVE_MESSAGE);
w->clientId = clientId;
w->buffer = UniqueBuffer{data, length};
w->stream = stream;
@@ -84,7 +84,7 @@ class SctpHandler : public sctp::ISctpHandler
void onUnhandledNotification() override
{
- auto *w = new NwGnbSctp(NwGnbSctp::UNHANDLED_NOTIFICATION);
+ auto *w = new NmGnbSctp(NmGnbSctp::UNHANDLED_NOTIFICATION);
w->clientId = clientId;
sctpTask->push(w);
}
@@ -119,35 +119,35 @@ void SctpTask::onLoop()
switch (msg->msgType)
{
case NtsMessageType::GNB_SCTP: {
- auto *w = dynamic_cast(msg);
+ auto *w = dynamic_cast(msg);
switch (w->present)
{
- case NwGnbSctp::CONNECTION_REQUEST: {
+ case NmGnbSctp::CONNECTION_REQUEST: {
receiveSctpConnectionSetupRequest(w->clientId, w->localAddress, w->localPort, w->remoteAddress,
w->remotePort, w->ppid, w->associatedTask);
break;
}
- case NwGnbSctp::CONNECTION_CLOSE: {
+ case NmGnbSctp::CONNECTION_CLOSE: {
receiveConnectionClose(w->clientId);
break;
}
- case NwGnbSctp::ASSOCIATION_SETUP: {
+ case NmGnbSctp::ASSOCIATION_SETUP: {
receiveAssociationSetup(w->clientId, w->associationId, w->inStreams, w->outStreams);
break;
}
- case NwGnbSctp::ASSOCIATION_SHUTDOWN: {
+ case NmGnbSctp::ASSOCIATION_SHUTDOWN: {
receiveAssociationShutdown(w->clientId);
break;
}
- case NwGnbSctp::RECEIVE_MESSAGE: {
+ case NmGnbSctp::RECEIVE_MESSAGE: {
receiveClientReceive(w->clientId, w->stream, std::move(w->buffer));
break;
}
- case NwGnbSctp::SEND_MESSAGE: {
+ case NmGnbSctp::SEND_MESSAGE: {
receiveSendMessage(w->clientId, w->stream, std::move(w->buffer));
break;
}
- case NwGnbSctp::UNHANDLED_NOTIFICATION: {
+ case NmGnbSctp::UNHANDLED_NOTIFICATION: {
receiveUnhandledNotification(w->clientId);
break;
}
@@ -242,7 +242,7 @@ void SctpTask::receiveAssociationSetup(int clientId, int associationId, int inSt
}
// Notify the relevant task
- auto *msg = new NwGnbSctp(NwGnbSctp::ASSOCIATION_SETUP);
+ auto *msg = new NmGnbSctp(NmGnbSctp::ASSOCIATION_SETUP);
msg->clientId = clientId;
msg->associationId = associationId;
msg->inStreams = inStreams;
@@ -262,7 +262,7 @@ void SctpTask::receiveAssociationShutdown(int clientId)
}
// Notify the relevant task
- auto *msg = new NwGnbSctp(NwGnbSctp::ASSOCIATION_SHUTDOWN);
+ auto *msg = new NmGnbSctp(NmGnbSctp::ASSOCIATION_SHUTDOWN);
msg->clientId = clientId;
entry->associatedTask->push(msg);
}
@@ -277,7 +277,7 @@ void SctpTask::receiveClientReceive(int clientId, uint16_t stream, UniqueBuffer
}
// Notify the relevant task
- auto *msg = new NwGnbSctp(NwGnbSctp::RECEIVE_MESSAGE);
+ auto *msg = new NmGnbSctp(NmGnbSctp::RECEIVE_MESSAGE);
msg->clientId = clientId;
msg->stream = stream;
msg->buffer = std::move(buffer);
diff --git a/src/lib/app/cli_cmd.cpp b/src/lib/app/cli_cmd.cpp
index af3fa28e4..5a0b847a3 100644
--- a/src/lib/app/cli_cmd.cpp
+++ b/src/lib/app/cli_cmd.cpp
@@ -158,13 +158,15 @@ static OrderedMap g_ueCmdEntries = {
{"info", {"Show some information about the UE", "", DefaultDesc, false}},
{"status", {"Show some status information about the UE", "", DefaultDesc, false}},
{"timers", {"Dump current status of the timers in the UE", "", DefaultDesc, false}},
+ {"rls-state", {"Show status information about RLS", "", DefaultDesc, false}},
+ {"coverage", {"Dump available cells and PLMNs in the coverage", "", DefaultDesc, false}},
{"ps-establish",
{"Trigger a PDU session establishment procedure", " [options]", DescForPsEstablish, true}},
+ {"ps-list", {"List all PDU sessions", "", DefaultDesc, false}},
{"ps-release", {"Trigger a PDU session release procedure", "...", DefaultDesc, true}},
{"ps-release-all", {"Trigger PDU session release procedures for all active sessions", "", DefaultDesc, false}},
{"deregister",
{"Perform a de-registration by the UE", "", DefaultDesc, true}},
- {"coverage", {"Show gNodeB cell coverage information", "", DefaultDesc, false}},
};
static std::unique_ptr GnbCliParseImpl(const std::string &subCmd, const opt::OptionsResult &options,
@@ -236,19 +238,20 @@ static std::unique_ptr UeCliParseImpl(const std::string &subCmd, c
else if (subCmd == "deregister")
{
auto cmd = std::make_unique(UeCliCommand::DE_REGISTER);
- cmd->deregCause = EDeregCause::UNSPECIFIED;
if (options.positionalCount() == 0)
CMD_ERR("De-registration type is expected")
if (options.positionalCount() > 1)
CMD_ERR("Only one de-registration type is expected")
auto type = options.getPositional(0);
- if (type == "switch-off")
+ if (type == "normal")
+ cmd->deregCause = EDeregCause::NORMAL;
+ else if (type == "switch-off")
cmd->deregCause = EDeregCause::SWITCH_OFF;
else if (type == "disable-5g")
cmd->deregCause = EDeregCause::DISABLE_5G;
else if (type == "remove-sim")
cmd->deregCause = EDeregCause::USIM_REMOVAL;
- else if (type != "normal")
+ else
CMD_ERR("Invalid de-registration type, possible values are: \"normal\", \"disable-5g\", \"switch-off\", "
"\"remove-sim\"")
return cmd;
@@ -316,6 +319,14 @@ static std::unique_ptr UeCliParseImpl(const std::string &subCmd, c
}
return cmd;
}
+ else if (subCmd == "ps-list")
+ {
+ return std::make_unique(UeCliCommand::PS_LIST);
+ }
+ else if (subCmd == "rls-state")
+ {
+ return std::make_unique(UeCliCommand::RLS_STATE);
+ }
else if (subCmd == "coverage")
{
return std::make_unique(UeCliCommand::COVERAGE);
diff --git a/src/lib/app/cli_cmd.hpp b/src/lib/app/cli_cmd.hpp
index 94dbb6fdd..49b32d891 100644
--- a/src/lib/app/cli_cmd.hpp
+++ b/src/lib/app/cli_cmd.hpp
@@ -52,7 +52,9 @@ struct UeCliCommand
PS_ESTABLISH,
PS_RELEASE,
PS_RELEASE_ALL,
+ PS_LIST,
DE_REGISTER,
+ RLS_STATE,
COVERAGE,
} present;
diff --git a/src/lib/app/monitor.hpp b/src/lib/app/monitor.hpp
index d8d599df9..848fefd4c 100644
--- a/src/lib/app/monitor.hpp
+++ b/src/lib/app/monitor.hpp
@@ -36,6 +36,7 @@ enum class StateType
RM,
CM,
U5,
+ RRC
};
class INodeListener
diff --git a/src/lib/asn/rrc.cpp b/src/lib/asn/rrc.cpp
new file mode 100644
index 000000000..ec5ce653d
--- /dev/null
+++ b/src/lib/asn/rrc.cpp
@@ -0,0 +1,77 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "rrc.hpp"
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+namespace asn::rrc
+{
+
+static int NthDigit(int number, int n)
+{
+ for (int i = 0; i < n; i++)
+ number /= 10;
+ return number % 10;
+}
+
+void SetPlmnId(const Plmn &source, ASN_RRC_PLMN_Identity &target)
+{
+ int mncDigits = source.isLongMnc ? 3 : 2;
+ for (int i = 0; i < mncDigits; i++)
+ asn::SequenceAdd(target.mnc, NewMccMncDigit(NthDigit(source.mnc, mncDigits - i - 1)));
+
+ target.mcc = asn::NewFor(target.mcc);
+
+ for (int i = 0; i < 3; i++)
+ asn::SequenceAdd(*target.mcc, NewMccMncDigit(NthDigit(source.mcc, 2 - i)));
+}
+
+ASN_RRC_PLMN_Identity *NewPlmnId(const Plmn &plmn)
+{
+ auto *value = asn::New();
+ SetPlmnId(plmn, *value);
+ return value;
+}
+
+ASN_RRC_MCC_MNC_Digit_t *NewMccMncDigit(int digit)
+{
+ auto *value = asn::New();
+ *value = digit;
+ return value;
+}
+
+Plmn GetPlmnId(const ASN_RRC_PLMN_Identity &value)
+{
+ if (value.mcc == nullptr)
+ throw std::runtime_error("");
+
+ Plmn plmn;
+
+ asn::ForeachItem(*value.mcc, [&plmn](auto &i) {
+ plmn.mcc *= 10;
+ plmn.mcc += static_cast(i);
+ });
+
+ asn::ForeachItem(value.mnc, [&plmn](auto &i) {
+ plmn.mnc *= 10;
+ plmn.mnc += static_cast(i);
+ });
+
+ plmn.isLongMnc = value.mnc.list.count == 3;
+
+ return plmn;
+}
+
+} // namespace asn::rrc
diff --git a/src/lib/asn/rrc.hpp b/src/lib/asn/rrc.hpp
new file mode 100644
index 000000000..a402030fb
--- /dev/null
+++ b/src/lib/asn/rrc.hpp
@@ -0,0 +1,24 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include
+
+#include
+
+namespace asn::rrc
+{
+
+void SetPlmnId(const Plmn &source, ASN_RRC_PLMN_Identity &target);
+
+ASN_RRC_PLMN_Identity *NewPlmnId(const Plmn &plmn);
+
+ASN_RRC_MCC_MNC_Digit_t *NewMccMncDigit(int digit);
+
+Plmn GetPlmnId(const ASN_RRC_PLMN_Identity& value);
+
+} // namespace asn::rrc
diff --git a/src/lib/asn/utils.hpp b/src/lib/asn/utils.hpp
index 1e4a2fef5..459458d48 100644
--- a/src/lib/asn/utils.hpp
+++ b/src/lib/asn/utils.hpp
@@ -43,6 +43,12 @@ inline T *NewFor(T *p)
return New::type>();
}
+template
+inline void MakeNew(T *&p)
+{
+ p = NewFor(p);
+}
+
template
inline void Free(asn_TYPE_descriptor_t &desc, T *ptr)
{
diff --git a/src/lib/nas/base.cpp b/src/lib/nas/base.cpp
index 07dce6c7e..8d288561e 100644
--- a/src/lib/nas/base.cpp
+++ b/src/lib/nas/base.cpp
@@ -36,7 +36,7 @@ void nas::EncodeBcdString(OctetString &stream, const std::string &bcd, size_t oc
if (skipFirst)
{
- for (int i = bcd.length(); i >= 1; i--)
+ for (size_t i = bcd.length(); i >= 1; i--)
halfOctets[i] = halfOctets[i - 1];
halfOctets[0] = skippedHalfOctet & 0xF;
}
diff --git a/src/lib/nas/enums.cpp b/src/lib/nas/enums.cpp
index 93ebff1f3..eadd0bd7a 100644
--- a/src/lib/nas/enums.cpp
+++ b/src/lib/nas/enums.cpp
@@ -7,3 +7,27 @@
//
#include "enums.hpp"
+
+namespace nas
+{
+
+Json ToJson(const EPduSessionType &v)
+{
+ switch (v)
+ {
+ case EPduSessionType::IPV4:
+ return "IPv4";
+ case EPduSessionType::IPV6:
+ return "IPv6";
+ case EPduSessionType::IPV4V6:
+ return "IPv4v6";
+ case EPduSessionType::UNSTRUCTURED:
+ return "unstructured";
+ case EPduSessionType::ETHERNET:
+ return "ethernet";
+ default:
+ return "?";
+ }
+}
+
+} // namespace nas
diff --git a/src/lib/nas/enums.hpp b/src/lib/nas/enums.hpp
index d810aa58a..4c6767ebc 100644
--- a/src/lib/nas/enums.hpp
+++ b/src/lib/nas/enums.hpp
@@ -8,6 +8,8 @@
#pragma once
+#include
+
namespace nas
{
@@ -750,4 +752,6 @@ enum class EQoSOperationCode
MODIFY_EXISTING = 0b011,
};
+Json ToJson(const EPduSessionType &v);
+
} // namespace nas
\ No newline at end of file
diff --git a/src/lib/nas/ie3.cpp b/src/lib/nas/ie3.cpp
index 75897087e..0d7360a07 100644
--- a/src/lib/nas/ie3.cpp
+++ b/src/lib/nas/ie3.cpp
@@ -32,6 +32,11 @@ IE5gsTrackingAreaIdentity::IE5gsTrackingAreaIdentity(int mcc, int mnc, bool isLo
{
}
+IE5gsTrackingAreaIdentity::IE5gsTrackingAreaIdentity(const Tai &tai)
+ : mcc(tai.plmn.mcc), mnc(tai.plmn.mnc), isLongMnc(tai.plmn.isLongMnc), trackingAreaCode(tai.tac)
+{
+}
+
IE5gsTrackingAreaIdentity IE5gsTrackingAreaIdentity::Decode(const OctetView &stream)
{
auto plmn = VPlmn::Decode(stream);
diff --git a/src/lib/nas/ie3.hpp b/src/lib/nas/ie3.hpp
index 19885d2a6..7aa9982ad 100644
--- a/src/lib/nas/ie3.hpp
+++ b/src/lib/nas/ie3.hpp
@@ -34,6 +34,7 @@ struct IE5gsTrackingAreaIdentity : InformationElement3
IE5gsTrackingAreaIdentity() = default;
IE5gsTrackingAreaIdentity(int mcc, int mnc, bool isLongMnc, const octet3 &trackingAreaCode);
+ explicit IE5gsTrackingAreaIdentity(const Tai &tai);
static IE5gsTrackingAreaIdentity Decode(const OctetView &stream);
static void Encode(const IE5gsTrackingAreaIdentity &ie, OctetString &stream);
diff --git a/src/lib/nas/ie4.cpp b/src/lib/nas/ie4.cpp
index 5a6e5ea14..b5df744bf 100644
--- a/src/lib/nas/ie4.cpp
+++ b/src/lib/nas/ie4.cpp
@@ -8,6 +8,8 @@
#include "ie4.hpp"
+#include
+
namespace nas
{
@@ -1075,4 +1077,43 @@ void IE5gsTrackingAreaIdentityList::Encode(const IE5gsTrackingAreaIdentityList &
VPartialTrackingAreaIdentityList::Encode(x, stream);
}
+Json ToJson(const IEPduAddress &v)
+{
+ switch (v.sessionType)
+ {
+ case EPduSessionType::IPV4:
+ case EPduSessionType::IPV6:
+ case EPduSessionType::IPV4V6:
+ return utils::OctetStringToIp(v.pduAddressInformation);
+ case EPduSessionType::UNSTRUCTURED:
+ case EPduSessionType::ETHERNET:
+ return v.pduAddressInformation.toHexString();
+ default:
+ return "?";
+ }
+}
+
+Json ToJson(const IESessionAmbr &v)
+{
+ int downlinkValue = static_cast(v.sessionAmbrForDownlink);
+ int uplinkValue = static_cast(v.sessionAmbrForUplink);
+
+ int downlinkUnit = static_cast(v.unitForSessionAmbrForDownlink);
+ int uplinkUnit = static_cast(v.unitForSessionAmbrForUplink);
+
+ int downlinkFactor = 1 << (2 * ((downlinkUnit - 1) % 5));
+ int uplinkFactor = 1 << (2 * ((uplinkUnit - 1) % 5));
+
+ int downlinkMagnitude = (downlinkUnit - 1) / 5;
+ int uplinkMagnitude = (uplinkUnit - 1) / 5;
+
+ int downlink = downlinkValue * downlinkFactor;
+ int uplink = uplinkValue * uplinkFactor;
+
+ static const std::string units[5] = {"Kb/s", "Mb/s", "Gb/s", "Tb/s", "Pb/s"};
+
+ return "up[" + std::to_string(uplink) + units[uplinkMagnitude] + "] down[" + std::to_string(downlink) +
+ units[downlinkMagnitude] + "]";
+}
+
} // namespace nas
\ No newline at end of file
diff --git a/src/lib/nas/ie4.hpp b/src/lib/nas/ie4.hpp
index b191f3ed9..1406054fe 100644
--- a/src/lib/nas/ie4.hpp
+++ b/src/lib/nas/ie4.hpp
@@ -14,6 +14,8 @@
#include
#include
+#include
+
namespace nas
{
@@ -570,4 +572,7 @@ struct IE5gsTrackingAreaIdentityList : InformationElement4
static void Encode(const IE5gsTrackingAreaIdentityList &ie, OctetString &stream);
};
+Json ToJson(const IEPduAddress &v);
+Json ToJson(const IESessionAmbr &v);
+
} // namespace nas
diff --git a/src/lib/nas/ie6.cpp b/src/lib/nas/ie6.cpp
index 1102496b0..54cd8b03a 100644
--- a/src/lib/nas/ie6.cpp
+++ b/src/lib/nas/ie6.cpp
@@ -448,7 +448,7 @@ Json ToJson(const IE5gsMobileIdentity &v)
switch (v.type)
{
case EIdentityType::NO_IDENTITY:
- return "no-identitiy";
+ return "no-identity";
case EIdentityType::SUCI: {
switch (v.supiFormat)
{
diff --git a/src/lib/nas/storage.cpp b/src/lib/nas/storage.cpp
new file mode 100644
index 000000000..6712838d6
--- /dev/null
+++ b/src/lib/nas/storage.cpp
@@ -0,0 +1,14 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "storage.hpp"
+
+namespace nas
+{
+
+}
\ No newline at end of file
diff --git a/src/lib/nas/storage.hpp b/src/lib/nas/storage.hpp
new file mode 100644
index 000000000..3c0f3a82d
--- /dev/null
+++ b/src/lib/nas/storage.hpp
@@ -0,0 +1,281 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace nas
+{
+
+// TODO: Periodun sonuna geldiğinde erişilmezse, (autoClearIfNecessary çağrılmazsa) delete yapılmaz backup çalışmaz
+
+/*
+ * - Items are unique, if already exists, deletes the previous one
+ * - List have fixed size, if capacity is full, oldest item is deleted
+ * - Automatically cleared after specified period
+ * - The list is NOT thread safe
+ */
+template
+class NasList
+{
+ public:
+ using backup_functor_type = std::function &buffer, size_t count)>;
+
+ private:
+ const size_t m_sizeLimit;
+ const int64_t m_autoClearingPeriod;
+ const std::optional m_backupFunctor;
+
+ std::vector m_data;
+ size_t m_size;
+ int64_t m_lastAutoCleared;
+
+ public:
+ NasList(size_t sizeLimit, int64_t autoClearingPeriod, std::optional backupFunctor)
+ : m_sizeLimit{sizeLimit}, m_autoClearingPeriod{autoClearingPeriod},
+ m_backupFunctor{backupFunctor}, m_data{sizeLimit}, m_size{}, m_lastAutoCleared{::utils::CurrentTimeMillis()}
+ {
+ }
+
+ NasList(const NasList &) = delete;
+ NasList(NasList &&) = delete;
+
+ public:
+ void add(const T &item)
+ {
+ autoClearIfNecessary();
+ remove(item);
+ makeSlotForNewItem();
+
+ m_data[m_size] = item;
+ m_size++;
+
+ touch();
+ }
+
+ void add(T &&item)
+ {
+ autoClearIfNecessary();
+ remove(item);
+ makeSlotForNewItem();
+
+ m_data[m_size] = std::move(item);
+ m_size++;
+
+ touch();
+ }
+
+ void remove(const T &item)
+ {
+ autoClearIfNecessary();
+
+ size_t index = ~0u;
+ for (size_t i = 0; i < m_size; i++)
+ {
+ if (m_data[i] == item)
+ {
+ index = i;
+ break;
+ }
+ }
+
+ if (index != ~0u)
+ removeAt(index);
+ }
+
+ bool contains(const T &item)
+ {
+ autoClearIfNecessary();
+
+ for (size_t i = 0; i < m_size; i++)
+ if (m_data[i] == item)
+ return true;
+ return false;
+ }
+
+ template
+ void forEach(Functor &&fun)
+ {
+ autoClearIfNecessary();
+
+ for (size_t i = 0; i < m_size; i++)
+ fun((const T &)m_data[i]);
+ }
+
+ template
+ void mutateForEach(Functor &&fun)
+ {
+ autoClearIfNecessary();
+
+ for (size_t i = 0; i < m_size; i++)
+ fun(m_data[i]);
+
+ touch();
+ }
+
+ void clear()
+ {
+ int64_t currentTime = ::utils::CurrentTimeMillis();
+ if (currentTime - m_lastAutoCleared >= m_autoClearingPeriod)
+ m_lastAutoCleared = currentTime;
+
+ m_data.clear();
+ m_size = 0;
+
+ touch();
+ }
+
+ [[nodiscard]] size_t size() const
+ {
+ autoClearIfNecessary();
+
+ return m_data.size();
+ }
+
+ private:
+ void autoClearIfNecessary()
+ {
+ if (m_autoClearingPeriod <= 0)
+ return;
+
+ int64_t currentTime = ::utils::CurrentTimeMillis();
+ if (currentTime - m_lastAutoCleared >= m_autoClearingPeriod)
+ {
+ m_lastAutoCleared = currentTime;
+ clear();
+ }
+ }
+
+ void makeSlotForNewItem()
+ {
+ if (m_size >= m_sizeLimit)
+ removeAt(0);
+ }
+
+ void removeAt(size_t index)
+ {
+ for (size_t i = index; i < m_size; ++i)
+ m_data[i] = i + 1 < m_sizeLimit ? m_data[i + 1] : T{};
+ m_size--;
+
+ touch();
+ }
+
+ void touch()
+ {
+ if (m_backupFunctor)
+ (*m_backupFunctor)(m_data, m_size);
+ }
+};
+
+template
+class NasSlot
+{
+ public:
+ using backup_functor_type = std::function;
+
+ private:
+ const int64_t m_autoClearingPeriod;
+ const std::optional m_backupFunctor;
+
+ T m_value;
+ int64_t m_lastAutoCleared;
+
+ static_assert(!std::is_reference::value);
+
+ public:
+ NasSlot(int64_t autoClearingPeriod, std::optional backupFunctor)
+ : m_autoClearingPeriod{autoClearingPeriod}, m_backupFunctor{backupFunctor}, m_value{},
+ m_lastAutoCleared{::utils::CurrentTimeMillis()}
+ {
+ }
+
+ const T &get()
+ {
+ autoClearIfNecessary();
+
+ return m_value;
+ }
+
+ const T &getPure() const
+ {
+ return m_value;
+ }
+
+ void clear()
+ {
+ set(T{});
+ }
+
+ void set(const T &value)
+ {
+ autoClearIfNecessary();
+
+ m_value = value;
+ touch();
+ }
+
+ void set(T &&value)
+ {
+ autoClearIfNecessary();
+
+ m_value = std::move(value);
+ touch();
+ }
+
+ template
+ void access(Functor fun)
+ {
+ autoClearIfNecessary();
+
+ fun((const T &)m_value);
+ }
+
+ template
+ void mutate(Functor fun)
+ {
+ autoClearIfNecessary();
+
+ fun((T &)m_value);
+ touch();
+ }
+
+ private:
+ void autoClearIfNecessary()
+ {
+ if (m_autoClearingPeriod <= 0)
+ return;
+
+ int64_t currentTime = ::utils::CurrentTimeMillis();
+ if (currentTime - m_lastAutoCleared >= m_autoClearingPeriod)
+ {
+ m_lastAutoCleared = currentTime;
+ m_value = {};
+ }
+ }
+
+ void touch()
+ {
+ if (m_backupFunctor)
+ (*m_backupFunctor)(m_value);
+ }
+};
+
+} // namespace nas
+
+template
+inline Json ToJson(const nas::NasSlot &v)
+{
+ return ToJson(v.getPure());
+}
diff --git a/src/lib/nas/utils.cpp b/src/lib/nas/utils.cpp
index d69eca31b..cdd36c687 100644
--- a/src/lib/nas/utils.cpp
+++ b/src/lib/nas/utils.cpp
@@ -11,6 +11,8 @@
#include
#include
+#include
+
namespace nas::utils
{
@@ -434,4 +436,118 @@ void RemoveFromTaiList(IE5gsTrackingAreaIdentityList &list, const VTrackingAreaI
list.list.end());
}
+int TaiListSize(const IE5gsTrackingAreaIdentityList &list)
+{
+ int size = 0;
+ for (auto &item : list.list)
+ size += TaiListSize(item);
+ return size;
+}
+
+int TaiListSize(const VPartialTrackingAreaIdentityList &list)
+{
+ size_t size = 0;
+ if (list.list00.has_value())
+ size += list.list00->tacs.size();
+ if (list.list01.has_value())
+ size++;
+ if (list.list10.has_value())
+ size += list.list10->tais.size();
+ return static_cast(size);
+}
+
+bool ServiceAreaListAllowsPlmn(const IEServiceAreaList &list, const VPlmn &plmn)
+{
+ return std::any_of(list.list.begin(), list.list.end(),
+ [&plmn](auto &item) { return ServiceAreaListAllowsPlmn(item, plmn); });
+}
+
+bool ServiceAreaListAllowsTai(const IEServiceAreaList &list, const VTrackingAreaIdentity &tai)
+{
+ return std::any_of(list.list.begin(), list.list.end(),
+ [&tai](auto &item) { return ServiceAreaListAllowsTai(item, tai); });
+}
+
+bool ServiceAreaListAllowsPlmn(const VPartialServiceAreaList &list, const VPlmn &plmn)
+{
+ if (list.present == 3)
+ {
+ if (list.list11->allowedType == EAllowedType::IN_THE_ALLOWED_AREA && DeepEqualsV(list.list11->plmn, plmn))
+ return true;
+ }
+ return false;
+}
+
+bool ServiceAreaListAllowsTai(const VPartialServiceAreaList &list, const VTrackingAreaIdentity &tai)
+{
+ if (list.present == 0)
+ {
+ if (list.list00->allowedType == EAllowedType::IN_THE_ALLOWED_AREA && DeepEqualsV(list.list00->plmn, tai.plmn) &&
+ std::any_of(list.list00->tacs.begin(), list.list00->tacs.end(),
+ [&tai](auto &i) { return (int)i == (int)tai.tac; }))
+ return true;
+ }
+ else if (list.present == 1)
+ {
+ if (list.list01->allowedType == EAllowedType::IN_THE_ALLOWED_AREA && DeepEqualsV(list.list01->plmn, tai.plmn) &&
+ (int)list.list01->tac == (int)tai.tac)
+ return true;
+ }
+ else if (list.present == 2)
+ {
+ if (list.list10->allowedType == EAllowedType::IN_THE_ALLOWED_AREA &&
+ std::any_of(list.list10->tais.begin(), list.list10->tais.end(),
+ [tai](auto &i) { return DeepEqualsV(i, tai); }))
+ return true;
+ }
+ return false;
+}
+
+Plmn PlmnFrom(const VPlmn &plmn)
+{
+ Plmn res;
+ res.mcc = plmn.mcc;
+ res.mnc = plmn.mnc;
+ res.isLongMnc = plmn.isLongMnc;
+ return res;
+}
+
+void RemoveFromServiceAreaList(IEServiceAreaList &list, const VTrackingAreaIdentity &tai)
+{
+ std::vector deletedSubLists;
+ int index = 0;
+
+ for (auto &sublist : list.list)
+ {
+ if (sublist.present == 0)
+ {
+ if (nas::utils::DeepEqualsV(sublist.list00->plmn, tai.plmn))
+ ::utils::EraseWhere(sublist.list00->tacs, [&tai](auto &i) { return (int)i == (int)tai.tac; });
+ if (sublist.list00->tacs.empty())
+ deletedSubLists.push_back(index);
+ }
+ else if (sublist.present == 1)
+ {
+ if (nas::utils::DeepEqualsV(sublist.list01->plmn, tai.plmn) && (int)tai.tac == (int)sublist.list01->tac)
+ deletedSubLists.push_back(index);
+ }
+ else if (sublist.present == 2)
+ {
+ ::utils::EraseWhere(sublist.list10->tais, [&tai](auto &i) { return nas::utils::DeepEqualsV(i, tai); });
+ if (sublist.list10->tais.empty())
+ deletedSubLists.push_back(index);
+ }
+ index++;
+ }
+
+ int deletedSoFar = 0;
+
+ for (int i : deletedSubLists)
+ {
+ int indexToDelete = i - deletedSoFar;
+ list.list.erase(list.list.begin() + indexToDelete);
+ deletedSoFar++;
+ }
+}
+
} // namespace nas::utils
diff --git a/src/lib/nas/utils.hpp b/src/lib/nas/utils.hpp
index 4262ce560..cd4cd38cc 100644
--- a/src/lib/nas/utils.hpp
+++ b/src/lib/nas/utils.hpp
@@ -17,6 +17,7 @@ IESNssai SNssaiFrom(const SingleSlice &v);
IENssai NssaiFrom(const NetworkSlice &v);
IEDnn DnnFromApn(const std::string &apn);
VPlmn PlmnFrom(const Plmn &plmn);
+Plmn PlmnFrom(const VPlmn &plmn);
NetworkSlice NssaiTo(const IENssai &v);
SingleSlice SNssaiTo(const IESNssai &v);
@@ -31,10 +32,17 @@ bool PlmnListContains(const IEPlmnList &list, VPlmn item);
bool PlmnListContains(const IEPlmnList &list, Plmn item);
bool TaiListContains(const nas::IE5gsTrackingAreaIdentityList &list, const VTrackingAreaIdentity &tai);
bool TaiListContains(const nas::VPartialTrackingAreaIdentityList &list, const VTrackingAreaIdentity &tai);
+int TaiListSize(const nas::VPartialTrackingAreaIdentityList &list);
+int TaiListSize(const nas::IE5gsTrackingAreaIdentityList &list);
bool ServiceAreaListForbidsPlmn(const nas::IEServiceAreaList &list, const VPlmn &plmn);
bool ServiceAreaListForbidsTai(const nas::IEServiceAreaList &list, const VTrackingAreaIdentity &tai);
bool ServiceAreaListForbidsPlmn(const nas::VPartialServiceAreaList &list, const VPlmn &plmn);
bool ServiceAreaListForbidsTai(const nas::VPartialServiceAreaList &list, const VTrackingAreaIdentity &tai);
+bool ServiceAreaListAllowsPlmn(const nas::IEServiceAreaList &list, const VPlmn &plmn);
+bool ServiceAreaListAllowsTai(const nas::IEServiceAreaList &list, const VTrackingAreaIdentity &tai);
+bool ServiceAreaListAllowsPlmn(const nas::VPartialServiceAreaList &list, const VPlmn &plmn);
+bool ServiceAreaListAllowsTai(const nas::VPartialServiceAreaList &list, const VTrackingAreaIdentity &tai);
+void RemoveFromServiceAreaList(nas::IEServiceAreaList &list, const VTrackingAreaIdentity &tai);
const char *EnumToString(ERegistrationType v);
const char *EnumToString(EMmCause v);
diff --git a/src/lib/nas/values.cpp b/src/lib/nas/values.cpp
index 88a7806ea..56508dd00 100644
--- a/src/lib/nas/values.cpp
+++ b/src/lib/nas/values.cpp
@@ -149,6 +149,11 @@ VTrackingAreaIdentity::VTrackingAreaIdentity(const VPlmn &plmn, const octet3 &ta
{
}
+VTrackingAreaIdentity::VTrackingAreaIdentity(const Tai &tai)
+ : plmn(tai.plmn.mcc, tai.plmn.mnc, tai.plmn.isLongMnc), tac(tai.tac)
+{
+}
+
void VTime::Encode(const VTime &value, OctetString &stream)
{
stream.appendOctet(value.year);
diff --git a/src/lib/nas/values.hpp b/src/lib/nas/values.hpp
index a07bf71a7..089ba0771 100644
--- a/src/lib/nas/values.hpp
+++ b/src/lib/nas/values.hpp
@@ -15,6 +15,7 @@
#include
#include
+#include
namespace nas
{
@@ -73,6 +74,7 @@ struct VTrackingAreaIdentity
octet3 tac;
VTrackingAreaIdentity(const VPlmn &plmn, const octet3 &tac);
+ explicit VTrackingAreaIdentity(const Tai &tai);
static void Encode(const VTrackingAreaIdentity &value, OctetString &stream);
static VTrackingAreaIdentity Decode(const OctetView &stream);
diff --git a/src/lib/rls/rls_base.cpp b/src/lib/rls/rls_base.cpp
new file mode 100644
index 000000000..f2a5ce76d
--- /dev/null
+++ b/src/lib/rls/rls_base.cpp
@@ -0,0 +1,15 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "rls_base.hpp"
+
+namespace rls
+{
+
+}
+
diff --git a/src/lib/rls/rls_base.hpp b/src/lib/rls/rls_base.hpp
new file mode 100644
index 000000000..bb8cbb5e0
--- /dev/null
+++ b/src/lib/rls/rls_base.hpp
@@ -0,0 +1,32 @@
+//
+// This file is a part of UERANSIM open source project.
+// Copyright (c) 2021 ALİ GÜNGÖR.
+//
+// The software and all associated files are licensed under GPL-3.0
+// and subject to the terms and conditions defined in LICENSE file.
+//
+
+#include "rls_pdu.hpp"
+
+#include
+
+namespace rls
+{
+
+struct PduInfo
+{
+ uint32_t id{};
+ OctetString pdu;
+ rrc::RrcChannel rrcChannel{};
+ int64_t sentTime{};
+ int endPointId{};
+};
+
+enum class ERlfCause
+{
+ PDU_ID_EXISTS,
+ PDU_ID_FULL,
+ SIGNAL_LOST_TO_CONNECTED_CELL
+};
+
+} // namespace rls
\ No newline at end of file
diff --git a/src/lib/rls/rls_pdu.cpp b/src/lib/rls/rls_pdu.cpp
index 2940b4465..cb4354467 100644
--- a/src/lib/rls/rls_pdu.cpp
+++ b/src/lib/rls/rls_pdu.cpp
@@ -13,36 +13,6 @@
namespace rls
{
-static void AppendPlmn(const Plmn &plmn, OctetString &stream)
-{
- stream.appendOctet2(plmn.mcc);
- stream.appendOctet2(plmn.mnc);
- stream.appendOctet(plmn.isLongMnc ? 1 : 0);
-}
-
-static void AppendGlobalNci(const GlobalNci &nci, OctetString &stream)
-{
- AppendPlmn(nci.plmn, stream);
- stream.appendOctet8(nci.nci);
-}
-
-static Plmn DecodePlmn(const OctetView &stream)
-{
- Plmn res{};
- res.mcc = stream.read2I();
- res.mnc = stream.read2I();
- res.isLongMnc = stream.readI() != 0;
- return res;
-}
-
-static GlobalNci DecodeGlobalNci(const OctetView &stream)
-{
- GlobalNci res{};
- res.plmn = DecodePlmn(stream);
- res.nci = stream.read8L();
- return res;
-}
-
void EncodeRlsMessage(const RlsMessage &msg, OctetString &stream)
{
stream.appendOctet(0x03); // (Just for old RLS compatibility)
@@ -52,32 +22,33 @@ void EncodeRlsMessage(const RlsMessage &msg, OctetString &stream)
stream.appendOctet(cons::Patch);
stream.appendOctet(static_cast(msg.msgType));
stream.appendOctet8(msg.sti);
- if (msg.msgType == EMessageType::CELL_INFO_REQUEST)
+ if (msg.msgType == EMessageType::HEARTBEAT)
{
- auto &m = (const RlsCellInfoRequest &)msg;
+ auto &m = (const RlsHeartBeat &)msg;
stream.appendOctet4(m.simPos.x);
stream.appendOctet4(m.simPos.y);
stream.appendOctet4(m.simPos.z);
}
- else if (msg.msgType == EMessageType::CELL_INFO_RESPONSE)
+ else if (msg.msgType == EMessageType::HEARTBEAT_ACK)
{
- auto &m = (const RlsCellInfoResponse &)msg;
- AppendGlobalNci(m.cellId, stream);
- stream.appendOctet4(m.tac);
+ auto &m = (const RlsHeartBeatAck &)msg;
stream.appendOctet4(m.dbm);
- stream.appendOctet4(static_cast(m.gnbName.size()));
- stream.appendUtf8(m.gnbName);
- stream.appendOctet4(static_cast(m.linkIp.size()));
- stream.appendUtf8(m.linkIp);
}
- else if (msg.msgType == EMessageType::PDU_DELIVERY)
+ else if (msg.msgType == EMessageType::PDU_TRANSMISSION)
{
- auto &m = (const RlsPduDelivery &)msg;
+ auto &m = (const RlsPduTransmission &)msg;
stream.appendOctet(static_cast(m.pduType));
+ stream.appendOctet4(m.pduId);
+ stream.appendOctet4(m.payload);
stream.appendOctet4(m.pdu.length());
stream.append(m.pdu);
- stream.appendOctet4(m.payload.length());
- stream.append(m.payload);
+ }
+ else if (msg.msgType == EMessageType::PDU_TRANSMISSION_ACK)
+ {
+ auto &m = (const RlsPduTransmissionAck &)msg;
+ stream.appendOctet4(static_cast(m.pduIds.size()));
+ for (auto pduId : m.pduIds)
+ stream.appendOctet4(pduId);
}
}
@@ -97,30 +68,36 @@ std::unique_ptr DecodeRlsMessage(const OctetView &stream)
auto msgType = static_cast(stream.readI());
uint64_t sti = stream.read8UL();
- if (msgType == EMessageType::CELL_INFO_REQUEST)
+ if (msgType == EMessageType::HEARTBEAT)
{
- auto res = std::make_unique(sti);
+ auto res = std::make_unique(sti);
res->simPos.x = stream.read4I();
res->simPos.y = stream.read4I();
res->simPos.z = stream.read4I();
return res;
}
- else if (msgType == EMessageType::CELL_INFO_RESPONSE)
+ else if (msgType == EMessageType::HEARTBEAT_ACK)
{
- auto res = std::make_unique(sti);
- res->cellId = DecodeGlobalNci(stream);
- res->tac = stream.read4I();
+ auto res = std::make_unique