From cfc8604c8e1590fc3e1452fb87cdae3cbfa99d0c Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Fri, 9 Apr 2021 23:56:35 +0000 Subject: [PATCH] fix buffer overflow error in HostMain; implement some of the basis for DMR Tier III; --- DVMHost.vcxproj | 1 + DVMHost.vcxproj.filters | 3 + HostMain.cpp | 3 +- dmr/Control.cpp | 2 +- dmr/DMRDefines.h | 36 +++++- dmr/SiteData.h | 219 ++++++++++++++++++++++++++++++++++ dmr/Slot.cpp | 115 +++++++++++++++++- dmr/Slot.h | 9 +- dmr/lc/CSBK.cpp | 255 ++++++++++++++++++++++++++++++++-------- dmr/lc/CSBK.h | 47 +++++++- p25/lc/TSBK.cpp | 2 +- 11 files changed, 633 insertions(+), 59 deletions(-) create mode 100644 dmr/SiteData.h diff --git a/DVMHost.vcxproj b/DVMHost.vcxproj index aa6f0524..8fb674d4 100644 --- a/DVMHost.vcxproj +++ b/DVMHost.vcxproj @@ -162,6 +162,7 @@ + diff --git a/DVMHost.vcxproj.filters b/DVMHost.vcxproj.filters index c34140d2..1e1614a2 100644 --- a/DVMHost.vcxproj.filters +++ b/DVMHost.vcxproj.filters @@ -329,6 +329,9 @@ Header Files\p25\data + + Header Files\dmr + diff --git a/HostMain.cpp b/HostMain.cpp index 894e9e07..b015578a 100644 --- a/HostMain.cpp +++ b/HostMain.cpp @@ -87,11 +87,12 @@ static void sigHandler(int signum) void fatal(const char* msg, ...) { char buffer[400U]; + ::memset(buffer, 0x20U, 400U); va_list vl; va_start(vl, msg); - ::vsprintf(buffer + ::strlen(buffer), msg, vl); + ::vsprintf(buffer, msg, vl); va_end(vl); diff --git a/dmr/Control.cpp b/dmr/Control.cpp index cbf21c5c..7260117f 100644 --- a/dmr/Control.cpp +++ b/dmr/Control.cpp @@ -81,7 +81,7 @@ Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool assert(rssi != NULL); acl::AccessControl::init(m_ridLookup, m_tidLookup); - Slot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, duplex, m_ridLookup, m_tidLookup, rssi, jitter); + Slot::init(colorCode, SiteData(), embeddedLCOnly, dumpTAData, callHang, modem, network, duplex, m_ridLookup, m_tidLookup, rssi, jitter); m_slot1 = new Slot(1U, timeout, tgHang, queueSize, dumpDataPacket, repeatDataPacket, dumpCSBKData, debug, verbose); m_slot2 = new Slot(2U, timeout, tgHang, queueSize, dumpDataPacket, repeatDataPacket, dumpCSBKData, debug, verbose); diff --git a/dmr/DMRDefines.h b/dmr/DMRDefines.h index cf069c1a..a83787bc 100644 --- a/dmr/DMRDefines.h +++ b/dmr/DMRDefines.h @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX -* Copyright (C) 2019 by Bryan Biedenkapp N2PLL +* Copyright (C) 2019-2021 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,6 +130,8 @@ namespace dmr const uint32_t DMR_EXT_FNCT_UNINHIBIT_ACK = 0x00FEU; // Radio Uninhibit Ack const uint32_t DMR_EXT_FNCT_INHIBIT_ACK = 0x00FFU; // Radio Inhibit Ack + const uint8_t DMR_ALOHA_VER_151 = 0x00U; + // Data Type(s) const uint8_t DT_VOICE_PI_HEADER = 0x00U; const uint8_t DT_VOICE_LC_HEADER = 0x01U; @@ -145,6 +147,31 @@ namespace dmr const uint8_t DT_VOICE_SYNC = 0xF0U; const uint8_t DT_VOICE = 0xF1U; + // Site Models + const uint8_t SITE_MODEL_TINY = 0x00U; + const uint8_t SITE_MODEL_SMALL = 0x01U; + const uint8_t SITE_MODEL_LARGE = 0x02U; + const uint8_t SITE_MODEL_HUGE = 0x03U; + + // Target Address + const uint8_t TGT_ADRS_SYSCODE = 0x00U; + const uint8_t TGT_ADRS_TGID = 0x01U; + + // Short-Link Control Opcode(s) + const uint8_t SLCO_NULL = 0x00U; + const uint8_t SLCO_ACT = 0x01U; + const uint8_t SLCO_TSCC = 0x02U; + + // Broadcast Announcement Type(s) + const uint8_t BCAST_ANNC_ANN_WD_TSCC = 0x00U; // Announce/Withdraw TSCC + const uint8_t BCAST_ANNC_CALL_TIMER_PARMS = 0x01U; // Specify Call Timer Parameters + const uint8_t BCAST_ANNC_VOTE_NOW = 0x02U; // Vote Now Advice + const uint8_t BCAST_ANNC_LOCAL_TIME = 0x03U; // Broadcast Local Time + const uint8_t BCAST_ANNC_MASS_REG = 0x04U; // Mass Registration + const uint8_t BCAST_ANNC_CHAN_FREQ = 0x05U; // Announce a logical channel/frequency relationship + const uint8_t BCAST_ANNC_ADJ_SITE = 0x06U; // Adjacent Site information + const uint8_t BCAST_ANNC_SITE_PARMS = 0x07U; // General Site Parameters information + // Full-Link Control Opcode(s) const uint8_t FLCO_GROUP = 0x00U; // GRP VCH USER - Group Voice Channel User const uint8_t FLCO_PRIVATE = 0x03U; // UU VCH USER - Unit-to-Unit Voice Channel User @@ -159,12 +186,15 @@ namespace dmr const uint8_t CSBKO_UU_V_REQ = 0x04U; // UU VCH REQ - Unit-to-Unit Voice Channel Request const uint8_t CSBKO_UU_ANS_RSP = 0x05U; // UU ANS RSP - Unit to Unit Answer Response const uint8_t CSBKO_CTCSBK = 0x07U; // CT CSBK - Channel Timing CSBK - const uint8_t CSBKO_CALL_ALRT = 0x1FU; // CALL ALRT - Call Alert + const uint8_t CSBKO_ALOHA = 0x19U; // ALOHA - Aloha PDUs for the random access protocol + const uint8_t CSBKO_RAND = 0x1FU; // (ETSI) RAND - Random Access / (DMRA) CALL ALRT - Call Alert + const uint8_t CSBKO_CALL_ALRT = 0x1FU; // (ETSI) RAND - Random Access / (DMRA) CALL ALRT - Call Alert const uint8_t CSBKO_ACK_RSP = 0x20U; // ACK RSP - Acknowledge Response - const uint8_t CSBKO_EXT_FNCT = 0x24U; // EXT FNCT - Extended Function + const uint8_t CSBKO_EXT_FNCT = 0x24U; // (DMRA) EXT FNCT - Extended Function const uint8_t CSBKO_NACK_RSP = 0x26U; // NACK RSP - Negative Acknowledgement Response const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK + const uint8_t CSBKO_BROADCAST = 0x40U; // BCAST - Announcement PDUs const uint8_t TALKER_ID_NONE = 0x00U; const uint8_t TALKER_ID_HEADER = 0x01U; diff --git a/dmr/SiteData.h b/dmr/SiteData.h new file mode 100644 index 00000000..92499bee --- /dev/null +++ b/dmr/SiteData.h @@ -0,0 +1,219 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Server +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2021 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#if !defined(__DMR_SITE_DATA_H__) +#define __DMR_SITE_DATA_H__ + +#include "Defines.h" +#include "dmr/DMRDefines.h" + +namespace dmr +{ + // --------------------------------------------------------------------------- + // Class Declaration + // Represents site data for DMR. + // --------------------------------------------------------------------------- + + class HOST_SW_API SiteData { + public: + /// Initializes a new instance of the SiteData class. + SiteData() : + m_siteModel(SITE_MODEL_SMALL), + m_netId(1U), + m_siteId(1U), + m_parId(3U), + m_requireReg(false) + { + /* stub */ + } + /// Initializes a new instance of the SiteData class. + /// DMR site model. + /// DMR Network ID. + /// DMR Site ID. + /// DMR partition ID. + /// + SiteData(uint8_t siteModel, uint16_t netId, uint16_t siteId, uint8_t parId, bool requireReq) : + m_siteModel(siteModel), + m_netId(netId), + m_siteId(siteId), + m_parId(parId), + m_requireReg(requireReq) + { + // siteModel clamping + if (siteModel > SITE_MODEL_HUGE) + siteModel = SITE_MODEL_SMALL; + + // netId clamping + if (netId == 0U) // clamp to 1 + netId = 1U; + + switch (siteModel) { + case SITE_MODEL_TINY: + { + if (netId > 0x1FFU) // clamp to $1FF + netId = 0x1FFU; + } + break; + case SITE_MODEL_SMALL: + { + if (netId > 0x7FU) // clamp to $7F + netId = 0x7FU; + } + break; + case SITE_MODEL_LARGE: + { + if (netId > 0x1FU) // clamp to $1F + netId = 0x1FU; + } + break; + case SITE_MODEL_HUGE: + { + if (netId > 0x03U) // clamp to $3 + netId = 0x03U; + } + break; + } + + m_netId = netId; + + // siteId clamping + if (siteId == 0U) // clamp to 1 + siteId = 1U; + + switch (siteModel) + { + case SITE_MODEL_TINY: + { + if (siteId > 0x07U) // clamp to $7 + siteId = 0x07U; + } + break; + case SITE_MODEL_SMALL: + { + if (siteId > 0x1FU) // clamp to $1F + siteId = 0x1FU; + } + break; + case SITE_MODEL_LARGE: + { + if (siteId > 0xFFU) // clamp to $FF + siteId = 0xFFU; + } + break; + case SITE_MODEL_HUGE: + { + if (siteId > 0x7FFU) // clamp to $7FF + siteId = 0x7FFU; + } + break; + } + + m_siteId = siteId; + + // parId clamping + if (parId == 0U) + parId = 3U; + if (parId > 3U) + parId = 3U; + } + + /// Returns the DMR system identity value. + /// + /// + const uint32_t systemIdentity(bool msb = false) + { + uint32_t value = m_siteModel; + + switch (m_siteModel) + { + case SITE_MODEL_TINY: + { + value = (value << 9) + m_netId; + value = (value << 3) + m_siteId; + } + break; + case SITE_MODEL_SMALL: + { + value = (value << 7) + m_netId; + value = (value << 5) + m_siteId; + } + break; + case SITE_MODEL_LARGE: + { + value = (value << 5) + m_netId; + value = (value << 7) + m_siteId; + } + break; + case SITE_MODEL_HUGE: + { + value = (value << 2) + m_netId; + value = (value << 10) + m_siteId; + } + break; + } + + if (!msb) { + value = (value << 2) + m_parId; + } + + return value & 0xFFFFU; + } + + /// Equals operator. + /// + /// + SiteData & operator=(const SiteData & data) + { + if (this != &data) { + m_siteModel = data.m_siteModel; + + m_netId = data.m_netId; + m_siteId = data.m_siteId; + + m_requireReg = data.m_requireReg; + } + + return *this; + } + + public: + /// DMR site model type. + __READONLY_PROPERTY_PLAIN(uint8_t, siteModel, siteModel); + /// DMR site network ID. + __READONLY_PROPERTY_PLAIN(uint16_t, netId, netId); + /// DMR site ID. + __READONLY_PROPERTY_PLAIN(uint16_t, siteId, siteId); + /// DMR partition ID. + __READONLY_PROPERTY_PLAIN(uint8_t, parId, parId); + /// DMR require registration. + __READONLY_PROPERTY_PLAIN(bool, requireReg, requireReg); + }; +} // namespace dmr + +#endif // __DMR_SITE_DATA_H__ diff --git a/dmr/Slot.cpp b/dmr/Slot.cpp index 2494b417..454bfdd9 100644 --- a/dmr/Slot.cpp +++ b/dmr/Slot.cpp @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX -* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL +* Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,6 +49,8 @@ using namespace dmr; uint32_t Slot::m_colorCode = 0U; +SiteData Slot::m_siteData = SiteData(); + bool Slot::m_embeddedLCOnly = false; bool Slot::m_dumpTAData = true; @@ -385,6 +387,7 @@ void Slot::clock() /// Helper to initialize the DMR slot processor. /// /// DMR access color code. +/// DMR site data. /// /// /// Amount of hangtime for a DMR call. @@ -395,7 +398,7 @@ void Slot::clock() /// Instance of the TalkgroupIdLookup class. /// Instance of the CRSSIInterpolator class. /// -void Slot::init(uint32_t colorCode, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, +void Slot::init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter) { @@ -405,6 +408,7 @@ void Slot::init(uint32_t colorCode, bool embeddedLCOnly, bool dumpTAData, uint32 assert(rssiMapper != NULL); m_colorCode = colorCode; + m_siteData = siteData; m_embeddedLCOnly = embeddedLCOnly; m_dumpTAData = dumpTAData; m_modem = modem; @@ -650,6 +654,50 @@ void Slot::writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId) writeQueueRF(data); } +/// +/// Helper to write a TSCC broadcast packet on the RF interface. +/// +/// Broadcast announcement type. +void Slot::writeRF_TSCC_Broadcast(uint8_t anncType) +{ + if (m_verbose) { + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), anncType = %u", + m_slotNo, anncType); + } + + uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; + ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); + + SlotType slotType; + slotType.setColorCode(m_colorCode); + slotType.setDataType(DT_CSBK); + + lc::CSBK csbk = lc::CSBK(); + csbk.setVerbose(m_dumpCSBKData); + csbk.setCSBKO(CSBKO_BROADCAST); + csbk.setFID(FID_ETSI); + + csbk.setAnncType(anncType); + csbk.setSiteData(m_siteData); + + // Regenerate the CSBK data + csbk.encode(data + 2U); + + // Regenerate the Slot Type + slotType.encode(data + 2U); + + // Convert the Data Sync to be from the BS or MS as needed + Sync::addDMRDataSync(data + 2U, m_duplex); + + m_rfSeqNo = 0U; + + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + if (m_duplex) + writeQueueRF(data); +} + /// /// /// @@ -696,7 +744,7 @@ void Slot::setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco, bool voice) return; uint8_t lc[5U]; - lc[0U] = 0x01U; + lc[0U] = SLCO_ACT; lc[1U] = 0x00U; lc[2U] = 0x00U; lc[3U] = 0x00U; @@ -742,3 +790,64 @@ void Slot::setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco, bool voice) m_modem->writeDMRShortLC(sLC); } + +/// +/// +/// +/// +/// +/// +void Slot::setShortLC_TSCC(SiteData siteData, uint16_t counter) +{ + assert(m_modem != NULL); + + uint8_t lc[5U]; + uint32_t lcValue = 0U; + lcValue = SLCO_TSCC; + lcValue = (lcValue << 2) + siteData.siteModel(); + + switch (siteData.siteModel()) + { + case SITE_MODEL_TINY: + { + lcValue = (lcValue << 9) + siteData.netId(); + lcValue = (lcValue << 3) + siteData.siteId(); + } + break; + case SITE_MODEL_SMALL: + { + lcValue = (lcValue << 7) + siteData.netId(); + lcValue = (lcValue << 5) + siteData.siteId(); + } + break; + case SITE_MODEL_LARGE: + { + lcValue = (lcValue << 5) + siteData.netId(); + lcValue = (lcValue << 7) + siteData.siteId(); + } + break; + case SITE_MODEL_HUGE: + { + lcValue = (lcValue << 2) + siteData.netId(); + lcValue = (lcValue << 10) + siteData.siteId(); + } + break; + } + + lcValue = (lcValue << 1) + ((siteData.requireReg()) ? 1U : 0U); + lcValue = (lcValue << 9) + (counter & 0x1FFU); + + // split value into bytes + lc[0U] = (uint8_t)((lcValue >> 24) & 0xFFU); + lc[1U] = (uint8_t)((lcValue >> 16) & 0xFFU); + lc[2U] = (uint8_t)((lcValue >> 8) & 0xFFU); + lc[3U] = (uint8_t)((lcValue >> 0) & 0xFFU); + lc[4U] = edac::CRC::crc8(lc, 4U); + + uint8_t sLC[9U]; + + lc::ShortLC shortLC; + shortLC.encode(lc, sLC); + + m_modem->writeDMRShortLC(sLC); +} diff --git a/dmr/Slot.h b/dmr/Slot.h index 69de0c68..88364484 100644 --- a/dmr/Slot.h +++ b/dmr/Slot.h @@ -33,6 +33,7 @@ #include "Defines.h" #include "dmr/Control.h" +#include "dmr/SiteData.h" #include "dmr/DataPacket.h" #include "dmr/VoicePacket.h" #include "modem/Modem.h" @@ -80,7 +81,7 @@ namespace dmr void clock(); /// Helper to initialize the slot processor. - static void init(uint32_t colorCode, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, + static void init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter); @@ -136,6 +137,8 @@ namespace dmr static uint32_t m_colorCode; + static SiteData m_siteData; + static bool m_embeddedLCOnly; static bool m_dumpTAData; @@ -181,9 +184,13 @@ namespace dmr void writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId); /// Helper to write a call alert packet on the RF interface. void writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId); + /// Helper to write a TSCC broadcast packet on the RF interface. + void writeRF_TSCC_Broadcast(uint8_t anncType); /// static void setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco = FLCO_GROUP, bool voice = true); + /// + static void setShortLC_TSCC(SiteData siteData, uint16_t counter); }; } // namespace dmr diff --git a/dmr/lc/CSBK.cpp b/dmr/lc/CSBK.cpp index 7eb29851..e4f92379 100644 --- a/dmr/lc/CSBK.cpp +++ b/dmr/lc/CSBK.cpp @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX -* Copyright (C) 2019 by Bryan Biedenkapp N2PLL +* Copyright (C) 2019-2021 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,15 +51,20 @@ CSBK::CSBK() : m_verbose(false), m_CSBKO(CSBKO_NONE), m_FID(0x00U), + m_lastBlock(true), m_bsId(0U), m_GI(false), m_srcId(0U), m_dstId(0U), m_dataContent(false), m_CBF(0U), - m_data(NULL) + m_data(NULL), + m_siteData(), + m_siteNetActive(false) { m_data = new uint8_t[12U]; + + reset(); } /// @@ -99,72 +104,86 @@ bool CSBK::decode(const uint8_t* bytes) Utils::dump(2U, "Decoded CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES); } - m_CSBKO = m_data[0U] & 0x3FU; - m_FID = m_data[1U]; + m_CSBKO = m_data[0U] & 0x3FU; // CSBKO + m_lastBlock = (m_data[0U] & 0x80U) == 0x80U; // Last Block Marker + m_FID = m_data[1U]; // Feature ID switch (m_CSBKO) { case CSBKO_BSDWNACT: m_GI = false; - m_bsId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; + m_bsId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Base Station ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID m_dataContent = false; m_CBF = 0U; break; case CSBKO_UU_V_REQ: m_GI = false; - m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID m_dataContent = false; m_CBF = 0U; break; case CSBKO_UU_ANS_RSP: m_GI = false; - m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID m_dataContent = false; m_CBF = 0U; break; case CSBKO_PRECCSBK: m_GI = (m_data[2U] & 0x40U) == 0x40U; - m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID m_dataContent = (m_data[2U] & 0x80U) == 0x80U; m_CBF = m_data[3U]; break; - case CSBKO_CALL_ALRT: - m_GI = (m_data[2U] & 0x40U) == 0x40U; - m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; - m_dataContent = (m_data[2U] & 0x80U) == 0x80U; - m_CBF = m_data[3U]; - break; + case CSBKO_RAND: // CSBKO_CALL_ALRT when FID == FID_DMRA + switch (m_FID) + { + case FID_DMRA: + m_GI = (m_data[2U] & 0x40U) == 0x40U; // Group or Individual + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID + m_dataContent = (m_data[2U] & 0x80U) == 0x80U; // + m_CBF = m_data[3U]; // + break; + + /* Tier III */ + case FID_ETSI: + default: + m_serviceOptions = m_data[2U]; // Service Options + m_targetAddress = (m_data[3U] >> 6 & 0x03U); // Target Address + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID + break; + } case CSBKO_ACK_RSP: m_GI = (m_data[2U] & 0x40U) == 0x40U; - m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; - m_dataContent = (m_data[2U] & 0x80U) == 0x80U; - m_CBF = m_data[3U]; + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID + m_response = m_data[3U]; // Response + m_dataContent = false; break; case CSBKO_EXT_FNCT: m_GI = false; - m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; - m_dataContent = (m_data[2U] & 0x80U) == 0x80U; - m_CBF = m_data[3U]; + m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Destination ID + m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Source ID + m_dataContent = (m_data[2U] & 0x80U) == 0x80U; // + m_CBF = m_data[3U]; // break; case CSBKO_NACK_RSP: m_GI = false; - m_srcId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; - m_dstId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; + m_srcId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U]; // Source ID + m_dstId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; // Destination ID + m_response = m_data[3U]; // Response m_dataContent = false; - m_CBF = 0U; break; default: @@ -184,40 +203,146 @@ bool CSBK::decode(const uint8_t* bytes) /// Encodes a DMR CSBK. /// /// -void CSBK::encode(uint8_t* bytes) const +void CSBK::encode(uint8_t* bytes) { assert(bytes != NULL); - m_data[0U] = m_CSBKO; - m_data[1U] = m_FID; + m_data[0U] = m_CSBKO; // CSBKO + m_data[0U] |= (m_lastBlock) ? 0x80U : 0x00U; // Last Block Marker + m_data[1U] = m_FID; // Feature ID - if (m_GI) { - m_data[2U] |= 0x40U; - } + switch (m_CSBKO) { + case CSBKO_ACK_RSP: + m_data[2U] = (uint8_t)(m_serviceType & 0x3FU); // Service Type + m_data[2U] |= 0x80U; // Additional Information Field (always 1) + if (m_GI) { + m_data[2U] |= 0x40U; // Source Type + } + m_data[3U] = m_response; // Reason Code + + m_data[4U] = (m_srcId >> 16) & 0xFFU; // Source ID + m_data[5U] = (m_srcId >> 8) & 0xFFU; + m_data[6U] = (m_srcId >> 0) & 0xFFU; - if (m_dataContent) { - m_data[2U] |= 0x80U; - } + m_data[7U] = (m_dstId >> 16) & 0xFFU; // Destination ID + m_data[8U] = (m_dstId >> 8) & 0xFFU; + m_data[9U] = (m_dstId >> 0) & 0xFFU; + break; + + case CSBKO_EXT_FNCT: + if (m_GI) { + m_data[2U] |= 0x40U; // Group or Individual + } - m_data[3U] = m_CBF; + if (m_dataContent) { + m_data[2U] |= 0x80U; // + } - if (m_CSBKO == CSBKO_EXT_FNCT) { - m_data[4U] = (m_srcId >> 16) & 0xFFU; + m_data[3U] = m_CBF; // + + m_data[4U] = (m_srcId >> 16) & 0xFFU; // Source ID m_data[5U] = (m_srcId >> 8) & 0xFFU; m_data[6U] = (m_srcId >> 0) & 0xFFU; - m_data[7U] = (m_dstId >> 16) & 0xFFU; + m_data[7U] = (m_dstId >> 16) & 0xFFU; // Destination ID m_data[8U] = (m_dstId >> 8) & 0xFFU; m_data[9U] = (m_dstId >> 0) & 0xFFU; - } - else { - m_data[4U] = (m_dstId >> 16) & 0xFFU; + break; + + case CSBKO_NACK_RSP: + m_data[2U] = (uint8_t)(m_serviceType & 0x3FU); // Service Type + m_data[2U] |= 0x80U; // Additional Information Field (always 1) + if (m_GI) { + m_data[2U] |= 0x40U; // Source Type + } + m_data[3U] = m_response; // Reason Code + + m_data[4U] = (m_srcId >> 16) & 0xFFU; // Source ID + m_data[5U] = (m_srcId >> 8) & 0xFFU; + m_data[6U] = (m_srcId >> 0) & 0xFFU; + + m_data[7U] = (m_dstId >> 16) & 0xFFU; // Destination ID + m_data[8U] = (m_dstId >> 8) & 0xFFU; + m_data[9U] = (m_dstId >> 0) & 0xFFU; + break; + + default: + if (m_GI) { + m_data[2U] |= 0x40U; // Group or Individual + } + + if (m_dataContent) { + m_data[2U] |= 0x80U; // + } + + m_data[3U] = m_CBF; // + + m_data[4U] = (m_dstId >> 16) & 0xFFU; // Destination ID m_data[5U] = (m_dstId >> 8) & 0xFFU; m_data[6U] = (m_dstId >> 0) & 0xFFU; - m_data[7U] = (m_srcId >> 16) & 0xFFU; + m_data[7U] = (m_srcId >> 16) & 0xFFU; // Source ID m_data[8U] = (m_srcId >> 8) & 0xFFU; m_data[9U] = (m_srcId >> 0) & 0xFFU; + break; + + /* Tier III */ + case CSBKO_ALOHA: + { + ulong64_t csbkValue = 0U; + csbkValue = (csbkValue << 2) + 0U; // Reserved + csbkValue = (csbkValue << 1) + ((m_siteTSSync) ? 1U : 0U); // Site Time Slot Synchronization + csbkValue = (csbkValue << 3) + DMR_ALOHA_VER_151; // DMR Spec. Version (1.5.1) + csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset + csbkValue = (csbkValue << 1) + ((m_siteNetActive) ? 1U : 0U); // Site Networked + csbkValue = (csbkValue << 5) + (m_alohaMask & 0x1FU); // MS Mask + csbkValue = (csbkValue << 2) + 0U; // Service Function + csbkValue = (csbkValue << 4) + 0U; // + csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration + csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number + csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + csbkValue = (csbkValue << 24) + m_srcId; // Source ID + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + break; + } + break; + case CSBKO_BROADCAST: + { + ulong64_t csbkValue = 0U; + csbkValue = m_anncType; // Announcement Type + + switch (m_anncType) + { + case BCAST_ANNC_SITE_PARMS: + csbkValue = (csbkValue << 14) + m_siteData.systemIdentity(true); // Site Identity (Broadcast Parms 1) + csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number + csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + csbkValue = (csbkValue << 1) + 0U; // Roaming TG Subscription/Attach + csbkValue = (csbkValue << 1) + ((m_hibernating) ? 1U : 0U); // TSCC Hibernating + csbkValue = (csbkValue << 22) + 0U; // Broadcast Parms 2 (Reserved) + break; + } + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + } + break; } m_data[10U] ^= CSBK_CRC_MASK[0U]; @@ -236,3 +361,39 @@ void CSBK::encode(uint8_t* bytes) const edac::BPTC19696 bptc; bptc.encode(m_data, bytes); } + +/// +/// Helper to reset data values to defaults. +/// +void CSBK::reset() +{ + m_backoffNo = 1U; + m_serviceType = 0U; + m_serviceOptions = 0U; + m_targetAddress = TGT_ADRS_TGID; + + m_response = 0U; + + /* Broadcast */ + m_anncType = BCAST_ANNC_SITE_PARMS; + m_hibernating = false; + + /* Aloha */ + m_siteTSSync = false; + m_siteOffsetTiming = false; +} + +/** Local Site data */ +/// Sets local configured site data. +/// +void CSBK::setSiteData(SiteData siteData) +{ + m_siteData = siteData; +} + +/// Sets a flag indicating whether or not networking is active. +/// +void CSBK::setNetActive(bool netActive) +{ + m_siteNetActive = netActive; +} diff --git a/dmr/lc/CSBK.h b/dmr/lc/CSBK.h index 1e0f9c78..dc7d136a 100644 --- a/dmr/lc/CSBK.h +++ b/dmr/lc/CSBK.h @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX -* Copyright (C) 2019 by Bryan Biedenkapp N2PLL +* Copyright (C) 2019-2021 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ #include "Defines.h" #include "dmr/DMRDefines.h" +#include "dmr/SiteData.h" namespace dmr { @@ -53,7 +54,16 @@ namespace dmr /// Decodes a DMR CSBK. bool decode(const uint8_t* bytes); /// Encodes a DMR CSBK. - void encode(uint8_t* bytes) const; + void encode(uint8_t* bytes); + + /// Helper to reset data values to defaults. + void reset(); + + /** Local Site data */ + /// Sets local configured site data. + void setSiteData(SiteData siteData); + /// Sets a flag indicating whether or not networking is active. + void setNetActive(bool netActive); public: /// @@ -65,6 +75,9 @@ namespace dmr /// CSBK feature ID. __PROPERTY(uint8_t, FID, FID); + /// Flag indicating this is the last TSBK in a sequence of TSBKs. + __PROPERTY(bool, lastBlock, LastBlock); + // For BS Dwn Act __READONLY_PROPERTY(uint32_t, bsId, BSId); @@ -83,8 +96,38 @@ namespace dmr /// Sets the number of blocks to follow. __PROPERTY(uint8_t, CBF, CBF); + // Tier III + /// Backoff Number. + __PROPERTY(uint8_t, backoffNo, BackoffNo); + + /// Service Type. + __PROPERTY(uint8_t, serviceType, serviceType); + /// Service type. + __PROPERTY(uint8_t, serviceOptions, ServiceOptions); + /// Destination/Target address type. + __PROPERTY(uint8_t, targetAddress, TargetAddress); + + /// Response type. + __PROPERTY(uint8_t, response, Response); + + /// Broadcast Announcment Type. + __PROPERTY(uint8_t, anncType, AnncType); + /// Broadcast Hibernation Flag. + __PROPERTY(bool, hibernating, Hibernating); + + /// Aloha Site Time Slot Synchronization. + __PROPERTY(bool, siteTSSync, SiteTSSync); + /// Aloha site users offset timing. + __PROPERTY(bool, siteOffsetTiming, SiteOffsetTiming); + /// Aloha MS mask. + __PROPERTY(uint8_t, alohaMask, AlohaMask); + private: uint8_t* m_data; + + /** Local Site data */ + SiteData m_siteData; + bool m_siteNetActive; }; } // namespace lc } // namespace dmr diff --git a/p25/lc/TSBK.cpp b/p25/lc/TSBK.cpp index 12e7a1e3..ca2679c1 100644 --- a/p25/lc/TSBK.cpp +++ b/p25/lc/TSBK.cpp @@ -130,7 +130,7 @@ bool TSBK::decode(const uint8_t* data) } m_lco = tsbk[0U] & 0x3F; // LCO - m_lastBlock = (tsbk[0U] & 0x80U) == 0x80U; // Protect Flag + m_lastBlock = (tsbk[0U] & 0x80U) == 0x80U; // Last Block Marker m_mfId = tsbk[1U]; // Mfg Id. ulong64_t tsbkValue = 0U;