From cfc036ca38ae28c305b43a3d3e8faf0cc8c52c2f Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Thu, 29 Oct 2026 11:17:39 -0400 Subject: [PATCH] add support for C++ peers to trigger a radio alias sync request; --- src/common/network/BaseNetwork.cpp | 13 +++ src/common/network/BaseNetwork.h | 6 + src/common/network/Network.cpp | 15 +++ src/common/network/Network.h | 27 +++++ src/common/network/packet/RadioAliasSync.cpp | 113 +++++++++++++++++++ src/fne/network/PeerNetwork.cpp | 1 + 6 files changed, 175 insertions(+) create mode 100644 src/common/network/packet/RadioAliasSync.cpp diff --git a/src/common/network/BaseNetwork.cpp b/src/common/network/BaseNetwork.cpp index c1f5aed5..91ee8b1d 100644 --- a/src/common/network/BaseNetwork.cpp +++ b/src/common/network/BaseNetwork.cpp @@ -218,6 +218,19 @@ bool BaseNetwork::writeUKEKReq(const uint32_t rsi) return writeMaster({ NET_FUNC::KEY_KEK_REQ, NET_SUBFUNC::NOP }, buffer, modifyKeyCmd.fullLength() + 11U, RTP_END_OF_CALL_SEQ, 0U); } +/* Requests the current radio alias table from the upstream master. */ + +bool BaseNetwork::writeRadioAliasSyncRequest() +{ + using namespace p25::defines; + + if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) + return false; + + uint8_t buffer[1U] = { 0U }; + return writeMaster({ NET_FUNC::RADIO_ALIAS_SYNC, NET_SUBFUNC::NOP }, buffer, 1U, RTP_END_OF_CALL_SEQ, 0U, true); +} + /* Writes the local activity log to the network. */ bool BaseNetwork::writeActLog(const char* message) diff --git a/src/common/network/BaseNetwork.h b/src/common/network/BaseNetwork.h index 42105e7b..77df4a39 100644 --- a/src/common/network/BaseNetwork.h +++ b/src/common/network/BaseNetwork.h @@ -484,6 +484,12 @@ namespace network */ bool writeUKEKReq(const uint32_t rsi); + /** + * @brief Requests the current radio alias table from the upstream master. + * @returns bool True, if the request was sent, otherwise false. + */ + bool writeRadioAliasSyncRequest(); + /** * @brief Writes the local activity log to the network. * \code{.unparsed} diff --git a/src/common/network/Network.cpp b/src/common/network/Network.cpp index 94e685c0..168aa098 100644 --- a/src/common/network/Network.cpp +++ b/src/common/network/Network.cpp @@ -49,6 +49,9 @@ Network::Network(const std::string& address, uint16_t port, uint16_t localPort, m_saveLookup(saveLookup), m_ridLookup(nullptr), m_tidLookup(nullptr), + m_ridAliasLookup(nullptr), + m_radioAliasSyncPkt(true, "Radio Alias Sync"), + m_radioAliasSyncStreamId(0U), m_salt(nullptr), m_kmfPresharedKey(nullptr), m_retryTimer(1000U, DEFAULT_RETRY_TIME), @@ -188,6 +191,13 @@ void Network::setLookups(lookups::RadioIdLookup* ridLookup, lookups::TalkgroupRu m_tidLookup = tidLookup; } +/* Sets the instance of the Radio Alias lookup table. */ + +void Network::setRadioAliasLookups(lookups::RadioAliasLookup* ridAliasLookup) +{ + m_ridAliasLookup = ridAliasLookup; +} + /* Sets metadata configuration settings from the modem. */ void Network::setMetadata(const std::string& identity, uint32_t rxFrequency, uint32_t txFrequency, float txOffsetMhz, float chBandwidthKhz, @@ -344,6 +354,8 @@ void Network::clock(uint32_t ms) { NET_FUNC::MASTER, &Network::PacketHandler::master }, + { NET_FUNC::RADIO_ALIAS_SYNC, &Network::PacketHandler::radioAliasSync }, + { NET_FUNC::INCALL_CTRL, &Network::PacketHandler::inCallControl }, { NET_FUNC::NAK, &Network::PacketHandler::nak }, @@ -466,6 +478,9 @@ void Network::close() writeMaster({ NET_FUNC::RPT_DISC, NET_SUBFUNC::NOP }, buffer, 1U, pktSeq(true), createStreamId()); } + m_radioAliasSyncPkt.clear(); + m_radioAliasSyncStreamId = 0U; + m_socket->close(); m_retryTimer.stop(); diff --git a/src/common/network/Network.h b/src/common/network/Network.h index 45f7a0f2..5a9eaa7b 100644 --- a/src/common/network/Network.h +++ b/src/common/network/Network.h @@ -20,6 +20,8 @@ #include "common/network/BaseNetwork.h" #include "common/network/RTPHeader.h" #include "common/network/RTPFNEHeader.h" +#include "common/network/PacketBuffer.h" +#include "common/lookups/RadioAliasLookup.h" #include "common/lookups/RadioIdLookup.h" #include "common/lookups/TalkgroupRulesLookup.h" #include "common/p25/kmm/KeysetItem.h" @@ -198,6 +200,12 @@ namespace network * @param tidLookup Talkgroup Rules Lookup Table Instance */ void setLookups(lookups::RadioIdLookup* ridLookup, lookups::TalkgroupRulesLookup* tidLookup); + /** + * @brief Sets the instance of the Radio Alias lookup table. + * @param ridAliasLookup Radio Alias Lookup Table Instance. + */ + void setRadioAliasLookups(lookups::RadioAliasLookup* ridAliasLookup); + /** * @brief Sets metadata configuration settings from the modem. * @param identity Peer Identity. @@ -348,6 +356,10 @@ namespace network lookups::RadioIdLookup* m_ridLookup; lookups::TalkgroupRulesLookup* m_tidLookup; + lookups::RadioAliasLookup* m_ridAliasLookup; + + PacketBuffer m_radioAliasSyncPkt; + uint32_t m_radioAliasSyncStreamId; uint8_t* m_salt; @@ -484,6 +496,21 @@ namespace network static bool master(Network* network, uint32_t peerId, uint32_t streamId, uint64_t now, const frame::RTPFNEHeader& fneHeader, const frame::RTPHeader& rtpHeader, const uint8_t* buffer, int length); + /** + * @brief Handles NET_FUNC::RADIO_ALIAS_SYNC packets. + * @param network Instance of the Network class. + * @param peerId Peer ID. + * @param streamId Stream ID. + * @param now Current time in milliseconds. + * @param fneHeader RTP FNE Header. + * @param rtpHeader RTP Header. + * @param buffer Buffer containing the received message. + * @param length Length of buffer. + * @returns bool True, if packet processing should stop, otherwise false. + */ + static bool radioAliasSync(Network* network, uint32_t peerId, uint32_t streamId, uint64_t now, + const frame::RTPFNEHeader& fneHeader, const frame::RTPHeader& rtpHeader, const uint8_t* buffer, int length); + /** * @brief Handles NET_FUNC::INCALL_CTRL packets. * @param network Instance of the TrafficNetwork class. diff --git a/src/common/network/packet/RadioAliasSync.cpp b/src/common/network/packet/RadioAliasSync.cpp new file mode 100644 index 00000000..1a26c925 --- /dev/null +++ b/src/common/network/packet/RadioAliasSync.cpp @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2026 Bryan Biedenkapp, N2PLL + * + */ +#include "Defines.h" +#include "common/Log.h" +#include "network/Network.h" + +using namespace network; + +#include +#include +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/* Handles NET_FUNC::RADIO_ALIAS_SYNC packets. */ + +bool Network::PacketHandler::radioAliasSync(Network* network, uint32_t peerId, uint32_t streamId, uint64_t now, + const frame::RTPFNEHeader& fneHeader, const frame::RTPHeader& rtpHeader, const uint8_t* buffer, int length) +{ + (void)peerId; + (void)now; + (void)rtpHeader; + + if (fneHeader.getSubFunction() != NET_SUBFUNC::NOP) + return false; + + if (network->m_radioAliasSyncStreamId == 0U || streamId != network->m_radioAliasSyncStreamId) { + LogWarning(LOG_NET, "PEER %u Radio Alias Sync, ignoring unexpected stream %u", network->m_peerId, streamId); + return true; + } + + if (length < static_cast(FRAG_SIZE)) { + LogWarning(LOG_NET, "PEER %u Radio Alias Sync, ignoring short fragment, length = %d", network->m_peerId, length); + network->m_radioAliasSyncPkt.clear(); + network->m_radioAliasSyncStreamId = 0U; + return true; + } + + uint32_t decodedLength = 0U; + uint8_t* decoded = nullptr; + if (!network->m_radioAliasSyncPkt.decode(buffer, &decoded, &decodedLength)) + return true; + + if (!network->m_enabled || !network->m_updateLookup || network->m_ridAliasLookup == nullptr || decodedLength == 0U) { + LogWarning(LOG_NET, "PEER %u Radio Alias Sync, alias lookup update is unavailable", network->m_peerId); + network->m_radioAliasSyncPkt.clear(); + network->m_radioAliasSyncStreamId = 0U; + delete[] decoded; + return true; + } + + std::ostringstream name; + std::random_device rd; + std::mt19937 mt(rd()); + std::uniform_int_distribution dist(0x00U, 0xFFFFFFFFU); + name << "/tmp/rid_alias.dat." << dist(mt); + + const std::string tempFilename = name.str(); + std::ofstream file(tempFilename, std::ios::out | std::ios::binary); + if (file.fail()) { + LogError(LOG_NET, "PEER %u Radio Alias Sync, cannot open temporary lookup file - %s", + network->m_peerId, tempFilename.c_str()); + network->m_radioAliasSyncPkt.clear(); + network->m_radioAliasSyncStreamId = 0U; + delete[] decoded; + return true; + } + + file.write(reinterpret_cast(decoded), decodedLength); + const bool writeFailed = file.fail(); + file.close(); + delete[] decoded; + + if (writeFailed) { + LogError(LOG_NET, "PEER %u Radio Alias Sync, failed writing temporary lookup file - %s", + network->m_peerId, tempFilename.c_str()); + ::remove(tempFilename.c_str()); + network->m_radioAliasSyncPkt.clear(); + network->m_radioAliasSyncStreamId = 0U; + return true; + } + + const std::string lookupFilename = network->m_ridAliasLookup->filename(); + network->m_ridAliasLookup->filename(tempFilename); + const bool loaded = network->m_ridAliasLookup->reload(); + network->m_ridAliasLookup->filename(lookupFilename); + + if (loaded && network->m_saveLookup) { + network->m_ridAliasLookup->commit(true); + } + + ::remove(tempFilename.c_str()); + + if (!loaded) { + LogError(LOG_NET, "PEER %u Radio Alias Sync, received lookup table could not be loaded", network->m_peerId); + } else { + LogInfoEx(LOG_NET, "PEER %u Radio Alias Sync, lookup table updated", network->m_peerId); + } + + network->m_radioAliasSyncPkt.clear(); + network->m_radioAliasSyncStreamId = 0U; + return true; +} diff --git a/src/fne/network/PeerNetwork.cpp b/src/fne/network/PeerNetwork.cpp index ee8cbc39..73270bde 100644 --- a/src/fne/network/PeerNetwork.cpp +++ b/src/fne/network/PeerNetwork.cpp @@ -99,6 +99,7 @@ PeerNetwork::~PeerNetwork() void PeerNetwork::setRadioAliasLookups(lookups::RadioAliasLookup* ridAliasLookup) { + Network::setRadioAliasLookups(ridAliasLookup); m_ridAliasLookup = ridAliasLookup; }