diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-ucp.c | |
parent | Initial commit. (diff) | |
download | wireshark-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.c | 2849 |
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: + */ |