package module.decode.p25.message.pdu.confirmed;
import module.decode.p25.reference.IPHeaderCompression;
import module.decode.p25.reference.IPProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SNDCPUserData extends PDUConfirmedMessage
{
public final static Logger mLog =
LoggerFactory.getLogger( SNDCPUserData.class );
public static final int DATA_BLOCK_START = 176;
public static final int[] NSAPI = { 180,181,182,183 };
public static final int[] PCOMP = { 184,185,186,187 };
public static final int[] DCOMP = { 188,189,190,191 };
/* IP Packet Header */
public static final int[] IP_VERSION = { 192,193,194,195 };
public static final int[] IHL = { 196,197,198,199 };
public static final int[] DSCP = { 200,201,202,203,204,205 };
public static final int[] ECN = { 206,207 };
public static final int[] TOTAL_LENGTH = { 208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223 };
public static final int[] IDENTIFICATION = { 224,225,226,227,228,229,230,231,
232,233,234,235,236,237,238,239 };
public static final int[] FLAGS = { 240,241,242 };
public static final int[] FRAGMENT_OFFSET = { 243,244,245,246,247,248,249,
250,251,252,253,254,255 };
public static final int[] TTL = { 256,257,258,259,260,261,262,263 };
public static final int[] PROTOCOL = { 264,265,266,267,268,269,270,271 };
public static final int[] HEADER_CHECKSUM = { 272,273,274,275,276,277,278,
279,280,281,282,283,284,285,286,287 };
public static final int[] SOURCE_IP_1 = { 288,289,290,291,292,293,294,295 };
public static final int[] SOURCE_IP_2 = { 296,297,298,299,300,301,302,303 };
public static final int[] BLOCK_SERIAL_2 = { 304,305,306,307,308,309,310 };
public static final int[] BLOCK_CRC9_2 = { 311,312,313,314,315,316,317,318,
319 };
public static final int[] SOURCE_IP_3 = { 320,321,322,323,324,325,326,327 };
public static final int[] SOURCE_IP_4 = { 328,329,330,331,332,333,334,335 };
public static final int[] DESTINATION_IP_1 = { 336,337,338,339,340,341,342,343 };
public static final int[] DESTINATION_IP_2 = { 344,345,346,347,348,349,350,351 };
public static final int[] DESTINATION_IP_3 = { 352,353,354,355,356,357,358,359 };
public static final int[] DESTINATION_IP_4 = { 360,361,362,363,364,365,366,367 };
public static final int IP_DATA_START = 368;
/* User Datagram Protocol */
public static final int[] UDP_SOURCE_PORT = { 368,369,370,371,372,373,374,
375 };
public static final int[] UDP_DESTINATION_PORT = { 376,377,378,379,380,381,
382,383 };
public static final int[] UDP_LENGTH = { 384,385,386,387,388,389,390,391,
392,393,394,395,396,397,398,399 };
public static final int[] UDP_CHECKSUM = { 400,401,402,403,404,405,406,407,
408,409,410,411,412,413,414,415 };
public static final int UDP_DATA_START = 416;
public SNDCPUserData( PDUConfirmedMessage message )
{
super( message );
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( "NAC:" );
sb.append( getNAC() );
sb.append( " PDUC LLID:" );
sb.append( getLogicalLinkID() );
sb.append( " SNDCP NSAPI:" );
sb.append( getNSAPI() );
sb.append( " " );
IPProtocol protocol = getIPProtocol();
sb.append( protocol.getLabel() );
sb.append( "/IP" );
sb.append( " FM:" );
sb.append( getSourceIPAddress() );
if( protocol == IPProtocol.UDP )
{
sb.append( ":" );
sb.append( getUDPSourcePort() );
}
sb.append( " TO:" );
sb.append( getDestinationIPAddress() );
if( protocol == IPProtocol.UDP )
{
sb.append( ":" );
sb.append( getUDPDestinationPort() );
}
sb.append( " DATA:" );
sb.append( getPayload() );
sb.append( " CRC[" );
sb.append( getErrorStatus() );
sb.append( "]" );
sb.append( " PACKET #" );
sb.append( getPacketSequenceNumber() );
if( isFinalFragment() && getFragmentSequenceNumber() == 0 )
{
sb.append( ".C" );
}
else
{
sb.append( "." );
sb.append( getFragmentSequenceNumber() );
if( isFinalFragment() )
{
sb.append( "C" );
}
}
sb.append( " " );
sb.append( mMessage.toString() );
return sb.toString();
}
/**
* Network Service Access Point Identifier - up to 14 NSAPI's can be
* allocated to the mobile with each NSAPI to be used for a specific
* protocol layer.
*/
public int getNSAPI()
{
return mMessage.getInt( NSAPI );
}
public IPHeaderCompression getIPHeaderCompressionState()
{
return IPHeaderCompression.fromValue( mMessage.getInt( PCOMP ) );
}
/**
* No enum values were defined for this
*/
public boolean hasUserDataCompression()
{
return mMessage.getInt( DCOMP ) > 0;
}
/**
* IP Version - should always be 4 (IPV4)
*/
public int getIPVersion()
{
return mMessage.getInt( IP_VERSION );
}
/**
* IP packet header length in 32-bit words
*/
public int getInternetHeaderLength()
{
return mMessage.getInt( IHL );
}
/**
* IP packet DSCP
*/
public int getDifferentiatedServicesCodePoint()
{
return mMessage.getInt( DSCP );
}
/**
* IP packet ECN
*/
public int getExplicitCongestionNotification()
{
return mMessage.getInt( ECN );
}
/**
* IP packet size in bytes, including header and data
*/
public int getTotalLength()
{
return mMessage.getInt( TOTAL_LENGTH );
}
/**
* IP packet identification
*/
public int getIdentification()
{
return mMessage.getInt( IDENTIFICATION );
}
/**
* IP packet flags. 0-Reserved, 1-Don't Fragment, 2-More Fragments
*/
public int getFlags()
{
return mMessage.getInt( FLAGS );
}
public boolean isFragment()
{
return getFlags() > 0;
}
/**
* IP packet - identifies the offset value in 8-byte blocks (64-bit blocks)
* for this packet fragment from the beginning.
*/
public int getFragmentOffset()
{
return mMessage.getInt( FRAGMENT_OFFSET );
}
/**
* IP packet time (hops) to live
*/
public int getTimeToLive()
{
return mMessage.getInt( TTL );
}
/**
* Identifies the IP protocol carried by the IP packet
*/
public IPProtocol getIPProtocol()
{
return IPProtocol.fromValue( mMessage.getInt( PROTOCOL ) );
}
/**
* Source IPV4 address
*/
public String getSourceIPAddress()
{
StringBuilder sb = new StringBuilder();
sb.append( mMessage.getInt( SOURCE_IP_1 ) );
sb.append( "." );
sb.append( mMessage.getInt( SOURCE_IP_2 ) );
sb.append( "." );
sb.append( mMessage.getInt( SOURCE_IP_3 ) );
sb.append( "." );
sb.append( mMessage.getInt( SOURCE_IP_4 ) );
return sb.toString();
}
/**
* Destination IPV4 address
*/
public String getDestinationIPAddress()
{
StringBuilder sb = new StringBuilder();
sb.append( mMessage.getInt( DESTINATION_IP_1 ) );
sb.append( "." );
sb.append( mMessage.getInt( DESTINATION_IP_2 ) );
sb.append( "." );
sb.append( mMessage.getInt( DESTINATION_IP_3 ) );
sb.append( "." );
sb.append( mMessage.getInt( DESTINATION_IP_4 ) );
return sb.toString();
}
/**
* UDP source port
*/
public int getUDPSourcePort()
{
return mMessage.getInt( UDP_SOURCE_PORT );
}
/**
* UDP destination port
*/
public int getUDPDestinationPort()
{
return mMessage.getInt( UDP_DESTINATION_PORT );
}
/**
* UDP data payload size in bytes
*/
public int getUDPDataLength()
{
return mMessage.getInt( UDP_LENGTH );
}
/**
* Hex string representation of the packet data, including packet header
* data if present.
*/
public String getPayload()
{
StringBuilder sb = new StringBuilder();
/* Adjust for PDU header (2 bytes) plus IP Packet header (20 bytes) */
int start = 22;
if( getIPProtocol() == IPProtocol.UDP )
{
/* Adjust for UDP header (8 bytes) */
start = 30;
}
int spacingCounter = 0;
/* Append octets inserting a space between each 32-bit value */
int octets = getOctetCount() + getDataHeaderOffset();
for( int x = start; x < octets; x++ )
{
sb.append( getPacketOctet( x ) );
spacingCounter++;
if( spacingCounter >= 4 )
{
sb.append( " " );
spacingCounter = 0;
}
}
return sb.toString();
}
/**
* Returns the octet identified by the 0-indexed 'octet' argument location.
* If there is a Data Header Offset, the 0 index points to the first octet
* of the data header. Otherwise, the 0 index points to the first octet
* of the packet. You must account for the data header offset when
* specifying the octet.
*/
public String getPacketOctet( int octet )
{
int block = (int)( octet / 16 );
int offset = octet % 16;
int start = DATA_BLOCK_START + ( block * 144 ) + ( offset * 8 );
return mMessage.getHex( start, start + 7, 2 );
}
}