diff --git a/configs/fne-config.example.yml b/configs/fne-config.example.yml index 2d2c9ad0..9549b4c5 100644 --- a/configs/fne-config.example.yml +++ b/configs/fne-config.example.yml @@ -71,8 +71,10 @@ master: # Flag indicating whether or not a parrot TG call will generate a grant demand. parrotGrantDemand: true + # Flag indicating whether or not a P25 ADJ_STS_BCAST will pass to any peers. + disallowAdjStsBcast: false # Flag indicating whether or not a P25 ADJ_STS_BCAST will pass to connected external peers. - disallowP25AdjStsBcast: true + disallowExtAdjStsBcast: true # # Talkgroup Rules Configuration diff --git a/src/fne/network/FNENetwork.cpp b/src/fne/network/FNENetwork.cpp index 73c597a3..f4a41c3f 100644 --- a/src/fne/network/FNENetwork.cpp +++ b/src/fne/network/FNENetwork.cpp @@ -87,7 +87,8 @@ FNENetwork::FNENetwork(HostFNE* host, const std::string& address, uint16_t port, m_updateLookupTime(updateLookupTime * 60U), m_softConnLimit(0U), m_callInProgress(false), - m_disallowP25AdjStsBcast(true), + m_disallowAdjStsBcast(false), + m_disallowExtAdjStsBcast(true), m_reportPeerPing(reportPeerPing), m_verbose(verbose) { @@ -118,16 +119,27 @@ FNENetwork::~FNENetwork() /// void FNENetwork::setOptions(yaml::Node& conf, bool printOptions) { - m_disallowP25AdjStsBcast = conf["disallowP25AdjStsBcast"].as(true); + m_disallowAdjStsBcast = conf["disallowAdjStsBcast"].as(false); + m_disallowExtAdjStsBcast = conf["disallowExtAdjStsBcast"].as(true); m_softConnLimit = conf["connectionLimit"].as(MAX_HARD_CONN_CAP); if (m_softConnLimit > MAX_HARD_CONN_CAP) { m_softConnLimit = MAX_HARD_CONN_CAP; } + // always force disable ADJ_STS_BCAST to external peers if the all option + // is enabled + if (m_disallowAdjStsBcast) { + m_disallowExtAdjStsBcast = true; + } + if (printOptions) { LogInfo(" Maximum Permitted Connections: %u", m_softConnLimit); - LogInfo(" Disable P25 ADJ_STS_BCAST to external peers: %s", m_disallowP25AdjStsBcast ? "yes" : "no"); + LogInfo(" Disable P25 ADJ_STS_BCAST to any peers: %s", m_disallowAdjStsBcast ? "yes" : "no"); + if (m_disallowAdjStsBcast) { + LogWarning(LOG_NET, "NOTICE: All P25 ADJ_STS_BCAST messages will be blocked and dropped!"); + } + LogInfo(" Disable P25 ADJ_STS_BCAST to external peers: %s", m_disallowExtAdjStsBcast ? "yes" : "no"); } } @@ -632,6 +644,11 @@ void* FNENetwork::threadedNetworkRx(void* arg) LogInfoEx(LOG_NET, "PEER %u RPTC ACK, completed the configuration exchange", peerId); json::object peerConfig = connection->config(); + if (peerConfig["externalPeer"].is()) { + bool external = peerConfig["externalPeer"].get(); + connection->isExternalPeer(external); + } + if (peerConfig["software"].is()) { std::string software = peerConfig["software"].get(); LogInfoEx(LOG_NET, "PEER %u reports software %s", peerId, software.c_str()); diff --git a/src/fne/network/FNENetwork.h b/src/fne/network/FNENetwork.h index 37a03a86..e652dee0 100644 --- a/src/fne/network/FNENetwork.h +++ b/src/fne/network/FNENetwork.h @@ -86,6 +86,7 @@ namespace network m_pingsReceived(0U), m_lastPing(0U), m_lastACLUpdate(0U), + m_isExternalPeer(false), m_config(), m_pktLastSeq(0U), m_pktNextSeq(1U) @@ -109,6 +110,7 @@ namespace network m_pingsReceived(0U), m_lastPing(0U), m_lastACLUpdate(0U), + m_isExternalPeer(false), m_config(), m_pktLastSeq(0U), m_pktNextSeq(1U) @@ -152,6 +154,9 @@ namespace network /// Last ACL update sent. __PROPERTY_PLAIN(uint64_t, lastACLUpdate); + /// Flag indicating this connection is from an external peer. + __PROPERTY_PLAIN(bool, isExternalPeer); + /// JSON objecting containing peer configuration information. __PROPERTY_PLAIN(json::object, config); @@ -278,7 +283,8 @@ namespace network bool m_callInProgress; - bool m_disallowP25AdjStsBcast; + bool m_disallowAdjStsBcast; + bool m_disallowExtAdjStsBcast; bool m_reportPeerPing; bool m_verbose; diff --git a/src/fne/network/PeerNetwork.cpp b/src/fne/network/PeerNetwork.cpp index 8555f0a6..02fb7306 100644 --- a/src/fne/network/PeerNetwork.cpp +++ b/src/fne/network/PeerNetwork.cpp @@ -117,7 +117,9 @@ bool PeerNetwork::writeConfig() rcon["port"].set(m_restApiPort); // REST API Port config["rcon"].set(rcon); - config["software"].set(std::string(software)); // Software ID + bool external = true; + config["externalPeer"].set(external); // External Peer Marker + config["software"].set(std::string(software)); // Software ID json::value v = json::value(config); std::string json = v.serialize(); diff --git a/src/fne/network/fne/TagP25Data.cpp b/src/fne/network/fne/TagP25Data.cpp index 7829a9d7..d399e9c9 100644 --- a/src/fne/network/fne/TagP25Data.cpp +++ b/src/fne/network/fne/TagP25Data.cpp @@ -244,6 +244,11 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId m_parrotFrames.push_back(std::make_tuple(copy, len, pktSeq, streamId, srcId, dstId)); } + // process TSDU from peer + if (!processTSDU(buffer, peerId, duid)) { + return false; + } + // repeat traffic to the connected peers if (m_network->m_peers.size() > 0U) { uint32_t i = 0U; @@ -306,7 +311,7 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId routeRewrite(outboundPeerBuffer, dstPeerId, duid, dstId); // process TSDUs going to external peers - if (processTSDUExternal(outboundPeerBuffer, peerId, dstPeerId, duid)) { + if (processTSDUToExternal(outboundPeerBuffer, peerId, dstPeerId, duid)) { peer.second->writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, outboundPeerBuffer, len, pktSeq, streamId); if (m_network->m_debug) { LogDebug(LOG_NET, "P25, srcPeer = %u, dstPeer = %u, duid = $%02X, lco = $%02X, MFId = $%02X, srcId = %u, dstId = %u, len = %u, pktSeq = %u, streamId = %u, external = %u", @@ -424,12 +429,12 @@ void TagP25Data::routeRewrite(uint8_t* buffer, uint32_t peerId, uint8_t duid, ui // rewrite destination TGID in the frame __SET_UINT16(rewriteDstId, buffer, 8U); - UInt8Array data = std::unique_ptr(new uint8_t[frameLength]); - ::memset(data.get(), 0x00U, frameLength); - ::memcpy(data.get(), buffer + 24U, frameLength); - // are we receiving a TSDU? if (duid == P25_DUID_TSDU) { + UInt8Array data = std::unique_ptr(new uint8_t[frameLength]); + ::memset(data.get(), 0x00U, frameLength); + ::memcpy(data.get(), buffer + 24U, frameLength); + std::unique_ptr tsbk = lc::tsbk::TSBKFactory::createTSBK(data.get()); if (tsbk != nullptr) { // handle standard P25 reference opcodes @@ -503,6 +508,52 @@ bool TagP25Data::peerRewrite(uint32_t peerId, uint32_t& dstId, bool outbound) return false; } +/// +/// Helper to process TSDUs being passed from a peer. +/// +/// +/// Peer ID +/// +bool TagP25Data::processTSDU(uint8_t* buffer, uint32_t peerId, uint8_t duid) +{ + // are we receiving a TSDU? + if (duid == P25_DUID_TSDU) { + uint32_t frameLength = buffer[23U]; + + UInt8Array data = std::unique_ptr(new uint8_t[frameLength]); + ::memset(data.get(), 0x00U, frameLength); + ::memcpy(data.get(), buffer + 24U, frameLength); + + std::unique_ptr tsbk = lc::tsbk::TSBKFactory::createTSBK(data.get()); + if (tsbk != nullptr) { + // handle standard P25 reference opcodes + switch (tsbk->getLCO()) { + case TSBK_OSP_ADJ_STS_BCAST: + { + if (m_network->m_disallowAdjStsBcast) { + // LogWarning(LOG_NET, "PEER %u, passing ADJ_STS_BCAST to internal peers is prohibited, dropping", peerId); + return false; + } else { + lc::tsbk::OSP_ADJ_STS_BCAST* osp = static_cast(tsbk.get()); + + if (m_network->m_verbose) { + LogMessage(LOG_NET, P25_TSDU_STR ", %s, sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X, peerId = %u", tsbk->toString().c_str(), + osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass(), peerId); + } + } + } + break; + default: + break; + } + } else { + LogWarning(LOG_NET, "PEER %u, passing TSBK that failed to decode? tsbk == nullptr", peerId); + } + } + + return true; +} + /// /// Helper to process TSDUs being passed to an external peer. /// @@ -510,7 +561,7 @@ bool TagP25Data::peerRewrite(uint32_t peerId, uint32_t& dstId, bool outbound) /// Source Peer ID /// Destination Peer ID /// -bool TagP25Data::processTSDUExternal(uint8_t* buffer, uint32_t srcPeerId, uint32_t dstPeerId, uint8_t duid) +bool TagP25Data::processTSDUToExternal(uint8_t* buffer, uint32_t srcPeerId, uint32_t dstPeerId, uint8_t duid) { // are we receiving a TSDU? if (duid == P25_DUID_TSDU) { @@ -526,15 +577,15 @@ bool TagP25Data::processTSDUExternal(uint8_t* buffer, uint32_t srcPeerId, uint32 switch (tsbk->getLCO()) { case TSBK_OSP_ADJ_STS_BCAST: { - if (m_network->m_disallowP25AdjStsBcast) { + if (m_network->m_disallowExtAdjStsBcast) { // LogWarning(LOG_NET, "PEER %u, passing ADJ_STS_BCAST to external peers is prohibited, dropping", dstPeerId); return false; } else { lc::tsbk::OSP_ADJ_STS_BCAST* osp = static_cast(tsbk.get()); if (m_network->m_verbose) { - LogMessage(LOG_NET, P25_TSDU_STR ", %s, sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X", tsbk->toString().c_str(), - osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); + LogMessage(LOG_NET, P25_TSDU_STR ", %s, sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X, peerId = %u", tsbk->toString().c_str(), + osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass(), srcPeerId); } } } diff --git a/src/fne/network/fne/TagP25Data.h b/src/fne/network/fne/TagP25Data.h index e7d83928..819fc3f1 100644 --- a/src/fne/network/fne/TagP25Data.h +++ b/src/fne/network/fne/TagP25Data.h @@ -77,8 +77,10 @@ namespace network /// Helper to route rewrite destination ID. bool peerRewrite(uint32_t peerId, uint32_t& dstId, bool outbound = true); + /// Helper to process TSDUs being passed from a peer. + bool processTSDU(uint8_t* buffer, uint32_t peerId, uint8_t duid); /// Helper to process TSDUs being passed to an external peer. - bool processTSDUExternal(uint8_t* buffer, uint32_t srcPeerId, uint32_t dstPeerId, uint8_t duid); + bool processTSDUToExternal(uint8_t* buffer, uint32_t srcPeerId, uint32_t dstPeerId, uint8_t duid); /// Helper to determine if the peer is permitted for traffic. bool isPeerPermitted(uint32_t peerId, p25::lc::LC& control, uint8_t duid, uint32_t streamId);