From guettler:

ATN decoding fixes for CLNP and COTP dissectors (configurable by option).

ATN decoding fixes for CLNP and COTP dissectors (configurable by option).

ATN specifics may be
selected/deseleted per CLNP/COTP dissector configuration (as requested).

CLNP dissector
1) configurable decoding of "ATN security label"

COTP dissector
1) configurable decoding of ATN TPDU's 
2) checksum calculation (none,OSI,ATN 16-bit, ATN 32-bit)
3) VP decoding for DR TPDU's

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5622

svn path=/trunk/; revision=46043
This commit is contained in:
Anders Broman 2012-11-16 14:18:27 +00:00
parent 22d1aa1f6c
commit c6cf5703f5
5 changed files with 977 additions and 155 deletions

View File

@ -38,6 +38,12 @@
#include <epan/nlpid.h> #include <epan/nlpid.h>
#include <epan/ipproto.h> #include <epan/ipproto.h>
/* pseudo-trailer for ATN extended checksums on TP4 layer*/
/* the checksum is calculated from the TPDU as well als */
/* dst NSAP length, dst NSAP, src NSAP length and src NSAP as encoded in CLNP PDU*/
guint clnp_pt_len ;
guint8 clnp_pt_buffer[42];
/* protocols and fields */ /* protocols and fields */
static int proto_clnp = -1; static int proto_clnp = -1;
@ -62,6 +68,8 @@ static int hf_clnp_dest_length = -1;
static int hf_clnp_dest = -1; static int hf_clnp_dest = -1;
static int hf_clnp_src_length = -1; static int hf_clnp_src_length = -1;
static int hf_clnp_src = -1; static int hf_clnp_src = -1;
int hf_clnp_atntt = -1; /* as referenced in packet-osi-options.c */
int hf_clnp_atnsc = -1; /* as referenced in packet-osi-options.c */
static int hf_clnp_segments = -1; static int hf_clnp_segments = -1;
static int hf_clnp_segment = -1; static int hf_clnp_segment = -1;
static int hf_clnp_segment_overlap = -1; static int hf_clnp_segment_overlap = -1;
@ -185,6 +193,7 @@ static GHashTable *clnp_reassembled_table = NULL;
static guint tp_nsap_selector = NSEL_TP; static guint tp_nsap_selector = NSEL_TP;
static gboolean always_decode_transport = FALSE; static gboolean always_decode_transport = FALSE;
static gboolean clnp_reassemble = TRUE; static gboolean clnp_reassemble = TRUE;
gboolean clnp_decode_atn_options = FALSE;
/* function definitions */ /* function definitions */
@ -250,7 +259,7 @@ dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* fixed part decoding */ /* fixed part decoding */
cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN); cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
opt_len = cnf_hdr_len; opt_len = cnf_hdr_len;
if (tree) { if (tree) {
ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA); ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA);
clnp_tree = proto_item_add_subtree(ti, ett_clnp); clnp_tree = proto_item_add_subtree(ti, ett_clnp);
@ -342,7 +351,7 @@ dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
cnf_cksum); cnf_cksum);
break; break;
} }
opt_len -= 9; /* Fixed part of Hesder */ opt_len -= 9; /* Fixed part of Header */
} /* tree */ } /* tree */
/* address part */ /* address part */
@ -354,6 +363,10 @@ dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
src_len = tvb_get_guint8(tvb, offset + dst_len + 1); src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len); src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
/* store src & dst address parts for ATN extended checksum calculation in ositp.c */
clnp_pt_len = dst_len + src_len + 2;
tvb_memcpy(tvb, &clnp_pt_buffer, offset, sizeof(clnp_pt_buffer));
if (tree) { if (tree) {
proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
dst_len); dst_len);
@ -595,7 +608,13 @@ proto_register_clnp(void)
{ &hf_clnp_src, { &hf_clnp_src,
{ "SA", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { "SA", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_clnp_segment_overlap, { &hf_clnp_atntt,
{ "ATN traffic type", "clnp.atn.tt", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_clnp_atnsc,
{ "ATN security classification", "clnp.atn.sc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_clnp_segment_overlap,
{ "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Segment overlaps with other segments", HFILL }}, "Segment overlaps with other segments", HFILL }},
@ -665,6 +684,14 @@ proto_register_clnp(void)
"Reassemble segmented CLNP datagrams", "Reassemble segmented CLNP datagrams",
"Whether segmented CLNP datagrams should be reassembled", "Whether segmented CLNP datagrams should be reassembled",
&clnp_reassemble); &clnp_reassemble);
prefs_register_bool_preference(clnp_module, "decode_atn_options",
"Decode ATN security label",
"Whether ATN security label should be decoded",
&clnp_decode_atn_options);
/* init src & dst address parts for ATN extended checksum calculation in ositp.c */
memset(clnp_pt_buffer, 0, sizeof(clnp_pt_buffer));
clnp_pt_len = 0;
} }
void void

View File

@ -41,6 +41,46 @@
#include "packet-esis.h" #include "packet-esis.h"
#include "packet-osi-options.h" #include "packet-osi-options.h"
/* ATN traffic types (ICAO doc 9705 Edition3 SV5 5.6.2.2.6.7.3) */
#define ATN_TT_ATSC_NO_PREFERENCE 0x01
#define ATN_TT_ATSC_CLASS_A 0x10
#define ATN_TT_ATSC_CLASS_B 0x11
#define ATN_TT_ATSC_CLASS_C 0x12
#define ATN_TT_ATSC_CLASS_D 0x13
#define ATN_TT_ATSC_CLASS_E 0x14
#define ATN_TT_ATSC_CLASS_F 0x15
#define ATN_TT_ATSC_CLASS_G 0x16
#define ATN_TT_ATSC_CLASS_H 0x17
#define ATN_TT_AOC_NO_PREFERENCE 0x21
#define ATN_TT_AOC_G 0x22
#define ATN_TT_AOC_V 0x23
#define ATN_TT_AOC_S 0x24
#define ATN_TT_AOC_H 0x25
#define ATN_TT_AOC_M 0x26
#define ATN_TT_AOC_G_V 0x27
#define ATN_TT_AOC_G_V_S 0x28
#define ATN_TT_AOC_G_V_H_S 0x29
#define ATN_TT_ADM_NO_PREFERENCE 0x30
#define ATN_TT_SYS_MGMT_NO_PREFERENCE 0x50
/* ATN security classification (ICAO doc 9705 Edition3 SV5 5.6.2.2.6.8.3) */
#define ATN_SC_UNCLASSIFIED 0x01
#define ATN_SC_RESTRICTED 0x02
#define ATN_SC_CONFIDENTIAL 0x03
#define ATN_SC_SECRET 0x04
#define ATN_SC_TOP_SECRET 0x05
/* ATN security label records */
#define OSI_OPT_SECURITY_ATN_SR 0xc0
#define OSI_OPT_SECURITY_ATN_TT 0x0f
#define OSI_OPT_SECURITY_ATN_SC 0x03
#define OSI_OPT_SECURITY_ATN_SR_LEN 6
#define OSI_OPT_SECURITY_ATN_TT_LEN 1
#define OSI_OPT_SECURITY_ATN_SC_LEN 1
#define OSI_OPT_SECURITY_ATN_SI_MAX_LEN 8
#define OSI_OPT_SECURITY 0xc5 #define OSI_OPT_SECURITY 0xc5
#define OSI_OPT_QOS_MAINTANANCE 0xc3 #define OSI_OPT_QOS_MAINTANANCE 0xc3
#define OSI_OPT_PRIORITY 0xcd #define OSI_OPT_PRIORITY 0xcd
@ -85,13 +125,56 @@
#define OSI_OPT_RFD_MASK 0xf0 #define OSI_OPT_RFD_MASK 0xf0
#define OSI_OPT_RFD_SUB_MASK 0x0f #define OSI_OPT_RFD_SUB_MASK 0x0f
extern gboolean clnp_decode_atn_options; /* as defined in packet-clnp.c */
extern int hf_clnp_atntt; /* as defined in packet-clnp.c */
extern int hf_clnp_atnsc; /* as defined in packet-clnp.c */
static gint ott_osi_options = -1; static gint ott_osi_options = -1;
static gint ott_osi_qos = -1; static gint ott_osi_qos = -1;
static gint ott_osi_route = -1; static gint ott_osi_route = -1;
static gint ott_osi_redirect = -1; static gint ott_osi_redirect = -1;
static const guchar atn_security_registration_val[] = { 0x06, 0x04, 0x2b, 0x1b, 0x00, 0x00 }; /* =iso(1).org(3).ICAO(27).ATN(0).TrafficType(0)*/
static const value_string osi_opt_sec_atn_sr_vals[] = {
{ OSI_OPT_SECURITY_ATN_SR, "ATN Security Label"},
{ 0, NULL} };
static const value_string osi_opt_sec_atn_si_vals[] = {
{ OSI_OPT_SECURITY_ATN_TT, "Traffic Type and Routing"},
{ OSI_OPT_SECURITY_ATN_SC, "Security classification"},
{ 0, NULL} };
static const value_string osi_opt_sec_atn_tt_vals[] = {
{ ATN_TT_ATSC_NO_PREFERENCE, "ATSC No preference"},
{ ATN_TT_ATSC_CLASS_A, "ATSC Class A"},
{ ATN_TT_ATSC_CLASS_B, "ATSC Class B"},
{ ATN_TT_ATSC_CLASS_C, "ATSC Class C"},
{ ATN_TT_ATSC_CLASS_D, "ATSC Class D"},
{ ATN_TT_ATSC_CLASS_E, "ATSC Class E"},
{ ATN_TT_ATSC_CLASS_F, "ATSC Class F"},
{ ATN_TT_ATSC_CLASS_G, "ATSC Class G"},
{ ATN_TT_ATSC_CLASS_H, "ATSC Class H"},
{ ATN_TT_AOC_NO_PREFERENCE, "AOC No preference"},
{ ATN_TT_AOC_G, "AOC Gatelink only"},
{ ATN_TT_AOC_V, "AOC VHF only"},
{ ATN_TT_AOC_S, "AOC Satellite only"},
{ ATN_TT_AOC_H, "AOC HF only"},
{ ATN_TT_AOC_M, "AOC Mode S only"},
{ ATN_TT_AOC_G_V, "AOC Gatelink first, then VHF"},
{ ATN_TT_AOC_G_V_S, "AOC Gatelink first, then VHF, then Satellite"},
{ ATN_TT_AOC_G_V_H_S, "AOC Gatelink first, then VHF, then HF, then Satellite"},
{ ATN_TT_ADM_NO_PREFERENCE, "ATN Administrative No preference"},
{ ATN_TT_SYS_MGMT_NO_PREFERENCE,"ATN Systems Management No preference"},
{ 0, NULL} };
static const value_string osi_opt_sec_atn_sc_vals[] = {
{ ATN_SC_UNCLASSIFIED, "unclassified"},
{ ATN_SC_RESTRICTED, "restricted"},
{ ATN_SC_CONFIDENTIAL, "confidential"},
{ ATN_SC_SECRET, "secret"},
{ ATN_SC_TOP_SECRET, "top secret"},
{ 0, NULL} };
static const value_string osi_opt_sec_vals[] = { static const value_string osi_opt_sec_vals[] = {
{ OSI_OPT_SEC_RESERVED, "Reserved"}, { OSI_OPT_SEC_RESERVED, "Reserved"},
@ -337,6 +420,108 @@ dissect_option_rfd( const guchar error, const guchar field, int offset,
} }
} }
/* dissect ATN security label used for policy based interdomain routing.*/
/* For details see ICAO doc 9705 Edition 3 SV5 5.6.2.2.2.2 */
static void
dissect_option_atn_security_label(
const guchar sub_type,
guchar length,
tvbuff_t *tvb,
guint offset,
proto_tree *tree ) {
proto_item *ti;
proto_tree *atn_sl_tree = NULL;
guchar len = 0;
guint8 tag_name = 0;
guint security_info_end = 0;
/* check for ATN security label */
if( OSI_OPT_SECURITY_ATN_SR != sub_type ){
return; } /* FALLTHROUGH */
/* check Security Registration Length */
len = tvb_get_guint8(tvb, ++offset);
if( OSI_OPT_SECURITY_ATN_SR_LEN != len ){
return; } /* FALLTHROUGH */
/* check Security Registration ID */
if (tvb_memeql(tvb, ++offset , atn_security_registration_val, OSI_OPT_SECURITY_ATN_SR_LEN )){
return; } /* FALLTHROUGH */
ti = proto_tree_add_text( tree, tvb, offset, length,
"%s",
val_to_str( sub_type, osi_opt_sec_atn_sr_vals, "Unknown (0x%x)"));
atn_sl_tree = proto_item_add_subtree( ti, ott_osi_qos );
offset+=OSI_OPT_SECURITY_ATN_SR_LEN ;
/* Security Information length */
len = tvb_get_guint8(tvb, offset);
if(OSI_OPT_SECURITY_ATN_SI_MAX_LEN < len){
/* FALLTHROUGH */
return;}
offset++;
security_info_end = offset + len;
while( offset < security_info_end ){
/* check tag name length*/
len = tvb_get_guint8(tvb, offset ); /* check tag name length*/
if( len != 1 ){
return; } /* FALLTHROUGH */
offset++;
tag_name = tvb_get_guint8(tvb, offset);
offset++;
switch(tag_name){
case OSI_OPT_SECURITY_ATN_TT:
/* check tag set length*/
len = tvb_get_guint8(tvb, offset);
if( len != OSI_OPT_SECURITY_ATN_TT_LEN ){
return; } /* FALLTHROUGH */
offset ++;
proto_tree_add_uint_format(atn_sl_tree, hf_clnp_atntt, tvb, offset, 1,
tvb_get_guint8(tvb, offset ),
"%s: %s",
val_to_str( OSI_OPT_SECURITY_ATN_TT, osi_opt_sec_atn_si_vals, "Unknown (0x%x)"),
val_to_str( tvb_get_guint8(tvb, offset ), osi_opt_sec_atn_tt_vals, "Unknown (0x%x)") );
offset += len ;
break;
case OSI_OPT_SECURITY_ATN_SC:
/* check tag set length*/
len = tvb_get_guint8(tvb, offset );
if( len != OSI_OPT_SECURITY_ATN_SC_LEN ){
/* FALLTHROUGH */
return;
}
offset ++;
proto_tree_add_uint_format(atn_sl_tree, hf_clnp_atnsc, tvb, offset, 1,
tvb_get_guint8(tvb, offset ),
"%s: %s",
val_to_str( OSI_OPT_SECURITY_ATN_SC, osi_opt_sec_atn_si_vals, "Unknown (0x%x)"),
val_to_str( tvb_get_guint8(tvb, offset ), osi_opt_sec_atn_sc_vals, "Unknown (0x%x)") );
offset += len ;
break;
default:
/* FALLTHROUGH */
return;
}
}
}
/* ############################## Dissection Functions ###################### */ /* ############################## Dissection Functions ###################### */
/* /*
@ -391,10 +576,16 @@ dissect_osi_options( guchar opt_len, tvbuff_t *tvb,
break; break;
case OSI_OPT_SECURITY: case OSI_OPT_SECURITY:
octet = tvb_get_guint8(tvb, offset); octet = tvb_get_guint8(tvb, offset);
proto_tree_add_text( osi_option_tree, tvb, offset, parm_len, if ( clnp_decode_atn_options ){
dissect_option_atn_security_label(octet,parm_len,tvb, offset, osi_option_tree );
}else {
proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
"Security type: %s", "Security type: %s",
val_to_str( octet&OSI_OPT_SEC_MASK, val_to_str( octet&OSI_OPT_SEC_MASK,
osi_opt_sec_vals, "Unknown (0x%x)") ); osi_opt_sec_vals, "Unknown (0x%x)") );
}
break; break;
case OSI_OPT_PRIORITY: case OSI_OPT_PRIORITY:
octet = tvb_get_guint8(tvb, offset); octet = tvb_get_guint8(tvb, offset);

View File

@ -194,6 +194,155 @@ check_and_get_checksum( tvbuff_t *tvb, int offset, guint len, guint checksum, in
return( CKSUM_OK ); return( CKSUM_OK );
} }
/* 4 octet ATN extended checksum: ICAO doc 9705 Ed3 Volume V section 5.5.4.6.4 */
/* It is calculated over TP4 userdata (all checksums set to zero ) and a pseudo tailer */
/* of length SRC-NSAP, SRC-NSAP, length DST-NSAP, DST-NSAP and ATN extended checksum. */
/* In case of a CR TPDU, the value of the ISO 8073 16-bit fletcher checksum parameter shall */
/* be set to zero. */
gboolean check_atn_ec_32(
tvbuff_t *tvb, guint tdpu_len,
guint offset_ec_32_val, /* offset ATN extended checksum value, calculated at last as part of pseudo trailer */
guint offset_iso8073_val, /* offset ISO 8073 fletcher checksum, CR only*/
guint clnp_pt_len, /* length of NSAP part of pseudo trailer */
guint8 * clnp_pt_buffer){ /* NSAP part of pseudo trailer */
guint i = 0;
guint32 c0 = 0;
guint32 c1 = 0;
guint32 c2 = 0;
guint32 c3 = 0;
guint32 sum = 0;
/* sum accross complete TDPU */
for ( i =0; i< tdpu_len; i++){
c0 += tvb_get_guint8(tvb, i) ;
if( ( i >= offset_ec_32_val ) && /* ignore 32 bit ATN extended checksum value */
( i < ( offset_ec_32_val + 4 ) ) ){
c0 -= tvb_get_guint8(tvb, i); }
if( ( offset_iso8073_val ) && /* ignore 16 bit ISO 8073 checksum, if present*/
( i >= offset_iso8073_val ) &&
( i < ( offset_iso8073_val + 2 ) ) ){
c0 -= tvb_get_guint8(tvb, i); }
if ( c0 >= 0x000000FF )
c0 -= 0x00000FF;
c1 += c0;
if ( c1 >= 0x000000FF )
c1 -= 0x000000FF;
c2 += c1;
if ( c2 >= 0x000000FF )
c2 -= 0x000000FF;
c3 += c2;
if ( c3 >= 0x000000FF )
c3 -= 0x000000FF;
}
/* add NSAP part of pseudo trailer */
for ( i =0; i< clnp_pt_len; i++){
c0 += clnp_pt_buffer[i];
if ( c0 >= 0x000000FF )
c0 -= 0x000000FF;
c1 += c0;
if ( c1 >= 0x000000FF )
c1 -= 0x000000FF;
c2 += c1;
if ( c2 >= 0x000000FF )
c2 -= 0x000000FF;
c3 += c2;
if ( c3 >= 0x000000FF )
c3 -= 0x000000FF;
}
/* add with extended checksum as last part of the pseudo trailer */
for ( i = offset_ec_32_val; i< (offset_ec_32_val+4); i++){
c0 += tvb_get_guint8(tvb, i) ;
if ( c0 >= 0x000000FF )
c0 -= 0x00000FF;
c1 += c0;
if ( c1 >= 0x000000FF )
c1 -= 0x000000FF;
c2 += c1;
if ( c2 >= 0x000000FF )
c2 -= 0x000000FF;
c3 += c2;
if ( c3 >= 0x000000FF )
c3 -= 0x000000FF;
}
sum = (c3 << 24) + (c2 << 16 ) + (c1 << 8) + c0 ;
if(!sum)
return TRUE;
else
return FALSE;
}
/* 2 octet ATN extended checksum: ICAO doc 9705 Ed3 Volume V section 5.5.4.6.4 */
/* It is calculated over TP4 userdata (all checksums set to zero ) and a pseudo tailer */
/* of length SRC-NSAP, SRC-NSAP, length DST-NSAP, DST-NSAP and ATN extended checksum. */
/* In case of a CR TPDU, the value of the ISO 8073 16-bit fletcher checksum parameter shall */
/* be set to zero. */
/* this routine is currently *untested* because of the unavailability of samples.*/
gboolean check_atn_ec_16(
tvbuff_t *tvb,
guint tdpu_len,
guint offset_ec_16_val, /* offset ATN extended checksum value, calculated at last as part of pseudo trailer */
guint offset_iso8073_val, /* offset ISO 8073 fletcher checksum, CR only*/
guint clnp_pt_len, /* length of NSAP part of pseudo trailer */
guint8 * clnp_pt_buffer ){ /* NSAP part of pseudo trailer */
guint i = 0;
guint16 c0 = 0;
guint16 c1 = 0;
guint16 sum = 0;
/* sum accross complete TDPU */
for ( i =0; i< tdpu_len; i++){
c0 += tvb_get_guint8(tvb, i);
if( (i >= offset_ec_16_val) && /* ignore 16 bit extended checksum */
(i < (offset_ec_16_val + 2) ) ) {
c0 -= tvb_get_guint8(tvb, i) ; }
if( (i >= offset_iso8073_val) && /* ignore 16 bit ISO 8073 checksum, if present*/
(i < (offset_iso8073_val + 2) ) ) {
c0 -= tvb_get_guint8(tvb, i) ; }
if ( c0 >= 0x00FF )
c0 -= 0x00FF;
c1 += c0;
if ( c1 >= 0x00FF )
c1 -= 0x00FF;
}
/* sum with NSAP part of the pseudo trailer */
for ( i =0; i< clnp_pt_len; i++){
c0 += clnp_pt_buffer[i] ;
c1 += c0;
}
/* add extended checksum as last part of the pseudo trailer */
for ( i = offset_ec_16_val; i< (offset_ec_16_val+2); i++){
c0 += tvb_get_guint8(tvb, i) ;
if ( c0 >= 0x00FF )
c0 -= 0x00FF;
c1 += c0;
if ( c1 >= 0x00FF )
c1 -= 0x00FF;
}
sum = (c1 << 8) + c0 ;
if(!sum)
return TRUE;
else
return FALSE;
}
/* main entry point */ /* main entry point */
@ -350,5 +499,6 @@ proto_register_osi(void)
"Whether segmented TPKT datagrams should be reassembled", "Whether segmented TPKT datagrams should be reassembled",
&tpkt_desegment); &tpkt_desegment);
} }

View File

@ -87,5 +87,7 @@ typedef enum {
extern cksum_status_t calc_checksum(tvbuff_t *, int, guint, guint); extern cksum_status_t calc_checksum(tvbuff_t *, int, guint, guint);
extern cksum_status_t check_and_get_checksum( tvbuff_t *, int, guint, guint, int, guint16*); extern cksum_status_t check_and_get_checksum( tvbuff_t *, int, guint, guint, int, guint16*);
extern gboolean check_atn_ec_32(tvbuff_t *tvb, guint tdpu_len, guint offset_ec_32_val, guint offset_iso8073_val, guint clnp_pt_len, guint8 * clnp_pt_buffer);
extern gboolean check_atn_ec_16( tvbuff_t *tvb, guint tdpu_len, guint offset_ec_16_val, guint offset_iso8073_val, guint clnp_pt_len, guint8 * clnp_pt_buffer );
#endif /* _PACKET_OSI_H */ #endif /* _PACKET_OSI_H */

View File

@ -198,6 +198,18 @@ static const value_string class_option_vals[] = {
number of octets? */ number of octets? */
#define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 ) #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
/* modified TPDU length indicators due to ATN extended checksum */
#define LI_ATN_NORMAL_DT_WITH_CHECKSUM 10 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_EXTENDED_DT_WITH_CHECKSUM 13 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_NORMAL_EA_WITH_CHECKSUM 10 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_EXTENDED_EA_WITH_CHECKSUM 13 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_NORMAL_RJ 6 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_EXTENDED_RJ 11 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_MAX_DC 11 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_MAX_AK 30 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_MAX_EA 13 /* ATN 4 octet extended checksum adds 2 octets */
#define LI_ATN_MAX_ER 10 /* ATN 4 octet extended checksum adds 2 octets */
/* variant part */ /* variant part */
#define VP_ACK_TIME 0x85 #define VP_ACK_TIME 0x85
@ -219,7 +231,23 @@ static const value_string class_option_vals[] = {
#define VP_PREF_MAX_TPDU_SIZE 0xF0 #define VP_PREF_MAX_TPDU_SIZE 0xF0
#define VP_INACTIVITY_TIMER 0xF2 #define VP_INACTIVITY_TIMER 0xF2
/* ATN */
/* Parameter codes with bits 7 and 8 are explicitly not */
/* assigned by ISO/IEC 8073, nor is their use precluded. */
/* Parameter codes for ATN defined in ICAO doc 9507 Ed3 SV 5 section 5.5.2.4.3.1 */
#define VP_ATN_EC_32 0x08 /* 4 octet ATN Extended Transport Checksum parameter */
#define VP_ATN_EC_16 0x09 /* 2 octet ATN Extended Transport Checksum parameter */
/* ATN end */
/* pseudo-trailer for ATN extended checksums on TP4 layer*/
/* the checksum is calculated from the TPDU as well als */
/* dst NSAP length, dst NSAP, src NSAP length and src NSAP as encoded in CLNP PDU*/
extern guint clnp_pt_len; /* length of dst-len + dst-nsap + src-len + src-nsap */
extern guint8 clnp_pt_buffer[42]; /* buffer containing CLNP pseudoheader */
static const value_string tp_vpart_type_vals[] = { static const value_string tp_vpart_type_vals[] = {
{ VP_ATN_EC_16, "ATN extended checksum - 16 bit" },
{ VP_ATN_EC_32, "ATN extended checksum - 32 bit" },
{ VP_ACK_TIME, "ack time" }, { VP_ACK_TIME, "ack time" },
{ VP_RES_ERROR, "res error" }, { VP_RES_ERROR, "res error" },
{ VP_PRIORITY, "priority" }, { VP_PRIORITY, "priority" },
@ -237,9 +265,16 @@ static const value_string tp_vpart_type_vals[] = {
{ VP_OPT_SEL, "options" }, { VP_OPT_SEL, "options" },
{ VP_PROTO_CLASS, "proto class" }, { VP_PROTO_CLASS, "proto class" },
{ VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" }, { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
{ VP_INACTIVITY_TIMER, "inactivity timer" },
{ 0, NULL } { 0, NULL }
}; };
static const value_string tp_vpart_checksum_vals[] = {
{ FALSE, "incorrect" },
{ TRUE, "correct" }
};
static int hf_cotp_vp_src_tsap = -1; static int hf_cotp_vp_src_tsap = -1;
static int hf_cotp_vp_dst_tsap = -1; static int hf_cotp_vp_dst_tsap = -1;
static int hf_cotp_vp_src_tsap_bytes = -1; static int hf_cotp_vp_src_tsap_bytes = -1;
@ -272,6 +307,8 @@ static gboolean cotp_last_fragment = FALSE;
/* options */ /* options */
static gboolean cotp_reassemble = TRUE; static gboolean cotp_reassemble = TRUE;
static gint32 tsap_display = TSAP_DISPLAY_AUTO; static gint32 tsap_display = TSAP_DISPLAY_AUTO;
static gboolean cotp_decode_atn = TRUE;
const enum_val_t tsap_display_options[] = { const enum_val_t tsap_display_options[] = {
{"auto", "As strings if printable", TSAP_DISPLAY_AUTO}, {"auto", "As strings if printable", TSAP_DISPLAY_AUTO},
@ -285,6 +322,7 @@ const enum_val_t tsap_display_options[] = {
#define MAX_TSAP_LEN 32 #define MAX_TSAP_LEN 32
static void cotp_frame_end(void) static void cotp_frame_end(void)
{ {
if (!cotp_last_fragment) { if (!cotp_last_fragment) {
@ -352,9 +390,18 @@ static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
guint8 c1; guint8 c1;
guint16 s, s1,s2,s3,s4; guint16 s, s1,s2,s3,s4;
guint32 t1, t2, t3, t4; guint32 t1, t2, t3, t4;
guint32 offset_iso8073_checksum = 0;
gint32 i = 0;
guint16 tdpu_length = 0;
guint8 tmp_code = 0;
guint tmp_len = 0;
guint checksum_ok = 0;
guint32 pref_max_tpdu_size; guint32 pref_max_tpdu_size;
proto_item *hidden_item; proto_item *hidden_item;
/* TDPU length needed for ATN checksum calculations */
tdpu_length = offset + vp_length + tvb_length_remaining(tvb, offset + vp_length);
while (vp_length != 0) { while (vp_length != 0) {
code = tvb_get_guint8(tvb, offset); code = tvb_get_guint8(tvb, offset);
proto_tree_add_text(tree, tvb, offset, 1, proto_tree_add_text(tree, tvb, offset, 1,
@ -373,6 +420,58 @@ static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
vp_length -= 1; vp_length -= 1;
switch (code) { switch (code) {
case VP_ATN_EC_16 : /* ATN */
if (cotp_decode_atn) {
/* if an alternate OSI checksum is present in the currently unprocessed VP section to the checksum algorithm has to know */
/* this may be the case for backward compatible CR TDPU */
if(!offset_iso8073_checksum){
/* search following parameters in VP part for ISO checksum */
for( i = ( offset + length ); i < vp_length; ){
tmp_code = tvb_get_guint8(tvb, i++);
tmp_len = tvb_get_guint8(tvb, i++);
if (tmp_code == VP_CHECKSUM ){
offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */
break;
}
i += tmp_len; }
}
checksum_ok = check_atn_ec_16(tvb, tdpu_length, offset, offset_iso8073_checksum, clnp_pt_len, (guint8 *) &clnp_pt_buffer);
proto_tree_add_text(tree, tvb, offset, length,
"ATN extended checksum : 0x%04x (%s)",
tvb_get_ntohs(tvb, offset),
val_to_str(checksum_ok, tp_vpart_checksum_vals, "?"));
}else {
proto_tree_add_text(tree, tvb, offset, length,"Parameter value: <not shown>");
}
offset += length;
vp_length -= length;
break;
case VP_ATN_EC_32 : /* ATN */
if (cotp_decode_atn) {
/* if an alternate OSI checksum is present in the currently unprocessed VP section the checksum algorithm has to know */
/* this may be the case for backward compatible CR TDPU */
if(!offset_iso8073_checksum){
/* search following parameters in VP part for ISO checksum */
for( i = ( offset + length ); i < vp_length; ){
tmp_code = tvb_get_guint8(tvb, i++);
tmp_len = tvb_get_guint8(tvb, i++);
if (tmp_code == VP_CHECKSUM ){
offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */
break;}
i += tmp_len; }
}
checksum_ok = check_atn_ec_32(tvb, tdpu_length, offset, offset_iso8073_checksum, clnp_pt_len, (guint8 *) &clnp_pt_buffer);
proto_tree_add_text(tree, tvb, offset, length,
"ATN extended checksum : 0x%08x (%s)",
tvb_get_ntohl(tvb, offset),
val_to_str(checksum_ok, tp_vpart_checksum_vals, "?"));
}else {
proto_tree_add_text(tree, tvb, offset, length,"Parameter value: <not shown>");
}
offset += length;
vp_length -= length;
break;
case VP_ACK_TIME: case VP_ACK_TIME:
s = tvb_get_ntohs(tvb, offset); s = tvb_get_ntohs(tvb, offset);
@ -585,8 +684,10 @@ static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
break; break;
case VP_CHECKSUM: case VP_CHECKSUM:
offset_iso8073_checksum = offset; /* save ISO 8073 checksum offset for ATN extended checksum calculation */
checksum_ok = calc_checksum(tvb, 0, tdpu_length, tvb_get_ntohs(tvb, offset));
proto_tree_add_text(tree, tvb, offset, length, proto_tree_add_text(tree, tvb, offset, length,
"Checksum: 0x%04x", tvb_get_ntohs(tvb, offset)); "Checksum: 0x%04x (%s)", tvb_get_ntohs(tvb, offset),val_to_str( (checksum_ok == CKSUM_OK) ? TRUE : FALSE , tp_vpart_checksum_vals, "?"));
offset += length; offset += length;
vp_length -= length; vp_length -= length;
break; break;
@ -697,10 +798,11 @@ static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
guint16 dst_ref, src_ref; guint16 dst_ref, src_ref;
guchar reason; guchar reason;
const char *str; const char *str;
/* ATN TPDU's tend to be larger than normal OSI, so nothing to do with respect to LI checks */
if (li < LI_MIN_DR) if (li < LI_MIN_DR)
return -1; return -1;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
@ -753,6 +855,11 @@ static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
"Cause: %s", str); "Cause: %s", str);
} }
/* decode VP */
if (tree) {
ositp_decode_var_part(tvb, offset + P_REASON_IN_DR + 1, li - P_REASON_IN_DR , 4, cotp_tree);
}
offset += li + 1; offset += li + 1;
expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_CHAT, expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_CHAT,
@ -785,79 +892,185 @@ static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
fragment_data *fd_head; fragment_data *fd_head;
conversation_t *conv; conversation_t *conv;
/* VP_CHECKSUM is the only parameter allowed in the variable part. /* note: in the ATN the user is up to chose between 3 different checksums: */
(This means we may misdissect this if the packet is bad and /* standard OSI, 2 or 4 octet extended checksum. */
contains other parameters.) */ /* The differences for DT are that the TDPU headers may be enlarged by 2 octets */
switch (li) { /* and that checksum related option codes and option lengths are different. */
/* to not mess up the original OSI dissector LI checking was implemented separately. */
if (!cotp_decode_atn) { /* non ATN, plain OSI*/
case LI_NORMAL_DT_WITH_CHECKSUM : /* VP_CHECKSUM is the only parameter allowed in the variable part.
if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) (This means we may misdissect this if the packet is bad and
return -1; contains other parameters.) */
/* FALLTHROUGH */ switch (li) {
case LI_NORMAL_DT_WITHOUT_CHECKSUM : case LI_NORMAL_DT_WITH_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234); if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
if ( tpdu_nr & 0x80 ) return -1;
tpdu_nr = tpdu_nr & 0x7F; /* FALLTHROUGH */
else
fragment = TRUE;
is_extended = FALSE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
case LI_EXTENDED_DT_WITH_CHECKSUM : case LI_NORMAL_DT_WITHOUT_CHECKSUM :
if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
return -1; if ( tpdu_nr & 0x80 )
/* FALLTHROUGH */ tpdu_nr = tpdu_nr & 0x7F;
else
fragment = TRUE;
is_extended = FALSE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
case LI_EXTENDED_DT_WITHOUT_CHECKSUM : case LI_EXTENDED_DT_WITH_CHECKSUM :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
if ( tpdu_nr & 0x80000000 ) return -1;
tpdu_nr = tpdu_nr & 0x7FFFFFFF; /* FALLTHROUGH */
else
fragment = TRUE;
is_extended = TRUE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
case LI_NORMAL_DT_CLASS_01 : case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1); tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 ) if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7F; tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else else
fragment = TRUE; fragment = TRUE;
is_extended = FALSE; is_extended = TRUE;
is_class_234 = FALSE; is_class_234 = TRUE;
prev_dst_ref = p_get_proto_data (pinfo->fd, proto_clnp); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
if (!prev_dst_ref) { break;
/* First COTP in frame - save previous dst_ref as offset */
prev_dst_ref = se_alloc (sizeof (guint32));
*prev_dst_ref = cotp_dst_ref;
p_add_proto_data (pinfo->fd, proto_clnp, prev_dst_ref);
} else if (cotp_frame_reset) {
cotp_dst_ref = *prev_dst_ref;
}
cotp_frame_reset = FALSE;
cotp_last_fragment = fragment;
dst_ref = cotp_dst_ref;
conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if (conv) {
/* Found a conversation, also use index for the generated dst_ref */
dst_ref += (conv->index << 16);
}
if (!fragment) {
cotp_dst_ref++;
register_frame_end_routine(pinfo, cotp_frame_end);
}
break;
default : /* bad TPDU */ case LI_NORMAL_DT_CLASS_01 :
return -1; tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
} if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
fragment = TRUE;
is_extended = FALSE;
is_class_234 = FALSE;
prev_dst_ref = p_get_proto_data (pinfo->fd, proto_clnp);
if (!prev_dst_ref) {
/* First COTP in frame - save previous dst_ref as offset */
prev_dst_ref = se_alloc (sizeof (guint32));
*prev_dst_ref = cotp_dst_ref;
p_add_proto_data (pinfo->fd, proto_clnp, prev_dst_ref);
} else if (cotp_frame_reset) {
cotp_dst_ref = *prev_dst_ref;
}
cotp_frame_reset = FALSE;
cotp_last_fragment = fragment;
dst_ref = cotp_dst_ref;
conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if (conv) {
/* Found a conversation, also use index for the generated dst_ref */
dst_ref += (conv->index << 16);
}
if (!fragment) {
cotp_dst_ref++;
register_frame_end_routine(pinfo, cotp_frame_end);
}
break;
default : /* bad TPDU */
return -1;
} /* li */
} else {
/* check ATN class4 TDPU's here */
/* check packet length indicators of DaTa(DT) TDPU */
/* note: use of checksum depends on the selected RER */
/* (high:non-use medium:16-bit OSI/16-bit ext.ATN low:32-bit ext. ATN) */
/* note: sole use of TP4 class in the ATN */
/* note: normal/extended TDPU numbering is negociable */
switch (li) {
case LI_NORMAL_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
fragment = TRUE;
is_extended = FALSE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
/* normal DT with 2 octets of OSI or of ATN Extended Checksum */
case LI_NORMAL_DT_WITH_CHECKSUM :
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM &&
tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16 )
return -1; /* FALLTHROUGH */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
fragment = TRUE;
is_extended = FALSE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
/* normal DT with ATN Extended Checksum (4 octets)*/
case LI_ATN_NORMAL_DT_WITH_CHECKSUM :
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32 )
return -1; /* FALLTHROUGH */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
fragment = TRUE;
is_extended = FALSE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else
fragment = TRUE;
is_extended = TRUE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
/* extended DT with 2 octets of OSI or of ATN Extended Checksum */
case LI_EXTENDED_DT_WITH_CHECKSUM :
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM &&
tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16 )
return -1; /* FALLTHROUGH */
/* FALLTHROUGH */
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else
fragment = TRUE;
is_extended = TRUE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
/* extended DT with 4 octets ATN Extended Checksum */
case LI_ATN_EXTENDED_DT_WITH_CHECKSUM:
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32 )
return -1; /* FALLTHROUGH */
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else
fragment = TRUE;
is_extended = TRUE;
is_class_234 = TRUE;
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
break;
default : /* bad TPDU */
return -1;
} /* li */
} /* cotp_decode_atn */
pinfo->clnp_dstref = dst_ref; pinfo->clnp_dstref = dst_ref;
pinfo->fragmented = fragment; pinfo->fragmented = fragment;
@ -1011,45 +1224,138 @@ static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
guint tpdu_nr; guint tpdu_nr;
tvbuff_t *next_tvb; tvbuff_t *next_tvb;
/* ED TPDUs are never fragmented */ /* note: in the ATN the user is up to chose between 3 different checksums: */
/* standard OSI, 2 or 4 octet extended checksum. */
/* The differences for ED (as for DT) are that the TDPU headers may be enlarged by 2 octets */
/* and that checksum related option codes and option lengths are different. */
/* to not mess up the original OSI dissector LI checking was implemented separately. */
/* note: this could not be tested, because no sample was avail for expedited data */
if (!cotp_decode_atn) { /* non ATN, plain OSI*/
/* ED TPDUs are never fragmented */
/* VP_CHECKSUM is the only parameter allowed in the variable part. /* VP_CHECKSUM is the only parameter allowed in the variable part.
(This means we may misdissect this if the packet is bad and (This means we may misdissect this if the packet is bad and
contains other parameters.) */ contains other parameters.) */
switch (li) { switch (li) {
case LI_NORMAL_DT_WITH_CHECKSUM : case LI_NORMAL_DT_WITH_CHECKSUM :
if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
return -1; return -1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case LI_NORMAL_DT_WITHOUT_CHECKSUM : case LI_NORMAL_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234); tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 ) if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F; tpdu_nr = tpdu_nr & 0x7F;
else else
return -1; return -1;
is_extended = FALSE; is_extended = FALSE;
break; break;
case LI_EXTENDED_DT_WITH_CHECKSUM : case LI_EXTENDED_DT_WITH_CHECKSUM :
if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
return -1; return -1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case LI_EXTENDED_DT_WITHOUT_CHECKSUM : case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 ) if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF; tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else else
return -1; return -1;
is_extended = TRUE; is_extended = TRUE;
break; break;
default : /* bad TPDU */ default : /* bad TPDU */
return -1; return -1;
} /* li */ } /* li */
}else {
/* check packet length indicators of ATN Expedited Data (ED) TDPU */
/* note: use of checksum depends on the selected RER */
/* (high:non-use medium:16-bit OSI/16-bit ext.ATN low:32-bit ext. ATN) */
/* note: sole use of TP4 class in the ATN */
/* note: normal/extended TDPU numbering is negociable */
switch (li) {
case LI_NORMAL_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
return -1;
is_extended = FALSE;
break;
case LI_NORMAL_DT_WITH_CHECKSUM :
if ((tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) &&
(tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16))
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
return -1;
is_extended = FALSE;
break;
case LI_ATN_NORMAL_DT_WITH_CHECKSUM :
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32 )
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80 )
tpdu_nr = tpdu_nr & 0x7F;
else
return -1;
is_extended = FALSE;
break;
case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else
return -1;
is_extended = TRUE;
break;
case LI_EXTENDED_DT_WITH_CHECKSUM :
if ( ( tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ) &&
( tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16) )
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else
return -1;
is_extended = TRUE;
break;
case LI_ATN_EXTENDED_DT_WITH_CHECKSUM :
if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32)
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
if ( tpdu_nr & 0x80000000 )
tpdu_nr = tpdu_nr & 0x7FFFFFFF;
else
return -1;
is_extended = TRUE;
break;
default : /* bad TPDU */
return -1;
} /* li */
} /* cotp_decode_atn */
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
pinfo->clnp_dstref = dst_ref; pinfo->clnp_dstref = dst_ref;
@ -1115,18 +1421,43 @@ static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
guint tpdu_nr; guint tpdu_nr;
gushort credit = 0; gushort credit = 0;
switch(li) { /* note: in the ATN the user is up to chose between 3 different checksums: */
case LI_NORMAL_RJ : /* standard OSI, 2 or 4 octet extended checksum. */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234); /* The difference for RJ is that the TDPU header may be enlarged by 2 octets */
break; /* for checksum parameters are not going to be checked here */
case LI_EXTENDED_RJ : if (!cotp_decode_atn) { /* non ATN, plain OSI*/
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); switch(li) {
credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ); case LI_NORMAL_RJ :
break; tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
default : break;
return -1; case LI_EXTENDED_RJ :
} tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
break;
default :
return -1;
}
} else {
switch(li) {
/* normal with 2 octets of OSI or ATN checksum */
case LI_NORMAL_RJ :
/* with 4 octets of ATN checksum */
case LI_ATN_NORMAL_RJ :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
break;
/* extended with 2 octets of OSI or ATN checksum */
case LI_EXTENDED_RJ :
/* with 4 octets of ATN checksum */
case LI_ATN_EXTENDED_RJ :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
break;
default :
return -1;
}
}
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
pinfo->clnp_dstref = dst_ref; pinfo->clnp_dstref = dst_ref;
@ -1168,7 +1499,10 @@ static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
gboolean uses_inactive_subset, gboolean uses_inactive_subset,
gboolean *subdissector_found) gboolean *subdissector_found)
{ {
/* note: in the ATN the user is up to chose between 3 different checksums: */
/* standard OSI, 2 or 4 octet extended checksum. */
/* Nothing has to be done here, for all ATN specifics are handled in VP. */
/* CC & CR decoding in the same function */ /* CC & CR decoding in the same function */
proto_tree *cotp_tree = NULL; proto_tree *cotp_tree = NULL;
@ -1264,9 +1598,15 @@ static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
proto_item *item = NULL; proto_item *item = NULL;
guint16 dst_ref, src_ref; guint16 dst_ref, src_ref;
if (li > LI_MAX_DC) /* ATN may use checksums different from OSI */
return -1; /* which may result in different TPDU header length. */
if ( !cotp_decode_atn) {
if (li > LI_MAX_DC)
return -1; }
else {
if (li > LI_ATN_MAX_DC)
return -1; }
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
pinfo->clnp_dstref = dst_ref; pinfo->clnp_dstref = dst_ref;
@ -1321,9 +1661,15 @@ static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
guint tpdu_nr; guint tpdu_nr;
gushort cdt_in_ak; gushort cdt_in_ak;
if (li > LI_MAX_AK) if (!cotp_decode_atn ){
return -1; if (li > LI_MAX_AK)
return -1;}
else {
if (li > LI_ATN_MAX_AK)
return -1; }
/* is_LI_NORMAL_AK() works for normal ATN AK's, */
/* for the TPDU header size may be enlarged by 2 octets */
if (is_LI_NORMAL_AK(li)) { if (is_LI_NORMAL_AK(li)) {
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
@ -1426,41 +1772,134 @@ static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
gboolean is_extended; gboolean is_extended;
guint16 dst_ref; guint16 dst_ref;
guint tpdu_nr; guint tpdu_nr;
/* Due to different checksums in the ATN the TDPU header sizes */
/* as well as the checksum parameters may be different than plain OSI EA.*/
/* because these are heavily checked for EA these checks had to be re-implemented. */
/* note: this could not be tested, because no sample was avail for expedited data */
if(!cotp_decode_atn) {
if (li > LI_MAX_EA) if (li > LI_MAX_EA)
return -1; return -1;
/* VP_CHECKSUM is the only parameter allowed in the variable part. /* VP_CHECKSUM is the only parameter allowed in the variable part.
(This means we may misdissect this if the packet is bad and (This means we may misdissect this if the packet is bad and
contains other parameters.) */ contains other parameters.) */
switch (li) { switch (li) {
case LI_NORMAL_EA_WITH_CHECKSUM : case LI_NORMAL_EA_WITH_CHECKSUM :
if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM || if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2) tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
return -1; return -1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case LI_NORMAL_EA_WITHOUT_CHECKSUM : case LI_NORMAL_EA_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234); tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
is_extended = FALSE; is_extended = FALSE;
break; break;
case LI_EXTENDED_EA_WITH_CHECKSUM : case LI_EXTENDED_EA_WITH_CHECKSUM :
if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM || if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
return -1; return -1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case LI_EXTENDED_EA_WITHOUT_CHECKSUM : case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
is_extended = TRUE; is_extended = TRUE;
break; break;
default : /* bad TPDU */ default : /* bad TPDU */
return -1; return -1;
} /* li */ } /* li */
}else { /* cotp_decode_atn */
/* check for ATN length: TDPU may be 2 octets longer due to checksum */
if (li > LI_ATN_MAX_EA)
return -1;
switch (li) {
/* extended TDPU numbering EA with no checksum */
case LI_NORMAL_EA_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
is_extended = FALSE;
break;
/* normal TDPU numbering EA with 2 octets of OSI or ATN extended checksum */
case LI_NORMAL_EA_WITH_CHECKSUM :
/* check checksum parameter (in VP) parameter code octet */
if ((tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) &&
(tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16 ))
return -1;
/* FALLTHROUGH */
/* check checksum parameter (in VP) length octet */
if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT +1 ) != 2)
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
is_extended = FALSE;
break;
/* normal TDPU numbering EA with 4 octets of ATN extended checksum */
case LI_ATN_NORMAL_EA_WITH_CHECKSUM :
/* check checksum parameter (in VP) parameter code octet */
if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32 )
return -1;
/* FALLTHROUGH */
/* check checksum parameter (in VP) length octet */
if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT +1 ) != 4)
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
is_extended = FALSE;
break;
/* extended TDPU numbering EA with no checksum */
case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
is_extended = TRUE;
break;
/* extended TDPU numbering EA with 2 octets of OSI or ATN extended checksum */
case LI_EXTENDED_EA_WITH_CHECKSUM :
/* check checksum parameter (in VP) parameter code octet */
if ( (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ) &&
(tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16))
return -1;
/* FALLTHROUGH */
/* check checksum parameter (in VP) length octet */
if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT +1 ) != 2 )
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
is_extended = TRUE;
break;
/* extended EA with 4 octets ATN extended checksum */
case LI_ATN_EXTENDED_EA_WITH_CHECKSUM :
/* check checksum parameter (in VP) parameter code octet */
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32 )
return -1;
/* FALLTHROUGH */
/* check checksum parameter (in VP) length octet */
if ( tvb_get_guint8(tvb, offset + P_VAR_PART_EDT +1 ) != 2 )
return -1;
/* FALLTHROUGH */
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
is_extended = TRUE;
break;
default : /* bad TPDU */
return -1;
}
}
dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
pinfo->clnp_dstref = dst_ref; pinfo->clnp_dstref = dst_ref;
@ -1518,8 +1957,14 @@ static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
const char *str; const char *str;
guint16 dst_ref; guint16 dst_ref;
if (li > LI_MAX_ER) /* ATN: except for modified LI checking nothing to be done here */
return -1; if(!cotp_decode_atn) {
if (li > LI_MAX_ER)
return -1;
}else {
if (li > LI_ATN_MAX_ER)
return -1;
}
switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) { switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
case 0 : case 0 :
@ -1826,7 +2271,7 @@ void proto_register_cotp(void)
{ &hf_cotp_vp_dst_tsap_bytes, { &hf_cotp_vp_dst_tsap_bytes,
{ "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0, { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
"Called TSAP (bytes representation)", HFILL }}, "Called TSAP (bytes representation)", HFILL }},
}; };
static gint *ett[] = { static gint *ett[] = {
&ett_cotp, &ett_cotp,
@ -1854,12 +2299,19 @@ void proto_register_cotp(void)
tsap_display_options, tsap_display_options,
FALSE); FALSE);
prefs_register_bool_preference(cotp_module, "decode_atn",
"Decode ATN TPDUs",
"Whether to decode OSI TDPUs with ATN (Aereonautical Telecommunications Network) extensions."
" To use this option, you must also enable \"Always try to decode NSDU as transport PDUs\" in the CLNP protocol settings.",
&cotp_decode_atn);
/* subdissector code in inactive subset */ /* subdissector code in inactive subset */
register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list); register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
/* other COTP/ISO 8473 subdissectors */ /* other COTP/ISO 8473 subdissectors */
register_heur_dissector_list("cotp", &cotp_heur_subdissector_list); register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
/* XXX - what about CLTP and proto_cltp? */ /* XXX - what about CLTP and proto_cltp? */
new_register_dissector("ositp", dissect_ositp, proto_cotp); new_register_dissector("ositp", dissect_ositp, proto_cotp);
new_register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp); new_register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp);