diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index c3d26ac8..f5e59bc2 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -28,6 +28,7 @@ file(GLOB common_SRC
"src/common/p25/lc/tdulc/*.cpp"
"src/common/p25/lc/tsbk/*.cpp"
"src/common/p25/lc/tsbk/mbt/*.cpp"
+ "src/common/p25/sndcp/*.cpp"
"src/common/p25/lookups/*.cpp"
# NXDN module
@@ -68,6 +69,7 @@ file(GLOB common_INCLUDE
"src/common/p25/lc/tdulc/*.h"
"src/common/p25/lc/tsbk/*.h"
"src/common/p25/lc/tsbk/mbt/*.h"
+ "src/common/p25/sndcp/*.h"
"src/common/p25/lookups/*.h"
# NXDN module
diff --git a/src/common/p25/P25Defines.h b/src/common/p25/P25Defines.h
index d674efe5..b4488624 100644
--- a/src/common/p25/P25Defines.h
+++ b/src/common/p25/P25Defines.h
@@ -356,8 +356,8 @@ namespace p25
///
namespace PDURegType {
enum : uint8_t {
- CNCT = 0x00U, // Connect
- DISCNCT = 0x01U, // Disconnect
+ CONNECT = 0x00U, // Connect
+ DISCONNECT = 0x01U, // Disconnect
ACCPT = 0x04U, // Accept
DENY = 0x05U // Deny
};
@@ -393,7 +393,18 @@ namespace p25
READY = 3U, // Ready - SU Activated and Rx/Tx Data
CLOSED = 4U, // Closed - SU not yet Registered or Deregistered
- ILLEGAL = 255U, // Illegal/Unknown
+ ILLEGAL = 255U // Illegal/Unknown
+ };
+ }
+
+ ///
+ /// SNDCP Network Address Type
+ ///
+ namespace SNDCPNAT {
+ enum : uint8_t {
+ IPV4_STATIC_ADDR = 0U, // IPv4 Static Address
+ IPV4_DYN_ADDR = 1U, // IPv4 Dynamic Address
+ IPV4_NO_ADDRESS = 15U // No Address
};
}
@@ -407,6 +418,7 @@ namespace p25
CONV_DATA_ONLY = 2U, // Conventional Data Only
ALTERNATING_CONV_DATA_VOICE = 3U, // Alternating Conventional Voice & Data
TRUNKED_CONV_DATA_ONLY = 4U, // Trunked and Conventional Data Only
+ ALT_T_AND_C_DATA_VOICE = 5U // Alternating Trunked and Conventional Voice & Data
};
}
@@ -482,6 +494,16 @@ namespace p25
};
}
+ ///
+ /// SNDCP Deactivation Types
+ ///
+ namespace SNDCPDeactivationType {
+ enum : uint8_t {
+ DEACT_ALL = 0U, // Deactivate all NSAPIs
+ DEACT_THIS_PDU = 1U // Deactivate NSAPI in this PDU
+ };
+ }
+
const uint8_t LC_SVC_OPT_EMERGENCY = 0x80U;
const uint8_t LC_SVC_OPT_ENCRYPTION = 0x40U;
diff --git a/src/common/p25/sndcp/SNDCPCtxActAccept.cpp b/src/common/p25/sndcp/SNDCPCtxActAccept.cpp
new file mode 100644
index 00000000..417dacea
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxActAccept.cpp
@@ -0,0 +1,110 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#include "Defines.h"
+#include "p25/P25Defines.h"
+#include "p25/sndcp/SNDCPCtxActAccept.h"
+#include "Log.h"
+
+using namespace p25;
+using namespace p25::defines;
+using namespace p25::sndcp;
+
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Initializes a new instance of the SNDCPCtxActAccept class.
+///
+SNDCPCtxActAccept::SNDCPCtxActAccept() : SNDCPPacket(),
+ m_priority(4U),
+ m_readyTimer(SNDCPReadyTimer::TEN_SECONDS),
+ m_standbyTimer(SNDCPStandbyTimer::ONE_MINUTE),
+ m_nat(SNDCPNAT::IPV4_STATIC_ADDR),
+ m_ipAddress(0U),
+ m_mtu(SNDCP_MTU_510)
+{
+ m_pduType = SNDCP_PDUType::ACT_TDS_CTX;
+}
+
+///
+/// Decode a SNDCP context activation response.
+///
+///
+/// True, if packet was decoded, otherwise false.
+bool SNDCPCtxActAccept::decode(const uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::decodeHeader(data, false);
+
+ m_priority = (uint8_t)((data[1U] >> 4) & 0x0FU); // Priority
+ m_readyTimer = (uint8_t)(data[1U] & 0x0FU); // Ready Timer
+ m_standbyTimer = (uint8_t)((data[2U] >> 4) & 0x0FU); // Standby Timer
+ m_nat = (uint8_t)(data[2U] & 0x0FU); // NAT
+
+ m_ipAddress = 0U; // IP Address
+ m_ipAddress = data[3U];
+ m_ipAddress = (m_ipAddress << 8) + data[4U];
+ m_ipAddress = (m_ipAddress << 8) + data[5U];
+ m_ipAddress = (m_ipAddress << 8) + data[6U];
+
+ m_mtu = (uint8_t)((data[9U] >> 4) & 0x0FU); // MTU
+
+ return true;
+}
+
+///
+/// Encode a SNDCP context activation response.
+///
+///
+void SNDCPCtxActAccept::encode(uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::encodeHeader(data, true);
+
+ data[1U] = ((m_priority << 4U) & 0xF0U) + // Priority
+ (m_readyTimer & 0x0FU); // Ready Timer
+ data[2U] = ((m_standbyTimer << 4U) & 0xF0U) + // Standby Timer
+ (m_nat & 0x0FU); // NAT
+
+ data[3U] = (uint8_t)((m_ipAddress >> 24) & 0xFFU); // IP Address
+ data[4U] = (uint8_t)((m_ipAddress >> 16) & 0xFFU);
+ data[5U] = (uint8_t)((m_ipAddress >> 8) & 0xFFU);
+ data[6U] = (uint8_t)((m_ipAddress >> 0) & 0xFFU);
+
+ data[9U] = ((m_mtu << 4U) & 0xF0U); // MTU
+}
+
+// ---------------------------------------------------------------------------
+// Protected Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Internal helper to copy the the class.
+///
+///
+void SNDCPCtxActAccept::copy(const SNDCPCtxActAccept& data)
+{
+ m_priority = data.m_priority;
+ m_readyTimer = data.m_readyTimer;
+ m_standbyTimer = data.m_standbyTimer;
+ m_nat = data.m_nat;
+
+ m_ipAddress = data.m_ipAddress;
+
+ m_mtu = data.m_mtu;
+}
diff --git a/src/common/p25/sndcp/SNDCPCtxActAccept.h b/src/common/p25/sndcp/SNDCPCtxActAccept.h
new file mode 100644
index 00000000..21d073de
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxActAccept.h
@@ -0,0 +1,62 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#if !defined(__P25_SNDCP__SNDCPCTXACTACCEPT_H__)
+#define __P25_SNDCP__SNDCPCTXACTACCEPT_H__
+
+#include "common/Defines.h"
+#include "common/p25/sndcp/SNDCPPacket.h"
+#include "common/Utils.h"
+
+#include
+
+namespace p25
+{
+ namespace sndcp
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Represents a SNDCP PDU context accept response.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API SNDCPCtxActAccept : public SNDCPPacket {
+ public:
+ /// Initializes a new instance of the SNDCPCtxActAccept class.
+ SNDCPCtxActAccept();
+
+ /// Decode a SNDCP context activation response.
+ bool decode(const uint8_t* data);
+ /// Encode a SNDCP context activation response.
+ void encode(uint8_t* data);
+
+ public:
+ /// Priority
+ __PROPERTY(uint8_t, priority, Priority);
+ /// Ready Timer
+ __PROPERTY(uint8_t, readyTimer, ReadyTimer);
+ /// Ready Timer
+ __PROPERTY(uint8_t, standbyTimer, StandbyTimer);
+ /// Network Address Type
+ __PROPERTY(uint8_t, nat, NAT);
+
+ /// IP Address
+ __PROPERTY(ulong64_t, ipAddress, IPAddress);
+
+ /// MTU
+ __PROPERTY(uint8_t, mtu, MTU);
+
+ __COPY(SNDCPCtxActAccept);
+ };
+ } // namespace sndcp
+} // namespace p25
+
+#endif // __P25_SNDCP__SNDCPCTXACTACCEPT_H__
diff --git a/src/common/p25/sndcp/SNDCPCtxActReject.cpp b/src/common/p25/sndcp/SNDCPCtxActReject.cpp
new file mode 100644
index 00000000..cd40d04d
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxActReject.cpp
@@ -0,0 +1,73 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#include "Defines.h"
+#include "p25/P25Defines.h"
+#include "p25/sndcp/SNDCPCtxActReject.h"
+#include "Log.h"
+
+using namespace p25;
+using namespace p25::defines;
+using namespace p25::sndcp;
+
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Initializes a new instance of the SNDCPCtxActReject class.
+///
+SNDCPCtxActReject::SNDCPCtxActReject() : SNDCPPacket(),
+ m_rejectCode(SNDCPRejectReason::ANY_REASON)
+{
+ m_pduType = SNDCP_PDUType::ACT_TDS_CTX_REJECT;
+}
+
+///
+/// Decode a SNDCP context activation reject packet.
+///
+///
+/// True, if packet was decoded, otherwise false.
+bool SNDCPCtxActReject::decode(const uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::decodeHeader(data, false);
+
+ m_rejectCode = data[1U]; // Reject Code
+
+ return true;
+}
+
+///
+/// Encode a SNDCP context activation reject packet.
+///
+///
+void SNDCPCtxActReject::encode(uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::encodeHeader(data, true);
+
+ data[1U] = m_rejectCode; // Reject Code
+}
+
+///
+/// Internal helper to copy the the class.
+///
+///
+void SNDCPCtxActReject::copy(const SNDCPCtxActReject& data)
+{
+ m_rejectCode = data.m_rejectCode;
+}
diff --git a/src/common/p25/sndcp/SNDCPCtxActReject.h b/src/common/p25/sndcp/SNDCPCtxActReject.h
new file mode 100644
index 00000000..60b2dbd6
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxActReject.h
@@ -0,0 +1,50 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#if !defined(__P25_SNDCP__SNDCPCTXACTREJECT_H__)
+#define __P25_SNDCP__SNDCPCTXACTREJECT_H__
+
+#include "common/Defines.h"
+#include "common/p25/sndcp/SNDCPPacket.h"
+#include "common/Utils.h"
+
+#include
+
+namespace p25
+{
+ namespace sndcp
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Represents a SNDCP PDU context activation reject response.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API SNDCPCtxActReject : public SNDCPPacket {
+ public:
+ /// Initializes a new instance of the SNDCPCtxActReject class.
+ SNDCPCtxActReject();
+
+ /// Decode a SNDCP context activation reject packet.
+ bool decode(const uint8_t* data);
+ /// Encode a SNDCP context activation reject packet.
+ void encode(uint8_t* data);
+
+ public:
+ /// Reject Code
+ __PROPERTY(uint8_t, rejectCode, RejectCode);
+
+ __COPY(SNDCPCtxActReject);
+ };
+ } // namespace sndcp
+} // namespace p25
+
+#endif // __P25_SNDCP__SNDCPCTXACTREJECT_H__
diff --git a/src/common/p25/sndcp/SNDCPCtxActRequest.cpp b/src/common/p25/sndcp/SNDCPCtxActRequest.cpp
new file mode 100644
index 00000000..4e50022f
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxActRequest.cpp
@@ -0,0 +1,97 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#include "Defines.h"
+#include "p25/P25Defines.h"
+#include "p25/sndcp/SNDCPCtxActRequest.h"
+#include "Log.h"
+
+using namespace p25;
+using namespace p25::defines;
+using namespace p25::sndcp;
+
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Initializes a new instance of the SNDCPCtxActRequest class.
+///
+SNDCPCtxActRequest::SNDCPCtxActRequest() : SNDCPPacket(),
+ m_nat(SNDCPNAT::IPV4_NO_ADDRESS),
+ m_ipAddress(0U),
+ m_dsut(SNDCP_DSUT::ALT_T_AND_C_DATA_VOICE)
+{
+ m_pduType = SNDCP_PDUType::ACT_TDS_CTX;
+}
+
+///
+/// Decode a SNDCP context activation request.
+///
+///
+/// True, if packet was decoded, otherwise false.
+bool SNDCPCtxActRequest::decode(const uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::decodeHeader(data, false);
+
+ m_nsapi = (uint8_t)((data[1U] >> 4) & 0x0FU); // NSAPI
+ m_nat = (uint8_t)((data[1U]) & 0x0FU); // NAT
+
+ m_ipAddress = 0U; // IP Address
+ m_ipAddress = data[2U];
+ m_ipAddress = (m_ipAddress << 8) + data[3U];
+ m_ipAddress = (m_ipAddress << 8) + data[4U];
+ m_ipAddress = (m_ipAddress << 8) + data[5U];
+
+ m_dsut = (uint8_t)((data[6U] >> 4) & 0x0FU); // Data Subscriber Unit Type
+
+ return true;
+}
+
+///
+/// Encode a SNDCP context activation request.
+///
+///
+void SNDCPCtxActRequest::encode(uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::encodeHeader(data, true);
+
+ data[1U] = ((m_nsapi << 4U) & 0xF0U) + // NSAPI
+ (m_nat & 0x0FU); // NAT
+
+ data[2U] = (uint8_t)((m_ipAddress >> 24) & 0xFFU); // IP Address
+ data[3U] = (uint8_t)((m_ipAddress >> 16) & 0xFFU);
+ data[4U] = (uint8_t)((m_ipAddress >> 8) & 0xFFU);
+ data[5U] = (uint8_t)((m_ipAddress >> 0) & 0xFFU);
+
+ data[6U] = ((m_dsut << 4U) & 0xF0U); // Data Subscriber Unit Type
+}
+
+///
+/// Internal helper to copy the the class.
+///
+///
+void SNDCPCtxActRequest::copy(const SNDCPCtxActRequest& data)
+{
+ m_nsapi = data.m_nsapi;
+ m_nat = data.m_nat;
+
+ m_ipAddress = data.m_ipAddress;
+
+ m_dsut = data.m_dsut;
+}
diff --git a/src/common/p25/sndcp/SNDCPCtxActRequest.h b/src/common/p25/sndcp/SNDCPCtxActRequest.h
new file mode 100644
index 00000000..148836de
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxActRequest.h
@@ -0,0 +1,56 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#if !defined(__P25_SNDCP__SNDCPCTXACTREQUEST_H__)
+#define __P25_SNDCP__SNDCPCTXACTREQUEST_H__
+
+#include "common/Defines.h"
+#include "common/p25/sndcp/SNDCPPacket.h"
+#include "common/Utils.h"
+
+#include
+
+namespace p25
+{
+ namespace sndcp
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Represents a SNDCP PDU context activation request.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API SNDCPCtxActRequest : public SNDCPPacket {
+ public:
+ /// Initializes a new instance of the SNDCPCtxActRequest class.
+ SNDCPCtxActRequest();
+
+ /// Decode a SNDCP context activation request.
+ bool decode(const uint8_t* data);
+ /// Encode a SNDCP context activation request.
+ void encode(uint8_t* data);
+
+ public:
+ /// Network Address Type
+ __PROPERTY(uint8_t, nat, NAT);
+
+ /// IP Address
+ __PROPERTY(ulong64_t, ipAddress, IPAddress);
+
+ /// Data Subscriber Unit Type
+ __PROPERTY(uint8_t, dsut, DSUT);
+
+ __COPY(SNDCPCtxActRequest);
+ };
+ } // namespace sndcp
+} // namespace p25
+
+#endif // __P25_SNDCP__SNDCPCTXACTREQUEST_H__
diff --git a/src/common/p25/sndcp/SNDCPCtxDeactivation.cpp b/src/common/p25/sndcp/SNDCPCtxDeactivation.cpp
new file mode 100644
index 00000000..d2831f6e
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxDeactivation.cpp
@@ -0,0 +1,73 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#include "Defines.h"
+#include "p25/P25Defines.h"
+#include "p25/sndcp/SNDCPCtxDeactivation.h"
+#include "Log.h"
+
+using namespace p25;
+using namespace p25::defines;
+using namespace p25::sndcp;
+
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Initializes a new instance of the SNDCPCtxDeactivation class.
+///
+SNDCPCtxDeactivation::SNDCPCtxDeactivation() : SNDCPPacket(),
+ m_deactType(SNDCPDeactivationType::DEACT_ALL)
+{
+ m_pduType = SNDCP_PDUType::DEACT_TDS_CTX_REQ;
+}
+
+///
+/// Decode a SNDCP context deactivation packet.
+///
+///
+/// True, if packet was decoded, otherwise false.
+bool SNDCPCtxDeactivation::decode(const uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::decodeHeader(data, false);
+
+ m_deactType = data[1U]; // Deactivation Type
+
+ return true;
+}
+
+///
+/// Encode a SNDCP context deactivation packet.
+///
+///
+void SNDCPCtxDeactivation::encode(uint8_t* data)
+{
+ assert(data != nullptr);
+
+ SNDCPPacket::encodeHeader(data, true);
+
+ data[1U] = m_deactType; // Deactivation Type
+}
+
+///
+/// Internal helper to copy the the class.
+///
+///
+void SNDCPCtxDeactivation::copy(const SNDCPCtxDeactivation& data)
+{
+ m_deactType = data.m_deactType;
+}
diff --git a/src/common/p25/sndcp/SNDCPCtxDeactivation.h b/src/common/p25/sndcp/SNDCPCtxDeactivation.h
new file mode 100644
index 00000000..5315f986
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPCtxDeactivation.h
@@ -0,0 +1,51 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#if !defined(__P25_SNDCP__SNDCPCTXDEACTIVATION_H__)
+#define __P25_SNDCP__SNDCPCTXDEACTIVATION_H__
+
+#include "common/Defines.h"
+#include "common/p25/sndcp/SNDCPPacket.h"
+#include "common/Utils.h"
+
+#include
+
+namespace p25
+{
+ namespace sndcp
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Represents a SNDCP PDU context deactivation.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API SNDCPCtxDeactivation : public SNDCPPacket {
+ public:
+ /// Initializes a new instance of the SNDCPCtxDeactivation class.
+ SNDCPCtxDeactivation();
+
+ /// Decode a SNDCP context deactivation packet.
+ bool decode(const uint8_t* data);
+ /// Encode a SNDCP context deactivation packet.
+ void encode(uint8_t* data);
+
+ public:
+ /** Common Data */
+ /// Deactivation Type
+ __PROPERTY(uint8_t, deactType, DeactType);
+
+ __COPY(SNDCPCtxDeactivation);
+ };
+ } // namespace sndcp
+} // namespace p25
+
+#endif // __P25_SNDCP__SNDCPCTXDEACTIVATION_H__
diff --git a/src/common/p25/sndcp/SNDCPFactory.cpp b/src/common/p25/sndcp/SNDCPFactory.cpp
new file mode 100644
index 00000000..9aca8f79
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPFactory.cpp
@@ -0,0 +1,90 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#include "Defines.h"
+#include "p25/P25Defines.h"
+#include "p25/sndcp/SNDCPFactory.h"
+#include "Log.h"
+#include "Utils.h"
+
+using namespace p25;
+using namespace p25::defines;
+using namespace p25::sndcp;
+
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Initializes a new instance of the SNDCPFactory class.
+///
+SNDCPFactory::SNDCPFactory() = default;
+
+///
+/// Finalizes a instance of SNDCPFactory class.
+///
+SNDCPFactory::~SNDCPFactory() = default;
+
+///
+/// Create an instance of a SNDCPPacket.
+///
+///
+/// True, if packet was decoded, otherwise false.
+std::unique_ptr SNDCPFactory::create(const uint8_t* data)
+{
+ assert(data != nullptr);
+
+ uint8_t pduType = (uint8_t)((data[0U] >> 4) & 0x0FU); // SNDCP PDU Message Type
+
+ switch (pduType) {
+ case SNDCP_PDUType::ACT_TDS_CTX:
+ return decode(new SNDCPCtxActRequest(), data);
+ break;
+ case SNDCP_PDUType::DEACT_TDS_CTX_REQ:
+ return decode(new SNDCPCtxDeactivation(), data);
+ break;
+ case SNDCP_PDUType::RF_CONFIRMED:
+ break;
+ case SNDCP_PDUType::RF_UNCONFIRMED:
+ break;
+ default:
+ LogError(LOG_P25, "SNDCPFactory::create(), unknown SNDCP PDU value, pduType = $%02X", pduType);
+ break;
+ }
+
+ return nullptr;
+}
+
+// ---------------------------------------------------------------------------
+// Private Class Members
+// ---------------------------------------------------------------------------
+
+///
+///
+///
+///
+///
+///
+///
+std::unique_ptr SNDCPFactory::decode(SNDCPPacket* packet, const uint8_t* data)
+{
+ assert(packet != nullptr);
+ assert(data != nullptr);
+
+ if (!packet->decode(data)) {
+ return nullptr;
+ }
+
+ return std::unique_ptr(packet);
+}
diff --git a/src/common/p25/sndcp/SNDCPFactory.h b/src/common/p25/sndcp/SNDCPFactory.h
new file mode 100644
index 00000000..e6847b8d
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPFactory.h
@@ -0,0 +1,50 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#if !defined(__P25_SNDCP__SNDCP_FACTORY_H__)
+#define __P25_SNDCP__SNDCP_FACTORY_H__
+
+#include "common/Defines.h"
+
+#include "common/p25/sndcp/SNDCPPacket.h"
+#include "common/p25/sndcp/SNDCPCtxActAccept.h"
+#include "common/p25/sndcp/SNDCPCtxActReject.h"
+#include "common/p25/sndcp/SNDCPCtxActRequest.h"
+#include "common/p25/sndcp/SNDCPCtxDeactivation.h"
+
+namespace p25
+{
+ namespace sndcp
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Helper class to instantiate an instance of a SNDCP packet.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API SNDCPFactory {
+ public:
+ /// Initializes a new instance of the SNDCPFactory class.
+ SNDCPFactory();
+ /// Finalizes a instance of the SNDCPFactory class.
+ ~SNDCPFactory();
+
+ /// Create an instance of a SNDCPPacket.
+ static std::unique_ptr create(const uint8_t* data);
+
+ private:
+ ///
+ static std::unique_ptr decode(SNDCPPacket* packet, const uint8_t* data);
+ };
+ } // namespace sndcp
+} // namespace p25
+
+#endif // __P25_SNDCP__SNDCP_FACTORY_H__
diff --git a/src/common/p25/sndcp/SNDCPPacket.cpp b/src/common/p25/sndcp/SNDCPPacket.cpp
new file mode 100644
index 00000000..6a049313
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPPacket.cpp
@@ -0,0 +1,104 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#include "Defines.h"
+#include "p25/P25Defines.h"
+#include "p25/sndcp/SNDCPPacket.h"
+#include "Log.h"
+
+using namespace p25;
+using namespace p25::defines;
+using namespace p25::sndcp;
+
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Initializes a copy instance of the SNDCPPacket class.
+///
+///
+SNDCPPacket::SNDCPPacket(const SNDCPPacket& data) : SNDCPPacket()
+{
+ copy(data);
+}
+
+///
+/// Initializes a new instance of the SNDCPPacket class.
+///
+SNDCPPacket::SNDCPPacket() :
+ m_pduType(SNDCP_PDUType::ACT_TDS_CTX),
+ m_sndcpVersion(SNDCP_VERSION_1),
+ m_nsapi(0U)
+{
+ /* stub */
+}
+
+///
+/// Finalizes a instance of SNDCPPacket class.
+///
+SNDCPPacket::~SNDCPPacket() = default;
+
+// ---------------------------------------------------------------------------
+// Protected Class Members
+// ---------------------------------------------------------------------------
+
+///
+/// Internal helper to decode a SNDCP header.
+///
+///
+///
+/// True, if header was decoded, otherwise false.
+bool SNDCPPacket::decodeHeader(const uint8_t* data, bool outbound)
+{
+ assert(data != nullptr);
+
+ m_pduType = (uint8_t)((data[0U] >> 4) & 0x0FU); // SNDCP PDU Message Type
+
+ if (m_pduType == SNDCP_PDUType::ACT_TDS_CTX && !outbound) {
+ m_sndcpVersion = (uint8_t)((data[0U]) & 0x0FU); // SNDCP Version
+ } else {
+ m_nsapi = (uint8_t)((data[0U]) & 0x0FU); // NSAPI
+ }
+
+ return true;
+}
+
+///
+/// Internal helper to encode a SNDCP header.
+///
+///
+///
+void SNDCPPacket::encodeHeader(uint8_t* data, bool outbound)
+{
+ assert(data != nullptr);
+
+ data[0U] = ((m_pduType << 4U) & 0xF0U); // SNDCP PDU Message Type
+
+ if (m_pduType == SNDCP_PDUType::ACT_TDS_CTX && !outbound) {
+ data[0U] += (m_sndcpVersion & 0x0FU); // SNDCP Version
+ } else {
+ data[0U] += (m_nsapi & 0x0FU); // NSAPI
+ }
+}
+
+///
+/// Internal helper to copy the the class.
+///
+///
+void SNDCPPacket::copy(const SNDCPPacket& data)
+{
+ m_pduType = data.m_pduType;
+ m_sndcpVersion = data.m_sndcpVersion;
+}
diff --git a/src/common/p25/sndcp/SNDCPPacket.h b/src/common/p25/sndcp/SNDCPPacket.h
new file mode 100644
index 00000000..0b78fbf7
--- /dev/null
+++ b/src/common/p25/sndcp/SNDCPPacket.h
@@ -0,0 +1,64 @@
+// 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.
+*
+* @package DVM / Common Library
+* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+*
+* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
+*
+*/
+#if !defined(__P25_SNDCP__SNDCPHEADER_H__)
+#define __P25_SNDCP__SNDCPHEADER_H__
+
+#include "common/Defines.h"
+#include "common/Utils.h"
+
+#include
+
+namespace p25
+{
+ namespace sndcp
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Represents a SNDCP PDU packet header.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API SNDCPPacket {
+ public:
+ /// Initializes a copy instance of the SNDCPPacket class.
+ SNDCPPacket(const SNDCPPacket& data);
+ /// Initializes a new instance of the SNDCPPacket class.
+ SNDCPPacket();
+ /// Finalizes a instance of the SNDCPPacket class.
+ ~SNDCPPacket();
+
+ /// Decode a SNDCP packet.
+ virtual bool decode(const uint8_t* data) = 0;
+ /// Encode a SNDCP packet.
+ virtual void encode(uint8_t* data) = 0;
+
+ public:
+ /** Common Data */
+ /// SNDCP PDU Type.
+ __PROTECTED_PROPERTY(uint8_t, pduType, PDUType);
+ /// Link control opcode.
+ __READONLY_PROPERTY(uint8_t, sndcpVersion, SNDCPVersion);
+ /// Network Service Access Point Identifier
+ __PROTECTED_PROPERTY(uint8_t, nsapi, NSAPI);
+
+ protected:
+ /// Internal helper to decode a SNDCP header.
+ bool decodeHeader(const uint8_t* data, bool outbound = false);
+ /// Internal helper to encode a SNDCP header.
+ void encodeHeader(uint8_t* data, bool outbound = false);
+
+ __PROTECTED_COPY(SNDCPPacket);
+ };
+ } // namespace sndcp
+} // namespace p25
+
+#endif // __P25_SNDCP__SNDCPHEADER_H__
diff --git a/src/host/p25/packet/Data.cpp b/src/host/p25/packet/Data.cpp
index 1cec7dfd..1ffb843d 100644
--- a/src/host/p25/packet/Data.cpp
+++ b/src/host/p25/packet/Data.cpp
@@ -16,6 +16,7 @@
#include "common/p25/P25Defines.h"
#include "common/p25/acl/AccessControl.h"
#include "common/p25/lc/tdulc/TDULCFactory.h"
+#include "common/p25/sndcp/SNDCPFactory.h"
#include "common/p25/P25Utils.h"
#include "common/p25/Sync.h"
#include "common/edac/CRC.h"
@@ -24,10 +25,11 @@
#include "p25/packet/Data.h"
#include "ActivityLog.h"
-using namespace p25::packet;
-using namespace p25::data;
-using namespace p25::defines;
using namespace p25;
+using namespace p25::defines;
+using namespace p25::data;
+using namespace p25::sndcp;
+using namespace p25::packet;
#include
#include
@@ -38,6 +40,7 @@ using namespace p25;
const uint32_t CONN_WAIT_TIMEOUT = 1U;
const uint32_t SNDCP_READY_TIMEOUT = 10U;
+const uint32_t SNDCP_STANDBY_TIMEOUT = 60U;
// ---------------------------------------------------------------------------
// Public Class Members
@@ -224,6 +227,12 @@ bool Data::process(uint8_t* data, uint32_t len)
// process all blocks in the data stream
uint32_t dataOffset = 0U;
+ // if the primary header has a header offset ensure data if offset by that amount
+ if (m_rfDataHeader.getHeaderOffset() > 0U) {
+ offset += m_rfDataHeader.getHeaderOffset() * 8;
+ m_pduUserDataLength -= m_rfDataHeader.getHeaderOffset();
+ }
+
// if we are using a secondary header place it in the PDU user data buffer
if (m_rfUseSecondHeader) {
m_rfSecondHeader.getData(m_pduUserData + dataOffset);
@@ -349,6 +358,36 @@ bool Data::process(uint8_t* data, uint32_t len)
LogMessage(LOG_RF, P25_PDU_STR ", ISP, response, fmt = $%02X, rspClass = $%02X, rspType = $%02X, rspStatus = $%02X, llId = %u, srcLlId = %u",
m_rfDataHeader.getFormat(), m_rfDataHeader.getResponseClass(), m_rfDataHeader.getResponseType(), m_rfDataHeader.getResponseStatus(),
m_rfDataHeader.getLLId(), m_rfDataHeader.getSrcLLId());
+
+ if (m_rfDataHeader.getResponseClass() == PDUAckClass::ACK && m_rfDataHeader.getResponseType() == PDUAckType::ACK) {
+ LogMessage(LOG_RF, P25_PDU_STR ", ISP, response, OSP ACK, llId = %u",
+ m_rfDataHeader.getLLId());
+ } else {
+ if (m_rfDataHeader.getResponseClass() == PDUAckClass::NACK) {
+ switch (m_rfDataHeader.getResponseType()) {
+ case PDUAckType::NACK_ILLEGAL:
+ LogMessage(LOG_RF, P25_PDU_STR ", ISP, response, OSP NACK, illegal format, llId = %u",
+ m_rfDataHeader.getLLId());
+ break;
+ case PDUAckType::NACK_PACKET_CRC:
+ LogMessage(LOG_RF, P25_PDU_STR ", ISP, response, OSP NACK, packet CRC error, llId = %u",
+ m_rfDataHeader.getLLId());
+ break;
+ case PDUAckType::NACK_SEQ:
+ case PDUAckType::NACK_OUT_OF_SEQ:
+ LogMessage(LOG_RF, P25_PDU_STR ", ISP, response, OSP NACK, packet out of sequence, llId = %u",
+ m_rfDataHeader.getLLId());
+ break;
+ case PDUAckType::NACK_UNDELIVERABLE:
+ LogMessage(LOG_RF, P25_PDU_STR ", ISP, response, OSP NACK, packet undeliverable, llId = %u",
+ m_rfDataHeader.getLLId());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
}
if (m_repeatPDU) {
@@ -367,14 +406,14 @@ bool Data::process(uint8_t* data, uint32_t len)
{
uint8_t regType = (m_pduUserData[0] >> 4) & 0x0F;
switch (regType) {
- case PDURegType::CNCT:
+ case PDURegType::CONNECT:
{
uint32_t llId = (m_pduUserData[1U] << 16) + (m_pduUserData[2U] << 8) + m_pduUserData[3U];
ulong64_t ipAddr = (m_pduUserData[8U] << 24) + (m_pduUserData[9U] << 16) +
(m_pduUserData[10U] << 8) + m_pduUserData[11U];
if (m_verbose) {
- LogMessage(LOG_RF, P25_PDU_STR ", CNCT (Registration Request Connect), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str());
+ LogMessage(LOG_RF, P25_PDU_STR ", CONNECT (Registration Request Connect), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str());
}
m_connQueueTable[llId] = std::make_tuple(m_rfDataHeader.getMFId(), ipAddr);
@@ -383,12 +422,12 @@ bool Data::process(uint8_t* data, uint32_t len)
m_connTimerTable[llId].start();
}
break;
- case PDURegType::DISCNCT:
+ case PDURegType::DISCONNECT:
{
uint32_t llId = (m_pduUserData[1U] << 16) + (m_pduUserData[2U] << 8) + m_pduUserData[3U];
if (m_verbose) {
- LogMessage(LOG_RF, P25_PDU_STR ", DISCNCT (Registration Request Disconnect), llId = %u", llId);
+ LogMessage(LOG_RF, P25_PDU_STR ", DISCONNECT (Registration Request Disconnect), llId = %u", llId);
}
if (hasLLIdFNEReg(llId)) {
@@ -416,7 +455,7 @@ bool Data::process(uint8_t* data, uint32_t len)
m_rfDataHeader.getAMBTOpcode(), m_rfDataHeader.getBlocksToFollow());
}
- processSNDCP();
+ processSNDCPControl();
}
break;
case PDUSAP::TRUNK_CTRL:
@@ -939,7 +978,7 @@ void Data::sndcpInitialize(uint32_t llId)
if (!isSNDCPInitialized(llId)) {
m_sndcpStateTable[llId] = SNDCPState::IDLE;
m_sndcpReadyTimers[llId] = Timer(1000U, SNDCP_READY_TIMEOUT);
- m_sndcpStandyTimers[llId] = Timer(1000U, 1000U);
+ m_sndcpStandbyTimers[llId] = Timer(1000U, SNDCP_STANDBY_TIMEOUT);
if (m_verbose) {
LogMessage(LOG_RF, P25_PDU_STR ", SNDCP, first initialize, llId = %u, state = %u", llId, (uint8_t)SNDCPState::IDLE);
@@ -962,6 +1001,37 @@ bool Data::isSNDCPInitialized(uint32_t llId) const
return false;
}
+///
+/// Helper to reset the SNDCP state for a logical link ID.
+///
+///
+///
+void Data::sndcpReset(uint32_t llId, bool callTerm)
+{
+ if (isSNDCPInitialized(llId)) {
+ if (m_verbose) {
+ LogMessage(LOG_RF, P25_PDU_STR ", SNDCP, reset, llId = %u, state = %u", llId, (uint8_t)m_sndcpStateTable[llId]);
+ }
+
+ m_sndcpStateTable[llId] = SNDCPState::CLOSED;
+ m_sndcpReadyTimers[llId].stop();
+ m_sndcpStandbyTimers[llId].stop();
+
+ if (callTerm) {
+ if (m_verbose) {
+ LogMessage(LOG_RF, P25_TDULC_STR ", CALL_TERM (Call Termination), llId = %u", llId);
+ }
+
+ std::unique_ptr lc = std::make_unique();
+ m_p25->m_control->writeRF_TDULC(lc.get(), true);
+
+ if (m_p25->m_notifyCC) {
+ m_p25->notifyCC_ReleaseGrant(llId);
+ }
+ }
+ }
+}
+
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
@@ -1002,7 +1072,7 @@ Data::Data(Control* p25, bool dumpPDUData, bool repeatPDU, bool debug, bool verb
m_connTimerTable(),
m_sndcpStateTable(),
m_sndcpReadyTimers(),
- m_sndcpStandyTimers(),
+ m_sndcpStandbyTimers(),
m_dumpPDUData(dumpPDUData),
m_repeatPDU(repeatPDU),
m_verbose(verbose),
@@ -1027,7 +1097,7 @@ Data::Data(Control* p25, bool dumpPDUData, bool repeatPDU, bool debug, bool verb
m_sndcpStateTable.clear();
m_sndcpReadyTimers.clear();
- m_sndcpStandyTimers.clear();
+ m_sndcpStandbyTimers.clear();
}
///
@@ -1045,14 +1115,110 @@ Data::~Data()
///
/// Helper used to process SNDCP control data from PDU data.
///
-///
-///
-bool Data::processSNDCP()
+bool Data::processSNDCPControl()
{
if (!m_p25->m_sndcpSupport) {
return false;
}
+ uint8_t data[P25_PDU_UNCONFIRMED_LENGTH_BYTES];
+ ::memset(data, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES);
+
+ std::unique_ptr packet = SNDCPFactory::create(m_pduUserData);
+ if (packet == nullptr) {
+ LogWarning(LOG_RF, P25_PDU_STR ", undecodable SNDCP packet");
+ return false;
+ }
+
+ uint32_t llId = m_rfDataHeader.getLLId();
+
+ switch (packet->getPDUType()) {
+ case SNDCP_PDUType::ACT_TDS_CTX:
+ {
+ SNDCPCtxActRequest* isp = static_cast(packet.get());
+ if (m_verbose) {
+ LogMessage(LOG_RF, P25_PDU_STR ", SNDCP context activation request, llId = %u, ipAddr = %08lX, nat = $%02X, dsut = $%02X", llId,
+ isp->getIPAddress(), isp->getNAT(), isp->getDSUT());
+ }
+
+ DataHeader rspHeader = DataHeader();
+ rspHeader.setFormat(PDUFormatType::CONFIRMED);
+ rspHeader.setMFId(MFG_STANDARD);
+ rspHeader.setAckNeeded(true);
+ rspHeader.setOutbound(true);
+ rspHeader.setSAP(PDUSAP::SNDCP_CTRL_DATA);
+ rspHeader.setLLId(llId);
+ rspHeader.setBlocksToFollow(1U);
+
+ // which network address type is this?
+ switch (isp->getNAT()) {
+ case SNDCPNAT::IPV4_STATIC_ADDR:
+ {
+ std::unique_ptr osp = std::make_unique();
+ osp->setNSAPI(packet->getNSAPI());
+ osp->setRejectCode(SNDCPRejectReason::DYN_IP_ALLOCATION_UNSUPPORTED);
+
+ osp->encode(data);
+ writeRF_PDU_User(rspHeader, rspHeader, false, data);
+
+ sndcpReset(llId, true);
+
+ // TODO TODO TODO
+ }
+ break;
+
+ case SNDCPNAT::IPV4_DYN_ADDR:
+ {
+ std::unique_ptr osp = std::make_unique();
+ osp->setNSAPI(packet->getNSAPI());
+ osp->setRejectCode(SNDCPRejectReason::STATIC_IP_ALLOCATION_UNSUPPORTED);
+
+ osp->encode(data);
+ writeRF_PDU_User(rspHeader, rspHeader, false, data);
+
+ sndcpReset(llId, true);
+
+ // TODO TODO TODO
+ }
+ break;
+
+ default:
+ {
+ std::unique_ptr osp = std::make_unique();
+ osp->setNSAPI(packet->getNSAPI());
+ osp->setRejectCode(SNDCPRejectReason::ANY_REASON);
+
+ osp->encode(data);
+ writeRF_PDU_User(rspHeader, rspHeader, false, data);
+
+ sndcpReset(llId, true);
+ }
+ break;
+ }
+ }
+ break;
+
+ case SNDCP_PDUType::DEACT_TDS_CTX_REQ:
+ {
+ SNDCPCtxDeactivation* isp = static_cast(packet.get());
+ if (m_verbose) {
+ LogMessage(LOG_RF, P25_PDU_STR ", SNDCP context deactivation request, llId = %u, deactType = %02X", llId,
+ isp->getDeactType());
+ }
+
+ writeRF_PDU_Ack_Response(PDUAckClass::ACK, PDUAckType::ACK, 0U, llId);
+ sndcpReset(llId, true);
+ }
+ break;
+
+ default:
+ {
+ LogError(LOG_RF, P25_PDU_STR ", unhandled SNDCP PDU Type, pduType = $%02X", packet->getPDUType());
+ sndcpReset(llId, true);
+ }
+ break;
+ } // switch (packet->getPDUType())
+
return true;
}
diff --git a/src/host/p25/packet/Data.h b/src/host/p25/packet/Data.h
index 6e389d6e..61e74474 100644
--- a/src/host/p25/packet/Data.h
+++ b/src/host/p25/packet/Data.h
@@ -64,9 +64,11 @@ namespace p25
/** SNDCP */
/// Helper to initialize the SNDCP state for a logical link ID.
- virtual void sndcpInitialize(uint32_t srcId);
+ void sndcpInitialize(uint32_t llId);
/// Helper to determine if the logical link ID has been SNDCP initialized.
- virtual bool isSNDCPInitialized(uint32_t srcId) const;
+ bool isSNDCPInitialized(uint32_t llId) const;
+ /// Helper to reset the SNDCP state for a logical link ID.
+ void sndcpReset(uint32_t llId, bool callTerm = false);
private:
friend class p25::Control;
@@ -104,7 +106,7 @@ namespace p25
std::unordered_map m_sndcpStateTable;
std::unordered_map m_sndcpReadyTimers;
- std::unordered_map m_sndcpStandyTimers;
+ std::unordered_map m_sndcpStandbyTimers;
bool m_dumpPDUData;
bool m_repeatPDU;
@@ -118,7 +120,7 @@ namespace p25
~Data();
/// Helper used to process SNDCP control data from PDU data.
- bool processSNDCP();
+ bool processSNDCPControl();
/// Write data processed from RF to the network.
void writeNetwork(const uint8_t currentBlock, const uint8_t* data, uint32_t len, bool lastBlock);
diff --git a/src/host/p25/packet/Voice.cpp b/src/host/p25/packet/Voice.cpp
index 2dbdee10..6b8fe4ed 100644
--- a/src/host/p25/packet/Voice.cpp
+++ b/src/host/p25/packet/Voice.cpp
@@ -26,10 +26,10 @@
#include "p25/packet/Voice.h"
#include "ActivityLog.h"
-using namespace p25::packet;
-using namespace p25::dfsi::defines;
-using namespace p25::defines;
using namespace p25;
+using namespace p25::defines;
+using namespace p25::dfsi::defines;
+using namespace p25::packet;
#include
#include