Skip to content

Commit d7b887a

Browse files
committed
implement enhancement/alterations to allow back-to-back configuration of dvmhost in TIA-102 DFSI mode (with FSC enabled); correct minor nullref handling in FSCACK; add writeImmediate() to ModemV24 to support TIA-102's need to immediately ack a Start of Stream block;
1 parent c3b31d2 commit d7b887a

8 files changed

Lines changed: 130 additions & 34 deletions

File tree

src/common/p25/dfsi/frames/fsc/FSCACK.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ using namespace p25::dfsi::frames::fsc;
2626
/* Initializes a instance of the FSCACK class. */
2727

2828
FSCACK::FSCACK() : FSCMessage(),
29+
responseData(nullptr),
2930
m_ackMessageId(FSCMessageType::FSC_INVALID),
3031
m_ackVersion(1U),
3132
m_ackCorrelationTag(0U),

src/host/Host.Config.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,10 +602,10 @@ bool Host::createModem()
602602
yaml::Node networkConf = m_conf["network"];
603603
uint32_t id = networkConf["id"].as<uint32_t>(1000U);
604604
if (useFSCForUDP) {
605-
modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort + 1U, g_remotePort, true, fscInitiator, debug);
605+
modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort + 1U, g_remotePort, g_remoteLocalPort, true, fscInitiator, debug);
606606
((modem::port::specialized::V24UDPPort*)modemPort)->setHeartbeatInterval(fscHeartbeat);
607607
} else {
608-
modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort, 0U, false, false, debug);
608+
modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort, 0U, 0U, false, false, debug);
609609
}
610610
m_udpDFSIRemotePort = modemPort;
611611
} else {
@@ -617,6 +617,8 @@ bool Host::createModem()
617617
LogInfo(" UDP Mode: %s", m_modemRemote ? "master" : "peer");
618618
LogInfo(" UDP Address: %s", g_remoteAddress.c_str());
619619
LogInfo(" UDP Port: %u", g_remotePort);
620+
if (g_remoteLocalPort > 0U)
621+
LogInfo(" Local Listening UDP Port: %u", g_remoteLocalPort);
620622
}
621623

622624
if (!m_modemRemote) {

src/host/HostMain.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ bool g_killed = false;
5353
bool g_remoteModemMode = false;
5454
std::string g_remoteAddress = std::string("127.0.0.1");
5555
uint16_t g_remotePort = REMOTE_MODEM_PORT;
56+
uint16_t g_remoteLocalPort = 0U;
5657

5758
bool g_fireDMRBeacon = false;
5859
bool g_fireP25Control = false;
@@ -140,6 +141,7 @@ void usage(const char* message, const char* arg)
140141
" --remote remote modem mode\n"
141142
" -a remote modem command address\n"
142143
" -p remote modem command port\n"
144+
" -P remote modem command port (local listening port)\n"
143145
"\n"
144146
" -- stop handling options\n",
145147
g_progExe.c_str());
@@ -218,6 +220,16 @@ int checkArgs(int argc, char* argv[])
218220

219221
p += 2;
220222
}
223+
else if (IS("-P")) {
224+
if ((argc - 1) <= 0)
225+
usage("error: %s", "must specify the port to connect to");
226+
g_remoteLocalPort = (uint16_t)::atoi(argv[++i]);
227+
228+
if (g_remoteLocalPort == 0)
229+
usage("error: %s", "remote port number cannot be blank or 0!");
230+
231+
p += 2;
232+
}
221233
else if (IS("-v")) {
222234
::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
223235
::fprintf(stdout, "Copyright (c) 2017-2025 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\n");

src/host/HostMain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ extern bool g_remoteModemMode;
4949
extern std::string g_remoteAddress;
5050
/** @brief (Global) Remote Modem Port. */
5151
extern uint16_t g_remotePort;
52+
/** @brief (Global) Local Remote Modem Port (Listening Port). */
53+
extern uint16_t g_remoteLocalPort;
5254

5355
/** @brief (Global) Fire DMR beacon flag. */
5456
extern bool g_fireDMRBeacon;

src/host/modem/ModemV24.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,11 +1155,8 @@ void ModemV24::convertToAirTIA(const uint8_t *data, uint32_t length)
11551155

11561156
dataOffs += StartOfStream::LENGTH;
11571157

1158-
// only ack the first start of stream block
1159-
if (blockCnt == 1U) {
1160-
// ack start of stream
1161-
ackStartOfStreamTIA();
1162-
}
1158+
// ack start of stream
1159+
ackStartOfStreamTIA();
11631160
}
11641161
break;
11651162
case BlockType::END_OF_STREAM:
@@ -1945,7 +1942,7 @@ void ModemV24::ackStartOfStreamTIA()
19451942
if (m_trace)
19461943
Utils::dump(1U, "ModemV24::ackStartOfStreamTIA() Ack StartOfStream", buffer, length);
19471944

1948-
queueP25Frame(buffer, length, STT_NON_IMBE);
1945+
writeImmediate(buffer, length);
19491946
}
19501947

19511948
/* Internal helper to convert from TIA-102 air interface to V.24/DFSI. */
@@ -2573,3 +2570,27 @@ void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length)
25732570
}
25742571
}
25752572
}
2573+
2574+
/* Writes raw data to the air interface modem. */
2575+
2576+
int ModemV24::writeImmediate(const uint8_t* data, uint32_t length)
2577+
{
2578+
assert(data != nullptr);
2579+
2580+
// add the DVM start byte, length byte, CMD byte, and padding 0
2581+
uint8_t header[4U];
2582+
header[0U] = DVM_SHORT_FRAME_START;
2583+
header[1U] = length & 0xFFU;
2584+
header[2U] = CMD_P25_DATA;
2585+
header[3U] = 0x00U;
2586+
2587+
// get the actual data
2588+
UInt8Array __buffer = std::make_unique<uint8_t[]>(length + 4U);
2589+
uint8_t* buffer = __buffer.get();
2590+
2591+
::memset(buffer, 0x00U, length + 4U);
2592+
::memcpy(buffer, header, 4U);
2593+
::memcpy(buffer + 4U, data, length);
2594+
2595+
return m_port->write(data, length);
2596+
}

src/host/modem/ModemV24.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,14 @@ namespace modem
408408
* @param length Length of buffer.
409409
*/
410410
void convertFromAirTIA(uint8_t* data, uint32_t length);
411+
412+
/**
413+
* @brief Writes raw data to the air interface modem (with no jitter delay).
414+
* @param data Data to write to modem.
415+
* @param length Length of data to write.
416+
* @returns int Actual length of data written.
417+
*/
418+
int writeImmediate(const uint8_t* data, uint32_t length);
411419
};
412420
} // namespace modem
413421

src/host/modem/port/specialized/V24UDPPort.cpp

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ std::mutex V24UDPPort::m_bufferMutex;
5050

5151
/* Initializes a new instance of the V24UDPPort class. */
5252

53-
V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t modemPort, uint16_t controlPort, bool useFSC, bool fscInitiator, bool debug) :
53+
V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t modemPort, uint16_t controlPort,
54+
uint16_t controlLocalPort, bool useFSC, bool fscInitiator, bool debug) :
5455
m_socket(nullptr),
5556
m_localPort(modemPort),
5657
m_controlSocket(nullptr),
@@ -60,8 +61,11 @@ V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t mod
6061
m_controlAddr(),
6162
m_addrLen(0U),
6263
m_ctrlAddrLen(0U),
63-
m_remoteAddr(),
64-
m_remoteAddrLen(0U),
64+
m_ctrlLocalPort(controlLocalPort),
65+
m_remoteCtrlAddr(),
66+
m_remoteCtrlAddrLen(0U),
67+
m_remoteRTPAddr(),
68+
m_remoteRTPAddrLen(0U),
6569
m_buffer(2000U, "UDP Port Ring Buffer"),
6670
m_fscInitiator(fscInitiator),
6771
m_timeoutTimer(1000U, 45U),
@@ -83,15 +87,18 @@ V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t mod
8387
assert(modemPort > 0U);
8488

8589
if (controlPort > 0U && useFSC) {
86-
m_controlSocket = new Socket(controlPort);
90+
if (controlLocalPort == 0U)
91+
controlLocalPort = controlPort;
92+
93+
m_controlSocket = new Socket(controlLocalPort);
8794
m_ctrlFrameQueue = new RawFrameQueue(m_controlSocket, m_debug);
8895

8996
if (udp::Socket::lookup(address, controlPort, m_controlAddr, m_ctrlAddrLen) != 0)
9097
m_ctrlAddrLen = 0U;
9198

9299
if (m_ctrlAddrLen > 0U) {
93-
m_remoteAddr = m_controlAddr;
94-
m_remoteAddrLen = m_remoteAddrLen;
100+
m_remoteCtrlAddr = m_controlAddr;
101+
m_remoteCtrlAddrLen = m_remoteCtrlAddrLen;
95102

96103
std::string ctrlAddrStr = udp::Socket::address(m_controlAddr);
97104
LogWarning(LOG_HOST, "SECURITY: Remote modem expects V.24 control channel IP address; %s for remote modem control", ctrlAddrStr.c_str());
@@ -272,7 +279,7 @@ int V24UDPPort::write(const uint8_t* buffer, uint32_t length)
272279
if (m_debug)
273280
Utils::dump(1U, "!!! Tx Outgoing DFSI UDP", buffer + 4U, length - 4U);
274281

275-
bool written = m_socket->write(message, messageLen, m_addr, m_addrLen);
282+
bool written = m_socket->write(message, messageLen, m_remoteRTPAddr, m_remoteRTPAddrLen);
276283
if (written)
277284
return length;
278285
} else {
@@ -408,16 +415,24 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg)
408415
network->m_socket = nullptr;
409416
}
410417

411-
network->m_localPort = vcBasePort;
412-
network->createVCPort(vcBasePort);
418+
uint16_t remoteCtrlPort = Socket::port(req->address);
419+
network->m_remoteCtrlAddr = req->address;
420+
network->m_remoteCtrlAddrLen = req->addrLen;
421+
422+
// setup local RTP VC port (where we receive traffic)
423+
network->createVCPort(network->m_localPort);
413424
network->m_socket->open(network->m_addr);
414425

426+
// setup remote RTP VC port (where we send traffic to)
427+
std::string remoteAddress = Socket::address(req->address);
428+
network->createRemoteVCPort(remoteAddress, vcBasePort);
429+
415430
network->m_fscState = CS_CONNECTED;
416431
network->m_reqConnectionTimer.stop();
417432
network->m_heartbeatTimer.start();
418433
network->m_timeoutTimer.start();
419434

420-
LogMessage(LOG_MODEM, "V.24 UDP, Established DFSI FSC Connection, vcBasePort = %u", vcBasePort);
435+
LogMessage(LOG_MODEM, "V.24 UDP, Established DFSI FSC Connection, ctrlRemotePort = %u, vcLocalPort = %u, vcRemotePort = %u", remoteCtrlPort, network->m_localPort, vcBasePort);
421436
}
422437
break;
423438

@@ -449,6 +464,10 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg)
449464
LogError(LOG_MODEM, "V.24 UDP, unknown ACK opcode, ackMessageId = $%02X", ackMessage->getAckMessageId());
450465
break;
451466
}
467+
468+
if (ackMessage->getResponseLength() > 0U && ackMessage->responseData != nullptr) {
469+
delete[] ackMessage->responseData; // FSCACK doesn't clean itself up...
470+
}
452471
}
453472
break;
454473

@@ -478,30 +497,35 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg)
478497
network->m_socket = nullptr;
479498
}
480499

481-
uint16_t vcPort = connMessage->getVCBasePort();
500+
uint16_t vcBasePort = connMessage->getVCBasePort();
482501
network->m_heartbeatInterval = connMessage->getHostHeartbeatPeriod();
483502
if (network->m_heartbeatInterval > 30U)
484503
network->m_heartbeatInterval = 30U;
485-
network->m_localPort = vcPort;
486504

505+
uint16_t remoteCtrlPort = Socket::port(req->address);
506+
network->m_remoteCtrlAddr = req->address;
507+
network->m_remoteCtrlAddrLen = req->addrLen;
508+
509+
LogMessage(LOG_MODEM, "V.24 UDP, Incoming DFSI FSC Connection, ctrlRemotePort = %u, vcLocalPort = %u, vcRemotePort = %u, hostHBInterval = %u", remoteCtrlPort, network->m_localPort, vcBasePort, connMessage->getHostHeartbeatPeriod());
510+
511+
// setup local RTP VC port (where we receive traffic)
487512
network->createVCPort(network->m_localPort);
488513
network->m_socket->open(network->m_addr);
489514

515+
// setup remote RTP VC port (where we send traffic to)
516+
std::string remoteAddress = Socket::address(req->address);
517+
network->createRemoteVCPort(remoteAddress, vcBasePort);
518+
490519
network->m_fscState = CS_CONNECTED;
491520
network->m_reqConnectionTimer.stop();
492521

493-
network->m_remoteAddr = req->address;
494-
network->m_remoteAddrLen = req->addrLen;
495-
496522
if (connMessage->getHostHeartbeatPeriod() > 30U)
497523
LogWarning(LOG_MODEM, "V.24 UDP, DFSI FSC Connection, requested heartbeat of %u, reduce to 30 seconds or less", connMessage->getHostHeartbeatPeriod());
498524

499525
network->m_heartbeatTimer = Timer(1000U, network->m_heartbeatInterval);
500526
network->m_heartbeatTimer.start();
501527
network->m_timeoutTimer.start();
502528

503-
LogMessage(LOG_MODEM, "V.24 UDP, Incoming DFSI FSC Connection, vcBasePort = %u, hostHBInterval = %u", network->m_localPort, connMessage->getHostHeartbeatPeriod());
504-
505529
// construct connect ACK response data
506530
uint8_t respData[3U];
507531
::memset(respData, 0x00U, 3U);
@@ -517,7 +541,8 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg)
517541
::memset(buffer, 0x00U, FSCACK::LENGTH + 3U);
518542
ackResp.encode(buffer);
519543

520-
network->m_ctrlFrameQueue->write(buffer, FSCACK::LENGTH + 3U, req->address, req->addrLen);
544+
if (network->m_ctrlFrameQueue->write(buffer, FSCACK::LENGTH + 3U, req->address, req->addrLen))
545+
LogMessage(LOG_MODEM, "V.24 UDP, Established DFSI FSC Connection, ctrlRemotePort = %u, vcLocalPort = %u, vcRemotePort = %u", remoteCtrlPort, network->m_localPort, vcBasePort);
521546
}
522547
break;
523548

@@ -676,7 +701,7 @@ void* V24UDPPort::threadedVCNetworkRx(void* arg)
676701
}
677702

678703
if (req->length > 0) {
679-
if (udp::Socket::match(req->address, network->m_addr)) {
704+
if (udp::Socket::match(req->address, network->m_remoteRTPAddr)) {
680705
UInt8Array __reply = std::make_unique<uint8_t[]>(req->length + 4U);
681706
uint8_t* reply = __reply.get();
682707

@@ -705,7 +730,7 @@ void* V24UDPPort::threadedVCNetworkRx(void* arg)
705730
return nullptr;
706731
}
707732

708-
/* Internal helper to setup the voice channel port. */
733+
/* Internal helper to setup the local voice channel port. */
709734

710735
void V24UDPPort::createVCPort(uint16_t port)
711736
{
@@ -716,7 +741,20 @@ void V24UDPPort::createVCPort(uint16_t port)
716741

717742
if (m_addrLen > 0U) {
718743
std::string addrStr = udp::Socket::address(m_addr);
719-
LogWarning(LOG_HOST, "SECURITY: Remote modem expects V.24 voice channel IP address; %s for remote modem control", addrStr.c_str());
744+
LogWarning(LOG_HOST, "SECURITY: Remote modem expects V.24 voice channel IP address; %s:%u for Rx traffic", addrStr.c_str(), port);
745+
}
746+
}
747+
748+
/* Internal helper to setup the remote voice channel port. */
749+
750+
void V24UDPPort::createRemoteVCPort(std::string address, uint16_t port)
751+
{
752+
if (udp::Socket::lookup(address, port, m_remoteRTPAddr, m_remoteRTPAddrLen) != 0)
753+
m_remoteRTPAddrLen = 0U;
754+
755+
if (m_remoteRTPAddrLen > 0U) {
756+
std::string addrStr = udp::Socket::address(m_remoteRTPAddr);
757+
LogWarning(LOG_HOST, "SECURITY: Remote modem expects V.24 voice channel IP address; %s:%u for Tx traffic", addrStr.c_str(), port);
720758
}
721759
}
722760

@@ -752,7 +790,7 @@ void V24UDPPort::writeHeartbeat()
752790
FSCHeartbeat hb = FSCHeartbeat();
753791
hb.encode(buffer);
754792

755-
m_ctrlFrameQueue->write(buffer, FSCHeartbeat::LENGTH, m_remoteAddr, m_remoteAddrLen);
793+
m_ctrlFrameQueue->write(buffer, FSCHeartbeat::LENGTH, m_remoteCtrlAddr, m_remoteCtrlAddrLen);
756794
}
757795

758796
/* Generate RTP message. */

src/host/modem/port/specialized/V24UDPPort.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ namespace modem
7171
* @param address Hostname/IP address to connect to.
7272
* @param modemPort Port number.
7373
* @param controlPort Control Port number.
74+
* @param controlLocalPort Local listening control port number.
7475
* @param useFSC Flag indicating whether or not FSC handshakes are used to setup communications.
7576
* @param fscInitiator Flag indicating whether or not the FSC handshake should be initiated when the port is opened.
7677
* @param debug Flag indicating whether network debug is enabled.
7778
*/
78-
V24UDPPort(uint32_t peerId, const std::string& modemAddress, uint16_t modemPort, uint16_t controlPort = 0U, bool useFSC = false, bool fscInitiator = false, bool debug = false);
79+
V24UDPPort(uint32_t peerId, const std::string& modemAddress, uint16_t modemPort, uint16_t controlPort = 0U,
80+
uint16_t controlLocalPort = 0U, bool useFSC = false, bool fscInitiator = false, bool debug = false);
7981
/**
8082
* @brief Finalizes a instance of the V24UDPPort class.
8183
*/
@@ -145,8 +147,12 @@ namespace modem
145147
uint32_t m_addrLen;
146148
uint32_t m_ctrlAddrLen;
147149

148-
sockaddr_storage m_remoteAddr;
149-
uint32_t m_remoteAddrLen;
150+
uint16_t m_ctrlLocalPort;
151+
152+
sockaddr_storage m_remoteCtrlAddr;
153+
uint32_t m_remoteCtrlAddrLen;
154+
sockaddr_storage m_remoteRTPAddr;
155+
uint32_t m_remoteRTPAddrLen;
150156

151157
RingBuffer<uint8_t> m_buffer;
152158

@@ -205,10 +211,16 @@ namespace modem
205211
static void* threadedVCNetworkRx(void* arg);
206212

207213
/**
208-
* @brief Internal helper to setup the voice channel port.
214+
* @brief Internal helper to setup the local voice channel port.
209215
* @param port Port number.
210216
*/
211217
void createVCPort(uint16_t port);
218+
/**
219+
* @brief Internal helper to setup the remote voice channel port.
220+
* @param address IP Address or Hostname.
221+
* @param port Port number.
222+
*/
223+
void createRemoteVCPort(std::string address, uint16_t port);
212224
/**
213225
* @brief Internal helper to write a FSC connect packet.
214226
*/

0 commit comments

Comments
 (0)