Add separate union entries to fvalue.value for signed and unsigned
[obnox/wireshark/wip.git] / epan / dissectors / packet-catapult-dct2000.c
index d63d98652ff77bf778c63805e72247991ab0125c..53da6200128aaec54600bb06245a030ae39cf54c 100644 (file)
 # include "config.h"
 #endif
 
+#include <glib.h>
+
 #include <string.h>
+#include <ctype.h>
 #include <epan/packet.h>
 #include <epan/emem.h>
 #include <epan/proto.h>
 #include <epan/prefs.h>
+#include <epan/strutil.h>
+#include <epan/addr_resolv.h>
 
 #include <wiretap/catapult_dct2000.h>
+#include "packet-umts_fp.h"
 
 /* Protocol and registered fields. */
 static int proto_catapult_dct2000 = -1;
@@ -46,6 +52,19 @@ static int hf_catapult_dct2000_outhdr = -1;
 static int hf_catapult_dct2000_direction = -1;
 static int hf_catapult_dct2000_encap = -1;
 static int hf_catapult_dct2000_unparsed_data = -1;
+static int hf_catapult_dct2000_dissected_length = -1;
+
+static int hf_catapult_dct2000_ipprim_addresses = -1;
+static int hf_catapult_dct2000_ipprim_src_addr = -1;
+static int hf_catapult_dct2000_ipprim_dst_addr = -1;
+static int hf_catapult_dct2000_ipprim_addr = -1;
+static int hf_catapult_dct2000_ipprim_udp_src_port = -1;
+static int hf_catapult_dct2000_ipprim_udp_dst_port = -1;
+static int hf_catapult_dct2000_ipprim_udp_port = -1;
+static int hf_catapult_dct2000_ipprim_tcp_src_port = -1;
+static int hf_catapult_dct2000_ipprim_tcp_dst_port = -1;
+static int hf_catapult_dct2000_ipprim_tcp_port = -1;
+
 
 /* Variables used for preferences */
 gboolean catapult_dct2000_try_ipprim_heuristic = TRUE;
@@ -53,6 +72,7 @@ gboolean catapult_dct2000_try_sctpprim_heuristic = TRUE;
 
 /* Protocol subtree. */
 static int ett_catapult_dct2000 = -1;
+static int ett_catapult_dct2000_ipprim = -1;
 
 static const value_string direction_vals[] = {
     { 0,   "Sent" },
@@ -69,22 +89,38 @@ static const value_string encap_vals[] = {
     { DCT2000_ENCAP_SSCOP,               "SSCOP" },
     { WTAP_ENCAP_FRELAY,                 "Frame Relay" },
     { WTAP_ENCAP_MTP2,                   "MTP2" },
+    { DCT2000_ENCAP_NBAP,                "NBAP" },
     { DCT2000_ENCAP_UNHANDLED,           "Unhandled Protocol" },
     { 0,                                 NULL },
 };
 
 
+#define MAX_OUTHDR_VALUES 32
+
+static guint outhdr_values[MAX_OUTHDR_VALUES];
+static gint outhdr_values_found = 0;
+
+extern int proto_fp;
+
+
 void proto_reg_handoff_catapult_dct2000(void);
 void proto_register_catapult_dct2000(void);
 
+static dissector_handle_t look_for_dissector(char *protocol_name);
+static void parse_outhdr_string(guchar *outhdr_string);
+static void attach_fp_info(packet_info *pinfo, gboolean received,
+                           const char *protocol_name, int variant);
+
 
 /* Look for the protocol data within an ipprim packet.
    Only set *data_offset if data field found. */
-static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset)
+static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset,
+                                        guint32 *source_addr_offset, guint32 *dest_addr_offset,
+                                        guint32 *source_port_offset, guint32 *dest_port_offset,
+                                        port_type *type_of_port)
 {
     guint8 length;
     int offset = *data_offset;
-    gboolean is_udp;
 
     /* Get the ipprim command code. */
     guint8 tag = tvb_get_guint8(tvb, offset++);
@@ -94,11 +130,11 @@ static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset)
     {
         case 0x23:  /* UDP data request */
         case 0x24:  /* UDP data indication */
-            is_udp = TRUE;
+            *type_of_port = PT_UDP;
             break;
         case 0x45:  /* TCP data request */
         case 0x46:  /* TCP data indication */
-            is_udp = FALSE;
+            *type_of_port = PT_TCP;
             break;
         default:
             return FALSE;
@@ -111,7 +147,8 @@ static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset)
         tag = tvb_get_guint8(tvb, offset++);
 
         /* Is this the data payload we're expecting? */
-        if ((tag == 0x34 && is_udp) || (tag == 0x48 && !is_udp))
+        if (((tag == 0x34) && (*type_of_port == PT_UDP)) ||
+            ((tag == 0x48) && (*type_of_port == PT_TCP)))
         {
             *data_offset = offset;
             return TRUE;
@@ -120,6 +157,29 @@ static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset)
         {
             /* Read length in next byte */
             length = tvb_get_guint8(tvb, offset++);
+
+            if (tag == 0x31 && length >=4 && length <= 6)
+            {
+                /* Dest IP address */
+                *dest_addr_offset = offset;
+
+                /* Dest port follows (if present) */
+                if (length > 4)
+                {
+                    *dest_port_offset = offset + 4;
+                }
+            }
+            if (tag == 0x32 && length == 4)
+            {
+                /* Source IP address */
+                *source_addr_offset = offset;
+            }
+            if (tag == 0x33 && length == 2)
+            {
+                /* Get source port */
+                *source_port_offset = offset;
+            }
+
             /* Skip the following value */
             offset += length;
         }
@@ -139,10 +199,11 @@ static gboolean find_sctpprim_variant1_data_offset(tvbuff_t *tvb, int *data_offs
     int offset = *data_offset;
 
     /* Get the sctpprim command code. */
-    guint8 tag = tvb_get_guint8(tvb, offset++);
+    guint8 first_tag = tvb_get_guint8(tvb, offset++);
+    guint8 tag;
 
     /* Only accept interested in data requests or indications */
-    switch (tag)
+    switch (first_tag)
     {
         case 0x04:  /* data request */
         case 0x62:  /* data indication */
@@ -151,17 +212,24 @@ static gboolean find_sctpprim_variant1_data_offset(tvbuff_t *tvb, int *data_offs
             return FALSE;
     }
 
-    /* Length field. msb set indicates 2 bytes */
-    if (tvb_get_guint8(tvb, offset) & 0x80)
+    if (first_tag == 0x04)
     {
-        offset += 2;
+        /* Overall length field. msb set indicates 2 bytes */
+        if (tvb_get_guint8(tvb, offset) & 0x80)
+        {
+            offset += 2;
+        }
+        else
+        {
+            offset++;
+        }
     }
     else
     {
-        offset++;
+        offset += 3;
     }
 
-    /* Skip any other TLC fields before reach payload */
+    /* Skip any other fields before reach payload */
     while (tvb_length_remaining(tvb, offset) > 2)
     {
         /* Look at next tag */
@@ -175,10 +243,29 @@ static gboolean find_sctpprim_variant1_data_offset(tvbuff_t *tvb, int *data_offs
         }
         else
         {
-            /* Read length in next byte */
-            length = tvb_get_guint8(tvb, offset++);
-            /* Skip the following value */
-            offset += length;
+            if (first_tag == 0x62)
+            {
+                switch (tag)
+                {
+                    case 0x0a: /* dest port */
+                    case 0x1e: /* strseqnum */
+                    case 0x0d:
+                        offset += 2;
+                        continue;
+                    case 0x1d:
+                    case 0x09:
+                    case 0x0c:
+                        offset += 4;
+                        continue;
+                }
+            }
+            else
+            {
+                /* Read length in next byte */
+                length = tvb_get_guint8(tvb, offset++);
+                /* Skip the following value */
+                offset += length;
+            }
         }
     }
 
@@ -229,6 +316,9 @@ static gboolean find_sctpprim_variant3_data_offset(tvbuff_t *tvb, int *data_offs
             /* 2-byte length field */
             offset += 2;
 
+            /* Skip 2-byte length field */
+            offset += 2;
+
             /* Data is here!!! */
             *data_offset = offset;
             return TRUE;
@@ -301,10 +391,41 @@ dissector_handle_t look_for_dissector(char *protocol_name)
     else
     if ((strcmp(protocol_name, "xcap_caps") == 0) ||
         (strcmp(protocol_name, "mm1") == 0) ||
+        (strcmp(protocol_name, "mm3") == 0) ||
         (strcmp(protocol_name, "mm7") == 0))
     {
         return find_dissector("http");
     }
+    else
+    if ((strcmp(protocol_name, "fp") == 0) ||
+        (strcmp(protocol_name, "fp_r4") == 0) ||
+        (strcmp(protocol_name, "fp_r5") == 0) ||
+        (strcmp(protocol_name, "fp_r6") == 0) ||
+        (strcmp(protocol_name, "fpiur_r5") == 0))
+    {
+        return find_dissector("fp");
+    }
+    else
+    if ((strcmp(protocol_name, "iuup_rtp_r5") == 0) ||
+        (strcmp(protocol_name, "iuup_rtp_r6") == 0))
+    {
+        return find_dissector("rtp");
+    }
+    else
+    if (strcmp(protocol_name, "sipt") == 0)
+    {
+        return find_dissector("sip");
+    }
+    else
+    if (strncmp(protocol_name, "nbap_sctp", strlen("nbap_sctp")) == 0)
+    {
+        return find_dissector("nbap");
+    }
+    else
+    if (strncmp(protocol_name, "gtp", strlen("gtp")) == 0)
+    {
+        return find_dissector("gtp");
+    }
 
     /* Try for an exact match */
     else
@@ -314,14 +435,169 @@ dissector_handle_t look_for_dissector(char *protocol_name)
 }
 
 
+/* Populate outhdr_values array with numbers found in outhdr_string */
+void parse_outhdr_string(guchar *outhdr_string)
+{
+    int n = 0;
+
+    /* Populate values array */
+    for (outhdr_values_found=0; outhdr_values_found < MAX_OUTHDR_VALUES; )
+    {
+        guint start_i = n;
+        guint digits;
+
+        /* Find digits */
+        for (digits = 0; digits < strlen((gchar*)outhdr_string); digits++, n++)
+        {
+            if (!isdigit(outhdr_string[n]))
+            {
+                break;
+            }
+        }
+
+        if (digits == 0)
+        {
+            /* No more numbers left */
+            break;
+        }
+
+        /* Convert digits into value */
+        outhdr_values[outhdr_values_found++] =
+            atoi((char*)format_text((guchar*)outhdr_string+start_i, digits));
+
+        /* Skip comma */
+        n++;
+    }
+}
+
+/* Fill in an FP packet info struct and attach it to the packet for the FP
+   dissector to use */
+void attach_fp_info(packet_info *pinfo, gboolean received, const char *protocol_name, int variant)
+{
+    int i=0;
+    int chan;
+    int tf_start, num_chans_start;
+
+    /* Allocate & zero struct */
+    struct _fp_info *p_fp_info = se_alloc(sizeof(struct _fp_info));
+    if (!p_fp_info)
+    {
+        return;
+    }
+    memset(p_fp_info, 0, sizeof(struct _fp_info));
+
+    /* Check that the number of outhdr values looks sensible */
+    if (((strcmp(protocol_name, "fpiur_r5") == 0) && (outhdr_values_found != 2)) ||
+        (outhdr_values_found < 5))
+    {
+        return;
+    }
+
+    /* 3gpp release (99, 4, 5, 6) */
+    if (strcmp(protocol_name, "fp") == 0)
+    {
+        p_fp_info->release = 99;
+    }
+    else if (strcmp(protocol_name, "fp_r4") == 0)
+    {
+        p_fp_info->release = 4;
+    }
+    else if (strcmp(protocol_name, "fp_r5") == 0)
+    {
+        p_fp_info->release = 5;
+    }
+    else if (strcmp(protocol_name, "fp_r6") == 0)
+    {
+        p_fp_info->release = 6;
+    }
+    else if (strcmp(protocol_name, "fpiur_r5") == 0)
+    {
+        p_fp_info->release = 5;
+    }
+    else
+    {
+        return;
+    }
+
+    /* Variant number */
+    p_fp_info->dct2000_variant = variant;
+
+    /* Channel type */
+    p_fp_info->channel = outhdr_values[i++];
+
+    /* Node type */
+    p_fp_info->node_type = outhdr_values[i++];
+
+    p_fp_info->is_uplink = (( received  && (p_fp_info->node_type == 2)) ||
+                            (!received  && (p_fp_info->node_type == 1)));
+
+    /* IUR only uses the above... */
+    if (strcmp(protocol_name, "fpiur_r5") == 0)
+    {
+        /* Store info in packet */
+        p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
+        return;
+    }
+
+    /* DCH CRC present */
+    p_fp_info->dch_crc_present = outhdr_values[i++];
+
+    /* How many paging indications (if PCH data) */
+    p_fp_info->paging_indications = outhdr_values[i++];
+
+    /* Number of channels (for coordinated channels) */
+    p_fp_info->num_chans = outhdr_values[i++];
+
+    if (p_fp_info->channel != CHANNEL_EDCH)
+    {
+        /* TF size for each channel */
+        tf_start = i;
+        for (chan=0; chan < p_fp_info->num_chans; chan++)
+        {
+            p_fp_info->chan_tf_size[chan] = outhdr_values[tf_start+chan];
+        }
+
+        /* Number of TBs for each channel */
+        num_chans_start = tf_start + p_fp_info->num_chans;
+        for (chan=0; chan < p_fp_info->num_chans; chan++)
+        {
+            p_fp_info->chan_num_tbs[chan] = outhdr_values[num_chans_start+chan];
+        }
+    }
+    /* EDCH info */
+    else
+    {
+        int n;
+
+        p_fp_info->no_ddi_entries = outhdr_values[i++];
+
+        /* DDI values */
+        for (n=0; n < p_fp_info->no_ddi_entries; n++)
+        {
+            p_fp_info->edch_ddi[n] = outhdr_values[i++];
+        }
+
+        /* Corresponding MAC-d sizes */
+        for (n=0; n < p_fp_info->no_ddi_entries; n++)
+        {
+            p_fp_info->edch_macd_pdu_size[n] = outhdr_values[i++];
+        }
+    }
+
+    /* Store info in packet */
+    p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
+}
+
+
+
 /*****************************************/
 /* Main dissection function.             */
 /*****************************************/
 static void
 dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-    proto_tree *dct2000_tree;
-    proto_item *ti;
+    proto_tree  *dct2000_tree = NULL;
+    proto_item  *ti = NULL;
     gint        offset = 0;
     gint        context_length;
     guint8      port_number;
@@ -339,6 +615,7 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     dissector_handle_t protocol_handle = 0;
     dissector_handle_t heur_protocol_handle = 0;
     int sub_dissector_result = 0;
+    char        *protocol_name;
 
     /* Protocol name */
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -353,8 +630,11 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     }
 
     /* Create protocol tree. */
-    ti = proto_tree_add_item(tree, proto_catapult_dct2000, tvb, offset, -1, FALSE);
-    dct2000_tree = proto_item_add_subtree(ti, ett_catapult_dct2000);
+    if (tree)
+    {
+        ti = proto_tree_add_item(tree, proto_catapult_dct2000, tvb, offset, -1, FALSE);
+        dct2000_tree = proto_item_add_subtree(ti, ett_catapult_dct2000);
+    }
 
     /* Context Name */
     context_length = tvb_strsize(tvb, offset);
@@ -363,9 +643,9 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     offset += context_length;
 
     /* Context port number */
-    proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_port_number, tvb,
-                        offset, 1, FALSE);
     port_number = tvb_get_guint8(tvb, offset);
+    proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_port_number, tvb,
+                            offset, 1, FALSE);
     offset++;
 
     /* Timestamp in file */
@@ -412,17 +692,37 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     encap = tvb_get_guint8(tvb, offset);
     offset++;
 
-    /* Set selection length of dct2000 tree */
-    proto_item_set_len(dct2000_tree, offset);
+    if (tree)
+    {
+        /* Set selection length of dct2000 tree */
+        proto_item_set_len(dct2000_tree, offset);
+    }
 
     /* Add useful details to protocol tree label */
-    proto_item_append_text(ti, "   context=%s.%u   t=%s   %c   prot=%s (v=%s)",
-                           tvb_get_ephemeral_string(tvb, 0, context_length),
-                           port_number,
-                           tvb_get_ephemeral_string(tvb, timestamp_start, timestamp_length),
-                           (direction == 0) ? 'S' : 'R',
-                           tvb_get_ephemeral_string(tvb, protocol_start, protocol_length),
-                           tvb_get_ephemeral_string(tvb, variant_start, variant_length));
+    protocol_name = (char*)tvb_get_ephemeral_string(tvb, protocol_start, protocol_length);
+    if (tree)
+    {
+        proto_item_append_text(ti, "   context=%s.%u   t=%s   %c   prot=%s (v=%s)",
+                               tvb_get_ephemeral_string(tvb, 0, context_length),
+                               port_number,
+                               tvb_get_ephemeral_string(tvb, timestamp_start, timestamp_length),
+                               (direction == 0) ? 'S' : 'R',
+                               protocol_name,
+                               tvb_get_ephemeral_string(tvb, variant_start, variant_length));
+    }
+
+
+    /* FP protocols need info from outhdr attached */
+    if ((strcmp(protocol_name, "fp") == 0) ||
+        (strcmp(protocol_name, "fp_r4") == 0) ||
+        (strcmp(protocol_name, "fp_r5") == 0) ||
+        (strcmp(protocol_name, "fp_r6") == 0) ||
+        (strcmp(protocol_name, "fpiur_r5") == 0))
+    {
+        parse_outhdr_string(tvb_get_ephemeral_string(tvb, outhdr_start, outhdr_length));
+        attach_fp_info(pinfo, direction, protocol_name,
+                       atoi((char*)tvb_get_ephemeral_string(tvb, variant_start, variant_length)));
+    }
 
 
     /* Note that the first item of pinfo->pseudo_header->dct2000 will contain
@@ -464,7 +764,27 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         case DCT2000_ENCAP_MTP2:
             protocol_handle = find_dissector("mtp2");
             break;
+        case DCT2000_ENCAP_NBAP:
+            protocol_handle = find_dissector("nbap");
+            break;
         case DCT2000_ENCAP_UNHANDLED:
+            /* Show context.port in src or dest column as appropriate */
+            if (check_col(pinfo->cinfo, COL_DEF_SRC) && direction == 0)
+            {
+                col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
+                             "%s.%u",
+                             tvb_get_ephemeral_string(tvb, 0, context_length),
+                             port_number);
+            }
+            else
+            if (check_col(pinfo->cinfo, COL_DEF_DST) && direction == 1)
+            {
+                col_add_fstr(pinfo->cinfo, COL_DEF_DST,
+                             "%s.%u",
+                             tvb_get_ephemeral_string(tvb, 0, context_length),
+                             port_number);
+            }
+
             /* Many DCT2000 protocols have at least one IPPrim variant. If the
                protocol names match, try to find the UDP/TCP data inside them and
                pass that offset to dissector
@@ -474,22 +794,118 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
             /* Try IP Prim heuristic if configured to */
             if (catapult_dct2000_try_ipprim_heuristic)
             {
-                heur_protocol_handle =
-                    look_for_dissector((char*)tvb_get_ephemeral_string(tvb, protocol_start,
-                                                                       protocol_length));
+                guint32 source_addr_offset = 0, dest_addr_offset = 0;
+                guint32 source_port_offset = 0, dest_port_offset = 0;
+                port_type type_of_port = PT_NONE;
+                int offset_before_ipprim_header = offset;
+
+                heur_protocol_handle = look_for_dissector(protocol_name);
                 if ((heur_protocol_handle != 0) &&
-                    find_ipprim_data_offset(tvb, &offset))
+                    find_ipprim_data_offset(tvb, &offset,
+                                            &source_addr_offset, &dest_addr_offset,
+                                            &source_port_offset, &dest_port_offset,
+                                            &type_of_port))
                 {
+                    proto_tree *ipprim_tree;
+                    proto_item *ti;
                     protocol_handle = heur_protocol_handle;
+
+                    if (source_addr_offset && check_col(pinfo->cinfo, COL_DEF_SRC))
+                    {
+                        col_append_fstr(pinfo->cinfo, COL_DEF_SRC,
+                                        "(%s:%u)",
+                                        (char*)get_hostname(tvb_get_ipv4(tvb, source_addr_offset)),
+                                        tvb_get_ntohs(tvb, source_port_offset));
+                    }
+                    if (dest_addr_offset && check_col(pinfo->cinfo, COL_DEF_DST))
+                    {
+                        col_append_fstr(pinfo->cinfo, COL_DEF_DST,
+                                        "(%s:%u)",
+                                        (char*)get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)),
+                                        tvb_get_ntohs(tvb, dest_port_offset));
+                    }
+
+                    /* Add address parameters to tree */
+                    /* Unfortunately can't automatically create a conversation filter for this...
+                       I could create a fake IP header from these details, but then it would be tricky
+                       to get FP dissector called as it has no well-known ports or heuristics... */
+                    ti =  proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_ipprim_addresses,
+                                                       tvb, offset_before_ipprim_header, 0,
+                                                       "", "IPPrim transport (%s): %s:%u -> %s:%u",
+                                                       (type_of_port == PT_UDP) ? "UDP" : "TCP",
+                                                       (source_addr_offset) ?
+                                                           (char *)get_hostname(tvb_get_ipv4(tvb, source_addr_offset)) :
+                                                           "0.0.0.0",
+                                                       (source_port_offset) ?
+                                                           tvb_get_ntohs(tvb, source_port_offset) :
+                                                           0,
+                                                       (dest_addr_offset) ?
+                                                           (char *)get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
+                                                           "0.0.0.0",
+                                                       (dest_port_offset) ?
+                                                           tvb_get_ntohs(tvb, dest_port_offset) :
+                                                           0);
+                    ipprim_tree = proto_item_add_subtree(ti, ett_catapult_dct2000_ipprim);
+
+
+                    if (source_addr_offset != 0)
+                    {
+                        proto_item *addr_ti;
+                        proto_tree_add_item(ipprim_tree, hf_catapult_dct2000_ipprim_src_addr,
+                                            tvb, source_addr_offset, 4, FALSE);
+                        addr_ti = proto_tree_add_item(ipprim_tree, hf_catapult_dct2000_ipprim_addr,
+                                                      tvb, source_addr_offset, 4, FALSE);
+                        PROTO_ITEM_SET_HIDDEN(addr_ti);
+                    }
+                    if (source_port_offset != 0)
+                    {
+                        proto_item *port_ti;
+                        proto_tree_add_item(ipprim_tree,
+                                            (type_of_port == PT_UDP) ?
+                                               hf_catapult_dct2000_ipprim_udp_src_port :
+                                               hf_catapult_dct2000_ipprim_tcp_src_port,
+                                            tvb, source_port_offset, 2, FALSE);
+                        port_ti = proto_tree_add_item(ipprim_tree,
+                                                      (type_of_port == PT_UDP) ?
+                                                          hf_catapult_dct2000_ipprim_udp_port :
+                                                          hf_catapult_dct2000_ipprim_tcp_port,
+                                                      tvb, source_port_offset, 2, FALSE);
+                        PROTO_ITEM_SET_HIDDEN(port_ti);
+                    }
+                    if (dest_addr_offset != 0)
+                    {
+                        proto_item *addr_ti;
+                        proto_tree_add_item(ipprim_tree, hf_catapult_dct2000_ipprim_dst_addr,
+                                            tvb, dest_addr_offset, 4, FALSE);
+                        addr_ti = proto_tree_add_item(ipprim_tree, hf_catapult_dct2000_ipprim_addr,
+                                                      tvb, dest_addr_offset, 4, FALSE);
+                        PROTO_ITEM_SET_HIDDEN(addr_ti);
+                    }
+                    if (dest_port_offset != 0)
+                    {
+                        proto_item *port_ti;
+                        proto_tree_add_item(ipprim_tree,
+                                            (type_of_port == PT_UDP) ?
+                                               hf_catapult_dct2000_ipprim_udp_dst_port :
+                                               hf_catapult_dct2000_ipprim_tcp_dst_port,
+                                            tvb, dest_port_offset, 2, FALSE);
+                        port_ti = proto_tree_add_item(ipprim_tree,
+                                                      (type_of_port == PT_UDP) ?
+                                                          hf_catapult_dct2000_ipprim_udp_port :
+                                                          hf_catapult_dct2000_ipprim_tcp_port,
+                                                      tvb, dest_port_offset, 2, FALSE);
+                        PROTO_ITEM_SET_HIDDEN(port_ti);
+                    }
+
+                    /* Set length for IPPrim tree */
+                    proto_item_set_len(ipprim_tree, offset - offset_before_ipprim_header);
                 }
             }
 
             /* Try SCTP Prim heuristic if configured to */
             if (!protocol_handle && catapult_dct2000_try_sctpprim_heuristic)
             {
-                heur_protocol_handle =
-                    look_for_dissector(tvb_get_ephemeral_string(tvb, protocol_start,
-                                                                protocol_length));
+                heur_protocol_handle = look_for_dissector(protocol_name);
                 if ((heur_protocol_handle != 0) &&
                     (find_sctpprim_variant1_data_offset(tvb, &offset) ||
                      find_sctpprim_variant3_data_offset(tvb, &offset)))
@@ -527,10 +943,11 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            Show remaining bytes as unparsed data */
         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_unparsed_data,
                             tvb, offset, -1, FALSE);
+
         if (check_col(pinfo->cinfo, COL_INFO))
         {
             col_add_fstr(pinfo->cinfo, COL_INFO,
-                         "Unparsed protocol data (context=%s.%u   t=%s   %c   prot=%s (v=%s))",
+                         "Not dissected  (context=%s.%u   t=%s   %c   prot=%s (v=%s))",
                          tvb_get_ephemeral_string(tvb, 0, context_length),
                          port_number,
                          tvb_get_ephemeral_string(tvb, timestamp_start, timestamp_length),
@@ -539,6 +956,14 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                          tvb_get_ephemeral_string(tvb, variant_start, variant_length));
         }
     }
+    else
+    {
+        /* Show number of dissected bytes */
+        proto_item *ti = proto_tree_add_uint(dct2000_tree,
+                                             hf_catapult_dct2000_dissected_length,
+                                             tvb, 0, 0, tvb_reported_length(tvb)-offset);
+        PROTO_ITEM_SET_GENERATED(ti);
+    }
 }
 
 
@@ -614,18 +1039,86 @@ void proto_register_catapult_dct2000(void)
               "Unparsed DCT2000 protocol data", HFILL
             }
         },
-
+        { &hf_catapult_dct2000_dissected_length,
+            { "Dissected length",
+              "dct2000.dissected-length", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "Number of bytes dissected by subdissector(s)", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_addresses,
+            { "IPPrim Addresses",
+              "dct2000.ipprim", FT_STRING, BASE_NONE, NULL, 0x0,
+              "IPPrim Addresses", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_src_addr,
+            { "Source Address",
+              "dct2000.ipprim.src", FT_IPv4, BASE_NONE, NULL, 0x0,
+              "IPPrim Source Address", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_dst_addr,
+            { "Destination Address",
+              "dct2000.ipprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
+              "IPPrim Destination Address", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_addr,
+            { "Address",
+              "dct2000.ipprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
+              "IPPrim Destination Address", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_udp_src_port,
+            { "UDP Source Port",
+              "dct2000.ipprim.udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "IPPrim UDP Source Port", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_udp_dst_port,
+            { "UDP Destination Port",
+              "dct2000.ipprim.udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "IPPrim UDP Destination Port", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_udp_port,
+            { "UDP Port",
+              "dct2000.ipprim.udp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "IPPrim UDP Port", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_tcp_src_port,
+            { "TCP Source Port",
+              "dct2000.ipprim.tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "IPPrim TCP Source Port", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_tcp_dst_port,
+            { "TCP Destination Port",
+              "dct2000.ipprim.tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "IPPrim TCP Destination Port", HFILL
+            }
+        },
+        { &hf_catapult_dct2000_ipprim_tcp_port,
+            { "TCP Port",
+              "dct2000.ipprim.tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
+              "IPPrim TCP Port", HFILL
+            }
+        }
     };
 
     static gint *ett[] =
     {
-        &ett_catapult_dct2000
+        &ett_catapult_dct2000,
+        &ett_catapult_dct2000_ipprim
     };
 
     module_t *catapult_dct2000_module;
-    
+
     /* Register protocol. */
-    proto_catapult_dct2000 = proto_register_protocol("DCT2000", "DCT2000", "dct2000");
+    proto_catapult_dct2000 = proto_register_protocol("Catapult DCT2000 packet",
+                                                     "DCT2000",
+                                                     "dct2000");
     proto_register_field_array(proto_catapult_dct2000, hf, array_length(hf));
     proto_register_subtree_array(ett, array_length(ett));
 
@@ -642,27 +1135,24 @@ void proto_register_catapult_dct2000(void)
 
     /* Determines whether for not-handled protocols we should try to parse it if:
        - it looks like its embedded in an ipprim message, AND
-       - the DCT2000 protocol name matches an wireshark dissector name */
+       - the DCT2000 protocol name matches a wireshark dissector name */
     prefs_register_bool_preference(catapult_dct2000_module, "ipprim_heuristic",
                                    "Use IP Primitive heuristic",
                                    "If a payload looks like its embedded in an "
-                                   "IP primitive message, and there is an wireshark "
+                                   "IP primitive message, and there is a wireshark "
                                    "dissector matching the DCT2000 protocol name, "
                                    "try parsing the payload using that dissector",
                                    &catapult_dct2000_try_ipprim_heuristic);
 
     /* Determines whether for not-handled protocols we should try to parse it if:
        - it looks like its embedded in an sctpprim message, AND
-       - the DCT2000 protocol name matches an wireshark dissector name */
+       - the DCT2000 protocol name matches n wireshark dissector name */
     prefs_register_bool_preference(catapult_dct2000_module, "sctpprim_heuristic",
                                    "Use SCTP Primitive heuristic",
                                    "If a payload looks like its embedded in an "
-                                   "SCTP primitive message, and there is an wireshark "
+                                   "SCTP primitive message, and there is a wireshark "
                                    "dissector matching the DCT2000 protocol name, "
                                    "try parsing the payload using that dissector",
                                    &catapult_dct2000_try_sctpprim_heuristic);
-
-
-
 }