Use "val_to_str()" to translate numerical values to strings, don't
[obnox/wireshark/wip.git] / packet-sctp.c
index 4f5caf3f893e7123be32fe7ca3da6b49ffa1f6d8..8c32040fbcc1b1f0c401288376a7dd6acf70e1cf 100644 (file)
@@ -2,10 +2,10 @@
  * Routines for Stream Control Transmission Protocol dissection
  * Copyright 2000, Michael Tüxen <Michael.Tuexen@icn.siemens.de>
  *
- * $Id: packet-sctp.c,v 1.1 2000/07/21 12:56:58 gram Exp $
+ * $Id: packet-sctp.c,v 1.19 2001/07/03 04:56:46 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@unicom.net>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
  * Copied from README.developer
 # include <netinet/in.h>
 #endif
 
+#include <string.h>
+#include <glib.h>
+
 #ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-#  include <stdarg.h>
-# else
-#  include <varargs.h>
-# endif
 # include "snprintf.h"
 #endif
 
-#include <string.h>
-#include <glib.h>
-#include <packet.h>
-
-#include "packet-ip.h"
+#include "packet.h"
+#include "ipproto.h"
 
 /* Initialize the protocol and registered fields */
 static int proto_sctp = -1;
@@ -119,6 +114,9 @@ static int hf_sctp_cause_measure_of_staleness = -1;
 
 static int hf_sctp_cause_tsn = -1;
 
+static dissector_table_t sctp_port_dissector_table;
+static dissector_table_t sctp_ppi_dissector_table;
+
 /* Initialize the subtree pointers */
 static gint ett_sctp = -1;
 static gint ett_sctp_chunk = -1;
@@ -149,20 +147,20 @@ static gint ett_sctp_unrecognized_parameter_parameter = -1;
 static const value_string sctp_chunk_type_values[] = {
   { SCTP_DATA_CHUNK_ID,              "DATA" },
   { SCTP_INIT_CHUNK_ID,              "INIT" },
-  { SCTP_INIT_ACK_CHUNK_ID,          "INIT ACK" },
+  { SCTP_INIT_ACK_CHUNK_ID,          "INIT_ACK" },
   { SCTP_SACK_CHUNK_ID,              "SACK" },
   { SCTP_HEARTBEAT_CHUNK_ID,         "HEARTBEAT" },
-  { SCTP_HEARTBEAT_ACK_CHUNK_ID,     "HEARTBEAT ACK" },
+  { SCTP_HEARTBEAT_ACK_CHUNK_ID,     "HEARTBEAT_ACK" },
   { SCTP_ABORT_CHUNK_ID,             "ABORT" },
   { SCTP_SHUTDOWN_CHUNK_ID,          "SHUTDOWN" },
-  { SCTP_SHUTDOWN_ACK_CHUNK_ID,      "SHUTDOWN ACK" },
+  { SCTP_SHUTDOWN_ACK_CHUNK_ID,      "SHUTDOWN_ACK" },
   { SCTP_ERROR_CHUNK_ID,             "ERROR" },
-  { SCTP_COOKIE_ECHO_CHUNK_ID,       "COOKIE ECHO" },
-  { SCTP_COOKIE_ACK_CHUNK_ID,        "COOKIE ACK" },
+  { SCTP_COOKIE_ECHO_CHUNK_ID,       "COOKIE_ECHO" },
+  { SCTP_COOKIE_ACK_CHUNK_ID,        "COOKIE_ACK" },
   { SCTP_ECNE_CHUNK_ID,              "ECNE" },
   { SCTP_CWR_CHUNK_ID,               "CWR" },
-  { SCTP_SHUTDOWN_COMPLETE_CHUNK_ID, "SHUTDOWN COMPLETE" },
-  { SCTP_IETF_EXT,                   "IETF EXTENSION" },
+  { SCTP_SHUTDOWN_COMPLETE_CHUNK_ID, "SHUTDOWN_COMPLETE" },
+  { SCTP_IETF_EXT,                   "IETF_EXTENSION" },
   { 0,                               NULL } };
 
 #define HEARTBEAT_INFO_PARAMETER_ID          0x0001
@@ -260,6 +258,24 @@ static const value_string sctp_cause_code_values[] = {
   { COOKIE_RECEIVED_WHILE_SHUTTING_DOWN, "Cookie received while shutting down" },
   { 0,                           NULL } };
 
+#define NOT_SPECIFIED_PROTOCOL_ID  0
+#define IUA_PAYLOAD_PROTOCOL_ID    1
+#define M2UA_PAYLOAD_PROTOCOL_ID   2
+#define M3UA_PAYLOAD_PROTOCOL_ID   3
+#define SUA_PAYLOAD_PROTOCOL_ID    4
+#define M2PA_PAYLOAD_PROTOCOL_ID   5
+#define V5UA_PAYLOAD_PROTOCOL_ID   6
+
+static const value_string sctp_payload_proto_id_values[] = {
+  { NOT_SPECIFIED_PROTOCOL_ID,           "not specified" },
+  { IUA_PAYLOAD_PROTOCOL_ID,             "IUA" },
+  { M2UA_PAYLOAD_PROTOCOL_ID,            "M2UA" },
+  { M3UA_PAYLOAD_PROTOCOL_ID,            "M3UA" },
+  { SUA_PAYLOAD_PROTOCOL_ID,             "SUA" },
+  { M2PA_PAYLOAD_PROTOCOL_ID,            "M2PA" },
+  { V5UA_PAYLOAD_PROTOCOL_ID,            "V5UA" },
+  { 0,                                   NULL } };
+
 /* The structure of the common header is described by the following constants */
 #define SOURCE_PORT_LENGTH      2
 #define DESTINATION_PORT_LENGTH 2
@@ -406,8 +422,9 @@ static const true_false_string sctp_shutdown_complete_chunk_t_bit_value = {
 #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
 #define DO16(buf)   DO8(buf,0); DO8(buf,8);
 
-unsigned int sctp_adler_32(const unsigned char* buf,
-                                unsigned int len)
+static unsigned int
+sctp_adler_32(const unsigned char* buf,
+             unsigned int len)
 {
     unsigned int s1 = 1L;
     unsigned int s2 = 0L;
@@ -445,7 +462,8 @@ unsigned int sctp_adler_32(const unsigned char* buf,
     return (s2 << 16) | s1;
 }
 
-static char *sctp_checksum_state(tvbuff_t *tvb, guint orig_checksum)
+static char 
+*sctp_checksum_state(tvbuff_t *tvb, guint orig_checksum)
 {
   guint length;
   
@@ -456,7 +474,7 @@ static char *sctp_checksum_state(tvbuff_t *tvb, guint orig_checksum)
     return "incorrect";
 }
 
-guint 
+static guint 
 nr_of_padding_bytes (guint length)
 {
   guint remainder;
@@ -473,13 +491,14 @@ nr_of_padding_bytes (guint length)
  * TLV parameter stuff for INIT and INIT-ACK chunks
  */
 
-void
+static void
 dissect_parameter(tvbuff_t *, proto_tree *);
 
-void
-dissect_sctp_chunk(tvbuff_t *, proto_tree *);
+static gboolean
+dissect_sctp_chunk(tvbuff_t *, packet_info *, proto_tree *, proto_tree *);
 
-void dissect_tlv_parameter_list(tvbuff_t *parameter_list_tvb, proto_tree *tree)
+static void 
+dissect_tlv_parameter_list(tvbuff_t *parameter_list_tvb, proto_tree *tree)
 {
   guint offset, length, padding_length, total_length;
   tvbuff_t *parameter_tvb;
@@ -497,7 +516,7 @@ void dissect_tlv_parameter_list(tvbuff_t *parameter_list_tvb, proto_tree *tree)
   }
 }
 
-void
+static void
 dissect_heartbeat_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint16 length, heartbeat_info_length;
@@ -514,7 +533,7 @@ dissect_heartbeat_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_
                      heartbeat_info_length, plurality(heartbeat_info_length, "", "s"));
 }
 
-void
+static void
 dissect_ipv4_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint32 ipv4_address;
@@ -526,7 +545,7 @@ dissect_ipv4_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, prot
   proto_item_set_text(parameter_item, "IPV4 address parameter");
 }
 
-void
+static void
 dissect_ipv6_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   proto_tree_add_ipv6(parameter_tree, hf_sctp_parameter_ipv6_address,
@@ -536,7 +555,7 @@ dissect_ipv6_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, prot
   proto_item_set_text(parameter_item, "IPV6 address parameter");
 }
 
-void
+static void
 dissect_state_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint16 length, state_cookie_length;
@@ -553,15 +572,16 @@ dissect_state_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tr
                      state_cookie_length, plurality(state_cookie_length, "", "s"));
 }
 
-void
+static void
 dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
-  guint16 length, parameter_value_length;
+  guint16 length, padding_length, parameter_value_length;
   tvbuff_t *unrecognized_parameters_tvb;
 
   length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
-  
-  parameter_value_length = length - PARAMETER_HEADER_LENGTH;
+  padding_length = nr_of_padding_bytes(length);
+
+  parameter_value_length = length - PARAMETER_HEADER_LENGTH + padding_length;
 
   unrecognized_parameters_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, 
                                               parameter_value_length, parameter_value_length);
@@ -570,7 +590,7 @@ dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, proto_tree *p
   proto_item_set_text(parameter_item, "Unrecognized parameter of type");
 }
 
-void
+static void
 dissect_cookie_preservative_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint32 increment;
@@ -586,7 +606,7 @@ dissect_cookie_preservative_parameter(tvbuff_t *parameter_tvb, proto_tree *param
                      increment);
 }
 
-void
+static void
 dissect_hostname_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint16  length, hostname_length;
@@ -603,7 +623,7 @@ dissect_hostname_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree,
   proto_item_set_text(parameter_item, "Hostname parameter");
 }
 
-void
+static void
 dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint16 length, address_type, number_of_address_types, address_type_number, list_of_address_types_length ;
@@ -634,13 +654,13 @@ dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *p
                      number_of_address_types, plurality(number_of_address_types, "", "s"));
 }
 
-void
+static void
 dissect_ecn_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
    proto_item_set_text(parameter_item, "ECN parameter");
 }
 
-void
+static void
 dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
   guint16 type, length, parameter_value_length;
@@ -658,7 +678,7 @@ dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, p
                      type, parameter_value_length, plurality(parameter_value_length, "", "s"));
 }
 
-void
+static void
 dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
 {
   guint16 type, length, padding_length, total_length;
@@ -713,7 +733,7 @@ dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
     dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
     break;
   };
-  if (padding_length > 0)
+  if ((padding_length > 0) && (type != UNREC_PARA_PARAMETER_ID))
     proto_tree_add_text(parameter_tree, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length,
                        "Padding: %u byte%s",
                        padding_length, plurality(padding_length, "", "s"));
@@ -722,7 +742,7 @@ dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
 /*
  * Code to handle error causes for ABORT and ERROR chunks
  */
-void
+static void
 dissect_invalid_stream_identifier_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint16 stream_identifier;
@@ -738,7 +758,7 @@ dissect_invalid_stream_identifier_cause(tvbuff_t *cause_tvb, proto_tree *cause_t
                      stream_identifier);
 }
 
-void
+static void
 dissect_missing_mandatory_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint32 number_of_missing_parameters, missing_parameter_number;
@@ -764,7 +784,7 @@ dissect_missing_mandatory_parameters_cause(tvbuff_t *cause_tvb, proto_tree *caus
                      number_of_missing_parameters, plurality(number_of_missing_parameters, "", "s") );
 }
 
-void
+static void
 dissect_stale_cookie_error_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint32 measure_of_staleness;
@@ -780,13 +800,13 @@ dissect_stale_cookie_error_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, pr
                      measure_of_staleness);
 }
 
-void
+static void
 dissect_out_of_resource_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   proto_item_set_text(cause_item, "Error cause reporting lack of resources");
 }
 
-void
+static void
 dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint16 code, length, parameter_length, parameter_type;
@@ -806,8 +826,9 @@ dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree,
                      parameter_type, val_to_str(parameter_type, sctp_parameter_identifier_values, "unknown") );
 }
 
-void
-dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
+static void
+dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb,  packet_info *pinfo, 
+                                     proto_tree *cause_tree, proto_item *cause_item)
 {
   guint16 length, chunk_length;
   guint8 unrecognized_type;
@@ -819,7 +840,7 @@ dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb, proto_tree *cause_tre
 
   unrecognized_chunk_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, 
                                          chunk_length, chunk_length);
-  dissect_sctp_chunk(unrecognized_chunk_tvb, cause_tree);
+  dissect_sctp_chunk(unrecognized_chunk_tvb, pinfo, cause_tree,cause_tree);
 
   unrecognized_type   = tvb_get_guint8(unrecognized_chunk_tvb, CHUNK_TYPE_OFFSET);
  
@@ -828,21 +849,22 @@ dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb, proto_tree *cause_tre
                      val_to_str(unrecognized_type, sctp_chunk_type_values, "unknown"));
 }
 
-void
+static void
 dissect_invalid_mandatory_parameter_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   proto_item_set_text(cause_item, "Error cause reporting an invalid mandatory parameter");
 }
 
-void
+static void
 dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
-  guint16 length, cause_info_length;
+  guint16 length, padding_length, cause_info_length;
   tvbuff_t *unrecognized_parameters_tvb;
 
   length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
-  
-  cause_info_length = length - CAUSE_HEADER_LENGTH;
+  padding_length = nr_of_padding_bytes(length);
+
+  cause_info_length = length - CAUSE_HEADER_LENGTH + padding_length;
 
   unrecognized_parameters_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, 
                                               cause_info_length, cause_info_length);
@@ -851,7 +873,7 @@ dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tre
   proto_item_set_text(cause_item, "Error cause reporting unrecognized parameters");
 }
 
-void
+static void
 dissect_no_user_data_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint32 tsn;
@@ -866,13 +888,13 @@ dissect_no_user_data_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_it
                      tsn);
 }
 
-void
+static void
 dissect_cookie_received_while_shutting_down_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   proto_item_set_text(cause_item, "Error cause reporting cookie reception while shutting down");
 }
 
-void
+static void
 dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint16 code, length, cause_info_length;
@@ -890,8 +912,8 @@ dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *c
                      code, cause_info_length, plurality(cause_info_length, "", "s"));
 }
 
-void
-dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *chunk_tree)
+static void
+dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_tree)
 {
   guint16 code, length, padding_length, total_length;
   proto_item *cause_item;
@@ -901,7 +923,7 @@ dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *chunk_tree)
   length         = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
   padding_length = nr_of_padding_bytes(length);
   total_length   = length + padding_length;
-  
+
   cause_item = proto_tree_add_notext(chunk_tree, cause_tvb, CAUSE_HEADER_OFFSET, total_length);
   proto_item_set_text(cause_item, "BAD ERROR CAUSE");
   cause_tree = proto_item_add_subtree(cause_item, ett_sctp_chunk_cause);
@@ -931,7 +953,7 @@ dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *chunk_tree)
     dissect_unresolvable_address_cause(cause_tvb, cause_tree, cause_item);
     break;
   case UNRECOGNIZED_CHUNK_TYPE:
-    dissect_unrecognized_chunk_type_cause(cause_tvb, cause_tree, cause_item);
+    dissect_unrecognized_chunk_type_cause(cause_tvb, pinfo, cause_tree, cause_item);
     break;
   case INVALID_MANDATORY_PARAMETER:
     dissect_invalid_mandatory_parameter_cause(cause_tvb, cause_tree, cause_item);
@@ -949,7 +971,7 @@ dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *chunk_tree)
     dissect_unknown_cause(cause_tvb, cause_tree, cause_item);
     break;
   };
-  if (padding_length > 0)
+  if ((padding_length > 0) && (code != UNRECOGNIZED_PARAMETERS))
     proto_tree_add_text(cause_tree, cause_tvb, CAUSE_HEADER_OFFSET + length, padding_length,
                        "Padding: %u byte%s",
                        padding_length, plurality(padding_length, "", "s"));
@@ -959,65 +981,88 @@ dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *chunk_tree)
  * Code to actually dissect the packets 
 */
 
-void
-dissect_data_chunk(tvbuff_t *chunk_tvb,
+static gboolean
+dissect_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree,
+               proto_tree *chunk_tree, guint32 ppi, guint16 payload_length, guint16 padding_length)
+{
+  /* do lookup with the subdissector table */
+  if (dissector_try_port (sctp_ppi_dissector_table, ppi,  payload_tvb, pinfo, tree) ||
+      dissector_try_port(sctp_port_dissector_table, pinfo->srcport,  payload_tvb, pinfo, tree) ||
+      dissector_try_port(sctp_port_dissector_table, pinfo->destport, payload_tvb, pinfo, tree)){
+    return TRUE;
+  }
+  else {
+    if (check_col(pinfo->fd, COL_INFO))
+      col_append_str(pinfo->fd, COL_INFO, "DATA ");
+    proto_tree_add_text(chunk_tree, payload_tvb, 0, payload_length,
+                       "Payload (%u byte%s)",
+                       payload_length, plurality(payload_length, "", "s")); 
+    if (padding_length > 0)
+      proto_tree_add_text(chunk_tree, payload_tvb, payload_length, padding_length,
+                         "Padding: %u byte%s",
+                         padding_length, plurality(padding_length, "", "s"));
+    return FALSE;
+  }
+}
+
+static gboolean
+dissect_data_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                   proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint8  flags;
-  guint16 length, payload_length, padding_length, stream_id, stream_seq_number;
+  guint16 length, total_payload_length, payload_length, padding_length, stream_id, stream_seq_number;
   guint32 tsn, payload_proto_id;
   proto_tree *flag_tree;
-
-  flags             = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
-  length            = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
+  tvbuff_t *payload_tvb;
    
-  flag_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
-  proto_tree_add_boolean(flag_tree, hf_sctp_data_chunk_e_bit, chunk_tvb,
-                        CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
-  proto_tree_add_boolean(flag_tree, hf_sctp_data_chunk_b_bit, chunk_tvb,
-                        CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
-  proto_tree_add_boolean(flag_tree, hf_sctp_data_chunk_u_bit, chunk_tvb,
-                        CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
-
-  tsn               = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
-  stream_id         = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
-  stream_seq_number = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
-  payload_proto_id  = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET);
-  
-  payload_length = length - DATA_CHUNK_HEADER_LENGTH;
-  padding_length = nr_of_padding_bytes(length);
-
-  proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_tsn, 
-                     chunk_tvb,
-                     DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH,
-                     tsn);
-  proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_stream_id, 
-                     chunk_tvb, 
-                     DATA_CHUNK_STREAM_ID_OFFSET, DATA_CHUNK_STREAM_ID_LENGTH,
-                     stream_id);
-  proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_stream_seq_number, 
-                     chunk_tvb, 
-                     DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET, DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH,
-                     stream_seq_number);
-  proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_payload_proto_id, 
-                     chunk_tvb,
-                     DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH,
-                     payload_proto_id);
-  proto_tree_add_text(chunk_tree, chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET, payload_length,
-                     "Payload (%u byte%s)",
-                     payload_length, plurality(payload_length, "", "s")); 
-  if (padding_length > 0)
-    proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length,
-                       "Padding: %u byte%s",
-                       padding_length, plurality(padding_length, "", "s"));
-  
-  proto_item_set_text(chunk_item, "DATA chunk with TSN %u (%u:%u) containing %u byte%s of payload",
-                     tsn, stream_id, stream_seq_number, 
-                     payload_length, plurality(payload_length, "", "s"));
-} 
+  length            = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
+  payload_length       = length - DATA_CHUNK_HEADER_LENGTH;
+  padding_length       = nr_of_padding_bytes(length);
+  total_payload_length = payload_length + padding_length;
+  payload_tvb          = tvb_new_subset(chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET,
+                                         total_payload_length, total_payload_length);
+  payload_proto_id     = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET);
+
+  if (chunk_tree) {
+    flags             = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
+     
+    flag_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
+    proto_tree_add_boolean(flag_tree, hf_sctp_data_chunk_e_bit, chunk_tvb,
+                          CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
+    proto_tree_add_boolean(flag_tree, hf_sctp_data_chunk_b_bit, chunk_tvb,
+                          CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
+    proto_tree_add_boolean(flag_tree, hf_sctp_data_chunk_u_bit, chunk_tvb,
+                          CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
+    
+    tsn               = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
+    stream_id         = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
+    stream_seq_number = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
+         
+    proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_tsn, 
+                       chunk_tvb,
+                       DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH,
+                       tsn);
+    proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_stream_id, 
+                       chunk_tvb, 
+                       DATA_CHUNK_STREAM_ID_OFFSET, DATA_CHUNK_STREAM_ID_LENGTH,
+                       stream_id);
+    proto_tree_add_uint(chunk_tree, hf_sctp_data_chunk_stream_seq_number, 
+                       chunk_tvb, 
+                       DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET, DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH,
+                       stream_seq_number);
+    proto_tree_add_uint_format(chunk_tree, hf_sctp_data_chunk_payload_proto_id, 
+                              chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH,
+                              payload_proto_id, "Payload protocol identifier: %u (%s)",
+                              payload_proto_id, val_to_str(payload_proto_id, sctp_payload_proto_id_values, "unknown"));
+    proto_item_set_text(chunk_item, "DATA chunk with TSN %u (%u:%u) containing %u byte%s of payload",
+                       tsn, stream_id, stream_seq_number, 
+                       payload_length, plurality(payload_length, "", "s"));
+  };   
+  return dissect_payload(payload_tvb, pinfo, tree, chunk_tree, payload_proto_id, payload_length, padding_length); 
+}
 
-void
-dissect_init_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_init_chunk(tvbuff_t *chunk_tvb,  packet_info *pinfo, proto_tree *tree,
                   proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint32 initiate_tag, adv_rec_window_credit, initial_tsn;
@@ -1026,55 +1071,65 @@ dissect_init_chunk(tvbuff_t *chunk_tvb,
   tvbuff_t *parameter_list_tvb;
 
   type                       = tvb_get_guint8(chunk_tvb, CHUNK_TYPE_OFFSET);
-  initiate_tag               = tvb_get_ntohl(chunk_tvb, INIT_CHUNK_INITIATE_TAG_OFFSET);
-  adv_rec_window_credit      = tvb_get_ntohl(chunk_tvb, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET);
-  number_of_inbound_streams  = tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET);
-  number_of_outbound_streams = tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET);
-  initial_tsn                = tvb_get_ntohl(chunk_tvb, INIT_CHUNK_INITIAL_TSN_OFFSET);
-
-  /* handle fixed parameters */
-  proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_initiate_tag, 
-                     chunk_tvb,
-                     INIT_CHUNK_INITIATE_TAG_OFFSET, INIT_CHUNK_INITIATE_TAG_LENGTH,
-                     initiate_tag);
-  proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_adv_rec_window_credit, 
-                     chunk_tvb,
-                     INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH,
-                     adv_rec_window_credit);
-  proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_number_of_outbound_streams, 
-                     chunk_tvb,
-                     INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH,
-                     number_of_outbound_streams);
-  proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_number_of_inbound_streams, 
-                     chunk_tvb,
-                     INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH,
-                     number_of_inbound_streams);
-  proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_initial_tsn, 
-                     chunk_tvb,
-                     INIT_CHUNK_INITIAL_TSN_OFFSET, INIT_CHUNK_INITIAL_TSN_LENGTH,
-                     initial_tsn);
   
-  /* handle variable paramters */
-  parameter_list_tvb = tvb_new_subset(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET, -1, -1);
-  dissect_tlv_parameter_list(parameter_list_tvb, chunk_tree);
-
-  proto_item_set_text(chunk_item, 
-                     "%s chunk requesting for %u outbound stream%s and accepting up to %u inbound stream%s",
-                     val_to_str(type, sctp_chunk_type_values, "unknown"),
-                     number_of_outbound_streams, plurality(number_of_outbound_streams, "", "s"),
-                     number_of_inbound_streams, plurality(number_of_inbound_streams, "", "s"));
+  if (check_col(pinfo->fd, COL_INFO)) {
+    if (type == SCTP_INIT_CHUNK_ID) {
+      col_append_str(pinfo->fd, COL_INFO, "INIT ");
+    } else {
+      col_append_str(pinfo->fd, COL_INFO, "INIT_ACK ");
+    };
+  };
+  
+  if (chunk_tree) {
+    initiate_tag               = tvb_get_ntohl(chunk_tvb, INIT_CHUNK_INITIATE_TAG_OFFSET);
+    adv_rec_window_credit      = tvb_get_ntohl(chunk_tvb, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET);
+    number_of_inbound_streams  = tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET);
+    number_of_outbound_streams = tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET);
+    initial_tsn                = tvb_get_ntohl(chunk_tvb, INIT_CHUNK_INITIAL_TSN_OFFSET);
+    
+    /* handle fixed parameters */
+    proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_initiate_tag, 
+                       chunk_tvb,
+                       INIT_CHUNK_INITIATE_TAG_OFFSET, INIT_CHUNK_INITIATE_TAG_LENGTH,
+                       initiate_tag);
+    proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_adv_rec_window_credit, 
+                       chunk_tvb,
+                       INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH,
+                       adv_rec_window_credit);
+    proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_number_of_outbound_streams, 
+                       chunk_tvb,
+                       INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH,
+                       number_of_outbound_streams);
+    proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_number_of_inbound_streams, 
+                       chunk_tvb,
+                       INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH,
+                       number_of_inbound_streams);
+    proto_tree_add_uint(chunk_tree, hf_sctp_init_chunk_initial_tsn, 
+                       chunk_tvb,
+                       INIT_CHUNK_INITIAL_TSN_OFFSET, INIT_CHUNK_INITIAL_TSN_LENGTH,
+                       initial_tsn);
+    
+    /* handle variable paramters */
+    parameter_list_tvb = tvb_new_subset(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET, -1, -1);
+    dissect_tlv_parameter_list(parameter_list_tvb, chunk_tree);
+    
+    proto_item_set_text(chunk_item, 
+                       "%s chunk requesting for %u outbound stream%s and accepting up to %u inbound stream%s",
+                       val_to_str(type, sctp_chunk_type_values, "unknown"),
+                       number_of_outbound_streams, plurality(number_of_outbound_streams, "", "s"),
+                       number_of_inbound_streams, plurality(number_of_inbound_streams, "", "s"));
+  }
 } 
 
-void
-dissect_init_ack_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_init_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                       proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
-  dissect_init_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+  dissect_init_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
 } 
 
-void
-dissect_sack_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_sack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                   proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint32 cumulative_tsn_ack, adv_rec_window_credit, dup_tsn;
@@ -1083,184 +1138,219 @@ dissect_sack_chunk(tvbuff_t *chunk_tvb,
   gint gap_block_offset, dup_tsn_offset;
   proto_item *block_item;
   proto_tree *block_tree;
-
-  cumulative_tsn_ack    = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
-  adv_rec_window_credit = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET);
-  number_of_gap_blocks  = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET);
-  number_of_dup_tsns    = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET);
-  
-  proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_cumulative_tsn_ack, 
-                     chunk_tvb,
-                     SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH,
-                     cumulative_tsn_ack);
-  proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_adv_rec_window_credit, 
-                     chunk_tvb,
-                     SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH,
-                     adv_rec_window_credit);
-  proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_number_of_gap_blocks, 
-                     chunk_tvb,
-                     SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH,
-                     number_of_gap_blocks);
-  proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_number_of_dup_tsns, 
-                     chunk_tvb,
-                     SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET, SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH,
-                     number_of_dup_tsns);
   
-  /* handle the gap acknowledgement blocks */
-  gap_block_offset = SACK_CHUNK_GAP_BLOCK_OFFSET;
-  for(gap_block_number = 1; gap_block_number <= number_of_gap_blocks; gap_block_number++) {
-    start = tvb_get_ntohs(chunk_tvb, gap_block_offset);
-    end   = tvb_get_ntohs(chunk_tvb, gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH);
-    block_item = proto_tree_add_text(chunk_tree, chunk_tvb,
-                                    gap_block_offset, SACK_CHUNK_GAP_BLOCK_LENGTH,
-                                    "Gap Acknowledgement for %u TSN%s",
-                                    1 + end - start, plurality(1 + end - start, "", "s"));
-    block_tree = proto_item_add_subtree(block_item, ett_sctp_sack_chunk_gap_block);
-    proto_tree_add_uint(block_tree, hf_sctp_sack_chunk_gap_block_start, 
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "SACK ");
+
+  if (chunk_tree) {
+    cumulative_tsn_ack    = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
+    adv_rec_window_credit = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET);
+    number_of_gap_blocks  = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET);
+    number_of_dup_tsns    = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET);
+    
+    proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_cumulative_tsn_ack, 
                        chunk_tvb,
-                       gap_block_offset, SACK_CHUNK_GAP_BLOCK_START_LENGTH,
-                       start);
-    proto_tree_add_uint(block_tree, hf_sctp_sack_chunk_gap_block_end
+                       SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH,
+                       cumulative_tsn_ack);
+    proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_adv_rec_window_credit
                        chunk_tvb,
-                       gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH,
-                       SACK_CHUNK_GAP_BLOCK_END_LENGTH,
-                       end);
-    gap_block_offset += SACK_CHUNK_GAP_BLOCK_LENGTH;
-  };
-  
-  /* handle the duplicate TSNs */
-  dup_tsn_offset = SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * SACK_CHUNK_GAP_BLOCK_LENGTH;
-  for(dup_tsn_number = 1; dup_tsn_number <= number_of_dup_tsns; dup_tsn_number++) {
-    dup_tsn = tvb_get_ntohl(chunk_tvb, dup_tsn_offset);
-    proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_duplicate_tsn, 
+                       SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH,
+                       adv_rec_window_credit);
+    proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_number_of_gap_blocks, 
                        chunk_tvb,
-                       dup_tsn, SACK_CHUNK_DUP_TSN_LENGTH,
-                       dup_tsn);
-    dup_tsn_offset += SACK_CHUNK_DUP_TSN_LENGTH;
-  };
-
-  proto_item_set_text(chunk_item, 
-                     "SACK chunk acknowledging TSN %u and reporting %u gap%s and %u duplicate TSN%s",
-                     cumulative_tsn_ack,
-                     number_of_gap_blocks, plurality(number_of_gap_blocks, "", "s"),
-                     number_of_dup_tsns, plurality(number_of_dup_tsns, "", "s"));
-} 
+                       SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH,
+                       number_of_gap_blocks);
+    proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_number_of_dup_tsns, 
+                       chunk_tvb,
+                       SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET, SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH,
+                       number_of_dup_tsns);
+    
+    /* handle the gap acknowledgement blocks */
+    gap_block_offset = SACK_CHUNK_GAP_BLOCK_OFFSET;
+    for(gap_block_number = 1; gap_block_number <= number_of_gap_blocks; gap_block_number++) {
+      start = tvb_get_ntohs(chunk_tvb, gap_block_offset);
+      end   = tvb_get_ntohs(chunk_tvb, gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH);
+      block_item = proto_tree_add_text(chunk_tree, chunk_tvb,
+                                      gap_block_offset, SACK_CHUNK_GAP_BLOCK_LENGTH,
+                                      "Gap Acknowledgement for %u TSN%s",
+                                      1 + end - start, plurality(1 + end - start, "", "s"));
+      block_tree = proto_item_add_subtree(block_item, ett_sctp_sack_chunk_gap_block);
+      proto_tree_add_uint(block_tree, hf_sctp_sack_chunk_gap_block_start, 
+                         chunk_tvb,
+                         gap_block_offset, SACK_CHUNK_GAP_BLOCK_START_LENGTH,
+                         start);
+      proto_tree_add_uint(block_tree, hf_sctp_sack_chunk_gap_block_end, 
+                         chunk_tvb,
+                         gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH,
+                         SACK_CHUNK_GAP_BLOCK_END_LENGTH,
+                         end);
+      gap_block_offset += SACK_CHUNK_GAP_BLOCK_LENGTH;
+    };
+    
+    /* handle the duplicate TSNs */
+    dup_tsn_offset = SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * SACK_CHUNK_GAP_BLOCK_LENGTH;
+    for(dup_tsn_number = 1; dup_tsn_number <= number_of_dup_tsns; dup_tsn_number++) {
+      dup_tsn = tvb_get_ntohl(chunk_tvb, dup_tsn_offset);
+      proto_tree_add_uint(chunk_tree, hf_sctp_sack_chunk_duplicate_tsn, 
+                         chunk_tvb,
+                         dup_tsn, SACK_CHUNK_DUP_TSN_LENGTH,
+                         dup_tsn);
+      dup_tsn_offset += SACK_CHUNK_DUP_TSN_LENGTH;
+    }
+    
+    proto_item_set_text(chunk_item, 
+                       "SACK chunk acknowledging TSN %u and reporting %u gap%s and %u duplicate TSN%s",
+                       cumulative_tsn_ack,
+                       number_of_gap_blocks, plurality(number_of_gap_blocks, "", "s"),
+                       number_of_dup_tsns, plurality(number_of_dup_tsns, "", "s"));
+  } 
+}
 
-void
-dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                        proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 {
   tvbuff_t   *parameter_tvb;
   guint chunk_length, info_length, padding_length, total_length;
-
-  chunk_length   = tvb_get_ntohs(chunk_tvb,  CHUNK_LENGTH_OFFSET);
-  info_length    = chunk_length - CHUNK_HEADER_LENGTH;
-  padding_length = nr_of_padding_bytes(info_length);
-  total_length   = info_length + padding_length;
-  parameter_tvb  = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET, total_length, total_length);
     
-  dissect_parameter(parameter_tvb, chunk_tree);
-
-  proto_item_set_text(chunk_item, "HEARTBEAT chunk");
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "HEARTBEAT ");
+
+  if (chunk_tree) {
+    chunk_length   = tvb_get_ntohs(chunk_tvb,  CHUNK_LENGTH_OFFSET);
+    info_length    = chunk_length - CHUNK_HEADER_LENGTH;
+    padding_length = nr_of_padding_bytes(info_length);
+    total_length   = info_length + padding_length;
+    parameter_tvb  = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET, total_length, total_length);
+    
+    dissect_parameter(parameter_tvb, chunk_tree);
+    
+    proto_item_set_text(chunk_item, "HEARTBEAT chunk");
+  }
 }
  
-void
-dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                            proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 {  
   tvbuff_t   *parameter_tvb;
   guint chunk_length, info_length, padding_length, total_length;
+  
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "HEARTBEAT_ACK ");
 
-  chunk_length   = tvb_get_ntohs(chunk_tvb,  CHUNK_LENGTH_OFFSET);
-  info_length    = chunk_length - CHUNK_HEADER_LENGTH;
-  padding_length = nr_of_padding_bytes(info_length);
-  total_length   = info_length + padding_length;
+  if (chunk_tree) {
+    chunk_length   = tvb_get_ntohs(chunk_tvb,  CHUNK_LENGTH_OFFSET);
+    info_length    = chunk_length - CHUNK_HEADER_LENGTH;
+    padding_length = nr_of_padding_bytes(info_length);
+    total_length   = info_length + padding_length;
 
-  parameter_tvb  = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET, total_length, total_length);
+    parameter_tvb  = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET, total_length, total_length);
     
-  dissect_parameter(parameter_tvb, chunk_tree);
-
-  proto_item_set_text(chunk_item, "HEARTBEAT ACK chunk");
-} 
+    dissect_parameter(parameter_tvb, chunk_tree);
+    
+    proto_item_set_text(chunk_item, "HEARTBEAT ACK chunk");
+  } 
+}
 
-void
-dissect_abort_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_abort_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                    proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 {
   guint offset, number_of_causes;
   guint16 length, padding_length, total_length;
   tvbuff_t *cause_tvb;
+  
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "ABORT ");
 
-  number_of_causes = 0;
-  offset = ABORT_CHUNK_FIRST_ERROR_CAUSE_OFFSET;
-  while(tvb_length_remaining(chunk_tvb, offset)) {
+  if (chunk_tree) {
+    number_of_causes = 0;
+    offset = ABORT_CHUNK_FIRST_ERROR_CAUSE_OFFSET;
+    while(tvb_length_remaining(chunk_tvb, offset)) {
     length         = tvb_get_ntohs(chunk_tvb, offset + CAUSE_LENGTH_OFFSET);
     padding_length = nr_of_padding_bytes(length);
     total_length   = length + padding_length;
     /* create a tvb for the chunk including the padding bytes */
     cause_tvb      = tvb_new_subset(chunk_tvb, offset, total_length, total_length);
-    dissect_error_cause(cause_tvb, chunk_tree); 
+    dissect_error_cause(cause_tvb, pinfo, chunk_tree); 
     /* get rid of the handled parameter */
     offset += total_length;
     number_of_causes++;
-  };
-
-  proto_item_set_text(chunk_item, "Abort chunk with %u cause%s",
-                     number_of_causes, plurality(number_of_causes, "", "s"));
-} 
+    };
+    
+    proto_item_set_text(chunk_item, "Abort chunk with %u cause%s",
+                       number_of_causes, plurality(number_of_causes, "", "s"));
+  } 
+}
 
-void
-dissect_shutdown_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_shutdown_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                       proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint32 cumulative_tsn_ack;
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "SHUTDOWN ");
 
-  cumulative_tsn_ack = tvb_get_ntohl(chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
-  proto_tree_add_uint(chunk_tree, hf_sctp_shutdown_chunk_cumulative_tsn_ack, 
-                     chunk_tvb,
-                     SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET,
-                     SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_LENGTH,
-                     cumulative_tsn_ack);
-
-  proto_item_set_text(chunk_item, "SHUTDOWN chunk acknowledging up to TSN %u",
-                     cumulative_tsn_ack);
-} 
+  if (chunk_tree) {
+    cumulative_tsn_ack = tvb_get_ntohl(chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
+    proto_tree_add_uint(chunk_tree, hf_sctp_shutdown_chunk_cumulative_tsn_ack, 
+                       chunk_tvb,
+                       SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET,
+                       SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_LENGTH,
+                       cumulative_tsn_ack);
+    
+    proto_item_set_text(chunk_item, "SHUTDOWN chunk acknowledging up to TSN %u",
+                       cumulative_tsn_ack);
+  } 
+}
 
-void
-dissect_shutdown_ack_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_shutdown_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                           proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
-  proto_item_set_text(chunk_item, "SHUTDOWN ACK chunk");
-} 
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "SHUTDOWN_ACK ");
 
-void
-dissect_error_chunk(tvbuff_t *chunk_tvb, 
+  if (chunk_tree) {
+    proto_item_set_text(chunk_item, "SHUTDOWN ACK chunk");
+  } 
+}
+
+static void
+dissect_error_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                    proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint offset, number_of_causes;
   guint16 length, padding_length, total_length;
   tvbuff_t *cause_tvb;
   
-  number_of_causes = 0;
-  offset = ERROR_CHUNK_FIRST_ERROR_CAUSE_OFFSET;
-  do {
-    length         = tvb_get_ntohs(chunk_tvb, offset + CAUSE_LENGTH_OFFSET);
-    padding_length = nr_of_padding_bytes(length);
-    total_length   = length + padding_length;
-    /* create a tvb for the chunk including the padding bytes */
-    cause_tvb      = tvb_new_subset(chunk_tvb, offset, total_length, total_length);
-    dissect_error_cause(cause_tvb, chunk_tree); 
-    /* get rid of the handled parameter */
-    offset += total_length;
-    number_of_causes++;
-  } while(tvb_length_remaining(chunk_tvb, offset));
-
-  proto_item_set_text(chunk_item, "Error chunk with %u cause%s",
-                     number_of_causes, plurality(number_of_causes, "", "s"));
-} 
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "ERROR ");
+
+  if (chunk_tree) {
+    number_of_causes = 0;
+    offset = ERROR_CHUNK_FIRST_ERROR_CAUSE_OFFSET;
+    do {
+      length         = tvb_get_ntohs(chunk_tvb, offset + CAUSE_LENGTH_OFFSET);
+      padding_length = nr_of_padding_bytes(length);
+      total_length   = length + padding_length;
+      /* create a tvb for the chunk including the padding bytes */
+      cause_tvb      = tvb_new_subset(chunk_tvb, offset, total_length, total_length);
+      dissect_error_cause(cause_tvb, pinfo, chunk_tree); 
+      /* get rid of the handled parameter */
+      offset += total_length;
+      number_of_causes++;
+    } while(tvb_length_remaining(chunk_tvb, offset));
+    
+    proto_item_set_text(chunk_item, "Error chunk with %u cause%s",
+                       number_of_causes, plurality(number_of_causes, "", "s"));
+  } 
+}
 
-void
-dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                          proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint length, cookie_length, padding_length;
@@ -1268,196 +1358,239 @@ dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb,
   length         = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
   padding_length = nr_of_padding_bytes(length);
   cookie_length  = length - CHUNK_HEADER_LENGTH;
-  
-  proto_tree_add_text(chunk_tree, chunk_tvb, COOKIE_ECHO_CHUNK_COOKIE_OFFSET, cookie_length,
-                     "Cookie (%u byte%s)",
-                     cookie_length, plurality(cookie_length, "", "s"));
-  proto_item_set_text(chunk_item, "COOKIE ECHO chunk containing a cookie of %u byte%s",
-                     cookie_length, plurality(cookie_length, "", "s"));
-
-  if (padding_length > 0)
-    proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length,
-                       "Padding: %u byte%s",
-                       padding_length, plurality(padding_length, "", "s"));
-} 
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "COOKIE_ECHO ");
+
+  if (chunk_tree) {  
+    proto_tree_add_text(chunk_tree, chunk_tvb, COOKIE_ECHO_CHUNK_COOKIE_OFFSET, cookie_length,
+                       "Cookie (%u byte%s)",
+                       cookie_length, plurality(cookie_length, "", "s"));
+    proto_item_set_text(chunk_item, "COOKIE ECHO chunk containing a cookie of %u byte%s",
+                       cookie_length, plurality(cookie_length, "", "s"));
+    
+    if (padding_length > 0)
+      proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length,
+                         "Padding: %u byte%s",
+                         padding_length, plurality(padding_length, "", "s"));
+  } 
+}
 
-void
-dissect_cookie_ack_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_cookie_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                         proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
-{ 
-  proto_item_set_text(chunk_item, "COOKIE ACK chunk");
-} 
+{  
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "COOKIE_ACK ");
 
-void
-dissect_ecne_chunk(tvbuff_t *chunk_tvb, 
+  if (chunk_tree) {
+    proto_item_set_text(chunk_item, "COOKIE ACK chunk");
+  } 
+}
+
+static void
+dissect_ecne_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                   proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint32 lowest_tsn;
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "ECNE ");
 
-  lowest_tsn = tvb_get_ntohl(chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET);
-  proto_tree_add_uint(chunk_tree, hf_sctp_ecne_chunk_lowest_tsn, 
-                     chunk_tvb,
-                     ECNE_CHUNK_LOWEST_TSN_OFFSET, ECNE_CHUNK_LOWEST_TSN_LENGTH,
-                     lowest_tsn);
-
-  proto_item_set_text(chunk_item, "ECNE chunk");
-} 
+  if (chunk_tree) {
+    lowest_tsn = tvb_get_ntohl(chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET);
+    proto_tree_add_uint(chunk_tree, hf_sctp_ecne_chunk_lowest_tsn, 
+                       chunk_tvb,
+                       ECNE_CHUNK_LOWEST_TSN_OFFSET, ECNE_CHUNK_LOWEST_TSN_LENGTH,
+                       lowest_tsn);
+    
+    proto_item_set_text(chunk_item, "ECNE chunk");
+  } 
+}
 
-void
-dissect_cwr_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_cwr_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                  proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint32 lowest_tsn;
+  
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "CWR ");
 
-  lowest_tsn = tvb_get_ntohl(chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET);
-  proto_tree_add_uint(chunk_tree, hf_sctp_cwr_chunk_lowest_tsn, 
-                     chunk_tvb,
-                     CWR_CHUNK_LOWEST_TSN_OFFSET, CWR_CHUNK_LOWEST_TSN_LENGTH,
-                     lowest_tsn);
-
-  proto_item_set_text(chunk_item, "CWR chunk");
-} 
+  if (chunk_tree) {
+    lowest_tsn = tvb_get_ntohl(chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET);
+    proto_tree_add_uint(chunk_tree, hf_sctp_cwr_chunk_lowest_tsn, 
+                       chunk_tvb,
+                       CWR_CHUNK_LOWEST_TSN_OFFSET, CWR_CHUNK_LOWEST_TSN_LENGTH,
+                       lowest_tsn);
+    
+    proto_item_set_text(chunk_item, "CWR chunk");
+  } 
+}
 
-void
-dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                                proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint8  flags;
   guint16 length;
   proto_tree *flag_tree;
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "SHUTDOWN_COMPLETE ");
 
-  flags             = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
-  length            = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
-
-  flag_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
-  proto_tree_add_boolean(flag_tree, hf_sctp_shutdown_complete_chunk_t_bit, chunk_tvb,
-                        CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
-
-  proto_item_set_text(chunk_item, "SHUTDOWN COMPLETE chunk");
-} 
+  if (chunk_tree) {
+    flags             = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
+    length            = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
+    
+    flag_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
+    proto_tree_add_boolean(flag_tree, hf_sctp_shutdown_complete_chunk_t_bit, chunk_tvb,
+                          CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
+    
+    proto_item_set_text(chunk_item, "SHUTDOWN COMPLETE chunk");
+  } 
+}
 
-void
-dissect_unknown_chunk(tvbuff_t *chunk_tvb, 
+static void
+dissect_unknown_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                      proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 { 
   guint length, chunk_value_length, padding_length;
   guint8 type;
-
-  length         = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
-  padding_length = nr_of_padding_bytes(length);
-  type           = tvb_get_guint8(chunk_tvb, CHUNK_TYPE_OFFSET);
-  chunk_value_length = length - CHUNK_HEADER_LENGTH;
   
-  proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_VALUE_OFFSET, chunk_value_length,
-                     "Chunk value (%u byte%s)",
-                     chunk_value_length, plurality(chunk_value_length, "", "s"));
-  
-  if (padding_length > 0)
-    proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length,
-                       "Padding: %u byte%s",
-                       padding_length, plurality(padding_length, "", "s"));
-   
-  proto_item_set_text(chunk_item, "Chunk of type %u and %u byte%s value",
-                     type, chunk_value_length, plurality(chunk_value_length, "", "s"));
+  if (check_col(pinfo->fd, COL_INFO))
+    col_append_str(pinfo->fd, COL_INFO, "UNKNOWN ");
 
+  if (chunk_tree) {
+    length         = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
+    padding_length = nr_of_padding_bytes(length);
+    type           = tvb_get_guint8(chunk_tvb, CHUNK_TYPE_OFFSET);
+    
+    chunk_value_length = length - CHUNK_HEADER_LENGTH;
+    
+    proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_VALUE_OFFSET, chunk_value_length,
+                       "Chunk value (%u byte%s)",
+                       chunk_value_length, plurality(chunk_value_length, "", "s"));
+    
+    if (padding_length > 0)
+      proto_tree_add_text(chunk_tree, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length,
+                         "Padding: %u byte%s",
+                         padding_length, plurality(padding_length, "", "s"));
+    
+    proto_item_set_text(chunk_item, "Chunk of type %u and %u byte%s value",
+                       type, chunk_value_length, plurality(chunk_value_length, "", "s"));
+  }
 } 
 
 
-void
-dissect_sctp_chunk(tvbuff_t *chunk_tvb, proto_tree *sctp_tree)
+static gboolean
+dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, proto_tree *sctp_tree)
 {  
   guint8 type, flags;
   guint16 length;
+  gboolean result;
   proto_item *flags_item;
   proto_item *chunk_item;
   proto_tree *chunk_tree;
 
+  result = FALSE;
+  
   /* first extract the chunk header */
   type   = tvb_get_guint8(chunk_tvb, CHUNK_TYPE_OFFSET);
   flags  = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
   length = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
-
-  /* create proto_tree stuff */
-  chunk_item   = proto_tree_add_text(sctp_tree, chunk_tvb,
-                                    CHUNK_HEADER_OFFSET, tvb_length(chunk_tvb), "Incomplete chunk");
-  chunk_tree   = proto_item_add_subtree(chunk_item, ett_sctp_chunk);
-  
-  /* then insert the chunk header components into the protocol tree */
-  proto_tree_add_uint_format(chunk_tree, hf_sctp_chunk_type, 
-                            chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH,
-                            type, "Identifier: %u (%s)",
-                            type, val_to_str(type, sctp_chunk_type_values, "unknown"));
-  flags_item = proto_tree_add_uint(chunk_tree, hf_sctp_chunk_flags, 
-                     chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH,
-                     flags);
-  proto_tree_add_uint(chunk_tree, hf_sctp_chunk_length, 
-                     chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH,
-                     length);
+  if (tree) {
+    /* create proto_tree stuff */
+    chunk_item   = proto_tree_add_text(sctp_tree, chunk_tvb,
+                                      CHUNK_HEADER_OFFSET, tvb_length(chunk_tvb), "Incomplete chunk");
+    chunk_tree   = proto_item_add_subtree(chunk_item, ett_sctp_chunk);
+    
+    /* then insert the chunk header components into the protocol tree */
+    proto_tree_add_uint_format(chunk_tree, hf_sctp_chunk_type, 
+                              chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH,
+                              type, "Identifier: %u (%s)",
+                              type, val_to_str(type, sctp_chunk_type_values, "unknown"));
+    flags_item = proto_tree_add_uint(chunk_tree, hf_sctp_chunk_flags, 
+                                    chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH,
+                                    flags);
+    proto_tree_add_uint(chunk_tree, hf_sctp_chunk_length, 
+                       chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH,
+                       length);
+  } else {
+    chunk_tree = NULL;
+    chunk_item = NULL;
+    flags_item = NULL;
+  };
   
   /* now dissect the chunk value */
+
   switch(type) {
   case SCTP_DATA_CHUNK_ID:
-    dissect_data_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    result = dissect_data_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_INIT_CHUNK_ID:
-    dissect_init_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_init_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_INIT_ACK_CHUNK_ID:
-    dissect_init_ack_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_init_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_SACK_CHUNK_ID:
-    dissect_sack_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_sack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break; 
   case SCTP_HEARTBEAT_CHUNK_ID:
-    dissect_heartbeat_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_heartbeat_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_HEARTBEAT_ACK_CHUNK_ID:
-    dissect_heartbeat_ack_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_heartbeat_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_ABORT_CHUNK_ID:
-    dissect_abort_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_abort_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_SHUTDOWN_CHUNK_ID:
-    dissect_shutdown_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_shutdown_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_SHUTDOWN_ACK_CHUNK_ID:
-    dissect_shutdown_ack_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_shutdown_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_ERROR_CHUNK_ID:
-    dissect_error_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_error_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_COOKIE_ECHO_CHUNK_ID:
-    dissect_cookie_echo_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_cookie_echo_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_COOKIE_ACK_CHUNK_ID:
-    dissect_cookie_ack_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_cookie_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_ECNE_CHUNK_ID:
-    dissect_ecne_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_ecne_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_CWR_CHUNK_ID:
-    dissect_cwr_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_cwr_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_SHUTDOWN_COMPLETE_CHUNK_ID:
-    dissect_shutdown_complete_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
-    break;
+    dissect_shutdown_complete_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+      break;
   default:
-    dissect_unknown_chunk(chunk_tvb, chunk_tree, chunk_item, flags_item);
+    dissect_unknown_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
     break;
-  }  
+  };
+  return result;
 }
 
-void
-dissect_sctp_chunks(tvbuff_t *tvb, proto_tree *sctp_tree)
+static void
+dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+                   proto_item *sctp_item, proto_tree *sctp_tree)
 { 
   tvbuff_t *chunk_tvb;
   guint16 length, padding_length, total_length;
-  gint offset;
-  
+  gint last_offset, offset;
+  gboolean sctp_item_length_set;
+
   /* the common header of the datagram is already handled */
+  last_offset = 0;
   offset = COMMON_HEADER_LENGTH;
+  sctp_item_length_set = FALSE;
 
   while(tvb_length_remaining(tvb, offset) > 0) {
     /* extract the chunk length and compute number of padding bytes */
@@ -1467,59 +1600,63 @@ dissect_sctp_chunks(tvbuff_t *tvb, proto_tree *sctp_tree)
     /* create a tvb for the chunk including the padding bytes */
     chunk_tvb    = tvb_new_subset(tvb, offset, total_length, total_length);
     /* call dissect_sctp_chunk for a actual work */
-    dissect_sctp_chunk(chunk_tvb, sctp_tree);
+    if (dissect_sctp_chunk(chunk_tvb, pinfo, tree, sctp_tree) && (tree)) {
+      proto_item_set_len(sctp_item, offset - last_offset + DATA_CHUNK_HEADER_LENGTH);
+      sctp_item_length_set = TRUE;
+      offset += total_length;
+      last_offset = offset;
+      if (tvb_length_remaining(tvb, offset) > 0) {
+       sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, offset, 0, FALSE);
+       sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
+       sctp_item_length_set = FALSE;
+      }
+    } else {
     /* get rid of the dissected chunk */
     offset += total_length;
-  }
+    }
+  };
+  if (!sctp_item_length_set && (tree)) { 
+    proto_item_set_len(sctp_item, offset - last_offset);
+  };
 }
 
-
-
 /* dissect_sctp handles the common header of a SCTP datagram.
  * For the handling of the chunks dissect_sctp_chunks is called.
  */
 
-#if 0
 static void
 dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-#else
-static void
-dissect_sctp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
-{
-        tvbuff_t *tvb = tvb_create_from_top(offset);
-        packet_info *pinfo = &pi;
-#endif
-
   guint16 source_port, destination_port;
   guint32 verification_tag, checksum;
-  proto_item *ti;
+  proto_item *sctp_item;
   proto_tree *sctp_tree;
 
-  pinfo->current_proto = "SCTP";
-
   /* Extract the common header */
   source_port      = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET);
   destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET);
   verification_tag = tvb_get_ntohl(tvb, VERIFICATION_TAG_OFFSET);
   checksum         = tvb_get_ntohl(tvb, CHECKSUM_OFFSET);
 
+  /* update pi structure */
+  pinfo->ptype    = PT_SCTP;
+  pinfo->srcport  = source_port;
+  pinfo->destport = destination_port;
+
   /* make entry in the Protocol column on summary display */
-  if (check_col(fd, COL_PROTOCOL)) 
-    col_add_str(fd, COL_PROTOCOL, "SCTP");
+  if (check_col(pinfo->fd, COL_PROTOCOL)) 
+    col_set_str(pinfo->fd, COL_PROTOCOL, "SCTP");
 
-  /* Make entries in Info column on summary display */
-  if (check_col(fd, COL_INFO)) 
-    col_add_fstr(fd, COL_INFO, "%u > %u: tag 0x%x",
-                source_port, destination_port, verification_tag);
+  /* Clear entries in Info column on summary display */
+  if (check_col(pinfo->fd, COL_INFO))
+    col_add_str(pinfo->fd, 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) {
     /* create the sctp protocol tree */
-    ti = proto_tree_add_protocol_format(tree, proto_sctp, tvb, 0, tvb_length(tvb), 
-                                       "Stream Control Transmission Protocol");
-    sctp_tree = proto_item_add_subtree(ti, ett_sctp);
+    sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, 0, 0, FALSE);
+    sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
 
     /* add the components of the common header to the protocol tree */
     proto_tree_add_uint(sctp_tree, hf_sctp_source_port, 
@@ -1535,10 +1672,12 @@ dissect_sctp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                               tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum,
                               "Adler-32 checksum: 0x%08x (%s)",
                               checksum, sctp_checksum_state(tvb, checksum));
-    
-    /* add all chunks of the sctp datagram to the protocol tree */
-    dissect_sctp_chunks(tvb, sctp_tree);
+  } else {
+    sctp_tree = NULL;
+    sctp_item = NULL;
   };
+  /* add all chunks of the sctp datagram to the protocol tree */
+  dissect_sctp_chunks(tvb, pinfo, tree, sctp_item, sctp_tree);
 }
 
 /* Register the protocol with Ethereal */
@@ -1551,227 +1690,227 @@ proto_register_sctp(void)
     { &hf_sctp_source_port,
       { "Source port", "sctp.srcport",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_destination_port,
       { "Destination port", "sctp.dstport",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     { &hf_sctp_verification_tag,
       { "Verification tag", "sctp.verfication_tag",
        FT_UINT32, BASE_HEX, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_checksum,
       { "Adler-32 checksum", "sctp.checksum",
        FT_UINT32, BASE_HEX, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_chunk_type,
       { "Identifier", "sctp.chunk_type",
        FT_UINT8, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_chunk_flags,
       { "Flags", "sctp.chunk_flags",
        FT_UINT8, BASE_BIN, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_chunk_length,
       { "Length", "sctp.chunk_length",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_init_chunk_initiate_tag,
       { "Initiate tag", "sctp.init.chunk.initiate.tag",
        FT_UINT32, BASE_HEX, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_init_chunk_adv_rec_window_credit,
       { "Advertised reciever window credit (a_rwnd)", "sctp.init.chunk.credit",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_init_chunk_number_of_outbound_streams,
       { "Number of outbound streams", "sctp.init.chunk.nr.out.streams",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     { &hf_sctp_init_chunk_number_of_inbound_streams,
       { "Number of inbound streams", "sctp.init.chunk.nr.in.streams",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_init_chunk_initial_tsn,
       { "Initial TSN", "sctp.init.chunk.initial.tsn",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_cumulative_tsn_ack,
      { "Cumulative TSN Ack", "sctp.cumulative.tsn.ack",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_tsn,
      { "TSN", "sctp.tsn",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_stream_id,
      { "Stream Identifier", "sctp.stream_id",
        FT_UINT16, BASE_HEX, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_stream_seq_number,
      { "Stream sequence number", "sctp.stream_seq_number",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_payload_proto_id,
      { "Payload Protocol identifier", "sctp.payload_proto_id",
        FT_UINT32, BASE_HEX, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_e_bit,
      { "E-Bit", "sctp.data.e_bit",
        FT_BOOLEAN, 8, TFS(&sctp_data_chunk_e_bit_value), SCTP_DATA_CHUNK_E_BIT,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_b_bit,
      { "B-Bit", "sctp.data.b_bit",
        FT_BOOLEAN, 8, TFS(&sctp_data_chunk_b_bit_value), SCTP_DATA_CHUNK_B_BIT,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_data_chunk_u_bit,
      { "U-Bit", "sctp.data.u.bit",
        FT_BOOLEAN, 8, TFS(&sctp_data_chunk_u_bit_value), SCTP_DATA_CHUNK_U_BIT,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_sack_chunk_cumulative_tsn_ack,
      { "Cumulative TSN ACK", "sctp.sack.cumulative_tsn_ack",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_sack_chunk_adv_rec_window_credit,
      { "Advertised receiver window credit (a_rwnd)", "sctp.sack.a_rwnd",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_sack_chunk_number_of_gap_blocks,
      { "Number of gap acknowldgement blocks ", "sctp.sack.number_of_gap_blocks",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_sack_chunk_number_of_dup_tsns,
      { "Number of duplicated TSNs", "sctp.sack.number_of_duplicated_tsns",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_sack_chunk_gap_block_start,
      { "Start", "sctp.sack.gap_block_start",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_sack_chunk_gap_block_end,
      { "End", "sctp.sack.gap_block_end",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_sack_chunk_duplicate_tsn,
      { "Duplicate TSN", "sctp.sack.duplicate.tsn",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },  
     {&hf_sctp_shutdown_chunk_cumulative_tsn_ack,
      { "Cumulative TSN Ack", "sctp.shutdown.cumulative_tsn_ack",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_ecne_chunk_lowest_tsn,
      { "Lowest TSN", "sctp.ecne.lowest_tsn",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_cwr_chunk_lowest_tsn,
      { "Lowest TSN", "sctp.cwr.lowest_tsn",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_shutdown_complete_chunk_t_bit,
      { "E-Bit", "sctp.shutdown_complete.t_bit",
        FT_BOOLEAN, 8, TFS(&sctp_shutdown_complete_chunk_t_bit_value), SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT,
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_chunk_parameter_type,
      { "Parameter type", "sctp.parameter.type",
        FT_UINT16, BASE_HEX, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_chunk_parameter_length,
      { "Parameter length", "sctp.parameter.length",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_parameter_ipv4_address,
      { "IP Version 4 address", "sctp.parameter.ipv4_address",
        FT_IPv4, BASE_NONE, NULL, 0x0,
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_parameter_ipv6_address,
      { "IP Version 6 address", "sctp.parameter.ipv6_address",
        FT_IPv6, BASE_NONE, NULL, 0x0,
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_parameter_cookie_preservative_increment,
      { "Suggested Cookie life-span increment (msec)", "sctp.parameter.cookie_preservative_incr",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_parameter_hostname_hostname,
      { "Hostname", "sctp.parameter.hostname.hostname",
        FT_STRING, BASE_NONE, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_supported_address_types_parameter,
      { "Supported address type", "sctp.parameter.supported_addres_type",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_cause_code,
      { "Cause code", "sctp.cause.code",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_cause_length,
      { "Cause length", "sctp.cause.length",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_cause_stream_identifier,
      { "Stream identifier", "sctp.cause.stream_identifier",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_cause_number_of_missing_parameters,
      { "Number of missing parameters", "sctp.cause.nr_of_missing_parameters",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     }, 
     {&hf_sctp_cause_missing_parameter_type,
      { "Missing parameters type", "sctp.cause.missing_parameter_type",
        FT_UINT16, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_cause_measure_of_staleness,
      { "Measure of staleness in usec", "sctp.cause.measure_of_staleness",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
     {&hf_sctp_cause_tsn,
      { "TSN", "sctp.cause.tsn",
        FT_UINT32, BASE_DEC, NULL, 0x0,          
-       ""}
+       "", HFILL }
     },
   };
   
@@ -1788,23 +1927,21 @@ proto_register_sctp(void)
   };
   
   /* Register the protocol name and description */
-  proto_sctp = proto_register_protocol("Stream Control Transmission Protcol",
-                                      "sctp");
+  proto_sctp = proto_register_protocol("Stream Control Transmission Protocol",
+                                      "SCTP", "sctp");
   
   /* Required function calls to register the header fields and subtrees used */
   proto_register_field_array(proto_sctp, hf, array_length(hf));
   proto_register_subtree_array(ett, array_length(ett));
+
+  /* subdissector code */
+  sctp_port_dissector_table = register_dissector_table("sctp.port");
+  sctp_ppi_dissector_table  = register_dissector_table("sctp.ppi");
+
 };
 
 void
 proto_reg_handoff_sctp(void)
 {
-       dissector_add("ip.proto", IP_PROTO_SCTP, dissect_sctp);
+       dissector_add("ip.proto", IP_PROTO_SCTP, dissect_sctp, proto_sctp);
 }
-
-
-
-
-
-
-