implement an internal DVM MFId so we can abuse TSDUs to transmit call termination across the network with ease; properly implement GRP_VCH_GRANT_UPD;

pull/12/head
Bryan Biedenkapp 4 years ago
parent 50cb75e4b3
commit d588982b72

@ -514,7 +514,7 @@ bool Control::writeControlRF()
return false; return false;
} }
const uint8_t maxSeq = 7U; const uint8_t maxSeq = 8U;
if (m_ccSeq == maxSeq) { if (m_ccSeq == maxSeq) {
m_ccSeq = 0U; m_ccSeq = 0U;
} }

@ -112,6 +112,7 @@ namespace p25
const uint8_t P25_MFG_STANDARD = 0x00U; const uint8_t P25_MFG_STANDARD = 0x00U;
const uint8_t P25_MFG_MOT = 0x90U; const uint8_t P25_MFG_MOT = 0x90U;
const uint8_t P25_MFG_DVM = 0xFEU; // internal P25 MFId used for internal signalling (shouldn't be air transmitted!)
const uint8_t P25_MOT_CALLSIGN_LENGTH_BYTES = 8U; const uint8_t P25_MOT_CALLSIGN_LENGTH_BYTES = 8U;

@ -562,19 +562,47 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
uint32_t srcId = m_netTSBK.getSrcId(); uint32_t srcId = m_netTSBK.getSrcId();
uint32_t dstId = m_netTSBK.getDstId(); uint32_t dstId = m_netTSBK.getDstId();
// handle internal DVM TSDUs
if (m_netTSBK.getMFId() == P25_MFG_DVM) {
switch (m_netTSBK.getLCO()) {
case LC_CALL_TERM:
if (m_p25->m_dedicatedControl) {
uint32_t chNo = m_netTSBK.getGrpVchNo();
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", LC_CALL_TERM (Call Termination), chNo = %u, srcId = %u, dstId = %u", chNo, srcId, dstId);
}
// is the specified channel granted?
if (isChBusy(chNo) && hasDstIdGranted(dstId)) {
releaseDstIdGrant(dstId, false);
}
}
break;
default:
LogError(LOG_NET, P25_TSDU_STR ", unhandled LCO, mfId = $%02X, lco = $%02X", m_netTSBK.getMFId(), m_netTSBK.getLCO());
return false;
}
writeNet_TSDU();
return true;
}
// handle standard P25 reference opcodes
switch (m_netTSBK.getLCO()) { switch (m_netTSBK.getLCO()) {
case TSBK_IOSP_GRP_VCH: case TSBK_IOSP_GRP_VCH:
if (m_verbose) { if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_GRP_VCH (Group Voice Channel Grant), emerg = %u, encrypt = %u, prio = %u, chNo = %u, srcId = %u, dstId = %u", LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_GRP_VCH (Group Voice Channel Grant), emerg = %u, encrypt = %u, prio = %u, chNo = %u, srcId = %u, dstId = %u",
m_netTSBK.getEmergency(), m_netTSBK.getEncrypted(), m_netTSBK.getPriority(), m_netTSBK.getGrpVchNo(), srcId, dstId); m_netTSBK.getEmergency(), m_netTSBK.getEncrypted(), m_netTSBK.getPriority(), m_netTSBK.getGrpVchNo(), srcId, dstId);
} }
break; return true; // don't allow this to write to the air
case TSBK_IOSP_UU_VCH: case TSBK_IOSP_UU_VCH:
if (m_verbose) { if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_UU_VCH (Unit-to-Unit Voice Channel Grant), emerg = %u, encrypt = %u, prio = %u, chNo = %u, srcId = %u, dstId = %u", LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_UU_VCH (Unit-to-Unit Voice Channel Grant), emerg = %u, encrypt = %u, prio = %u, chNo = %u, srcId = %u, dstId = %u",
m_netTSBK.getEmergency(), m_netTSBK.getEncrypted(), m_netTSBK.getPriority(), m_netTSBK.getGrpVchNo(), srcId, dstId); m_netTSBK.getEmergency(), m_netTSBK.getEncrypted(), m_netTSBK.getPriority(), m_netTSBK.getGrpVchNo(), srcId, dstId);
} }
break; return true; // don't allow this to write to the air
case TSBK_IOSP_UU_ANS: case TSBK_IOSP_UU_ANS:
if (m_netTSBK.getResponse() > 0U) { if (m_netTSBK.getResponse() > 0U) {
if (m_verbose) { if (m_verbose) {
@ -654,13 +682,13 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
break; break;
case TSBK_IOSP_GRP_AFF: case TSBK_IOSP_GRP_AFF:
// ignore a network group affiliation command // ignore a network group affiliation command
break; return true; // don't allow this to write to the air
case TSBK_OSP_U_DEREG_ACK: case TSBK_OSP_U_DEREG_ACK:
// ignore a network user deregistration command // ignore a network user deregistration command
break; return true; // don't allow this to write to the air
case TSBK_OSP_LOC_REG_RSP: case TSBK_OSP_LOC_REG_RSP:
// ignore a network location registration command // ignore a network location registration command
break; return true; // don't allow this to write to the air
case TSBK_OSP_DENY_RSP: case TSBK_OSP_DENY_RSP:
if (m_verbose) { if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_DENY_RSP (Deny Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u", LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_DENY_RSP (Deny Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u",
@ -1136,6 +1164,7 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpT
m_mbfIdenCnt(0U), m_mbfIdenCnt(0U),
m_mbfAdjSSCnt(0U), m_mbfAdjSSCnt(0U),
m_mbfSCCBCnt(0U), m_mbfSCCBCnt(0U),
m_mbfGrpGrntCnt(0U),
m_voiceChTable(), m_voiceChTable(),
m_adjSiteTable(), m_adjSiteTable(),
m_adjSiteUpdateCnt(), m_adjSiteUpdateCnt(),
@ -1250,11 +1279,17 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
else else
queueRF_TSBK_Ctrl(TSBK_OSP_NET_STS_BCAST); queueRF_TSBK_Ctrl(TSBK_OSP_NET_STS_BCAST);
break; break;
/** extra data */ /** update data */
case 4: case 4:
queueRF_TSBK_Ctrl(TSBK_OSP_SNDCP_CH_ANN); if (m_grantChTable.size() > 0) {
queueRF_TSBK_Ctrl(TSBK_OSP_GRP_VCH_GRANT_UPD);
}
break; break;
/** extra data */
case 5: case 5:
queueRF_TSBK_Ctrl(TSBK_OSP_SNDCP_CH_ANN);
break;
case 6:
// write ADJSS // write ADJSS
if (adjSS && m_adjSiteTable.size() > 0) { if (adjSS && m_adjSiteTable.size() > 0) {
queueRF_TSBK_Ctrl(TSBK_OSP_ADJ_STS_BCAST); queueRF_TSBK_Ctrl(TSBK_OSP_ADJ_STS_BCAST);
@ -1262,12 +1297,14 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
} else { } else {
forcePad = true; forcePad = true;
} }
case 6: break;
case 7:
// write SCCB // write SCCB
if (adjSS && m_sccbTable.size() > 0) { if (adjSS && m_sccbTable.size() > 0) {
queueRF_TSBK_Ctrl(TSBK_OSP_SCCB_EXP); queueRF_TSBK_Ctrl(TSBK_OSP_SCCB_EXP);
break; break;
} }
break;
} }
// should we insert the BSI bursts? // should we insert the BSI bursts?
@ -1278,7 +1315,7 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
// add padding after the last sequence or if forced; and only // add padding after the last sequence or if forced; and only
// if we're doing multiblock frames (MBF) // if we're doing multiblock frames (MBF)
if ((n == 6U || forcePad) && m_ctrlTSDUMBF) if ((n >= 4U || forcePad) && m_ctrlTSDUMBF)
{ {
// pad MBF if we have 1 queued TSDUs // pad MBF if we have 1 queued TSDUs
if (m_mbfCnt == 1U) { if (m_mbfCnt == 1U) {
@ -1389,6 +1426,10 @@ void TrunkPacket::writeRF_TDULC_ChanRelease(bool grp, uint32_t srcId, uint32_t d
lc.setLCO(LC_CALL_TERM); lc.setLCO(LC_CALL_TERM);
writeRF_TDULC(lc, true); writeRF_TDULC(lc, true);
if (m_p25->m_control) {
writeNet_TSDU_Call_Term(srcId, dstId);
}
} }
/// <summary> /// <summary>
@ -1568,6 +1609,53 @@ void TrunkPacket::queueRF_TSBK_Ctrl(uint8_t lco)
resetRF(); resetRF();
switch (lco) { switch (lco) {
case TSBK_OSP_GRP_VCH_GRANT_UPD:
// write group voice grant update
if (m_grantChTable.size() > 0) {
if (m_mbfGrpGrntCnt >= m_grantChTable.size())
m_mbfGrpGrntCnt = 0U;
if (m_debug) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_GRP_VCH_GRANT_UPD (Group Voice Channel Grant Update)");
}
bool noData = false;
uint8_t i = 0U;
for (auto it = m_grantChTable.begin(); it != m_grantChTable.end(); ++it) {
// no good very bad way of skipping entries...
if (i != m_mbfGrpGrntCnt) {
i++;
continue;
}
else {
uint32_t dstId = it->first;
uint32_t chNo = it->second;
if (chNo == 0U) {
noData = true;
m_mbfGrpGrntCnt++;
break;
}
else {
// transmit group voice grant update
m_rfTSBK.setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD);
m_rfTSBK.setDstId(dstId);
m_rfTSBK.setGrpVchNo(chNo);
m_mbfGrpGrntCnt++;
break;
}
}
}
if (noData) {
return; // don't create anything
}
}
else {
return; // don't create anything
}
break;
case TSBK_OSP_IDEN_UP: case TSBK_OSP_IDEN_UP:
{ {
if (m_debug) { if (m_debug) {
@ -2186,6 +2274,26 @@ bool TrunkPacket::writeRF_TSDU_Loc_Reg_Rsp(uint32_t srcId, uint32_t dstId)
return ret; return ret;
} }
/// <summary>
/// Helper to write a call termination packet.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
bool TrunkPacket::writeNet_TSDU_Call_Term(uint32_t srcId, uint32_t dstId)
{
bool ret = false;
m_rfTSBK.setLCO(LC_CALL_TERM);
m_rfTSBK.setMFId(P25_MFG_DVM);
m_rfTSBK.setGrpVchId(m_p25->m_siteData.channelId());
m_rfTSBK.setGrpVchNo(m_p25->m_siteData.channelNo());
m_rfTSBK.setDstId(dstId);
m_rfTSBK.setSrcId(srcId);
writeRF_TSDU_SBF(false); // the problem with this is the vendor code going over the air!
return ret;
}
/// <summary> /// <summary>
/// Helper to write a network TSDU from the RF data queue. /// Helper to write a network TSDU from the RF data queue.
/// </summary> /// </summary>

@ -129,6 +129,7 @@ namespace p25
uint8_t m_mbfIdenCnt; uint8_t m_mbfIdenCnt;
uint8_t m_mbfAdjSSCnt; uint8_t m_mbfAdjSSCnt;
uint8_t m_mbfSCCBCnt; uint8_t m_mbfSCCBCnt;
uint8_t m_mbfGrpGrntCnt;
std::vector<uint32_t> m_voiceChTable; std::vector<uint32_t> m_voiceChTable;
@ -203,6 +204,9 @@ namespace p25
/// <summary>Helper to write a location registration response packet.</summary> /// <summary>Helper to write a location registration response packet.</summary>
bool writeRF_TSDU_Loc_Reg_Rsp(uint32_t srcId, uint32_t dstId); bool writeRF_TSDU_Loc_Reg_Rsp(uint32_t srcId, uint32_t dstId);
/// <summary>Helper to write a call termination packet.</summary>
bool writeNet_TSDU_Call_Term(uint32_t srcId, uint32_t dstId);
/// <summary>Helper to write a network TSDU from the RF data queue.</summary> /// <summary>Helper to write a network TSDU from the RF data queue.</summary>
void writeNet_TSDU_From_RF(uint8_t* data); void writeNet_TSDU_From_RF(uint8_t* data);

@ -259,12 +259,36 @@ bool TSBK::decode(const uint8_t* data)
} }
} }
// internal P25 vendor opcodes
if (m_mfId == P25_MFG_DVM) {
switch (m_lco) {
case LC_CALL_TERM:
m_grpVchId = ((tsbkValue >> 52) & 0x0FU); // Channel ID
m_grpVchNo = ((tsbkValue >> 40) & 0xFFFU); // Channel Number
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFU); // Target Radio Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break;
default:
m_mfId = P25_MFG_STANDARD;
break;
}
if (m_mfId == P25_MFG_DVM) {
return true;
}
else {
m_mfId = tsbk[1U];
}
}
// standard P25 reference opcodes // standard P25 reference opcodes
switch (m_lco) { switch (m_lco) {
case TSBK_IOSP_GRP_VCH: case TSBK_IOSP_GRP_VCH:
m_emergency = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag m_emergency = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
m_encrypted = (((tsbkValue >> 56) & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag m_encrypted = (((tsbkValue >> 56) & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
m_priority = (((tsbkValue >> 56) & 0xFFU) & 0x07U); // Priority m_priority = (((tsbkValue >> 56) & 0xFFU) & 0x07U); // Priority
m_grpVchId = ((tsbkValue >> 52) & 0x0FU); // Channel ID
m_grpVchNo = ((tsbkValue >> 40) & 0xFFFU); // Channel Number
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFU); // Target Radio Address m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFU); // Target Radio Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break; break;
@ -272,6 +296,8 @@ bool TSBK::decode(const uint8_t* data)
m_emergency = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag m_emergency = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
m_encrypted = (((tsbkValue >> 56) & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag m_encrypted = (((tsbkValue >> 56) & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
m_priority = (((tsbkValue >> 56) & 0xFFU) & 0x07U); // Priority m_priority = (((tsbkValue >> 56) & 0xFFU) & 0x07U); // Priority
m_grpVchId = ((tsbkValue >> 52) & 0x0FU); // Channel ID
m_grpVchNo = ((tsbkValue >> 40) & 0xFFFU); // Channel Number
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFFFU); // Target Radio Address m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFFFU); // Target Radio Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break; break;
@ -484,6 +510,13 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
tsbkValue = (tsbkValue << 24) + m_dstId; // Source ID tsbkValue = (tsbkValue << 24) + m_dstId; // Source ID
tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address
break; break;
case TSBK_OSP_GRP_VCH_GRANT_UPD:
tsbkValue = 0U;
tsbkValue = m_siteData.channelId(); // Channel ID
tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number
tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address
tsbkValue = (tsbkValue << 32) + 0;
break;
case TSBK_OSP_DENY_RSP: case TSBK_OSP_DENY_RSP:
case TSBK_OSP_QUE_RSP: case TSBK_OSP_QUE_RSP:
{ {
@ -795,6 +828,21 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
break; break;
} }
} }
// internal P25 vendor opcodes
if (m_mfId == P25_MFG_DVM) {
switch (m_lco) {
case LC_CALL_TERM:
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID
tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number
tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address
tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address
break;
default:
LogError(LOG_P25, "unknown TSBK LCO value, mfId = $%02X, lco = $%02X", m_mfId, m_lco);
break;
}
}
} }
// split rs value into bytes // split rs value into bytes
@ -879,6 +927,7 @@ TSBK::TSBK(SiteData siteData) :
m_response(P25_RSP_ACCEPT), m_response(P25_RSP_ACCEPT),
m_netId(P25_WACN_STD_DEFAULT), m_netId(P25_WACN_STD_DEFAULT),
m_sysId(P25_SID_STD_DEFAULT), m_sysId(P25_SID_STD_DEFAULT),
m_grpVchId(0U),
m_grpVchNo(0U), m_grpVchNo(0U),
m_messageValue(0U), m_messageValue(0U),
m_statusValue(0U), m_statusValue(0U),

@ -115,6 +115,8 @@ namespace p25
/// <summary>Configured system ID.</summary> /// <summary>Configured system ID.</summary>
__READONLY_PROPERTY(uint32_t, sysId, SysId); __READONLY_PROPERTY(uint32_t, sysId, SysId);
/// <summary>Voice channel ID.</summary>
__PROPERTY(uint32_t, grpVchId, GrpVchId);
/// <summary>Voice channel number.</summary> /// <summary>Voice channel number.</summary>
__PROPERTY(uint32_t, grpVchNo, GrpVchNo); __PROPERTY(uint32_t, grpVchNo, GrpVchNo);

Loading…
Cancel
Save

Powered by TurnKey Linux.