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