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