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