summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ucp.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-ucp.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-ucp.c')
-rw-r--r--epan/dissectors/packet-ucp.c2849
1 files changed, 2849 insertions, 0 deletions
diff --git a/epan/dissectors/packet-ucp.c b/epan/dissectors/packet-ucp.c
new file mode 100644
index 00000000..5032b831
--- /dev/null
+++ b/epan/dissectors/packet-ucp.c
@@ -0,0 +1,2849 @@
+/* packet-ucp.c
+ * Routines for Universal Computer Protocol dissection
+ * Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * ----------
+ *
+ * Dissector of a UCP (Universal Computer Protocol) PDU, as defined for the
+ * ERMES paging system in ETS 300 133-3 (2nd final draft, September 1997,
+ * www.etsi.org).
+ * Includes the extension of EMI-UCP interface
+ * (V4.0, May 2001, www.advox.se/download/protocols/EMI_UCP.pdf)
+ *
+ * Support for statistics using the Stats Tree API added by
+ * Abhik Sarkar <sarkar.abhik@gmail.com>
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/expert.h>
+#include <epan/stats_tree.h>
+#include <epan/charsets.h>
+
+#include <wsutil/strtoi.h>
+
+#include "packet-tcp.h"
+
+void proto_register_ucp(void);
+void proto_reg_handoff_ucp(void);
+
+/* 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 */
+static gboolean ucp_desegment = TRUE;
+
+/* STX + TRN(2 num. char.) + / + LEN(5 num. char.) + / + 'O'/'R' + / + OT(2 num. char.) + / */
+#define UCP_HEADER_SIZE 15
+
+/*
+ * Convert ASCII-hex character to binary equivalent. No checks, assume
+ * is valid hex character.
+ */
+#define AHex2Bin(n) (((n) & 0x40) ? ((n) & 0x0F) + 9 : ((n) & 0x0F))
+
+#define UCP_STX 0x02 /* Start of UCP PDU */
+#define UCP_ETX 0x03 /* End of UCP PDU */
+
+#define UCP_MALFORMED -1 /* Not a valid PDU */
+#define UCP_INV_CHK -2 /* Incorrect checksum */
+
+#define UCP_TRN_OFFSET 1
+#define UCP_LEN_OFFSET 4
+#define UCP_O_R_OFFSET 10 /* Location of O/R field */
+#define UCP_OT_OFFSET 12 /* Location of OT field */
+
+#define UCP_TRN_LEN 2 /* Length of TRN-field */
+#define UCP_LEN_LEN 5 /* Length of LEN-field */
+#define UCP_O_R_LEN 1 /* Length of O/R-field */
+#define UCP_OT_LEN 2 /* Length of OT-field */
+
+
+static dissector_handle_t ucp_handle;
+
+/*
+ * Initialize the protocol and registered fields
+ *
+ * Header (fixed) section
+ */
+static int proto_ucp = -1;
+
+static int hf_ucp_hdr_TRN = -1;
+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 const gchar st_str_ucp[] = "UCP Messages";
+static const gchar st_str_ops[] = "Operations";
+static const gchar st_str_res[] = "Results";
+static const gchar st_str_ucp_res[] = "UCP Results Acks/Nacks";
+static const gchar st_str_pos[] = "Positive";
+static const gchar st_str_neg[] = "Negative";
+
+/*
+ * Data (variable) section
+ */
+static int hf_ucp_oper_section = -1;
+static int hf_ucp_parm_AdC = -1;
+static int hf_ucp_parm_OAdC = -1;
+static int hf_ucp_parm_DAdC = -1;
+static int hf_ucp_parm_AC = -1;
+static int hf_ucp_parm_OAC = -1;
+static int hf_ucp_parm_BAS = -1;
+static int hf_ucp_parm_LAR = -1;
+static int hf_ucp_parm_LAC = -1;
+static int hf_ucp_parm_L1R = -1;
+static int hf_ucp_parm_L1P = -1;
+static int hf_ucp_parm_L3R = -1;
+static int hf_ucp_parm_L3P = -1;
+static int hf_ucp_parm_LCR = -1;
+static int hf_ucp_parm_LUR = -1;
+static int hf_ucp_parm_LRR = -1;
+static int hf_ucp_parm_RT = -1;
+static int hf_ucp_parm_NoN = -1;
+static int hf_ucp_parm_NoA = -1;
+static int hf_ucp_parm_NoB = -1;
+static int hf_ucp_parm_NAC = -1;
+static int hf_ucp_parm_PNC = -1;
+static int hf_ucp_parm_AMsg = -1;
+static int hf_ucp_parm_LNo = -1;
+static int hf_ucp_parm_LST = -1;
+static int hf_ucp_parm_TNo = -1;
+static int hf_ucp_parm_CS = -1;
+static int hf_ucp_parm_PID = -1;
+static int hf_ucp_parm_NPL = -1;
+static int hf_ucp_parm_GA = -1;
+static int hf_ucp_parm_RP = -1;
+static int hf_ucp_parm_LRP = -1;
+static int hf_ucp_parm_PR = -1;
+static int hf_ucp_parm_LPR = -1;
+static int hf_ucp_parm_UM = -1;
+static int hf_ucp_parm_LUM = -1;
+static int hf_ucp_parm_RC = -1;
+static int hf_ucp_parm_LRC = -1;
+static int hf_ucp_parm_NRq = -1;
+static int hf_ucp_parm_GAdC = -1;
+static int hf_ucp_parm_A_D = -1;
+static int hf_ucp_parm_CT = -1;
+static int hf_ucp_parm_AAC = -1;
+static int hf_ucp_parm_MNo = -1;
+static int hf_ucp_parm_R_T = -1;
+static int hf_ucp_parm_IVR5x = -1;
+static int hf_ucp_parm_REQ_OT = -1;
+static int hf_ucp_parm_SSTAT = -1;
+static int hf_ucp_parm_LMN = -1;
+static int hf_ucp_parm_NMESS = -1;
+static int hf_ucp_parm_NAdC = -1;
+static int hf_ucp_parm_NT = -1;
+static int hf_ucp_parm_NPID = -1;
+static int hf_ucp_parm_LRq = -1;
+static int hf_ucp_parm_LRAd = -1;
+static int hf_ucp_parm_LPID = -1;
+static int hf_ucp_parm_DD = -1;
+static int hf_ucp_parm_DDT = -1;
+static int hf_ucp_parm_STx = -1;
+static int hf_ucp_parm_ST = -1;
+static int hf_ucp_parm_SP = -1;
+static int hf_ucp_parm_VP = -1;
+static int hf_ucp_parm_RPID = -1;
+static int hf_ucp_parm_SCTS = -1;
+static int hf_ucp_parm_Dst = -1;
+static int hf_ucp_parm_Rsn = -1;
+static int hf_ucp_parm_DSCTS = -1;
+static int hf_ucp_parm_MT = -1;
+static int hf_ucp_parm_NB = -1;
+static int hf_ucp_data_section = -1;
+static int hf_ucp_parm_MMS = -1;
+static int hf_ucp_parm_DCs = -1;
+static int hf_ucp_parm_MCLs = -1;
+static int hf_ucp_parm_RPI = -1;
+static int hf_ucp_parm_CPg = -1;
+static int hf_ucp_parm_RPLy = -1;
+static int hf_ucp_parm_OTOA = -1;
+static int hf_ucp_parm_HPLMN = -1;
+static int hf_ucp_parm_RES4 = -1;
+static int hf_ucp_parm_RES5 = -1;
+static int hf_ucp_parm_OTON = -1;
+static int hf_ucp_parm_ONPI = -1;
+static int hf_ucp_parm_STYP0 = -1;
+static int hf_ucp_parm_STYP1 = -1;
+static int hf_ucp_parm_ACK = -1;
+static int hf_ucp_parm_PWD = -1;
+static int hf_ucp_parm_NPWD = -1;
+static int hf_ucp_parm_VERS = -1;
+static int hf_ucp_parm_LAdC = -1;
+static int hf_ucp_parm_LTON = -1;
+static int hf_ucp_parm_LNPI = -1;
+static int hf_ucp_parm_OPID = -1;
+static int hf_ucp_parm_RES1 = -1;
+static int hf_ucp_parm_RES2 = -1;
+static int hf_ucp_parm_MVP = -1;
+static int hf_ucp_parm_EC = -1;
+static int hf_ucp_parm_SM = -1;
+static int hf_ucp_not_subscribed = -1;
+static int hf_ucp_ga_roaming = -1;
+static int hf_ucp_call_barring = -1;
+static int hf_ucp_deferred_delivery = -1;
+static int hf_ucp_diversion = -1;
+
+static int hf_ucp_parm_XSer = -1;
+static int hf_xser_service = -1;
+static int hf_xser_length = -1;
+static int hf_xser_data = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_ucp = -1;
+static gint ett_sub = -1;
+static gint ett_XSer = -1;
+
+static expert_field ei_ucp_stx_missing = EI_INIT;
+static expert_field ei_ucp_intstring_invalid = EI_INIT;
+
+/* Tap */
+static int ucp_tap = -1;
+
+/*
+ * Value-arrays for certain field-contents
+ */
+static const value_string vals_hdr_O_R[] = {
+ { 'O', "Operation" },
+ { 'R', "Result" },
+ { 0, NULL }
+};
+
+static const value_string vals_hdr_OT[] = { /* Operation type */
+ { 0, "Enquiry" },
+ { 1, "Call input" },
+ { 2, "Call input (multiple address)" },
+ { 3, "Call input (supplementary services included)" },
+ { 4, "Address list information" },
+ { 5, "Change address list" },
+ { 6, "Advice of accumulated charges" },
+ { 7, "Password management" },
+ { 8, "Legitimisation code management" },
+ { 9, "Standard text information" },
+ { 10, "Change standard text" },
+ { 11, "Request roaming information" },
+ { 12, "Change roaming information" },
+ { 13, "Roaming reset" },
+ { 14, "Message retrieval" },
+ { 15, "Request call barring" },
+ { 16, "Cancel call barring" },
+ { 17, "Request call diversion" },
+ { 18, "Cancel call diversion" },
+ { 19, "Request deferred delivery" },
+ { 20, "Cancel deferred delivery" },
+ { 21, "All features reset" },
+ { 22, "Call input (with specific character set)" },
+ { 23, "UCP version status request" },
+ { 24, "Mobile subscriber feature status request" },
+ { 30, "SMS message transfer" },
+ { 31, "SMT alert" },
+ { 32, "(proprietary)" },
+ { 34, "(proprietary)" },
+ { 36, "(proprietary)" },
+ { 38, "(proprietary)" },
+ { 40, "(proprietary)" },
+ { 41, "(proprietary)" },
+ { 42, "(proprietary)" },
+ { 43, "(proprietary)" },
+ { 44, "(proprietary)" },
+ { 45, "(proprietary)" },
+ { 51, "Submit short message" },
+ { 52, "Deliver short message" },
+ { 53, "Deliver notification" },
+ { 54, "Modify message" },
+ { 55, "Inquiry message" },
+ { 56, "Delete message" },
+ { 57, "Inquiry response message" },
+ { 58, "Delete response message" },
+ { 60, "Session management" },
+ { 61, "List management" },
+ { 95, "(proprietary)" },
+ { 96, "(proprietary)" },
+ { 97, "(proprietary)" },
+ { 98, "(proprietary)" },
+ { 99, "(proprietary)" },
+ { 0, NULL }
+};
+static value_string_ext vals_hdr_OT_ext = VALUE_STRING_EXT_INIT(vals_hdr_OT);
+
+static const value_string vals_parm_EC[] = { /* Error code */
+ { 1, "Checksum error" },
+ { 2, "Syntax error" },
+ { 3, "Operation not supported by system" },
+ { 4, "Operation not allowed" },
+ { 5, "Call barring active" },
+ { 6, "AdC invalid" },
+ { 7, "Authentication failure" },
+ { 8, "Legitimisation code for all calls, failure" },
+ { 9, "GA not valid" },
+ { 10, "Repetition not allowed" },
+ { 11, "Legitimisation code for repetition, failure" },
+ { 12, "Priority call not allowed" },
+ { 13, "Legitimisation code for priority call, failure" },
+ { 14, "Urgent message not allowed" },
+ { 15, "Legitimisation code for urgent message, failure" },
+ { 16, "Reverse charging not allowed" },
+ { 17, "Legitimisation code for rev. charging, failure" },
+ { 18, "Deferred delivery not allowed" },
+ { 19, "New AC not valid" },
+ { 20, "New legitimisation code not valid" },
+ { 21, "Standard text not valid" },
+ { 22, "Time period not valid" },
+ { 23, "Message type not supported by system" },
+ { 24, "Message too long" },
+ { 25, "Requested standard text not valid" },
+ { 26, "Message type not valid for the pager type" },
+ { 27, "Message not found in SMSC" },
+ { 28, "Invalid character set" },
+ { 30, "Subscriber hang-up" },
+ { 31, "Fax group not supported" },
+ { 32, "Fax message type not supported" },
+ { 33, "Address already in list (60-series)" },
+ { 34, "Address not in list (60-series)" },
+ { 35, "List full, cannot add address to list (60-series)" },
+ { 36, "RPID already in use" },
+ { 37, "Delivery in progress" },
+ { 38, "Message forwarded" },
+ { 50, "Low network status" },
+ { 51, "Legitimisation code for standard text, failure" },
+ { 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" },
+ { 59, "Requested standard text list invalid" },
+ { 61, "Not controller of GAdC address list" },
+ { 62, "Standard text too large" },
+ { 63, "Not owner of standard text list" },
+ { 64, "Address list full" },
+ { 65, "GAdC invalid" },
+ { 66, "Operation restricted to mobile subscribers" },
+ { 68, "Invalid AdC type" },
+ { 69, "Cannot add AdC to GAdC address list" },
+ { 90, "(proprietary error code)" },
+ { 91, "(proprietary error code)" },
+ { 92, "(proprietary error code)" },
+ { 93, "(proprietary error code)" },
+ { 94, "(proprietary error code)" },
+ { 95, "(proprietary error code)" },
+ { 96, "(proprietary error code)" },
+ { 97, "(proprietary error code)" },
+ { 98, "(proprietary error code)" },
+ { 99, "(proprietary error code)" },
+ { 0, NULL },
+};
+static value_string_ext vals_parm_EC_ext = VALUE_STRING_EXT_INIT(vals_parm_EC);
+
+static const value_string vals_parm_NRq[] = {
+ { '0', "NAdC not used" },
+ { '1', "NAdC used" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_NT[] = {
+ { '0', "Default value" },
+ { '1', "Delivery notification" },
+ { '2', "Non-delivery notification" },
+ { '3', "Delivery and Non-delivery notification" },
+ { '4', "Buffered message notification" },
+ { '5', "Buffered and Delivery notification" },
+ { '6', "Buffered and Non-delivery notification" },
+ { '7', "All notifications" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_PID[] = {
+ { 100, "Mobile station" },
+ { 122, "Fax Group 3" },
+ { 131, "X.400" },
+ { 138, "Menu over PSTN" },
+ { 139, "PC appl. over PSTN (E.164)" },
+ { 339, "PC appl. over X.25 (X.121)" },
+ { 439, "PC appl. over ISDN (E.164)" },
+ { 539, "PC appl. over TCP/IP" },
+ { 639, "PC appl. via abbreviated number" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_LRq[] = {
+ { '0', "LRAd not used" },
+ { '1', "LRAd used" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_DD[] = {
+ { '0', "DDT not used" },
+ { '1', "DDT used" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_Dst[] = {
+ { '0', "delivered" },
+ { '1', "buffered (see Rsn)" },
+ { '2', "not delivered (see Rsn)" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_Rsn[] = {
+ { 0, "Unknown subscriber" },
+ { 1, "Service temporary not available" },
+ { 2, "Service temporary not available" },
+ { 3, "Service temporary not available" },
+ { 4, "Service temporary not available" },
+ { 5, "Service temporary not available" },
+ { 6, "Service temporary not available" },
+ { 7, "Service temporary not available" },
+ { 8, "Service temporary not available" },
+ { 9, "Illegal error code" },
+ { 10, "Network time-out" },
+ { 100, "Facility not supported" },
+ { 101, "Unknown subscriber" },
+ { 102, "Facility not provided" },
+ { 103, "Call barred" },
+ { 104, "Operation barred" },
+ { 105, "SC congestion" },
+ { 106, "Facility not supported" },
+ { 107, "Absent subscriber" },
+ { 108, "Delivery fail" },
+ { 109, "Sc congestion" },
+ { 110, "Protocol error" },
+ { 111, "MS not equipped" },
+ { 112, "Unknown SC" },
+ { 113, "SC congestion" },
+ { 114, "Illegal MS" },
+ { 115, "MS nota subscriber" },
+ { 116, "Error in MS" },
+ { 117, "SMS lower layer not provisioned" },
+ { 118, "System fail" },
+ { 119, "PLMN system failure" },
+ { 120, "HLR system failure" },
+ { 121, "VLR system failure" },
+ { 122, "Previous VLR system failure" },
+ { 123, "Controlling MSC system failure" },
+ { 124, "VMSC system failure" },
+ { 125, "EIR system failure" },
+ { 126, "System failure" },
+ { 127, "Unexpected data value" },
+ { 200, "Error in address service centre" },
+ { 201, "Invalid absolute validity period" },
+ { 202, "Short message exceeds maximum" },
+ { 203, "Unable to unpack GSM message" },
+ { 204, "Unable to convert to IRA alphabet" },
+ { 205, "Invalid validity period format" },
+ { 206, "Invalid destination address" },
+ { 207, "Duplicate message submit" },
+ { 208, "Invalid message type indicator" },
+ { 0, NULL },
+};
+static value_string_ext vals_parm_Rsn_ext = VALUE_STRING_EXT_INIT(vals_parm_Rsn);
+
+static const value_string vals_parm_MT[] = {
+ { '2', "Numeric message" },
+ { '3', "Alphanumeric message" },
+ { '4', "Transparent data" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_DCs[] = {
+ { '0', "default alphabet" },
+ { '1', "User defined data (8 bit)" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_MCLs[] = {
+ { '0', "message class 0" },
+ { '1', "message class 1" },
+ { '2', "message class 2" },
+ { '3', "message class 3" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_RPI[] = {
+ { '1', "Request" },
+ { '2', "Response" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_ACK[] = {
+ { 'A', "Ack" },
+ { 'N', "Nack" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_RP[] = {
+ { '1', "Repetition requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_UM[] = {
+ { '1', "Urgent message" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_RC[] = {
+ { '1', "Reverse charging request" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_OTON[] = {
+ { '1', "International number" },
+ { '2', "National number" },
+ { '6', "Abbreviated number (short number alias)" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_ONPI[] = {
+ { '1', "E.164 address" },
+ { '3', "X.121 address" },
+ { '5', "Private -TCP/IP or abbreviated number- address" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_STYP0[] = {
+ { '1', "open session" },
+ { '2', "reserved" },
+ { '3', "change password" },
+ { '4', "open provisioning session" },
+ { '5', "reserved" },
+ { '6', "change provisioning password" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_STYP1[] = {
+ { '1', "add item to mo-list" },
+ { '2', "remove item from mo-list" },
+ { '3', "verify item mo-list" },
+ { '4', "add item to mt-list" },
+ { '5', "remove item from mt-list" },
+ { '6', "verify item mt-list" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_OPID[] = {
+ { 0, "Mobile station" },
+ { 39, "PC application" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_BAS[] = {
+ { '1', "Barred" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_LAR[] = {
+ { '1', "Leg. code for all calls requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_L1R[] = {
+ { '1', "Leg. code for priority 1 requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_L3R[] = {
+ { '1', "Leg. code for priority 3 requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_LCR[] = {
+ { '1', "Leg. code for reverse charging requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_LUR[] = {
+ { '1', "Leg. code for urgent message requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_LRR[] = {
+ { '1', "Leg. code for repetition requested" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_RT[] = {
+ { '1', "Tone only" },
+ { '2', "Numeric" },
+ { '3', "Alphanumeric" },
+ { '4', "Transparent data" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_PNC[] = {
+ { 'H', "Home PNC" },
+ { 'I', "Input PNC" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_A_D[] = {
+ { 'A', "Add" },
+ { 'D', "Delete" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_R_T[] = {
+ { 'R', "Retrieval Ok" },
+ { 'T', "Retransmit on radio channel" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_REQ_OT[] = {
+ { 'S', "Send used operation types" },
+ { 'N', "Don't send used operation types" },
+ { 0, NULL },
+};
+
+static const value_string vals_parm_SSTAT[] = {
+ { '0', "All services" },
+ { '1', "All in the moment active services" },
+ { '2', "Call diversion" },
+ { '3', "Roaming information status" },
+ { '4', "Call barring status" },
+ { '5', "Deferred delivery status" },
+ { '6', "Number of stored messages" },
+ { 0, NULL },
+};
+
+static const value_string vals_xser_service[] = {
+ { 0, "Not Used" },
+ { 1, "GSM UDH information" },
+ { 2, "GSM DCS information" },
+ { 3, "[Message Type] TDMA information exchange" },
+ { 4, "[Message Reference] TDMA information exchange" },
+ { 5, "[Privacy Indicator] TDMA information exchange" },
+ { 6, "[Urgency Indicator] TDMA information exchange" },
+ { 7, "[Acknowledgement Request] 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" },
+ { 12, "Billing identifier" },
+ { 13, "Single shot indicator" },
+ { 14, "Originator TON" },
+ { 15, "Originator NPI" },
+ { 16, "Recipient TON" },
+ { 17, "Recipient NPI" },
+ { 18, "Message Original Submission Time" },
+ { 19, "Destination Network Type" },
+ { 0, NULL },
+};
+static value_string_ext vals_xser_service_ext = VALUE_STRING_EXT_INIT(vals_xser_service);
+
+/* For statistics */
+static void
+ucp_stats_tree_init(stats_tree* st)
+{
+ st_ucp_messages = stats_tree_create_node(st, st_str_ucp, 0, STAT_DT_INT, TRUE);
+ st_ucp_ops = stats_tree_create_node(st, st_str_ops, st_ucp_messages, STAT_DT_INT, TRUE);
+ st_ucp_res = stats_tree_create_node(st, st_str_res, st_ucp_messages, STAT_DT_INT, TRUE);
+ st_ucp_results = stats_tree_create_node(st, st_str_ucp_res, 0, STAT_DT_INT, TRUE);
+ st_ucp_results_pos = stats_tree_create_node(st, st_str_pos, st_ucp_results, STAT_DT_INT, TRUE);
+ st_ucp_results_neg = stats_tree_create_node(st, st_str_neg, st_ucp_results, STAT_DT_INT, TRUE);
+}
+
+static tap_packet_status
+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,
+ tap_flags_t flags _U_) /* Used for getting UCP stats */
+{
+ const ucp_tap_rec_t *tap_rec = (const 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_ext(tap_rec->operation, &vals_hdr_OT_ext,
+ "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_ext(tap_rec->operation, &vals_hdr_OT_ext,
+ "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_ext(tap_rec->result, &vals_parm_EC_ext,
+ "Unknown EC: %d"), st_ucp_results_neg, FALSE);
+ }
+ }
+
+ return TAP_PACKET_REDRAW;
+}
+
+/*!
+ * Checks whether the PDU looks a bit like UCP and checks the checksum
+ *
+ * Note: check_ucp is called only with a buffer of at least LEN+2 bytes.
+ * IOW: The buffer should contain a complete UCP PDU [STX ... ETX]
+ *
+ * \param tvb The buffer with PDU-data
+ * \param endpkt Returns pointer, indicating the end of the PDU
+ *
+ * \return The state of this PDU
+ * 0 Definitely UCP
+ * UCP_MALFORMED ???
+ * UCP_INV_CHK Nice packet, but checksum doesn't add up...
+ */
+static int
+check_ucp(tvbuff_t *tvb, int *endpkt)
+{
+ guint offset = 1;
+ guint checksum = 0;
+ int pkt_check, tmp;
+ int length;
+
+ length = tvb_find_guint8(tvb, offset, -1, UCP_ETX);
+ if (length == -1) {
+ *endpkt = tvb_reported_length_remaining(tvb, offset);
+ return UCP_MALFORMED;
+ }
+ for (; offset < (guint) (length - 2); offset++)
+ checksum += tvb_get_guint8(tvb, offset);
+ checksum &= 0xFF;
+ tmp = tvb_get_guint8(tvb, offset++);
+ pkt_check = AHex2Bin(tmp);
+ tmp = tvb_get_guint8(tvb, offset++);
+ pkt_check = 16 * pkt_check + AHex2Bin(tmp);
+ *endpkt = offset + 1;
+ if (checksum == (guint) pkt_check)
+ return 0;
+ else
+ return UCP_INV_CHK;
+}
+
+/*!
+ * UCP equivalent of mktime() (3). Convert date to standard 'time_t' format
+ *
+ * \param len The length of datestr
+ * \param datestr The UCP-formatted date to convert
+ *
+ * \return The date in standard 'time_t' format.
+ */
+static time_t
+ucp_mktime(const gint len, const char *datestr)
+{
+ struct tm r_time;
+
+ r_time.tm_mday = (10 * (datestr[0] - '0') + (datestr[1] - '0'));
+
+ if (len >= 4)
+ r_time.tm_mon = (10 * (datestr[2] - '0') + (datestr[3] - '0')) - 1;
+ else
+ r_time.tm_mon = 0;
+
+ if (len >= 6)
+ r_time.tm_year = (10 * (datestr[4] - '0') + (datestr[5] - '0'));
+ else
+ r_time.tm_year = 0;
+ if (r_time.tm_year < 90)
+ r_time.tm_year += 100;
+
+ if (len >= 8)
+ r_time.tm_hour = (10 * (datestr[6] - '0') + (datestr[7] - '0'));
+ else
+ r_time.tm_hour = 0;
+
+ if (len >= 10)
+ r_time.tm_min = (10 * (datestr[8] - '0') + (datestr[9] - '0'));
+ else
+ r_time.tm_min = 0;
+
+ if (len >= 12)
+ r_time.tm_sec = (10 * (datestr[10] - '0') + (datestr[11] - '0'));
+ else
+ r_time.tm_sec = 0;
+
+ r_time.tm_isdst = -1;
+
+ return mktime(&r_time);
+}
+
+/*!
+ * Scanning routines to add standard types (byte, int, string, data)
+ * to the protocol-tree. Each field is seperated with a slash ('/').
+ *
+ * \param tree The protocol tree to add to
+ * \param tvb Buffer containing the data
+ * \param field The actual field, whose value needs displaying
+ * \param offset Location of field within the buffer, returns location
+ * of next field.
+ *
+ */
+static void
+ucp_handle_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+ gint idx, len;
+
+ idx = tvb_find_guint8(tvb, *offset, -1, '/');
+ if (idx == -1) {
+ /* Force the appropriate exception to be thrown. */
+ len = tvb_captured_length_remaining(tvb, *offset);
+ tvb_ensure_bytes_exist(tvb, *offset, len + 1);
+ } else
+ len = idx - *offset;
+ if (len > 0)
+ proto_tree_add_item(tree, field, tvb, *offset, len, ENC_ASCII|ENC_NA);
+ *offset += len;
+ if (idx != -1)
+ *offset += 1; /* skip terminating '/' */
+}
+
+static void
+ucp_handle_IRAstring(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+ GByteArray *bytes;
+ wmem_strbuf_t *strbuf;
+ char *strval = NULL;
+ int idx, len;
+ int tmpoff;
+
+ idx = tvb_find_guint8(tvb, *offset, -1, '/');
+ if (idx == -1) {
+ /* Force the appropriate exception to be thrown. */
+ len = tvb_captured_length_remaining(tvb, *offset);
+ tvb_ensure_bytes_exist(tvb, *offset, len + 1);
+ } else {
+ len = idx - *offset;
+ }
+ bytes = g_byte_array_sized_new(len);
+ if (tvb_get_string_bytes(tvb, *offset, len, ENC_ASCII|ENC_STR_HEX|ENC_SEP_NONE, bytes, &tmpoff)) {
+ strval = get_ts_23_038_7bits_string_unpacked(wmem_packet_scope(), bytes->data, bytes->len);
+ }
+ strbuf = wmem_strbuf_new(wmem_packet_scope(), strval);
+ while ((tmpoff + 1) < idx) {
+ wmem_strbuf_append_unichar_repl(strbuf);
+ tmpoff += 2;
+ if ((tmpoff + 1) >= idx) break;
+ bytes = g_byte_array_set_size(bytes, 0);
+ if (tvb_get_string_bytes(tvb, tmpoff, idx-tmpoff, ENC_ASCII|ENC_STR_HEX|ENC_SEP_NONE, bytes, &tmpoff)) {
+ strval = get_ts_23_038_7bits_string_unpacked(wmem_packet_scope(), bytes->data, bytes->len);
+ wmem_strbuf_append(strbuf, strval);
+ }
+ }
+ if (tmpoff < idx) {
+ /* Odd string length, which is impossible and indicates an error. */
+ wmem_strbuf_append_unichar_repl(strbuf);
+ }
+ g_byte_array_free(bytes, TRUE);
+ if (len > 0) {
+ proto_tree_add_string(tree, field, tvb, *offset,
+ len, wmem_strbuf_finalize(strbuf));
+ }
+ *offset += len;
+ if (idx != -1)
+ *offset += 1; /* skip terminating '/' */
+}
+
+static guint
+ucp_handle_byte(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+ guint intval = 0;
+
+ if ((intval = tvb_get_guint8(tvb, (*offset)++)) != '/') {
+ proto_tree_add_uint(tree, field, tvb, *offset - 1, 1, intval);
+ (*offset)++;
+ }
+ return intval;
+}
+
+static guint
+ucp_handle_int(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, int field, int *offset)
+{
+ gint idx, len;
+ const char *strval;
+ guint intval = 0;
+ gboolean intval_valid;
+ proto_item *pi;
+
+ idx = tvb_find_guint8(tvb, *offset, -1, '/');
+ if (idx == -1) {
+ /* Force the appropriate exception to be thrown. */
+ len = tvb_captured_length_remaining(tvb, *offset);
+ tvb_ensure_bytes_exist(tvb, *offset, len + 1);
+ } else
+ len = idx - *offset;
+ strval = tvb_get_string_enc(wmem_packet_scope(), tvb, *offset, len, ENC_ASCII);
+ if (len > 0) {
+ intval_valid = ws_strtou32(strval, NULL, &intval);
+ pi = proto_tree_add_uint(tree, field, tvb, *offset, len, intval);
+ if (!intval_valid)
+ expert_add_info_format(pinfo, pi, &ei_ucp_intstring_invalid,
+ "Invalid integer string: %s", strval);
+ }
+ *offset += len;
+ if (idx != -1)
+ *offset += 1; /* skip terminating '/' */
+ return intval;
+}
+
+static void
+ucp_handle_time(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+ gint idx, len;
+ const char *strval;
+ time_t tval;
+ nstime_t tmptime;
+
+ idx = tvb_find_guint8(tvb, *offset, -1, '/');
+ if (idx == -1) {
+ /* Force the appropriate exception to be thrown. */
+ len = tvb_captured_length_remaining(tvb, *offset);
+ tvb_ensure_bytes_exist(tvb, *offset, len + 1);
+ } else
+ len = idx - *offset;
+ strval = tvb_get_string_enc(wmem_packet_scope(), tvb, *offset, len, ENC_ASCII);
+ if (len > 0) {
+ tval = ucp_mktime(len, strval);
+ tmptime.secs = tval;
+ tmptime.nsecs = 0;
+ proto_tree_add_time(tree, field, tvb, *offset, len, &tmptime);
+ }
+ *offset += len;
+ if (idx != -1)
+ *offset += 1; /* skip terminating '/' */
+}
+
+static void
+ucp_handle_data(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+ int tmpoff = *offset;
+
+ while (tvb_get_guint8(tvb, tmpoff++) != '/')
+ ;
+ if ((tmpoff - *offset) > 1)
+ proto_tree_add_item(tree, field, tvb, *offset,
+ tmpoff - *offset - 1, ENC_NA);
+ *offset = tmpoff;
+}
+
+static void
+ucp_handle_data_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+ int tmpoff = *offset;
+
+ while (tvb_get_guint8(tvb, tmpoff++) != '/')
+ ;
+ if ((tmpoff - *offset) > 1)
+ proto_tree_add_item(tree, field, tvb, *offset,
+ tmpoff - *offset - 1, ENC_ASCII|ENC_NA);
+ *offset = tmpoff;
+}
+
+/*!
+ * Handle the data-field within the UCP-message, according the Message Type
+ * - 1 Tone only
+ * - 2 Numeric message
+ * - 3 Alphanumeric message
+ * - 4 Transparent (binary) data
+ * - 5 Standard text handling
+ * - 6 Alphanumeric message in specified character set
+ *
+ * \param tree The protocol tree to add to
+ * \param tvb Buffer containing the data
+ * \param offset Location of field within the buffer, returns location
+ * of next field.
+ */
+static void
+ucp_handle_mt(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, int *offset)
+{
+ guint intval;
+
+ intval = ucp_handle_byte(tree, tvb, hf_ucp_parm_MT, offset);
+ switch (intval) {
+ case '1': /* Tone only, no data */
+ break;
+ case '4': /* TMsg, no of bits */
+ ucp_handle_string(tree, tvb, hf_ucp_parm_NB, offset);
+ /* fall through here for the data piece */
+ /* FALLTHROUGH */
+ case '2':
+ ucp_handle_data(tree, tvb, hf_ucp_data_section, offset);
+ break;
+ case '3':
+ ucp_handle_IRAstring(tree, tvb, hf_ucp_parm_AMsg, offset);
+ break;
+ case '5':
+ ucp_handle_byte(tree, tvb, hf_ucp_parm_PNC, offset);
+ ucp_handle_string(tree, tvb, hf_ucp_parm_LNo, offset);
+ ucp_handle_string(tree, tvb, hf_ucp_parm_LST, offset);
+ ucp_handle_string(tree, tvb, hf_ucp_parm_TNo, offset);
+ break;
+ case '6':
+ ucp_handle_data(tree, tvb, hf_ucp_data_section, offset);
+ ucp_handle_int(tree, pinfo, tvb, hf_ucp_parm_CS, offset);
+ break;
+ default:
+ break; /* No data so ? */
+ }
+}
+
+/*!
+ * Handle the data within the 'Extended services' field. Each field having the
+ * format TTLLDD..., TT being the type of service, LL giving the length of the
+ * field, DD... containing the actual data
+ *
+ * \param tree The protocol tree to add to
+ * \param tvb Buffer containing the extended services data
+ */
+static void
+ucp_handle_XSer(proto_tree *tree, tvbuff_t *tvb)
+{
+ int offset = 0;
+ guint intval;
+ int service;
+ int len;
+
+ while ((intval = tvb_get_guint8(tvb, offset)) != '/') {
+ service = AHex2Bin(intval);
+ intval = tvb_get_guint8(tvb, offset+1);
+ service = service * 16 + AHex2Bin(intval);
+ intval = tvb_get_guint8(tvb, offset+2);
+ len = AHex2Bin(intval);
+ intval = tvb_get_guint8(tvb, offset+3);
+ len = len * 16 + AHex2Bin(intval);
+ proto_tree_add_uint(tree, hf_xser_service, tvb, offset, 2, service);
+ proto_tree_add_uint(tree, hf_xser_length, tvb, offset+2, 2, len);
+ proto_tree_add_item(tree, hf_xser_data, tvb, offset+4, len*2, ENC_ASCII);
+ offset += 4 + (2 * len);
+ }
+}
+
+/* Next definitions are just a convenient shorthand to make the coding a
+ * bit more readable instead of summing up all these parameters.
+ */
+#define UcpHandleString(field) ucp_handle_string(tree, tvb, (field), &offset)
+
+#define UcpHandleIRAString(field) \
+ ucp_handle_IRAstring(tree, tvb, (field), &offset)
+
+#define UcpHandleByte(field) ucp_handle_byte(tree, tvb, (field), &offset)
+
+#define UcpHandleInt(field) ucp_handle_int(tree, pinfo, tvb, (field), &offset)
+
+#define UcpHandleTime(field) ucp_handle_time(tree, tvb, (field), &offset)
+
+#define UcpHandleData(field) ucp_handle_data(tree, tvb, (field), &offset)
+
+#define UcpHandleDataString(field)\
+ ucp_handle_data_string(tree, tvb, (field), &offset)
+
+/*!
+ * The next set of routines handle the different operation types,
+ * associated with UCP.
+ */
+static void
+add_00O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Enquiry */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+}
+
+static void
+add_00R(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A')
+ {
+ UcpHandleByte(hf_ucp_parm_BAS);
+ UcpHandleByte(hf_ucp_parm_LAR);
+ UcpHandleByte(hf_ucp_parm_L1R);
+ UcpHandleByte(hf_ucp_parm_L3R);
+ UcpHandleByte(hf_ucp_parm_LCR);
+ UcpHandleByte(hf_ucp_parm_LUR);
+ UcpHandleByte(hf_ucp_parm_LRR);
+ UcpHandleByte(hf_ucp_parm_RT);
+ UcpHandleInt(hf_ucp_parm_NoN);
+ UcpHandleInt(hf_ucp_parm_NoA);
+ UcpHandleInt(hf_ucp_parm_NoB);
+
+ tap_rec->result = 0;
+ } else {
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+ }
+}
+
+static void
+add_01O(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb)
+{ /* Call input */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+ ucp_handle_mt(tree, pinfo, tvb, &offset);
+}
+
+static void
+add_01R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'N')
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ else
+ tap_rec->result = 0;
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_02O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* Multiple address call input*/
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_AdC);
+
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+ ucp_handle_mt(tree, pinfo, tvb, &offset);
+}
+
+#define add_02R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_03O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* Call input with SS */
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_GA);
+
+ UcpHandleByte(hf_ucp_parm_RP);
+ UcpHandleString(hf_ucp_parm_LRP);
+ UcpHandleByte(hf_ucp_parm_PR);
+ UcpHandleString(hf_ucp_parm_LPR);
+ UcpHandleByte(hf_ucp_parm_UM);
+ UcpHandleString(hf_ucp_parm_LUM);
+ UcpHandleByte(hf_ucp_parm_RC);
+ UcpHandleString(hf_ucp_parm_LRC);
+ UcpHandleByte(hf_ucp_parm_DD);
+ UcpHandleTime(hf_ucp_parm_DDT); /* DDMMYYHHmm */
+ ucp_handle_mt(tree, pinfo, tvb, &offset);
+}
+
+#define add_03R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_04O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Address list information */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_GAdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+}
+
+static void
+add_04R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_GAdC);
+ tap_rec->result = 0;
+ } else
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_05O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* Change address list */
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ UcpHandleString(hf_ucp_parm_GAdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleByte(hf_ucp_parm_A_D);
+}
+
+#define add_05R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_06O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Advice of accum. charges */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+}
+
+static void
+add_06R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ UcpHandleTime(hf_ucp_parm_CT);
+ UcpHandleString(hf_ucp_parm_AAC);
+ tap_rec->result = 0;
+ } else
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_07O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Password management */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_NAC);
+}
+
+#define add_07R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_08O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Leg. code management */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_LAC);
+ UcpHandleString(hf_ucp_parm_L1P);
+ UcpHandleString(hf_ucp_parm_L3P);
+ UcpHandleString(hf_ucp_parm_LRC);
+ UcpHandleString(hf_ucp_parm_LUM);
+ UcpHandleString(hf_ucp_parm_LRP);
+ UcpHandleString(hf_ucp_parm_LST);
+}
+
+#define add_08R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_09O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Standard text information */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_LNo);
+ UcpHandleString(hf_ucp_parm_LST);
+}
+
+static void
+add_09R(proto_tree *tree, packet_info *pinfo,tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_LST);
+ tap_rec->result = 0;
+ } else
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_10O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* Change standard text */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_LNo);
+ UcpHandleString(hf_ucp_parm_TNo);
+ UcpHandleData(hf_ucp_parm_STx);
+ UcpHandleInt(hf_ucp_parm_CS);
+}
+
+#define add_10R(a, b, c, d) add_01R(a, b, c, d)
+
+#define add_11O(a, b) add_06O(a, b) /* Request roaming info */
+
+static void
+add_11R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_GA);
+ tap_rec->result = 0;
+ } else
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_12O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* Change roaming */
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleString(hf_ucp_parm_GA);
+}
+
+#define add_12R(a, b, c, d) add_01R(a, b, c, d)
+
+#define add_13O(a, c) add_06O(a, c) /* Roaming reset */
+
+#define add_13R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_14O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Message retrieval */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_MNo);
+ UcpHandleByte(hf_ucp_parm_R_T);
+}
+
+static void
+add_14R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ /*
+ * Spec is unclear here. Is 'SM' part of the Msg:s field or not?
+ * For now, assume it is part of it...
+ */
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleData(hf_ucp_data_section);
+ tap_rec->result = 0;
+ } else {
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+ }
+}
+
+static void
+add_15O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Request call barring */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleTime(hf_ucp_parm_ST);
+ UcpHandleTime(hf_ucp_parm_SP);
+}
+
+#define add_15R(a, b, c, d) add_01R(a, b, c, d)
+
+#define add_16O(a, b) add_06O(a, b) /* Cancel call barring */
+
+#define add_16R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_17O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Request call diversion */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleString(hf_ucp_parm_DAdC);
+ UcpHandleTime(hf_ucp_parm_ST);
+ UcpHandleTime(hf_ucp_parm_SP);
+}
+
+#define add_17R(a, b, c, d) add_01R(a, b, c, d)
+
+#define add_18O(a, b) add_06O(a, b) /* Cancel call diversion */
+
+#define add_18R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_19O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Request deferred delivery*/
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleTime(hf_ucp_parm_ST);
+ UcpHandleTime(hf_ucp_parm_SP);
+}
+
+#define add_19R(a, b, c, d) add_01R(a, b, c, d)
+
+#define add_20O(a, b) add_06O(a, b) /* Cancel deferred delivery */
+
+#define add_20R(a, b, c, d) add_01R(a, b, c, d)
+
+#define add_21O(a, b) add_06O(a, b) /* All features reset */
+
+#define add_21R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_22O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* Call input w. add. CS */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_OAC);
+ UcpHandleData(hf_ucp_data_section);
+ UcpHandleInt(hf_ucp_parm_CS);
+}
+
+#define add_22R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_23O(proto_tree *tree, tvbuff_t *tvb)
+{ /* UCP version status */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_IVR5x);
+ UcpHandleByte(hf_ucp_parm_REQ_OT);
+}
+
+static void
+add_23R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ UcpHandleByte(hf_ucp_parm_IVR5x);
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleInt(hf_ucp_hdr_OT);
+ tap_rec->result = 0;
+ } else
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_24O(proto_tree *tree, tvbuff_t *tvb)
+{ /* Mobile subs. feature stat*/
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleByte(hf_ucp_parm_SSTAT);
+}
+
+static void
+add_24R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+ guint idx;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
+ proto_tree_add_item(tree, hf_ucp_ga_roaming, tvb, offset - 1, 1, ENC_NA);
+ if (intval == 'N') {
+ proto_tree_add_item(tree, hf_ucp_not_subscribed, tvb, offset -1, 1, ENC_NA);
+ offset++;
+ } else {
+ --offset;
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleData(hf_ucp_data_section);
+ }
+ }
+ if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
+ proto_tree_add_item(tree, hf_ucp_call_barring, tvb, offset - 1, 1, ENC_NA);
+ if (intval == 'N') {
+ proto_tree_add_item(tree, hf_ucp_not_subscribed, tvb, offset -1, 1, ENC_NA);
+ offset++;
+ } else {
+ --offset;
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleData(hf_ucp_data_section);
+ }
+ }
+ if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
+ proto_tree_add_item(tree, hf_ucp_deferred_delivery, tvb, offset - 1, 1, ENC_NA);
+ if (intval == 'N') {
+ proto_tree_add_item(tree, hf_ucp_not_subscribed, tvb, offset -1, 1, ENC_NA);
+ offset++;
+ } else {
+ --offset;
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleData(hf_ucp_data_section);
+ }
+ }
+ if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
+ proto_tree_add_item(tree, hf_ucp_diversion, tvb, offset - 1, 1, ENC_NA);
+ if (intval == 'N') {
+ proto_tree_add_item(tree, hf_ucp_not_subscribed, tvb, offset -1, 1, ENC_NA);
+ offset++;
+ } else {
+ --offset;
+ intval = UcpHandleInt(hf_ucp_parm_NPL);
+ for (idx = 0; idx < intval; idx++)
+ UcpHandleData(hf_ucp_data_section);
+ }
+ }
+ UcpHandleInt(hf_ucp_parm_LMN);
+ if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
+ if (intval == 'N') {
+ proto_tree_add_item(tree, hf_ucp_not_subscribed, tvb, offset -1, 1, ENC_NA);
+ offset++;
+ } else {
+ --offset;
+ UcpHandleInt(hf_ucp_parm_NMESS);
+ }
+ }
+ tap_rec->result = 0;
+ } else
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_30O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* SMS message transfer */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleByte(hf_ucp_parm_NRq);
+ UcpHandleString(hf_ucp_parm_NAdC);
+ UcpHandleInt(hf_ucp_parm_NPID);
+ UcpHandleByte(hf_ucp_parm_DD);
+ UcpHandleTime(hf_ucp_parm_DDT); /* DDMMYYHHmm */
+ UcpHandleTime(hf_ucp_parm_VP); /* DDMMYYHHmm */
+ UcpHandleIRAString(hf_ucp_parm_AMsg);
+}
+
+static void
+add_30R(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
+{
+ int offset = 1;
+ guint intval;
+
+ intval = UcpHandleByte(hf_ucp_parm_ACK);
+ if (intval == 'A') {
+ UcpHandleTime(hf_ucp_parm_MVP); /* DDMMYYHHmm */
+ tap_rec->result = 0;
+ } else {
+ tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
+ }
+ UcpHandleString(hf_ucp_parm_SM);
+}
+
+static void
+add_31O(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* SMT alert */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleInt(hf_ucp_parm_PID);
+}
+
+#define add_31R(a, b, c, d) add_01R(a, b, c, d)
+
+static void
+add_5xO(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{ /* 50-series operations */
+ guint intval;
+ int offset = 1;
+ int tmpoff;
+ proto_item *ti;
+ tvbuff_t *tmptvb;
+
+ UcpHandleString(hf_ucp_parm_AdC);
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleString(hf_ucp_parm_AC);
+ UcpHandleByte(hf_ucp_parm_NRq);
+ UcpHandleString(hf_ucp_parm_NAdC);
+ UcpHandleByte(hf_ucp_parm_NT);
+ UcpHandleInt(hf_ucp_parm_NPID);
+ UcpHandleByte(hf_ucp_parm_LRq);
+ UcpHandleString(hf_ucp_parm_LRAd);
+ UcpHandleInt(hf_ucp_parm_LPID);
+ UcpHandleByte(hf_ucp_parm_DD);
+ UcpHandleTime(hf_ucp_parm_DDT); /* DDMMYYHHmm */
+ UcpHandleTime(hf_ucp_parm_VP); /* DDMMYYHHmm */
+ UcpHandleString(hf_ucp_parm_RPID);
+ UcpHandleTime(hf_ucp_parm_SCTS); /* DDMMYYhhmmss */
+ UcpHandleByte(hf_ucp_parm_Dst);
+ UcpHandleInt(hf_ucp_parm_Rsn);
+ UcpHandleTime(hf_ucp_parm_DSCTS); /* DDMMYYhhmmss */
+ intval = UcpHandleByte(hf_ucp_parm_MT);
+ UcpHandleString(hf_ucp_parm_NB);
+ if (intval != '3')
+ UcpHandleData(hf_ucp_data_section);
+ else
+ UcpHandleIRAString(hf_ucp_parm_AMsg);
+ UcpHandleByte(hf_ucp_parm_MMS);
+ UcpHandleByte(hf_ucp_parm_PR);
+ UcpHandleByte(hf_ucp_parm_DCs);
+ UcpHandleByte(hf_ucp_parm_MCLs);
+ UcpHandleByte(hf_ucp_parm_RPI);
+ if (tvb_get_guint8(tvb, offset++) != '/') {
+ proto_tree_add_string(tree, hf_ucp_parm_CPg, tvb, offset - 1,1,
+ "(reserved for Code Page)");
+ offset++;
+ }
+ if (tvb_get_guint8(tvb, offset++) != '/') {
+ proto_tree_add_string(tree, hf_ucp_parm_RPLy, tvb, offset - 1,1,
+ "(reserved for Reply type)");
+ offset++;
+ }
+ UcpHandleString(hf_ucp_parm_OTOA);
+ UcpHandleString(hf_ucp_parm_HPLMN);
+ tmpoff = offset; /* Extra services */
+ while (tvb_get_guint8(tvb, tmpoff++) != '/')
+ ;
+ if ((tmpoff - offset) > 1) {
+ int len = tmpoff - offset - 1;
+ proto_tree *subtree;
+
+ ti = proto_tree_add_item(tree, hf_ucp_parm_XSer, tvb, offset, len, ENC_NA);
+ tmptvb = tvb_new_subset_length(tvb, offset, len + 1);
+ subtree = proto_item_add_subtree(ti, ett_XSer);
+ ucp_handle_XSer(subtree, tmptvb);
+ }
+ offset = tmpoff;
+ UcpHandleDataString(hf_ucp_parm_RES4);
+ UcpHandleDataString(hf_ucp_parm_RES5);
+}
+
+#define add_5xR(a, b, c, d) add_30R(a, b, c, d)
+
+static void
+add_6xO(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, guint8 OT)
+{ /* 60-series operations */
+ int offset = 1;
+
+ UcpHandleString(hf_ucp_parm_OAdC);
+ UcpHandleByte(hf_ucp_parm_OTON);
+ UcpHandleByte(hf_ucp_parm_ONPI);
+ if (OT == 60) {
+ UcpHandleByte(hf_ucp_parm_STYP0);
+ } else {
+ UcpHandleByte(hf_ucp_parm_STYP1);
+ }
+ UcpHandleIRAString(hf_ucp_parm_PWD);
+ UcpHandleIRAString(hf_ucp_parm_NPWD);
+ UcpHandleString(hf_ucp_parm_VERS);
+ UcpHandleString(hf_ucp_parm_LAdC);
+ UcpHandleByte(hf_ucp_parm_LTON);
+ UcpHandleByte(hf_ucp_parm_LNPI);
+ if (OT == 60) {
+ UcpHandleInt(hf_ucp_parm_OPID);
+ }
+ UcpHandleDataString(hf_ucp_parm_RES1);
+ if (OT == 61) {
+ UcpHandleDataString(hf_ucp_parm_RES2);
+ }
+}
+
+#define add_6xR(a, b, c, d) add_01R(a, b, c, d)
+
+/*
+ * End of convenient shorthands
+ */
+#undef UcpHandleString
+#undef UcpHandleIRAString
+#undef UcpHandleByte
+#undef UcpHandleInt
+#undef UcpHandleTime
+#undef UcpHandleData
+
+static guint
+get_ucp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
+{
+ 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;
+}
+
+/*
+ * The actual dissector
+ */
+
+/* We get here only with at least LEN+2 bytes in the buffer */
+
+static int
+dissect_ucp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0; /* Offset in packet within tvbuff */
+ guint8 O_R; /* Request or response */
+ guint8 OT; /* Operation type */
+ guint intval;
+ int i;
+ int result;
+ int endpkt;
+ ucp_tap_rec_t *tap_rec; /* Tap record */
+
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_item *sub_ti;
+ proto_tree *ucp_tree;
+ proto_tree *sub_tree;
+ tvbuff_t *tmp_tvb;
+
+ /* Make entries in Protocol column */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "UCP");
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ if (tvb_get_guint8(tvb, 0) != UCP_STX){
+ proto_tree_add_expert(tree, pinfo, &ei_ucp_stx_missing, tvb, 0, -1);
+ return tvb_captured_length(tvb);
+ }
+
+ /* Get data needed for dissect_ucp_common */
+ result = check_ucp(tvb, &endpkt);
+
+ O_R = tvb_get_guint8(tvb, UCP_O_R_OFFSET);
+ OT = tvb_get_guint8(tvb, UCP_OT_OFFSET) - '0';
+ OT = 10 * OT + (tvb_get_guint8(tvb, UCP_OT_OFFSET + 1) - '0');
+
+ /* Create Tap record */
+ tap_rec = wmem_new0(wmem_packet_scope(), 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_append_fstr(pinfo->cinfo, COL_INFO, "%s (%s)",
+ val_to_str_ext_const(OT, &vals_hdr_OT_ext, "unknown operation"),
+ val_to_str(O_R, vals_hdr_O_R, "Unknown (%d)"));
+ if (result == UCP_INV_CHK)
+ col_append_str(pinfo->cinfo, COL_INFO, " [checksum invalid]");
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ necessary to generate protocol tree items. */
+ if (tree) {
+
+ /* create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_ucp, tvb, 0, -1, ENC_NA);
+
+ ucp_tree = proto_item_add_subtree(ti, ett_ucp);
+ /*
+ * Process the packet here.
+ * Transaction number
+ */
+ offset++; /* Skip <stx> */
+ intval = tvb_get_guint8(tvb, offset+0) - '0';
+ intval = 10 * intval + (tvb_get_guint8(tvb, offset+1) - '0');
+ proto_tree_add_uint(ucp_tree, hf_ucp_hdr_TRN, tvb, offset,
+ UCP_TRN_LEN, intval);
+ offset += UCP_TRN_LEN + 1; /* Skip TN/ */
+
+ intval = 0;
+ for (i = 0; i < UCP_LEN_LEN; i++) { /* Length */
+ intval = 10 * intval +
+ (tvb_get_guint8(tvb, offset+i) - '0');
+ }
+ proto_tree_add_uint(ucp_tree, hf_ucp_hdr_LEN, tvb, offset,
+ UCP_LEN_LEN, intval);
+ offset += UCP_LEN_LEN + 1; /* skip LEN/ */
+
+ proto_tree_add_uint(ucp_tree, hf_ucp_hdr_O_R, tvb, offset,
+ UCP_O_R_LEN, O_R);
+
+ offset += UCP_O_R_LEN + 1; /* skip Operation_type/ */
+
+ proto_tree_add_uint(ucp_tree, hf_ucp_hdr_OT, tvb, offset,
+ UCP_OT_LEN, OT);
+ offset += UCP_OT_LEN;
+
+ /*
+ * Variable part starts here.
+ */
+
+ tmp_tvb = tvb_new_subset_remaining(tvb, offset);
+ sub_ti = proto_tree_add_item(ucp_tree, hf_ucp_oper_section, tvb,
+ offset, endpkt - offset, ENC_NA);
+ 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, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 1:
+ O_R == 'O' ? add_01O(sub_tree, pinfo, tmp_tvb) : add_01R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 2:
+ O_R == 'O' ? add_02O(sub_tree, pinfo, tmp_tvb) : add_02R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 3:
+ O_R == 'O' ? add_03O(sub_tree, pinfo, tmp_tvb) : add_03R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 4:
+ O_R == 'O' ? add_04O(sub_tree, tmp_tvb) : add_04R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 5:
+ O_R == 'O' ? add_05O(sub_tree, pinfo, tmp_tvb) : add_05R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 6:
+ O_R == 'O' ? add_06O(sub_tree, tmp_tvb) : add_06R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 7:
+ O_R == 'O' ? add_07O(sub_tree,tmp_tvb) : add_07R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 8:
+ O_R == 'O' ? add_08O(sub_tree,tmp_tvb) : add_08R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 9:
+ O_R == 'O' ? add_09O(sub_tree,tmp_tvb) : add_09R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 10:
+ O_R == 'O' ? add_10O(sub_tree, pinfo, tmp_tvb) : add_10R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 11:
+ O_R == 'O' ? add_11O(sub_tree,tmp_tvb) : add_11R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 12:
+ O_R == 'O' ? add_12O(sub_tree, pinfo, tmp_tvb) : add_12R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 13:
+ O_R == 'O' ? add_13O(sub_tree, tmp_tvb) : add_13R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 14:
+ O_R == 'O' ? add_14O(sub_tree,tmp_tvb) : add_14R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 15:
+ O_R == 'O' ? add_15O(sub_tree,tmp_tvb) : add_15R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 16:
+ O_R == 'O' ? add_16O(sub_tree,tmp_tvb) : add_16R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 17:
+ O_R == 'O' ? add_17O(sub_tree,tmp_tvb) : add_17R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 18:
+ O_R == 'O' ? add_18O(sub_tree,tmp_tvb) : add_18R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 19:
+ O_R == 'O' ? add_19O(sub_tree,tmp_tvb) : add_19R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 20:
+ O_R == 'O' ? add_20O(sub_tree,tmp_tvb) : add_20R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 21:
+ O_R == 'O' ? add_21O(sub_tree,tmp_tvb) : add_21R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 22:
+ O_R == 'O' ? add_22O(sub_tree, pinfo, tmp_tvb) : add_22R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 23:
+ O_R == 'O' ? add_23O(sub_tree,tmp_tvb) : add_23R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 24:
+ O_R == 'O' ? add_24O(sub_tree,tmp_tvb) : add_24R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 30:
+ O_R == 'O' ? add_30O(sub_tree, pinfo, tmp_tvb) : add_30R(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 31:
+ O_R == 'O' ? add_31O(sub_tree, pinfo, tmp_tvb) : add_31R(sub_tree, pinfo, 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, pinfo, tmp_tvb) : add_5xR(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ case 60: case 61:
+ O_R == 'O' ? add_6xO(sub_tree, pinfo, tmp_tvb,OT) : add_6xR(sub_tree, pinfo, tmp_tvb, tap_rec);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Queue packet for Tap */
+ tap_queue_packet(ucp_tap, pinfo, tap_rec);
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_ucp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ tcp_dissect_pdus(tvb, pinfo, tree, ucp_desegment, UCP_HEADER_SIZE,
+ get_ucp_pdu_len, dissect_ucp_common, data);
+ return tvb_captured_length(tvb);
+}
+
+/*
+ * The heuristic dissector
+ */
+
+static gboolean
+dissect_ucp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ conversation_t *conversation;
+
+ /* Heuristic */
+
+ if (tvb_captured_length(tvb) < UCP_HEADER_SIZE)
+ return FALSE;
+
+ if ((tvb_get_guint8(tvb, 0) != UCP_STX) ||
+ (tvb_get_guint8(tvb, UCP_TRN_OFFSET + UCP_TRN_LEN) != '/') ||
+ (tvb_get_guint8(tvb, UCP_LEN_OFFSET + UCP_LEN_LEN) != '/') ||
+ (tvb_get_guint8(tvb, UCP_O_R_OFFSET + UCP_O_R_LEN) != '/') ||
+ (tvb_get_guint8(tvb, UCP_OT_OFFSET + UCP_OT_LEN) != '/'))
+ return FALSE;
+
+ if (try_val_to_str(tvb_get_guint8(tvb, UCP_O_R_OFFSET), vals_hdr_O_R) == NULL)
+ return FALSE;
+
+ /*
+ * Ok, looks like a valid packet
+ */
+
+ /* Set up a conversation with attached dissector so dissect_ucp_heur
+ * won't be called any more for this TCP connection.
+ */
+
+ conversation = find_or_create_conversation(pinfo);
+ conversation_set_dissector(conversation, ucp_handle);
+
+ dissect_ucp_tcp(tvb, pinfo, tree, data);
+
+ return TRUE;
+}
+
+/* Register the protocol with Wireshark */
+void
+proto_register_ucp(void)
+{
+
+ /* Setup list of fields */
+ static hf_register_info hf[] = {
+ { &hf_ucp_hdr_TRN,
+ { "Transaction Reference Number", "ucp.hdr.TRN",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Transaction number for this command, used in windowing.",
+ HFILL
+ }
+ },
+ { &hf_ucp_hdr_LEN,
+ { "Length", "ucp.hdr.LEN",
+ FT_UINT16, BASE_DEC, NULL, 0x00,
+ "Total number of characters between <stx>...<etx>.",
+ HFILL
+ }
+ },
+ { &hf_ucp_hdr_O_R,
+ { "Type", "ucp.hdr.O_R",
+ FT_CHAR, BASE_HEX, VALS(vals_hdr_O_R), 0x00,
+ "Your basic 'is a request or response'.",
+ HFILL
+ }
+ },
+ { &hf_ucp_hdr_OT,
+ { "Operation", "ucp.hdr.OT",
+ FT_UINT8, BASE_DEC | BASE_EXT_STRING, &vals_hdr_OT_ext, 0x00,
+ "The operation that is requested with this message.",
+ HFILL
+ }
+ },
+ { &hf_ucp_oper_section,
+ { "Data", "ucp.parm",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ "The actual content of the operation.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_AdC,
+ { "AdC", "ucp.parm.AdC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Address code recipient.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_OAdC,
+ { "OAdC", "ucp.parm.OAdC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Address code originator.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_DAdC,
+ { "DAdC", "ucp.parm.DAdC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Diverted address code.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_AC,
+ { "AC", "ucp.parm.AC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Authentication code.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_OAC,
+ { "OAC", "ucp.parm.OAC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Authentication code, originator.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NAC,
+ { "NAC", "ucp.parm.NAC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "New authentication code.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_BAS,
+ { "BAS", "ucp.parm.BAS",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_BAS), 0x00,
+ "Barring status flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LAR,
+ { "LAR", "ucp.parm.LAR",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_LAR), 0x00,
+ "Leg. code for all calls flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LAC,
+ { "LAC", "ucp.parm.LAC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "New leg. code for all calls.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_L1R,
+ { "L1R", "ucp.parm.L1R",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_L1R), 0x00,
+ "Leg. code for priority 1 flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_L1P,
+ { "L1P", "ucp.parm.L1P",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "New leg. code for level 1 priority.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_L3R,
+ { "L3R", "ucp.parm.L3R",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_L3R), 0x00,
+ "Leg. code for priority 3 flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_L3P,
+ { "L3P", "ucp.parm.L3P",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "New leg. code for level 3 priority.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LCR,
+ { "LCR", "ucp.parm.LCR",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_LCR), 0x00,
+ "Leg. code for reverse charging flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LUR,
+ { "LUR", "ucp.parm.LUR",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_LUR), 0x00,
+ "Leg. code for urgent message flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LRR,
+ { "LRR", "ucp.parm.LRR",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_LRR), 0x00,
+ "Leg. code for repetition flag.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RT,
+ { "RT", "ucp.parm.RT",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_RT), 0x00,
+ "Receiver type.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NoN,
+ { "NoN", "ucp.parm.NoN",
+ FT_UINT16, BASE_DEC, NULL, 0x00,
+ "Maximum number of numerical characters accepted.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NoA,
+ { "NoA", "ucp.parm.NoA",
+ FT_UINT16, BASE_DEC, NULL, 0x00,
+ "Maximum number of alphanumerical characters accepted.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NoB,
+ { "NoB", "ucp.parm.NoB",
+ FT_UINT16, BASE_DEC, NULL, 0x00,
+ "Maximum number of data bits accepted.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_PNC,
+ { "PNC", "ucp.parm.PNC",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_PNC), 0x00,
+ "Paging network controller.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_AMsg,
+ { "AMsg", "ucp.parm.AMsg",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "The alphanumeric message that is being sent.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LNo,
+ { "LNo", "ucp.parm.LNo",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Standard text list number requested by calling party.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LST,
+ { "LST", "ucp.parm.LST",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Legitimisation code for standard text.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_TNo,
+ { "TNo", "ucp.parm.TNo",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Standard text number requested by calling party.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_CS,
+ { "CS", "ucp.parm.CS",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Additional character set number.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_PID,
+ { "PID", "ucp.parm.PID",
+ FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
+ "SMT PID value.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NPL,
+ { "NPL", "ucp.parm.NPL",
+ FT_UINT16, BASE_DEC, NULL, 0x00,
+ "Number of parameters in the following list.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_GA,
+ { "GA", "ucp.parm.GA",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "GA?? haven't got a clue.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RP,
+ { "RP", "ucp.parm.RP",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_RP), 0x00,
+ "Repetition requested.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LRP,
+ { "LRP", "ucp.parm.LRP",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Legitimisation code for repetition.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_PR,
+ { "PR", "ucp.parm.PR",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Priority requested.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LPR,
+ { "LPR", "ucp.parm.LPR",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Legitimisation code for priority requested.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_UM,
+ { "UM", "ucp.parm.UM",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_UM), 0x00,
+ "Urgent message indicator.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LUM,
+ { "LUM", "ucp.parm.LUM",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Legitimisation code for urgent message.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RC,
+ { "RC", "ucp.parm.RC",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_RC), 0x00,
+ "Reverse charging request.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LRC,
+ { "LRC", "ucp.parm.LRC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Legitimisation code for reverse charging.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NRq,
+ { "NRq", "ucp.parm.NRq",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_NRq), 0x00,
+ "Notification request.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_GAdC,
+ { "GAdC", "ucp.parm.GAdC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Group address code.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_A_D,
+ { "A_D", "ucp.parm.A_D",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_A_D), 0x00,
+ "Add to/delete from fixed subscriber address list record.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_CT,
+ { "CT", "ucp.parm.CT",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Accumulated charges timestamp.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_AAC,
+ { "AAC", "ucp.parm.AAC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Accumulated charges.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_MNo,
+ { "MNo", "ucp.parm.MNo",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Message number.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_R_T,
+ { "R_T", "ucp.parm.R_T",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_R_T), 0x00,
+ "Message number.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NAdC,
+ { "NAdC", "ucp.parm.NAdC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Notification address.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NT,
+ { "NT", "ucp.parm.NT",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_NT), 0x00,
+ "Notification type.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_IVR5x,
+ { "IVR5x", "ucp.parm.IVR5x",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "UCP release number supported/accepted.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_REQ_OT,
+ { "REQ_OT", "ucp.parm.REQ_OT",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_REQ_OT), 0x00,
+ "UCP release number supported/accepted.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_SSTAT,
+ { "SSTAT", "ucp.parm.SSTAT",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_SSTAT), 0x00,
+ "Supplementary services for which status is requested.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LMN,
+ { "LMN", "ucp.parm.LMN",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Last message number.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NMESS,
+ { "NMESS", "ucp.parm.NMESS",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Number of stored messages.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NPID,
+ { "NPID", "ucp.parm.NPID",
+ FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
+ "Notification PID value.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LRq,
+ { "LRq", "ucp.parm.LRq",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_LRq), 0x00,
+ "Last resort address request.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LRAd,
+ { "LRAd", "ucp.parm.LRAd",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Last resort address.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LPID,
+ { "LPID", "ucp.parm.LPID",
+ FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
+ "Last resort PID value.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_DD,
+ { "DD", "ucp.parm.DD",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_DD), 0x00,
+ "Deferred delivery requested.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_DDT,
+ { "DDT", "ucp.parm.DDT",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Deferred delivery time.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_STx,
+ { "STx", "ucp.parm.STx",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ "Standard text.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_ST,
+ { "ST", "ucp.parm.ST",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Start time.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_SP,
+ { "SP", "ucp.parm.SP",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Stop time.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_VP,
+ { "VP", "ucp.parm.VP",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Validity period.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RPID,
+ { "RPID", "ucp.parm.RPID",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Replace PID",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_SCTS,
+ { "SCTS", "ucp.parm.SCTS",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Service Centre timestamp.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_Dst,
+ { "Dst", "ucp.parm.Dst",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_Dst), 0x00,
+ "Delivery status.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_Rsn,
+ { "Rsn", "ucp.parm.Rsn",
+ FT_UINT16, BASE_DEC | BASE_EXT_STRING, &vals_parm_Rsn_ext, 0x00,
+ "Reason code.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_DSCTS,
+ { "DSCTS", "ucp.parm.DSCTS",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Delivery timestamp.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_MT,
+ { "MT", "ucp.parm.MT",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_MT), 0x00,
+ "Message type.",
+ HFILL
+ }
+ },
+ { &hf_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",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ "The actual message or data.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_MMS,
+ { "MMS", "ucp.parm.MMS",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "More messages to send.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_DCs,
+ { "DCs", "ucp.parm.DCs",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_DCs), 0x00,
+ "Data coding scheme (deprecated).",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_MCLs,
+ { "MCLs", "ucp.parm.MCLs",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_MCLs), 0x00,
+ "Message class.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RPI,
+ { "RPI", "ucp.parm.RPI",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_RPI), 0x00,
+ "Reply path.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_CPg,
+ { "CPg", "ucp.parm.CPg",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Reserved for Code Page.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RPLy,
+ { "RPLy", "ucp.parm.RPLy",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Reserved for Reply type.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_OTOA,
+ { "OTOA", "ucp.parm.OTOA",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Originator Type Of Address.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_HPLMN,
+ { "HPLMN", "ucp.parm.HPLMN",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Home PLMN address.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_XSer,
+ { "Extra services:", "ucp.parm.XSer",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ "Extra services.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RES4,
+ { "RES4", "ucp.parm.RES4",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Reserved for future use.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RES5,
+ { "RES5", "ucp.parm.RES5",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Reserved for future use.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_OTON,
+ { "OTON", "ucp.parm.OTON",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_OTON), 0x00,
+ "Originator type of number.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_ONPI,
+ { "ONPI", "ucp.parm.ONPI",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_ONPI), 0x00,
+ "Originator numbering plan id.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_STYP0,
+ { "STYP0", "ucp.parm.STYP0",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_STYP0), 0x00,
+ "Subtype of operation.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_STYP1,
+ { "STYP1", "ucp.parm.STYP1",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_STYP1), 0x00,
+ "Subtype of operation.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_PWD,
+ { "PWD", "ucp.parm.PWD",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Current password.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_NPWD,
+ { "NPWD", "ucp.parm.NPWD",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "New password.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_VERS,
+ { "VERS", "ucp.parm.VERS",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Version number.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LAdC,
+ { "LAdC", "ucp.parm.LAdC",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Address for VSMSC list operation.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LTON,
+ { "LTON", "ucp.parm.LTON",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Type of number list address.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_LNPI,
+ { "LNPI", "ucp.parm.LNPI",
+ FT_UINT8, BASE_DEC, NULL, 0x00,
+ "Numbering plan id. list address.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_OPID,
+ { "OPID", "ucp.parm.OPID",
+ FT_UINT8, BASE_DEC, VALS(vals_parm_OPID), 0x00,
+ "Originator protocol identifier.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RES1,
+ { "RES1", "ucp.parm.RES1",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Reserved for future use.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_RES2,
+ { "RES2", "ucp.parm.RES2",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Reserved for future use.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_ACK,
+ { "(N)Ack", "ucp.parm.ACK",
+ FT_CHAR, BASE_HEX, VALS(vals_parm_ACK), 0x00,
+ "Positive or negative acknowledge of the operation.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_MVP,
+ { "MVP", "ucp.parm.MVP",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
+ "Modified validity period.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_EC,
+ { "Error code", "ucp.parm.EC",
+ FT_UINT8, BASE_DEC | BASE_EXT_STRING, &vals_parm_EC_ext, 0x00,
+ "The result of the requested operation.",
+ HFILL
+ }
+ },
+ { &hf_ucp_parm_SM,
+ { "SM", "ucp.parm.SM",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "System message.",
+ HFILL
+ }
+ },
+ { &hf_ucp_ga_roaming,
+ { "GA roaming definitions", "ucp.parm.ga_roaming",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ { &hf_ucp_call_barring,
+ { "Call barring definitions", "ucp.parm.call_barring",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ { &hf_ucp_deferred_delivery,
+ { "Deferred delivery definitions", "ucp.parm.deferred_delivery",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ { &hf_ucp_diversion,
+ { "Diversion definitions", "ucp.parm.diversion",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ { &hf_ucp_not_subscribed,
+ { "Not subscribed/not allowed", "ucp.parm.not_subscribed",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ { &hf_xser_service,
+ { "Type of service", "ucp.xser.service",
+ FT_UINT8, BASE_HEX | BASE_EXT_STRING, &vals_xser_service_ext, 0x00,
+ "The type of service specified.",
+ HFILL
+ }
+ },
+ { &hf_xser_length,
+ { "Length", "ucp.xser.length",
+ FT_UINT16, BASE_DEC, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ { &hf_xser_data,
+ { "Data", "ucp.xser.data",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ NULL,
+ HFILL
+ }
+ },
+ };
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_ucp,
+ &ett_sub,
+ &ett_XSer
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_ucp_stx_missing, { "ucp.stx_missing", PI_MALFORMED, PI_ERROR, "UCP_STX missing, this is not a new packet", EXPFILL }},
+ { &ei_ucp_intstring_invalid, { "ucp.intstring.invalid", PI_MALFORMED, PI_ERROR, "Invalid integer string", EXPFILL }}
+ };
+
+ module_t *ucp_module;
+ expert_module_t* expert_ucp;
+
+ /* 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));
+ expert_ucp = expert_register_protocol(proto_ucp);
+ expert_register_field_array(expert_ucp, ei, array_length(ei));
+
+ /* Register the dissector handle */
+ ucp_handle = register_dissector("ucp", dissect_ucp_tcp, proto_ucp);
+
+ /* 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);
+}
+
+void
+proto_reg_handoff_ucp(void)
+{
+ /*
+ * UCP can be spoken on any port so, when not on a specific port, try heuristic
+ * whenever TCP is spoken.
+ */
+ heur_dissector_add("tcp", dissect_ucp_heur, "UCP over TCP", "ucp_tcp", proto_ucp, HEURISTIC_ENABLE);
+
+ /*
+ * Also register as a dissector that can be selected by a TCP port number via "decode as".
+ */
+ dissector_add_for_decode_as_with_preference("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);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */