diff --git a/src/common/network/RPC.cpp b/src/common/network/RPC.cpp index cb60fff7..d40f15c7 100644 --- a/src/common/network/RPC.cpp +++ b/src/common/network/RPC.cpp @@ -13,6 +13,7 @@ #include "common/network/RPCHeader.h" #include "common/network/json/json.h" #include "common/Log.h" +#include "common/Thread.h" #include "common/Utils.h" #include "network/RPC.h" @@ -27,6 +28,12 @@ using namespace network::frame; // Public Class Members // --------------------------------------------------------------------------- +#define REPLY_WAIT 200 // 200ms + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + /* Initializes a new instance of the RPC class. */ RPC::RPC(const std::string& address, uint16_t port, uint16_t localPort, const std::string& password, bool debug) : @@ -36,7 +43,8 @@ RPC::RPC(const std::string& address, uint16_t port, uint16_t localPort, const st m_socket(nullptr), m_frameQueue(nullptr), m_password(password), - m_handlers() + m_handlers(), + m_handlerReplied() { assert(!address.empty()); assert(port > 0U); @@ -86,7 +94,8 @@ void RPC::clock(uint32_t ms) } if (m_debug) { - LogDebugEx(LOG_NET, "RPC::clock()", "RPC, func = $%04X, messageLength = %u", rpcHeader.getFunction(), rpcHeader.getMessageLength()); + LogDebugEx(LOG_NET, "RPC::clock()", "received RPC, %s:%u, func = $%04X, messageLength = %u", + udp::Socket::address(address).c_str(), udp::Socket::port(address), rpcHeader.getFunction(), rpcHeader.getMessageLength()); } // copy message @@ -125,10 +134,15 @@ void RPC::clock(uint32_t ms) // find RPC function callback if (m_handlers.find(rpcHeader.getFunction()) != m_handlers.end()) { + bool isReply = (rpcHeader.getFunction() & RPC_REPLY_FUNC) == RPC_REPLY_FUNC; + if (isReply) { + m_handlerReplied[rpcHeader.getFunction()] = true; + } + m_handlers[rpcHeader.getFunction()](request, response); // remove the reply handler (these should be temporary) - if ((rpcHeader.getFunction() & RPC_REPLY_FUNC) == RPC_REPLY_FUNC) { + if (isReply) { m_handlers.erase(rpcHeader.getFunction()); } else { reply(rpcHeader.getFunction(), response, address, addrLen); @@ -136,6 +150,8 @@ void RPC::clock(uint32_t ms) } else { bool isReply = (rpcHeader.getFunction() & RPC_REPLY_FUNC) == RPC_REPLY_FUNC; if (isReply) { + m_handlerReplied[rpcHeader.getFunction()] = true; + if (!request["status"].is()) { ::LogError(LOG_NET, "RPC %s:%u, invalid RPC response", udp::Socket::address(address).c_str(), udp::Socket::port(address)); return; @@ -157,12 +173,13 @@ void RPC::clock(uint32_t ms) /* Writes an RPC request to the network. */ -bool RPC::req(uint16_t func, const json::object& request, RPCType reply, std::string address, uint16_t port) +bool RPC::req(uint16_t func, const json::object& request, RPCType reply, std::string address, uint16_t port, + bool blocking) { sockaddr_storage addr; uint32_t addrLen = 0U; if (udp::Socket::lookup(address, port, addr, addrLen) == 0) { - return req(func, request, reply, addr, addrLen); + return req(func, request, reply, addr, addrLen, blocking); } return false; @@ -170,11 +187,23 @@ bool RPC::req(uint16_t func, const json::object& request, RPCType reply, std::st /* Writes an RPC request to the network. */ -bool RPC::req(uint16_t func, const json::object& request, RPCType reply, sockaddr_storage& address, uint32_t addrLen) +bool RPC::req(uint16_t func, const json::object& request, RPCType reply, sockaddr_storage& address, uint32_t addrLen, + bool blocking) { json::value v = json::value(request); std::string json = v.serialize(); + if (m_debug) { + LogDebugEx(LOG_NET, "RPC::req()", "sending RPC, %s:%u, func = $%04X, messageLength = %u", + udp::Socket::address(address).c_str(), udp::Socket::port(address), func, json.length() + 1U); + } + + // make sure we're not trying to send an RPC request to ourselves + if (m_address == udp::Socket::address(address) && m_port == udp::Socket::port(address)) { + LogError(LOG_NET, "RPC, cowardly refusing to send RPC to ourselves"); + return false; + } + // generate RPC header RPCHeader header = RPCHeader(); header.setFunction(func & 0x3FFFU); @@ -201,10 +230,46 @@ bool RPC::req(uint16_t func, const json::object& request, RPCType reply, sockadd ::memcpy(buffer + 8U, message, json.length() + 1U); // install reply handler - if (reply != nullptr) + if (reply != nullptr) { m_handlers[func | RPC_REPLY_FUNC] = reply; + m_handlerReplied[func | RPC_REPLY_FUNC] = false; + } - return m_frameQueue->write(buffer, json.length() + 9U, address, addrLen); + bool ret = m_frameQueue->write(buffer, json.length() + 9U, address, addrLen); + if (!ret) + return false; + else { + // are we blocking return until a reply is received? + if (blocking) { + // we only block for up to 200ms -- after we we treat the call as failed and return + int timeout = REPLY_WAIT; + while (timeout > 0) { + if (m_handlerReplied.find(func | RPC_REPLY_FUNC) != m_handlerReplied.end()) { + if (m_handlerReplied[func | RPC_REPLY_FUNC]) { + m_handlerReplied[func | RPC_REPLY_FUNC] = false; + break; + } + } + + if (m_debug) + LogDebugEx(LOG_HOST, "RPC::req()", "blocking = %u, to = %d", blocking, timeout); + + timeout--; + Thread::sleep(1); + } + + if (timeout == 0) { + return false; + } + + return true; + } + else { + return true; + } + } + + return false; } /* Helper to generate a default response error payload. */ diff --git a/src/common/network/RPC.h b/src/common/network/RPC.h index 31530d49..b492d1eb 100644 --- a/src/common/network/RPC.h +++ b/src/common/network/RPC.h @@ -80,22 +80,26 @@ namespace network /** * @brief Writes an RPC request to the network. + * @note When using blocking, execution will only be blocked up to a timeout period maximum of 200ms. * @param request JSON content body for request. * @param reply Reply handler. * @param address IP address to write data to. * @param port Port number to write data to. + * @param blocking Flag indicating this RPC call should block while waiting for a reply. * @returns bool True, if message was written, otherwise false. */ - bool req(uint16_t func, const json::object& request, RPCType reply, std::string address, uint16_t port); + bool req(uint16_t func, const json::object& request, RPCType reply, std::string address, uint16_t port, bool blocking = false); /** * @brief Writes an RPC request to the network. + * @note When using blocking, execution will only be blocked up to a timeout period maximum of 200ms. * @param request JSON content body for request. * @param reply Reply handler. * @param address IP address to write data to. * @param addrLen + * @param blocking Flag indicating this RPC call should block while waiting for a reply. * @returns bool True, if message was written, otherwise false. */ - bool req(uint16_t func, const json::object& request, RPCType reply, sockaddr_storage& address, uint32_t addrLen); + bool req(uint16_t func, const json::object& request, RPCType reply, sockaddr_storage& address, uint32_t addrLen, bool blocking = false); /** * @brief Helper to generate a default response error payload. @@ -140,6 +144,7 @@ namespace network std::string m_password; std::map m_handlers; + std::map m_handlerReplied; /** * @brief Writes an RPC reply to the network. diff --git a/src/host/dmr/packet/ControlSignaling.cpp b/src/host/dmr/packet/ControlSignaling.cpp index 7fc0805e..10df31c4 100644 --- a/src/host/dmr/packet/ControlSignaling.cpp +++ b/src/host/dmr/packet/ControlSignaling.cpp @@ -959,31 +959,36 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_ req["dstId"].set(dstId); req["slot"].set(slot); - bool requestFailed = false; - g_RPC->req(RPC_PERMIT_DMR_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { + // send blocking RPC request + bool requestFailed = !g_RPC->req(RPC_PERMIT_DMR_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { if (!req["status"].is()) { return; } int status = req["status"].get(); if (status != network::RPC::OK) { - ::LogError((net) ? LOG_NET : LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to permit TG for use, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); if (req["message"].is()) { std::string retMsg = req["message"].get(); ::LogError((net) ? LOG_NET : LOG_RF, "DMR Slot %u, RPC failed, %s", tscc->m_slotNo, retMsg.c_str()); } - - tscc->m_affiliations->releaseGrant(dstId, false); - if (!net) { - writeRF_CSBK_ACK_RSP(srcId, ReasonCode::TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U); - m_slot->m_rfState = RS_RF_REJECTED; - } requestFailed = true; + } else { + requestFailed = false; + } + }, voiceChData.address(), voiceChData.port(), true); + + // if the request failed block grant + if (requestFailed) { + ::LogError((net) ? LOG_NET : LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to permit TG for use, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); + + tscc->m_affiliations->releaseGrant(dstId, false); + if (!net) { + writeRF_CSBK_ACK_RSP(srcId, ReasonCode::TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U); + m_slot->m_rfState = RS_RF_REJECTED; } - }, voiceChData.address(), voiceChData.port()); - if (requestFailed) return false; + } } else { ::LogError(LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to permit TG for use, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); @@ -1023,7 +1028,7 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_ bool voice = true; req["voice"].set(voice); - g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port()); + g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port(), true); } else { ::LogError(LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to activate payload channel, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); @@ -1047,31 +1052,36 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_ req["dstId"].set(dstId); req["slot"].set(slot); - bool requestFailed = false; - g_RPC->req(RPC_PERMIT_DMR_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { + // send blocking RPC request + bool requestFailed = !g_RPC->req(RPC_PERMIT_DMR_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { if (!req["status"].is()) { return; } int status = req["status"].get(); if (status != network::RPC::OK) { - ::LogError((net) ? LOG_NET : LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to permit TG for use, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); if (req["message"].is()) { std::string retMsg = req["message"].get(); ::LogError((net) ? LOG_NET : LOG_RF, "DMR Slot %u, RPC failed, %s", tscc->m_slotNo, retMsg.c_str()); } - - tscc->m_affiliations->releaseGrant(dstId, false); - if (!net) { - writeRF_CSBK_ACK_RSP(srcId, ReasonCode::TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U); - m_slot->m_rfState = RS_RF_REJECTED; - } requestFailed = true; + } else { + requestFailed = false; + } + }, voiceChData.address(), voiceChData.port(), true); + + // if the request failed block grant + if (requestFailed) { + ::LogError((net) ? LOG_NET : LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to permit TG for use, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); + + tscc->m_affiliations->releaseGrant(dstId, false); + if (!net) { + writeRF_CSBK_ACK_RSP(srcId, ReasonCode::TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U); + m_slot->m_rfState = RS_RF_REJECTED; } - }, voiceChData.address(), voiceChData.port()); - if (requestFailed) return false; + } } else { ::LogError(LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to permit TG for use, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); @@ -1109,7 +1119,7 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_ bool voice = true; req["voice"].set(voice); - g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port()); + g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port(), true); } else { ::LogError(LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to activate payload channel, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); @@ -1261,7 +1271,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u bool voice = false; req["voice"].set(voice); - g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port()); + g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port(), true); } else { ::LogError(LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to activate payload channel, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); @@ -1307,7 +1317,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u bool voice = false; req["voice"].set(voice); - g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port()); + g_RPC->req(RPC_DMR_TSCC_PAYLOAD_ACT, req, nullptr, voiceChData.address(), voiceChData.port(), true); } else { ::LogError(LOG_RF, "DMR Slot %u, CSBK, RAND (Random Access), failed to activate payload channel, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot); diff --git a/src/host/nxdn/packet/ControlSignaling.cpp b/src/host/nxdn/packet/ControlSignaling.cpp index ca66ac1e..8b676ecf 100644 --- a/src/host/nxdn/packet/ControlSignaling.cpp +++ b/src/host/nxdn/packet/ControlSignaling.cpp @@ -568,32 +568,36 @@ bool ControlSignaling::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uin json::object req = json::object(); req["dstId"].set(dstId); - bool requestFailed = false; - std::string rcchStr = rcch->toString().c_str(); - g_RPC->req(RPC_PERMIT_NXDN_TG, req, [=, &requestFailed, &rcchStr](json::object& req, json::object& reply) { + // send blocking RPC request + bool requestFailed = !g_RPC->req(RPC_PERMIT_NXDN_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { if (!req["status"].is()) { return; } int status = req["status"].get(); if (status != network::RPC::OK) { - ::LogError((net) ? LOG_NET : LOG_RF, "NXDN, %s, failed to permit TG for use, chNo = %u", rcchStr.c_str(), chNo); if (req["message"].is()) { std::string retMsg = req["message"].get(); ::LogError((net) ? LOG_NET : LOG_RF, "NXDN, RPC failed, %s", retMsg.c_str()); } - - m_nxdn->m_affiliations.releaseGrant(dstId, false); - if (!net) { - writeRF_Message_Deny(0U, srcId, CauseResponse::VD_QUE_GRP_BUSY, MessageType::RTCH_VCALL); - m_nxdn->m_rfState = RS_RF_REJECTED; - } requestFailed = true; + } else { + requestFailed = false; + } + }, voiceChData.address(), voiceChData.port(), true); + + // if the request failed block grant + if (requestFailed) { + ::LogError((net) ? LOG_NET : LOG_RF, "NXDN, %s, failed to permit TG for use, chNo = %u", rcch->toString().c_str(), chNo); + + m_nxdn->m_affiliations.releaseGrant(dstId, false); + if (!net) { + writeRF_Message_Deny(0U, srcId, CauseResponse::VD_QUE_GRP_BUSY, MessageType::RTCH_VCALL); + m_nxdn->m_rfState = RS_RF_REJECTED; } - }, voiceChData.address(), voiceChData.port()); - if (requestFailed) return false; + } } else { ::LogError((net) ? LOG_NET : LOG_RF, "NXDN, %s, failed to permit TG for use, chNo = %u", rcch->toString().c_str(), chNo); diff --git a/src/host/p25/packet/ControlSignaling.cpp b/src/host/p25/packet/ControlSignaling.cpp index 4269968b..61ecb18c 100644 --- a/src/host/p25/packet/ControlSignaling.cpp +++ b/src/host/p25/packet/ControlSignaling.cpp @@ -2295,31 +2295,36 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_ json::object req = json::object(); req["dstId"].set(dstId); - bool requestFailed = false; - g_RPC->req(RPC_PERMIT_P25_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { + // send blocking RPC request + bool requestFailed = !g_RPC->req(RPC_PERMIT_P25_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { if (!req["status"].is()) { return; } int status = req["status"].get(); if (status != network::RPC::OK) { - ::LogError((net) ? LOG_NET : LOG_RF, P25_TSDU_STR ", TSBKO, IOSP_GRP_VCH (Group Voice Channel Request), failed to permit TG for use, chNo = %u", chNo); if (req["message"].is()) { std::string retMsg = req["message"].get(); ::LogError((net) ? LOG_NET : LOG_RF, "P25, RPC failed, %s", retMsg.c_str()); } - - m_p25->m_affiliations.releaseGrant(dstId, false); - if (!net) { - writeRF_TSDU_Deny(srcId, dstId, ReasonCode::DENY_PTT_BONK, (grp) ? TSBKO::IOSP_GRP_VCH : TSBKO::IOSP_UU_VCH, grp, true); - m_p25->m_rfState = RS_RF_REJECTED; - } requestFailed = true; + } else { + requestFailed = false; + } + }, voiceChData.address(), voiceChData.port(), true); + + // if the request failed block grant + if (requestFailed) { + ::LogError((net) ? LOG_NET : LOG_RF, P25_TSDU_STR ", TSBKO, IOSP_GRP_VCH (Group Voice Channel Request), failed to permit TG for use, chNo = %u", chNo); + + m_p25->m_affiliations.releaseGrant(dstId, false); + if (!net) { + writeRF_TSDU_Deny(srcId, dstId, ReasonCode::DENY_PTT_BONK, (grp) ? TSBKO::IOSP_GRP_VCH : TSBKO::IOSP_UU_VCH, grp, true); + m_p25->m_rfState = RS_RF_REJECTED; } - }, voiceChData.address(), voiceChData.port()); - if (requestFailed) return false; + } } else { ::LogError((net) ? LOG_NET : LOG_RF, P25_TSDU_STR ", TSBKO, IOSP_GRP_VCH (Group Voice Channel Request), failed to permit TG for use, chNo = %u", chNo); @@ -2360,31 +2365,36 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_ json::object req = json::object(); req["dstId"].set(dstId); - bool requestFailed = false; - g_RPC->req(RPC_PERMIT_P25_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { + // send blocking RPC request + bool requestFailed = !g_RPC->req(RPC_PERMIT_P25_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { if (!req["status"].is()) { return; } int status = req["status"].get(); if (status != network::RPC::OK) { - ::LogError((net) ? LOG_NET : LOG_RF, P25_TSDU_STR ", TSBKO, IOSP_UU_VCH (Unit-to-Unit Voice Channel Request), failed to permit TG for use, chNo = %u", chNo); if (req["message"].is()) { std::string retMsg = req["message"].get(); ::LogError((net) ? LOG_NET : LOG_RF, "P25, RPC failed, %s", retMsg.c_str()); } - - m_p25->m_affiliations.releaseGrant(dstId, false); - if (!net) { - writeRF_TSDU_Deny(srcId, dstId, ReasonCode::DENY_PTT_BONK, (grp) ? TSBKO::IOSP_GRP_VCH : TSBKO::IOSP_UU_VCH, grp, true); - m_p25->m_rfState = RS_RF_REJECTED; - } requestFailed = true; + } else { + requestFailed = false; + } + }, voiceChData.address(), voiceChData.port(), true); + + // if the request failed block grant + if (requestFailed) { + ::LogError((net) ? LOG_NET : LOG_RF, P25_TSDU_STR ", TSBKO, IOSP_UU_VCH (Unit-to-Unit Voice Channel Request), failed to permit TG for use, chNo = %u", chNo); + + m_p25->m_affiliations.releaseGrant(dstId, false); + if (!net) { + writeRF_TSDU_Deny(srcId, dstId, ReasonCode::DENY_PTT_BONK, (grp) ? TSBKO::IOSP_GRP_VCH : TSBKO::IOSP_UU_VCH, grp, true); + m_p25->m_rfState = RS_RF_REJECTED; } - }, voiceChData.address(), voiceChData.port()); - if (requestFailed) return false; + } } else { ::LogError((net) ? LOG_NET : LOG_RF, P25_TSDU_STR ", TSBKO, IOSP_UU_VCH (Unit-to-Unit Voice Channel Request), failed to permit TG for use, chNo = %u", chNo); @@ -2573,29 +2583,34 @@ bool ControlSignaling::writeRF_TSDU_SNDCP_Grant(uint32_t srcId, bool skip, uint3 bool dataCh = true; req["dataPermit"].set(dataCh); - bool requestFailed = false; - g_RPC->req(RPC_PERMIT_P25_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { + // send blocking RPC request + bool requestFailed = !g_RPC->req(RPC_PERMIT_P25_TG, req, [=, &requestFailed](json::object& req, json::object& reply) { if (!req["status"].is()) { return; } int status = req["status"].get(); if (status != network::RPC::OK) { - ::LogError(LOG_RF, P25_TSDU_STR ", TSBKO, ISP_SNDCP_CH_REQ (SNDCP Data Channel Request), failed to permit for use, chNo = %u", chNo); if (req["message"].is()) { std::string retMsg = req["message"].get(); ::LogError(LOG_RF, "P25, RPC failed, %s", retMsg.c_str()); } - - m_p25->m_affiliations.releaseGrant(srcId, false); - writeRF_TSDU_Deny(srcId, srcId, ReasonCode::DENY_PTT_BONK, TSBKO::ISP_SNDCP_CH_REQ, false, true); - m_p25->m_rfState = RS_RF_REJECTED; requestFailed = true; + } else { + requestFailed = false; } - }, voiceChData.address(), voiceChData.port()); + }, voiceChData.address(), voiceChData.port(), true); + + // if the request failed block grant + if (requestFailed) { + ::LogError(LOG_RF, P25_TSDU_STR ", TSBKO, ISP_SNDCP_CH_REQ (SNDCP Data Channel Request), failed to permit for use, chNo = %u", chNo); + + m_p25->m_affiliations.releaseGrant(srcId, false); + writeRF_TSDU_Deny(srcId, srcId, ReasonCode::DENY_PTT_BONK, TSBKO::ISP_SNDCP_CH_REQ, false, true); + m_p25->m_rfState = RS_RF_REJECTED; - if (requestFailed) return false; + } } else { ::LogError(LOG_RF, P25_TSDU_STR ", TSBKO, ISP_SNDCP_CH_REQ (SNDCP Data Channel Request), failed to permit for use, chNo = %u", chNo);