mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
* #6 DMR decoder feature - work in progress * #6 DMR Decoder. * #6 DMR Decoder. Code review updates. Co-authored-by: Zhenyu Mao <maozhenyu@foxmail.com> Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
@@ -20,11 +20,11 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
public abstract class Packet implements IPacket
|
||||
{
|
||||
private BinaryMessage mMessage;
|
||||
private CorrectedBinaryMessage mMessage;
|
||||
private int mOffset;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ public abstract class Packet implements IPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public Packet(BinaryMessage message, int offset)
|
||||
public Packet(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
mMessage = message;
|
||||
mOffset = offset;
|
||||
@@ -41,7 +41,7 @@ public abstract class Packet implements IPacket
|
||||
/**
|
||||
* Underlying message that contains this packet
|
||||
*/
|
||||
public BinaryMessage getMessage()
|
||||
public CorrectedBinaryMessage getMessage()
|
||||
{
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* Copyright (C) 2014-2020 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
|
||||
@@ -20,13 +20,17 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.ip.ars.ARSPacket;
|
||||
import io.github.dsheirer.module.decode.ip.cellocator.MCGPHeader;
|
||||
import io.github.dsheirer.module.decode.ip.cellocator.MCGPMessageFactory;
|
||||
import io.github.dsheirer.module.decode.ip.icmp.ICMPPacket;
|
||||
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Header;
|
||||
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet;
|
||||
import io.github.dsheirer.module.decode.ip.lrrp.LRRPPacket;
|
||||
import io.github.dsheirer.module.decode.ip.udp.UDPPacket;
|
||||
import io.github.dsheirer.module.decode.ip.udp.UDPPort;
|
||||
import io.github.dsheirer.module.decode.ip.xcmp.XCMPPacket;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketHeader;
|
||||
import io.github.dsheirer.module.decode.p25.reference.IPHeaderCompression;
|
||||
|
||||
@@ -42,7 +46,7 @@ public class PacketMessageFactory
|
||||
* @param offset to the IP packet within the message
|
||||
* @return constructed packet message parser
|
||||
*/
|
||||
public static IPacket create(SNDCPPacketHeader sndcpPacketHeader, BinaryMessage message, int offset)
|
||||
public static IPacket create(SNDCPPacketHeader sndcpPacketHeader, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
if(sndcpPacketHeader.getIPHeaderCompression() == IPHeaderCompression.NONE)
|
||||
{
|
||||
@@ -62,6 +66,26 @@ public class PacketMessageFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IP packet message parser
|
||||
*
|
||||
* @param message containing an IP packet
|
||||
* @param offset to the IP packet within the message
|
||||
* @return constructed packet message parser
|
||||
*/
|
||||
public static IPacket create(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
int version = IPV4Header.getIPVersion(message, offset);
|
||||
|
||||
switch(version)
|
||||
{
|
||||
case 4:
|
||||
return new IPV4Packet(message, offset);
|
||||
default:
|
||||
return new UnknownPacket(message, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IP packet protocol payload message parser.
|
||||
*
|
||||
@@ -70,10 +94,12 @@ public class PacketMessageFactory
|
||||
* @param offset to the start of the IP packet payload
|
||||
* @return constructed packet message parser
|
||||
*/
|
||||
public static IPacket create(IPProtocol protocol, BinaryMessage binaryMessage, int offset)
|
||||
public static IPacket create(IPProtocol protocol, CorrectedBinaryMessage binaryMessage, int offset)
|
||||
{
|
||||
switch(protocol)
|
||||
{
|
||||
case ICMP:
|
||||
return new ICMPPacket(binaryMessage, offset);
|
||||
case UDP:
|
||||
return new UDPPacket(binaryMessage, offset);
|
||||
default:
|
||||
@@ -88,32 +114,37 @@ public class PacketMessageFactory
|
||||
* @param destinationPort for the packet (to identify the protocol/format)
|
||||
* @param binaryMessage containing the IP/UDP payload
|
||||
* @param offset in the message to the start of the payload
|
||||
* @return constructed packet messge parser
|
||||
* @return constructed packet message parser
|
||||
*/
|
||||
public static IPacket createUDPPayload(int sourcePort, int destinationPort, BinaryMessage binaryMessage, int offset)
|
||||
public static IPacket createUDPPayload(UDPPort sourcePort, UDPPort destinationPort, CorrectedBinaryMessage binaryMessage, int offset)
|
||||
{
|
||||
switch(destinationPort)
|
||||
switch(destinationPort.getValue())
|
||||
{
|
||||
case 231:
|
||||
//Cellocator
|
||||
case 231: //Cellocator
|
||||
if(MCGPHeader.isCellocatorMessage(binaryMessage, offset))
|
||||
{
|
||||
return MCGPMessageFactory.create(binaryMessage, offset);
|
||||
}
|
||||
break;
|
||||
case 4001: //Location Service
|
||||
break;
|
||||
return new LRRPPacket(binaryMessage, offset);
|
||||
case 4004: //XCMP Service
|
||||
break;
|
||||
return new XCMPPacket(binaryMessage, offset);
|
||||
case 4005: //Automatic Registration Service
|
||||
return new ARSPacket(binaryMessage, offset);
|
||||
case 4007: //Text Message Service
|
||||
break;
|
||||
case 4008: //Telemetry Service
|
||||
break;
|
||||
case 4009: //Over The Air Programming (OTAP)
|
||||
break;
|
||||
case 4012: //Battery Management
|
||||
break;
|
||||
case 4013: //Job Ticket Server
|
||||
break;
|
||||
}
|
||||
|
||||
switch(sourcePort)
|
||||
switch(sourcePort.getValue())
|
||||
{
|
||||
case 231:
|
||||
//Cellocator
|
||||
|
||||
@@ -26,6 +26,9 @@ import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDC
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class UnknownCompressedHeaderPacket implements IPacket
|
||||
{
|
||||
private SNDCPPacketHeader mSNDCPPacketHeader;
|
||||
|
||||
@@ -22,6 +22,7 @@ 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;
|
||||
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.Header;
|
||||
|
||||
public class ARSHeader extends Header
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ARSHeader extends Header
|
||||
{
|
||||
private static final int[] LENGTH = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
private static final int HEADER_EXTENSION_FLAG = 16;
|
||||
@@ -43,19 +46,6 @@ public class ARSHeader extends Header
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("ARS ").append(getPDUType());
|
||||
|
||||
if(getPDUType() == ARSPDUType.UNKNOWN)
|
||||
{
|
||||
sb.append(" PACKET:").append(getMessage().toHexString());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the underlying message is long enough to contain the PDU
|
||||
*/
|
||||
@@ -141,4 +131,9 @@ public class ARSHeader extends Header
|
||||
return 16 + 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifiers for this packet
|
||||
*/
|
||||
public abstract List<Identifier> getIdentifiers();
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ARSHeaderFactory
|
||||
return new RegistrationAcknowledgement(message, offset);
|
||||
case UNKNOWN:
|
||||
default:
|
||||
return new ARSHeader(message, offset);
|
||||
return new UnknownARSHeader(message, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
import java.util.Collections;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ARSPacket extends Packet
|
||||
@@ -37,7 +37,7 @@ public class ARSPacket extends Packet
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ARSPacket(BinaryMessage message, int offset)
|
||||
public ARSPacket(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
@@ -71,6 +71,6 @@ public class ARSPacket extends Packet
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
return getHeader().getIdentifiers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DeviceDeRegistration extends ARSHeader
|
||||
{
|
||||
@@ -41,4 +45,10 @@ public class DeviceDeRegistration extends ARSHeader
|
||||
sb.append("ARS DEVICE/USER DE-REGISTRATION");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,23 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.ars.identifier.ARSDevice;
|
||||
import io.github.dsheirer.module.decode.ip.ars.identifier.ARSPassword;
|
||||
import io.github.dsheirer.module.decode.ip.ars.identifier.ARSUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Automatic Registration Service - Device Registration
|
||||
*/
|
||||
public class DeviceRegistration extends ARSHeader
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(DeviceRegistration.class);
|
||||
|
||||
private static final int SECOND_HEADER_EXTENSION_FLAG = 24;
|
||||
private static final int[] EVENT = {25, 26};
|
||||
private static final int[] ENCODING = {27, 28, 29, 30, 31};
|
||||
@@ -32,6 +46,11 @@ public class DeviceRegistration extends ARSHeader
|
||||
|
||||
private static final int[] BYTE_VALUE = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
private ARSDevice mDevice;
|
||||
private ARSUser mUser;
|
||||
private ARSPassword mPassword;
|
||||
private List<Identifier> mIdentifiers;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
@@ -41,6 +60,7 @@ public class DeviceRegistration extends ARSHeader
|
||||
public DeviceRegistration(BinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
parsePayload();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
@@ -52,10 +72,23 @@ public class DeviceRegistration extends ARSHeader
|
||||
{
|
||||
if(hasHeaderExtension())
|
||||
{
|
||||
sb.append(isInitialEvent() ? "-INITIAL " : "-REFRESH ");
|
||||
sb.append(isInitialEvent() ? "-INITIAL" : "-REFRESH");
|
||||
}
|
||||
|
||||
sb.append(" ").append(getPayload());
|
||||
if(hasDevice())
|
||||
{
|
||||
sb.append(" DEVICE:").append(getDevice());
|
||||
}
|
||||
|
||||
if(hasUser())
|
||||
{
|
||||
sb.append(" USER:").append(getUser());
|
||||
}
|
||||
|
||||
if(hasPassword())
|
||||
{
|
||||
sb.append(" PW:").append(getPassword());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -72,14 +105,62 @@ public class DeviceRegistration extends ARSHeader
|
||||
return getMessage().getInt(EVENT, getOffset()) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ARS User Id
|
||||
* @return user or null
|
||||
*/
|
||||
public ARSUser getUser()
|
||||
{
|
||||
return mUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has a user Id
|
||||
*/
|
||||
public boolean hasUser()
|
||||
{
|
||||
return mUser != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ARS Password
|
||||
* @return password or null
|
||||
*/
|
||||
public ARSPassword getPassword()
|
||||
{
|
||||
return mPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has a password
|
||||
*/
|
||||
public boolean hasPassword()
|
||||
{
|
||||
return mPassword != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ARS Device
|
||||
* @return device or null
|
||||
*/
|
||||
public ARSDevice getDevice()
|
||||
{
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has a device Id
|
||||
*/
|
||||
public boolean hasDevice()
|
||||
{
|
||||
return mDevice != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Device, user and password values contained in the registration packet.
|
||||
*/
|
||||
public String getPayload()
|
||||
private void parsePayload()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DEVICE:");
|
||||
|
||||
int pointer = getOffset();
|
||||
|
||||
if(hasHeaderExtension())
|
||||
@@ -91,53 +172,62 @@ public class DeviceRegistration extends ARSHeader
|
||||
pointer += DEVICE_IDENTIFIER_START;
|
||||
}
|
||||
|
||||
int identifierSize = getMessage().getInt(BYTE_VALUE, pointer += 8);
|
||||
int deviceIdentifierSize = getMessage().getInt(BYTE_VALUE, pointer);
|
||||
|
||||
if(identifierSize > 0)
|
||||
pointer += 8;
|
||||
|
||||
if(deviceIdentifierSize > 0)
|
||||
{
|
||||
for(int x = 0; x < identifierSize; x++)
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for(int x = 0; x < deviceIdentifierSize; x++)
|
||||
{
|
||||
sb.append(getCharacter(pointer += 8));
|
||||
sb.append(getCharacter(pointer));
|
||||
pointer += 8;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int device = Integer.parseInt(sb.toString());
|
||||
mDevice = ARSDevice.createFrom(device);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error parsing ARS device identifier from value [" + sb.toString() + "]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(none)");
|
||||
}
|
||||
|
||||
sb.append(" USER:");
|
||||
|
||||
int userIdentifierSize = getMessage().getInt(BYTE_VALUE, pointer += 8);
|
||||
int userIdentifierSize = getMessage().getInt(BYTE_VALUE, pointer);
|
||||
pointer += 8;
|
||||
|
||||
if(userIdentifierSize > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for(int x = 0; x < userIdentifierSize; x++)
|
||||
{
|
||||
sb.append(getCharacter(pointer += 8));
|
||||
sb.append(getCharacter(pointer));
|
||||
pointer += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(none)");
|
||||
|
||||
mUser = ARSUser.createFrom(sb.toString());
|
||||
}
|
||||
|
||||
sb.append(" PASSWORD:");
|
||||
|
||||
int passwordSize = getMessage().getInt(BYTE_VALUE, pointer += 8);
|
||||
int passwordSize = getMessage().getInt(BYTE_VALUE, pointer);
|
||||
pointer += 8;
|
||||
|
||||
if(passwordSize > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for(int x = 0; x < passwordSize; x++)
|
||||
{
|
||||
sb.append(getCharacter(pointer += 8));
|
||||
sb.append(getCharacter(pointer));
|
||||
pointer += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(none)");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
mPassword = ARSPassword.createFrom(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,4 +240,30 @@ public class DeviceRegistration extends ARSHeader
|
||||
{
|
||||
return (char)getMessage().getByte(BYTE_VALUE, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
if(mIdentifiers == null)
|
||||
{
|
||||
mIdentifiers = new ArrayList<>();
|
||||
|
||||
if(hasUser())
|
||||
{
|
||||
mIdentifiers.add(getUser());
|
||||
}
|
||||
|
||||
if(hasDevice())
|
||||
{
|
||||
mIdentifiers.add(getDevice());
|
||||
}
|
||||
|
||||
if(hasPassword())
|
||||
{
|
||||
mIdentifiers.add(getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
return mIdentifiers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class QueryMessage extends ARSHeader
|
||||
{
|
||||
@@ -41,4 +45,10 @@ public class QueryMessage extends ARSHeader
|
||||
sb.append("ARS QUERY MESSAGE");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class RegistrationAcknowledgement extends ARSHeader
|
||||
{
|
||||
@@ -93,4 +97,10 @@ public class RegistrationAcknowledgement extends ARSHeader
|
||||
{
|
||||
return getMessage().getInt(TIMER_OR_REASON, getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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
|
||||
@@ -15,14 +14,21 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
public class DeviceRegistrationAcknowledge extends ARSHeader
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unknown ARS Header
|
||||
*/
|
||||
public class UnknownARSHeader extends ARSHeader
|
||||
{
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
@@ -30,7 +36,7 @@ public class DeviceRegistrationAcknowledge extends ARSHeader
|
||||
* @param message containing the header
|
||||
* @param offset to the header within the message
|
||||
*/
|
||||
public DeviceRegistrationAcknowledge(BinaryMessage message, int offset)
|
||||
public UnknownARSHeader(BinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
@@ -38,7 +44,15 @@ public class DeviceRegistrationAcknowledge extends ARSHeader
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DEVICE REGISTRATION ACKNOWLEDGED");
|
||||
sb.append("*UNKNOWN* ").append(getPDUType());
|
||||
sb.append(" PACKET:").append(getMessage().toHexString());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,14 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Automatic Registration Service - User De-Registration
|
||||
*/
|
||||
public class UserDeRegistration extends ARSHeader
|
||||
{
|
||||
/**
|
||||
@@ -38,7 +45,13 @@ public class UserDeRegistration extends ARSHeader
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("ARS USER DE-REGISTRATION");
|
||||
sb.append("USER DE-REGISTRATION");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class UserDeRegistrationAcknowledge extends ARSHeader
|
||||
{
|
||||
@@ -38,7 +42,13 @@ public class UserDeRegistrationAcknowledge extends ARSHeader
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("ARS USER DE-REGISTRATION ACKNOWLEDGED");
|
||||
sb.append("USER DE-REGISTRATION ACKNOWLEDGED");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,19 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.ars.identifier.ARSDevice;
|
||||
import io.github.dsheirer.module.decode.ip.ars.identifier.ARSPassword;
|
||||
import io.github.dsheirer.module.decode.ip.ars.identifier.ARSUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UserRegistration extends ARSHeader
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(UserRegistration.class);
|
||||
private static final int HEADER_EXTENSION_FLAG = 24;
|
||||
private static final int[] EVENT = {25, 26};
|
||||
private static final int[] ENCODING = {27, 28, 29, 30, 31};
|
||||
@@ -32,6 +42,11 @@ public class UserRegistration extends ARSHeader
|
||||
|
||||
private static final int[] BYTE_VALUE = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
private ARSDevice mDevice;
|
||||
private ARSUser mUser;
|
||||
private ARSPassword mPassword;
|
||||
private List<Identifier> mIdentifiers;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
@@ -41,6 +56,7 @@ public class UserRegistration extends ARSHeader
|
||||
public UserRegistration(BinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
parsePayload();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
@@ -50,7 +66,20 @@ public class UserRegistration extends ARSHeader
|
||||
|
||||
if(isValid())
|
||||
{
|
||||
sb.append(" ").append(getPayload());
|
||||
if(hasDevice())
|
||||
{
|
||||
sb.append(" DEVICE:").append(getDevice());
|
||||
}
|
||||
|
||||
if(hasUser())
|
||||
{
|
||||
sb.append(" USER:").append(getUser());
|
||||
}
|
||||
|
||||
if(hasPassword())
|
||||
{
|
||||
sb.append(" PW:").append(getPassword());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -62,11 +91,8 @@ public class UserRegistration extends ARSHeader
|
||||
/**
|
||||
* Device, user and password values contained in the registration packet.
|
||||
*/
|
||||
public String getPayload()
|
||||
private void parsePayload()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DEVICE:");
|
||||
|
||||
int pointer = getOffset();
|
||||
|
||||
if(hasHeaderExtension())
|
||||
@@ -78,53 +104,114 @@ public class UserRegistration extends ARSHeader
|
||||
pointer += DEVICE_IDENTIFIER_START;
|
||||
}
|
||||
|
||||
int identifierSize = getMessage().getInt(BYTE_VALUE, pointer += 8);
|
||||
int deviceIdentifierSize = getMessage().getInt(BYTE_VALUE, pointer);
|
||||
|
||||
if(identifierSize > 0)
|
||||
pointer += 8;
|
||||
|
||||
if(deviceIdentifierSize > 0)
|
||||
{
|
||||
for(int x = 0; x < identifierSize; x++)
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for(int x = 0; x < deviceIdentifierSize; x++)
|
||||
{
|
||||
sb.append(getCharacter(pointer += 8));
|
||||
sb.append(getCharacter(pointer));
|
||||
pointer += 8;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int device = Integer.parseInt(sb.toString());
|
||||
mDevice = ARSDevice.createFrom(device);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Abort processing
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(none)");
|
||||
}
|
||||
|
||||
sb.append(" USER:");
|
||||
|
||||
int userIdentifierSize = getMessage().getInt(BYTE_VALUE, pointer += 8);
|
||||
int userIdentifierSize = getMessage().getInt(BYTE_VALUE, pointer);
|
||||
pointer += 8;
|
||||
|
||||
if(userIdentifierSize > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for(int x = 0; x < userIdentifierSize; x++)
|
||||
{
|
||||
sb.append(getCharacter(pointer += 8));
|
||||
sb.append(getCharacter(pointer));
|
||||
pointer += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(none)");
|
||||
|
||||
mUser = ARSUser.createFrom(sb.toString());
|
||||
}
|
||||
|
||||
sb.append(" PASSWORD:");
|
||||
|
||||
int passwordSize = getMessage().getInt(BYTE_VALUE, pointer += 8);
|
||||
int passwordSize = getMessage().getInt(BYTE_VALUE, pointer);
|
||||
pointer += 8;
|
||||
|
||||
if(passwordSize > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for(int x = 0; x < passwordSize; x++)
|
||||
{
|
||||
sb.append(getCharacter(pointer += 8));
|
||||
sb.append(getCharacter(pointer));
|
||||
pointer += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(none)");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
mPassword = ARSPassword.createFrom(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ARS User Id
|
||||
* @return user or null
|
||||
*/
|
||||
public ARSUser getUser()
|
||||
{
|
||||
return mUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has a user Id
|
||||
*/
|
||||
public boolean hasUser()
|
||||
{
|
||||
return mUser != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ARS Password
|
||||
* @return password or null
|
||||
*/
|
||||
public ARSPassword getPassword()
|
||||
{
|
||||
return mPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has a password
|
||||
*/
|
||||
public boolean hasPassword()
|
||||
{
|
||||
return mPassword != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ARS Device
|
||||
* @return device or null
|
||||
*/
|
||||
public ARSDevice getDevice()
|
||||
{
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has a device Id
|
||||
*/
|
||||
public boolean hasDevice()
|
||||
{
|
||||
return mDevice != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,4 +224,30 @@ public class UserRegistration extends ARSHeader
|
||||
{
|
||||
return (char)getMessage().getByte(BYTE_VALUE, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
if(mIdentifiers == null)
|
||||
{
|
||||
mIdentifiers = new ArrayList<>();
|
||||
|
||||
if(hasUser())
|
||||
{
|
||||
mIdentifiers.add(getUser());
|
||||
}
|
||||
|
||||
if(hasDevice())
|
||||
{
|
||||
mIdentifiers.add(getDevice());
|
||||
}
|
||||
|
||||
if(hasPassword())
|
||||
{
|
||||
mIdentifiers.add(getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
return mIdentifiers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
package io.github.dsheirer.module.decode.ip.ars;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class UserRegistrationAcknowledge extends ARSHeader
|
||||
{
|
||||
@@ -85,4 +89,10 @@ public class UserRegistrationAcknowledge extends ARSHeader
|
||||
|
||||
return "NONE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.ars.identifier;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.integer.IntegerIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* Automatic Registration Service - Device Identifier
|
||||
*/
|
||||
public class ARSDevice extends IntegerIdentifier
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param value of the device identifier
|
||||
* @param role of the device (TO/FROM)
|
||||
*/
|
||||
public ARSDevice(int value, Role role)
|
||||
{
|
||||
super(value, IdentifierClass.USER, Form.ARS_DEVICE, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.ARS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARS device with a FROM role
|
||||
*/
|
||||
public static ARSDevice createFrom(int value)
|
||||
{
|
||||
return new ARSDevice(value, Role.FROM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARS device with a TO role
|
||||
*/
|
||||
public static ARSDevice createTo(int value)
|
||||
{
|
||||
return new ARSDevice(value, Role.TO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.ars.identifier;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.string.StringIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* Automatic Registration Service - User Password
|
||||
*/
|
||||
public class ARSPassword extends StringIdentifier
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param value of the password
|
||||
* @param role of the password (TO/FROM)
|
||||
*/
|
||||
public ARSPassword(String value, Role role)
|
||||
{
|
||||
super(value, IdentifierClass.USER, Form.ARS_USER, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.ARS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARS password with a FROM role
|
||||
*/
|
||||
public static ARSPassword createFrom(String value)
|
||||
{
|
||||
return new ARSPassword(value, Role.FROM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARS password with a TO role
|
||||
*/
|
||||
public static ARSPassword createTo(String value)
|
||||
{
|
||||
return new ARSPassword(value, Role.TO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.ars.identifier;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.string.StringIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* Automatic Registration Service - User Identifier
|
||||
*/
|
||||
public class ARSUser extends StringIdentifier
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param value of the user
|
||||
* @param role of the user (TO/FROM)
|
||||
*/
|
||||
public ARSUser(String value, Role role)
|
||||
{
|
||||
super(value, IdentifierClass.USER, Form.ARS_USER, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.ARS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARS user with a FROM role
|
||||
*/
|
||||
public static ARSUser createFrom(String value)
|
||||
{
|
||||
return new ARSUser(value, Role.FROM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARS user with a TO role
|
||||
*/
|
||||
public static ARSUser createTo(String value)
|
||||
{
|
||||
return new ARSUser(value, Role.TO);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@@ -62,7 +62,7 @@ public class AcknowledgeMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public AcknowledgeMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public AcknowledgeMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Unit (Outbound) data being forwarded over the wireless interface to a central application
|
||||
@@ -46,7 +46,7 @@ public class ForwardedDataMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ForwardedDataMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public ForwardedDataMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Controller (Inbound) Generic Command
|
||||
@@ -44,7 +44,7 @@ public class GenericCommandMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public GenericCommandMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public GenericCommandMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
|
||||
/**
|
||||
* Unit (Outbound) Status and Location
|
||||
@@ -101,7 +102,7 @@ public class LocationStatusMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public LocationStatusMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public LocationStatusMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Creates an MCGP packet and header for parsing the contents of the packet.
|
||||
@@ -33,7 +33,7 @@ public class MCGPMessageFactory
|
||||
* @param offset into the message for the start of the MCGP payload
|
||||
* @return MCGP packet message parser
|
||||
*/
|
||||
public static MCGPPacket create(BinaryMessage message, int offset)
|
||||
public static MCGPPacket create(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
MCGPHeader header = new MCGPHeader(message, offset);
|
||||
int payloadOffset = offset + MCGPHeader.HEADER_LENGTH;
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -41,7 +42,7 @@ public abstract class MCGPPacket extends Packet
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public MCGPPacket(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public MCGPPacket(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
mHeader = header;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Inbound (from Controller) Modular Request Message
|
||||
@@ -44,7 +45,7 @@ public class ModularRequestMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ModularRequestMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public ModularRequestMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Modular Message
|
||||
@@ -47,7 +48,7 @@ public class ModularResponseMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ModularResponseMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public ModularResponseMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -48,7 +48,7 @@ public class ProgrammingCommandMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ProgrammingCommandMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public ProgrammingCommandMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Unit (Outbound) Programming Status/Response
|
||||
@@ -47,7 +47,7 @@ public class ProgrammingStatusMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ProgrammingStatusMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public ProgrammingStatusMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.cellocator;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.UnknownPacket;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class UnknownMCGPMessage extends MCGPPacket
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public UnknownMCGPMessage(MCGPHeader header, BinaryMessage message, int offset)
|
||||
public UnknownMCGPMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(header, message, offset);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 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 <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.icmp;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.module.decode.ip.Header;
|
||||
|
||||
/**
|
||||
* Internet Control Message Protocol (ICMP) Header
|
||||
*/
|
||||
public class ICMPHeader extends Header
|
||||
{
|
||||
private static final int[] TYPE = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
private static final int[] CODE = {8, 9, 10, 11, 12, 13, 14, 15};
|
||||
private static final int[] TYPE_CODE = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the header
|
||||
* @param offset to the header within the message
|
||||
*/
|
||||
public ICMPHeader(BinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
checkValid();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
ICMPTypeCode typeCode = getTypeCode();
|
||||
|
||||
if(typeCode != ICMPTypeCode.UNKNOWN)
|
||||
{
|
||||
sb.append("ICMP ").append(typeCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("ICMP UNKNOWN TYPE CODE:").append(getTypeCodeValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ICMPTypeCode getTypeCode()
|
||||
{
|
||||
return ICMPTypeCode.fromValue(getTypeCodeValue());
|
||||
}
|
||||
|
||||
public int getTypeCodeValue()
|
||||
{
|
||||
return getMessage().getInt(TYPE_CODE, getOffset());
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return getMessage().getInt(TYPE, getOffset());
|
||||
}
|
||||
|
||||
public int getCode()
|
||||
{
|
||||
return getMessage().getInt(CODE, getOffset());
|
||||
}
|
||||
|
||||
private void checkValid()
|
||||
{
|
||||
setValid(getMessage().size() >= getOffset() + getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 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 <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.icmp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
import io.github.dsheirer.module.decode.ip.PacketMessageFactory;
|
||||
import io.github.dsheirer.module.decode.ip.UnknownPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Internet Control Message Protocol (ICMP) Packet
|
||||
*/
|
||||
public class ICMPPacket extends Packet
|
||||
{
|
||||
private ICMPHeader mHeader;
|
||||
private IPacket mPayload;
|
||||
private List<Identifier> mIdentifiers;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public ICMPPacket(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if(getHeader().isValid())
|
||||
{
|
||||
sb.append(getHeader());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("INVALID HEADER");
|
||||
}
|
||||
|
||||
sb.append(" PACKET:").append(getPayload());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICMPHeader getHeader()
|
||||
{
|
||||
if(mHeader == null)
|
||||
{
|
||||
mHeader = new ICMPHeader(getMessage(), getOffset());
|
||||
}
|
||||
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket getPayload()
|
||||
{
|
||||
if(mPayload == null && getHeader().isValid())
|
||||
{
|
||||
if(getHeader().isValid())
|
||||
{
|
||||
int offset = getOffset();
|
||||
int headerLength = getHeader().getLength();
|
||||
int totalOffset = offset + headerLength;
|
||||
mPayload = PacketMessageFactory.create(getMessage(), getOffset() + getHeader().getLength());
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set the offset to the message offset plus 64 bits for UDP header
|
||||
mPayload = new UnknownPacket(getMessage(), getOffset() + getHeader().getLength());
|
||||
}
|
||||
}
|
||||
|
||||
return mPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
if(mIdentifiers == null)
|
||||
{
|
||||
mIdentifiers = new ArrayList<>();
|
||||
|
||||
//Roll up the identifiers from the payload packet
|
||||
if(hasPayload())
|
||||
{
|
||||
mIdentifiers.addAll(getPayload().getIdentifiers());
|
||||
}
|
||||
}
|
||||
|
||||
return mIdentifiers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.icmp;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* ICMP Type:Code enumeration
|
||||
*/
|
||||
public enum ICMPTypeCode
|
||||
{
|
||||
ECHO_REPLY(0,0,"ECHO REPLY"),
|
||||
|
||||
//Type: 3 Destination Unreachable
|
||||
DESTINATION_NETWORK_UNREACHABLE(3,0, "DESTINATION NETWORK UNREACHABLE"),
|
||||
DESTINATION_HOST_UNREACHABLE(3,1, "DESTINATION HOST UNREACHABLE"),
|
||||
DESTINATION_PROTOCOL_UNREACHABLE(3,2, "DESTINATION PROTOCOL UNREACHABLE"),
|
||||
DESTINATION_PORT_UNREACHABLE(3,3, "DESTINATION PORT UNREACHABLE"),
|
||||
FRAGMENTATION_REQUIRED(3,4, "FRAGMENTATION REQUIRED"),
|
||||
SOURCE_ROUTE_FAILED(3,5, "SOURCE ROUTE FAILED"),
|
||||
DESTINATION_NETWORK_UNKNOWN(3,6, "DESTINATION NETWORK UNKNOWN"),
|
||||
DESTINATION_HOST_UNKNOWN(3,7, "DESTINATION HOST UNKNOWN"),
|
||||
SOURCE_HOST_ISOLATED(3,8, "SOURCE HOST ISOLATED"),
|
||||
NETWORK_ADMINISTRATIVELY_PROHIBITED(3,9, "NETWORK ADMINISTRATIVELY PROHIBITED"),
|
||||
HOST_ADMINISTRATIVELY_PROHIBITED(3,10, "HOST ADMINISTRATIVELY PROHIBITED"),
|
||||
NETWORK_UNREACHABLE_FOR_TOS(3,11, "NETWORK UNREACHABLE FOR TOS"),
|
||||
HOST_UNREACHABLE_FOR_TOS(3,12, "HOST UNREACHABLE FOR TOS"),
|
||||
COMMUNICATION_ADMINISTRATIVELY_PROHIBITED(3,13, "COMMUNICATION ADMINISTRATIVELY PROHIBITED"),
|
||||
HOST_PRECEDENCE_VIOLATION(3,14, "HOST PRECEDENCE VIOLATION"),
|
||||
PRECEDENCE_CUTOFF_IN_EFFECT(3,15, "PRECEDENCE CUTOFF IN EFFECT"),
|
||||
|
||||
//Type: 5 Redirect Message
|
||||
REDIRECT_DATAGRAM_FOR_THE_NETWORK(5,0, "REDIRECT DATAGRAM FOR THE NETWORK"),
|
||||
REDIRECT_DATAGRAM_FOR_THE_HOST(5,1, "REDIRECT DATAGRAM FOR THE HOST"),
|
||||
REDIRECT_DATAGRAM_FOR_THE_TOS_AND_NETWORK(5,2, "REDIRECT DATAGRAM FOR THE TOS & NETWORK"),
|
||||
REDIRECT_DATAGRAM_FOR_THE_TOS_AND_HOST(5,3, "REDIRECT DATAGRAM FOR THE TOS & HOST"),
|
||||
|
||||
//Type: 8 Echo Request
|
||||
ECHO_REQUEST(8,0, "ECHO REQUEST"),
|
||||
|
||||
//Type: 9 Router Advertisement
|
||||
ROUTER_ADVERTISEMENT(9, 0, "ROUTER ADVERTISEMENT"),
|
||||
|
||||
//Type: 10 Router Solicitation
|
||||
ROUTER_SOLICITATION(10,0,"ROUTER SOLICITATION"),
|
||||
|
||||
//Type: 11 Time Exceeded
|
||||
TTL_EXPIRED_IN_TRANSIT(11, 0, "TTL EXPIRED IN TRANSIT"),
|
||||
FRAGMENT_REASSEMBLY_TIME_EXCEEDED(11, 1, "FRAGMENT REASSEMBLY TIME EXCEEDED"),
|
||||
|
||||
//Type: 12 Bad IP Header
|
||||
IP_HEADER_ERROR_POINTER(12, 0, "IP HEADER ERROR - POINTER INDICATES ERROR"),
|
||||
IP_HEADER_ERROR_MISSING_OPTION(12,1,"IP HEADER ERROR - MISSING REQUIRED OPTION"),
|
||||
IP_HEADER_ERROR_BAD_LENGTH(12,2,"IP HEADER ERROR - BAD LENGTH"),
|
||||
|
||||
//Type: 13 Timestamp
|
||||
TIMESTAMP(13, 0, "TIMESTAMP"),
|
||||
|
||||
//Type: 14 Timestamp Reply
|
||||
TIMESTAMP_REPLY(14, 0, "TIMESTAMP REPLY"),
|
||||
|
||||
//Type: 42 Extended Echo Request
|
||||
EXTENDED_ECHO_REQUEST(42, 0, "EXTENDED ECHO REQUEST"),
|
||||
|
||||
//Type: 43 Extended Echo Reply
|
||||
EXTENDED_ECHO_REPLY_NO_ERROR(43, 0, "EXTENDED ECHO - NO ERROR"),
|
||||
EXTENDED_ECHO_REPLY_MALFORMED_QUERY(43, 1, "EXTENDED ECHO - MALFORMED QUERY"),
|
||||
EXTENDED_ECHO_REPLY_NO_INTERFACE(43, 2, "EXTENDED ECHO - NO SUCH INTERFACE"),
|
||||
EXTENDED_ECHO_REPLY_NO_TABLE(43, 3, "EXTENDED ECHO - NO SUCH TABLE ENTRY"),
|
||||
EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES(43, 4, "EXTENDED ECHO - MULTIPLE INTERFACES"),
|
||||
|
||||
UNKNOWN(-1, -1, "UNKNOWN");
|
||||
|
||||
private int mValue;
|
||||
private String mLabel;
|
||||
|
||||
ICMPTypeCode(int type, int code, String label)
|
||||
{
|
||||
mValue = (type << 8) + code;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
private static final Map<Integer,ICMPTypeCode> LOOKUP_MAP = new TreeMap<>();
|
||||
|
||||
static
|
||||
{
|
||||
for(ICMPTypeCode type: ICMPTypeCode.values())
|
||||
{
|
||||
LOOKUP_MAP.put(type.getValue(), type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to lookup the ICMP type:code entry from the combined 16-bit value form the ICMP header
|
||||
* @param value to lookup
|
||||
* @return entry or UNKNOWN
|
||||
*/
|
||||
public static ICMPTypeCode fromValue(int value)
|
||||
{
|
||||
if(LOOKUP_MAP.containsKey(value))
|
||||
{
|
||||
return LOOKUP_MAP.get(value);
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* 16-bit value that is the type and code bytes combined.
|
||||
*/
|
||||
public int getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
@@ -73,11 +73,11 @@ public class IPV4Header extends Header
|
||||
return;
|
||||
}
|
||||
|
||||
if(getMessage().size() < totalLength + getOffset())
|
||||
{
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
// if(getMessage().size() < totalLength + getOffset())
|
||||
// {
|
||||
// setValid(false);
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.ipv4;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
import io.github.dsheirer.module.decode.ip.PacketMessageFactory;
|
||||
import io.github.dsheirer.module.decode.ip.UnknownPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,7 +45,7 @@ public class IPV4Packet extends Packet
|
||||
* @param message containing an IPV4 packet
|
||||
* @param offset to the start of the packet within the binary message
|
||||
*/
|
||||
public IPV4Packet(BinaryMessage message, int offset)
|
||||
public IPV4Packet(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
@@ -120,14 +121,14 @@ public class IPV4Packet extends Packet
|
||||
if(mIdentifiers == null)
|
||||
{
|
||||
mIdentifiers = new ArrayList<>();
|
||||
mIdentifiers.add(getHeader().getFromAddress());
|
||||
mIdentifiers.add(getHeader().getToAddress());
|
||||
|
||||
//Roll up the identifiers from the payload packet
|
||||
if(hasPayload())
|
||||
{
|
||||
mIdentifiers.addAll(getPayload().getIdentifiers());
|
||||
}
|
||||
|
||||
mIdentifiers.add(getHeader().getToAddress());
|
||||
mIdentifiers.add(getHeader().getFromAddress());
|
||||
}
|
||||
|
||||
return mIdentifiers;
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.Header;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Location Request/Response Protocol (LRRP) Header
|
||||
*/
|
||||
public class LRRPHeader extends Header
|
||||
{
|
||||
private static final int[] TYPE = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
private static final int[] LENGTH = {8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the header
|
||||
* @param offset to the header within the message
|
||||
*/
|
||||
public LRRPHeader(BinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the underlying message is long enough to contain the PDU
|
||||
*/
|
||||
private void checkValid()
|
||||
{
|
||||
setValid(getMessage().size() >= (getOffset() + getLength() + getPayloadLength()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of the payload in 8-bit characters
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getPayloadLength()
|
||||
{
|
||||
return getMessage().getInt(LENGTH, getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of this header in bits
|
||||
*
|
||||
* Note this length value includes the first 2 bytes of the message that indicates the overall
|
||||
* message length and the length of the PDU header byte(s).
|
||||
*
|
||||
* This method may need to be overridden if there is more than 1 extension header in a PDU.
|
||||
*/
|
||||
@Override
|
||||
public int getLength()
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifiers for this packet
|
||||
*/
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
import io.github.dsheirer.module.decode.ip.lrrp.token.Token;
|
||||
import io.github.dsheirer.module.decode.ip.lrrp.token.TokenFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Location Request/Response Protocol (LRRP) Packet
|
||||
*/
|
||||
public class LRRPPacket extends Packet
|
||||
{
|
||||
//Constant for parsing a hexadecimal byte token identifier
|
||||
private static final int[] BYTE_VALUE = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
public static final int TOKEN_START = 16;
|
||||
|
||||
private LRRPHeader mHeader;
|
||||
private List<Token> mTokens;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public LRRPPacket(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("LRRP");
|
||||
|
||||
for(Token token: getTokens())
|
||||
{
|
||||
sb.append(" ").append(token);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LRRPHeader getHeader()
|
||||
{
|
||||
if(mHeader == null)
|
||||
{
|
||||
mHeader = new LRRPHeader(getMessage(), getOffset());
|
||||
}
|
||||
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of LRRP tokens parsed from the packet
|
||||
*/
|
||||
public List<Token> getTokens()
|
||||
{
|
||||
parseTokens();
|
||||
return mTokens;
|
||||
}
|
||||
|
||||
private void parseTokens()
|
||||
{
|
||||
if(mTokens == null)
|
||||
{
|
||||
mTokens = new ArrayList<>();
|
||||
|
||||
int characterCount = getHeader().getPayloadLength();
|
||||
int offset = getOffset() + TOKEN_START;
|
||||
|
||||
while(characterCount > 0 && offset < getMessage().size())
|
||||
{
|
||||
String tokenId = getTokenIdentifier(offset);
|
||||
Token token = TokenFactory.createToken(tokenId, getMessage(), offset, characterCount);
|
||||
mTokens.add(token);
|
||||
int length = token.getByteLength();
|
||||
characterCount -= token.getByteLength();
|
||||
offset += (8 * token.getByteLength());
|
||||
}
|
||||
|
||||
Collections.sort(mTokens, (o1, o2) -> o1.getTokenType().compareTo(o2.getTokenType()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string hexadecimal value of the 8-bit value that starts at the specified offset.
|
||||
*/
|
||||
private String getTokenIdentifier(int offset)
|
||||
{
|
||||
int id = getMessage().getInt(BYTE_VALUE, offset);
|
||||
return String.format("%02X", id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket getPayload()
|
||||
{
|
||||
//The payload is a sequence of tokens. There is no packet payload.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return getHeader().getIdentifiers();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Heading Token
|
||||
*
|
||||
* Start Token: 0x56
|
||||
* Total Length: 2 bytes
|
||||
*/
|
||||
public class Heading extends Token
|
||||
{
|
||||
private static final int[] HEADING = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
/**
|
||||
* Constructs an instance of a heading token.
|
||||
*
|
||||
* @param message containing the heading
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Heading(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.HEADING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Heading degrees relative to true North
|
||||
*/
|
||||
public long getHeading()
|
||||
{
|
||||
return getMessage().getInt(HEADING, getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "HEADING:" + getHeading();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Identity Token
|
||||
*
|
||||
* Start Token: 0x22
|
||||
* Total Length: 6 bytes
|
||||
*/
|
||||
public class Identity extends Token
|
||||
{
|
||||
private static final int IDENTIFIER_START = 16;
|
||||
private static final int[] BYTE_VALUE = new int[]{0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
/**
|
||||
* Constructs an instance of a heading token.
|
||||
*
|
||||
* @param message containing the heading
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Identity(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.IDENTITY;
|
||||
}
|
||||
|
||||
private BinaryMessage getTokenContents()
|
||||
{
|
||||
return getMessage().getSubMessage(getOffset(), getOffset() + 48);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the payload contents.
|
||||
*
|
||||
* Note: assumes that the values are 1-4 bytes in big-endian format? Not sure if this is correct because the
|
||||
* values that I observed only had value in the LSB and the 3 MSBs were all zeros.
|
||||
*/
|
||||
public int getID()
|
||||
{
|
||||
int length = getVariableLengthPayloadSize();
|
||||
int payloadOffset = 16;
|
||||
int value = 0;
|
||||
|
||||
while(0 < length && length <= 4)
|
||||
{
|
||||
int byteValue = getMessage().getInt(BYTE_VALUE, getOffset() + payloadOffset);
|
||||
|
||||
byteValue = Integer.rotateLeft(byteValue, payloadOffset - 16);
|
||||
value += byteValue;
|
||||
payloadOffset += 8;
|
||||
length--;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int id = getID();
|
||||
|
||||
if(id != 0)
|
||||
{
|
||||
return "ID:" + id;
|
||||
}
|
||||
|
||||
return "ID:" + getTokenContents().toHexString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.location.LocationIdentifier;
|
||||
import io.github.dsheirer.identifier.location.Point;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* LRRP Position/Location
|
||||
*/
|
||||
public class LRRPPosition extends LocationIdentifier
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
*
|
||||
* @param value location
|
||||
* @param role to or from
|
||||
*/
|
||||
public LRRPPosition(Point value, Role role)
|
||||
{
|
||||
super(value, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.LRRP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a FROM position
|
||||
*/
|
||||
public static LRRPPosition createFrom(double latitude, double longitude)
|
||||
{
|
||||
return new LRRPPosition(new Point(latitude, longitude), Role.FROM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TO position
|
||||
*/
|
||||
public static LRRPPosition createTo(double latitude, double longitude)
|
||||
{
|
||||
return new LRRPPosition(new Point(latitude, longitude), Role.TO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Position Token
|
||||
*
|
||||
* Start Token: 0x66
|
||||
* Total Length: 9 bytes
|
||||
*/
|
||||
public class Position extends Token
|
||||
{
|
||||
private static final int[] LATITUDE = new int[]{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
|
||||
private static final int[] LONGITUDE = new int[]{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};
|
||||
|
||||
private static final double LATITUDE_MULTIPLIER = 180.0 / 4294967295.0d;
|
||||
private static final double LONGITUDE_MULTIPLIER = 360.0 / 4294967295.0d;
|
||||
|
||||
private LRRPPosition mPosition;
|
||||
|
||||
/**
|
||||
* Constructs an instance of a heading token.
|
||||
*
|
||||
* @param message containing the heading
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Position(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.POSITION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position value
|
||||
*/
|
||||
public LRRPPosition getPosition()
|
||||
{
|
||||
if(mPosition == null)
|
||||
{
|
||||
mPosition = LRRPPosition.createFrom(getLatitude(), getLongitude());
|
||||
}
|
||||
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Latitude in degrees decimal
|
||||
*/
|
||||
public double getLatitude()
|
||||
{
|
||||
return getMessage().getInt(LATITUDE, getOffset()) * LATITUDE_MULTIPLIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Longitude in degrees decimal
|
||||
*/
|
||||
public double getLongitude()
|
||||
{
|
||||
return getMessage().getInt(LONGITUDE, getOffset()) * LONGITUDE_MULTIPLIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "POSITION:" + getPosition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP 3-D Position with latitude, longitude and altitude
|
||||
*/
|
||||
public class Position3D extends Position
|
||||
{
|
||||
private static final int[] ALTITUDE = new int[]{72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87};
|
||||
|
||||
/**
|
||||
* Constructs an instance of a heading token.
|
||||
*
|
||||
* @param message containing the heading
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Position3D(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.POSITION_3D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Altitude
|
||||
*
|
||||
* @return altitude in meters
|
||||
*/
|
||||
public int getAltitude()
|
||||
{
|
||||
return getMessage().getInt(ALTITUDE, getOffset());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "POSITION:" + getPosition() + " ALT:" + getAltitude() + " MTRS";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Speed Token
|
||||
*
|
||||
* Start Token: 0x6C
|
||||
* Total Length: 3 bytes
|
||||
*/
|
||||
public class Speed extends Token
|
||||
{
|
||||
private static final int[] UNKNOWN = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
|
||||
private static final int[] SPEED = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
|
||||
|
||||
/**
|
||||
* Constructs an instance of a heading token.
|
||||
*
|
||||
* @param message containing the heading
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Speed(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.SPEED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Speed in kilometers per hour (kph)
|
||||
*/
|
||||
public long getSpeed()
|
||||
{
|
||||
return getMessage().getInt(SPEED, getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "SPEED:" + getSpeed() + " KPH";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* LRRP Timestamp Token
|
||||
*
|
||||
* Start Token: 0x34
|
||||
* Total Length: 6 bytes
|
||||
*/
|
||||
public class Timestamp extends Token
|
||||
{
|
||||
private static final int[] YEAR = new int[]{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
|
||||
private static final int[] MONTH = new int[]{22, 23, 24, 25};
|
||||
private static final int[] DAY = new int[]{26, 27, 28, 29, 30};
|
||||
private static final int[] HOUR = new int[]{31, 32, 33, 34, 35};
|
||||
private static final int[] MINUTE = new int[]{36, 37, 38, 39, 40, 41};
|
||||
private static final int[] SECOND = new int[]{42, 43, 44, 45, 46, 47};
|
||||
|
||||
/**
|
||||
* Constructs an instance of a timestamp token.
|
||||
*
|
||||
* @param message containing the timestamp
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Timestamp(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp value in milliseconds
|
||||
*/
|
||||
public long getTimestamp()
|
||||
{
|
||||
int year = getMessage().getInt(YEAR, getOffset());
|
||||
int month = getMessage().getInt(MONTH, getOffset()) - 1;
|
||||
int day = getMessage().getInt(DAY, getOffset());
|
||||
int hour = getMessage().getInt(HOUR, getOffset());
|
||||
int minute = getMessage().getInt(MINUTE, getOffset());
|
||||
int second = getMessage().getInt(SECOND, getOffset());
|
||||
|
||||
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.set(year, month, day, hour, minute, second);
|
||||
return calendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TIME:" + new Date(getTimestamp()).toString().toUpperCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Token.
|
||||
*
|
||||
* LRRP packets are composed of a sequence of tokens that makeup a set of values for the LRRP report.
|
||||
*/
|
||||
public abstract class Token
|
||||
{
|
||||
/**
|
||||
* Length field for a variable length token
|
||||
*/
|
||||
private static final int[] VARIABLE_LENGTH_BYTE_COUNT = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
private CorrectedBinaryMessage mMessage;
|
||||
private int mOffset;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*
|
||||
* @param message containing the token and value
|
||||
* @param offset to the start of the token identifier
|
||||
*/
|
||||
public Token(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
mMessage = message;
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message that contains this token and value.
|
||||
*/
|
||||
protected CorrectedBinaryMessage getMessage()
|
||||
{
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to the start of the token identifier within the message
|
||||
*
|
||||
* @return bit offset value
|
||||
*/
|
||||
protected int getOffset()
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of token and value
|
||||
*/
|
||||
public abstract TokenType getTokenType();
|
||||
|
||||
/**
|
||||
* Token payload byte length for variable length tokens.
|
||||
*/
|
||||
public int getVariableLengthPayloadSize()
|
||||
{
|
||||
return getMessage().getInt(VARIABLE_LENGTH_BYTE_COUNT, getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of bytes for this token including the token identifier
|
||||
*/
|
||||
public int getByteLength()
|
||||
{
|
||||
if(getTokenType().isVariableLength())
|
||||
{
|
||||
return getVariableLengthPayloadSize() + 2; //Variable Length Payload + Id + Length Field
|
||||
}
|
||||
else
|
||||
{
|
||||
return getTokenType().getLength() + 1; //Fixed Length Payload + Id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Token Factory
|
||||
*/
|
||||
public class TokenFactory
|
||||
{
|
||||
public static Token createToken(String id, CorrectedBinaryMessage message, int offset, int remainingCharacterCount)
|
||||
{
|
||||
TokenType tokenType = TokenType.fromValue(id);
|
||||
|
||||
switch(tokenType)
|
||||
{
|
||||
case HEADING:
|
||||
return new Heading(message, offset);
|
||||
case POSITION:
|
||||
return new Position(message, offset);
|
||||
case POSITION_3D:
|
||||
return new Position3D(message, offset);
|
||||
case SPEED:
|
||||
return new Speed(message, offset);
|
||||
case TIMESTAMP:
|
||||
return new Timestamp(message, offset);
|
||||
case IDENTITY:
|
||||
return new Identity(message, offset);
|
||||
case UNKNOWN_23:
|
||||
return new Unknown23(message, offset);
|
||||
case UNKNOWN:
|
||||
default:
|
||||
return new UnknownToken(message, offset, remainingCharacterCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* LRRP Token Types
|
||||
*
|
||||
* Variable length tokens consist of an identifier, a length indicator, and then a sequence of bytes equal in length
|
||||
* to the length indicator.
|
||||
*/
|
||||
public enum TokenType
|
||||
{
|
||||
POSITION("66", 8),
|
||||
POSITION_3D("51", 10),
|
||||
HEADING("56", 1),
|
||||
SPEED("6C", 2),
|
||||
TIMESTAMP("34", 5),
|
||||
IDENTITY("22", -1),
|
||||
UNKNOWN_23("23", 1),
|
||||
UNKNOWN("0",0);
|
||||
|
||||
private String mValue;
|
||||
private int mLength;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param value of the token
|
||||
* @param length of the token, exclusive of the identifier, where -1 indicates a variable length token.
|
||||
*/
|
||||
TokenType(String value, int length)
|
||||
{
|
||||
mValue = value;
|
||||
mLength = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* String (Numeric) value of the token
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this token is variable length.
|
||||
*/
|
||||
public boolean isVariableLength()
|
||||
{
|
||||
return mLength == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of the token value in bytes.
|
||||
* Note: byte count does not include the token byte itself.
|
||||
*/
|
||||
public int getLength()
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
private static final Map<String,TokenType> LOOKUP_MAP = new HashMap<>();
|
||||
|
||||
static
|
||||
{
|
||||
for(TokenType tokenType: TokenType.values())
|
||||
{
|
||||
LOOKUP_MAP.put(tokenType.getValue(), tokenType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a token from a 2-character string value
|
||||
* @param value that represents the token
|
||||
* @return matching token or UNKNOWN.
|
||||
*/
|
||||
public static TokenType fromValue(String value)
|
||||
{
|
||||
if(value != null && LOOKUP_MAP.containsKey(value))
|
||||
{
|
||||
return LOOKUP_MAP.get(value);
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* LRRP Unknown Token
|
||||
*
|
||||
* Start Token: 0x23
|
||||
* Total Length: 2 bytes
|
||||
*/
|
||||
public class Unknown23 extends Token
|
||||
{
|
||||
private static final int[] UNKNOWN = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
/**
|
||||
* Constructs an instance of a heading token.
|
||||
*
|
||||
* @param message containing the heading
|
||||
* @param offset to the start of the token
|
||||
*/
|
||||
public Unknown23(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.UNKNOWN_23;
|
||||
}
|
||||
|
||||
private BinaryMessage getTokenContents()
|
||||
{
|
||||
return getMessage().getSubMessage(getOffset(), getOffset() + 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "UNK:" + getTokenContents().toHexString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.lrrp.token;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
|
||||
/**
|
||||
* Unknown or Unrecognized token. This class is also used to capture the remaining character content of the token
|
||||
* string when parsing tokens from a LRRP packet, to account for the remaining token content.
|
||||
*/
|
||||
public class UnknownToken extends Token
|
||||
{
|
||||
private int mCharacterLength;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*
|
||||
* @param message containing the token and value
|
||||
* @param offset to the start of the token identifier
|
||||
*/
|
||||
public UnknownToken(CorrectedBinaryMessage message, int offset, int characterLength)
|
||||
{
|
||||
super(message, offset);
|
||||
mCharacterLength = characterLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenType getTokenType()
|
||||
{
|
||||
return TokenType.UNKNOWN;
|
||||
}
|
||||
|
||||
private BinaryMessage getTokenContents()
|
||||
{
|
||||
return getMessage().getSubMessage(getOffset(), getOffset() + (mCharacterLength * 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "UNK:" + getTokenContents().toHexString();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,9 @@ public class UDPHeader extends Header
|
||||
private static final int[] SOURCE_PORT = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
private static final int[] DESTINATION_PORT = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
||||
|
||||
private UDPPort mSourcePort;
|
||||
private UDPPort mDestinationPort;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
@@ -63,16 +66,26 @@ public class UDPHeader extends Header
|
||||
* Source UDP port number
|
||||
* @return
|
||||
*/
|
||||
public int getSourcePort()
|
||||
public UDPPort getSourcePort()
|
||||
{
|
||||
return getMessage().getInt(SOURCE_PORT, getOffset());
|
||||
if(mSourcePort == null)
|
||||
{
|
||||
mSourcePort = UDPPort.createFrom(getMessage().getInt(SOURCE_PORT, getOffset()));
|
||||
}
|
||||
|
||||
return mSourcePort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destination UDP port number
|
||||
*/
|
||||
public int getDestinationPort()
|
||||
public UDPPort getDestinationPort()
|
||||
{
|
||||
return getMessage().getInt(DESTINATION_PORT, getOffset());
|
||||
if(mDestinationPort == null)
|
||||
{
|
||||
mDestinationPort = UDPPort.createTo(getMessage().getInt(DESTINATION_PORT, getOffset()));
|
||||
}
|
||||
|
||||
return mDestinationPort;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,20 +20,21 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.udp;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
import io.github.dsheirer.module.decode.ip.PacketMessageFactory;
|
||||
import io.github.dsheirer.module.decode.ip.UnknownPacket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UDPPacket extends Packet
|
||||
{
|
||||
private UDPHeader mHeader;
|
||||
private IPacket mPayload;
|
||||
private List<Identifier> mIdentifiers;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
@@ -41,7 +42,7 @@ public class UDPPacket extends Packet
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public UDPPacket(BinaryMessage message, int offset)
|
||||
public UDPPacket(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
@@ -77,7 +78,7 @@ public class UDPPacket extends Packet
|
||||
@Override
|
||||
public IPacket getPayload()
|
||||
{
|
||||
if(mPayload == null)
|
||||
if(mPayload == null && getHeader().isValid())
|
||||
{
|
||||
if(getHeader().isValid())
|
||||
{
|
||||
@@ -97,11 +98,19 @@ public class UDPPacket extends Packet
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
if(hasPayload())
|
||||
if(mIdentifiers == null)
|
||||
{
|
||||
return getPayload().getIdentifiers();
|
||||
mIdentifiers = new ArrayList<>();
|
||||
mIdentifiers.add(getHeader().getSourcePort());
|
||||
mIdentifiers.add(getHeader().getDestinationPort());
|
||||
|
||||
//Roll up the identifiers from the payload packet
|
||||
if(hasPayload())
|
||||
{
|
||||
mIdentifiers.addAll(getPayload().getIdentifiers());
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
return mIdentifiers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.udp;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.integer.IntegerIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* UDP Port Number Identifier
|
||||
*/
|
||||
public class UDPPort extends IntegerIdentifier
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param value of the port
|
||||
* @param role of the port (TO/FROM)
|
||||
*/
|
||||
public UDPPort(int value, Role role)
|
||||
{
|
||||
super(value, IdentifierClass.NETWORK, Form.UDP_PORT, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.UDP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create a FROM port
|
||||
*/
|
||||
public static UDPPort createFrom(int value)
|
||||
{
|
||||
return new UDPPort(value, Role.FROM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create a TO port
|
||||
*/
|
||||
public static UDPPort createTo(int value)
|
||||
{
|
||||
return new UDPPort(value, Role.TO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.xcmp;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRNetwork;
|
||||
import io.github.dsheirer.module.decode.ip.IHeader;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* XCMP Transfer: Network Frequency File
|
||||
*/
|
||||
public class NetworkFrequencyFile extends Packet
|
||||
{
|
||||
private static final int[] VERSION = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
private static final int[] SEGMENT_NUMBER = new int[]{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
||||
private static final int[] SEGMENT_COUNT = new int[]{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||
private static final int[] NETWORK = new int[]{48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59};
|
||||
private static final int[] UNKNOWN = new int[]{60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79};
|
||||
private static final int REPEATER_STRUCTURE_START = 80;
|
||||
private static final int REPEATER_STRUCTURE_LENGTH = 72;
|
||||
private List<Repeater> mRepeaters;
|
||||
private DMRNetwork mNetwork;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public NetworkFrequencyFile(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("NETWORK FREQUENCY FILE VERSION:").append(getVersion());
|
||||
sb.append(" NETWORK:").append(getNetwork());
|
||||
sb.append(" SEGMENT:").append(getSegmentNumber()).append(" OF ").append(getSegmentCount());
|
||||
|
||||
List<Repeater> repeaters = getRepeaters();
|
||||
|
||||
if(repeaters.isEmpty())
|
||||
{
|
||||
sb.append(" NO REPEATER INFO");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(" ").append(Joiner.on(" | ").join(mRepeaters));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public DMRNetwork getNetwork()
|
||||
{
|
||||
if(mNetwork == null)
|
||||
{
|
||||
mNetwork = DMRNetwork.create(getMessage().getInt(NETWORK, getOffset()));
|
||||
}
|
||||
|
||||
return mNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unknown 20-bit field contents
|
||||
*/
|
||||
public String getUnknown()
|
||||
{
|
||||
return String.format("%05X", getMessage().getInt(UNKNOWN, getOffset()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Segment number for this packet
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getSegmentNumber()
|
||||
{
|
||||
return getMessage().getInt(SEGMENT_NUMBER, getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of segments contained in the complete file
|
||||
*/
|
||||
public int getSegmentCount()
|
||||
{
|
||||
return getMessage().getInt(SEGMENT_COUNT, getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* List of repeater structures parsed from the Network Information File segment
|
||||
*/
|
||||
public List<Repeater> getRepeaters()
|
||||
{
|
||||
if(mRepeaters == null)
|
||||
{
|
||||
mRepeaters = new ArrayList<>();
|
||||
|
||||
int offset = getOffset() + REPEATER_STRUCTURE_START;
|
||||
|
||||
for(int x = 0; x < 15; x++)
|
||||
{
|
||||
if(offset <= getMessage().length())
|
||||
{
|
||||
Repeater repeater = new Repeater(getMessage(), offset, getNetwork());
|
||||
|
||||
if(repeater.isValid())
|
||||
{
|
||||
mRepeaters.add(repeater);
|
||||
}
|
||||
|
||||
offset += REPEATER_STRUCTURE_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mRepeaters;
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return getMessage().getInt(VERSION, getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHeader getHeader()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket getPayload()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.xcmp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRNetwork;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRSite;
|
||||
|
||||
/**
|
||||
* Repeater Structure Parser
|
||||
*/
|
||||
public class Repeater
|
||||
{
|
||||
private static int[] SITE = new int[]{0, 1, 2, 3, 4, 5, 6, 7};
|
||||
private static int[] REPEATER_ID = new int[]{8, 9, 10, 11};
|
||||
private static int CONTROL_CHANNEL_FLAG = 12;
|
||||
private static int[] UPLINK_FREQUENCY = new int[]{13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
||||
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
|
||||
private static int[] COLOR_CODE = new int[]{40, 41, 42, 43};
|
||||
private static int RESERVED = 44;
|
||||
private static int[] DOWNLINK_FREQUENCY = new int[]{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};
|
||||
|
||||
private CorrectedBinaryMessage mMessage;
|
||||
private int mOffset;
|
||||
private DMRNetwork mDMRNetwork;
|
||||
private DMRSite mSite;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*
|
||||
* @param message containing a repeater structure
|
||||
* @param offset into the message to where the repeater structure starts
|
||||
*/
|
||||
public Repeater(CorrectedBinaryMessage message, int offset, DMRNetwork dmrNetwork)
|
||||
{
|
||||
mMessage = message;
|
||||
mOffset = offset;
|
||||
mDMRNetwork = dmrNetwork;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("REPEATER:").append(getNetwork()).append(".").append(getSite()).append(".").append(getRepeaterNumber());
|
||||
sb.append(" CC:").append(getColorCode());
|
||||
sb.append(" DN:").append(getDownlinkFrequency() / 1E6d);
|
||||
sb.append(" UP:").append(getUplinkFrequency() / 1E6d);
|
||||
if(isControlChannel())
|
||||
{
|
||||
sb.append(" CONTROL");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public DMRNetwork getNetwork()
|
||||
{
|
||||
return mDMRNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message containing this repeater structure
|
||||
*/
|
||||
private CorrectedBinaryMessage getMessage()
|
||||
{
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset into the message where this structure starts
|
||||
*/
|
||||
private int getOffset()
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this repeater structure contains valid information
|
||||
* @return true if valid, or false if the downlink and uplink frequency values are the same.
|
||||
*/
|
||||
public boolean isValid()
|
||||
{
|
||||
return getDownlinkFrequency() != getUplinkFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Color code for the repeater
|
||||
*/
|
||||
public int getColorCode()
|
||||
{
|
||||
return getMessage().getInt(COLOR_CODE, getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeater receive / uplink frequency
|
||||
* @return frequency in Hertz
|
||||
*/
|
||||
public long getUplinkFrequency()
|
||||
{
|
||||
return getMessage().getInt(UPLINK_FREQUENCY, getOffset()) * 10l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeater transmit / downlink frequency
|
||||
* @return frequency in Hertz
|
||||
*/
|
||||
public long getDownlinkFrequency()
|
||||
{
|
||||
return getMessage().getInt(DOWNLINK_FREQUENCY, getOffset()) * 10l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this is a control channel
|
||||
*/
|
||||
public boolean isControlChannel()
|
||||
{
|
||||
return getMessage().get(CONTROL_CHANNEL_FLAG + getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeater Number/ID
|
||||
*
|
||||
* @return id as a 1-based index
|
||||
*/
|
||||
public int getRepeaterNumber()
|
||||
{
|
||||
return getMessage().getInt(REPEATER_ID, getOffset()) + 1;
|
||||
}
|
||||
|
||||
public DMRSite getSite()
|
||||
{
|
||||
if(mSite == null)
|
||||
{
|
||||
mSite = DMRSite.create(getMessage().getInt(SITE, getOffset()));
|
||||
}
|
||||
|
||||
return mSite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.xcmp;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.Header;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* EXtensible Command Message Protocol (XCMP) Header
|
||||
*/
|
||||
public class XCMPHeader extends Header
|
||||
{
|
||||
private static final int[] MESSAGE_TYPE = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the header
|
||||
* @param offset to the header within the message
|
||||
*/
|
||||
public XCMPHeader(BinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the XCMP message type from the message
|
||||
*/
|
||||
public static XCMPMessageType getMessageType(BinaryMessage message, int offset)
|
||||
{
|
||||
return XCMPMessageType.fromValue(message.getInt(MESSAGE_TYPE, offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the XCMP message type for this message
|
||||
*/
|
||||
public XCMPMessageType getMessageType()
|
||||
{
|
||||
return getMessageType(getMessage(), getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Message Type Value
|
||||
*/
|
||||
public int getMessageTypeValue()
|
||||
{
|
||||
return getMessage().getInt(MESSAGE_TYPE, getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of this header in bits
|
||||
*
|
||||
* Note this length value includes the first 2 bytes of the message that indicates the overall
|
||||
* message length and the length of the PDU header byte(s).
|
||||
*
|
||||
* This method may need to be overridden if there is more than 1 extension header in a PDU.
|
||||
*/
|
||||
@Override
|
||||
public int getLength()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifiers for this packet
|
||||
*/
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("XCMP");
|
||||
|
||||
if(getMessageType() != XCMPMessageType.UNKNOWN)
|
||||
{
|
||||
sb.append(" ").append(getMessageType());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(" UNKNOWN FILE TYPE:").append(String.format("%02X", getMessageTypeValue()));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.xcmp;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* XCMP Message Types enumeration
|
||||
*/
|
||||
public enum XCMPMessageType
|
||||
{
|
||||
NETWORK_FREQUENCY_FILE(2, "NETWORK FREQUENCY FILE"),
|
||||
UNKNOWN(-1, "UNKNOWN");
|
||||
|
||||
private int mValue;
|
||||
private String mLabel;
|
||||
|
||||
XCMPMessageType(int value, String label)
|
||||
{
|
||||
mValue = value;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeric value for the type
|
||||
*/
|
||||
public int getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
private static final Map<Integer,XCMPMessageType> LOOKUP_MAP = new TreeMap<>();
|
||||
|
||||
static
|
||||
{
|
||||
for(XCMPMessageType type: XCMPMessageType.values())
|
||||
{
|
||||
LOOKUP_MAP.put(type.getValue(), type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the XCMP Message type from the value
|
||||
*/
|
||||
public static XCMPMessageType fromValue(int value)
|
||||
{
|
||||
if(LOOKUP_MAP.containsKey(value))
|
||||
{
|
||||
return LOOKUP_MAP.get(value);
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.xcmp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.Packet;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* EXtensible Command Message Protocol (XCMP) Packet
|
||||
*/
|
||||
public class XCMPPacket extends Packet
|
||||
{
|
||||
private XCMPHeader mHeader;
|
||||
private IPacket mPayload;
|
||||
|
||||
/**
|
||||
* Constructs a parser for a header contained within a binary message starting at the offset.
|
||||
*
|
||||
* @param message containing the packet
|
||||
* @param offset to the packet within the message
|
||||
*/
|
||||
public XCMPPacket(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getHeader());
|
||||
sb.append(" ").append(getPayload());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XCMPHeader getHeader()
|
||||
{
|
||||
if(mHeader == null)
|
||||
{
|
||||
mHeader = new XCMPHeader(getMessage(), getOffset());
|
||||
}
|
||||
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket getPayload()
|
||||
{
|
||||
if(mPayload == null)
|
||||
{
|
||||
mPayload = XCMPPacketFactory.create(getMessage(), getOffset() + getHeader().getLength(),
|
||||
getHeader().getMessageType());
|
||||
}
|
||||
|
||||
return mPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return getHeader().getIdentifiers();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.ip.xcmp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.UnknownPacket;
|
||||
|
||||
public class XCMPPacketFactory
|
||||
{
|
||||
/**
|
||||
* Creates an XCMP Packet payload
|
||||
* @param message containing the full packet payload
|
||||
* @param offset to the start of the XCMP message
|
||||
* @return XCMP packet parser
|
||||
*/
|
||||
public static IPacket create(CorrectedBinaryMessage message, int offset, XCMPMessageType messageType)
|
||||
{
|
||||
switch(messageType)
|
||||
{
|
||||
case NETWORK_FREQUENCY_FILE:
|
||||
return new NetworkFrequencyFile(message, offset);
|
||||
case UNKNOWN:
|
||||
default:
|
||||
return new UnknownPacket(message, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user