Set the svn:eol-style property on all text files to "native", so that
[obnox/wireshark/wip.git] / packet-sua.c
index 237c1b35537cd4fde47e9a0e4aef1e8e757c8c65..cd90c4e390b5f98cc36308bf30161db6661fcc5d 100644 (file)
@@ -1,11 +1,11 @@
 /* packet-sua.c
  * Routines for SS7 SCCP-User Adaptation Layer (SUA) dissection
  * It is hopefully (needs testing) compilant to
- * http://www.ietf.org/internet-drafts/draft-ietf-sigtran-sua-14.txt
+ * http://www.ietf.org/internet-drafts/draft-ietf-sigtran-sua-15.txt
  *
  * Copyright 2002, 2003 Michael Tuexen <tuexen [AT] fh-muenster.de>
  *
- * $Id: packet-sua.c,v 1.15 2003/04/19 20:09:00 tuexen Exp $
+ * $Id$
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -240,6 +240,7 @@ static const value_string message_class_type_values[] = {
   { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_DAUD,          "Destination state audit (DAUD)" },
   { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_SCON,          "SS7 Network congestion state (SCON)" },
   { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_DUPU,          "Destination userpart unavailable (DUPU)" },
+  { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_DRST,          "Destination Restricted (DRST)" },
   { MESSAGE_CLASS_ASPSM_MESSAGE * 256 + MESSAGE_TYPE_UP,            "ASP up (UP)" },
   { MESSAGE_CLASS_ASPSM_MESSAGE * 256 + MESSAGE_TYPE_DOWN,          "ASP down (DOWN)" },
   { MESSAGE_CLASS_ASPSM_MESSAGE * 256 + MESSAGE_TYPE_BEAT,          "Heartbeat (BEAT)" },
@@ -277,6 +278,7 @@ static const value_string message_class_type_acro_values[] = {
   { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_DAUD,          "DAUD" },
   { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_SCON,          "SCON" },
   { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_DUPU,          "DUPU" },
+  { MESSAGE_CLASS_SSNM_MESSAGE  * 256 + MESSAGE_TYPE_DRST,          "DRST" },
   { MESSAGE_CLASS_ASPSM_MESSAGE * 256 + MESSAGE_TYPE_UP,            "ASP_UP" },
   { MESSAGE_CLASS_ASPSM_MESSAGE * 256 + MESSAGE_TYPE_DOWN,          "ASP_DOWN" },
   { MESSAGE_CLASS_ASPSM_MESSAGE * 256 + MESSAGE_TYPE_BEAT,          "BEAT" },
@@ -390,6 +392,8 @@ static int hf_tid_label_value = -1;
 static int hf_drn_label_start = -1;
 static int hf_drn_label_end = -1;
 static int hf_drn_label_value = -1;
+static int hf_gt_reserved = -1;
+static int hf_gti = -1;
 static int hf_number_of_digits = -1;
 static int hf_translation_type = -1;
 static int hf_numbering_plan = -1;
@@ -415,8 +419,11 @@ static gint ett_sua_receive_sequence_number_number = -1;
 static gint ett_sua_return_on_error_bit_and_protocol_class = -1;
 static gint ett_sua_protcol_classes = -1;
 
+static dissector_handle_t data_handle;
+static dissector_table_t sua_ssn_dissector_table;
+
 static void
-dissect_parameters(tvbuff_t *tlv_tvb, proto_tree *tree);
+dissect_parameters(tvbuff_t *tlv_tvb, proto_tree *tree, tvbuff_t **data_tvb, guint8 *source_ssn, guint8 *dest_ssn);
 
 static void
 dissect_common_header(tvbuff_t *common_header_tvb, packet_info *pinfo, proto_tree *sua_tree)
@@ -426,10 +433,8 @@ dissect_common_header(tvbuff_t *common_header_tvb, packet_info *pinfo, proto_tre
   message_class  = tvb_get_guint8(common_header_tvb, MESSAGE_CLASS_OFFSET);
   message_type   = tvb_get_guint8(common_header_tvb, MESSAGE_TYPE_OFFSET);
 
-  if (check_col(pinfo->cinfo, COL_INFO)) {
+  if (check_col(pinfo->cinfo, COL_INFO))
     col_add_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(message_class * 256 + message_type, message_class_type_acro_values, "reserved"));
-    col_set_fence(pinfo->cinfo, COL_INFO);
-  };
 
   if (sua_tree) {
     /* add the components of the common header to the protocol tree */
@@ -532,7 +537,6 @@ static const value_string error_code_values[] = {
   { 0x14, "Destination status unknown" },
   { 0x15, "Invalid network appearance" },
   { 0x16, "Missing parameter" },
-  { 0x17, "Routing key change refused" },
   { 0x19, "Invalid routing context" },
   { 0x1a, "No configured AS for ASP" },
   { 0x1b, "Subsystem status unknown" },
@@ -641,7 +645,7 @@ dissect_registration_result_parameter(tvbuff_t *parameter_tvb, proto_tree *param
   tvbuff_t *parameters_tvb;
   
   parameters_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, -1, -1);
-  dissect_parameters(parameters_tvb, parameter_tree);
+  dissect_parameters(parameters_tvb, parameter_tree, NULL, NULL, NULL);
 }
 
 static void
@@ -650,7 +654,7 @@ dissect_deregistration_result_parameter(tvbuff_t *parameter_tvb, proto_tree *par
   tvbuff_t *parameters_tvb;
   
   parameters_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, -1, -1);
-  dissect_parameters(parameters_tvb, parameter_tree);
+  dissect_parameters(parameters_tvb, parameter_tree, NULL, NULL, NULL);
 }
 
 #define REGISTRATION_STATUS_LENGTH 4
@@ -668,6 +672,7 @@ static const value_string registration_status_values[] = {
   {  8,            "Error - insufficient resources" },
   {  9,            "Error - unsupported RK parameter field" },
   { 10,            "Error - unsupported/invalid traffic mode type" },
+  { 11,            "Error - routing key change refused" },
   {  0,            NULL } };
 
 static void
@@ -744,41 +749,45 @@ static const value_string routing_indicator_values[] = {
 #define ADDRESS_SSN_BITMASK      0x0001
 
 static void
-dissect_source_address_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
+dissect_source_address_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, guint8 *ssn)
 {
   proto_item *address_indicator_item;
   proto_tree *address_indicator_tree;
   tvbuff_t *parameters_tvb;
   
-  proto_tree_add_item(parameter_tree, hf_source_address_routing_indicator, parameter_tvb, ROUTING_INDICATOR_OFFSET, ROUTING_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  address_indicator_item = proto_tree_add_text(parameter_tree, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, "Address Indicator");
-  address_indicator_tree = proto_item_add_subtree(address_indicator_item, ett_sua_source_address_indicator);
-  proto_tree_add_item(address_indicator_tree, hf_source_address_reserved_bits, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(address_indicator_tree, hf_source_address_gt_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(address_indicator_tree, hf_source_address_pc_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(address_indicator_tree, hf_source_address_ssn_bit,       parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+  if(parameter_tree) {
+    proto_tree_add_item(parameter_tree, hf_source_address_routing_indicator, parameter_tvb, ROUTING_INDICATOR_OFFSET, ROUTING_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    address_indicator_item = proto_tree_add_text(parameter_tree, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, "Address Indicator");
+    address_indicator_tree = proto_item_add_subtree(address_indicator_item, ett_sua_source_address_indicator);
+    proto_tree_add_item(address_indicator_tree, hf_source_address_reserved_bits, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(address_indicator_tree, hf_source_address_gt_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(address_indicator_tree, hf_source_address_pc_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(address_indicator_tree, hf_source_address_ssn_bit,       parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+  }
 
   parameters_tvb = tvb_new_subset(parameter_tvb, ADDRESS_PARAMETERS_OFFSET, -1, -1);
-  dissect_parameters(parameters_tvb, parameter_tree);
+  dissect_parameters(parameters_tvb, parameter_tree, NULL, ssn, NULL);
 }
 
 static void
-dissect_destination_address_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
+dissect_destination_address_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, guint8 *ssn)
 {
   proto_item *address_indicator_item;
   proto_tree *address_indicator_tree;
   tvbuff_t *parameters_tvb;
 
-  proto_tree_add_item(parameter_tree, hf_destination_address_routing_indicator, parameter_tvb, ROUTING_INDICATOR_OFFSET, ROUTING_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  address_indicator_item = proto_tree_add_text(parameter_tree, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, "Address Indicator");
-  address_indicator_tree = proto_item_add_subtree(address_indicator_item, ett_sua_destination_address_indicator);
-  proto_tree_add_item(address_indicator_tree, hf_destination_address_reserved_bits, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(address_indicator_tree, hf_destination_address_gt_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(address_indicator_tree, hf_destination_address_pc_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(address_indicator_tree, hf_destination_address_ssn_bit,       parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+  if(parameter_tree) {
+    proto_tree_add_item(parameter_tree, hf_destination_address_routing_indicator, parameter_tvb, ROUTING_INDICATOR_OFFSET, ROUTING_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    address_indicator_item = proto_tree_add_text(parameter_tree, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, "Address Indicator");
+    address_indicator_tree = proto_item_add_subtree(address_indicator_item, ett_sua_destination_address_indicator);
+    proto_tree_add_item(address_indicator_tree, hf_destination_address_reserved_bits, parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(address_indicator_tree, hf_destination_address_gt_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(address_indicator_tree, hf_destination_address_pc_bit,        parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(address_indicator_tree, hf_destination_address_ssn_bit,       parameter_tvb, ADDRESS_INDICATOR_OFFSET, ADDRESS_INDICATOR_LENGTH, NETWORK_BYTE_ORDER);
+  }
 
   parameters_tvb = tvb_new_subset(parameter_tvb, ADDRESS_PARAMETERS_OFFSET, -1, -1);
-  dissect_parameters(parameters_tvb, parameter_tree);
+  dissect_parameters(parameters_tvb, parameter_tree, NULL, NULL, ssn);
 }
 
 #define SOURCE_REFERENCE_NUMBER_LENGTH 4
@@ -929,13 +938,21 @@ dissect_credit_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, pr
 #define DATA_PARAMETER_DATA_OFFSET PARAMETER_VALUE_OFFSET
 
 static void
-dissect_data_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
+dissect_data_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, tvbuff_t **data_tvb)
 {
   guint16 data_length;
 
   data_length    = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
-  proto_tree_add_item(parameter_tree, hf_data, parameter_tvb, DATA_PARAMETER_DATA_OFFSET, data_length, NETWORK_BYTE_ORDER);
-  proto_item_append_text(parameter_item, " (SS7 message of %u byte%s)", data_length, plurality(data_length, "", "s"));
+
+  if(parameter_tree) {
+    proto_tree_add_item(parameter_tree, hf_data, parameter_tvb, DATA_PARAMETER_DATA_OFFSET, data_length, NETWORK_BYTE_ORDER);
+    proto_item_append_text(parameter_item, " (SS7 message of %u byte%s)", data_length, plurality(data_length, "", "s"));
+  }
+  
+  if(data_tvb)
+  {
+    *data_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, data_length, data_length);
+  }
 }
 
 
@@ -973,7 +990,7 @@ dissect_routing_key_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tre
   tvbuff_t *parameters_tvb;
 
   parameters_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, -1, -1);
-  dissect_parameters(parameters_tvb, parameter_tree);
+  dissect_parameters(parameters_tvb, parameter_tree, NULL, NULL, NULL);
 }
 #define DRN_START_LENGTH 1
 #define DRN_END_LENGTH 1
@@ -1015,7 +1032,7 @@ dissect_address_range_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_t
   tvbuff_t *parameters_tvb;
   
   parameters_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, -1, -1);
-  dissect_parameters(parameters_tvb, parameter_tree);
+  dissect_parameters(parameters_tvb, parameter_tree, NULL, NULL, NULL);
 }
 
 #define SMI_LENGTH 1
@@ -1124,12 +1141,14 @@ dissect_congestion_level_parameter(tvbuff_t *parameter_tvb, proto_tree *paramete
   proto_item_append_text(parameter_item, " (%u)", tvb_get_ntohl(parameter_tvb, CONGESTION_LEVEL_OFFSET));
 }
 
+#define GTI_LENGTH               1
 #define NO_OF_DIGITS_LENGTH      1
 #define TRANSLATION_TYPE_LENGTH  1
 #define NUMBERING_PLAN_LENGTH    1
 #define NATURE_OF_ADDRESS_LENGTH 1
 
-#define NO_OF_DIGITS_OFFSET      PARAMETER_VALUE_OFFSET
+#define GTI_OFFSET               (PARAMETER_VALUE_OFFSET + RESERVED_3_LENGTH)
+#define NO_OF_DIGITS_OFFSET      (GTI_OFFSET + GTI_LENGTH)
 #define TRANSLATION_TYPE_OFFSET  (NO_OF_DIGITS_OFFSET + NO_OF_DIGITS_LENGTH)
 #define NUMBERING_PLAN_OFFSET    (TRANSLATION_TYPE_OFFSET + TRANSLATION_TYPE_LENGTH)
 #define NATURE_OF_ADDRESS_OFFSET (NUMBERING_PLAN_OFFSET + NUMBERING_PLAN_LENGTH)
@@ -1175,7 +1194,9 @@ dissect_global_title_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tr
   guint16 global_title_length;
 
   global_title_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - 
-                        (PARAMETER_HEADER_LENGTH + NO_OF_DIGITS_LENGTH + TRANSLATION_TYPE_LENGTH + NUMBERING_PLAN_LENGTH + NATURE_OF_ADDRESS_LENGTH);
+                        (PARAMETER_HEADER_LENGTH + RESERVED_3_LENGTH + GTI_LENGTH + NO_OF_DIGITS_LENGTH + TRANSLATION_TYPE_LENGTH + NUMBERING_PLAN_LENGTH + NATURE_OF_ADDRESS_LENGTH);
+  proto_tree_add_item(parameter_tree, hf_gt_reserved,       parameter_tvb, PARAMETER_VALUE_OFFSET,   RESERVED_3_LENGTH,        NETWORK_BYTE_ORDER);
+  proto_tree_add_item(parameter_tree, hf_gti,               parameter_tvb, GTI_OFFSET,               GTI_LENGTH,               NETWORK_BYTE_ORDER);
   proto_tree_add_item(parameter_tree, hf_number_of_digits,  parameter_tvb, NO_OF_DIGITS_OFFSET,      NO_OF_DIGITS_LENGTH,      NETWORK_BYTE_ORDER);
   proto_tree_add_item(parameter_tree, hf_translation_type,  parameter_tvb, TRANSLATION_TYPE_OFFSET,  TRANSLATION_TYPE_LENGTH,  NETWORK_BYTE_ORDER);
   proto_tree_add_item(parameter_tree, hf_numbering_plan,    parameter_tvb, NUMBERING_PLAN_OFFSET,    NUMBERING_PLAN_LENGTH,    NETWORK_BYTE_ORDER);
@@ -1195,14 +1216,18 @@ dissect_point_code_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree
 
 #define SSN_LENGTH 1
 #define SSN_OFFSET (PARAMETER_VALUE_OFFSET + RESERVED_3_LENGTH)
+#define INVALID_SSN 0xff
 
 static void
-dissect_ssn_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
+dissect_ssn_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, guint8 *ssn)
 {
-  proto_tree_add_item(parameter_tree, hf_ssn_reserved, parameter_tvb, PARAMETER_VALUE_OFFSET, RESERVED_3_LENGTH, NETWORK_BYTE_ORDER);
-  proto_tree_add_item(parameter_tree, hf_ssn_number,   parameter_tvb, SSN_OFFSET,             SSN_LENGTH,        NETWORK_BYTE_ORDER);
+  *ssn = tvb_get_guint8(parameter_tvb,  SSN_OFFSET);
 
-  proto_item_append_text(parameter_item, " (%u)", tvb_get_guint8(parameter_tvb,  SSN_OFFSET));
+  if(parameter_tree) {
+    proto_tree_add_item(parameter_tree, hf_ssn_reserved, parameter_tvb, PARAMETER_VALUE_OFFSET, RESERVED_3_LENGTH, NETWORK_BYTE_ORDER);
+    proto_tree_add_item(parameter_tree, hf_ssn_number,   parameter_tvb, SSN_OFFSET,             SSN_LENGTH,        NETWORK_BYTE_ORDER);
+    proto_item_append_text(parameter_item, " (%u)", *ssn);
+  }
 }
 
 #define IPV4_ADDRESS_LENGTH 4
@@ -1249,171 +1274,273 @@ dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, p
 }
 
 static void
-dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *tree)
+dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *tree, tvbuff_t **data_tvb, guint8 *source_ssn, guint8 *dest_ssn)
 {
   guint16 tag, length, padding_length;
   proto_item *parameter_item;
   proto_tree *parameter_tree;
+  guint8 ssn = INVALID_SSN;
 
   /* extract tag and length from the parameter */
   tag            = tvb_get_ntohs(parameter_tvb, PARAMETER_TAG_OFFSET);
   length         = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
   padding_length = tvb_length(parameter_tvb) - length;
 
-  /* create proto_tree stuff */
-  parameter_item   = proto_tree_add_text(tree, parameter_tvb, PARAMETER_HEADER_OFFSET, tvb_length(parameter_tvb), val_to_str(tag, parameter_tag_values, "Unknown parameter"));
-  parameter_tree   = proto_item_add_subtree(parameter_item, ett_sua_parameter);
-
-  /* add tag and length to the sua tree */
-  proto_tree_add_item(parameter_tree, hf_parameter_tag,    parameter_tvb, PARAMETER_TAG_OFFSET,    PARAMETER_TAG_LENGTH,    NETWORK_BYTE_ORDER);
-  proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, NETWORK_BYTE_ORDER);
+  if (tree) {
+    /* create proto_tree stuff */
+    parameter_item   = proto_tree_add_text(tree, parameter_tvb, PARAMETER_HEADER_OFFSET, tvb_length(parameter_tvb), val_to_str(tag, parameter_tag_values, "Unknown parameter"));
+    parameter_tree   = proto_item_add_subtree(parameter_item, ett_sua_parameter);
 
+    /* add tag and length to the sua tree */
+    proto_tree_add_item(parameter_tree, hf_parameter_tag,    parameter_tvb, PARAMETER_TAG_OFFSET,    PARAMETER_TAG_LENGTH,    NETWORK_BYTE_ORDER);
+    proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, NETWORK_BYTE_ORDER);
+  } else {
+    parameter_tree = NULL;
+    parameter_item = NULL;
+  }
+/*
+** If no tree, only the data and ssn parameters in the source and destination
+** address need to be dissected. This in order to make dissection of the data
+** possible when there is no tree.
+*/
   switch(tag) {
   case DATA_PARAMETER_TAG:
-    dissect_data_parameter(parameter_tvb, parameter_tree, parameter_item);
+    dissect_data_parameter(parameter_tvb, parameter_tree, parameter_item, data_tvb);
     break;
   case INFO_STRING_PARAMETER_TAG:
-    dissect_info_string_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_info_string_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case ROUTING_CONTEXT_PARAMETER_TAG:
-    dissect_routing_context_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_routing_context_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case DIAGNOSTIC_INFO_PARAMETER_TAG:
-    dissect_diagnostic_information_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_diagnostic_information_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case HEARTBEAT_DATA_PARAMETER_TAG:
-    dissect_heartbeat_data_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_heartbeat_data_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case TRAFFIC_MODE_TYPE_PARAMETER_TAG:
-    dissect_traffic_mode_type_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_traffic_mode_type_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case ERROR_CODE_PARAMETER_TAG:
-    dissect_error_code_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_error_code_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case STATUS_PARAMETER_TAG:
-    dissect_status_type_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_status_type_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case CONGESTION_LEVEL_PARAMETER_TAG:
-    dissect_congestion_level_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_congestion_level_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case ASP_IDENTIFIER_PARAMETER_TAG:
-    dissect_asp_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_asp_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case AFFECTED_POINT_CODE_PARAMETER_TAG:
-    dissect_affected_destinations_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_affected_destinations_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case REGISTRATION_STATUS_PARAMETER_TAG:
-    dissect_registration_status_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_registration_status_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case DEREGISTRATION_STATUS_PARAMETER_TAG:
-    dissect_deregistration_status_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_deregistration_status_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case LOCAL_ROUTING_KEY_IDENTIFIER_PARAMETER_TAG:
-    dissect_local_routing_key_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_local_routing_key_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case SS7_HOP_COUNTER_PARAMETER_TAG:
-    dissect_ss7_hop_counter_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_ss7_hop_counter_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case SOURCE_ADDRESS_PARAMETER_TAG:
-    dissect_source_address_parameter(parameter_tvb, parameter_tree);
+    dissect_source_address_parameter(parameter_tvb, parameter_tree, source_ssn);
     break;
   case DESTINATION_ADDRESS_PARAMETER_TAG:
-    dissect_destination_address_parameter(parameter_tvb, parameter_tree);
+    dissect_destination_address_parameter(parameter_tvb, parameter_tree, dest_ssn);
     break;
   case SOURCE_REFERENCE_NUMBER_PARAMETER_TAG:
-    dissect_source_reference_number_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_source_reference_number_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case DESTINATION_REFERENCE_NUMBER_PARAMETER_TAG:
-    dissect_destination_reference_number_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_destination_reference_number_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case SCCP_CAUSE_PARAMETER_TAG:
-    dissect_sccp_cause_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_sccp_cause_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case SEQUENCE_NUMBER_PARAMETER_TAG:
-    dissect_sequence_number_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_sequence_number_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case RECEIVE_SEQUENCE_NUMBER_PARAMETER_TAG:
-    dissect_receive_sequence_number_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_receive_sequence_number_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case ASP_CAPABILITIES_PARAMETER_TAG:
-    dissect_asp_capabilities_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_asp_capabilities_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case CREDIT_PARAMETER_TAG:
-    dissect_credit_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_credit_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case USER_CAUSE_PARAMETER_TAG:
-    dissect_user_cause_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_user_cause_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case NETWORK_APPEARANCE_PARAMETER_TAG:
-    dissect_network_appearance_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_network_appearance_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case ROUTING_KEY_PARAMETER_TAG:
-    dissect_routing_key_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_routing_key_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case REGISTRATION_RESULT_PARAMETER_TAG:
-    dissect_registration_result_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_registration_result_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case DEREGISTRATION_RESULT_PARAMETER_TAG:
-    dissect_deregistration_result_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_deregistration_result_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case ADDRESS_RANGE_PARAMETER_TAG:
-    dissect_address_range_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_address_range_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case CORRELATION_ID_PARAMETER_TAG:
-    dissect_correlation_id_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_correlation_id_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case IMPORTANCE_PARAMETER_TAG:
-    dissect_importance_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_importance_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case MESSAGE_PRIORITY_PARAMETER_TAG:
-    dissect_message_priority_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_message_priority_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case PROTOCOL_CLASS_PARAMETER_TAG:
-    dissect_protocol_class_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_protocol_class_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case SEQUENCE_CONTROL_PARAMETER_TAG:
-    dissect_sequence_control_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_sequence_control_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case SEGMENTATION_PARAMETER_TAG:
-    dissect_segmentation_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_segmentation_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case SMI_PARAMETER_TAG:
-    dissect_smi_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_smi_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case TID_LABEL_PARAMETER_TAG:
-    dissect_tid_label_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_tid_label_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case DRN_LABEL_PARAMETER_TAG:
-    dissect_drn_label_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_drn_label_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case GLOBAL_TITLE_PARAMETER_TAG:
-    dissect_global_title_parameter(parameter_tvb, parameter_tree);
+    if (parameter_tree) {
+      dissect_global_title_parameter(parameter_tvb, parameter_tree);
+    }
     break;
   case POINT_CODE_PARAMETER_TAG:
-    dissect_point_code_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_point_code_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case SUBSYSTEM_NUMBER_PARAMETER_TAG:
-    dissect_ssn_parameter(parameter_tvb, parameter_tree, parameter_item);
+    dissect_ssn_parameter(parameter_tvb, parameter_tree, parameter_item, &ssn);
+    if(source_ssn)
+    {
+        *source_ssn = ssn;
+    }
+    if(dest_ssn)
+    {
+        *dest_ssn = ssn;
+    }
     break;
   case IPV4_ADDRESS_PARAMETER_TAG:
-    dissect_ipv4_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_ipv4_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case HOSTNAME_PARAMETER_TAG:
-    dissect_hostname_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_hostname_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   case IPV6_ADDRESS_PARAMETER_TAG:
-    dissect_ipv6_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_ipv6_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   default:
-    dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
+    if (parameter_tree) {
+      dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
+    }
     break;
   };
-  if (padding_length > 0)
+  if (parameter_tree && (padding_length > 0))
     proto_tree_add_item(parameter_tree, hf_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, NETWORK_BYTE_ORDER);
 }
 
 static void
-dissect_parameters(tvbuff_t *parameters_tvb, proto_tree *tree)
+dissect_parameters(tvbuff_t *parameters_tvb, proto_tree *tree, tvbuff_t **data_tvb, guint8 *source_ssn, guint8 *dest_ssn)
 {
   gint offset, length, total_length, remaining_length;
   tvbuff_t *parameter_tvb;
@@ -1426,24 +1553,39 @@ dissect_parameters(tvbuff_t *parameters_tvb, proto_tree *tree)
       total_length = MIN(total_length, remaining_length);
     /* create a tvb for the parameter including the padding bytes */
     parameter_tvb  = tvb_new_subset(parameters_tvb, offset, total_length, total_length);
-    dissect_parameter(parameter_tvb, tree);
+    dissect_parameter(parameter_tvb, tree, data_tvb, source_ssn, dest_ssn);
     /* get rid of the handled parameter */
     offset += total_length;
   }
 }
 
 static void
-dissect_sua_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *sua_tree)
+dissect_sua_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *sua_tree, proto_tree *tree)
 {
   tvbuff_t *common_header_tvb;
   tvbuff_t *parameters_tvb;
+  tvbuff_t *data_tvb = NULL;
+  guint8 source_ssn = INVALID_SSN;
+  guint8 dest_ssn = INVALID_SSN;
 
   common_header_tvb = tvb_new_subset(message_tvb, COMMON_HEADER_OFFSET, COMMON_HEADER_LENGTH, COMMON_HEADER_LENGTH);
   dissect_common_header(common_header_tvb, pinfo, sua_tree);
 
-  if (sua_tree) {
-       parameters_tvb = tvb_new_subset(message_tvb, COMMON_HEADER_LENGTH, -1, -1);
-    dissect_parameters(parameters_tvb, sua_tree);
+  parameters_tvb = tvb_new_subset(message_tvb, COMMON_HEADER_LENGTH, -1, -1);
+  dissect_parameters(parameters_tvb, sua_tree, &data_tvb, &source_ssn, &dest_ssn);
+
+  /* If there was SUA data it could be dissected */
+  if(data_tvb)
+  {
+    /* Try subdissectors (if we found a valid SSN on the current message) */
+    if ((dest_ssn == INVALID_SSN ||
+       !dissector_try_port(sua_ssn_dissector_table, dest_ssn, data_tvb, pinfo, tree))
+       && (source_ssn == INVALID_SSN ||
+       !dissector_try_port(sua_ssn_dissector_table, source_ssn, data_tvb, pinfo, tree)))
+    {
+      /* No sub-dissection occured, treat it as raw data */
+      call_dissector(data_handle, data_tvb, pinfo, sua_tree);
+    }
   }
 }
 
@@ -1457,6 +1599,10 @@ dissect_sua(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree)
   if (check_col(pinfo->cinfo, COL_PROTOCOL))
      col_set_str(pinfo->cinfo, COL_PROTOCOL, "SUA");
 
+  /* Clear entries in Info column on summary display */
+  if (check_col(pinfo->cinfo, COL_INFO))
+     col_clear(pinfo->cinfo, COL_INFO);
+
   /* In the interest of speed, if "tree" is NULL, don't do any work not
      necessary to generate protocol tree items. */
   if (tree) {
@@ -1468,7 +1614,7 @@ dissect_sua(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree)
   };
 
   /* dissect the message */
-  dissect_sua_message(message_tvb, pinfo, sua_tree);
+  dissect_sua_message(message_tvb, pinfo, sua_tree, tree);
 }
 
 /* Register the protocol with Ethereal */
@@ -1490,7 +1636,7 @@ proto_register_sua(void)
     { &hf_info_string,                           { "Info string",                  "sua.info_string",                               FT_STRING,  BASE_NONE, NULL,                               0x0,                      "", HFILL } },
     { &hf_routing_context,                       { "Routing context",              "sua.routing_context",                           FT_UINT32,  BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
     { &hf_diagnostic_information_info,           { "Diagnostic Information",       "sua.diagnostic_information",                    FT_BYTES,   BASE_NONE, NULL,                               0x0,                      "", HFILL } },
-    { &hf_heartbeat_data,                        { "Heratbeat Data",               "sua.heartbeat_data",                            FT_BYTES,   BASE_NONE, NULL,                               0x0,                      "", HFILL } },
+    { &hf_heartbeat_data,                        { "Heartbeat Data",               "sua.heartbeat_data",                            FT_BYTES,   BASE_NONE, NULL,                               0x0,                      "", HFILL } },
     { &hf_traffic_mode_type,                     { "Traffic mode Type",            "sua.traffic_mode_type",                         FT_UINT32,  BASE_DEC,  VALS(traffic_mode_type_values),     0x0,                      "", HFILL } },
     { &hf_error_code,                            { "Error code",                   "sua.error_code",                                FT_UINT32,  BASE_DEC,  VALS(error_code_values),            0x0,                      "", HFILL } },
     { &hf_status_type,                           { "Status type",                  "sua.status_type",                               FT_UINT16,  BASE_DEC,  VALS(status_type_values),           0x0,                      "", HFILL } },
@@ -1560,15 +1706,16 @@ proto_register_sua(void)
     { &hf_drn_label_start,                       { "Start",                        "sua.drn_label_start",                           FT_UINT8,   BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
     { &hf_drn_label_end,                         { "End",                          "sua.drn_label_end",                             FT_UINT8,   BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
     { &hf_drn_label_value,                       { "Label Value",                  "sua.drn_label_value",                           FT_UINT16,  BASE_HEX,  NULL,                               0x0,                      "", HFILL } },
+    { &hf_gt_reserved,                           { "Reserved",                     "sua.gt_reserved",                               FT_BYTES,   BASE_NONE, NULL,                               0x0,                      "", HFILL } },
+    { &hf_gti,                                   { "GTI",                          "sua.gti",                                       FT_UINT8,   BASE_HEX,  NULL,                               0x0,                      "", HFILL } },
     { &hf_number_of_digits,                      { "Number of Digits",             "sua.global_title_number_of_digits",             FT_UINT8,   BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
     { &hf_translation_type,                      { "Translation Type",             "sua.global_title_translation_type",             FT_UINT8,   BASE_HEX,  NULL,                               0x0,                      "", HFILL } },
     { &hf_numbering_plan,                        { "Numbering Plan",               "sua.global_title_numbering_plan",               FT_UINT8,   BASE_HEX,  VALS(numbering_plan_values),        0x0,                      "", HFILL } },
     { &hf_nature_of_address,                     { "Nature of Address",            "sua.global_title_nature_of_address",            FT_UINT8,   BASE_HEX,  VALS(nature_of_address_values),     0x0,                      "", HFILL } },
-    { &hf_nature_of_address,                     { "Nature Of Address",            "sua.global_title_nature_of_address",            FT_UINT8,   BASE_HEX,  VALS(nature_of_address_values),     0x0,                      "", HFILL } },
     { &hf_global_title,                          { "Global Title",                 "sua.global_title_signals",                      FT_BYTES,   BASE_NONE, NULL,                               0x0,                      "", HFILL } },
     { &hf_point_code_dpc,                        { "Point Code",                   "sua.point_code",                                FT_UINT32,  BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
     { &hf_ssn_reserved,                          { "Reserved",                     "sua.ssn_reserved",                              FT_BYTES,   BASE_NONE, NULL,                               0x0,                      "", HFILL } },
-    { &hf_ssn_number,                            { "Subsystem Number",             "sua.ssn_number",                                FT_UINT8,   BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
+    { &hf_ssn_number,                            { "Subsystem Number",             "sua.ssn",                                       FT_UINT8,   BASE_DEC,  NULL,                               0x0,                      "", HFILL } },
     { &hf_ipv4,                                  { "IP Version 4 address",         "sua.ipv4_address",                              FT_IPv4,    BASE_NONE, NULL,                               0x0,                      "", HFILL } },
     { &hf_hostname,                              { "Hostname",                     "sua.hostname.name",                             FT_STRING,  BASE_NONE, NULL,                               0x0,                      "", HFILL } },
     { &hf_ipv6,                                  { "IP Version 6 address",         "sua.ipv6_address",                              FT_IPv6,    BASE_NONE, NULL,                               0x0,                      "", HFILL } },
@@ -1599,6 +1746,8 @@ proto_register_sua(void)
 
   sua_module = prefs_register_protocol(proto_sua, NULL);
   prefs_register_obsolete_preference(sua_module, "sua_version");
+
+  sua_ssn_dissector_table = register_dissector_table("sua.ssn", "SUA SSN", FT_UINT8, BASE_DEC);
 }
 
 void
@@ -1609,4 +1758,6 @@ proto_reg_handoff_sua(void)
   sua_handle = create_dissector_handle(dissect_sua, proto_sua);
   dissector_add("sctp.ppi",  SUA_PAYLOAD_PROTOCOL_ID, sua_handle);
   dissector_add("sctp.port", SCTP_PORT_SUA,           sua_handle);
+
+  data_handle = find_dissector("data");
 }