fix DVRS unit deregistration issue (units weren't registered properly during GRP_AFF because DVRS doesn't do the typical U_REG); implement 12-hour timeout for unit registrations (this is only applied if the SU in question has *NOT* had *ANY* activity within 12 hours);

pull/55/head
Bryan Biedenkapp 2 years ago
parent 0251944438
commit 1de86458a6

@ -137,6 +137,8 @@ protocols:
dumpCsbkData: false
# Flag indicating unit registration will be verified after some operations.
verifyReg: false
# Flag indicating automated 12-hour idle unit registration timeout is disabled.
disableUnitRegTimeout: false
# Specifies the random wait delay for a subscriber.
# (This should not be altered.)
nRandWait: 8
@ -218,6 +220,8 @@ protocols:
verifyAff: false
# Flag indicating the host should verify unit registration.
verifyReg: false
# Flag indicating automated 12-hour idle unit registration timeout is disabled.
disableUnitRegTimeout: false
# Flag indicating the host requires LLA verification before allowing unit registration.
requireLLAForReg: false
# Flag indicating whether verbose dumping of P25 data packets is enabled.
@ -277,6 +281,8 @@ protocols:
verifyAff: false
# Flag indicating the host should verify unit registration.
verifyReg: false
# Flag indicating automated 12-hour idle unit registration timeout is disabled.
disableUnitRegTimeout: false
# Flag indicating whether verbose dumping of NXDN RCCH data is enabled.
dumpRcchData: false
# Amount of time to hang after a voice call.

@ -17,6 +17,12 @@ using namespace lookups;
#include <cassert>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t UNIT_REG_TIMEOUT = 43200U; // 12 hours
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
@ -30,6 +36,7 @@ using namespace lookups;
AffiliationLookup::AffiliationLookup(const std::string name, ChannelLookup* channelLookup, bool verbose) :
m_rfGrantChCnt(0U),
m_unitRegTable(),
m_unitRegTimers(),
m_grpAffTable(),
m_grantChTable(),
m_grantSrcIdTable(),
@ -39,6 +46,7 @@ AffiliationLookup::AffiliationLookup(const std::string name, ChannelLookup* chan
m_releaseGrant(nullptr),
m_name(),
m_chLookup(channelLookup),
m_disableUnitRegTimeout(false),
m_verbose(verbose)
{
assert(channelLookup != nullptr);
@ -46,6 +54,7 @@ AffiliationLookup::AffiliationLookup(const std::string name, ChannelLookup* chan
m_name = name;
m_unitRegTable.clear();
m_unitRegTimers.clear();
m_grpAffTable.clear();
m_grantChTable.clear();
@ -70,6 +79,9 @@ void AffiliationLookup::unitReg(uint32_t srcId)
m_unitRegTable.push_back(srcId);
m_unitRegTimers[srcId] = Timer(1000U, UNIT_REG_TIMEOUT);
m_unitRegTimers[srcId].start();
if (m_verbose) {
LogMessage(LOG_HOST, "%s, unit registration, srcId = %u",
m_name.c_str(), srcId);
@ -95,6 +107,8 @@ bool AffiliationLookup::unitDereg(uint32_t srcId)
groupUnaff(srcId);
m_unitRegTimers[srcId].stop();
// remove dynamic unit registration table entry
if (std::find(m_unitRegTable.begin(), m_unitRegTable.end(), srcId) != m_unitRegTable.end()) {
auto it = std::find(m_unitRegTable.begin(), m_unitRegTable.end(), srcId);
@ -102,9 +116,67 @@ bool AffiliationLookup::unitDereg(uint32_t srcId)
ret = true;
}
if (ret) {
if (m_unitDereg != nullptr) {
m_unitDereg(srcId);
}
}
return ret;
}
/// <summary>
/// Helper to start the source ID registration timer.
/// </summary>
/// <param name="srcId"></param>
/// <returns></returns>
void AffiliationLookup::touchUnitReg(uint32_t srcId)
{
if (srcId == 0U) {
return;
}
if (isUnitReg(srcId)) {
m_unitRegTimers[srcId].start();
}
}
/// <summary>
/// Gets the current timer timeout for this unit registration.
/// </summary>
/// <param name="srcId"></param>
/// <returns></returns>
uint32_t AffiliationLookup::unitRegTimeout(uint32_t srcId)
{
if (srcId == 0U) {
return 0U;
}
if (isUnitReg(srcId)) {
return m_unitRegTimers[srcId].getTimeout();
}
return 0U;
}
/// <summary>
/// Gets the current timer value for this unit registration.
/// </summary>
/// <param name="srcId"></param>
/// <returns></returns>
uint32_t AffiliationLookup::unitRegTimer(uint32_t srcId)
{
if (srcId == 0U) {
return 0U;
}
if (isUnitReg(srcId)) {
return m_unitRegTimers[srcId].getTimer();
}
return 0U;
}
/// <summary>
/// Helper to determine if the source ID has unit registered.
/// </summary>
@ -156,8 +228,7 @@ void AffiliationLookup::groupAff(uint32_t srcId, uint32_t dstId)
bool AffiliationLookup::groupUnaff(uint32_t srcId)
{
// lookup dynamic affiliation table entry
auto entry = m_grpAffTable.find(srcId);
if (entry != m_grpAffTable.end()) {
if (m_grpAffTable.find(srcId) != m_grpAffTable.end()) {
uint32_t tblDstId = m_grpAffTable.at(srcId);
if (m_verbose) {
LogMessage(LOG_HOST, "%s, group unaffiliation, srcId = %u, dstId = %u",
@ -204,8 +275,7 @@ bool AffiliationLookup::hasGroupAff(uint32_t dstId) const
bool AffiliationLookup::isGroupAff(uint32_t srcId, uint32_t dstId) const
{
// lookup dynamic affiliation table entry
auto entry = m_grpAffTable.find(srcId);
if (entry != m_grpAffTable.end()) {
if (m_grpAffTable.find(srcId) != m_grpAffTable.end()) {
uint32_t tblDstId = m_grpAffTable.at(srcId);
if (tblDstId == dstId) {
return true;
@ -536,4 +606,20 @@ void AffiliationLookup::clock(uint32_t ms)
for (uint32_t dstId : gntsToRel) {
releaseGrant(dstId, false);
}
if (!m_disableUnitRegTimeout) {
// clock all the unit registration timers
std::vector<uint32_t> unitsToDereg = std::vector<uint32_t>();
for (uint32_t srcId : m_unitRegTable) {
m_unitRegTimers[srcId].clock(ms);
if (m_unitRegTimers[srcId].isRunning() && m_unitRegTimers[srcId].hasExpired()) {
unitsToDereg.push_back(srcId);
}
}
// release units registrations that have timed out
for (uint32_t srcId : unitsToDereg) {
unitDereg(srcId);
}
}
}

@ -47,6 +47,12 @@ namespace lookups
virtual void unitReg(uint32_t srcId);
/// <summary>Helper to deregister a source ID.</summary>
virtual bool unitDereg(uint32_t srcId);
/// <summary>Helper to start the source ID registration timer.</summary>
virtual void touchUnitReg(uint32_t srcId);
/// <summary>Gets the current timer timeout for this unit registration.</summary>
virtual uint32_t unitRegTimeout(uint32_t srcId);
/// <summary>Gets the current timer value for this unit registration.</summary>
virtual uint32_t unitRegTimer(uint32_t srcId);
/// <summary>Helper to determine if the source ID has unit registered.</summary>
virtual bool isUnitReg(uint32_t srcId) const;
/// <summary>Helper to release unit registrations.</summary>
@ -102,13 +108,21 @@ namespace lookups
/// <summary>Updates the processor by the passed number of milliseconds.</summary>
void clock(uint32_t ms);
/// <summary>Helper to determine if the unit registration timeout is enabled or not.</summary>
virtual bool isDisableUnitRegTimeout() const { return m_disableUnitRegTimeout; }
/// <summary>Disables the unit registration timeout.</summary>
void setDisableUnitRegTimeout(bool disabled) { m_disableUnitRegTimeout = disabled; }
/// <summary>Helper to set the release grant callback.</summary>
void setReleaseGrantCallback(std::function<void(uint32_t, uint32_t, uint8_t)>&& callback) { m_releaseGrant = callback; }
/// <summary>Helper to set the unit deregistration callback.</summary>
void setUnitDeregCallback(std::function<void(uint32_t)>&& callback) { m_unitDereg = callback; }
protected:
uint8_t m_rfGrantChCnt;
std::vector<uint32_t> m_unitRegTable;
std::unordered_map<uint32_t, Timer> m_unitRegTimers;
std::unordered_map<uint32_t, uint32_t> m_grpAffTable;
std::unordered_map<uint32_t, uint32_t> m_grantChTable;
@ -119,10 +133,14 @@ namespace lookups
// chNo dstId slot
std::function<void(uint32_t, uint32_t, uint8_t)> m_releaseGrant;
// srcId
std::function<void(uint32_t)> m_unitDereg;
std::string m_name;
ChannelLookup* m_chLookup;
bool m_disableUnitRegTimeout;
bool m_verbose;
};
} // namespace lookups

@ -1153,6 +1153,7 @@ void FNENetwork::createPeerAffiliations(uint32_t peerId, std::string peerName)
std::lock_guard<std::mutex> lock(m_peerMutex);
lookups::ChannelLookup* chLookup = new lookups::ChannelLookup();
m_peerAffiliations[peerId] = new lookups::AffiliationLookup(peerName, chLookup, m_verbose);
m_peerAffiliations[peerId]->setDisableUnitRegTimeout(true); // FNE doesn't allow unit registration timeouts (notification must come from the peers)
}
/// <summary>

@ -992,7 +992,7 @@ bool TagP25Data::isPeerPermitted(uint32_t peerId, lc::LC& control, uint8_t duid,
}
/// <summary>
/// Helper to validate the DMR call stream.
/// Helper to validate the P25 call stream.
/// </summary>
/// <param name="peerId">Peer ID</param>
/// <param name="control"></param>

@ -174,6 +174,10 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, ::lookups::VoiceChDa
m_slot1->setNotifyCC(notifyCC);
m_slot2->setNotifyCC(notifyCC);
bool disableUnitRegTimeout = dmrProtocol["disableUnitRegTimeout"].as<bool>(false);
m_slot1->m_affiliations->setDisableUnitRegTimeout(disableUnitRegTimeout);
m_slot2->m_affiliations->setDisableUnitRegTimeout(disableUnitRegTimeout);
/*
** Voice Silence and Frame Loss Thresholds
*/

@ -994,6 +994,12 @@ void Slot::init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData s
}
});
// set the unit deregistration callback
m_affiliations->setUnitDeregCallback([=](uint32_t srcId) {
if (m_network != nullptr)
m_network->announceUnitDeregistration(srcId);
});
m_hangCount = callHang * 17U;
m_rssiMapper = rssiMapper;

@ -156,6 +156,8 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len)
uint32_t srcId = csbk->getSrcId();
uint32_t dstId = csbk->getDstId();
m_slot->m_affiliations->touchUnitReg(srcId);
if (srcId != 0U || dstId != 0U) {
CHECK_TRAFFIC_COLLISION(dstId);
@ -1357,8 +1359,8 @@ void ControlSignaling::writeRF_CSBK_U_Reg_Rsp(uint32_t srcId, uint8_t serviceOpt
// remove dynamic unit registration table entry
m_slot->m_affiliations->unitDereg(srcId);
if (m_slot->m_network != nullptr)
m_slot->m_network->announceUnitDeregistration(srcId);
// if (m_slot->m_network != nullptr)
// m_slot->m_network->announceUnitDeregistration(srcId);
csbk->setReason(TS_ACK_RSN_REG);
}

@ -278,6 +278,9 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
m_controlChData = controlChData;
bool disableUnitRegTimeout = nxdnProtocol["disableUnitRegTimeout"].as<bool>(false);
m_affiliations.setDisableUnitRegTimeout(disableUnitRegTimeout);
// set the grant release callback
m_affiliations.setReleaseGrantCallback([=](uint32_t chNo, uint32_t dstId, uint8_t slot) {
// callback REST API to clear TG permit for the granted TG on the specified voice channel
@ -300,6 +303,12 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
}
});
// set the unit deregistration callback
m_affiliations.setUnitDeregCallback([=](uint32_t srcId) {
if (m_network != nullptr)
m_network->announceUnitDeregistration(srcId);
});
lc::RCCH::setSiteData(m_siteData);
lc::RCCH::setCallsign(cwCallsign);
@ -324,6 +333,10 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
LogInfo(" Notify Control: %s", m_notifyCC ? "yes" : "no");
LogInfo(" Verify Affiliation: %s", m_control->m_verifyAff ? "yes" : "no");
LogInfo(" Verify Registration: %s", m_control->m_verifyReg ? "yes" : "no");
if (disableUnitRegTimeout) {
LogInfo(" Disable Unit Registration Timeout: yes");
}
}
if (m_voice != nullptr) {

@ -163,6 +163,7 @@ bool ControlSignaling::process(uint8_t fct, uint8_t option, uint8_t* data, uint3
uint16_t srcId = rcch->getSrcId();
uint16_t dstId = rcch->getDstId();
m_nxdn->m_affiliations.touchUnitReg(srcId);
switch (rcch->getMessageType()) {
case RTCH_MESSAGE_TYPE_VCALL:

@ -415,6 +415,9 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
m_controlChData = controlChData;
bool disableUnitRegTimeout = p25Protocol["disableUnitRegTimeout"].as<bool>(false);
m_affiliations.setDisableUnitRegTimeout(disableUnitRegTimeout);
// set the grant release callback
m_affiliations.setReleaseGrantCallback([=](uint32_t chNo, uint32_t dstId, uint8_t slot) {
// callback REST API to clear TG permit for the granted TG on the specified voice channel
@ -437,6 +440,12 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
}
});
// set the unit deregistration callback
m_affiliations.setUnitDeregCallback([=](uint32_t srcId) {
if (m_network != nullptr)
m_network->announceUnitDeregistration(srcId);
});
if (printOptions) {
LogInfo(" Silence Threshold: %u (%.1f%%)", m_voice->m_silenceThreshold, float(m_voice->m_silenceThreshold) / 12.33F);
LogInfo(" Frame Loss Threshold: %u", m_frameLossThreshold);
@ -486,6 +495,10 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
LogInfo(" Explicit Source ID Support: %s", m_allowExplicitSourceId ? "yes" : "no");
LogInfo(" Conventional Network Grant Demand: %s", m_convNetGrantDemand ? "yes" : "no");
if (disableUnitRegTimeout) {
LogInfo(" Disable Unit Registration Timeout: yes");
}
LogInfo(" Redundant Immediate: %s", m_control->m_redundantImmediate ? "yes" : "no");
if (m_control->m_redundantGrant) {
LogInfo(" Redundant Grant Transmit: yes");
@ -494,7 +507,7 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
// are we overriding the NAC for split NAC operations?
uint32_t txNAC = (uint32_t)::strtoul(systemConf["config"]["txNAC"].as<std::string>("F7E").c_str(), NULL, 16);
if (txNAC != 0xF7EU && txNAC != m_nac) {
if (txNAC != P25_NAC_DIGITAL_SQ && txNAC != m_nac) {
LogMessage(LOG_P25, "Split NAC operations, setting Tx NAC to $%03X", txNAC);
m_txNAC = txNAC;
m_nid.setTxNAC(m_txNAC);

@ -214,6 +214,7 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len, std::unique_ptr<lc::
uint32_t srcId = tsbk->getSrcId();
uint32_t dstId = tsbk->getDstId();
m_p25->m_affiliations.touchUnitReg(srcId);
m_lastMFID = tsbk->getMFId();
// handle standard P25 reference opcodes
@ -2619,6 +2620,26 @@ bool ControlSignaling::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
noNet = true;
}
// register the RID if the MFID is $90 (this is typically DVRS, and DVRS won't unit register so we'll do it for them)
if (!m_p25->m_affiliations.isUnitReg(srcId) && m_lastMFID == P25_MFG_MOT) {
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
LogWarning(LOG_RF, P25_TSDU_STR ", %s denial, RID rejection, srcId = %u", iosp->toString().c_str(), srcId);
::ActivityLog("P25", true, "unit registration request from %u denied", srcId);
iosp->setResponse(P25_RSP_REFUSED);
noNet = true;
}
else {
// update dynamic unit registration table
if (!m_p25->m_affiliations.isUnitReg(srcId)) {
m_p25->m_affiliations.unitReg(srcId);
}
if (m_p25->m_network != nullptr)
m_p25->m_network->announceUnitRegistration(srcId);
}
}
// validate the source RID is registered
if (!m_p25->m_affiliations.isUnitReg(srcId) && m_verifyReg) {
LogWarning(LOG_RF, P25_TSDU_STR ", %s denial, RID not registered, srcId = %u", iosp->toString().c_str(), srcId);
@ -2744,8 +2765,8 @@ void ControlSignaling::writeRF_TSDU_U_Dereg_Ack(uint32_t srcId)
writeRF_TSDU_SBF_Imm(osp.get(), false);
if (m_p25->m_network != nullptr)
m_p25->m_network->announceUnitDeregistration(srcId);
// if (m_p25->m_network != nullptr)
// m_p25->m_network->announceUnitDeregistration(srcId);
}
}

Loading…
Cancel
Save

Powered by TurnKey Linux.