For fields of type FT_ABSOLUTE_TIME, have the "display" value be one of
[obnox/wireshark/wip.git] / epan / dissectors / packet-ucp.c
index 98331a176613ebc2387a318bf31407968db9c334..4c2cdf32d0349d6a8fb6b5e19922c87a231070df 100644 (file)
@@ -4,8 +4,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -28,6 +28,9 @@
  * www.etsi.org).
  * Includes the extension of EMI-UCP interface (V4.0, May 2001, www.cmgwds.com)
  *
+ * Support for statistics using the Stats Tree API added by
+ * Abhik Sarkar <sarkar.abhik@gmail.com>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <glib.h>
 
 #include <epan/packet.h>
-/* #include "packet-ucp.h" */                  /* We autoregister      */
+#include <epan/prefs.h>
+#include <epan/emem.h>
+#include <epan/stats_tree.h>
+
+#include "packet-tcp.h"
 
 /* Prototypes  */
-static void dissect_ucp(tvbuff_t *, packet_info *, proto_tree *);
+static void dissect_ucp_common(tvbuff_t *, packet_info *, proto_tree *);
+
+/* Tap Record */
+typedef struct _ucp_tap_rec_t {
+    guint message_type;        /* 0 = Operation; 1 = Result */
+    guint operation;   /* Operation Type */
+    guint result;      /* 0 = Success; Non 0 = Error Code */
+} ucp_tap_rec_t;
+
+/* Preferences */
+gboolean ucp_desegment = TRUE;
+/* STX + TRN 2 num. char.+ LEN 5 num. char. + O/R Char 'O' or 'R' + OT 2 num. char. */
+#define UCP_HEADER_SIZE 11
 
 /*
  * Convert ASCII-hex character to binary equivalent. No checks, assume
@@ -59,7 +78,7 @@ static void dissect_ucp(tvbuff_t *, packet_info *, proto_tree *);
 
 #define UCP_MALFORMED  -1                      /* Not a valid PDU      */
 #define UCP_SHORTENED  -2                      /* May be valid but short */
-#define UCP_INV_CHK    -3                      /* Checksum doesn't add up */
+#define UCP_INV_CHK    -3                      /* Checksum doesn't add up */
 
 #define        UCP_O_R_OFFSET 10                       /* Location of O/R field*/
 #define UCP_OT_OFFSET  12                      /* Location of OT field */
@@ -81,6 +100,23 @@ static int hf_ucp_hdr_LEN   = -1;
 static int hf_ucp_hdr_O_R      = -1;
 static int hf_ucp_hdr_OT       = -1;
 
+/*
+ * Stats section
+ */
+static int st_ucp_messages     = -1;
+static int st_ucp_ops          = -1;
+static int st_ucp_res          = -1;
+static int st_ucp_results      = -1;
+static int st_ucp_results_pos  = -1;
+static int st_ucp_results_neg  = -1;
+
+static gchar* st_str_ucp       = "UCP Messages";
+static gchar* st_str_ops       = "Operations";
+static gchar* st_str_res       = "Results";
+static gchar* st_str_ucp_res   = "UCP Results Acks/Nacks";
+static gchar* st_str_pos       = "Positive";
+static gchar* st_str_neg       = "Negative";
+
 /*
  * Data (variable) section
  */
@@ -191,6 +227,9 @@ static gint ett_ucp  = -1;
 static gint ett_sub  = -1;
 static gint ett_XSer = -1;
 
+/* Tap */
+static int ucp_tap             = -1;
+
 /*
  * Value-arrays for certain field-contents
  */
@@ -272,7 +311,7 @@ static const value_string vals_parm_EC[] = {        /* Error code   */
     { 13, "Legitimisation code for priority call, failure" },
     { 14, "Urgent message not allowed" },
     { 15, "Legitimisation code for urgent message, failure" },
-    { 16, "Reverse charging not alllowed" },
+    { 16, "Reverse charging not allowed" },
     { 17, "Legitimisation code for rev. charging, failure" },
     { 18, "Deferred delivery not allowed" },
     { 19, "New AC not valid" },
@@ -296,8 +335,8 @@ static const value_string vals_parm_EC[] = {        /* Error code   */
     { 38, "Message forwarded" },
     { 50, "Low network status" },
     { 51, "Legitimisation code for standard text, failure" },
-    { 53, "Operation partially successfull" },
-    { 54, "Operation not successfull" },
+    { 53, "Operation partially successful" },
+    { 54, "Operation not successful" },
     { 55, "System error" },
     { 57, "AdC already a member of GAdC address list" },
     { 58, "AdC not a member of GAdC address list" },
@@ -543,7 +582,7 @@ static const value_string vals_parm_LUR[] = {
 };
 
 static const value_string vals_parm_LRR[] = {
-    {  '1', "Leg. code for repitition requested" },
+    {  '1', "Leg. code for repetition requested" },
     {  0, NULL },
 };
 
@@ -581,7 +620,7 @@ static const value_string vals_parm_REQ_OT[] = {
 
 static const value_string vals_parm_SSTAT[] = {
     {  '0', "All services" },
-    {  '1', "All in the moment active servics" },
+    {  '1', "All in the moment active services" },
     {  '2', "Call diversion" },
     {  '3', "Roaming information status" },
     {  '4', "Call barring status" },
@@ -598,7 +637,7 @@ static const value_string vals_xser_service[] = {
     {  5, "[Privacy Indicator]       TDMA information exchange" },
     {  6, "[Urgency Indicator]       TDMA information exchange" },
     {  7, "[Acknowledgement Request] TDMA information exchange" },
-    {  8, "[Messsage Updating]       TDMA information exchange" },
+    {  8, "[Message Updating]        TDMA information exchange" },
     {  9, "[Call Back Number]        TDMA information exchange" },
     { 10, "[Response Code]           TDMA information exchange" },
     { 11, "[Teleservice ID]          TDMA information exchange" },
@@ -607,6 +646,57 @@ static const value_string vals_xser_service[] = {
     {  0, NULL },
 };
 
+/* For statistics */
+static void
+ucp_stats_tree_init(stats_tree* st)
+{
+    st_ucp_messages = stats_tree_create_node(st, st_str_ucp, 0, TRUE);
+    st_ucp_ops = stats_tree_create_node(st, st_str_ops, st_ucp_messages, TRUE);
+    st_ucp_res = stats_tree_create_node(st, st_str_res, st_ucp_messages, TRUE);
+    st_ucp_results = stats_tree_create_node(st, st_str_ucp_res, 0, TRUE);
+    st_ucp_results_pos = stats_tree_create_node(st, st_str_pos, st_ucp_results, TRUE);
+    st_ucp_results_neg = stats_tree_create_node(st, st_str_neg, st_ucp_results, TRUE);
+}
+
+static int
+ucp_stats_tree_per_packet(stats_tree *st, /* st as it was passed to us */
+                                      packet_info *pinfo _U_,
+                                      epan_dissect_t *edt _U_,
+                                      const void *p) /* Used for getting UCP stats */
+{
+    ucp_tap_rec_t* tap_rec = (ucp_tap_rec_t*)p;
+
+    tick_stat_node(st, st_str_ucp, 0, TRUE);
+
+    if (tap_rec->message_type == 0) /* Operation */
+    {
+        tick_stat_node(st, st_str_ops, st_ucp_messages, TRUE);
+        tick_stat_node(st, val_to_str(tap_rec->operation, vals_hdr_OT,
+                       "Unknown OT: %d"), st_ucp_ops, FALSE);
+    }
+    else /* Result */
+    {
+        tick_stat_node(st, st_str_res, st_ucp_messages, TRUE);
+        tick_stat_node(st, val_to_str(tap_rec->operation, vals_hdr_OT,
+                       "Unknown OT: %d"), st_ucp_res, FALSE);
+
+        tick_stat_node(st, st_str_ucp_res, 0, TRUE);
+
+        if (tap_rec->result == 0) /* Positive Result */
+        {
+            tick_stat_node(st, st_str_pos, st_ucp_results, FALSE);
+        }
+        else /* Negative Result */
+        {
+            tick_stat_node(st, st_str_neg, st_ucp_results, TRUE);
+            tick_stat_node(st, val_to_str(tap_rec->result, vals_parm_EC,
+                           "Unknown EC: %d"), st_ucp_results_neg, FALSE);
+        }
+    }
+
+    return 1;
+}
+
 /*!
  * Checks whether the PDU looks a bit like UCP and checks the checksum
  *
@@ -629,7 +719,6 @@ check_ucp(tvbuff_t *tvb, int *endpkt)
 
     length = tvb_find_guint8(tvb, offset, -1, UCP_ETX);
     if (length == -1) {
-       /* XXX - should we have an option to request reassembly? */
        *endpkt = tvb_reported_length_remaining(tvb, offset);
        return UCP_SHORTENED;
     }
@@ -785,7 +874,7 @@ ucp_handle_int(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
        tvb_ensure_bytes_exist(tvb, *offset, len + 1);
     } else
        len = idx - *offset;
-    strval = tvb_get_ephemeral_string(tvb, *offset, len);
+    strval = (gchar*)tvb_get_ephemeral_string(tvb, *offset, len);
     if (len > 0) {
        intval = atoi(strval);
        proto_tree_add_uint(tree, field, tvb, *offset, idx, intval);
@@ -811,7 +900,7 @@ ucp_handle_time(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
        tvb_ensure_bytes_exist(tvb, *offset, len + 1);
     } else
        len = idx - *offset;
-    strval = tvb_get_ephemeral_string(tvb, *offset, len);
+    strval = (gchar*)tvb_get_ephemeral_string(tvb, *offset, len);
     if (len > 0) {
        tval = ucp_mktime(strval);
        tmptime.secs  = tval;
@@ -945,7 +1034,7 @@ add_00O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_00R(proto_tree *tree, tvbuff_t *tvb)
+add_00R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -964,8 +1053,10 @@ add_00R(proto_tree *tree, tvbuff_t *tvb)
        UcpHandleInt(hf_ucp_parm_NoN);
        UcpHandleInt(hf_ucp_parm_NoA);
        UcpHandleInt(hf_ucp_parm_NoB);
+
+       tap_rec->result = 0;
     } else {
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
        UcpHandleString(hf_ucp_parm_SM);
     }
 }
@@ -982,14 +1073,16 @@ add_01O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_01R(proto_tree *tree, tvbuff_t *tvb)
+add_01R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
 
     intval = UcpHandleByte(hf_ucp_parm_ACK);
     if (intval == 'N')
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+    else
+       tap_rec->result = 0;
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1009,7 +1102,7 @@ add_02O(proto_tree *tree, tvbuff_t *tvb)
     ucp_handle_mt(tree, tvb, &offset);
 }
 
-#define add_02R(a, b) add_01R(a,b)
+#define add_02R(a, b, c) add_01R(a, b, c)
 
 static void
 add_03O(proto_tree *tree, tvbuff_t *tvb)
@@ -1038,7 +1131,7 @@ add_03O(proto_tree *tree, tvbuff_t *tvb)
     ucp_handle_mt(tree, tvb, &offset);
 }
 
-#define add_03R(a, b) add_01R(a,b)
+#define add_03R(a, b, c) add_01R(a, b, c)
 
 static void
 add_04O(proto_tree *tree, tvbuff_t *tvb)
@@ -1052,7 +1145,7 @@ add_04O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_04R(proto_tree *tree, tvbuff_t *tvb)
+add_04R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1064,8 +1157,9 @@ add_04R(proto_tree *tree, tvbuff_t *tvb)
        for (idx = 0; idx < intval; idx++)
            UcpHandleString(hf_ucp_parm_AdC);
        UcpHandleString(hf_ucp_parm_GAdC);
+       tap_rec->result = 0;
     } else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1086,7 +1180,7 @@ add_05O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleByte(hf_ucp_parm_A_D);
 }
 
-#define add_05R(a, b) add_01R(a, b)
+#define add_05R(a, b, c) add_01R(a, b, c)
 
 static void
 add_06O(proto_tree *tree, tvbuff_t *tvb)
@@ -1098,7 +1192,7 @@ add_06O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_06R(proto_tree *tree, tvbuff_t *tvb)
+add_06R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1107,8 +1201,9 @@ add_06R(proto_tree *tree, tvbuff_t *tvb)
     if (intval == 'A') {
        UcpHandleTime(hf_ucp_parm_CT);
        UcpHandleString(hf_ucp_parm_AAC);
+       tap_rec->result = 0;
     } else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1122,7 +1217,7 @@ add_07O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleString(hf_ucp_parm_NAC);
 }
 
-#define add_07R(a, b) add_01R(a, b)
+#define add_07R(a, b, c) add_01R(a, b, c)
 
 static void
 add_08O(proto_tree *tree, tvbuff_t *tvb)
@@ -1140,7 +1235,7 @@ add_08O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleString(hf_ucp_parm_LST);
 }
 
-#define add_08R(a, b) add_01R(a, b)
+#define add_08R(a, b, c) add_01R(a, b, c)
 
 static void
 add_09O(proto_tree *tree, tvbuff_t *tvb)
@@ -1152,7 +1247,7 @@ add_09O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_09R(proto_tree *tree, tvbuff_t *tvb)
+add_09R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1163,8 +1258,9 @@ add_09R(proto_tree *tree, tvbuff_t *tvb)
        intval = UcpHandleInt(hf_ucp_parm_NPL);
        for (idx = 0; idx < intval; idx++)
            UcpHandleString(hf_ucp_parm_LST);
+       tap_rec->result = 0;
     } else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1181,12 +1277,12 @@ add_10O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleInt(hf_ucp_parm_CS);
 }
 
-#define add_10R(a, b) add_01R(a, b)
+#define add_10R(a, b, c) add_01R(a, b, c)
 
 #define add_11O(a, b) add_06O(a, b)            /* Request roaming info */
 
 static void
-add_11R(proto_tree *tree, tvbuff_t *tvb)
+add_11R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1197,8 +1293,9 @@ add_11R(proto_tree *tree, tvbuff_t *tvb)
        intval = UcpHandleInt(hf_ucp_parm_NPL);
        for (idx = 0; idx < intval; idx++)
            UcpHandleString(hf_ucp_parm_GA);
+       tap_rec->result = 0;
     } else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1216,11 +1313,11 @@ add_12O(proto_tree *tree, tvbuff_t *tvb)
        UcpHandleString(hf_ucp_parm_GA);
 }
 
-#define add_12R(a, b) add_01R(a, b)
+#define add_12R(a, b, c) add_01R(a, b, c)
 
 #define add_13O(a, b) add_06O(a, b)            /* Roaming reset        */
 
-#define add_13R(a, b) add_01R(a, b)
+#define add_13R(a, b, c) add_01R(a, b, c)
 
 static void
 add_14O(proto_tree *tree, tvbuff_t *tvb)
@@ -1234,7 +1331,7 @@ add_14O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_14R(proto_tree *tree, tvbuff_t *tvb)
+add_14R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1249,9 +1346,10 @@ add_14R(proto_tree *tree, tvbuff_t *tvb)
         */
        for (idx = 0; idx < intval; idx++)
            UcpHandleData(hf_ucp_data_section);
+       tap_rec->result = 0;
     } else {
-       UcpHandleInt(hf_ucp_parm_EC);
-       UcpHandleString(hf_ucp_parm_SM);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+        UcpHandleString(hf_ucp_parm_SM);
     }
 }
 
@@ -1266,11 +1364,11 @@ add_15O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleTime(hf_ucp_parm_SP);
 }
 
-#define add_15R(a, b) add_01R(a, b)
+#define add_15R(a, b, c) add_01R(a, b, c)
 
 #define add_16O(a, b) add_06O(a, b)            /* Cancel call barring  */
 
-#define add_16R(a, b) add_01R(a, b)
+#define add_16R(a, b, c) add_01R(a, b, c)
 
 static void
 add_17O(proto_tree *tree, tvbuff_t *tvb)
@@ -1284,11 +1382,11 @@ add_17O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleTime(hf_ucp_parm_SP);
 }
 
-#define add_17R(a, b) add_01R(a, b)
+#define add_17R(a, b, c) add_01R(a, b, c)
 
 #define add_18O(a, b) add_06O(a, b)            /* Cancel call diversion */
 
-#define add_18R(a, b) add_01R(a, b)
+#define add_18R(a, b, c) add_01R(a, b, c)
 
 static void
 add_19O(proto_tree *tree, tvbuff_t *tvb)
@@ -1301,15 +1399,15 @@ add_19O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleTime(hf_ucp_parm_SP);
 }
 
-#define add_19R(a, b) add_01R(a, b)
+#define add_19R(a, b, c) add_01R(a, b, c)
 
 #define add_20O(a, b) add_06O(a, b)            /* Cancel deferred delivery */
 
-#define add_20R(a, b) add_01R(a, b)
+#define add_20R(a, b, c) add_01R(a, b, c)
 
 #define add_21O(a, b) add_06O(a, b)            /* All features reset   */
 
-#define add_21R(a, b) add_01R(a, b)
+#define add_21R(a, b, c) add_01R(a, b, c)
 
 static void
 add_22O(proto_tree *tree, tvbuff_t *tvb)
@@ -1323,7 +1421,7 @@ add_22O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleInt(hf_ucp_parm_CS);
 }
 
-#define add_22R(a, b) add_01R(a, b)
+#define add_22R(a, b, c) add_01R(a, b, c)
 
 static void
 add_23O(proto_tree *tree, tvbuff_t *tvb)
@@ -1335,7 +1433,7 @@ add_23O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_23R(proto_tree *tree, tvbuff_t *tvb)
+add_23R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1347,8 +1445,9 @@ add_23R(proto_tree *tree, tvbuff_t *tvb)
        intval = UcpHandleInt(hf_ucp_parm_NPL);
        for (idx = 0; idx < intval; idx++)
            UcpHandleInt(hf_ucp_hdr_OT);
+       tap_rec->result = 0;
     } else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1363,7 +1462,7 @@ add_24O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_24R(proto_tree *tree, tvbuff_t *tvb)
+add_24R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
@@ -1438,8 +1537,9 @@ add_24R(proto_tree *tree, tvbuff_t *tvb)
                intval = UcpHandleInt(hf_ucp_parm_NMESS);
            }
        }
+       tap_rec->result = 0;
     } else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1461,16 +1561,18 @@ add_30O(proto_tree *tree, tvbuff_t *tvb)
 }
 
 static void
-add_30R(proto_tree *tree, tvbuff_t *tvb)
+add_30R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
 {
     int                 offset = 1;
     guint       intval;
 
     intval = UcpHandleByte(hf_ucp_parm_ACK);
-    if (intval == 'A')
+    if (intval == 'A') {
        UcpHandleTime(hf_ucp_parm_MVP);
-    else
-       UcpHandleInt(hf_ucp_parm_EC);
+       tap_rec->result = 0;
+    } else {
+       tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+    }
     UcpHandleString(hf_ucp_parm_SM);
 }
 
@@ -1483,7 +1585,7 @@ add_31O(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleInt(hf_ucp_parm_PID);
 }
 
-#define add_31R(a, b) add_01R(a, b)
+#define add_31R(a, b, c) add_01R(a, b, c)
 
 static void
 add_5xO(proto_tree *tree, tvbuff_t *tvb)
@@ -1551,7 +1653,7 @@ add_5xO(proto_tree *tree, tvbuff_t *tvb)
     UcpHandleData(hf_ucp_parm_RES5);
 }
 
-#define add_5xR(a, b) add_30R(a, b)
+#define add_5xR(a, b,c ) add_30R(a, b, c)
 
 static void
 add_6xO(proto_tree *tree, tvbuff_t *tvb, guint8 OT)
@@ -1574,10 +1676,12 @@ add_6xO(proto_tree *tree, tvbuff_t *tvb, guint8 OT)
     UcpHandleByte(hf_ucp_parm_LNPI);
     UcpHandleInt(hf_ucp_parm_OPID);
     UcpHandleData(hf_ucp_parm_RES1);
-    UcpHandleData(hf_ucp_parm_RES2);
+    if (OT == 61) {
+      UcpHandleData(hf_ucp_parm_RES2);
+    }
 }
 
-#define add_6xR(a, b) add_01R(a, b)
+#define add_6xR(a, b, c) add_01R(a, b, c)
 
 /*
  * End of convenient shorthands
@@ -1627,15 +1731,39 @@ dissect_ucp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     /*
      * Ok, looks like a valid packet, go dissect.
      */
-    dissect_ucp(tvb, pinfo, tree);
+
+    dissect_ucp_common(tvb, pinfo, tree);
     return TRUE;
 }
 
+static guint
+get_ucp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
+{
+    guint       intval=0;
+    int                 i;
+
+    offset = offset + 4;
+    for (i = 0; i < UCP_LEN_LEN; i++) {        /* Length       */
+        intval = 10 * intval +
+            (tvb_get_guint8(tvb, offset) - '0');
+        offset++;
+    }
+
+    return intval + 2;
+}
+
+
+static void
+dissect_ucp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+    tcp_dissect_pdus(tvb, pinfo, tree, ucp_desegment, UCP_HEADER_SIZE,
+                     get_ucp_pdu_len, dissect_ucp_common);
+}
 /*
  * The actual dissector
  */
 static void
-dissect_ucp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_ucp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
     int                 offset = 0;    /* Offset in packet within tvbuff       */
     int                 tmpoff;        /* Local offset value (per field)       */
@@ -1643,6 +1771,7 @@ dissect_ucp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     guint8      OT;            /* Operation type                       */
     guint       intval;
     int                 i;
+    ucp_tap_rec_t* tap_rec;    /* Tap record                           */
 
     /* Set up structures needed to add the protocol subtree and manage it */
     proto_item *ti;
@@ -1651,6 +1780,19 @@ dissect_ucp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     proto_tree *sub_tree;
     tvbuff_t   *tmp_tvb;
 
+    /* Make entries in Protocol column */
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "UCP");
+
+    /* This runs atop TCP, so we are guaranteed that there is at least one
+       byte in the tvbuff. */
+    if (tvb_get_guint8(tvb, 0) != UCP_STX){
+               proto_tree_add_text(tree, tvb, 0, -1,"UCP_STX missing, this is not a new packet");
+               return;
+       }
+
+       /* Get data needed for dissect_ucp_common */
+       result = check_ucp(tvb, &endpkt);
+
     O_R = tvb_get_guint8(tvb, UCP_O_R_OFFSET);
     /*
      * So do an atoi() on the operation type
@@ -1658,15 +1800,18 @@ dissect_ucp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     OT  = tvb_get_guint8(tvb, UCP_OT_OFFSET) - '0';
     OT  = 10 * OT + (tvb_get_guint8(tvb, UCP_OT_OFFSET + 1) - '0');
 
-    /* Make entries in Protocol column and Info column on summary display */
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))
-           col_set_str(pinfo->cinfo, COL_PROTOCOL, "UCP");
+    /* Create Tap record */
+    tap_rec = ep_alloc0(sizeof(ucp_tap_rec_t));
+    tap_rec->message_type = (O_R == 'O' ? 0 : 1);
+    tap_rec->operation = OT;
 
+     /* Make entries in  Info column on summary display */
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "UCP");
     if (check_col(pinfo->cinfo, COL_INFO)) {
        col_clear(pinfo->cinfo, COL_INFO);
        col_append_fstr(pinfo->cinfo, COL_INFO, "%s (%s)",
                     val_to_str(OT,  vals_hdr_OT,  "unknown operation"),
-                    match_strval(O_R, vals_hdr_O_R));
+                    val_to_str(O_R, vals_hdr_O_R, "Unknown (%d)"));
        if (result == UCP_SHORTENED)
            col_append_str(pinfo->cinfo, COL_INFO, " [short packet]");
        else if (result == UCP_INV_CHK)
@@ -1717,108 +1862,112 @@ dissect_ucp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         */
        if (result == UCP_SHORTENED)
            return;
-       tmp_tvb = tvb_new_subset(tvb, offset, -1, -1);
+       tmp_tvb = tvb_new_subset_remaining(tvb, offset);
        sub_ti = proto_tree_add_item(ucp_tree, hf_ucp_oper_section, tvb,
                                     offset, endpkt - offset, FALSE);
        sub_tree = proto_item_add_subtree(sub_ti, ett_sub);
 
        switch (OT) {
            case  0:
-               O_R == 'O' ? add_00O(sub_tree,tmp_tvb) : add_00R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_00O(sub_tree,tmp_tvb) : add_00R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  1:
-               O_R == 'O' ? add_01O(sub_tree,tmp_tvb) : add_01R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_01O(sub_tree,tmp_tvb) : add_01R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  2:
-               O_R == 'O' ? add_02O(sub_tree,tmp_tvb) : add_02R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_02O(sub_tree,tmp_tvb) : add_02R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  3:
-               O_R == 'O' ? add_03O(sub_tree,tmp_tvb) : add_03R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_03O(sub_tree,tmp_tvb) : add_03R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  4:
-               O_R == 'O' ? add_04O(sub_tree,tmp_tvb) : add_04R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_04O(sub_tree,tmp_tvb) : add_04R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  5:
-               O_R == 'O' ? add_05O(sub_tree,tmp_tvb) : add_05R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_05O(sub_tree,tmp_tvb) : add_05R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  6:
-               O_R == 'O' ? add_06O(sub_tree,tmp_tvb) : add_06R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_06O(sub_tree,tmp_tvb) : add_06R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  7:
-               O_R == 'O' ? add_07O(sub_tree,tmp_tvb) : add_07R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_07O(sub_tree,tmp_tvb) : add_07R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  8:
-               O_R == 'O' ? add_08O(sub_tree,tmp_tvb) : add_08R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_08O(sub_tree,tmp_tvb) : add_08R(sub_tree,tmp_tvb, tap_rec);
                break;
            case  9:
-               O_R == 'O' ? add_09O(sub_tree,tmp_tvb) : add_09R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_09O(sub_tree,tmp_tvb) : add_09R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 10:
-               O_R == 'O' ? add_10O(sub_tree,tmp_tvb) : add_10R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_10O(sub_tree,tmp_tvb) : add_10R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 11:
-               O_R == 'O' ? add_11O(sub_tree,tmp_tvb) : add_11R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_11O(sub_tree,tmp_tvb) : add_11R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 12:
-               O_R == 'O' ? add_12O(sub_tree,tmp_tvb) : add_12R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_12O(sub_tree,tmp_tvb) : add_12R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 13:
-               O_R == 'O' ? add_13O(sub_tree,tmp_tvb) : add_13R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_13O(sub_tree,tmp_tvb) : add_13R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 14:
-               O_R == 'O' ? add_14O(sub_tree,tmp_tvb) : add_14R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_14O(sub_tree,tmp_tvb) : add_14R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 15:
-               O_R == 'O' ? add_15O(sub_tree,tmp_tvb) : add_15R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_15O(sub_tree,tmp_tvb) : add_15R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 16:
-               O_R == 'O' ? add_16O(sub_tree,tmp_tvb) : add_16R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_16O(sub_tree,tmp_tvb) : add_16R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 17:
-               O_R == 'O' ? add_17O(sub_tree,tmp_tvb) : add_17R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_17O(sub_tree,tmp_tvb) : add_17R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 18:
-               O_R == 'O' ? add_18O(sub_tree,tmp_tvb) : add_18R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_18O(sub_tree,tmp_tvb) : add_18R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 19:
-               O_R == 'O' ? add_19O(sub_tree,tmp_tvb) : add_19R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_19O(sub_tree,tmp_tvb) : add_19R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 20:
-               O_R == 'O' ? add_20O(sub_tree,tmp_tvb) : add_20R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_20O(sub_tree,tmp_tvb) : add_20R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 21:
-               O_R == 'O' ? add_21O(sub_tree,tmp_tvb) : add_21R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_21O(sub_tree,tmp_tvb) : add_21R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 22:
-               O_R == 'O' ? add_22O(sub_tree,tmp_tvb) : add_22R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_22O(sub_tree,tmp_tvb) : add_22R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 23:
-               O_R == 'O' ? add_23O(sub_tree,tmp_tvb) : add_23R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_23O(sub_tree,tmp_tvb) : add_23R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 24:
-               O_R == 'O' ? add_24O(sub_tree,tmp_tvb) : add_24R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_24O(sub_tree,tmp_tvb) : add_24R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 30:
-               O_R == 'O' ? add_30O(sub_tree,tmp_tvb) : add_30R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_30O(sub_tree,tmp_tvb) : add_30R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 31:
-               O_R == 'O' ? add_31O(sub_tree,tmp_tvb) : add_31R(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_31O(sub_tree,tmp_tvb) : add_31R(sub_tree,tmp_tvb, tap_rec);
                break;
            case 51: case 52: case 53: case 54: case 55: case 56: case 57:
            case 58:
-               O_R == 'O' ? add_5xO(sub_tree,tmp_tvb) : add_5xR(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_5xO(sub_tree,tmp_tvb) : add_5xR(sub_tree,tmp_tvb, tap_rec);
                break;
            case 60: case 61:
-               O_R == 'O' ? add_6xO(sub_tree,tmp_tvb,OT) : add_6xR(sub_tree,tmp_tvb);
+               O_R == 'O' ? add_6xO(sub_tree,tmp_tvb,OT) : add_6xR(sub_tree,tmp_tvb, tap_rec);
                break;
            default:
                break;
        }
     }
+    
+    /* Queue packet for Tap */
+    tap_queue_packet(ucp_tap, pinfo, tap_rec);
+
     return;
 }
 
-/* Register the protocol with Ethereal */
+/* Register the protocol with Wireshark */
 void
 proto_register_ucp(void)
 {
@@ -1855,7 +2004,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_oper_section,
            { "Data", "ucp.parm",
-             FT_NONE, BASE_DEC, NULL, 0x00,
+             FT_NONE, BASE_NONE, NULL, 0x00,
              "The actual content of the operation.",
              HFILL
            }
@@ -1968,7 +2117,7 @@ proto_register_ucp(void)
        { &hf_ucp_parm_LRR,
            { "LRR", "ucp.parm.LRR",
              FT_UINT8, BASE_DEC, VALS(vals_parm_LRR), 0x00,
-             "Leg. code for repitition flag.",
+             "Leg. code for repetition flag.",
              HFILL
            }
        },
@@ -2066,14 +2215,14 @@ proto_register_ucp(void)
        { &hf_ucp_parm_RP,
            { "RP", "ucp.parm.RP",
              FT_UINT8, BASE_DEC, VALS(vals_parm_RP), 0x00,
-             "Repitition requested.",
+             "Repetition requested.",
              HFILL
            }
        },
        { &hf_ucp_parm_LRP,
            { "LRP", "ucp.parm.LRP",
-             FT_STRING, BASE_DEC, NULL, 0x00,
-             "Legitimisation code for repitition.",
+             FT_STRING, BASE_NONE, NULL, 0x00,
+             "Legitimisation code for repetition.",
              HFILL
            }
        },
@@ -2086,7 +2235,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_LPR,
            { "LPR", "ucp.parm.LPR",
-             FT_STRING, BASE_DEC, NULL, 0x00,
+             FT_STRING, BASE_NONE, NULL, 0x00,
              "Legitimisation code for priority requested.",
              HFILL
            }
@@ -2100,7 +2249,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_LUM,
            { "LUM", "ucp.parm.LUM",
-             FT_STRING, BASE_DEC, NULL, 0x00,
+             FT_STRING, BASE_NONE, NULL, 0x00,
              "Legitimisation code for urgent message.",
              HFILL
            }
@@ -2114,7 +2263,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_LRC,
            { "LRC", "ucp.parm.LRC",
-             FT_STRING, BASE_DEC, NULL, 0x00,
+             FT_STRING, BASE_NONE, NULL, 0x00,
              "Legitimisation code for reverse charging.",
              HFILL
            }
@@ -2142,7 +2291,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_CT,
            { "CT", "ucp.parm.CT",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Accumulated charges timestamp.",
              HFILL
            }
@@ -2261,7 +2410,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_DDT,
            { "DDT", "ucp.parm.DDT",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Deferred delivery time.",
              HFILL
            }
@@ -2275,21 +2424,21 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_ST,
            { "ST", "ucp.parm.ST",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Start time.",
              HFILL
            }
        },
        { &hf_ucp_parm_SP,
            { "SP", "ucp.parm.SP",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Stop time.",
              HFILL
            }
        },
        { &hf_ucp_parm_VP,
            { "VP", "ucp.parm.VP",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Validity period.",
              HFILL
            }
@@ -2303,7 +2452,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_SCTS,
            { "SCTS", "ucp.parm.SCTS",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Service Centre timestamp.",
              HFILL
            }
@@ -2324,7 +2473,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_DSCTS,
            { "DSCTS", "ucp.parm.DSCTS",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
              "Delivery timestamp.",
              HFILL
            }
@@ -2337,14 +2486,14 @@ proto_register_ucp(void)
            }
        },
        { &hf_ucp_parm_NB,
-           { "  NB", "ucp.parm.NB",
+           { "NB", "ucp.parm.NB",
              FT_STRING, BASE_NONE, NULL, 0x00,
              "No. of bits in Transparent Data (TD) message.",
              HFILL
            }
        },
        { &hf_ucp_data_section,
-           { "  Data", "ucp.message",
+           { "Data", "ucp.message",
              FT_NONE, BASE_NONE, NULL, 0x00,
              "The actual message or data.",
              HFILL
@@ -2408,7 +2557,7 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_XSer,
            { "Extra services:", "ucp.parm.XSer",
-             FT_NONE, BASE_DEC, NULL, 0x00,
+             FT_NONE, BASE_NONE, NULL, 0x00,
              "Extra services.",
              HFILL
            }
@@ -2527,8 +2676,8 @@ proto_register_ucp(void)
        },
        { &hf_ucp_parm_MVP,
            { "MVP", "ucp.parm.MVP",
-             FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
-             "Mofified validity period.",
+             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+             "Modified validity period.",
              HFILL
            }
        },
@@ -2560,13 +2709,27 @@ proto_register_ucp(void)
        &ett_sub,
        &ett_XSer
     };
-    /* Register the protocol name and description */
+   module_t *ucp_module;
+
+   /* Register the protocol name and description */
     proto_ucp = proto_register_protocol("Universal Computer Protocol",
                                        "UCP", "ucp");
 
     /* Required function calls to register header fields and subtrees used */
     proto_register_field_array(proto_ucp, hf, array_length(hf));
     proto_register_subtree_array(ett, array_length(ett));
+
+    /* Register for tapping */
+    ucp_tap = register_tap("ucp");
+
+  /* register preferences */
+    ucp_module = prefs_register_protocol(proto_ucp, NULL);
+    prefs_register_bool_preference(ucp_module, "desegment_ucp_messages",
+                           "Reassemble UCP messages spanning multiple TCP segments",
+                           "Whether the UCP dissector should reassemble messages spanning multiple TCP segments."
+                           " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+                           &ucp_desegment);
+
 }
 
 /*
@@ -2588,6 +2751,11 @@ proto_reg_handoff_ucp(void)
     /*
      * Also register as one that can be selected by a TCP port number.
      */
-    ucp_handle = create_dissector_handle(dissect_ucp, proto_ucp);
+    ucp_handle = create_dissector_handle(dissect_ucp_tcp, proto_ucp);
     dissector_add_handle("tcp.port", ucp_handle);
+
+    /* Tapping setup */
+    stats_tree_register_with_group("ucp", "ucp_messages", "_UCP Messages", 0,
+                       ucp_stats_tree_per_packet, ucp_stats_tree_init,
+                       NULL, REGISTER_STAT_GROUP_TELEPHONY);
 }