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