feat(debug): add DMR burst logging (#5)

* debug: add DMR burst logging (Header+6 frames)

* feat: add raw packet logging and header detection for counter reset

* fix(dmr): remove hardcoded Slot 2 restriction allowing TS1 RX

* fix(dmr): correctly propagate and use TS slot for subscriptions

* fix(dmr): pass uiSlot to OnDvHeaderPacketIn call in IsValidDvFramePacket

* fix(protocols): sanitize source callsigns to strip suffixes/modules for Dashboard reporting
pull/23/head
Dave Behnke 3 months ago committed by GitHub
parent 6df692e6ba
commit 22e5e4957b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -188,6 +188,10 @@ void CDcsProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Critical Fix: Sanitize source callsign to strip suffixes (e.g. "KF8S D" -> "KF8S")
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

@ -322,6 +322,10 @@ void CDextraProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Heade
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Critical Fix: Sanitize source callsign to strip suffixes (e.g. "KF8S D" -> "KF8S")
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

@ -65,6 +65,10 @@ bool CDmrmmdvmProtocol::Initialize(const char *type, const EProtocol ptype, cons
::srand((unsigned) time(&t)); ::srand((unsigned) time(&t));
m_uiAuthSeed = (uint32_t)rand(); m_uiAuthSeed = (uint32_t)rand();
// Debug: Start disabled
m_debugFrameCount = 6;
std::cout << "[DEBUG] DMR Burst Logging Enabled (Header + 6 Frames)" << std::endl;
// done // done
return true; return true;
} }
@ -82,6 +86,7 @@ void CDmrmmdvmProtocol::Task(void)
int iRssi; int iRssi;
uint8_t Cmd; uint8_t Cmd;
uint8_t CallType; uint8_t CallType;
uint8_t uiSlot;
std::unique_ptr<CDvHeaderPacket> Header; std::unique_ptr<CDvHeaderPacket> Header;
std::unique_ptr<CDvFramePacket> LastFrame; std::unique_ptr<CDvFramePacket> LastFrame;
std::array<std::unique_ptr<CDvFramePacket>, 3> Frames; std::array<std::unique_ptr<CDvFramePacket>, 3> Frames;
@ -98,21 +103,67 @@ void CDmrmmdvmProtocol::Task(void)
#endif #endif
{ {
//Buffer.DebugDump(g_Reflector.m_DebugFile); //Buffer.DebugDump(g_Reflector.m_DebugFile);
// RAW DEBUG LOGGING (Pre-Validation)
// Detect Header to reset counter
uint8_t dmrd_tag[] = { 'D','M','R','D' };
if (Buffer.size() == 55 && Buffer.Compare(dmrd_tag, 4) == 0) {
uint8_t uiSlotType = Buffer.data()[15] & 0x0F;
uint8_t uiFrameType = (Buffer.data()[15] & 0x30) >> 4;
// Check if it's a Header (DataSync + Header Slot Type)
// Need definitions or hardcoded values matching IsValidDvHeaderPacket
// DMRMMDVM_FRAMETYPE_DATASYNC=2, MMDVM_SLOTTYPE_HEADER=1
if (uiFrameType == 2 && uiSlotType == 1) {
m_debugFrameCount = 0;
std::cout << "[DEBUG-RAW] Header Detected -> Reset Log Counter" << std::endl;
}
}
if (m_debugFrameCount < 6) {
std::cout << "[DEBUG-RAW] Pkt " << m_debugFrameCount << " Size=" << Buffer.size() << " Data: ";
for (size_t i = 0; i < Buffer.size(); i++) printf("%02X", Buffer.data()[i]);
std::cout << std::endl;
// If this wasn't a header (counter 0), increment?
// Or let IsValidDvFramePacket increment?
// If validation fails, we won't increment, so we might log infinite "bad" packets.
// Let's increment here for "Raw" logging purposes if not 0?
// Actually, keep it simple. If valid header, count=0. Then we see it.
// If valid frame, increment.
// If invalid frame, we verify it arrived.
// BUT if we don't increment on invalid frames, we'll spam logs if client sends garbage.
// Force increment counter if > 0?
if (m_debugFrameCount > 0) m_debugFrameCount++;
}
// crack the packet // crack the packet
if ( IsValidDvFramePacket(Ip, Buffer, Header, Frames) ) if ( IsValidDvFramePacket(Ip, Buffer, Header, Frames) )
{ {
if (m_debugFrameCount < 6) {
m_debugFrameCount++;
std::cout << "[DEBUG] DMR Frame " << m_debugFrameCount << " Size=" << Buffer.size() << " Data: ";
for (size_t i = 0; i < Buffer.size(); i++) printf("%02X", Buffer.data()[i]);
std::cout << std::endl;
}
for ( int i = 0; i < 3; i++ ) for ( int i = 0; i < 3; i++ )
{ {
OnDvFramePacketIn(Frames.at(i), &Ip); OnDvFramePacketIn(Frames.at(i), &Ip);
} }
} }
else if ( IsValidDvHeaderPacket(Buffer, Header, &Cmd, &CallType) ) else if ( IsValidDvHeaderPacket(Buffer, Header, &Cmd, &CallType, &uiSlot) )
{ {
// Reset Logging on Header
m_debugFrameCount = 0;
std::cout << "[DEBUG] DMR Header IN (Reset Log) Size=" << Buffer.size() << " Data: ";
for (size_t i = 0; i < Buffer.size(); i++) printf("%02X", Buffer.data()[i]);
std::cout << std::endl;
// callsign muted? // callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) ) if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) )
{ {
// handle it // handle it
OnDvHeaderPacketIn(Header, Ip, Cmd, CallType); OnDvHeaderPacketIn(Header, Ip, Cmd, CallType, uiSlot);
} }
} }
else if ( IsValidDvLastFramePacket(Buffer, LastFrame) ) else if ( IsValidDvLastFramePacket(Buffer, LastFrame) )
@ -267,7 +318,9 @@ void CDmrmmdvmProtocol::Task(void)
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// streams helpers // streams helpers
void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip, uint8_t cmd, uint8_t CallType) // stream helpers
void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip, uint8_t cmd, uint8_t CallType, uint8_t uiSlot)
{ {
bool lastheard = false; bool lastheard = false;
@ -282,6 +335,10 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
else else
{ {
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Sanitize source callsign (Strip suffixes)
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());
// no stream open yet, open a new one // no stream open yet, open a new one
@ -350,28 +407,19 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
// But if we subscribe, CheckAccess(tg) will return true (unless held by OTHER). // But if we subscribe, CheckAccess(tg) will return true (unless held by OTHER).
// So we add subscription first. // So we add subscription first.
// Add Subscription (Dynamic)
// Add Subscription (Dynamic) // Add Subscription (Dynamic)
unsigned int timeout = g_Configure.GetUnsigned(g_Keys.dmr.timeout); unsigned int timeout = g_Configure.GetUnsigned(g_Keys.dmr.timeout);
// Slot? Usually assume Slot 2 or from Header? Header has slot info?
// CDvHeaderPacket doesn't easily expose slot in args here, passed in? // FIX: Use actual slot from packet
// Header->GetBitField? int slot = uiSlot;
// Actually buffer parsing did it. if (slot == 0) slot = 2; // Default to TS2 only if slot not resolved (safety)
// We don't have slot easily available here except from previous context?
// Buffer parsing sets 'header' and 'cmd'.
// Mini DMR Mode: Scanner Check
// We need to know which slot the user is transmitting on.
// The packet doesn't explicitly tell us (it's embedded in obscure bits or implicit).
// However, if the user is transmitting on TG X, they MUST be subscribed to TG X.
// So we can look up the slot from the scanner!
int slot = dmrClient->m_Scanner.GetSubscriptionSlot(tg);
if (slot == 0) slot = 2; // Default to TS2 if not found (e.g. initial PTT)
// Auto-subscribe if not subscribed? // Auto-subscribe if not subscribed?
// If slot was 0, it means not subscribed. We should probably auto-subscribe. // If user is transmitting on 'slot', they want to subscribe on 'slot'.
// But which slot? Usually TS2 is safe default for Hotspots. if (dmrClient->m_Scanner.GetSubscriptionSlot(tg) == 0) {
if (slot == 2 && dmrClient->m_Scanner.GetSubscriptionSlot(tg) == 0) {
// PTT -> Dynamic Subscription (isStatic=false) // PTT -> Dynamic Subscription (isStatic=false)
dmrClient->m_Scanner.AddSubscription(tg, 2, timeout, false); dmrClient->m_Scanner.AddSubscription(tg, slot, timeout, false);
} }
// Check Access on the specific slot // Check Access on the specific slot
@ -818,11 +866,12 @@ bool CDmrmmdvmProtocol::IsValidRssiPacket(const CBuffer &Buffer, CCallsign *call
return valid; return valid;
} }
bool CDmrmmdvmProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header, uint8_t *cmd, uint8_t *CallType) bool CDmrmmdvmProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header, uint8_t *cmd, uint8_t *CallType, uint8_t *Slot)
{ {
uint8_t tag[] = { 'D','M','R','D' }; uint8_t tag[] = { 'D','M','R','D' };
*cmd = CMD_NONE; *cmd = CMD_NONE;
if (Slot) *Slot = 0; // Init safe value
if ( (Buffer.size() == 55) && (Buffer.Compare(tag, sizeof(tag)) == 0) ) if ( (Buffer.size() == 55) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{ {
@ -833,7 +882,7 @@ bool CDmrmmdvmProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique
uint8_t uiSlotType = Buffer.data()[15] & 0x0F; uint8_t uiSlotType = Buffer.data()[15] & 0x0F;
//std::cout << (int)uiSlot << std::endl; //std::cout << (int)uiSlot << std::endl;
if ( (uiFrameType == DMRMMDVM_FRAMETYPE_DATASYNC) && if ( (uiFrameType == DMRMMDVM_FRAMETYPE_DATASYNC) &&
(uiSlot == DMRMMDVM_REFLECTOR_SLOT) && //(uiSlot == DMRMMDVM_REFLECTOR_SLOT) &&
(uiSlotType == MMDVM_SLOTTYPE_HEADER) ) (uiSlotType == MMDVM_SLOTTYPE_HEADER) )
{ {
// extract sync // extract sync
@ -860,6 +909,9 @@ bool CDmrmmdvmProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique
// call type // call type
*CallType = uiCallType; *CallType = uiCallType;
// Return Slot
if (Slot) *Slot = uiSlot;
// link/unlink command ? // link/unlink command ?
if ( uiDstId == 4000 ) if ( uiDstId == 4000 )
@ -903,7 +955,7 @@ bool CDmrmmdvmProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffe
uint8_t uiSlot = (Buffer.data()[15] & 0x80) ? DMR_SLOT2 : DMR_SLOT1; uint8_t uiSlot = (Buffer.data()[15] & 0x80) ? DMR_SLOT2 : DMR_SLOT1;
uint8_t uiCallType = (Buffer.data()[15] & 0x40) ? DMR_PRIVATE_CALL : DMR_GROUP_CALL; uint8_t uiCallType = (Buffer.data()[15] & 0x40) ? DMR_PRIVATE_CALL : DMR_GROUP_CALL;
if ( ((uiFrameType == DMRMMDVM_FRAMETYPE_VOICE) || (uiFrameType == DMRMMDVM_FRAMETYPE_VOICESYNC)) && if ( ((uiFrameType == DMRMMDVM_FRAMETYPE_VOICE) || (uiFrameType == DMRMMDVM_FRAMETYPE_VOICESYNC)) &&
(uiSlot == DMRMMDVM_REFLECTOR_SLOT) && (uiCallType == DMR_GROUP_CALL) ) /*(uiSlot == DMRMMDVM_REFLECTOR_SLOT) &&*/ (uiCallType == DMR_GROUP_CALL) )
{ {
// crack DMR header // crack DMR header
//uint8_t uiSeqId = Buffer.data()[4]; //uint8_t uiSeqId = Buffer.data()[4];
@ -957,7 +1009,7 @@ bool CDmrmmdvmProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffe
if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) ) if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) )
{ {
// handle it // handle it
OnDvHeaderPacketIn(header, Ip, cmd, uiCallType); OnDvHeaderPacketIn(header, Ip, cmd, uiCallType, uiSlot);
} }
} }
@ -1017,7 +1069,7 @@ bool CDmrmmdvmProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer, std::uni
uint8_t uiSlotType = Buffer.data()[15] & 0x0F; uint8_t uiSlotType = Buffer.data()[15] & 0x0F;
//std::cout << (int)uiSlot << std::endl; //std::cout << (int)uiSlot << std::endl;
if ( (uiFrameType == DMRMMDVM_FRAMETYPE_DATASYNC) && if ( (uiFrameType == DMRMMDVM_FRAMETYPE_DATASYNC) &&
(uiSlot == DMRMMDVM_REFLECTOR_SLOT) && //(uiSlot == DMRMMDVM_REFLECTOR_SLOT) &&
(uiSlotType == MMDVM_SLOTTYPE_TERMINATOR) ) (uiSlotType == MMDVM_SLOTTYPE_TERMINATOR) )
{ {
// extract sync // extract sync

@ -70,7 +70,7 @@ protected:
void HandleKeepalives(void); void HandleKeepalives(void);
// stream helpers // stream helpers
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &, uint8_t, uint8_t); void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &, uint8_t, uint8_t, uint8_t);
// packet decoding helpers // packet decoding helpers
bool IsValidConnectPacket(const CBuffer &, CCallsign *, const CIp &); bool IsValidConnectPacket(const CBuffer &, CCallsign *, const CIp &);
@ -80,7 +80,7 @@ protected:
bool IsValidOptionPacket(const CBuffer &, CCallsign *, const CIp &); bool IsValidOptionPacket(const CBuffer &, CCallsign *, const CIp &);
bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *); bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *);
bool IsValidRssiPacket(const CBuffer &, CCallsign *, int *); bool IsValidRssiPacket(const CBuffer &, CCallsign *, int *);
bool IsValidDvHeaderPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, uint8_t *, uint8_t *); bool IsValidDvHeaderPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, uint8_t *, uint8_t *, uint8_t *);
bool IsValidDvFramePacket(const CIp &, const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, std::array<std::unique_ptr<CDvFramePacket>, 3> &); bool IsValidDvFramePacket(const CIp &, const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, std::array<std::unique_ptr<CDvFramePacket>, 3> &);
bool IsValidDvLastFramePacket(const CBuffer &, std::unique_ptr<CDvFramePacket> &); bool IsValidDvLastFramePacket(const CBuffer &, std::unique_ptr<CDvFramePacket> &);
@ -119,6 +119,9 @@ protected:
// for authentication // for authentication
uint32_t m_uiAuthSeed; uint32_t m_uiAuthSeed;
// for debug logging
int m_debugFrameCount;
// config data // config data
unsigned m_DefaultId; unsigned m_DefaultId;
}; };

@ -180,6 +180,10 @@ void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Sanitize source callsign (Strip suffixes)
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

@ -286,6 +286,12 @@ void CM17Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Critical Fix: Sanitize source callsign to strip suffixes (e.g. "KF8S D" -> "KF8S")
// This ensures Dashboard lookups and display are clean.
// GetBase() returns the callsign string up to the first non-alphanumeric character.
my.SetCallsign(my.GetBase(), false);
my.SetSuffix("M17"); my.SetSuffix("M17");
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

@ -208,6 +208,10 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Critical Fix: Sanitize source callsign to strip suffixes (e.g. "KF8S D" -> "KF8S")
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

@ -207,6 +207,10 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Sanitize source callsign (Strip suffixes)
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

@ -392,6 +392,10 @@ void CURFProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
else else
{ {
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Critical Fix: Sanitize source callsign to strip suffixes (e.g. "KF8S D" -> "KF8S")
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());
// no stream open yet, open a new one // no stream open yet, open a new one

@ -266,6 +266,10 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
{ {
// no stream open yet, open a new one // no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign()); CCallsign my(Header->GetMyCallsign());
// Critical Fix: Sanitize source callsign to strip suffixes (e.g. "KF8S D" -> "KF8S")
my.SetCallsign(my.GetBase(), false);
CCallsign rpt1(Header->GetRpt1Callsign()); CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());

Loading…
Cancel
Save

Powered by TurnKey Linux.