Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-sctp.c
index 48081e91aa62de9bbfad15b0a2aee1d5689e673a..e26dbf34f3b7c5b0f3e6f60d9e27cb57054b4344 100644 (file)
@@ -1,8 +1,16 @@
 /* packet-sctp.c
  * Routines for Stream Control Transmission Protocol dissection
- * Copyright 2000, Michael Tüxen <Michael.Tuexen@icn.siemens.de>
+ * It should be compilant to
+ * - RFC 2960, for basic SCTP support
+ * - http://www.ietf.org/internet-drafts/draft-ietf-tsvwg-addip-sctp-06.txt for the add-IP extension
+ * - http://www.ietf.org/internet-drafts/draft-stewart-tsvwg-prsctp-01.txt for the 'Partial Reliability' extension
+ * - http://www.ietf.org/internet-drafts/draft-ietf-tsvwg-sctpcsum-07.txt
+ * Copyright 2000, 2001, 2002, Michael Tuexen <Michael.Tuexen@icn.siemens.de>
+ * Still to do (so stay tuned)
+ * - support for reassembly
+ * - code cleanup
  *
- * $Id: packet-sctp.c,v 1.20 2001/08/28 08:28:14 guy Exp $
+ * $Id: packet-sctp.c,v 1.40 2002/07/10 21:01:57 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 # include "config.h"
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
-
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#include <string.h>
-#include <glib.h>
-
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
-
-#include "packet.h"
+#include "prefs.h"
+#include <epan/packet.h>
 #include "ipproto.h"
 
 /* Initialize the protocol and registered fields */
 static int proto_sctp = -1;
+static int hf_sctp_port = -1;
 static int hf_sctp_source_port      = -1;
 static int hf_sctp_destination_port = -1;
 static int hf_sctp_verification_tag = -1;
 static int hf_sctp_checksum         = -1;
+static int hf_sctp_checksum_bad     = -1;
 
 static int hf_sctp_chunk_type       = -1;
 static int hf_sctp_chunk_flags      = -1;
@@ -114,19 +106,35 @@ static int hf_sctp_cause_measure_of_staleness = -1;
 
 static int hf_sctp_cause_tsn = -1;
 
+static int hf_sctp_forward_tsn_chunk_tsn = -1;
+static int hf_sctp_forward_tsn_chunk_sid = -1;
+static int hf_sctp_forward_tsn_chunk_ssn = -1;
+
+static int hf_sctp_asconf_ack_serial = -1;
+static int hf_sctp_asconf_serial = -1;
+static int hf_sctp_correlation_id = -1;
+
+static int hf_sctp_adap_indication = -1;
+static int hf_sctp_abort_chunk_t_bit = -1;
 static dissector_table_t sctp_port_dissector_table;
 static dissector_table_t sctp_ppi_dissector_table;
 
+static module_t *sctp_module;
+
 /* Initialize the subtree pointers */
 static gint ett_sctp = -1;
 static gint ett_sctp_chunk = -1;
 static gint ett_sctp_chunk_parameter = -1;
 static gint ett_sctp_chunk_cause = -1;
 static gint ett_sctp_data_chunk_flags = -1;
+static gint ett_sctp_shutdown_complete_chunk_flags = -1;
+static gint ett_sctp_abort_chunk_flags = -1;
 static gint ett_sctp_sack_chunk_gap_block = -1;
 static gint ett_sctp_supported_address_types_parameter = -1;
 static gint ett_sctp_unrecognized_parameter_parameter = -1;
 
+static dissector_handle_t data_handle;
+
 #define SCTP_DATA_CHUNK_ID               0
 #define SCTP_INIT_CHUNK_ID               1
 #define SCTP_INIT_ACK_CHUNK_ID           2
@@ -142,6 +150,10 @@ static gint ett_sctp_unrecognized_parameter_parameter = -1;
 #define SCTP_ECNE_CHUNK_ID              12
 #define SCTP_CWR_CHUNK_ID               13
 #define SCTP_SHUTDOWN_COMPLETE_CHUNK_ID 14
+#define SCTP_FORWARD_TSN_CHUNK_ID      192 
+#define SCTP_ASCONF_ACK_CHUNK_ID      0x80
+#define SCTP_ASCONF_CHUNK_ID          0XC1
+
 #define SCTP_IETF_EXT                  255
 
 static const value_string sctp_chunk_type_values[] = {
@@ -160,6 +172,9 @@ static const value_string sctp_chunk_type_values[] = {
   { SCTP_ECNE_CHUNK_ID,              "ECNE" },
   { SCTP_CWR_CHUNK_ID,               "CWR" },
   { SCTP_SHUTDOWN_COMPLETE_CHUNK_ID, "SHUTDOWN_COMPLETE" },
+  { SCTP_FORWARD_TSN_CHUNK_ID,       "FORWARD TSN" },
+  { SCTP_ASCONF_ACK_CHUNK_ID,        "ASCONF_ACK" },
+  { SCTP_ASCONF_CHUNK_ID,            "ASCONF" },
   { SCTP_IETF_EXT,                   "IETF_EXTENSION" },
   { 0,                               NULL } };
 
@@ -172,6 +187,13 @@ static const value_string sctp_chunk_type_values[] = {
 #define HOSTNAME_ADDRESS_PARAMETER_ID        0x000b
 #define SUPPORTED_ADDRESS_TYPES_PARAMETER_ID 0x000c
 #define ECN_PARAMETER_ID                     0x8000
+#define FORWARD_TSN_SUPPORTED_PARAMETER_ID   0xC000
+#define ADD_IP_ADDRESS_PARAMETER_ID          0xC001
+#define DEL_IP_ADDRESS_PARAMETER_ID          0xC002
+#define ERROR_CAUSE_INDICATION_PARAMETER_ID  0xC003
+#define SET_PRIMARY_ADDRESS_PARAMETER_ID     0xC004
+#define SUCCESS_REPORT_PARAMETER_ID          0xC005
+#define ADAP_LAYER_INDICATION_PARAMETER_ID   0xC006
 
 static const value_string sctp_parameter_identifier_values[] = {
   { HEARTBEAT_INFO_PARAMETER_ID,          "Heartbeat info" },
@@ -183,6 +205,13 @@ static const value_string sctp_parameter_identifier_values[] = {
   { HOSTNAME_ADDRESS_PARAMETER_ID,        "Hostname address" },
   { SUPPORTED_ADDRESS_TYPES_PARAMETER_ID, "Supported address types" },
   { ECN_PARAMETER_ID,                     "ECN" },
+  { FORWARD_TSN_SUPPORTED_PARAMETER_ID,   "Forward TSN supported" },
+  { ADD_IP_ADDRESS_PARAMETER_ID,          "Add IP address" },
+  { DEL_IP_ADDRESS_PARAMETER_ID,          "Delete IP address" },
+  { ERROR_CAUSE_INDICATION_PARAMETER_ID,  "Error cause indication" },
+  { SET_PRIMARY_ADDRESS_PARAMETER_ID,     "Set primary address" },
+  { SUCCESS_REPORT_PARAMETER_ID,          "Success report" },
+  { ADAP_LAYER_INDICATION_PARAMETER_ID,   "Adaptation Layer Indication" },
   { 0,                                    NULL } };
 
 #define PARAMETER_TYPE_LENGTH            2
@@ -234,29 +263,39 @@ static const value_string sctp_parameter_identifier_values[] = {
 #define CAUSE_TSN_LENGTH 4
 #define CAUSE_TSN_OFFSET CAUSE_INFO_OFFSET
 
-#define INVALID_STREAM_IDENTIFIER              0x01
-#define MISSING_MANDATORY_PARAMETERS           0x02
-#define STALE_COOKIE_ERROR                     0x03
-#define OUT_OF_RESOURCE                        0x04
-#define UNRESOLVABLE_ADDRESS                   0x05
-#define UNRECOGNIZED_CHUNK_TYPE                0x06
-#define INVALID_MANDATORY_PARAMETER            0x07
-#define UNRECOGNIZED_PARAMETERS                0x08
-#define NO_USER_DATA                           0x09
-#define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN    0x0a
+#define INVALID_STREAM_IDENTIFIER                  0x01
+#define MISSING_MANDATORY_PARAMETERS               0x02
+#define STALE_COOKIE_ERROR                         0x03
+#define OUT_OF_RESOURCE                            0x04
+#define UNRESOLVABLE_ADDRESS                       0x05
+#define UNRECOGNIZED_CHUNK_TYPE                    0x06
+#define INVALID_MANDATORY_PARAMETER                0x07
+#define UNRECOGNIZED_PARAMETERS                    0x08
+#define NO_USER_DATA                               0x09
+#define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN        0x0a
+#define RESTART_WITH_NEW_ADDRESSES                 0x0b
+#define REQUEST_TO_DELETE_LAST_ADDRESS             0x0100
+#define OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE 0X0101
+#define REQUEST_TO_DELETE_SOURCE_ADDRESS           0x0102
+#define ABORT_DUE_TO_ILLEGAL_ASCONF                0x0103
 
 static const value_string sctp_cause_code_values[] = {
-  { INVALID_STREAM_IDENTIFIER,           "Invalid stream identifier" },
-  { MISSING_MANDATORY_PARAMETERS,        "Missing mandator parameter" },
-  { STALE_COOKIE_ERROR,                  "Stale cookie error" },
-  { OUT_OF_RESOURCE,                     "Out of resource" },
-  { UNRESOLVABLE_ADDRESS,                "Unresolvable address" },
-  { UNRECOGNIZED_CHUNK_TYPE,             "Unrecognized chunk type " },
-  { INVALID_MANDATORY_PARAMETER,         "Invalid mandatory parameter" },
-  { UNRECOGNIZED_PARAMETERS,             "Unrecognized parameters" },
-  { NO_USER_DATA,                        "No user data" },
-  { COOKIE_RECEIVED_WHILE_SHUTTING_DOWN, "Cookie received while shutting down" },
-  { 0,                           NULL } };
+  { INVALID_STREAM_IDENTIFIER,                  "Invalid stream identifier" },
+  { MISSING_MANDATORY_PARAMETERS,               "Missing mandator parameter" },
+  { STALE_COOKIE_ERROR,                         "Stale cookie error" },
+  { OUT_OF_RESOURCE,                            "Out of resource" },
+  { UNRESOLVABLE_ADDRESS,                       "Unresolvable address" },
+  { UNRECOGNIZED_CHUNK_TYPE,                    "Unrecognized chunk type " },
+  { INVALID_MANDATORY_PARAMETER,                "Invalid mandatory parameter" },
+  { UNRECOGNIZED_PARAMETERS,                    "Unrecognized parameters" },
+  { NO_USER_DATA,                               "No user data" },
+  { COOKIE_RECEIVED_WHILE_SHUTTING_DOWN,        "Cookie received while shutting down" },
+  { RESTART_WITH_NEW_ADDRESSES,                 "Restart of an association with new addresses" },
+  { REQUEST_TO_DELETE_LAST_ADDRESS,             "Request to delete last address" },
+  { OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE, "Operation refused due to resource shortage" },
+  { REQUEST_TO_DELETE_SOURCE_ADDRESS,           "Request to delete source address" },
+  { ABORT_DUE_TO_ILLEGAL_ASCONF,                "Association Aborted due to illegal ASCONF-ACK" },
+  { 0,                                          NULL } };
 
 #define NOT_SPECIFIED_PROTOCOL_ID  0
 #define IUA_PAYLOAD_PROTOCOL_ID    1
@@ -404,6 +443,13 @@ static const true_false_string sctp_shutdown_complete_chunk_t_bit_value = {
   "TCB destroyed"
 };
 
+#define SCTP_CHECKSUM_NONE      0
+#define SCTP_CHECKSUM_ADLER32   1
+#define SCTP_CHECKSUM_CRC32C    2
+#define SCTP_CHECKSUM_AUTOMATIC 3
+
+static gint sctp_checksum = SCTP_CHECKSUM_ADLER32;
+
 /* adler32.c -- compute the Adler-32 checksum of a data stream
  * Copyright (C) 1995-1996 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
@@ -423,8 +469,7 @@ static const true_false_string sctp_shutdown_complete_chunk_t_bit_value = {
 #define DO16(buf)   DO8(buf,0); DO8(buf,8);
 
 static unsigned int
-sctp_adler_32(const unsigned char* buf,
-             unsigned int len)
+sctp_adler32(const unsigned char* buf, unsigned int len)
 {
     unsigned int s1 = 1L;
     unsigned int s2 = 0L;
@@ -462,16 +507,107 @@ sctp_adler_32(const unsigned char* buf,
     return (s2 << 16) | s1;
 }
 
-static char 
-*sctp_checksum_state(tvbuff_t *tvb, guint orig_checksum)
+/* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
+ * That code is copyrighted by D. Otis and has been modified.
+ */
+  
+#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) 
+static unsigned long crc_c[256] = 
+{ 
+0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,  
+0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,  
+0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,  
+0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,  
+0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,  
+0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,  
+0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,  
+0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,  
+0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,  
+0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,  
+0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,  
+0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,  
+0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,  
+0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,  
+0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,  
+0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,  
+0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,  
+0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,  
+0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,  
+0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,  
+0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,  
+0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,  
+0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,  
+0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,  
+0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,  
+0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,  
+0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,  
+0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,  
+0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,  
+0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,  
+0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,  
+0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,  
+0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,  
+0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,  
+0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,  
+0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,  
+0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,  
+0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,  
+0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,  
+0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,  
+0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,  
+0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,  
+0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,  
+0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,  
+0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,  
+0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,  
+0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,  
+0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,  
+0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,  
+0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,  
+0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,  
+0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,  
+0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,  
+0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,  
+0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,  
+0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,  
+0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,  
+0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,  
+0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,  
+0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,  
+0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,  
+0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,  
+0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,  
+0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,  
+}; 
+     
+static unsigned int
+sctp_crc32c(const unsigned char* buf, unsigned int len)
 {
-  guint length;
+  unsigned int i; 
+  unsigned long crc32 = ~0L; 
+  unsigned long result;
+  unsigned char byte0,byte1,byte2,byte3;
+
+  for (i = 0; i < SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH; i++) 
+  { 
+    CRC32C(crc32, buf[i]); 
+  }
+  CRC32C(crc32, 0);
+  CRC32C(crc32, 0);
+  CRC32C(crc32, 0);
+  CRC32C(crc32, 0);
+  for (i = COMMON_HEADER_LENGTH; i < len; i++) 
+  { 
+    CRC32C(crc32, buf[i]); 
+  }  
+  result = ~crc32;
   
-  length = tvb_length(tvb);
-  if (orig_checksum == sctp_adler_32(tvb_get_ptr(tvb, 0, length), length))
-    return "correct";
-  else
-    return "incorrect";
+  byte0 = result & 0xff;
+  byte1 = (result>>8) & 0xff;
+  byte2 = (result>>16) & 0xff;
+  byte3 = (result>>24) & 0xff;
+  crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
+  return ( crc32 );
 }
 
 static guint 
@@ -492,25 +628,28 @@ nr_of_padding_bytes (guint length)
  */
 
 static void
-dissect_parameter(tvbuff_t *, proto_tree *);
+dissect_parameter(tvbuff_t *, packet_info *, proto_tree *);
+
+static void
+dissect_error_cause(tvbuff_t *, packet_info *, proto_tree *);
 
 static gboolean
 dissect_sctp_chunk(tvbuff_t *, packet_info *, proto_tree *, proto_tree *);
 
 static void 
-dissect_tlv_parameter_list(tvbuff_t *parameter_list_tvb, proto_tree *tree)
+dissect_tlv_parameter_list(tvbuff_t *parameter_list_tvb, packet_info *pinfo, proto_tree *tree)
 {
   guint offset, length, padding_length, total_length;
   tvbuff_t *parameter_tvb;
 
   offset = 0;
-  while(tvb_length_remaining(parameter_list_tvb, offset)) {
+  while(tvb_reported_length_remaining(parameter_list_tvb, offset)) {
     length         = tvb_get_ntohs(parameter_list_tvb, offset + PARAMETER_LENGTH_OFFSET);
     padding_length = nr_of_padding_bytes(length);
     total_length   = length + padding_length;
     /* create a tvb for the chunk including the padding bytes */
     parameter_tvb    = tvb_new_subset(parameter_list_tvb, offset, total_length, total_length);
-    dissect_parameter(parameter_tvb, tree); 
+    dissect_parameter(parameter_tvb, pinfo, tree); 
     /* get rid of the handled parameter */
     offset += total_length;
   }
@@ -573,9 +712,9 @@ dissect_state_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tr
 }
 
 static void
-dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
+dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
 {
-  guint16 length, padding_length, parameter_value_length;
+  guint16 length, padding_length, parameter_value_length, unrecognized_parameter_type;
   tvbuff_t *unrecognized_parameters_tvb;
 
   length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
@@ -585,9 +724,11 @@ dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, proto_tree *p
 
   unrecognized_parameters_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, 
                                               parameter_value_length, parameter_value_length);
-  dissect_tlv_parameter_list(unrecognized_parameters_tvb, parameter_tree);
+  unrecognized_parameter_type = tvb_get_ntohs(unrecognized_parameters_tvb, PARAMETER_TYPE_OFFSET);
+  dissect_tlv_parameter_list(unrecognized_parameters_tvb, pinfo, parameter_tree);
    
-  proto_item_set_text(parameter_item, "Unrecognized parameter of type");
+  proto_item_set_text(parameter_item, "Unrecognized parameter of type %s (0x%x)",
+                      val_to_str(unrecognized_parameter_type, sctp_parameter_identifier_values, "unknown"), unrecognized_parameter_type);
 }
 
 static void
@@ -645,7 +786,7 @@ dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *p
     address_type = tvb_get_ntohs(parameter_tvb, offset);
     proto_tree_add_uint_format(address_list_tree, hf_sctp_supported_address_types_parameter,
                               parameter_tvb, offset, SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH,
-                              address_type, "Supported address type: %u (%s)",
+                              address_type, "Supported address type: 0x%04x (%s)",
                               address_type, val_to_str(address_type, sctp_parameter_identifier_values, "unknown"));
     offset += SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH;
   };
@@ -655,11 +796,122 @@ dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *p
 }
 
 static void
-dissect_ecn_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
+dissect_ecn_parameter(proto_item *parameter_item)
 {
    proto_item_set_text(parameter_item, "ECN parameter");
 }
 
+static void
+dissect_forward_tsn_supported_parameter(proto_item *parameter_item)
+{  
+   proto_item_set_text(parameter_item, "Forward TSN supported parameter");
+}
+
+#define CORRELATION_ID_LENGTH    4
+#define CORRELATION_ID_OFFSET    PARAMETER_VALUE_OFFSET
+#define ADDRESS_PARAMETER_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH)
+
+static void
+dissect_add_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
+{
+  guint32 correlation_id;
+  guint16 length, parameter_value_length;
+  tvbuff_t *address_tvb;
+
+  length                 = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
+  parameter_value_length = length - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
+  correlation_id         = tvb_get_ntohs(parameter_tvb, CORRELATION_ID_OFFSET);
+  proto_tree_add_uint(parameter_tree, hf_sctp_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, correlation_id);
+  address_tvb            =  tvb_new_subset(parameter_tvb, ADDRESS_PARAMETER_OFFSET, parameter_value_length, parameter_value_length);
+  dissect_parameter(address_tvb, pinfo, parameter_tree); 
+
+  proto_item_set_text(parameter_item, "Add IP address parameter");
+}
+
+static void
+dissect_del_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
+{
+  guint32 correlation_id;
+  guint16 length, parameter_value_length;
+  tvbuff_t *address_tvb;
+
+  length                 = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
+  parameter_value_length = length - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
+  correlation_id         = tvb_get_ntohs(parameter_tvb, CORRELATION_ID_OFFSET);
+  proto_tree_add_uint(parameter_tree, hf_sctp_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, correlation_id);
+  address_tvb            =  tvb_new_subset(parameter_tvb, ADDRESS_PARAMETER_OFFSET, parameter_value_length, parameter_value_length);
+  dissect_parameter(address_tvb, pinfo, parameter_tree); 
+
+  proto_item_set_text(parameter_item, "Delete IP address parameter");
+}
+
+static void
+dissect_error_cause_indication_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
+{
+  guint32 correlation_id;
+  guint16 length, padding_length, total_length;
+  gint offset;
+  tvbuff_t *error_cause_tvb;
+
+  correlation_id         = tvb_get_ntohs(parameter_tvb, CORRELATION_ID_OFFSET);
+  proto_tree_add_uint(parameter_tree, hf_sctp_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, correlation_id);
+
+  offset = PARAMETER_VALUE_OFFSET + CORRELATION_ID_LENGTH;
+  while(tvb_reported_length_remaining(parameter_tvb, offset)) {
+    length         = tvb_get_ntohs(parameter_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 */
+    error_cause_tvb    = tvb_new_subset(parameter_tvb, offset , total_length, total_length);
+    dissect_error_cause(error_cause_tvb, pinfo, parameter_tree); 
+    /* get rid of the handled parameter */
+    offset += total_length;
+  }
+  proto_item_set_text(parameter_item, "Error cause indication");
+}
+
+static void
+dissect_set_primary_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
+{
+  guint32 correlation_id;
+  guint16 length, parameter_value_length;
+  tvbuff_t *address_tvb;
+
+  length                 = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
+  parameter_value_length = length - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
+
+  correlation_id         = tvb_get_ntohs(parameter_tvb, CORRELATION_ID_OFFSET);
+  proto_tree_add_uint(parameter_tree, hf_sctp_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, correlation_id);
+  address_tvb            =  tvb_new_subset(parameter_tvb, ADDRESS_PARAMETER_OFFSET, parameter_value_length, parameter_value_length);
+  dissect_parameter(address_tvb, pinfo, parameter_tree); 
+
+  proto_item_set_text(parameter_item, "Set primary address parameter");
+}
+
+static void
+dissect_success_report_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
+{
+  guint32 correlation_id;
+  
+  correlation_id         = tvb_get_ntohs(parameter_tvb, CORRELATION_ID_OFFSET);
+  proto_tree_add_uint(parameter_tree, hf_sctp_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, correlation_id);
+  
+  proto_item_set_text(parameter_item, "Success report parameter");
+}
+
+#define ADAP_INDICATION_LENGTH 4
+#define ADAP_INDICATION_OFFSET PARAMETER_VALUE_OFFSET
+
+static void
+dissect_adap_indication_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
+{
+  guint32 indication;
+
+  indication =  tvb_get_ntohl(parameter_tvb, ADAP_INDICATION_OFFSET);
+  proto_tree_add_uint(parameter_tree, hf_sctp_adap_indication, parameter_tvb, ADAP_INDICATION_OFFSET, ADAP_INDICATION_LENGTH, indication);
+  proto_item_set_text(parameter_item, "Adaptation layer indication");
+}
+
 static void
 dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
 {
@@ -679,7 +931,7 @@ dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, p
 }
 
 static void
-dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
+dissect_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *chunk_tree)
 {
   guint16 type, length, padding_length, total_length;
   proto_item *parameter_item;
@@ -695,10 +947,9 @@ dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
        val_to_str(type, sctp_parameter_identifier_values, "Unknown"));
   parameter_tree = proto_item_add_subtree(parameter_item, ett_sctp_chunk_parameter);
  
-  proto_tree_add_uint_format(parameter_tree, hf_sctp_chunk_parameter_type, 
-                            parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH,
-                            type, "Parameter type: %u (%s)",
-                            type, val_to_str(type, sctp_parameter_identifier_values, "unknown"));
+  proto_tree_add_uint(parameter_tree, hf_sctp_chunk_parameter_type, 
+                     parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH,
+                     type);
   proto_tree_add_uint(parameter_tree, hf_sctp_chunk_parameter_length, 
                      parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH,
                      length);
@@ -717,7 +968,7 @@ dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
     dissect_state_cookie_parameter(parameter_tvb, parameter_tree, parameter_item);
     break;
   case UNREC_PARA_PARAMETER_ID:
-    dissect_unrecognized_parameters_parameter(parameter_tvb, parameter_tree, parameter_item);
+    dissect_unrecognized_parameters_parameter(parameter_tvb, pinfo,  parameter_tree, parameter_item);
     break;
   case COOKIE_PRESERVATIVE_PARAMETER_ID:
     dissect_cookie_preservative_parameter(parameter_tvb, parameter_tree, parameter_item);
@@ -729,8 +980,29 @@ dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *chunk_tree)
     dissect_supported_address_types_parameter(parameter_tvb, parameter_tree, parameter_item);
     break;
   case ECN_PARAMETER_ID:
-    dissect_ecn_parameter(parameter_tvb, parameter_tree, parameter_item);
+    dissect_ecn_parameter(parameter_item);
+    break;
+  case FORWARD_TSN_SUPPORTED_PARAMETER_ID:
+    dissect_forward_tsn_supported_parameter(parameter_item);
+    break;
+  case ADD_IP_ADDRESS_PARAMETER_ID:
+    dissect_add_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
     break;
+  case DEL_IP_ADDRESS_PARAMETER_ID:
+    dissect_del_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
+    break;
+  case ERROR_CAUSE_INDICATION_PARAMETER_ID:
+    dissect_error_cause_indication_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
+    break;
+  case SET_PRIMARY_ADDRESS_PARAMETER_ID:
+    dissect_set_primary_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
+    break;    
+  case SUCCESS_REPORT_PARAMETER_ID:
+    dissect_success_report_parameter(parameter_tvb, parameter_tree, parameter_item);
+    break; 
+  case ADAP_LAYER_INDICATION_PARAMETER_ID:
+    dissect_adap_indication_parameter(parameter_tvb, parameter_tree, parameter_item);
+    break;    
   default:
     dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
     break;
@@ -774,11 +1046,9 @@ dissect_missing_mandatory_parameters_cause(tvbuff_t *cause_tvb, proto_tree *caus
   offset = CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET;
   for(missing_parameter_number = 1; missing_parameter_number <= number_of_missing_parameters; missing_parameter_number++) {
     parameter_type = tvb_get_ntohs(cause_tvb, offset);
-    proto_tree_add_uint_format(cause_tree, hf_sctp_cause_missing_parameter_type,
-                              cause_tvb, offset, CAUSE_MISSING_PARAMETER_TYPE_LENGTH,
-                              parameter_type, "Missing parameter type: %u (%s)",
-                              parameter_type, 
-                              val_to_str(parameter_type, sctp_parameter_identifier_values, "unknown"));
+    proto_tree_add_uint(cause_tree, hf_sctp_cause_missing_parameter_type,
+                       cause_tvb, offset, CAUSE_MISSING_PARAMETER_TYPE_LENGTH,
+                       parameter_type);
     offset +=  CAUSE_MISSING_PARAMETER_TYPE_LENGTH;
   };
 
@@ -803,13 +1073,13 @@ dissect_stale_cookie_error_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, pr
 }
 
 static void
-dissect_out_of_resource_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
+dissect_out_of_resource_cause(proto_item *cause_item)
 {
   proto_item_set_text(cause_item, "Error cause reporting lack of resources");
 }
 
 static void
-dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
+dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint16 code, length, parameter_length, parameter_type;
   tvbuff_t *parameter_tvb;
@@ -821,10 +1091,10 @@ dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree,
   parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, 
                                 parameter_length, parameter_length);
 
-  dissect_parameter(parameter_tvb, cause_tree);
+  dissect_parameter(parameter_tvb, pinfo, cause_tree);
   parameter_type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
  
-  proto_item_set_text(cause_item, "Error cause reporting unresolvable address of type %u (%s)",
+  proto_item_set_text(cause_item, "Error cause reporting unresolvable address of type 0x%04x (%s)",
                      parameter_type, val_to_str(parameter_type, sctp_parameter_identifier_values, "unknown") );
 }
 
@@ -840,8 +1110,7 @@ dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb,  packet_info *pinfo,
   
   chunk_length = length - CAUSE_HEADER_LENGTH;
 
-  unrecognized_chunk_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, 
-                                         chunk_length, chunk_length);
+  unrecognized_chunk_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, chunk_length, chunk_length);
   dissect_sctp_chunk(unrecognized_chunk_tvb, pinfo, cause_tree,cause_tree);
 
   unrecognized_type   = tvb_get_guint8(unrecognized_chunk_tvb, CHUNK_TYPE_OFFSET);
@@ -852,25 +1121,23 @@ dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb,  packet_info *pinfo,
 }
 
 static void
-dissect_invalid_mandatory_parameter_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
+dissect_invalid_mandatory_parameter_cause(proto_item *cause_item)
 {
   proto_item_set_text(cause_item, "Error cause reporting an invalid mandatory parameter");
 }
 
 static void
-dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
+dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
 {
   guint16 length, padding_length, cause_info_length;
   tvbuff_t *unrecognized_parameters_tvb;
 
-  length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
-  padding_length = nr_of_padding_bytes(length);
-
+  length            = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
+  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);
-  dissect_tlv_parameter_list(unrecognized_parameters_tvb, cause_tree);
+  unrecognized_parameters_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, cause_info_length);
+  dissect_tlv_parameter_list(unrecognized_parameters_tvb, pinfo, cause_tree);
  
   proto_item_set_text(cause_item, "Error cause reporting unrecognized parameters");
 }
@@ -891,11 +1158,50 @@ dissect_no_user_data_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_it
 }
 
 static void
-dissect_cookie_received_while_shutting_down_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
+dissect_cookie_received_while_shutting_down_cause(proto_item *cause_item)
 {
   proto_item_set_text(cause_item, "Error cause reporting cookie reception while shutting down");
 }
 
+static void
+dissect_delete_last_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
+{
+  guint16 length, cause_info_length;
+  tvbuff_t *parameter_tvb;
+
+  length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
+  cause_info_length = length - CAUSE_HEADER_LENGTH;
+  parameter_tvb    = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, cause_info_length);
+  dissect_parameter(parameter_tvb, pinfo, cause_tree); 
+  proto_item_set_text(cause_item, "Delete last address cause");
+}
+
+static void
+dissect_resource_outage_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
+{
+  guint16 length, cause_info_length;
+  tvbuff_t *parameter_tvb;
+
+  length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
+  cause_info_length = length - CAUSE_HEADER_LENGTH;
+  parameter_tvb    = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, cause_info_length);
+  dissect_parameter(parameter_tvb, pinfo, cause_tree); 
+  proto_item_set_text(cause_item, "Operation refused due to resource shortage");
+}
+
+static void
+dissect_delete_source_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
+{
+  guint16 length, cause_info_length;
+  tvbuff_t *parameter_tvb;
+
+  length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
+  cause_info_length = length - CAUSE_HEADER_LENGTH;
+  parameter_tvb    = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, cause_info_length);
+  dissect_parameter(parameter_tvb, pinfo, cause_tree); 
+  proto_item_set_text(cause_item, "Delete source address cause");
+}
+
 static void
 dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
 {
@@ -931,10 +1237,9 @@ dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_t
                                   "BAD ERROR CAUSE");
   cause_tree = proto_item_add_subtree(cause_item, ett_sctp_chunk_cause);
  
-  proto_tree_add_uint_format(cause_tree, hf_sctp_cause_code, 
-                            cause_tvb, CAUSE_CODE_OFFSET, CAUSE_CODE_LENGTH,
-                            code, "Cause code: %u (%s)",
-                            code, val_to_str(code, sctp_cause_code_values, "unknown"));
+  proto_tree_add_uint(cause_tree, hf_sctp_cause_code, 
+                     cause_tvb, CAUSE_CODE_OFFSET, CAUSE_CODE_LENGTH,
+                     code);
   proto_tree_add_uint(cause_tree, hf_sctp_cause_length, 
                      cause_tvb, CAUSE_LENGTH_OFFSET, CAUSE_LENGTH_LENGTH,
                      length);
@@ -950,25 +1255,34 @@ dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_t
     dissect_stale_cookie_error_cause(cause_tvb, cause_tree, cause_item);
     break;
   case OUT_OF_RESOURCE:
-    dissect_out_of_resource_cause(cause_tvb, cause_tree, cause_item);
+    dissect_out_of_resource_cause(cause_item);
     break;
   case UNRESOLVABLE_ADDRESS:
-    dissect_unresolvable_address_cause(cause_tvb, cause_tree, cause_item);
+    dissect_unresolvable_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
     break;
   case UNRECOGNIZED_CHUNK_TYPE:
     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);
+    dissect_invalid_mandatory_parameter_cause(cause_item);
     break;
   case UNRECOGNIZED_PARAMETERS:
-    dissect_unrecognized_parameters_cause(cause_tvb, cause_tree, cause_item);
+    dissect_unrecognized_parameters_cause(cause_tvb, pinfo, cause_tree, cause_item);
     break;
   case NO_USER_DATA:
     dissect_no_user_data_cause(cause_tvb, cause_tree, cause_item);
     break;
   case COOKIE_RECEIVED_WHILE_SHUTTING_DOWN:
-    dissect_cookie_received_while_shutting_down_cause(cause_tvb, cause_tree, cause_item);
+    dissect_cookie_received_while_shutting_down_cause(cause_item);
+    break;
+  case REQUEST_TO_DELETE_LAST_ADDRESS:
+    dissect_delete_last_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
+    break;
+  case OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE:
+    dissect_resource_outage_cause(cause_tvb, pinfo, cause_tree, cause_item);
+    break;
+  case REQUEST_TO_DELETE_SOURCE_ADDRESS:
+    dissect_delete_source_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
     break;
   default:
     dissect_unknown_cause(cause_tvb, cause_tree, cause_item);
@@ -985,27 +1299,47 @@ dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_t
 */
 
 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)
+dissect_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree, guint32 ppi)
 {
-  /* 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)){
+  guint32 low_port, high_port;
+
+  /* Do lookups with the subdissector table.
+
+     When trying port numbers, we try the port number with the lower value
+     first, followed by the port number with the higher value.  This means
+     that, for packets where a dissector is registered for *both* port
+     numbers, and where there's no match on the PPI:
+
+       1) we pick the same dissector for traffic going in both directions;
+
+       2) we prefer the port number that's more likely to be the right
+          one (as that prefers well-known ports to reserved ports);
+
+     although there is, of course, no guarantee that any such strategy
+     will always pick the right port number.
+
+     XXX - we ignore port numbers of 0, as some dissectors use a port
+     number of 0 to disable the port. */
+  if (dissector_try_port(sctp_ppi_dissector_table, ppi, payload_tvb, pinfo, tree))
     return TRUE;
+  if (pinfo->srcport > pinfo->destport) {
+    low_port = pinfo->destport;
+    high_port = pinfo->srcport;
+  } else {
+    low_port = pinfo->srcport;
+    high_port = pinfo->destport;
   }
-  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;
-  }
+  if (low_port != 0 &&
+      dissector_try_port(sctp_port_dissector_table, low_port, payload_tvb, pinfo, tree))
+    return TRUE;
+  if (high_port != 0 &&
+      dissector_try_port(sctp_port_dissector_table, high_port, payload_tvb, pinfo, tree))
+    return TRUE;
+
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "DATA ");
+  call_dissector(data_handle, payload_tvb, pinfo, tree);
+  return TRUE;
 }
 
 static gboolean
@@ -1023,7 +1357,7 @@ dissect_data_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
   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_length, payload_length);
   payload_proto_id     = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET);
 
   if (chunk_tree) {
@@ -1053,20 +1387,26 @@ dissect_data_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
                        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_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);
+    if (padding_length > 0)
+      proto_tree_add_text(chunk_tree, chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET + payload_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"));
+    proto_item_set_len(chunk_item, DATA_CHUNK_HEADER_LENGTH);
+
   };   
-  return dissect_payload(payload_tvb, pinfo, tree, chunk_tree, payload_proto_id, payload_length, padding_length); 
+  return dissect_payload(payload_tvb, pinfo, tree, payload_proto_id); 
 }
 
 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)
+dissect_init_chunk(tvbuff_t *chunk_tvb,  packet_info *pinfo,
+                  proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint32 initiate_tag, adv_rec_window_credit, initial_tsn;
   guint16 number_of_inbound_streams, number_of_outbound_streams;
@@ -1075,11 +1415,11 @@ dissect_init_chunk(tvbuff_t *chunk_tvb,  packet_info *pinfo, proto_tree *tree,
 
   type                       = tvb_get_guint8(chunk_tvb, CHUNK_TYPE_OFFSET);
   
-  if (check_col(pinfo->fd, COL_INFO)) {
+  if (check_col(pinfo->cinfo, COL_INFO)) {
     if (type == SCTP_INIT_CHUNK_ID) {
-      col_append_str(pinfo->fd, COL_INFO, "INIT ");
+      col_append_str(pinfo->cinfo, COL_INFO, "INIT ");
     } else {
-      col_append_str(pinfo->fd, COL_INFO, "INIT_ACK ");
+      col_append_str(pinfo->cinfo, COL_INFO, "INIT_ACK ");
     };
   };
   
@@ -1114,7 +1454,7 @@ dissect_init_chunk(tvbuff_t *chunk_tvb,  packet_info *pinfo, proto_tree *tree,
     
     /* 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);
+    dissect_tlv_parameter_list(parameter_list_tvb, pinfo, chunk_tree);
     
     proto_item_set_text(chunk_item, 
                        "%s chunk requesting for %u outbound stream%s and accepting up to %u inbound stream%s",
@@ -1125,15 +1465,15 @@ dissect_init_chunk(tvbuff_t *chunk_tvb,  packet_info *pinfo, proto_tree *tree,
 } 
 
 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_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                      proto_tree *chunk_tree, proto_item *chunk_item)
 { 
-  dissect_init_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+  dissect_init_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
 } 
 
 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)
+dissect_sack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                  proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint32 cumulative_tsn_ack, adv_rec_window_credit, dup_tsn;
   guint16 number_of_gap_blocks, number_of_dup_tsns;
@@ -1142,8 +1482,8 @@ dissect_sack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
   proto_item *block_item;
   proto_tree *block_tree;
   
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "SACK ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "SACK ");
 
   if (chunk_tree) {
     cumulative_tsn_ack    = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
@@ -1210,14 +1550,14 @@ dissect_sack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 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)
+dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                       proto_tree *chunk_tree, proto_item *chunk_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 ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "HEARTBEAT ");
 
   if (chunk_tree) {
     chunk_length   = tvb_get_ntohs(chunk_tvb,  CHUNK_LENGTH_OFFSET);
@@ -1226,21 +1566,21 @@ dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tre
     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);
+    dissect_parameter(parameter_tvb, pinfo, chunk_tree);
     
     proto_item_set_text(chunk_item, "HEARTBEAT chunk");
   }
 }
  
 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)
+dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                           proto_tree *chunk_tree, proto_item *chunk_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 ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "HEARTBEAT_ACK ");
 
   if (chunk_tree) {
     chunk_length   = tvb_get_ntohs(chunk_tvb,  CHUNK_LENGTH_OFFSET);
@@ -1250,51 +1590,54 @@ dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree
 
     parameter_tvb  = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET, total_length, total_length);
     
-    dissect_parameter(parameter_tvb, chunk_tree);
+    dissect_parameter(parameter_tvb, pinfo, chunk_tree);
     
     proto_item_set_text(chunk_item, "HEARTBEAT ACK chunk");
   } 
 }
 
 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)
+dissect_abort_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
 {
+  guint8 flags;
   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 ");
+  proto_tree *flag_tree;
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "ABORT ");
 
   if (chunk_tree) {
+    flags     = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
+    flag_tree = proto_item_add_subtree(flags_item, ett_sctp_abort_chunk_flags);
+    proto_tree_add_boolean(flag_tree, hf_sctp_abort_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
+
     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, pinfo, chunk_tree); 
-    /* get rid of the handled parameter */
-    offset += total_length;
-    number_of_causes++;
+    while(tvb_reported_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, 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"));
   } 
 }
 
 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)
+dissect_shutdown_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                      proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint32 cumulative_tsn_ack;
  
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "SHUTDOWN ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "SHUTDOWN ");
 
   if (chunk_tree) {
     cumulative_tsn_ack = tvb_get_ntohl(chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
@@ -1310,11 +1653,11 @@ dissect_shutdown_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree
 }
 
 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)
+dissect_shutdown_ack_chunk(packet_info *pinfo,
+                          proto_tree *chunk_tree, proto_item *chunk_item)
 { 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "SHUTDOWN_ACK ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "SHUTDOWN_ACK ");
 
   if (chunk_tree) {
     proto_item_set_text(chunk_item, "SHUTDOWN ACK chunk");
@@ -1322,15 +1665,15 @@ dissect_shutdown_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *
 }
 
 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)
+dissect_error_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                   proto_tree *chunk_tree, proto_item *chunk_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, "ERROR ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "ERROR ");
 
   if (chunk_tree) {
     number_of_causes = 0;
@@ -1345,7 +1688,7 @@ dissect_error_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
       /* get rid of the handled parameter */
       offset += total_length;
       number_of_causes++;
-    } while(tvb_length_remaining(chunk_tvb, offset));
+    } while(tvb_reported_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"));
@@ -1353,8 +1696,8 @@ dissect_error_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 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)
+dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                         proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint length, cookie_length, padding_length;
 
@@ -1362,8 +1705,8 @@ dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *t
   padding_length = nr_of_padding_bytes(length);
   cookie_length  = length - CHUNK_HEADER_LENGTH;
  
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "COOKIE_ECHO ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "COOKIE_ECHO ");
 
   if (chunk_tree) {  
     proto_tree_add_text(chunk_tree, chunk_tvb, COOKIE_ECHO_CHUNK_COOKIE_OFFSET, cookie_length,
@@ -1380,11 +1723,11 @@ dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *t
 }
 
 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)
+dissect_cookie_ack_chunk(packet_info *pinfo,
+                        proto_tree *chunk_tree, proto_item *chunk_item)
 {  
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "COOKIE_ACK ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "COOKIE_ACK ");
 
   if (chunk_tree) {
     proto_item_set_text(chunk_item, "COOKIE ACK chunk");
@@ -1392,13 +1735,13 @@ dissect_cookie_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tr
 }
 
 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)
+dissect_ecne_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                  proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint32 lowest_tsn;
  
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "ECNE ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "ECNE ");
 
   if (chunk_tree) {
     lowest_tsn = tvb_get_ntohl(chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET);
@@ -1412,13 +1755,13 @@ dissect_ecne_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 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)
+dissect_cwr_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                 proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint32 lowest_tsn;
   
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "CWR ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "CWR ");
 
   if (chunk_tree) {
     lowest_tsn = tvb_get_ntohl(chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET);
@@ -1432,21 +1775,21 @@ dissect_cwr_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 static void
-dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree,
+dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
                                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 ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "SHUTDOWN_COMPLETE ");
 
   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);
+    flag_tree = proto_item_add_subtree(flags_item, ett_sctp_shutdown_complete_chunk_flags);
     proto_tree_add_boolean(flag_tree, hf_sctp_shutdown_complete_chunk_t_bit, chunk_tvb,
                           CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, flags);
     
@@ -1454,15 +1797,115 @@ dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_t
   } 
 }
 
+#define FORWARD_TSN_CHUNK_TSN_LENGTH 4
+#define FORWARD_TSN_CHUNK_SID_LENGTH 2
+#define FORWARD_TSN_CHUNK_SSN_LENGTH 2
+#define FORWARD_TSN_CHUNK_TSN_OFFSET CHUNK_VALUE_OFFSET
+#define FORWARD_TSN_CHUNK_SID_OFFSET 0
+#define FORWARD_TSN_CHUNK_SSN_OFFSET (FORWARD_TSN_CHUNK_SID_OFFSET + FORWARD_TSN_CHUNK_SID_LENGTH)
+
+static void
+dissect_forward_tsn_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
+{ 
+  guint32 tsn;
+  guint   offset;
+  guint16 number_of_affected_streams, affected_stream, length, sid, ssn;
+  
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "FORWARD TSN ");
+
+  if (chunk_tree) {
+    tsn = tvb_get_ntohl(chunk_tvb, FORWARD_TSN_CHUNK_TSN_OFFSET);
+    proto_tree_add_uint(chunk_tree, hf_sctp_forward_tsn_chunk_tsn, chunk_tvb, FORWARD_TSN_CHUNK_TSN_OFFSET, FORWARD_TSN_CHUNK_TSN_LENGTH, tsn);
+    length = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
+    number_of_affected_streams = (length - CHUNK_HEADER_LENGTH - FORWARD_TSN_CHUNK_TSN_LENGTH) /
+                                 (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH);
+    offset = CHUNK_VALUE_OFFSET + FORWARD_TSN_CHUNK_TSN_LENGTH;
+    
+    for(affected_stream = 0;  affected_stream < number_of_affected_streams; affected_stream++) {
+        sid    = tvb_get_ntohs(chunk_tvb, offset + FORWARD_TSN_CHUNK_SID_OFFSET);
+        ssn    = tvb_get_ntohs(chunk_tvb, offset + FORWARD_TSN_CHUNK_SSN_OFFSET);
+        proto_tree_add_uint(chunk_tree, hf_sctp_forward_tsn_chunk_sid, 
+                                       chunk_tvb, offset + FORWARD_TSN_CHUNK_SID_OFFSET, FORWARD_TSN_CHUNK_SID_LENGTH, sid);
+        proto_tree_add_uint(chunk_tree, hf_sctp_forward_tsn_chunk_ssn, 
+                                       chunk_tvb, offset + FORWARD_TSN_CHUNK_SSN_OFFSET, FORWARD_TSN_CHUNK_SSN_LENGTH, ssn);
+        offset = offset + (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH);
+    }
+    proto_item_set_text(chunk_item, "FORWARD TSN chunk (new cumulative TSN %u)", tsn);
+  } 
+}
+
+#define SERIAL_NUMBER_LENGTH    4
+#define SERIAL_NUMBER_OFFSET    PARAMETER_VALUE_OFFSET
+
+static void
+dissect_asconf_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
+{ 
+  guint32 serial_number;
+  guint offset, length, padding_length, total_length;
+  tvbuff_t *parameter_tvb;
+
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "ASCONF ");
+
+  if (chunk_tree) {
+    offset = SERIAL_NUMBER_OFFSET;
+    serial_number    = tvb_get_ntohl(chunk_tvb, offset);
+    proto_tree_add_uint(chunk_tree, hf_sctp_asconf_serial, chunk_tvb, offset, SERIAL_NUMBER_LENGTH, serial_number);
+    offset          += SERIAL_NUMBER_LENGTH;
+    proto_item_set_text(chunk_item, "ASCONF chunk");
+    
+    while(tvb_reported_length_remaining(chunk_tvb, offset)) {
+      length         = tvb_get_ntohs(chunk_tvb, offset + PARAMETER_LENGTH_OFFSET);
+      padding_length = nr_of_padding_bytes(length);
+      total_length   = length + padding_length;
+      /* create a tvb for the chunk including the padding bytes */
+      parameter_tvb  = tvb_new_subset(chunk_tvb, offset, total_length, total_length);
+      dissect_parameter(parameter_tvb, pinfo, chunk_tree); 
+      /* get rid of the handled parameter */
+      offset        += total_length;
+    }
+  } 
+}
+
+static void
+dissect_asconf_ack_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
+{ 
+  guint32 serial_number;
+  guint offset, length, padding_length, total_length;
+  tvbuff_t *parameter_tvb;
+
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "ASCONF-ACK ");
+
+  if (chunk_tree) {
+    serial_number = tvb_get_ntohl(chunk_tvb, SERIAL_NUMBER_OFFSET);
+    proto_tree_add_uint(chunk_tree, hf_sctp_asconf_ack_serial, chunk_tvb, SERIAL_NUMBER_OFFSET, SERIAL_NUMBER_LENGTH, serial_number);
+    proto_item_set_text(chunk_item, "ASCONF-ACK chunk");
+    
+    offset = SERIAL_NUMBER_OFFSET + SERIAL_NUMBER_LENGTH;
+    while(tvb_reported_length_remaining(chunk_tvb, offset)) {
+      length         = tvb_get_ntohs(chunk_tvb, offset + PARAMETER_LENGTH_OFFSET);
+      padding_length = nr_of_padding_bytes(length);
+      total_length   = length + padding_length;
+      /* create a tvb for the chunk including the padding bytes */
+      parameter_tvb  = tvb_new_subset(chunk_tvb, offset, total_length, total_length);
+      dissect_parameter(parameter_tvb, pinfo, chunk_tree); 
+      /* get rid of the handled parameter */
+      offset        += total_length;
+    }
+  } 
+}
+
 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)
+dissect_unknown_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo,
+                     proto_tree *chunk_tree, proto_item *chunk_item)
 { 
   guint length, chunk_value_length, padding_length;
   guint8 type;
   
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "UNKNOWN ");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "UNKNOWN ");
 
   if (chunk_tree) {
     length         = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
@@ -1505,21 +1948,13 @@ dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, pr
  
   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_item   = proto_tree_add_text(sctp_tree, chunk_tvb, CHUNK_HEADER_OFFSET, -1, "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);
+    proto_tree_add_uint(chunk_tree, hf_sctp_chunk_type, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, type);
+    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;
@@ -1533,57 +1968,65 @@ dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, pr
     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, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_init_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_INIT_ACK_CHUNK_ID:
-    dissect_init_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_init_ack_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_SACK_CHUNK_ID:
-    dissect_sack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_sack_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break; 
   case SCTP_HEARTBEAT_CHUNK_ID:
-    dissect_heartbeat_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_heartbeat_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_HEARTBEAT_ACK_CHUNK_ID:
-    dissect_heartbeat_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_heartbeat_ack_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_ABORT_CHUNK_ID:
-    dissect_abort_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_abort_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item, flags_item);
     break;
   case SCTP_SHUTDOWN_CHUNK_ID:
-    dissect_shutdown_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_shutdown_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_SHUTDOWN_ACK_CHUNK_ID:
-    dissect_shutdown_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_shutdown_ack_chunk(pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_ERROR_CHUNK_ID:
-    dissect_error_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_error_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_COOKIE_ECHO_CHUNK_ID:
-    dissect_cookie_echo_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_cookie_echo_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_COOKIE_ACK_CHUNK_ID:
-    dissect_cookie_ack_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_cookie_ack_chunk(pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_ECNE_CHUNK_ID:
-    dissect_ecne_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_ecne_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_CWR_CHUNK_ID:
-    dissect_cwr_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_cwr_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   case SCTP_SHUTDOWN_COMPLETE_CHUNK_ID:
-    dissect_shutdown_complete_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
-      break;
+    dissect_shutdown_complete_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item, flags_item);
+    break;
+  case SCTP_FORWARD_TSN_CHUNK_ID:
+    dissect_forward_tsn_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
+    break;
+  case SCTP_ASCONF_ACK_CHUNK_ID:
+    dissect_asconf_ack_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
+    break;
+  case SCTP_ASCONF_CHUNK_ID:
+    dissect_asconf_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
+    break;
   default:
-    dissect_unknown_chunk(chunk_tvb, pinfo, tree, chunk_tree, chunk_item, flags_item);
+    dissect_unknown_chunk(chunk_tvb, pinfo, chunk_tree, chunk_item);
     break;
   };
   return result;
 }
 
 static void
-dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-                   proto_item *sctp_item, proto_tree *sctp_tree)
+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;
@@ -1595,7 +2038,7 @@ dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
   offset = COMMON_HEADER_LENGTH;
   sctp_item_length_set = FALSE;
 
-  while(tvb_length_remaining(tvb, offset) > 0) {
+  while(tvb_reported_length_remaining(tvb, offset) > 0) {
     /* extract the chunk length and compute number of padding bytes */
     length         = tvb_get_ntohs(tvb, offset + CHUNK_LENGTH_OFFSET);
     padding_length = nr_of_padding_bytes(length);
@@ -1608,8 +2051,8 @@ dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
       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);
+      if (tvb_reported_length_remaining(tvb, offset) > 0) {
+       sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, offset, -1, FALSE);
        sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
        sctp_item_length_set = FALSE;
       }
@@ -1631,7 +2074,9 @@ static void
 dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   guint16 source_port, destination_port;
-  guint32 verification_tag, checksum;
+  guint32 verification_tag, checksum, calculated_crc32c, calculated_adler32;
+  guint length;
+  gboolean crc32c_correct, adler32_correct;
   proto_item *sctp_item;
   proto_tree *sctp_tree;
 
@@ -1647,34 +2092,75 @@ dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   pinfo->destport = destination_port;
 
   /* make entry in the Protocol column on summary display */
-  if (check_col(pinfo->fd, COL_PROTOCOL)) 
-    col_set_str(pinfo->fd, COL_PROTOCOL, "SCTP");
+  if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCTP");
 
   /* Clear entries in Info column on summary display */
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_str(pinfo->fd, COL_INFO, "");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_str(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) {
     /* create the sctp protocol tree */
-    sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, 0, 0, FALSE);
+    sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, 0, -1, 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, 
-                       tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH,
-                       source_port);
-    proto_tree_add_uint(sctp_tree, hf_sctp_destination_port,
-                       tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH,
-                       destination_port);
-    proto_tree_add_uint(sctp_tree, hf_sctp_verification_tag,
-                       tvb, VERIFICATION_TAG_OFFSET, VERIFICATION_TAG_LENGTH,
-                       verification_tag);
-    proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum,
-                              tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum,
-                              "Adler-32 checksum: 0x%08x (%s)",
-                              checksum, sctp_checksum_state(tvb, checksum));
+    proto_tree_add_uint(sctp_tree, hf_sctp_source_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, source_port);
+    proto_tree_add_uint(sctp_tree, hf_sctp_destination_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, destination_port);
+    proto_tree_add_uint(sctp_tree, hf_sctp_verification_tag, tvb, VERIFICATION_TAG_OFFSET, VERIFICATION_TAG_LENGTH, verification_tag);
+    proto_tree_add_uint_hidden(sctp_tree, hf_sctp_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, source_port);
+    proto_tree_add_uint_hidden(sctp_tree, hf_sctp_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, destination_port);
+
+    length = tvb_length(tvb);
+    switch(sctp_checksum) {
+    case SCTP_CHECKSUM_NONE:
+      proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum, "Checksum: 0x%08x (not verified)", checksum);
+      break;
+    case SCTP_CHECKSUM_ADLER32:
+      calculated_adler32 = sctp_adler32(tvb_get_ptr(tvb, 0, length), length);
+      adler32_correct    = (checksum == calculated_adler32);
+      if (adler32_correct)
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
+                                   checksum, "Checksum: 0x%08x (correct Adler32)", checksum);
+      else
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, 
+                                   checksum, "Checksum: 0x%08x (incorrect Adler32, should be 0x%08x)", checksum, calculated_adler32);    
+      proto_tree_add_boolean_hidden(sctp_tree, hf_sctp_checksum_bad, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, !(adler32_correct));
+      break;
+    case SCTP_CHECKSUM_CRC32C:
+      calculated_crc32c = sctp_crc32c(tvb_get_ptr(tvb, 0, length), length);
+      crc32c_correct    = (checksum == calculated_crc32c);
+      if (crc32c_correct)
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
+                                   checksum, "Checksum: 0x%08x (correct CRC32C)", checksum);
+      else
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, 
+                                   checksum, "Checksum: 0x%08x (incorrect CRC32C, should be 0x%08x)", checksum, calculated_crc32c);    
+      proto_tree_add_boolean_hidden(sctp_tree, hf_sctp_checksum_bad, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, !(crc32c_correct));
+      break;
+    case SCTP_CHECKSUM_AUTOMATIC:
+      calculated_adler32 = sctp_adler32(tvb_get_ptr(tvb, 0, length), length);
+      adler32_correct    = (checksum == calculated_adler32);
+      calculated_crc32c  = sctp_crc32c(tvb_get_ptr(tvb, 0, length), length);
+      crc32c_correct     = (checksum == calculated_crc32c);
+      if ((adler32_correct) && !(crc32c_correct))
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
+                                   checksum, "Checksum: 0x%08x (correct Adler32)", checksum);
+      else if (!(adler32_correct) && (crc32c_correct))
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
+                                   checksum, "Checksum: 0x%08x (correct CRC32C)", checksum);
+      else if ((adler32_correct) && (crc32c_correct))
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
+                                   checksum, "Checksum: 0x%08x (correct Adler32 and CRC32C)", checksum);
+      else
+        proto_tree_add_uint_format(sctp_tree, hf_sctp_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, 
+                                   checksum, "Checksum: 0x%08x (incorrect, should be 0x%08x (Adler32) or 0x%08x (CRC32C))",
+                                   checksum, calculated_adler32, calculated_crc32c);
+      proto_tree_add_boolean_hidden(sctp_tree, hf_sctp_checksum_bad, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, !(crc32c_correct || adler32_correct));
+      break;
+    }
   } else {
     sctp_tree = NULL;
     sctp_item = NULL;
@@ -1692,27 +2178,37 @@ proto_register_sctp(void)
   static hf_register_info hf[] = {
     { &hf_sctp_source_port,
       { "Source port", "sctp.srcport",
-       FT_UINT16, BASE_DEC, NULL, 0x0,          
-       "", HFILL }
+             FT_UINT16, BASE_DEC, NULL, 0x0,          
+             "", HFILL }
     },
     { &hf_sctp_destination_port,
       { "Destination port", "sctp.dstport",
-       FT_UINT16, BASE_DEC, NULL, 0x0,          
-       "", HFILL }
+              FT_UINT16, BASE_DEC, NULL, 0x0,          
+              "", HFILL }
+    }, 
+    { &hf_sctp_port,
+      { "Port", "sctp.port",
+              FT_UINT16, BASE_DEC, NULL, 0x0,          
+              "", HFILL }
     }, 
     { &hf_sctp_verification_tag,
       { "Verification tag", "sctp.verfication_tag",
-       FT_UINT32, BASE_HEX, NULL, 0x0,          
-       "", HFILL }
+              FT_UINT32, BASE_HEX, NULL, 0x0,          
+              "", HFILL }
     },
     { &hf_sctp_checksum,
-      { "Adler-32 checksum", "sctp.checksum",
-       FT_UINT32, BASE_HEX, NULL, 0x0,          
-       "", HFILL }
+      { "Checksum", "sctp.checksum",
+             FT_UINT32, BASE_HEX, NULL, 0x0,          
+             "", HFILL }
+    },
+    { &hf_sctp_checksum_bad,
+      { "Bad checksum", "sctp.checksum_bad",
+             FT_BOOLEAN, BASE_NONE, NULL, 0x0,          
+             "", HFILL }
     },
     { &hf_sctp_chunk_type,
       { "Identifier", "sctp.chunk_type",
-       FT_UINT8, BASE_DEC, NULL, 0x0,          
+       FT_UINT8, BASE_DEC, VALS(sctp_chunk_type_values), 0x0,          
        "", HFILL }
     },
     { &hf_sctp_chunk_flags,
@@ -1771,8 +2267,8 @@ proto_register_sctp(void)
        "", HFILL }
     },
     {&hf_sctp_data_chunk_payload_proto_id,
-     { "Payload Protocol identifier", "sctp.payload_proto_id",
-       FT_UINT32, BASE_HEX, NULL, 0x0,          
+     { "Payload protocol identifier", "sctp.payload_proto_id",
+       FT_UINT32, BASE_DEC, VALS(sctp_payload_proto_id_values), 0x0,          
        "", HFILL }
     },
     {&hf_sctp_data_chunk_e_bit,
@@ -1841,13 +2337,33 @@ proto_register_sctp(void)
        "", HFILL }
     }, 
     {&hf_sctp_shutdown_complete_chunk_t_bit,
-     { "E-Bit", "sctp.shutdown_complete.t_bit",
+     { "T-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_abort_chunk_t_bit,
+     { "T-Bit", "sctp.abort.t_bit",
        FT_BOOLEAN, 8, TFS(&sctp_shutdown_complete_chunk_t_bit_value), SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT,
        "", HFILL }
     },
+    {&hf_sctp_forward_tsn_chunk_tsn,
+     { "New cumulative TSN", "sctp.forward_tsn.tsn",
+       FT_UINT32, BASE_DEC, NULL, 0x0,          
+       "", HFILL }
+    }, 
+    {&hf_sctp_forward_tsn_chunk_sid,
+     { "Stream identifier", "sctp.forward_tsn.sid",
+       FT_UINT16, BASE_DEC, NULL, 0x0,          
+       "", HFILL }
+    }, 
+    {&hf_sctp_forward_tsn_chunk_ssn,
+     { "Stream sequence number", "sctp.forward_tsn.ssn",
+       FT_UINT16, BASE_DEC, NULL, 0x0,          
+       "", HFILL }
+    }, 
     {&hf_sctp_chunk_parameter_type,
      { "Parameter type", "sctp.parameter.type",
-       FT_UINT16, BASE_HEX, NULL, 0x0,          
+       FT_UINT16, BASE_HEX, VALS(sctp_parameter_identifier_values), 0x0,
        "", HFILL }
     },
     {&hf_sctp_chunk_parameter_length,
@@ -1880,9 +2396,29 @@ proto_register_sctp(void)
        FT_UINT16, BASE_DEC, NULL, 0x0,          
        "", HFILL }
     }, 
+    {&hf_sctp_asconf_serial,
+     { "Serial Number", "sctp.asconf.serial_number",
+       FT_UINT32, BASE_HEX, NULL, 0x0,          
+       "", HFILL }
+    }, 
+    {&hf_sctp_asconf_ack_serial,
+     { "Serial Number", "sctp.asconf_ack.serial_number",
+       FT_UINT32, BASE_HEX, NULL, 0x0,          
+       "", HFILL }
+    }, 
+    {&hf_sctp_correlation_id,
+     { "Correlation_id", "sctp.correlation_id",
+       FT_UINT32, BASE_HEX, NULL, 0x0,          
+       "", HFILL }
+    },
+    {&hf_sctp_adap_indication,
+     { "Indication", "sctp.adapation_layer_indication.indication",
+       FT_UINT32, BASE_HEX, NULL, 0x0,          
+       "", HFILL }
+    }, 
     {&hf_sctp_cause_code,
      { "Cause code", "sctp.cause.code",
-       FT_UINT16, BASE_DEC, NULL, 0x0,          
+       FT_UINT16, BASE_HEX, VALS(sctp_cause_code_values), 0x0,          
        "", HFILL }
     },
     {&hf_sctp_cause_length,
@@ -1901,8 +2437,8 @@ proto_register_sctp(void)
        "", HFILL }
     }, 
     {&hf_sctp_cause_missing_parameter_type,
-     { "Missing parameters type", "sctp.cause.missing_parameter_type",
-       FT_UINT16, BASE_DEC, NULL, 0x0,          
+     { "Missing parameter type", "sctp.cause.missing_parameter_type",
+       FT_UINT16, BASE_HEX, VALS(sctp_parameter_identifier_values), 0x0,
        "", HFILL }
     },
     {&hf_sctp_cause_measure_of_staleness,
@@ -1924,27 +2460,45 @@ proto_register_sctp(void)
     &ett_sctp_chunk_parameter,
     &ett_sctp_chunk_cause,
     &ett_sctp_data_chunk_flags,
+    &ett_sctp_shutdown_complete_chunk_flags,
+    &ett_sctp_abort_chunk_flags,
     &ett_sctp_sack_chunk_gap_block,
     &ett_sctp_supported_address_types_parameter,
-    &ett_sctp_unrecognized_parameter_parameter
+    &ett_sctp_unrecognized_parameter_parameter,
   };
   
+  static enum_val_t sctp_checksum_options[] = {
+    { "None",        SCTP_CHECKSUM_NONE },
+    { "Adler 32",    SCTP_CHECKSUM_ADLER32 },
+    { "CRC 32c",     SCTP_CHECKSUM_CRC32C },
+    { "Automatic",   SCTP_CHECKSUM_AUTOMATIC},
+    { NULL, 0 }
+  };
   /* Register the protocol name and description */
-  proto_sctp = proto_register_protocol("Stream Control Transmission Protocol",
-                                      "SCTP", "sctp");
-  
+  proto_sctp = proto_register_protocol("Stream Control Transmission Protocol", "SCTP", "sctp");
+  sctp_module = prefs_register_protocol(proto_sctp, NULL);
+  prefs_register_enum_preference(sctp_module, "checksum",
+                                "Checksum type",
+                                "The type of checksum used in SCTP packets",
+                                 &sctp_checksum, sctp_checksum_options, FALSE);
+
   /* 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");
+  sctp_port_dissector_table = register_dissector_table("sctp.port", "SCTP port", FT_UINT16, BASE_DEC);
+  sctp_ppi_dissector_table  = register_dissector_table("sctp.ppi",  "SCTP payload protocol identifier", FT_UINT32, BASE_HEX);
 
-};
+}
 
 void
 proto_reg_handoff_sctp(void)
 {
-       dissector_add("ip.proto", IP_PROTO_SCTP, dissect_sctp, proto_sctp);
+  dissector_handle_t sctp_handle;
+
+  data_handle = find_dissector("data");
+  sctp_handle = create_dissector_handle(dissect_sctp, proto_sctp);
+  dissector_add("ip.proto", IP_PROTO_SCTP, sctp_handle);
 }