a16a16a6d7a2a3a7e85384402ca63c961ea7b301
[obnox/wireshark/wip.git] / epan / dissectors / packet-ucp.c
1 /* packet-ucp.c
2  * Routines for Universal Computer Protocol dissection
3  * Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  * ----------
25  *
26  * Dissector of a UCP (Universal Computer Protocol) PDU, as defined for the
27  * ERMES paging system in ETS 300 133-3 (2nd final draft, September 1997,
28  * www.etsi.org).
29  * Includes the extension of EMI-UCP interface (V4.0, May 2001, www.cmgwds.com)
30  *
31  * Support for statistics using the Stats Tree API added by
32  * Abhik Sarkar <sarkar.abhik@gmail.com>
33  *
34  */
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <ctype.h>
43 #include <time.h>
44
45 #include <glib.h>
46
47 #include <epan/packet.h>
48 #include <epan/prefs.h>
49 #include <epan/emem.h>
50 #include <epan/conversation.h>
51 #include <epan/stats_tree.h>
52
53 #include "packet-tcp.h"
54
55 /* Prototypes   */
56 static void dissect_ucp_tcp(tvbuff_t *, packet_info *, proto_tree *);
57 static void dissect_ucp_common(tvbuff_t *, packet_info *, proto_tree *);
58
59 /* Tap Record */
60 typedef struct _ucp_tap_rec_t {
61     guint message_type; /* 0 = Operation; 1 = Result */
62     guint operation;    /* Operation Type */
63     guint result;       /* 0 = Success; Non 0 = Error Code */
64 } ucp_tap_rec_t;
65
66 /* Preferences */
67 static gboolean ucp_desegment = TRUE;
68
69 /* STX + TRN(2 num. char.) + / + LEN(5 num. char.) + / + 'O'/'R' + / + OT(2 num. char.) + / */
70 #define UCP_HEADER_SIZE 15
71
72 /*
73  * Convert ASCII-hex character to binary equivalent. No checks, assume
74  * is valid hex character.
75  */
76 #define AHex2Bin(n)     (((n) & 0x40) ? ((n) & 0x0F) + 9 : ((n) & 0x0F))
77
78 #define UCP_STX       0x02                      /* Start of UCP PDU      */
79 #define UCP_ETX       0x03                      /* End of UCP PDU        */
80
81 #define UCP_MALFORMED   -1                      /* Not a valid PDU       */
82 #define UCP_INV_CHK     -2                      /* Incorrect checksum    */
83
84 #define UCP_TRN_OFFSET   1
85 #define UCP_LEN_OFFSET   4
86 #define UCP_O_R_OFFSET  10                      /* Location of O/R field */
87 #define UCP_OT_OFFSET   12                      /* Location of OT field  */
88
89 #define UCP_TRN_LEN      2                      /* Length of TRN-field   */
90 #define UCP_LEN_LEN      5                      /* Length of LEN-field   */
91 #define UCP_O_R_LEN      1                      /* Length of O/R-field   */
92 #define UCP_OT_LEN       2                      /* Length of OT-field    */
93
94
95 static  dissector_handle_t ucp_handle;
96
97 /*
98  * Initialize the protocol and registered fields
99  *
100  * Header (fixed) section
101  */
102 static int proto_ucp             = -1;
103
104 static int hf_ucp_hdr_TRN        = -1;
105 static int hf_ucp_hdr_LEN        = -1;
106 static int hf_ucp_hdr_O_R        = -1;
107 static int hf_ucp_hdr_OT         = -1;
108
109 /*
110  * Stats section
111  */
112 static int st_ucp_messages       = -1;
113 static int st_ucp_ops            = -1;
114 static int st_ucp_res            = -1;
115 static int st_ucp_results        = -1;
116 static int st_ucp_results_pos    = -1;
117 static int st_ucp_results_neg    = -1;
118
119 static gchar* st_str_ucp         = "UCP Messages";
120 static gchar* st_str_ops         = "Operations";
121 static gchar* st_str_res         = "Results";
122 static gchar* st_str_ucp_res     = "UCP Results Acks/Nacks";
123 static gchar* st_str_pos         = "Positive";
124 static gchar* st_str_neg         = "Negative";
125
126 /*
127  * Data (variable) section
128  */
129 static int hf_ucp_oper_section   = -1;
130 static int hf_ucp_parm_AdC       = -1;
131 static int hf_ucp_parm_OAdC      = -1;
132 static int hf_ucp_parm_DAdC      = -1;
133 static int hf_ucp_parm_AC        = -1;
134 static int hf_ucp_parm_OAC       = -1;
135 static int hf_ucp_parm_BAS       = -1;
136 static int hf_ucp_parm_LAR       = -1;
137 static int hf_ucp_parm_LAC       = -1;
138 static int hf_ucp_parm_L1R       = -1;
139 static int hf_ucp_parm_L1P       = -1;
140 static int hf_ucp_parm_L3R       = -1;
141 static int hf_ucp_parm_L3P       = -1;
142 static int hf_ucp_parm_LCR       = -1;
143 static int hf_ucp_parm_LUR       = -1;
144 static int hf_ucp_parm_LRR       = -1;
145 static int hf_ucp_parm_RT        = -1;
146 static int hf_ucp_parm_NoN       = -1;
147 static int hf_ucp_parm_NoA       = -1;
148 static int hf_ucp_parm_NoB       = -1;
149 static int hf_ucp_parm_NAC       = -1;
150 static int hf_ucp_parm_PNC       = -1;
151 static int hf_ucp_parm_AMsg      = -1;
152 static int hf_ucp_parm_LNo       = -1;
153 static int hf_ucp_parm_LST       = -1;
154 static int hf_ucp_parm_TNo       = -1;
155 static int hf_ucp_parm_CS        = -1;
156 static int hf_ucp_parm_PID       = -1;
157 static int hf_ucp_parm_NPL       = -1;
158 static int hf_ucp_parm_GA        = -1;
159 static int hf_ucp_parm_RP        = -1;
160 static int hf_ucp_parm_LRP       = -1;
161 static int hf_ucp_parm_PR        = -1;
162 static int hf_ucp_parm_LPR       = -1;
163 static int hf_ucp_parm_UM        = -1;
164 static int hf_ucp_parm_LUM       = -1;
165 static int hf_ucp_parm_RC        = -1;
166 static int hf_ucp_parm_LRC       = -1;
167 static int hf_ucp_parm_NRq       = -1;
168 static int hf_ucp_parm_GAdC      = -1;
169 static int hf_ucp_parm_A_D       = -1;
170 static int hf_ucp_parm_CT        = -1;
171 static int hf_ucp_parm_AAC       = -1;
172 static int hf_ucp_parm_MNo       = -1;
173 static int hf_ucp_parm_R_T       = -1;
174 static int hf_ucp_parm_IVR5x     = -1;
175 static int hf_ucp_parm_REQ_OT    = -1;
176 static int hf_ucp_parm_SSTAT     = -1;
177 static int hf_ucp_parm_LMN       = -1;
178 static int hf_ucp_parm_NMESS     = -1;
179 static int hf_ucp_parm_NMESS_str = -1;
180 static int hf_ucp_parm_NAdC      = -1;
181 static int hf_ucp_parm_NT        = -1;
182 static int hf_ucp_parm_NPID      = -1;
183 static int hf_ucp_parm_LRq       = -1;
184 static int hf_ucp_parm_LRAd      = -1;
185 static int hf_ucp_parm_LPID      = -1;
186 static int hf_ucp_parm_DD        = -1;
187 static int hf_ucp_parm_DDT       = -1;
188 static int hf_ucp_parm_STx       = -1;
189 static int hf_ucp_parm_ST        = -1;
190 static int hf_ucp_parm_SP        = -1;
191 static int hf_ucp_parm_VP        = -1;
192 static int hf_ucp_parm_RPID      = -1;
193 static int hf_ucp_parm_SCTS      = -1;
194 static int hf_ucp_parm_Dst       = -1;
195 static int hf_ucp_parm_Rsn       = -1;
196 static int hf_ucp_parm_DSCTS     = -1;
197 static int hf_ucp_parm_MT        = -1;
198 static int hf_ucp_parm_NB        = -1;
199 static int hf_ucp_data_section   = -1;
200 static int hf_ucp_parm_MMS       = -1;
201 static int hf_ucp_parm_DCs       = -1;
202 static int hf_ucp_parm_MCLs      = -1;
203 static int hf_ucp_parm_RPI       = -1;
204 static int hf_ucp_parm_CPg       = -1;
205 static int hf_ucp_parm_RPLy      = -1;
206 static int hf_ucp_parm_OTOA      = -1;
207 static int hf_ucp_parm_HPLMN     = -1;
208 static int hf_ucp_parm_RES4      = -1;
209 static int hf_ucp_parm_RES5      = -1;
210 static int hf_ucp_parm_OTON      = -1;
211 static int hf_ucp_parm_ONPI      = -1;
212 static int hf_ucp_parm_STYP0     = -1;
213 static int hf_ucp_parm_STYP1     = -1;
214 static int hf_ucp_parm_ACK       = -1;
215 static int hf_ucp_parm_PWD       = -1;
216 static int hf_ucp_parm_NPWD      = -1;
217 static int hf_ucp_parm_VERS      = -1;
218 static int hf_ucp_parm_LAdC      = -1;
219 static int hf_ucp_parm_LTON      = -1;
220 static int hf_ucp_parm_LNPI      = -1;
221 static int hf_ucp_parm_OPID      = -1;
222 static int hf_ucp_parm_RES1      = -1;
223 static int hf_ucp_parm_RES2      = -1;
224 static int hf_ucp_parm_MVP       = -1;
225 static int hf_ucp_parm_EC        = -1;
226 static int hf_ucp_parm_SM        = -1;
227
228 static int hf_ucp_parm_XSer      = -1;
229 static int hf_xser_service       = -1;
230 static int hf_xser_length        = -1;
231 static int hf_xser_data          = -1;
232
233 /* Initialize the subtree pointers */
234 static gint ett_ucp              = -1;
235 static gint ett_sub              = -1;
236 static gint ett_XSer             = -1;
237
238 /* Tap */
239 static int ucp_tap               = -1;
240
241 /*
242  * Value-arrays for certain field-contents
243  */
244 static const value_string vals_hdr_O_R[] = {
245     {  'O', "Operation" },
246     {  'R', "Result" },
247     {  0, NULL }
248 };
249
250 static const value_string vals_hdr_OT[] = {     /* Operation type       */
251     {  0, "Enquiry" },
252     {  1, "Call input" },
253     {  2, "Call input (multiple address)" },
254     {  3, "Call input (supplementary services included)" },
255     {  4, "Address list information" },
256     {  5, "Change address list" },
257     {  6, "Advice of accumulated charges" },
258     {  7, "Password management" },
259     {  8, "Legitimisation code management" },
260     {  9, "Standard text information" },
261     { 10, "Change standard text" },
262     { 11, "Request roaming information" },
263     { 12, "Change roaming information" },
264     { 13, "Roaming reset" },
265     { 14, "Message retrieval" },
266     { 15, "Request call barring" },
267     { 16, "Cancel call barring" },
268     { 17, "Request call diversion" },
269     { 18, "Cancel call diversion" },
270     { 19, "Request deferred delivery" },
271     { 20, "Cancel deferred delivery" },
272     { 21, "All features reset" },
273     { 22, "Call input (with specific character set)" },
274     { 23, "UCP version status request" },
275     { 24, "Mobile subscriber feature status request" },
276     { 30, "SMS message transfer" },
277     { 31, "SMT alert" },
278     { 32, "(proprietary)" },
279     { 34, "(proprietary)" },
280     { 36, "(proprietary)" },
281     { 38, "(proprietary)" },
282     { 40, "(proprietary)" },
283     { 41, "(proprietary)" },
284     { 42, "(proprietary)" },
285     { 43, "(proprietary)" },
286     { 44, "(proprietary)" },
287     { 45, "(proprietary)" },
288     { 51, "Submit short message" },
289     { 52, "Deliver short message" },
290     { 53, "Deliver notification" },
291     { 54, "Modify message" },
292     { 55, "Inquiry message" },
293     { 56, "Delete message" },
294     { 57, "Inquiry response message" },
295     { 58, "Delete response message" },
296     { 60, "Session management" },
297     { 61, "List management" },
298     { 95, "(proprietary)" },
299     { 96, "(proprietary)" },
300     { 97, "(proprietary)" },
301     { 98, "(proprietary)" },
302     { 99, "(proprietary)" },
303     {  0, NULL }
304 };
305
306 static const value_string vals_parm_EC[] = {    /* Error code   */
307     {  1, "Checksum error" },
308     {  2, "Syntax error" },
309     {  3, "Operation not supported by system" },
310     {  4, "Operation not allowed" },
311     {  5, "Call barring active" },
312     {  6, "AdC invalid" },
313     {  7, "Authentication failure" },
314     {  8, "Legitimisation code for all calls, failure" },
315     {  9, "GA not valid" },
316     { 10, "Repetition not allowed" },
317     { 11, "Legitimisation code for repetition, failure" },
318     { 12, "Priority call not allowed" },
319     { 13, "Legitimisation code for priority call, failure" },
320     { 14, "Urgent message not allowed" },
321     { 15, "Legitimisation code for urgent message, failure" },
322     { 16, "Reverse charging not allowed" },
323     { 17, "Legitimisation code for rev. charging, failure" },
324     { 18, "Deferred delivery not allowed" },
325     { 19, "New AC not valid" },
326     { 20, "New legitimisation code not valid" },
327     { 21, "Standard text not valid" },
328     { 22, "Time period not valid" },
329     { 23, "Message type not supported by system" },
330     { 24, "Message too long" },
331     { 25, "Requested standard text not valid" },
332     { 26, "Message type not valid for the pager type" },
333     { 27, "Message not found in SMSC" },
334     { 28, "Invalid character set" },
335     { 30, "Subscriber hang-up" },
336     { 31, "Fax group not supported" },
337     { 32, "Fax message type not supported" },
338     { 33, "Address already in list (60-series)" },
339     { 34, "Address not in list (60-series)" },
340     { 35, "List full, cannot add address to list (60-series)" },
341     { 36, "RPID already in use" },
342     { 37, "Delivery in progress" },
343     { 38, "Message forwarded" },
344     { 50, "Low network status" },
345     { 51, "Legitimisation code for standard text, failure" },
346     { 53, "Operation partially successful" },
347     { 54, "Operation not successful" },
348     { 55, "System error" },
349     { 57, "AdC already a member of GAdC address list" },
350     { 58, "AdC not a member of GAdC address list" },
351     { 59, "Requested standard text list invalid" },
352     { 61, "Not controller of GAdC address list" },
353     { 62, "Standard text too large" },
354     { 63, "Not owner of standard text list" },
355     { 64, "Address list full" },
356     { 65, "GAdC invalid" },
357     { 66, "Operation restricted to mobile subscribers" },
358     { 68, "Invalid AdC type" },
359     { 69, "Cannot add AdC to GAdC address list" },
360     { 90, "(proprietary error code)" },
361     { 91, "(proprietary error code)" },
362     { 92, "(proprietary error code)" },
363     { 93, "(proprietary error code)" },
364     { 94, "(proprietary error code)" },
365     { 95, "(proprietary error code)" },
366     { 96, "(proprietary error code)" },
367     { 97, "(proprietary error code)" },
368     { 98, "(proprietary error code)" },
369     { 99, "(proprietary error code)" },
370     {  0, NULL },
371 };
372
373 static const value_string vals_parm_NRq[] = {
374     {  '0', "NAdC not used" },
375     {  '1', "NAdC used" },
376     {  0, NULL },
377 };
378
379 static const value_string vals_parm_NT[] = {
380     {  '0', "Default value" },
381     {  '1', "Delivery notification" },
382     {  '2', "Non-delivery notification" },
383     {  '3', "Delivery and Non-delivery notification" },
384     {  '4', "Buffered message notification" },
385     {  '5', "Buffered and Delivery notification" },
386     {  '6', "Buffered and Non-delivery notification" },
387     {  '7', "All notifications" },
388     {  0, NULL },
389 };
390
391 static const value_string vals_parm_PID[] = {
392     {  100, "Mobile station" },
393     {  122, "Fax Group 3" },
394     {  131, "X.400" },
395     {  138, "Menu over PSTN" },
396     {  139, "PC appl. over PSTN (E.164)" },
397     {  339, "PC appl. over X.25 (X.121)" },
398     {  439, "PC appl. over ISDN (E.164)" },
399     {  539, "PC appl. over TCP/IP" },
400     {  0, NULL },
401 };
402
403 static const value_string vals_parm_LRq[] = {
404     {  '0', "LRAd not used" },
405     {  '1', "LRAd used" },
406     {  0, NULL },
407 };
408
409 static const value_string vals_parm_DD[] = {
410     {  '0', "DDT not used" },
411     {  '1', "DDT used" },
412     {  0, NULL },
413 };
414
415 static const value_string vals_parm_Dst[] = {
416     {  '0', "delivered" },
417     {  '1', "buffered (see Rsn)" },
418     {  '2', "not delivered (see Rsn)" },
419     {  0, NULL },
420 };
421
422 static const value_string vals_parm_Rsn[] = {
423     {    0, "Unknown subscriber" },
424     {    1, "Service temporary not available" },
425     {    2, "Service temporary not available" },
426     {    3, "Service temporary not available" },
427     {    4, "Service temporary not available" },
428     {    5, "Service temporary not available" },
429     {    6, "Service temporary not available" },
430     {    7, "Service temporary not available" },
431     {    8, "Service temporary not available" },
432     {    9, "Illegal error code" },
433     {   10, "Network time-out" },
434     {  100, "Facility not supported" },
435     {  101, "Unknown subscriber" },
436     {  102, "Facility not provided" },
437     {  103, "Call barred" },
438     {  104, "Operation barred" },
439     {  105, "SC congestion" },
440     {  106, "Facility not supported" },
441     {  107, "Absent subscriber" },
442     {  108, "Delivery fail" },
443     {  109, "Sc congestion" },
444     {  110, "Protocol error" },
445     {  111, "MS not equipped" },
446     {  112, "Unknown SC" },
447     {  113, "SC congestion" },
448     {  114, "Illegal MS" },
449     {  115, "MS nota subscriber" },
450     {  116, "Error in MS" },
451     {  117, "SMS lower layer not provisioned" },
452     {  118, "System fail" },
453     {  119, "PLMN system failure" },
454     {  120, "HLR system failure" },
455     {  121, "VLR system failure" },
456     {  122, "Previous VLR system failure" },
457     {  123, "Controlling MSC system failure" },
458     {  124, "VMSC system failure" },
459     {  125, "EIR system failure" },
460     {  126, "System failure" },
461     {  127, "Unexpected data value" },
462     {  200, "Error in address service centre" },
463     {  201, "Invalid absolute validity period" },
464     {  202, "Short message exceeds maximum" },
465     {  203, "Unable to unpack GSM message" },
466     {  204, "Unable to convert to IRA alphabet" },
467     {  205, "Invalid validity period format" },
468     {  206, "Invalid destination address" },
469     {  207, "Duplicate message submit" },
470     {  208, "Invalid message type indicator" },
471     {  0, NULL },
472 };
473
474 static const value_string vals_parm_MT[] = {
475     {  '2', "Numeric message" },
476     {  '3', "Alphanumeric message" },
477     {  '4', "Transparent data" },
478     {  0, NULL },
479 };
480
481 static const value_string vals_parm_DCs[] = {
482     {  '0', "default alphabet" },
483     {  '1', "User defined data (8 bit)" },
484     {  0, NULL },
485 };
486
487 static const value_string vals_parm_MCLs[] = {
488     {  '0', "message class 0" },
489     {  '1', "message class 1" },
490     {  '2', "message class 2" },
491     {  '3', "message class 3" },
492     {  0, NULL },
493 };
494
495 static const value_string vals_parm_RPI[] = {
496     {  '1', "Request" },
497     {  '2', "Response" },
498     {  0, NULL },
499 };
500
501 static const value_string vals_parm_ACK[] = {
502     {  'A', "Ack" },
503     {  'N', "Nack" },
504     {  0, NULL },
505 };
506
507 static const value_string vals_parm_RP[] = {
508     {  '1', "Repetition requested" },
509     {  0, NULL },
510 };
511
512 static const value_string vals_parm_UM[] = {
513     {  '1', "Urgent message" },
514     {  0, NULL },
515 };
516
517 static const value_string vals_parm_RC[] = {
518     {  '1', "Reverse charging request" },
519     {  0, NULL },
520 };
521
522 static const value_string vals_parm_OTON[] = {
523     {  '1', "International number" },
524     {  '2', "National number" },
525     {  '6', "Abbreviated number (short number alias)" },
526     {  0, NULL },
527 };
528
529 static const value_string vals_parm_ONPI[] = {
530     {  '1', "E.164 address" },
531     {  '3', "X.121 address" },
532     {  '5', "Private -TCP/IP or abbreviated number- address" },
533     {  0, NULL },
534 };
535
536 static const value_string vals_parm_STYP0[] = {
537     {  '1', "open session" },
538     {  '2', "reserved" },
539     {  '3', "change password" },
540     {  '4', "open provisioning session" },
541     {  '5', "reserved" },
542     {  '6', "change provisioning password" },
543     {  0, NULL },
544 };
545
546 static const value_string vals_parm_STYP1[] = {
547     {  '1', "add item to mo-list" },
548     {  '2', "remove item from mo-list" },
549     {  '3', "verify item mo-list" },
550     {  '4', "add item to mt-list" },
551     {  '5', "remove item from mt-list" },
552     {  '6', "verify item mt-list" },
553     {  0, NULL },
554 };
555
556 static const value_string vals_parm_OPID[] = {
557     {  0, "Mobile station" },
558     {  39, "PC application" },
559     {  0, NULL },
560 };
561
562 static const value_string vals_parm_BAS[] = {
563     {  '1', "Barred" },
564     {  0, NULL },
565 };
566
567 static const value_string vals_parm_LAR[] = {
568     {  '1', "Leg. code for all calls requested" },
569     {  0, NULL },
570 };
571
572 static const value_string vals_parm_L1R[] = {
573     {  '1', "Leg. code for priority 1 requested" },
574     {  0, NULL },
575 };
576
577 static const value_string vals_parm_L3R[] = {
578     {  '1', "Leg. code for priority 3 requested" },
579     {  0, NULL },
580 };
581
582 static const value_string vals_parm_LCR[] = {
583     {  '1', "Leg. code for reverse charging requested" },
584     {  0, NULL },
585 };
586
587 static const value_string vals_parm_LUR[] = {
588     {  '1', "Leg. code for urgent message requested" },
589     {  0, NULL },
590 };
591
592 static const value_string vals_parm_LRR[] = {
593     {  '1', "Leg. code for repetition requested" },
594     {  0, NULL },
595 };
596
597 static const value_string vals_parm_RT[] = {
598     {  '1', "Tone only" },
599     {  '2', "Numeric" },
600     {  '3', "Alphanumeric" },
601     {  '4', "Transparent data" },
602     {  0, NULL },
603 };
604
605 static const value_string vals_parm_PNC[] = {
606     {  'H', "Home PNC" },
607     {  'I', "Input PNC" },
608     {  0, NULL },
609 };
610
611 static const value_string vals_parm_A_D[] = {
612     {  'A', "Add" },
613     {  'D', "Delete" },
614     {  0, NULL },
615 };
616
617 static const value_string vals_parm_R_T[] = {
618     {  'R', "Retrieval Ok" },
619     {  'T', "Retransmit on radio channel" },
620     {  0, NULL },
621 };
622
623 static const value_string vals_parm_REQ_OT[] = {
624     {  'S', "Send used operation types" },
625     {  'N', "Don't send used operation types" },
626     {  0, NULL },
627 };
628
629 static const value_string vals_parm_SSTAT[] = {
630     {  '0', "All services" },
631     {  '1', "All in the moment active services" },
632     {  '2', "Call diversion" },
633     {  '3', "Roaming information status" },
634     {  '4', "Call barring status" },
635     {  '5', "Deferred delivery status" },
636     {  '6', "Number of stored messages" },
637     {  0, NULL },
638 };
639
640 static const value_string vals_xser_service[] = {
641     {  1, "GSM UDH information" },
642     {  2, "GSM DCS information" },
643     {  3, "[Message Type]            TDMA information exchange" },
644     {  4, "[Message Reference]       TDMA information exchange" },
645     {  5, "[Privacy Indicator]       TDMA information exchange" },
646     {  6, "[Urgency Indicator]       TDMA information exchange" },
647     {  7, "[Acknowledgement Request] TDMA information exchange" },
648     {  8, "[Message Updating]        TDMA information exchange" },
649     {  9, "[Call Back Number]        TDMA information exchange" },
650     { 10, "[Response Code]           TDMA information exchange" },
651     { 11, "[Teleservice ID]          TDMA information exchange" },
652     { 12, "Billing identifier" },
653     { 13, "Single shot indicator" },
654     {  0, NULL },
655 };
656
657 /* For statistics */
658 static void
659 ucp_stats_tree_init(stats_tree* st)
660 {
661     st_ucp_messages = stats_tree_create_node(st, st_str_ucp, 0, TRUE);
662     st_ucp_ops = stats_tree_create_node(st, st_str_ops, st_ucp_messages, TRUE);
663     st_ucp_res = stats_tree_create_node(st, st_str_res, st_ucp_messages, TRUE);
664     st_ucp_results = stats_tree_create_node(st, st_str_ucp_res, 0, TRUE);
665     st_ucp_results_pos = stats_tree_create_node(st, st_str_pos, st_ucp_results, TRUE);
666     st_ucp_results_neg = stats_tree_create_node(st, st_str_neg, st_ucp_results, TRUE);
667 }
668
669 static int
670 ucp_stats_tree_per_packet(stats_tree *st, /* st as it was passed to us */
671                                       packet_info *pinfo _U_,
672                                       epan_dissect_t *edt _U_,
673                                       const void *p) /* Used for getting UCP stats */
674 {
675     ucp_tap_rec_t* tap_rec = (ucp_tap_rec_t*)p;
676
677     tick_stat_node(st, st_str_ucp, 0, TRUE);
678
679     if (tap_rec->message_type == 0) /* Operation */
680     {
681         tick_stat_node(st, st_str_ops, st_ucp_messages, TRUE);
682         tick_stat_node(st, val_to_str(tap_rec->operation, vals_hdr_OT,
683                        "Unknown OT: %d"), st_ucp_ops, FALSE);
684     }
685     else /* Result */
686     {
687         tick_stat_node(st, st_str_res, st_ucp_messages, TRUE);
688         tick_stat_node(st, val_to_str(tap_rec->operation, vals_hdr_OT,
689                        "Unknown OT: %d"), st_ucp_res, FALSE);
690
691         tick_stat_node(st, st_str_ucp_res, 0, TRUE);
692
693         if (tap_rec->result == 0) /* Positive Result */
694         {
695             tick_stat_node(st, st_str_pos, st_ucp_results, FALSE);
696         }
697         else /* Negative Result */
698         {
699             tick_stat_node(st, st_str_neg, st_ucp_results, TRUE);
700             tick_stat_node(st, val_to_str(tap_rec->result, vals_parm_EC,
701                            "Unknown EC: %d"), st_ucp_results_neg, FALSE);
702         }
703     }
704
705     return 1;
706 }
707
708 /*!
709  * Checks whether the PDU looks a bit like UCP and checks the checksum
710  *
711  * Note: check_ucp is called only with a buffer of at least LEN+2 bytes.
712  *       IOW: The buffer should contain a complete UCP PDU [STX ... ETX]
713  *
714  * \param       tvb     The buffer with PDU-data
715  * \param       endpkt  Returns pointer, indicating the end of the PDU
716  *
717  * \return              The state of this PDU
718  * \retval      0               Definitely UCP
719  * \retval      UCP_MALFORMED   ???
720  * \retval      UCP_INV_CHK     Nice packet, but checksum doesn't add up...
721  */
722 static int
723 check_ucp(tvbuff_t *tvb, int *endpkt)
724 {
725     guint        offset = 1;
726     guint        checksum = 0;
727     int          pkt_check, tmp;
728     int          length;
729
730     length = tvb_find_guint8(tvb, offset, -1, UCP_ETX);
731     if (length == -1) {
732         *endpkt = tvb_reported_length_remaining(tvb, offset);
733         return UCP_MALFORMED;
734     }
735     for (; offset < (guint) (length - 2); offset++)
736         checksum += tvb_get_guint8(tvb, offset);
737     checksum &= 0xFF;
738     tmp = tvb_get_guint8(tvb, offset++);
739     pkt_check = AHex2Bin(tmp);
740     tmp = tvb_get_guint8(tvb, offset++);
741     pkt_check = 16 * pkt_check + AHex2Bin(tmp);
742     *endpkt = offset + 1;
743     if (checksum == (guint) pkt_check)
744         return 0;
745     else
746         return UCP_INV_CHK;
747 }
748
749 /*!
750  * UCP equivalent of mktime() (3). Convert date to standard 'time_t' format
751  *
752  * \param       datestr The UCP-formatted date to convert
753  *
754  * \return              The date in standard 'time_t' format.
755  */
756 static time_t
757 ucp_mktime(char *datestr)
758 {
759     struct tm    r_time;
760
761     r_time.tm_mday = (10 * (datestr[0] - '0') + (datestr[1] - '0'));
762     r_time.tm_mon  = (10 * (datestr[2] - '0') + (datestr[3] - '0')) - 1;
763     r_time.tm_year = (10 * (datestr[4] - '0') + (datestr[5] - '0'));
764     if (r_time.tm_year < 90)
765         r_time.tm_year += 100;
766     r_time.tm_hour = (10 * (datestr[6] - '0') + (datestr[7] - '0'));
767     r_time.tm_min  = (10 * (datestr[8] - '0') + (datestr[9] - '0'));
768     if (datestr[10])
769         r_time.tm_sec  = (10 * (datestr[10] - '0') + (datestr[11] - '0'));
770     else
771         r_time.tm_sec  = 0;
772     r_time.tm_isdst = -1;
773     return mktime(&r_time);
774 }
775
776 /*!
777  * Scanning routines to add standard types (byte, int, string, data)
778  * to the protocol-tree. Each field is seperated with a slash ('/').
779  *
780  * \param       tree    The protocol tree to add to
781  * \param       tvb     Buffer containing the data
782  * \param       field   The actual field, whose value needs displaying
783  * \param       offset  Location of field within the buffer, returns location
784  *                      of next field.
785  *
786  * \return              For 'int'-types, the value of the field.
787  */
788 static void
789 ucp_handle_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
790 {
791     gint         idx, len;
792
793     idx = tvb_find_guint8(tvb, *offset, -1, '/');
794     if (idx == -1) {
795         /* Force the appropriate exception to be thrown. */
796         len = tvb_length_remaining(tvb, *offset);
797         tvb_ensure_bytes_exist(tvb, *offset, len + 1);
798     } else
799         len = idx - *offset;
800     if (len > 0)
801         proto_tree_add_item(tree, field, tvb, *offset, len, FALSE);
802     *offset += len;
803     if (idx != -1)
804         *offset += 1;   /* skip terminating '/' */
805 }
806
807 static void
808 ucp_handle_IRAstring(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
809 {
810     char         strval[BUFSIZ + 1],
811                 *p_dst = strval;
812     guint8       byte;
813     int          idx = 0;
814     int          tmpoff = *offset;
815
816     while (((byte = tvb_get_guint8(tvb, tmpoff++)) != '/') &&
817            (idx < BUFSIZ))
818     {
819         if (byte >= '0' && byte <= '9')
820         {
821             *p_dst = (byte - '0') * 16;
822         }
823         else
824         {
825             *p_dst = (byte - 'A' + 10) * 16;
826         }
827         if ((byte = tvb_get_guint8(tvb, tmpoff++)) == '/')
828         {
829             break;
830         }
831         if (byte >= '0' && byte <= '9')
832         {
833             *p_dst++ += byte - '0';
834         }
835         else
836         {
837             *p_dst++ += byte - 'A' + 10;
838         }
839         idx++;
840     }
841     strval[idx] = '\0';
842     if (idx == BUFSIZ)
843     {
844         /*
845          * Data clipped, eat rest of field
846          */
847         while ((tvb_get_guint8(tvb, tmpoff++)) != '/')
848             ;
849     }
850     if ((tmpoff - *offset) > 1)
851         proto_tree_add_string(tree, field, tvb, *offset,
852                               tmpoff - *offset - 1, strval);
853     *offset = tmpoff;
854 }
855
856 static guint
857 ucp_handle_byte(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
858 {
859     guint        intval = 0;
860
861     if ((intval = tvb_get_guint8(tvb, (*offset)++)) != '/') {
862         proto_tree_add_uint(tree, field, tvb, *offset - 1, 1, intval);
863         (*offset)++;
864     }
865     return intval;
866 }
867
868 static guint
869 ucp_handle_int(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
870 {
871     gint         idx, len;
872     char         *strval;
873     guint        intval = 0;
874
875     idx = tvb_find_guint8(tvb, *offset, -1, '/');
876     if (idx == -1) {
877         /* Force the appropriate exception to be thrown. */
878         len = tvb_length_remaining(tvb, *offset);
879         tvb_ensure_bytes_exist(tvb, *offset, len + 1);
880     } else
881         len = idx - *offset;
882     strval = (gchar*)tvb_get_ephemeral_string(tvb, *offset, len);
883     if (len > 0) {
884         intval = atoi(strval);
885         proto_tree_add_uint(tree, field, tvb, *offset, len, intval);
886     }
887     *offset += len;
888     if (idx != -1)
889         *offset += 1;   /* skip terminating '/' */
890     return intval;
891 }
892
893 static void
894 ucp_handle_time(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
895 {
896     gint         idx, len;
897     char         *strval;
898     time_t       tval;
899     nstime_t     tmptime;
900
901     idx = tvb_find_guint8(tvb, *offset, -1, '/');
902     if (idx == -1) {
903         /* Force the appropriate exception to be thrown. */
904         len = tvb_length_remaining(tvb, *offset);
905         tvb_ensure_bytes_exist(tvb, *offset, len + 1);
906     } else
907         len = idx - *offset;
908     strval = (gchar*)tvb_get_ephemeral_string(tvb, *offset, len);
909     if (len > 0) {
910         tval = ucp_mktime(strval);
911         tmptime.secs  = tval;
912         tmptime.nsecs = 0;
913         proto_tree_add_time(tree, field, tvb, *offset, len, &tmptime);
914     }
915     *offset += len;
916     if (idx != -1)
917         *offset += 1;   /* skip terminating '/' */
918 }
919
920 static void
921 ucp_handle_data(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
922 {
923     int          tmpoff = *offset;
924
925     while (tvb_get_guint8(tvb, tmpoff++) != '/')
926         ;
927     if ((tmpoff - *offset) > 1)
928         proto_tree_add_item(tree, field, tvb, *offset,
929                             tmpoff - *offset - 1, FALSE);
930     *offset = tmpoff;
931 }
932
933 /*!
934  * Handle the data-field within the UCP-message, according the Message Type
935  *      - 1     Tone only
936  *      - 2     Numeric message
937  *      - 3     Alphanumeric message
938  *      - 4     Transparent (binary) data
939  *      - 5     Standard text handling
940  *      - 6     Alphanumeric message in specified character set
941  *
942  * \param       tree    The protocol tree to add to
943  * \param       tvb     Buffer containing the data
944  * \param       field   The actual field, whose value needs displaying
945  * \param       offset  Location of field within the buffer, returns location
946  *                      of next field.
947  */
948 static void
949 ucp_handle_mt(proto_tree *tree, tvbuff_t *tvb, int *offset)
950 {
951     guint                intval;
952
953     intval = ucp_handle_byte(tree, tvb, hf_ucp_parm_MT, offset);
954     switch (intval) {
955         case '1':                               /* Tone only, no data   */
956             break;
957         case '4':                               /* TMsg, no of bits     */
958             ucp_handle_string(tree, tvb, hf_ucp_parm_NB, offset);
959             /* fall through here for the data piece     */
960         case '2':
961             ucp_handle_data(tree, tvb, hf_ucp_data_section, offset);
962             break;
963         case '3':
964             ucp_handle_IRAstring(tree, tvb, hf_ucp_parm_AMsg, offset);
965             break;
966         case '5':
967             ucp_handle_byte(tree, tvb, hf_ucp_parm_PNC, offset);
968             ucp_handle_string(tree, tvb, hf_ucp_parm_LNo, offset);
969             ucp_handle_string(tree, tvb, hf_ucp_parm_LST, offset);
970             ucp_handle_string(tree, tvb, hf_ucp_parm_TNo, offset);
971             break;
972         case '6':
973             ucp_handle_data(tree, tvb, hf_ucp_data_section, offset);
974             ucp_handle_int(tree, tvb, hf_ucp_parm_CS, offset);
975             break;
976         default:
977             break;              /* No data so ? */
978     }
979 }
980
981 /*!
982  * Handle the data within the 'Extended services' field. Each field having the
983  * format TTLLDD..., TT being the type of service, LL giving the length of the
984  * field, DD... containing the actual data
985  *
986  * \param       tree    The protocol tree to add to
987  * \param       tvb     Buffer containing the extended services data
988  */
989 static void
990 ucp_handle_XSer(proto_tree *tree, tvbuff_t *tvb)
991 {
992     int          offset = 0;
993     guint        intval;
994     int          service;
995     int          len;
996
997     while ((intval = tvb_get_guint8(tvb, offset)) != '/') {
998         service = AHex2Bin(intval);
999         intval = tvb_get_guint8(tvb, offset+1);
1000         service = service * 16 + AHex2Bin(intval);
1001         intval = tvb_get_guint8(tvb, offset+2);
1002         len = AHex2Bin(intval);
1003         intval = tvb_get_guint8(tvb, offset+3);
1004         len = len * 16 + AHex2Bin(intval);
1005         proto_tree_add_uint(tree, hf_xser_service, tvb, offset,   2, service);
1006         proto_tree_add_uint(tree, hf_xser_length,  tvb, offset+2, 2, len);
1007         proto_tree_add_item(tree, hf_xser_data,    tvb, offset+4, len*2, ENC_ASCII|ENC_NA);
1008         offset += 4 + (2 * len);
1009     }
1010 }
1011
1012 /* Next definitions are just a convenient shorthand to make the coding a
1013  * bit more readable instead of summing up all these parameters.
1014  */
1015 #define UcpHandleString(field)  ucp_handle_string(tree, tvb, (field), &offset)
1016
1017 #define UcpHandleIRAString(field) \
1018                         ucp_handle_IRAstring(tree, tvb, (field), &offset)
1019
1020 #define UcpHandleByte(field)    ucp_handle_byte(tree, tvb, (field), &offset)
1021
1022 #define UcpHandleInt(field)     ucp_handle_int(tree, tvb, (field), &offset)
1023
1024 #define UcpHandleTime(field)    ucp_handle_time(tree, tvb, (field), &offset)
1025
1026 #define UcpHandleData(field)    ucp_handle_data(tree, tvb, (field), &offset)
1027
1028 /*!
1029  * The next set of routines handle the different operation types,
1030  * associated with UCP.
1031  */
1032 static void
1033 add_00O(proto_tree *tree, tvbuff_t *tvb)
1034 {                                               /* Enquiry      */
1035     int          offset = 1;
1036
1037     UcpHandleString(hf_ucp_parm_AdC);
1038     UcpHandleString(hf_ucp_parm_OAdC);
1039     UcpHandleString(hf_ucp_parm_OAC);
1040 }
1041
1042 static void
1043 add_00R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1044 {
1045     int          offset = 1;
1046     guint        intval;
1047
1048     intval = UcpHandleByte(hf_ucp_parm_ACK);
1049     if (intval == 'A')
1050     {
1051         UcpHandleByte(hf_ucp_parm_BAS);
1052         UcpHandleByte(hf_ucp_parm_LAR);
1053         UcpHandleByte(hf_ucp_parm_L1R);
1054         UcpHandleByte(hf_ucp_parm_L3R);
1055         UcpHandleByte(hf_ucp_parm_LCR);
1056         UcpHandleByte(hf_ucp_parm_LUR);
1057         UcpHandleByte(hf_ucp_parm_LRR);
1058         UcpHandleByte(hf_ucp_parm_RT);
1059         UcpHandleInt(hf_ucp_parm_NoN);
1060         UcpHandleInt(hf_ucp_parm_NoA);
1061         UcpHandleInt(hf_ucp_parm_NoB);
1062
1063         tap_rec->result = 0;
1064     } else {
1065         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1066         UcpHandleString(hf_ucp_parm_SM);
1067     }
1068 }
1069
1070 static void
1071 add_01O(proto_tree *tree, tvbuff_t *tvb)
1072 {                                               /* Call input   */
1073     int          offset = 1;
1074
1075     UcpHandleString(hf_ucp_parm_AdC);
1076     UcpHandleString(hf_ucp_parm_OAdC);
1077     UcpHandleString(hf_ucp_parm_OAC);
1078     ucp_handle_mt(tree, tvb, &offset);
1079 }
1080
1081 static void
1082 add_01R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1083 {
1084     int          offset = 1;
1085     guint        intval;
1086
1087     intval = UcpHandleByte(hf_ucp_parm_ACK);
1088     if (intval == 'N')
1089         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1090     else
1091         tap_rec->result = 0;
1092     UcpHandleString(hf_ucp_parm_SM);
1093 }
1094
1095 static void
1096 add_02O(proto_tree *tree, tvbuff_t *tvb)
1097 {                                               /* Multiple address call input*/
1098     int          offset = 1;
1099     guint        intval;
1100     guint        idx;
1101
1102     intval = UcpHandleInt(hf_ucp_parm_NPL);
1103     for (idx = 0; idx < intval; idx++)
1104         UcpHandleString(hf_ucp_parm_AdC);
1105
1106     UcpHandleString(hf_ucp_parm_OAdC);
1107     UcpHandleString(hf_ucp_parm_OAC);
1108     ucp_handle_mt(tree, tvb, &offset);
1109 }
1110
1111 #define add_02R(a, b, c) add_01R(a, b, c)
1112
1113 static void
1114 add_03O(proto_tree *tree, tvbuff_t *tvb)
1115 {                                               /* Call input with SS   */
1116     int          offset = 1;
1117     guint        intval;
1118     guint        idx;
1119
1120     UcpHandleString(hf_ucp_parm_AdC);
1121     UcpHandleString(hf_ucp_parm_OAdC);
1122     UcpHandleString(hf_ucp_parm_OAC);
1123     intval = UcpHandleInt(hf_ucp_parm_NPL);
1124     for (idx = 0; idx < intval; idx++)
1125         UcpHandleString(hf_ucp_parm_GA);
1126
1127     UcpHandleByte(hf_ucp_parm_RP);
1128     UcpHandleString(hf_ucp_parm_LRP);
1129     UcpHandleByte(hf_ucp_parm_PR);
1130     UcpHandleString(hf_ucp_parm_LPR);
1131     UcpHandleByte(hf_ucp_parm_UM);
1132     UcpHandleString(hf_ucp_parm_LUM);
1133     UcpHandleByte(hf_ucp_parm_RC);
1134     UcpHandleString(hf_ucp_parm_LRC);
1135     UcpHandleByte(hf_ucp_parm_DD);
1136     UcpHandleTime(hf_ucp_parm_DDT);    /* DDMMYYHHmm */
1137     ucp_handle_mt(tree, tvb, &offset);
1138 }
1139
1140 #define add_03R(a, b, c) add_01R(a, b, c)
1141
1142 static void
1143 add_04O(proto_tree *tree, tvbuff_t *tvb)
1144 {                                               /* Address list information */
1145     int          offset = 1;
1146
1147     UcpHandleString(hf_ucp_parm_GAdC);
1148     UcpHandleString(hf_ucp_parm_AC);
1149     UcpHandleString(hf_ucp_parm_OAdC);
1150     UcpHandleString(hf_ucp_parm_OAC);
1151 }
1152
1153 static void
1154 add_04R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1155 {
1156     int          offset = 1;
1157     guint        intval;
1158     guint        idx;
1159
1160     intval = UcpHandleByte(hf_ucp_parm_ACK);
1161     if (intval == 'A') {
1162         intval = UcpHandleInt(hf_ucp_parm_NPL);
1163         for (idx = 0; idx < intval; idx++)
1164             UcpHandleString(hf_ucp_parm_AdC);
1165         UcpHandleString(hf_ucp_parm_GAdC);
1166         tap_rec->result = 0;
1167     } else
1168         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1169     UcpHandleString(hf_ucp_parm_SM);
1170 }
1171
1172 static void
1173 add_05O(proto_tree *tree, tvbuff_t *tvb)
1174 {                                               /* Change address list */
1175     int          offset = 1;
1176     guint        intval;
1177     guint        idx;
1178
1179     UcpHandleString(hf_ucp_parm_GAdC);
1180     UcpHandleString(hf_ucp_parm_AC);
1181     UcpHandleString(hf_ucp_parm_OAdC);
1182     UcpHandleString(hf_ucp_parm_OAC);
1183     intval = UcpHandleInt(hf_ucp_parm_NPL);
1184     for (idx = 0; idx < intval; idx++)
1185         UcpHandleString(hf_ucp_parm_AdC);
1186     UcpHandleByte(hf_ucp_parm_A_D);
1187 }
1188
1189 #define add_05R(a, b, c) add_01R(a, b, c)
1190
1191 static void
1192 add_06O(proto_tree *tree, tvbuff_t *tvb)
1193 {                                               /* Advice of accum. charges */
1194     int          offset = 1;
1195
1196     UcpHandleString(hf_ucp_parm_AdC);
1197     UcpHandleString(hf_ucp_parm_AC);
1198 }
1199
1200 static void
1201 add_06R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1202 {
1203     int          offset = 1;
1204     guint        intval;
1205
1206     intval = UcpHandleByte(hf_ucp_parm_ACK);
1207     if (intval == 'A') {
1208         UcpHandleTime(hf_ucp_parm_CT);
1209         UcpHandleString(hf_ucp_parm_AAC);
1210         tap_rec->result = 0;
1211     } else
1212         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1213     UcpHandleString(hf_ucp_parm_SM);
1214 }
1215
1216 static void
1217 add_07O(proto_tree *tree, tvbuff_t *tvb)
1218 {                                               /* Password management  */
1219     int          offset = 1;
1220
1221     UcpHandleString(hf_ucp_parm_AdC);
1222     UcpHandleString(hf_ucp_parm_AC);
1223     UcpHandleString(hf_ucp_parm_NAC);
1224 }
1225
1226 #define add_07R(a, b, c) add_01R(a, b, c)
1227
1228 static void
1229 add_08O(proto_tree *tree, tvbuff_t *tvb)
1230 {                                               /* Leg. code management */
1231     int          offset = 1;
1232
1233     UcpHandleString(hf_ucp_parm_AdC);
1234     UcpHandleString(hf_ucp_parm_AC);
1235     UcpHandleString(hf_ucp_parm_LAC);
1236     UcpHandleString(hf_ucp_parm_L1P);
1237     UcpHandleString(hf_ucp_parm_L3P);
1238     UcpHandleString(hf_ucp_parm_LRC);
1239     UcpHandleString(hf_ucp_parm_LUM);
1240     UcpHandleString(hf_ucp_parm_LRP);
1241     UcpHandleString(hf_ucp_parm_LST);
1242 }
1243
1244 #define add_08R(a, b, c) add_01R(a, b, c)
1245
1246 static void
1247 add_09O(proto_tree *tree, tvbuff_t *tvb)
1248 {                                               /* Standard text information */
1249     int          offset = 1;
1250
1251     UcpHandleString(hf_ucp_parm_LNo);
1252     UcpHandleString(hf_ucp_parm_LST);
1253 }
1254
1255 static void
1256 add_09R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1257 {
1258     int          offset = 1;
1259     guint        intval;
1260     guint        idx;
1261
1262     intval = UcpHandleByte(hf_ucp_parm_ACK);
1263     if (intval == 'A') {
1264         intval = UcpHandleInt(hf_ucp_parm_NPL);
1265         for (idx = 0; idx < intval; idx++)
1266             UcpHandleString(hf_ucp_parm_LST);
1267         tap_rec->result = 0;
1268     } else
1269         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1270     UcpHandleString(hf_ucp_parm_SM);
1271 }
1272
1273 static void
1274 add_10O(proto_tree *tree, tvbuff_t *tvb)
1275 {                                               /* Change standard text */
1276     int          offset = 1;
1277
1278     UcpHandleString(hf_ucp_parm_AdC);
1279     UcpHandleString(hf_ucp_parm_AC);
1280     UcpHandleString(hf_ucp_parm_LNo);
1281     UcpHandleString(hf_ucp_parm_TNo);
1282     UcpHandleData(hf_ucp_parm_STx);
1283     UcpHandleInt(hf_ucp_parm_CS);
1284 }
1285
1286 #define add_10R(a, b, c) add_01R(a, b, c)
1287
1288 #define add_11O(a, b) add_06O(a, b)             /* Request roaming info */
1289
1290 static void
1291 add_11R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1292 {
1293     int          offset = 1;
1294     guint        intval;
1295     guint        idx;
1296
1297     intval = UcpHandleByte(hf_ucp_parm_ACK);
1298     if (intval == 'A') {
1299         intval = UcpHandleInt(hf_ucp_parm_NPL);
1300         for (idx = 0; idx < intval; idx++)
1301             UcpHandleString(hf_ucp_parm_GA);
1302         tap_rec->result = 0;
1303     } else
1304         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1305     UcpHandleString(hf_ucp_parm_SM);
1306 }
1307
1308 static void
1309 add_12O(proto_tree *tree, tvbuff_t *tvb)
1310 {                                               /* Change roaming       */
1311     int          offset = 1;
1312     guint        intval;
1313     guint        idx;
1314
1315     UcpHandleString(hf_ucp_parm_AdC);
1316     UcpHandleString(hf_ucp_parm_AC);
1317     intval = UcpHandleInt(hf_ucp_parm_NPL);
1318     for (idx = 0; idx < intval; idx++)
1319         UcpHandleString(hf_ucp_parm_GA);
1320 }
1321
1322 #define add_12R(a, b, c) add_01R(a, b, c)
1323
1324 #define add_13O(a, b) add_06O(a, b)             /* Roaming reset        */
1325
1326 #define add_13R(a, b, c) add_01R(a, b, c)
1327
1328 static void
1329 add_14O(proto_tree *tree, tvbuff_t *tvb)
1330 {                                               /* Message retrieval    */
1331     int          offset = 1;
1332
1333     UcpHandleString(hf_ucp_parm_AdC);
1334     UcpHandleString(hf_ucp_parm_AC);
1335     UcpHandleString(hf_ucp_parm_MNo);
1336     UcpHandleByte(hf_ucp_parm_R_T);
1337 }
1338
1339 static void
1340 add_14R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1341 {
1342     int          offset = 1;
1343     guint        intval;
1344     guint        idx;
1345
1346     intval = UcpHandleByte(hf_ucp_parm_ACK);
1347     if (intval == 'A') {
1348         intval = UcpHandleInt(hf_ucp_parm_NPL);
1349         /*
1350          * Spec is unclear here. Is 'SM' part of the Msg:s field or not?
1351          * For now, assume it is part of it...
1352          */
1353         for (idx = 0; idx < intval; idx++)
1354             UcpHandleData(hf_ucp_data_section);
1355         tap_rec->result = 0;
1356     } else {
1357         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1358         UcpHandleString(hf_ucp_parm_SM);
1359     }
1360 }
1361
1362 static void
1363 add_15O(proto_tree *tree, tvbuff_t *tvb)
1364 {                                               /* Request call barring */
1365     int          offset = 1;
1366
1367     UcpHandleString(hf_ucp_parm_AdC);
1368     UcpHandleString(hf_ucp_parm_AC);
1369     UcpHandleTime(hf_ucp_parm_ST);
1370     UcpHandleTime(hf_ucp_parm_SP);
1371 }
1372
1373 #define add_15R(a, b, c) add_01R(a, b, c)
1374
1375 #define add_16O(a, b) add_06O(a, b)             /* Cancel call barring  */
1376
1377 #define add_16R(a, b, c) add_01R(a, b, c)
1378
1379 static void
1380 add_17O(proto_tree *tree, tvbuff_t *tvb)
1381 {                                               /* Request call diversion */
1382     int          offset = 1;
1383
1384     UcpHandleString(hf_ucp_parm_AdC);
1385     UcpHandleString(hf_ucp_parm_AC);
1386     UcpHandleString(hf_ucp_parm_DAdC);
1387     UcpHandleTime(hf_ucp_parm_ST);
1388     UcpHandleTime(hf_ucp_parm_SP);
1389 }
1390
1391 #define add_17R(a, b, c) add_01R(a, b, c)
1392
1393 #define add_18O(a, b) add_06O(a, b)             /* Cancel call diversion */
1394
1395 #define add_18R(a, b, c) add_01R(a, b, c)
1396
1397 static void
1398 add_19O(proto_tree *tree, tvbuff_t *tvb)
1399 {                                               /* Request deferred delivery*/
1400     int          offset = 1;
1401
1402     UcpHandleString(hf_ucp_parm_AdC);
1403     UcpHandleString(hf_ucp_parm_AC);
1404     UcpHandleTime(hf_ucp_parm_ST);
1405     UcpHandleTime(hf_ucp_parm_SP);
1406 }
1407
1408 #define add_19R(a, b, c) add_01R(a, b, c)
1409
1410 #define add_20O(a, b) add_06O(a, b)             /* Cancel deferred delivery */
1411
1412 #define add_20R(a, b, c) add_01R(a, b, c)
1413
1414 #define add_21O(a, b) add_06O(a, b)             /* All features reset   */
1415
1416 #define add_21R(a, b, c) add_01R(a, b, c)
1417
1418 static void
1419 add_22O(proto_tree *tree, tvbuff_t *tvb)
1420 {                                               /* Call input w. add. CS */
1421     int          offset = 1;
1422
1423     UcpHandleString(hf_ucp_parm_AdC);
1424     UcpHandleString(hf_ucp_parm_OAdC);
1425     UcpHandleString(hf_ucp_parm_OAC);
1426     UcpHandleData(hf_ucp_data_section);
1427     UcpHandleInt(hf_ucp_parm_CS);
1428 }
1429
1430 #define add_22R(a, b, c) add_01R(a, b, c)
1431
1432 static void
1433 add_23O(proto_tree *tree, tvbuff_t *tvb)
1434 {                                               /* UCP version status   */
1435     int          offset = 1;
1436
1437     UcpHandleString(hf_ucp_parm_IVR5x);
1438     UcpHandleByte(hf_ucp_parm_REQ_OT);
1439 }
1440
1441 static void
1442 add_23R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1443 {
1444     int          offset = 1;
1445     guint        intval;
1446     guint        idx;
1447
1448     intval = UcpHandleByte(hf_ucp_parm_ACK);
1449     if (intval == 'A') {
1450         UcpHandleByte(hf_ucp_parm_IVR5x);
1451         intval = UcpHandleInt(hf_ucp_parm_NPL);
1452         for (idx = 0; idx < intval; idx++)
1453             UcpHandleInt(hf_ucp_hdr_OT);
1454         tap_rec->result = 0;
1455     } else
1456         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1457     UcpHandleString(hf_ucp_parm_SM);
1458 }
1459
1460 static void
1461 add_24O(proto_tree *tree, tvbuff_t *tvb)
1462 {                                               /* Mobile subs. feature stat*/
1463     int          offset = 1;
1464
1465     UcpHandleString(hf_ucp_parm_AdC);
1466     UcpHandleString(hf_ucp_parm_AC);
1467     UcpHandleByte(hf_ucp_parm_SSTAT);
1468 }
1469
1470 static void
1471 add_24R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1472 {
1473     int          offset = 1;
1474     guint        intval;
1475     guint        idx;
1476
1477     intval = UcpHandleByte(hf_ucp_parm_ACK);
1478     if (intval == 'A') {
1479         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1480             proto_tree_add_text(tree, tvb, offset - 1, 1,
1481                                 "GA roaming definitions");
1482             if (intval == 'N') {
1483                 proto_tree_add_text(tree, tvb, offset -1, 1,
1484                                 "Not subscribed/not allowed");
1485                 offset++;
1486             } else {
1487                 --offset;
1488                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1489                 for (idx = 0; idx < intval; idx++)
1490                     UcpHandleData(hf_ucp_data_section);
1491             }
1492         }
1493         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1494             proto_tree_add_text(tree, tvb, offset - 1, 1,
1495                                 "Call barring definitions");
1496             if (intval == 'N') {
1497                 proto_tree_add_text(tree, tvb, offset -1, 1,
1498                                 "Not subscribed/not allowed");
1499                 offset++;
1500             } else {
1501                 --offset;
1502                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1503                 for (idx = 0; idx < intval; idx++)
1504                     UcpHandleData(hf_ucp_data_section);
1505             }
1506         }
1507         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1508             proto_tree_add_text(tree, tvb, offset - 1, 1,
1509                                 "Deferred delivery definitions");
1510             if (intval == 'N') {
1511                 proto_tree_add_text(tree, tvb, offset -1, 1,
1512                                 "Not subscribed/not allowed");
1513                 offset++;
1514             } else {
1515                 --offset;
1516                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1517                 for (idx = 0; idx < intval; idx++)
1518                     UcpHandleData(hf_ucp_data_section);
1519             }
1520         }
1521         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1522             proto_tree_add_text(tree, tvb, offset - 1, 1,
1523                                 "Diversion definitions");
1524             if (intval == 'N') {
1525                 proto_tree_add_text(tree, tvb, offset -1, 1,
1526                                 "Not subscribed/not allowed");
1527                 offset++;
1528             } else {
1529                 --offset;
1530                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1531                 for (idx = 0; idx < intval; idx++)
1532                     UcpHandleData(hf_ucp_data_section);
1533             }
1534         }
1535         UcpHandleInt(hf_ucp_parm_LMN);
1536         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1537             if (intval == 'N') {
1538                 proto_tree_add_string(tree, hf_ucp_parm_NMESS_str, tvb,
1539                                 offset -1, 1, "Not subscribed/not allowed");
1540                 offset++;
1541             } else {
1542                 --offset;
1543                 intval = UcpHandleInt(hf_ucp_parm_NMESS);
1544             }
1545         }
1546         tap_rec->result = 0;
1547     } else
1548         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1549     UcpHandleString(hf_ucp_parm_SM);
1550 }
1551
1552 static void
1553 add_30O(proto_tree *tree, tvbuff_t *tvb)
1554 {                                               /* SMS message transfer */
1555     int          offset = 1;
1556
1557     UcpHandleString(hf_ucp_parm_AdC);
1558     UcpHandleString(hf_ucp_parm_OAdC);
1559     UcpHandleString(hf_ucp_parm_AC);
1560     UcpHandleByte(hf_ucp_parm_NRq);
1561     UcpHandleString(hf_ucp_parm_NAdC);
1562     UcpHandleInt(hf_ucp_parm_NPID);
1563     UcpHandleByte(hf_ucp_parm_DD);
1564     UcpHandleTime(hf_ucp_parm_DDT);     /* DDMMYYHHmm */
1565     UcpHandleTime(hf_ucp_parm_VP);      /* DDMMYYHHmm */
1566     UcpHandleData(hf_ucp_data_section);
1567 }
1568
1569 static void
1570 add_30R(proto_tree *tree, tvbuff_t *tvb, ucp_tap_rec_t *tap_rec)
1571 {
1572     int          offset = 1;
1573     guint        intval;
1574
1575     intval = UcpHandleByte(hf_ucp_parm_ACK);
1576     if (intval == 'A') {
1577         UcpHandleTime(hf_ucp_parm_MVP); /* DDMMYYHHmm */
1578         tap_rec->result = 0;
1579     } else {
1580         tap_rec->result = UcpHandleInt(hf_ucp_parm_EC);
1581     }
1582     UcpHandleString(hf_ucp_parm_SM);
1583 }
1584
1585 static void
1586 add_31O(proto_tree *tree, tvbuff_t *tvb)
1587 {                                               /* SMT alert            */
1588     int          offset = 1;
1589
1590     UcpHandleString(hf_ucp_parm_AdC);
1591     UcpHandleInt(hf_ucp_parm_PID);
1592 }
1593
1594 #define add_31R(a, b, c) add_01R(a, b, c)
1595
1596 static void
1597 add_5xO(proto_tree *tree, tvbuff_t *tvb)
1598 {                                               /* 50-series operations */
1599     guint        intval;
1600     int          offset = 1;
1601     int          tmpoff;
1602     proto_item  *ti;
1603     tvbuff_t    *tmptvb;
1604
1605     UcpHandleString(hf_ucp_parm_AdC);
1606     UcpHandleString(hf_ucp_parm_OAdC);
1607     UcpHandleString(hf_ucp_parm_AC);
1608     UcpHandleByte(hf_ucp_parm_NRq);
1609     UcpHandleString(hf_ucp_parm_NAdC);
1610     UcpHandleByte(hf_ucp_parm_NT);
1611     UcpHandleInt(hf_ucp_parm_NPID);
1612     UcpHandleByte(hf_ucp_parm_LRq);
1613     UcpHandleString(hf_ucp_parm_LRAd);
1614     UcpHandleInt(hf_ucp_parm_LPID);
1615     UcpHandleByte(hf_ucp_parm_DD);
1616     UcpHandleTime(hf_ucp_parm_DDT);     /* DDMMYYHHmm */
1617     UcpHandleTime(hf_ucp_parm_VP);      /* DDMMYYHHmm */
1618     UcpHandleString(hf_ucp_parm_RPID);
1619     UcpHandleTime(hf_ucp_parm_SCTS);    /* DDMMYYhhmmss */
1620     UcpHandleByte(hf_ucp_parm_Dst);
1621     UcpHandleInt(hf_ucp_parm_Rsn);
1622     UcpHandleTime(hf_ucp_parm_DSCTS);   /* DDMMYYhhmmss */
1623     intval = UcpHandleByte(hf_ucp_parm_MT);
1624     UcpHandleString(hf_ucp_parm_NB);
1625     if (intval != '3')
1626         UcpHandleData(hf_ucp_data_section);
1627     else
1628         UcpHandleIRAString(hf_ucp_parm_AMsg);
1629     UcpHandleByte(hf_ucp_parm_MMS);
1630     UcpHandleByte(hf_ucp_parm_PR);
1631     UcpHandleByte(hf_ucp_parm_DCs);
1632     UcpHandleByte(hf_ucp_parm_MCLs);
1633     UcpHandleByte(hf_ucp_parm_RPI);
1634     if (tvb_get_guint8(tvb, offset++) != '/') {
1635         proto_tree_add_string(tree, hf_ucp_parm_CPg, tvb, offset - 1,1,
1636                               "(reserved for Code Page)");
1637         offset++;
1638     }
1639     if (tvb_get_guint8(tvb, offset++) != '/') {
1640         proto_tree_add_string(tree, hf_ucp_parm_RPLy, tvb, offset - 1,1,
1641                               "(reserved for Reply type)");
1642         offset++;
1643     }
1644     UcpHandleString(hf_ucp_parm_OTOA);
1645     UcpHandleString(hf_ucp_parm_HPLMN);
1646     tmpoff = offset;                            /* Extra services       */
1647     while (tvb_get_guint8(tvb, tmpoff++) != '/')
1648         ;
1649     if ((tmpoff - offset) > 1) {
1650         int      len = tmpoff - offset - 1;
1651         proto_tree *subtree;
1652
1653         ti = proto_tree_add_item(tree, hf_ucp_parm_XSer, tvb, offset, len, ENC_NA);
1654         tmptvb = tvb_new_subset(tvb, offset, len + 1, len + 1);
1655         subtree = proto_item_add_subtree(ti, ett_XSer);
1656         ucp_handle_XSer(subtree, tmptvb);
1657     }
1658     offset = tmpoff;
1659     UcpHandleData(hf_ucp_parm_RES4);
1660     UcpHandleData(hf_ucp_parm_RES5);
1661 }
1662
1663 #define add_5xR(a, b,c ) add_30R(a, b, c)
1664
1665 static void
1666 add_6xO(proto_tree *tree, tvbuff_t *tvb, guint8 OT)
1667 {                                               /* 60-series operations */
1668     int          offset = 1;
1669
1670     UcpHandleString(hf_ucp_parm_OAdC);
1671     UcpHandleByte(hf_ucp_parm_OTON);
1672     UcpHandleByte(hf_ucp_parm_ONPI);
1673     if (OT == 60) {
1674         UcpHandleByte(hf_ucp_parm_STYP0);
1675     } else {
1676         UcpHandleByte(hf_ucp_parm_STYP1);
1677     }
1678     UcpHandleIRAString(hf_ucp_parm_PWD);
1679     UcpHandleIRAString(hf_ucp_parm_NPWD);
1680     UcpHandleString(hf_ucp_parm_VERS);
1681     UcpHandleString(hf_ucp_parm_LAdC);
1682     UcpHandleByte(hf_ucp_parm_LTON);
1683     UcpHandleByte(hf_ucp_parm_LNPI);
1684     UcpHandleInt(hf_ucp_parm_OPID);
1685     UcpHandleData(hf_ucp_parm_RES1);
1686     if (OT == 61) {
1687       UcpHandleData(hf_ucp_parm_RES2);
1688     }
1689 }
1690
1691 #define add_6xR(a, b, c) add_01R(a, b, c)
1692
1693 /*
1694  * End of convenient shorthands
1695  */
1696 #undef UcpHandleString
1697 #undef UcpHandleIRAString
1698 #undef UcpHandleByte
1699 #undef UcpHandleInt
1700 #undef UcpHandleTime
1701 #undef UcpHandleData
1702
1703 /*
1704  * The heuristic dissector
1705  */
1706
1707 static gboolean
1708 dissect_ucp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1709 {
1710     conversation_t *conversation;
1711
1712     /* Heuristic */
1713
1714     if (tvb_length(tvb) < UCP_HEADER_SIZE)
1715         return FALSE;
1716
1717     if ((tvb_get_guint8(tvb, 0)                            != UCP_STX) ||
1718         (tvb_get_guint8(tvb, UCP_TRN_OFFSET + UCP_TRN_LEN) != '/') ||
1719         (tvb_get_guint8(tvb, UCP_LEN_OFFSET + UCP_LEN_LEN) != '/') ||
1720         (tvb_get_guint8(tvb, UCP_O_R_OFFSET + UCP_O_R_LEN) != '/') ||
1721         (tvb_get_guint8(tvb, UCP_OT_OFFSET  + UCP_OT_LEN)  != '/'))
1722         return FALSE;
1723
1724     if (match_strval(tvb_get_guint8(tvb, UCP_O_R_OFFSET), vals_hdr_O_R) == NULL)
1725         return FALSE;
1726
1727     /*
1728      * Ok, looks like a valid packet
1729      */
1730
1731     /* Set up a conversation with attached dissector so dissect_ucp_heur
1732      *  won't be called any more for this TCP connection.
1733      */
1734
1735     conversation = find_or_create_conversation(pinfo);
1736     conversation_set_dissector(conversation, ucp_handle);
1737
1738     dissect_ucp_tcp(tvb, pinfo, tree);
1739
1740     return TRUE;
1741 }
1742
1743 static guint
1744 get_ucp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1745 {
1746     guint        intval=0;
1747     int          i;
1748
1749     offset = offset + 4;
1750     for (i = 0; i < UCP_LEN_LEN; i++) { /* Length       */
1751         intval = 10 * intval +
1752             (tvb_get_guint8(tvb, offset) - '0');
1753         offset++;
1754     }
1755
1756     return intval + 2;
1757 }
1758
1759
1760 static void
1761 dissect_ucp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1762 {
1763     tcp_dissect_pdus(tvb, pinfo, tree, ucp_desegment, UCP_HEADER_SIZE,
1764                      get_ucp_pdu_len, dissect_ucp_common);
1765 }
1766 /*
1767  * The actual dissector
1768  */
1769
1770 /* We get here only with at least LEN+2 bytes in the buffer */
1771
1772 static void
1773 dissect_ucp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1774 {
1775     int          offset = 0;    /* Offset in packet within tvbuff       */
1776     guint8       O_R;           /* Request or response                  */
1777     guint8       OT;            /* Operation type                       */
1778     guint        intval;
1779     int          i;
1780     int          result;
1781     int          endpkt;
1782     ucp_tap_rec_t* tap_rec;     /* Tap record                           */
1783
1784     /* Set up structures needed to add the protocol subtree and manage it */
1785     proto_item  *ti;
1786     proto_item  *sub_ti;
1787     proto_tree  *ucp_tree;
1788     proto_tree  *sub_tree;
1789     tvbuff_t    *tmp_tvb;
1790
1791     /* Make entries in Protocol column */
1792     col_set_str(pinfo->cinfo, COL_PROTOCOL, "UCP");
1793     col_clear(pinfo->cinfo, COL_INFO);
1794
1795     if (tvb_get_guint8(tvb, 0) != UCP_STX){
1796                 proto_tree_add_text(tree, tvb, 0, -1,"UCP_STX missing, this is not a new packet");
1797                 return;
1798         }
1799
1800     /* Get data needed for dissect_ucp_common */
1801     result = check_ucp(tvb, &endpkt);
1802
1803     O_R = tvb_get_guint8(tvb, UCP_O_R_OFFSET);
1804     /*
1805      * So do an atoi() on the operation type
1806      */
1807     OT  = tvb_get_guint8(tvb, UCP_OT_OFFSET) - '0';
1808     OT  = 10 * OT + (tvb_get_guint8(tvb, UCP_OT_OFFSET + 1) - '0');
1809
1810     /* Create Tap record */
1811     tap_rec = ep_alloc0(sizeof(ucp_tap_rec_t));
1812     tap_rec->message_type = (O_R == 'O' ? 0 : 1);
1813     tap_rec->operation = OT;
1814
1815      /* Make entries in  Info column on summary display */
1816     if (check_col(pinfo->cinfo, COL_INFO)) {
1817         col_append_fstr(pinfo->cinfo, COL_INFO, "%s (%s)",
1818                      val_to_str(OT,  vals_hdr_OT,  "unknown operation"),
1819                      val_to_str(O_R, vals_hdr_O_R, "Unknown (%d)"));
1820         if (result == UCP_INV_CHK)
1821             col_append_str(pinfo->cinfo, COL_INFO, " [checksum invalid]");
1822     }
1823
1824     /* In the interest of speed, if "tree" is NULL, don't do any work not
1825        necessary to generate protocol tree items. */
1826     if (tree) {
1827
1828         /* create display subtree for the protocol */
1829         ti = proto_tree_add_item(tree, proto_ucp, tvb, 0, -1, FALSE);
1830
1831         ucp_tree = proto_item_add_subtree(ti, ett_ucp);
1832         /*
1833          * Process the packet here.
1834          * Transaction number
1835          */
1836         offset++;                               /* Skip <stx>   */
1837         intval = tvb_get_guint8(tvb, offset+0) - '0';
1838         intval = 10 * intval + (tvb_get_guint8(tvb, offset+1) - '0');
1839         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_TRN, tvb, offset,
1840                             UCP_TRN_LEN, intval);
1841         offset += UCP_TRN_LEN + 1;              /* Skip TN/     */
1842
1843         intval = 0;
1844         for (i = 0; i < UCP_LEN_LEN; i++) {     /* Length       */
1845             intval = 10 * intval +
1846                         (tvb_get_guint8(tvb, offset+i) - '0');
1847         }
1848         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_LEN, tvb, offset,
1849                             UCP_LEN_LEN, intval);
1850         offset += UCP_LEN_LEN + 1;              /* skip LEN/    */
1851
1852         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_O_R, tvb, offset,
1853                             UCP_O_R_LEN, O_R);
1854
1855         offset += UCP_O_R_LEN + 1;              /* skip Operation_type/ */
1856
1857         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_OT, tvb, offset,
1858                             UCP_OT_LEN, OT);
1859         offset += UCP_OT_LEN;
1860
1861         /*
1862          * Variable part starts here.
1863          */
1864
1865         tmp_tvb = tvb_new_subset_remaining(tvb, offset);
1866         sub_ti = proto_tree_add_item(ucp_tree, hf_ucp_oper_section, tvb,
1867                                      offset, endpkt - offset, ENC_NA);
1868         sub_tree = proto_item_add_subtree(sub_ti, ett_sub);
1869
1870         switch (OT) {
1871             case  0:
1872                 O_R == 'O' ? add_00O(sub_tree,tmp_tvb) : add_00R(sub_tree,tmp_tvb, tap_rec);
1873                 break;
1874             case  1:
1875                 O_R == 'O' ? add_01O(sub_tree,tmp_tvb) : add_01R(sub_tree,tmp_tvb, tap_rec);
1876                 break;
1877             case  2:
1878                 O_R == 'O' ? add_02O(sub_tree,tmp_tvb) : add_02R(sub_tree,tmp_tvb, tap_rec);
1879                 break;
1880             case  3:
1881                 O_R == 'O' ? add_03O(sub_tree,tmp_tvb) : add_03R(sub_tree,tmp_tvb, tap_rec);
1882                 break;
1883             case  4:
1884                 O_R == 'O' ? add_04O(sub_tree,tmp_tvb) : add_04R(sub_tree,tmp_tvb, tap_rec);
1885                 break;
1886             case  5:
1887                 O_R == 'O' ? add_05O(sub_tree,tmp_tvb) : add_05R(sub_tree,tmp_tvb, tap_rec);
1888                 break;
1889             case  6:
1890                 O_R == 'O' ? add_06O(sub_tree,tmp_tvb) : add_06R(sub_tree,tmp_tvb, tap_rec);
1891                 break;
1892             case  7:
1893                 O_R == 'O' ? add_07O(sub_tree,tmp_tvb) : add_07R(sub_tree,tmp_tvb, tap_rec);
1894                 break;
1895             case  8:
1896                 O_R == 'O' ? add_08O(sub_tree,tmp_tvb) : add_08R(sub_tree,tmp_tvb, tap_rec);
1897                 break;
1898             case  9:
1899                 O_R == 'O' ? add_09O(sub_tree,tmp_tvb) : add_09R(sub_tree,tmp_tvb, tap_rec);
1900                 break;
1901             case 10:
1902                 O_R == 'O' ? add_10O(sub_tree,tmp_tvb) : add_10R(sub_tree,tmp_tvb, tap_rec);
1903                 break;
1904             case 11:
1905                 O_R == 'O' ? add_11O(sub_tree,tmp_tvb) : add_11R(sub_tree,tmp_tvb, tap_rec);
1906                 break;
1907             case 12:
1908                 O_R == 'O' ? add_12O(sub_tree,tmp_tvb) : add_12R(sub_tree,tmp_tvb, tap_rec);
1909                 break;
1910             case 13:
1911                 O_R == 'O' ? add_13O(sub_tree,tmp_tvb) : add_13R(sub_tree,tmp_tvb, tap_rec);
1912                 break;
1913             case 14:
1914                 O_R == 'O' ? add_14O(sub_tree,tmp_tvb) : add_14R(sub_tree,tmp_tvb, tap_rec);
1915                 break;
1916             case 15:
1917                 O_R == 'O' ? add_15O(sub_tree,tmp_tvb) : add_15R(sub_tree,tmp_tvb, tap_rec);
1918                 break;
1919             case 16:
1920                 O_R == 'O' ? add_16O(sub_tree,tmp_tvb) : add_16R(sub_tree,tmp_tvb, tap_rec);
1921                 break;
1922             case 17:
1923                 O_R == 'O' ? add_17O(sub_tree,tmp_tvb) : add_17R(sub_tree,tmp_tvb, tap_rec);
1924                 break;
1925             case 18:
1926                 O_R == 'O' ? add_18O(sub_tree,tmp_tvb) : add_18R(sub_tree,tmp_tvb, tap_rec);
1927                 break;
1928             case 19:
1929                 O_R == 'O' ? add_19O(sub_tree,tmp_tvb) : add_19R(sub_tree,tmp_tvb, tap_rec);
1930                 break;
1931             case 20:
1932                 O_R == 'O' ? add_20O(sub_tree,tmp_tvb) : add_20R(sub_tree,tmp_tvb, tap_rec);
1933                 break;
1934             case 21:
1935                 O_R == 'O' ? add_21O(sub_tree,tmp_tvb) : add_21R(sub_tree,tmp_tvb, tap_rec);
1936                 break;
1937             case 22:
1938                 O_R == 'O' ? add_22O(sub_tree,tmp_tvb) : add_22R(sub_tree,tmp_tvb, tap_rec);
1939                 break;
1940             case 23:
1941                 O_R == 'O' ? add_23O(sub_tree,tmp_tvb) : add_23R(sub_tree,tmp_tvb, tap_rec);
1942                 break;
1943             case 24:
1944                 O_R == 'O' ? add_24O(sub_tree,tmp_tvb) : add_24R(sub_tree,tmp_tvb, tap_rec);
1945                 break;
1946             case 30:
1947                 O_R == 'O' ? add_30O(sub_tree,tmp_tvb) : add_30R(sub_tree,tmp_tvb, tap_rec);
1948                 break;
1949             case 31:
1950                 O_R == 'O' ? add_31O(sub_tree,tmp_tvb) : add_31R(sub_tree,tmp_tvb, tap_rec);
1951                 break;
1952             case 51: case 52: case 53: case 54: case 55: case 56: case 57:
1953             case 58:
1954                 O_R == 'O' ? add_5xO(sub_tree,tmp_tvb) : add_5xR(sub_tree,tmp_tvb, tap_rec);
1955                 break;
1956             case 60: case 61:
1957                 O_R == 'O' ? add_6xO(sub_tree,tmp_tvb,OT) : add_6xR(sub_tree,tmp_tvb, tap_rec);
1958                 break;
1959             default:
1960                 break;
1961         }
1962     }
1963
1964     /* Queue packet for Tap */
1965     tap_queue_packet(ucp_tap, pinfo, tap_rec);
1966
1967     return;
1968 }
1969
1970 /* Register the protocol with Wireshark */
1971 void
1972 proto_register_ucp(void)
1973 {
1974
1975     /* Setup list of fields     */
1976     static hf_register_info hf[] = {
1977         { &hf_ucp_hdr_TRN,
1978             { "Transaction Reference Number", "ucp.hdr.TRN",
1979               FT_UINT8, BASE_DEC, NULL, 0x00,
1980               "Transaction number for this command, used in windowing.",
1981               HFILL
1982             }
1983         },
1984         { &hf_ucp_hdr_LEN,
1985             { "Length", "ucp.hdr.LEN",
1986               FT_UINT16, BASE_DEC, NULL, 0x00,
1987               "Total number of characters between <stx>...<etx>.",
1988               HFILL
1989             }
1990         },
1991         { &hf_ucp_hdr_O_R,
1992             { "Type", "ucp.hdr.O_R",
1993               FT_UINT8, BASE_DEC, VALS(vals_hdr_O_R), 0x00,
1994               "Your basic 'is a request or response'.",
1995               HFILL
1996             }
1997         },
1998         { &hf_ucp_hdr_OT,
1999             { "Operation", "ucp.hdr.OT",
2000               FT_UINT8, BASE_DEC, VALS(vals_hdr_OT), 0x00,
2001               "The operation that is requested with this message.",
2002               HFILL
2003             }
2004         },
2005         { &hf_ucp_oper_section,
2006             { "Data", "ucp.parm",
2007               FT_NONE, BASE_NONE, NULL, 0x00,
2008               "The actual content of the operation.",
2009               HFILL
2010             }
2011         },
2012         { &hf_ucp_parm_AdC,
2013             { "AdC", "ucp.parm.AdC",
2014               FT_STRING, BASE_NONE, NULL, 0x00,
2015               "Address code recipient.",
2016               HFILL
2017             }
2018         },
2019         { &hf_ucp_parm_OAdC,
2020             { "OAdC", "ucp.parm.OAdC",
2021               FT_STRING, BASE_NONE, NULL, 0x00,
2022               "Address code originator.",
2023               HFILL
2024             }
2025         },
2026         { &hf_ucp_parm_DAdC,
2027             { "DAdC", "ucp.parm.DAdC",
2028               FT_STRING, BASE_NONE, NULL, 0x00,
2029               "Diverted address code.",
2030               HFILL
2031             }
2032         },
2033         { &hf_ucp_parm_AC,
2034             { "AC", "ucp.parm.AC",
2035               FT_STRING, BASE_NONE, NULL, 0x00,
2036               "Authentication code.",
2037               HFILL
2038             }
2039         },
2040         { &hf_ucp_parm_OAC,
2041             { "OAC", "ucp.parm.OAC",
2042               FT_STRING, BASE_NONE, NULL, 0x00,
2043               "Authentication code, originator.",
2044               HFILL
2045             }
2046         },
2047         { &hf_ucp_parm_NAC,
2048             { "NAC", "ucp.parm.NAC",
2049               FT_STRING, BASE_NONE, NULL, 0x00,
2050               "New authentication code.",
2051               HFILL
2052             }
2053         },
2054         { &hf_ucp_parm_BAS,
2055             { "BAS", "ucp.parm.BAS",
2056               FT_UINT8, BASE_DEC, VALS(vals_parm_BAS), 0x00,
2057               "Barring status flag.",
2058               HFILL
2059             }
2060         },
2061         { &hf_ucp_parm_LAR,
2062             { "LAR", "ucp.parm.LAR",
2063               FT_UINT8, BASE_DEC, VALS(vals_parm_LAR), 0x00,
2064               "Leg. code for all calls flag.",
2065               HFILL
2066             }
2067         },
2068         { &hf_ucp_parm_LAC,
2069             { "LAC", "ucp.parm.LAC",
2070               FT_STRING, BASE_NONE, NULL, 0x00,
2071               "New leg. code for all calls.",
2072               HFILL
2073             }
2074         },
2075         { &hf_ucp_parm_L1R,
2076             { "L1R", "ucp.parm.L1R",
2077               FT_UINT8, BASE_DEC, VALS(vals_parm_L1R), 0x00,
2078               "Leg. code for priority 1 flag.",
2079               HFILL
2080             }
2081         },
2082         { &hf_ucp_parm_L1P,
2083             { "L1P", "ucp.parm.L1P",
2084               FT_STRING, BASE_NONE, NULL, 0x00,
2085               "New leg. code for level 1 priority.",
2086               HFILL
2087             }
2088         },
2089         { &hf_ucp_parm_L3R,
2090             { "L3R", "ucp.parm.L3R",
2091               FT_UINT8, BASE_DEC, VALS(vals_parm_L3R), 0x00,
2092               "Leg. code for priority 3 flag.",
2093               HFILL
2094             }
2095         },
2096         { &hf_ucp_parm_L3P,
2097             { "L3P", "ucp.parm.L3P",
2098               FT_STRING, BASE_NONE, NULL, 0x00,
2099               "New leg. code for level 3 priority.",
2100               HFILL
2101             }
2102         },
2103         { &hf_ucp_parm_LCR,
2104             { "LCR", "ucp.parm.LCR",
2105               FT_UINT8, BASE_DEC, VALS(vals_parm_LCR), 0x00,
2106               "Leg. code for reverse charging flag.",
2107               HFILL
2108             }
2109         },
2110         { &hf_ucp_parm_LUR,
2111             { "LUR", "ucp.parm.LUR",
2112               FT_UINT8, BASE_DEC, VALS(vals_parm_LUR), 0x00,
2113               "Leg. code for urgent message flag.",
2114               HFILL
2115             }
2116         },
2117         { &hf_ucp_parm_LRR,
2118             { "LRR", "ucp.parm.LRR",
2119               FT_UINT8, BASE_DEC, VALS(vals_parm_LRR), 0x00,
2120               "Leg. code for repetition flag.",
2121               HFILL
2122             }
2123         },
2124         { &hf_ucp_parm_RT,
2125             { "RT", "ucp.parm.RT",
2126               FT_UINT8, BASE_DEC, VALS(vals_parm_RT), 0x00,
2127               "Receiver type.",
2128               HFILL
2129             }
2130         },
2131         { &hf_ucp_parm_NoN,
2132             { "NoN", "ucp.parm.NoN",
2133               FT_UINT16, BASE_DEC, NULL, 0x00,
2134               "Maximum number of numerical characters accepted.",
2135               HFILL
2136             }
2137         },
2138         { &hf_ucp_parm_NoA,
2139             { "NoA", "ucp.parm.NoA",
2140               FT_UINT16, BASE_DEC, NULL, 0x00,
2141               "Maximum number of alphanumerical characters accepted.",
2142               HFILL
2143             }
2144         },
2145         { &hf_ucp_parm_NoB,
2146             { "NoB", "ucp.parm.NoB",
2147               FT_UINT16, BASE_DEC, NULL, 0x00,
2148               "Maximum number of data bits accepted.",
2149               HFILL
2150             }
2151         },
2152         { &hf_ucp_parm_PNC,
2153             { "PNC", "ucp.parm.PNC",
2154               FT_UINT8, BASE_DEC, VALS(vals_parm_PNC), 0x00,
2155               "Paging network controller.",
2156               HFILL
2157             }
2158         },
2159         { &hf_ucp_parm_AMsg,
2160             { "AMsg", "ucp.parm.AMsg",
2161               FT_STRING, BASE_NONE, NULL, 0x00,
2162               "The alphanumeric message that is being sent.",
2163               HFILL
2164             }
2165         },
2166         { &hf_ucp_parm_LNo,
2167             { "LNo", "ucp.parm.LNo",
2168               FT_STRING, BASE_NONE, NULL, 0x00,
2169               "Standard text list number requested by calling party.",
2170               HFILL
2171             }
2172         },
2173         { &hf_ucp_parm_LST,
2174             { "LST", "ucp.parm.LST",
2175               FT_STRING, BASE_NONE, NULL, 0x00,
2176               "Legitimisation code for standard text.",
2177               HFILL
2178             }
2179         },
2180         { &hf_ucp_parm_TNo,
2181             { "TNo", "ucp.parm.TNo",
2182               FT_STRING, BASE_NONE, NULL, 0x00,
2183               "Standard text number requested by calling party.",
2184               HFILL
2185             }
2186         },
2187         { &hf_ucp_parm_CS,
2188             { "CS", "ucp.parm.CS",
2189               FT_UINT8, BASE_DEC, NULL, 0x00,
2190               "Additional character set number.",
2191               HFILL
2192             }
2193         },
2194         { &hf_ucp_parm_PID,
2195             { "PID", "ucp.parm.PID",
2196               FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
2197               "SMT PID value.",
2198               HFILL
2199             }
2200         },
2201         { &hf_ucp_parm_NPL,
2202             { "NPL", "ucp.parm.NPL",
2203               FT_UINT16, BASE_DEC, NULL, 0x00,
2204               "Number of parameters in the following list.",
2205               HFILL
2206             }
2207         },
2208         { &hf_ucp_parm_GA,
2209             { "GA", "ucp.parm.GA",
2210               FT_STRING, BASE_NONE, NULL, 0x00,
2211               "GA?? haven't got a clue.",
2212               HFILL
2213             }
2214         },
2215         { &hf_ucp_parm_RP,
2216             { "RP", "ucp.parm.RP",
2217               FT_UINT8, BASE_DEC, VALS(vals_parm_RP), 0x00,
2218               "Repetition requested.",
2219               HFILL
2220             }
2221         },
2222         { &hf_ucp_parm_LRP,
2223             { "LRP", "ucp.parm.LRP",
2224               FT_STRING, BASE_NONE, NULL, 0x00,
2225               "Legitimisation code for repetition.",
2226               HFILL
2227             }
2228         },
2229         { &hf_ucp_parm_PR,
2230             { "PR", "ucp.parm.PR",
2231               FT_UINT8, BASE_DEC, NULL, 0x00,
2232               "Priority requested.",
2233               HFILL
2234             }
2235         },
2236         { &hf_ucp_parm_LPR,
2237             { "LPR", "ucp.parm.LPR",
2238               FT_STRING, BASE_NONE, NULL, 0x00,
2239               "Legitimisation code for priority requested.",
2240               HFILL
2241             }
2242         },
2243         { &hf_ucp_parm_UM,
2244             { "UM", "ucp.parm.UM",
2245               FT_UINT8, BASE_DEC, VALS(vals_parm_UM), 0x00,
2246               "Urgent message indicator.",
2247               HFILL
2248             }
2249         },
2250         { &hf_ucp_parm_LUM,
2251             { "LUM", "ucp.parm.LUM",
2252               FT_STRING, BASE_NONE, NULL, 0x00,
2253               "Legitimisation code for urgent message.",
2254               HFILL
2255             }
2256         },
2257         { &hf_ucp_parm_RC,
2258             { "RC", "ucp.parm.RC",
2259               FT_UINT8, BASE_DEC, VALS(vals_parm_RC), 0x00,
2260               "Reverse charging request.",
2261               HFILL
2262             }
2263         },
2264         { &hf_ucp_parm_LRC,
2265             { "LRC", "ucp.parm.LRC",
2266               FT_STRING, BASE_NONE, NULL, 0x00,
2267               "Legitimisation code for reverse charging.",
2268               HFILL
2269             }
2270         },
2271         { &hf_ucp_parm_NRq,
2272             { "NRq", "ucp.parm.NRq",
2273               FT_UINT8, BASE_DEC, VALS(vals_parm_NRq), 0x00,
2274               "Notification request.",
2275               HFILL
2276             }
2277         },
2278         { &hf_ucp_parm_GAdC,
2279             { "GAdC", "ucp.parm.GAdC",
2280               FT_STRING, BASE_NONE, NULL, 0x00,
2281               "Group address code.",
2282               HFILL
2283             }
2284         },
2285         { &hf_ucp_parm_A_D,
2286             { "A_D", "ucp.parm.A_D",
2287               FT_UINT8, BASE_DEC, VALS(vals_parm_A_D), 0x00,
2288               "Add to/delete from fixed subscriber address list record.",
2289               HFILL
2290             }
2291         },
2292         { &hf_ucp_parm_CT,
2293             { "CT", "ucp.parm.CT",
2294               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2295               "Accumulated charges timestamp.",
2296               HFILL
2297             }
2298         },
2299         { &hf_ucp_parm_AAC,
2300             { "AAC", "ucp.parm.AAC",
2301               FT_STRING, BASE_NONE, NULL, 0x00,
2302               "Accumulated charges.",
2303               HFILL
2304             }
2305         },
2306         { &hf_ucp_parm_MNo,
2307             { "MNo", "ucp.parm.MNo",
2308               FT_STRING, BASE_NONE, NULL, 0x00,
2309               "Message number.",
2310               HFILL
2311             }
2312         },
2313         { &hf_ucp_parm_R_T,
2314             { "R_T", "ucp.parm.R_T",
2315               FT_UINT8, BASE_DEC, VALS(vals_parm_R_T), 0x00,
2316               "Message number.",
2317               HFILL
2318             }
2319         },
2320         { &hf_ucp_parm_NAdC,
2321             { "NAdC", "ucp.parm.NAdC",
2322               FT_STRING, BASE_NONE, NULL, 0x00,
2323               "Notification address.",
2324               HFILL
2325             }
2326         },
2327         { &hf_ucp_parm_NT,
2328             { "NT", "ucp.parm.NT",
2329               FT_UINT8, BASE_DEC, VALS(vals_parm_NT), 0x00,
2330               "Notification type.",
2331               HFILL
2332             }
2333         },
2334         { &hf_ucp_parm_IVR5x,
2335             { "IVR5x", "ucp.parm.IVR5x",
2336               FT_STRING, BASE_NONE, NULL, 0x00,
2337               "UCP release number supported/accepted.",
2338               HFILL
2339             }
2340         },
2341         { &hf_ucp_parm_REQ_OT,
2342             { "REQ_OT", "ucp.parm.REQ_OT",
2343               FT_UINT8, BASE_DEC, VALS(vals_parm_REQ_OT), 0x00,
2344               "UCP release number supported/accepted.",
2345               HFILL
2346             }
2347         },
2348         { &hf_ucp_parm_SSTAT,
2349             { "SSTAT", "ucp.parm.SSTAT",
2350               FT_UINT8, BASE_DEC, VALS(vals_parm_SSTAT), 0x00,
2351               "Supplementary services for which status is requested.",
2352               HFILL
2353             }
2354         },
2355         { &hf_ucp_parm_LMN,
2356             { "LMN", "ucp.parm.LMN",
2357               FT_UINT8, BASE_DEC, NULL, 0x00,
2358               "Last message number.",
2359               HFILL
2360             }
2361         },
2362         { &hf_ucp_parm_NMESS,
2363             { "NMESS", "ucp.parm.NMESS",
2364               FT_UINT8, BASE_DEC, NULL, 0x00,
2365               "Number of stored messages.",
2366               HFILL
2367             }
2368         },
2369         { &hf_ucp_parm_NMESS_str,
2370             { "NMESS_str", "ucp.parm.NMESS_str",
2371               FT_STRING, BASE_NONE, NULL, 0x00,
2372               "Number of stored messages.",
2373               HFILL
2374             }
2375         },
2376         { &hf_ucp_parm_NPID,
2377             { "NPID", "ucp.parm.NPID",
2378               FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
2379               "Notification PID value.",
2380               HFILL
2381             }
2382         },
2383         { &hf_ucp_parm_LRq,
2384             { "LRq", "ucp.parm.LRq",
2385               FT_UINT8, BASE_DEC, VALS(vals_parm_LRq), 0x00,
2386               "Last resort address request.",
2387               HFILL
2388             }
2389         },
2390         { &hf_ucp_parm_LRAd,
2391             { "LRAd", "ucp.parm.LRAd",
2392               FT_STRING, BASE_NONE, NULL, 0x00,
2393               "Last resort address.",
2394               HFILL
2395             }
2396         },
2397         { &hf_ucp_parm_LPID,
2398             { "LPID", "ucp.parm.LPID",
2399               FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
2400               "Last resort PID value.",
2401               HFILL
2402             }
2403         },
2404         { &hf_ucp_parm_DD,
2405             { "DD", "ucp.parm.DD",
2406               FT_UINT8, BASE_DEC, VALS(vals_parm_DD), 0x00,
2407               "Deferred delivery requested.",
2408               HFILL
2409             }
2410         },
2411         { &hf_ucp_parm_DDT,
2412             { "DDT", "ucp.parm.DDT",
2413               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2414               "Deferred delivery time.",
2415               HFILL
2416             }
2417         },
2418         { &hf_ucp_parm_STx,
2419             { "STx", "ucp.parm.STx",
2420               FT_NONE, BASE_NONE, NULL, 0x00,
2421               "Standard text.",
2422               HFILL
2423             }
2424         },
2425         { &hf_ucp_parm_ST,
2426             { "ST", "ucp.parm.ST",
2427               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2428               "Start time.",
2429               HFILL
2430             }
2431         },
2432         { &hf_ucp_parm_SP,
2433             { "SP", "ucp.parm.SP",
2434               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2435               "Stop time.",
2436               HFILL
2437             }
2438         },
2439         { &hf_ucp_parm_VP,
2440             { "VP", "ucp.parm.VP",
2441               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2442               "Validity period.",
2443               HFILL
2444             }
2445         },
2446         { &hf_ucp_parm_RPID,
2447             { "RPID", "ucp.parm.RPID",
2448               FT_STRING, BASE_NONE, NULL, 0x00,
2449               "Replace PID",
2450               HFILL
2451             }
2452         },
2453         { &hf_ucp_parm_SCTS,
2454             { "SCTS", "ucp.parm.SCTS",
2455               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2456               "Service Centre timestamp.",
2457               HFILL
2458             }
2459         },
2460         { &hf_ucp_parm_Dst,
2461             { "Dst", "ucp.parm.Dst",
2462               FT_UINT8, BASE_DEC, VALS(vals_parm_Dst), 0x00,
2463               "Delivery status.",
2464               HFILL
2465             }
2466         },
2467         { &hf_ucp_parm_Rsn,
2468             { "Rsn", "ucp.parm.Rsn",
2469               FT_UINT16, BASE_DEC, VALS(vals_parm_Rsn), 0x00,
2470               "Reason code.",
2471               HFILL
2472             }
2473         },
2474         { &hf_ucp_parm_DSCTS,
2475             { "DSCTS", "ucp.parm.DSCTS",
2476               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2477               "Delivery timestamp.",
2478               HFILL
2479             }
2480         },
2481         { &hf_ucp_parm_MT,
2482             { "MT", "ucp.parm.MT",
2483               FT_UINT8, BASE_DEC, VALS(vals_parm_MT), 0x00,
2484               "Message type.",
2485               HFILL
2486             }
2487         },
2488         { &hf_ucp_parm_NB,
2489             { "NB", "ucp.parm.NB",
2490               FT_STRING, BASE_NONE, NULL, 0x00,
2491               "No. of bits in Transparent Data (TD) message.",
2492               HFILL
2493             }
2494         },
2495         { &hf_ucp_data_section,
2496             { "Data", "ucp.message",
2497               FT_NONE, BASE_NONE, NULL, 0x00,
2498               "The actual message or data.",
2499               HFILL
2500             }
2501         },
2502         { &hf_ucp_parm_MMS,
2503             { "MMS", "ucp.parm.MMS",
2504               FT_UINT8, BASE_DEC, NULL, 0x00,
2505               "More messages to send.",
2506               HFILL
2507             }
2508         },
2509         { &hf_ucp_parm_DCs,
2510             { "DCs", "ucp.parm.DCs",
2511               FT_UINT8, BASE_DEC, VALS(vals_parm_DCs), 0x00,
2512               "Data coding scheme (deprecated).",
2513               HFILL
2514             }
2515         },
2516         { &hf_ucp_parm_MCLs,
2517             { "MCLs", "ucp.parm.MCLs",
2518               FT_UINT8, BASE_DEC, VALS(vals_parm_MCLs), 0x00,
2519               "Message class.",
2520               HFILL
2521             }
2522         },
2523         { &hf_ucp_parm_RPI,
2524             { "RPI", "ucp.parm.RPI",
2525               FT_UINT8, BASE_DEC, VALS(vals_parm_RPI), 0x00,
2526               "Reply path.",
2527               HFILL
2528             }
2529         },
2530         { &hf_ucp_parm_CPg,
2531             { "CPg", "ucp.parm.CPg",
2532               FT_STRING, BASE_NONE, NULL, 0x00,
2533               "Reserved for Code Page.",
2534               HFILL
2535             }
2536         },
2537         { &hf_ucp_parm_RPLy,
2538             { "RPLy", "ucp.parm.RPLy",
2539               FT_STRING, BASE_NONE, NULL, 0x00,
2540               "Reserved for Reply type.",
2541               HFILL
2542             }
2543         },
2544         { &hf_ucp_parm_OTOA,
2545             { "OTOA", "ucp.parm.OTOA",
2546               FT_STRING, BASE_NONE, NULL, 0x00,
2547               "Originator Type Of Address.",
2548               HFILL
2549             }
2550         },
2551         { &hf_ucp_parm_HPLMN,
2552             { "HPLMN", "ucp.parm.HPLMN",
2553               FT_STRING, BASE_NONE, NULL, 0x00,
2554               "Home PLMN address.",
2555               HFILL
2556             }
2557         },
2558         { &hf_ucp_parm_XSer,
2559             { "Extra services:", "ucp.parm.XSer",
2560               FT_NONE, BASE_NONE, NULL, 0x00,
2561               "Extra services.",
2562               HFILL
2563             }
2564         },
2565         { &hf_ucp_parm_RES4,
2566             { "RES4", "ucp.parm.RES4",
2567               FT_STRING, BASE_NONE, NULL, 0x00,
2568               "Reserved for future use.",
2569               HFILL
2570             }
2571         },
2572         { &hf_ucp_parm_RES5,
2573             { "RES5", "ucp.parm.RES5",
2574               FT_STRING, BASE_NONE, NULL, 0x00,
2575               "Reserved for future use.",
2576               HFILL
2577             }
2578         },
2579         { &hf_ucp_parm_OTON,
2580             { "OTON", "ucp.parm.OTON",
2581               FT_UINT8, BASE_DEC, VALS(vals_parm_OTON), 0x00,
2582               "Originator type of number.",
2583               HFILL
2584             }
2585         },
2586         { &hf_ucp_parm_ONPI,
2587             { "ONPI", "ucp.parm.ONPI",
2588               FT_UINT8, BASE_DEC, VALS(vals_parm_ONPI), 0x00,
2589               "Originator numbering plan id.",
2590               HFILL
2591             }
2592         },
2593         { &hf_ucp_parm_STYP0,
2594             { "STYP0", "ucp.parm.STYP0",
2595               FT_UINT8, BASE_DEC, VALS(vals_parm_STYP0), 0x00,
2596               "Subtype of operation.",
2597               HFILL
2598             }
2599         },
2600         { &hf_ucp_parm_STYP1,
2601             { "STYP1", "ucp.parm.STYP1",
2602               FT_UINT8, BASE_DEC, VALS(vals_parm_STYP1), 0x00,
2603               "Subtype of operation.",
2604               HFILL
2605             }
2606         },
2607         { &hf_ucp_parm_PWD,
2608             { "PWD", "ucp.parm.PWD",
2609               FT_STRING, BASE_NONE, NULL, 0x00,
2610               "Current password.",
2611               HFILL
2612             }
2613         },
2614         { &hf_ucp_parm_NPWD,
2615             { "NPWD", "ucp.parm.NPWD",
2616               FT_STRING, BASE_NONE, NULL, 0x00,
2617               "New password.",
2618               HFILL
2619             }
2620         },
2621         { &hf_ucp_parm_VERS,
2622             { "VERS", "ucp.parm.VERS",
2623               FT_STRING, BASE_NONE, NULL, 0x00,
2624               "Version number.",
2625               HFILL
2626             }
2627         },
2628         { &hf_ucp_parm_LAdC,
2629             { "LAdC", "ucp.parm.LAdC",
2630               FT_STRING, BASE_NONE, NULL, 0x00,
2631               "Address for VSMSC list operation.",
2632               HFILL
2633             }
2634         },
2635         { &hf_ucp_parm_LTON,
2636             { "LTON", "ucp.parm.LTON",
2637               FT_UINT8, BASE_DEC, NULL, 0x00,
2638               "Type of number list address.",
2639               HFILL
2640             }
2641         },
2642         { &hf_ucp_parm_LNPI,
2643             { "LNPI", "ucp.parm.LNPI",
2644               FT_UINT8, BASE_DEC, NULL, 0x00,
2645               "Numbering plan id. list address.",
2646               HFILL
2647             }
2648         },
2649         { &hf_ucp_parm_OPID,
2650             { "OPID", "ucp.parm.OPID",
2651               FT_UINT8, BASE_DEC, VALS(vals_parm_OPID), 0x00,
2652               "Originator protocol identifier.",
2653               HFILL
2654             }
2655         },
2656         { &hf_ucp_parm_RES1,
2657             { "RES1", "ucp.parm.RES1",
2658               FT_STRING, BASE_NONE, NULL, 0x00,
2659               "Reserved for future use.",
2660               HFILL
2661             }
2662         },
2663         { &hf_ucp_parm_RES2,
2664             { "RES2", "ucp.parm.RES2",
2665               FT_STRING, BASE_NONE, NULL, 0x00,
2666               "Reserved for future use.",
2667               HFILL
2668             }
2669         },
2670         { &hf_ucp_parm_ACK,
2671             { "(N)Ack", "ucp.parm.ACK",
2672               FT_UINT8, BASE_DEC, VALS(vals_parm_ACK), 0x00,
2673               "Positive or negative acknowledge of the operation.",
2674               HFILL
2675             }
2676         },
2677         { &hf_ucp_parm_MVP,
2678             { "MVP", "ucp.parm.MVP",
2679               FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
2680               "Modified validity period.",
2681               HFILL
2682             }
2683         },
2684         { &hf_ucp_parm_EC,
2685             { "Error code", "ucp.parm.EC",
2686               FT_UINT8, BASE_DEC, VALS(vals_parm_EC), 0x00,
2687               "The result of the requested operation.",
2688               HFILL
2689             }
2690         },
2691         { &hf_ucp_parm_SM,
2692             { "SM", "ucp.parm.SM",
2693               FT_STRING, BASE_NONE, NULL, 0x00,
2694               "System message.",
2695               HFILL
2696             }
2697         },
2698         { &hf_xser_service,
2699             { "Type of service", "ucp.xser.service",
2700               FT_UINT8, BASE_HEX, VALS(vals_xser_service), 0x00,
2701               "The type of service specified.",
2702               HFILL
2703             }
2704         },
2705         { &hf_xser_length,
2706             { "Length", "ucp.xser.length",
2707               FT_UINT16, BASE_DEC, NULL, 0x00,
2708               NULL,
2709               HFILL
2710             }
2711         },
2712         { &hf_xser_data,
2713             { "Data", "ucp.xser.data",
2714               FT_STRING, BASE_NONE, NULL, 0x00,
2715               NULL,
2716               HFILL
2717             }
2718         },
2719     };
2720     /* Setup protocol subtree array */
2721     static gint *ett[] = {
2722         &ett_ucp,
2723         &ett_sub,
2724         &ett_XSer
2725     };
2726    module_t *ucp_module;
2727
2728    /* Register the protocol name and description */
2729     proto_ucp = proto_register_protocol("Universal Computer Protocol",
2730                                         "UCP", "ucp");
2731
2732     /* Required function calls to register header fields and subtrees used */
2733     proto_register_field_array(proto_ucp, hf, array_length(hf));
2734     proto_register_subtree_array(ett, array_length(ett));
2735
2736     /* Register for tapping */
2737     ucp_tap = register_tap("ucp");
2738
2739   /* register preferences */
2740     ucp_module = prefs_register_protocol(proto_ucp, NULL);
2741     prefs_register_bool_preference(ucp_module, "desegment_ucp_messages",
2742                            "Reassemble UCP messages spanning multiple TCP segments",
2743                            "Whether the UCP dissector should reassemble messages spanning"
2744                            " multiple TCP segments."
2745                            " To use this option, you must also enable "
2746                            "\"Allow subdissectors to reassemble TCP streams\" in the "
2747                            "TCP protocol settings.",
2748                            &ucp_desegment);
2749
2750 }
2751
2752 void
2753 proto_reg_handoff_ucp(void)
2754 {
2755     /*
2756      * UCP can be spoken on any port so, when not on a specific port, try heuristic
2757      * whenever TCP is spoken.
2758      */
2759     heur_dissector_add("tcp", dissect_ucp_heur, proto_ucp);
2760
2761     /*
2762      * Also register as a dissectoir that can be selected by a TCP port number via "decode as".
2763      */
2764     ucp_handle = create_dissector_handle(dissect_ucp_tcp, proto_ucp);
2765     dissector_add_handle("tcp.port", ucp_handle);
2766
2767     /* Tapping setup */
2768     stats_tree_register_with_group("ucp", "ucp_messages", "_UCP Messages", 0,
2769                         ucp_stats_tree_per_packet, ucp_stats_tree_init,
2770                         NULL, REGISTER_STAT_GROUP_TELEPHONY);
2771 }