better implement V(R) V(S) checking;

r05a04_dev
Bryan Biedenkapp 2 months ago
parent ce6f04e6eb
commit 4f5051e8b6

@ -64,6 +64,7 @@ P25PacketData::P25PacketData(FNENetwork* network, TagP25Data* tag, bool debug) :
m_arpTable(),
m_readyForNextPkt(),
m_suSendSeq(),
m_suRecvSeq(),
m_debug(debug)
{
assert(network != nullptr);
@ -764,6 +765,49 @@ void P25PacketData::dispatch(uint32_t peerId)
}
}
// sequence validation - check N(S) against V(R)
uint8_t receivedNs = status->assembler.dataHeader.getNs();
bool synchronize = status->assembler.dataHeader.getSynchronize();
// Initialize V(R) if first packet from this LLId
auto recvSeqIt = m_suRecvSeq.find(srcLlId);
if (recvSeqIt == m_suRecvSeq.end()) {
m_suRecvSeq[srcLlId] = 0U;
}
uint8_t expectedNs = m_suRecvSeq[srcLlId];
bool sequenceValid = false;
// handle synchronize flag - resets receive window per TIA-102
if (synchronize) {
//LogDebugEx(LOG_P25, "P25PacketData::dispatch()", "synchronize flag set by llId %u, resetting V(R) from %u to %u",
// srcLlId, expectedNs, (receivedNs + 1) % 8);
m_suRecvSeq[srcLlId] = (receivedNs + 1) % 8;
sequenceValid = true;
}
else if (receivedNs == expectedNs || receivedNs == (expectedNs + 1) % 8) {
// accept if N(S) == V(R) or V(R)+1 (allows one-ahead windowing)
m_suRecvSeq[srcLlId] = (receivedNs + 1) % 8;
sequenceValid = true;
//LogDebugEx(LOG_P25, "P25PacketData::dispatch()", "sequence valid, llId %u, N(S) = %u, V(R) now = %u",
// srcLlId, receivedNs, m_suRecvSeq[srcLlId]);
}
else {
// out of sequence - send NACK_OUT_OF_SEQ
LogWarning(LOG_P25, P25_PDU_STR ", NACK_OUT_OF_SEQ, llId %u, expected N(S) %u or %u, received N(S) = %u",
srcLlId, expectedNs, (expectedNs + 1) % 8, receivedNs);
if (status->assembler.getExtendedAddress()) {
write_PDU_Ack_Response(PDUAckClass::NACK, PDUAckType::NACK_OUT_OF_SEQ, expectedNs, srcLlId, true, dstLlId);
} else {
write_PDU_Ack_Response(PDUAckClass::NACK, PDUAckType::NACK_OUT_OF_SEQ, expectedNs, srcLlId, false);
}
break; // don't process out-of-sequence packet
}
if (!sequenceValid) {
break; // should never reach here due to logic above, but safety check
}
// transmit packet to IP network
LogInfoEx(LOG_P25, "PDU -> VTUN, IP Data, srcIp = %s (%u), dstIp = %s (%u), pktLen = %u, proto = %02X%s",
srcIp, srcLlId, dstIp, dstLlId, pktLen, proto, (proto == 0x01) ? " (ICMP)" : "");
@ -782,11 +826,10 @@ void P25PacketData::dispatch(uint32_t peerId)
//LogDebugEx(LOG_P25, "P25PacketData::dispatch()", "marking llId %u ready for next packet (proto = %02X)", srcLlId, proto);
if (status->assembler.getExtendedAddress()) {
m_readyForNextPkt[srcLlId] = true;
write_PDU_Ack_Response(PDUAckClass::ACK, PDUAckType::ACK, status->assembler.dataHeader.getNs(), srcLlId,
true, dstLlId);
write_PDU_Ack_Response(PDUAckClass::ACK, PDUAckType::ACK, receivedNs, srcLlId, true, dstLlId);
} else {
m_readyForNextPkt[srcLlId] = true;
write_PDU_Ack_Response(PDUAckClass::ACK, PDUAckType::ACK, status->assembler.dataHeader.getNs(), srcLlId, false);
write_PDU_Ack_Response(PDUAckClass::ACK, PDUAckType::ACK, receivedNs, srcLlId, false);
}
}
#endif // !defined(_WIN32)

@ -199,7 +199,8 @@ namespace network
std::unordered_map<uint32_t, uint32_t> m_arpTable;
typedef std::pair<const uint32_t, bool> ReadyForNextPktPair;
std::unordered_map<uint32_t, bool> m_readyForNextPkt;
std::unordered_map<uint32_t, uint8_t> m_suSendSeq;
std::unordered_map<uint32_t, uint8_t> m_suSendSeq; // V(S) send state variable per LLId
std::unordered_map<uint32_t, uint8_t> m_suRecvSeq; // V(R) receive state variable per LLId
bool m_debug;

Loading…
Cancel
Save

Powered by TurnKey Linux.