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