diff --git a/.idea/misc.xml b/.idea/misc.xml index 29ce38d1d..00f52ed7b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/DMRDataMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/DMRDataMessageFactory.java index 3fd873855..0b13a0cca 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/DMRDataMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/DMRDataMessageFactory.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -45,7 +45,7 @@ import io.github.dsheirer.module.decode.dmr.message.data.header.VoiceHeader; import io.github.dsheirer.module.decode.dmr.message.data.header.hytera.HyteraProprietaryDataHeader; import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MNISProprietaryDataHeader; -import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaProprietaryDataHeader; +import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaDataEncryptionHeader; import io.github.dsheirer.module.decode.dmr.message.data.mbc.MBCContinuationBlock; import io.github.dsheirer.module.decode.dmr.message.data.terminator.Terminator; import io.github.dsheirer.module.decode.dmr.message.data.usb.USBData; @@ -132,7 +132,7 @@ public static DataMessage create(DMRSyncPattern pattern, CorrectedBinaryMessage } else { - MotorolaProprietaryDataHeader mprdh = new MotorolaProprietaryDataHeader(pattern, + MotorolaDataEncryptionHeader mprdh = new MotorolaDataEncryptionHeader(pattern, payload, cach, slotType, timestamp, timeslot); mprdh.setValid(valid); return mprdh; diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/csbk/motorola/CapacityPlusSiteStatus.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/csbk/motorola/CapacityPlusSiteStatus.java index d7b6d13e2..a406f03e5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/csbk/motorola/CapacityPlusSiteStatus.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/csbk/motorola/CapacityPlusSiteStatus.java @@ -78,7 +78,7 @@ public String toString() sb.append(" RAS:").append(getBPTCReservedBits()); } - sb.append(" CSBK CAP+ SITE STATUS REST ").append(getRestChannel()); + sb.append(" CSBK CAP+ SITE STATUS REST:").append(getRestChannel()); sb.append(" ").append(getSegmentIndicator()); sb.append(" "); diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/DefinedShortDataHeader.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/DefinedShortDataHeader.java index 89828448b..893b5fd5c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/DefinedShortDataHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/DefinedShortDataHeader.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -25,7 +25,6 @@ import io.github.dsheirer.module.decode.dmr.message.CACH; import io.github.dsheirer.module.decode.dmr.message.data.SlotType; import io.github.dsheirer.module.decode.dmr.message.type.DefinedDataFormat; - import java.util.ArrayList; import java.util.List; @@ -39,6 +38,7 @@ public class DefinedShortDataHeader extends PacketSequenceHeader private static final int RESYNCHRONIZE_FLAG = 70; private static final int FULL_MESSAGE_FLAG = 71; private static final int[] BIT_PADDING = new int[]{72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] HEADER_CRC = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}; private List mIdentifiers; diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/ProprietaryDataHeader.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/ProprietaryDataHeader.java index 2f40f045f..33b8eef1d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/ProprietaryDataHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/ProprietaryDataHeader.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -34,6 +34,11 @@ public class ProprietaryDataHeader extends DataHeader { private static final int[] SERVICE_ACCESS_POINT = new int[]{0, 1, 2, 3}; private static final int[] VENDOR = new int[]{8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] VENDOR_DATA = new int[]{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] HEADER_CRC = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}; /** * Constructs an instance. @@ -62,10 +67,20 @@ public String toString() sb.append(" PROPRIETARY DATA HEADER"); sb.append(" VENDOR:").append(getVendor()); sb.append(" ").append(getServiceAccessPoint()); + sb.append(" VENDOR DATA:").append(getVendorData()); sb.append(" MSG:").append(getMessage().toHexString()); return sb.toString(); } + /** + * Vendor defined data payload from this proprietary header. + * @return hex values. + */ + public String getVendorData() + { + return getMessage().getHex(VENDOR_DATA, 16); + } + /** * Optional packet prefix. * @return packet prefix fragment or null. diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MNISProprietaryDataHeader.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MNISProprietaryDataHeader.java index 523b56835..b3346d518 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MNISProprietaryDataHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MNISProprietaryDataHeader.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -66,7 +66,8 @@ public MNISProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinaryMess public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("MOTOROLA MNIS HEADER"); + sb.append("CC:").append(getSlotType().getColorCode()); + sb.append(" MOTOROLA MNIS HEADER"); if(getApplicationType() == ApplicationType.UNKNOWN) { sb.append(" APPLICATION TYPE:0x").append(Integer.toHexString(getApplicationTypeNumber()).toUpperCase()); diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MotorolaProprietaryDataHeader.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MotorolaDataEncryptionHeader.java similarity index 62% rename from src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MotorolaProprietaryDataHeader.java rename to src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MotorolaDataEncryptionHeader.java index 4e0070df9..f72589f57 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MotorolaProprietaryDataHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/header/motorola/MotorolaDataEncryptionHeader.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -31,10 +31,15 @@ /** * Motorola Proprietary Data Header */ -public class MotorolaProprietaryDataHeader extends ProprietaryDataHeader +public class MotorolaDataEncryptionHeader extends ProprietaryDataHeader { private static final int[] SERVICE_ACCESS_POINT = new int[]{0, 1, 2, 3}; private static final int[] VENDOR = new int[]{8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] ALGORITHM = new int[]{16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] KEY_ID = new int[]{24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] UNKNOWN = new int[]{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] INITIALIZATION_VECTOR = new int[]{48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; /** * Constructs an instance. @@ -46,7 +51,7 @@ public class MotorolaProprietaryDataHeader extends ProprietaryDataHeader * @param timestamp message was received * @param timeslot for the DMR burst */ - public MotorolaProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinaryMessage message, CACH cach, SlotType slotType, long timestamp, int timeslot) + public MotorolaDataEncryptionHeader(DMRSyncPattern syncPattern, CorrectedBinaryMessage message, CACH cach, SlotType slotType, long timestamp, int timeslot) { super(syncPattern, message, cach, slotType, timestamp, timeslot); } @@ -55,14 +60,57 @@ public MotorolaProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinary public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("MOTOROLA PROPRIETARY DATA HEADER"); - sb.append(" ").append(getServiceAccessPoint()); + sb.append("CC:").append(getSlotType().getColorCode()); + sb.append(" MOTOROLA DATA ENCRYPTION HEADER"); + sb.append(" SAP:").append(getServiceAccessPoint()); + sb.append(" ALGORITHM:").append(getAlgorithm()); + sb.append(" KEY:").append(getKeyId()); + sb.append(" IV:").append(getInitializationVector()); + sb.append(" UNK:").append(getUnknown()); sb.append(" MSG:").append(getMessage().toHexString()); return sb.toString(); } + /** + * Unknown message field(s). + * @return hex value. + */ + public String getUnknown() + { + return getMessage().getHex(UNKNOWN, 4); + } + + /** + * Encryption key ID + * @return key ID + */ + public int getKeyId() + { + return getMessage().getInt(KEY_ID); + } + + /** + * Encryption Algorithm + * @return algorithm ID + */ + public int getAlgorithm() + { + return getMessage().getInt(ALGORITHM); + } + + /** + * Encryption initialization vector + * + * @return vector in hex + */ + public String getInitializationVector() + { + return getMessage().getHex(INITIALIZATION_VECTOR, 8); + } + /** * Utility method to lookup the vendor from a CSBK message + * * @param message containing CSBK bits * @return vendor */ diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/LCMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/LCMessageFactory.java index cf32d84bd..f4907515d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/LCMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/LCMessageFactory.java @@ -37,9 +37,9 @@ import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraTerminator; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraUnitToUnitVoiceChannelUser; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptedVoiceChannelUser; -import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptionParameters; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusGroupVoiceChannelUser; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusWideAreaVoiceChannelUser; +import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaEncryptionParameters; import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ActivityUpdateMessage; import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.CapacityPlusRestChannel; import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ConnectPlusControlChannel; @@ -123,7 +123,7 @@ else if(message.size() == 96) flc = new CapacityPlusWideAreaVoiceChannelUser(message, timestamp, timeslot); break; case FULL_CAPACITY_PLUS_ENCRYPTION_PARAMETERS: - flc = new CapacityPlusEncryptionParameters(message, timestamp, timeslot); + flc = new MotorolaEncryptionParameters(message, timestamp, timeslot); break; case FULL_HYTERA_GROUP_VOICE_CHANNEL_USER: flc = new HyteraGroupVoiceChannelUser(message, timestamp, timeslot); diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusWideAreaVoiceChannelUser.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusWideAreaVoiceChannelUser.java index b835cc1b1..fdc7dbd7b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusWideAreaVoiceChannelUser.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusWideAreaVoiceChannelUser.java @@ -27,9 +27,7 @@ import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver; import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency; import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio; -import io.github.dsheirer.module.decode.dmr.identifier.DMRSite; import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup; - import java.util.ArrayList; import java.util.List; @@ -45,15 +43,13 @@ public class CapacityPlusWideAreaVoiceChannelUser extends CapacityPlusVoiceChann private static final int[] GROUP_ID = new int[]{40, 41, 42, 43, 44, 45, 46, 47}; private static final int[] UNUSED = new int[]{48, 49, 50, 51}; private static final int[] REST_LSN = new int[]{52, 53, 54, 55}; - private static final int[] RADIO_ID = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; - private static final int[] SITE = new int[]{72, 73, 74, 75}; + private static final int[] RADIO_ID = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75}; private static final int[] UNKNOWN_2 = new int[]{76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}; private RadioIdentifier mRadio; private TalkgroupIdentifier mTalkgroup; private DMRLogicalChannel mRestChannel; - private DMRSite mSite; private List mIdentifiers; /** @@ -98,8 +94,6 @@ public String toString() { sb.append("--"); } - sb.append(" SITE:").append(getSite()); - sb.append(" ").append(getServiceOptions()); sb.append(" ").append(getServiceOptions()); sb.append(" UNK1:").append(getUnknown1()); sb.append(" UNK2:").append(getUnknown2()); @@ -120,7 +114,7 @@ public String getUnknown1() */ public String getUnknown2() { - return getMessage().getHex(UNKNOWN_2, 5); + return getMessage().getHex(UNKNOWN_2, 6); } /** @@ -153,20 +147,6 @@ public boolean hasRestChannel() return getRestLSN() != 0; } - /** - * Site number - * @return site - */ - public DMRSite getSite() - { - if(mSite == null) - { - mSite = new DMRSite(getMessage().getInt(SITE)); - } - - return mSite; - } - /** * Source radio address */ diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusEncryptionParameters.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/MotorolaEncryptionParameters.java similarity index 72% rename from src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusEncryptionParameters.java rename to src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/MotorolaEncryptionParameters.java index b98409c8b..76f226d79 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/CapacityPlusEncryptionParameters.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/full/motorola/MotorolaEncryptionParameters.java @@ -21,33 +21,25 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.identifier.radio.RadioIdentifier; -import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; -import io.github.dsheirer.module.decode.dmr.channel.DMRLogicalChannel; -import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver; -import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency; -import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio; import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage; - import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** - * Motorola Capacity Plus - Encryption Parameters + * Motorola Encryption Parameters *

* Note: observed as FLC payload for a PI_HEADER slot type. + * Note: observed on a possible Hytera (clone) system that was configured as IP Site Connect compatible. */ -public class CapacityPlusEncryptionParameters extends FullLCMessage +public class MotorolaEncryptionParameters extends FullLCMessage { - //NOTE: field definitions are best guesses ... algorithm and key ID fields might be interchanged - private static final int[] ENCRYPTION_ALGORITHM = new int[]{16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] KEY_ID = new int[]{16, 17, 18, 19, 20, 21, 22, 23}; private static final int[] INITIALIZATION_VECTOR = new int[]{24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}; - private static final int[] KEY_ID = new int[]{56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] ALGORITHM = new int[]{56, 57, 58, 59, 60, 61, 62, 63}; private static final int[] DESTINATION_GROUP = new int[]{64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; - private static final int[] UNKNOWN = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 83, 94, 95}; + private static final int[] UNKNOWN = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}; private DMRTalkgroup mTalkgroup; private List mIdentifiers; @@ -57,7 +49,7 @@ public class CapacityPlusEncryptionParameters extends FullLCMessage * * @param message for the link control payload */ - public CapacityPlusEncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot) + public MotorolaEncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot) { super(message, timestamp, timeslot); } @@ -82,11 +74,10 @@ public String toString() sb.append(" *RESERVED-BIT*"); } - sb.append("FLC MOTOROLA CAP+ ENCRYPTION PARAMETERS - ALGORITHM:").append(getEncryptionAlgorithm()); + sb.append("FLC MOTOROLA ENCRYPTION PARAMETERS - ALGORITHM:").append(getAlgorithm()); sb.append(" KEY:").append(getKeyId()); sb.append(" IV:").append(getInitializationVector()); sb.append(" TALKGROUP:").append(getTalkgroup()); - sb.append(" UNK:").append(getUnknown()); sb.append(" MSG:").append(getMessage().toHexString()); return sb.toString(); } @@ -106,9 +97,16 @@ public int getKeyId() return getMessage().getInt(KEY_ID); } - public int getEncryptionAlgorithm() + public String getAlgorithm() { - return getMessage().getInt(ENCRYPTION_ALGORITHM); + int algorithm = getMessage().getInt(ALGORITHM); + + if(algorithm == 0) + { + return "EP/RC4"; + } + + return "UNK(" + algorithm + ")"; } public String getInitializationVector() diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/ActivityUpdateMessage.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/ActivityUpdateMessage.java index 1c1763c42..8eb7fa64d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/ActivityUpdateMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/ActivityUpdateMessage.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -22,7 +22,6 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.dmr.message.type.Activity; - import java.util.Collections; import java.util.List; @@ -55,13 +54,18 @@ public String toString() { sb.append("[CRC ERROR] "); } - - sb.append("SLC ACTIVITY UPDATE TS1 ["); - sb.append(getHashAddressTS1()).append("] "); + sb.append("SLC TS1:"); sb.append(getActivityTS1()); - sb.append(" / TS2 ["); - sb.append(getHashAddressTS2()).append("] "); + if(getActivityTS1() != Activity.IDLE) + { + sb.append(" [").append(getHashAddressTS1()).append("]"); + } + sb.append(" TS2:"); sb.append(getActivityTS2()); + if(getActivityTS2() != Activity.IDLE) + { + sb.append(" [").append(getHashAddressTS2()).append("]"); + } sb.append(" MSG:").append(getMessage().toHexString()); return sb.toString(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/NullMessage.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/NullMessage.java index 8a18ce85f..ef96de9fe 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/NullMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/lc/shorty/NullMessage.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -21,7 +21,6 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; - import java.util.Collections; import java.util.List; @@ -48,8 +47,7 @@ public String toString() { sb.append("[CRC ERROR] "); } - sb.append("SLC IDLE/NULL MESSAGE"); - sb.append(" MSG:").append(getMessage().toHexString()); + sb.append("SLC TS1:IDLE TS2:IDLE"); return sb.toString(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/DMRPacketMessage.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/DMRPacketMessage.java index 063295a90..6d7dfcb62 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/DMRPacketMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/DMRPacketMessage.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2023 Dennis Sheirer * * 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 @@ -23,7 +23,6 @@ import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.dmr.message.DMRMessage; import io.github.dsheirer.module.decode.ip.IPacket; - import java.util.ArrayList; import java.util.List; @@ -75,6 +74,10 @@ public String toString() sb.append("CC:").append(getPacketSequence().getPacketSequenceHeader().getSlotType().getColorCode()); sb.append(" FM:").append(getPacketSequence().getPacketSequenceHeader().getSourceLLID()); sb.append(" TO:").append(getPacketSequence().getPacketSequenceHeader().getDestinationLLID()); + if(getPacketSequence().isEncrypted()) + { + sb.append(" ENCRYPTED"); + } sb.append(" ").append(getPacket().toString()); return sb.toString(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequence.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequence.java index 9136b1519..d22bc6812 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequence.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequence.java @@ -24,6 +24,7 @@ import io.github.dsheirer.module.decode.dmr.message.data.header.PacketSequenceHeader; import io.github.dsheirer.module.decode.dmr.message.data.header.ProprietaryDataHeader; import io.github.dsheirer.module.decode.dmr.message.data.header.UDTHeader; +import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaDataEncryptionHeader; import java.util.ArrayList; import java.util.List; @@ -89,6 +90,15 @@ public boolean isComplete() return false; } + /** + * Indicates if this sequence contains a Motorola data encryption header. + * @return true if so + */ + public boolean isEncrypted() + { + return hasProprietaryDataHeader() && getProprietaryDataHeader() instanceof MotorolaDataEncryptionHeader; + } + public int getTimeslot() { return mTimeslot; diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequenceMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequenceMessageFactory.java index cb444b37d..4a27855c0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequenceMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/data/packet/PacketSequenceMessageFactory.java @@ -29,7 +29,10 @@ import io.github.dsheirer.module.decode.dmr.message.data.header.UDTHeader; import io.github.dsheirer.module.decode.dmr.message.data.header.hytera.HyteraProprietaryDataHeader; import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MNISProprietaryDataHeader; +import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaDataEncryptionHeader; import io.github.dsheirer.module.decode.dmr.message.type.ApplicationType; +import io.github.dsheirer.module.decode.dmr.message.type.DataPacketFormat; +import io.github.dsheirer.module.decode.ip.DefinedShortDataPacket; import io.github.dsheirer.module.decode.ip.UnknownPacket; import io.github.dsheirer.module.decode.ip.hytera.sds.HyteraTokenHeader; import io.github.dsheirer.module.decode.ip.hytera.sds.HyteraUnknownPacket; @@ -179,9 +182,20 @@ else if(secondaryHeader instanceof HyteraProprietaryDataHeader) packetSequence.getTimeslot(), packetSequence.getPacketSequenceHeader().getTimestamp()); } } + else if(secondaryHeader instanceof MotorolaDataEncryptionHeader && + packetSequence.getPacketSequenceHeader().getDataPacketFormat() == DataPacketFormat.DEFINED_SHORT_DATA) + { + return createDefinedShortData(packetSequence, packet); + } else { - mLog.info("Unknown Proprietary Packet Header Type - creating unknown packet."); + if(packetSequence.getProprietaryDataHeader() != null) + { + mLog.info("Unknown Proprietary Packet Header Type - creating unknown packet. Data Packet Format: " + + packetSequence.getPacketSequenceHeader().getDataPacketFormat() + " Proprietary Header: " + + packetSequence.getProprietaryDataHeader().getClass()); + } + return new DMRPacketMessage(packetSequence, new UnknownPacket(packet, 0), packet, packetSequence.getTimeslot(), packetSequence.getPacketSequenceHeader().getTimestamp()); } @@ -217,8 +231,7 @@ public static IMessage createIPPacketData(PacketSequence packetSequence, Correct */ public static IMessage createDefinedShortData(PacketSequence packetSequence, CorrectedBinaryMessage packet) { - mLog.info("Unknown Short Data Packet Header Type - creating unknown packet."); - return new DMRPacketMessage(packetSequence, new UnknownPacket(packet, 0), packet, + return new DMRPacketMessage(packetSequence, new DefinedShortDataPacket(packet, 0), packet, packetSequence.getTimeslot(), packetSequence.getPacketSequenceHeader().getTimestamp()); } diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/DefinedShortDataPacket.java b/src/main/java/io/github/dsheirer/module/decode/ip/DefinedShortDataPacket.java new file mode 100644 index 000000000..a89ba9c15 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/DefinedShortDataPacket.java @@ -0,0 +1,98 @@ +/* + * ***************************************************************************** + * Copyright (C) 2014-2023 Dennis Sheirer + * + * 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 3 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, see + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import java.util.Collections; +import java.util.List; + +/** + * Defined Short Data Packet + */ +public class DefinedShortDataPacket implements IPacket +{ + private BinaryMessage mMessage; + private int mOffset; + + /** + * Constructor + * @param message of the complete packet + * @param offset into the message + */ + public DefinedShortDataPacket(BinaryMessage message, int offset) + { + mMessage = message; + mOffset = offset; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append("DEFINED SHORT DATA PACKET:"); + + if(getMessage().size() > getOffset()) + { + sb.append(mMessage.getSubMessage(getOffset(), getMessage().size()).toHexString()); + } + else + { + sb.append("(EMPTY)"); + } + + return sb.toString(); + } + + public BinaryMessage getMessage() + { + return mMessage; + } + + public int getOffset() + { + return mOffset; + } + + @Override + public IHeader getHeader() + { + return null; + } + + @Override + public IPacket getPayload() + { + return null; + } + + @Override + public boolean hasPayload() + { + return false; + } + + @Override + public List getIdentifiers() + { + return Collections.emptyList(); + } +}