Fix up some warnings.
[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.24 2004/03/23 01:29:45 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         /* XXX - should we have an option to request reassembly? */
633         *endpkt = tvb_reported_length_remaining(tvb, offset);
634         return UCP_SHORTENED;
635     }
636     if (length > (int) tvb_reported_length(tvb)) {
637         /* XXX - "cannot happen" */
638         *endpkt = 0;
639         return UCP_MALFORMED;
640     }
641     for (; offset < (guint) (length - 2); offset++)
642         checksum += tvb_get_guint8(tvb, offset);
643     checksum &= 0xFF;
644     tmp = tvb_get_guint8(tvb, offset++);
645     pkt_check = AHex2Bin(tmp);
646     tmp = tvb_get_guint8(tvb, offset++);
647     pkt_check = 16 * pkt_check + AHex2Bin(tmp);
648     *endpkt = offset + 1;
649     if (checksum == (guint) pkt_check)
650         return 0;
651     else
652         return UCP_INV_CHK;
653 }
654
655 /*!
656  * UCP equivalent of mktime() (3). Convert date to standard 'time_t' format
657  *
658  * \param       datestr The UCP-formatted date to convert
659  *
660  * \return              The date in standard 'time_t' format.
661  */
662 static time_t
663 ucp_mktime(char *datestr)
664 {
665     struct tm    r_time;
666
667     r_time.tm_mday = 10 * (datestr[0] - '0') + (datestr[1] - '0');
668     r_time.tm_mon  = (10 * (datestr[2] - '0') + (datestr[3] - '0')) - 1;
669     r_time.tm_year = 10 * (datestr[4] - '0') + (datestr[5] - '0');
670     if (r_time.tm_year < 90)
671         r_time.tm_year += 100;
672     r_time.tm_hour = 10 * (datestr[6] - '0') + (datestr[7] - '0');
673     r_time.tm_min  = 10 * (datestr[8] - '0') + (datestr[9] - '0');
674     if (datestr[10])
675         r_time.tm_sec  = 10 * (datestr[10] - '0') + (datestr[11] - '0');
676     else
677         r_time.tm_sec  = 0;
678     r_time.tm_isdst = -1;
679     return mktime(&r_time);
680 }
681
682 /*!
683  * Scanning routines to add standard types (byte, int, string, data)
684  * to the protocol-tree. Each field is seperated with a slash ('/').
685  *
686  * \param       tree    The protocol tree to add to
687  * \param       tvb     Buffer containing the data
688  * \param       field   The actual field, whose value needs displaying
689  * \param       offset  Location of field within the buffer, returns location
690  *                      of next field.
691  *
692  * \return              For 'int'-types, the value of the field.
693  */
694 static void
695 ucp_handle_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
696 {
697     gint         idx, len;
698
699     idx = tvb_find_guint8(tvb, *offset, -1, '/');
700     if (idx == -1) {
701         /* Force the appropriate exception to be thrown. */
702         len = tvb_length_remaining(tvb, *offset);
703         tvb_ensure_bytes_exist(tvb, *offset, len + 1);
704     } else
705         len = idx - *offset;
706     if (len > 0)
707         proto_tree_add_item(tree, field, tvb, *offset, len, FALSE);
708     *offset += len;
709     if (idx != -1)
710         *offset += 1;   /* skip terminating '/' */
711 }
712
713 static void
714 ucp_handle_IRAstring(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
715 {
716     char         strval[BUFSIZ + 1],
717                 *p_dst = strval;
718     guint8       byte;
719     int          idx = 0;
720     int          tmpoff = *offset;
721
722     while (((byte = tvb_get_guint8(tvb, tmpoff++)) != '/') &&
723            (idx < BUFSIZ))
724     {
725         if (byte >= '0' && byte <= '9')
726         {
727             *p_dst = (byte - '0') * 16;
728         }
729         else
730         {
731             *p_dst = (byte - 'A' + 10) * 16;
732         }
733         if ((byte = tvb_get_guint8(tvb, tmpoff++)) == '/')
734         {
735             break;
736         }
737         if (byte >= '0' && byte <= '9')
738         {
739             *p_dst++ += byte - '0';
740         }
741         else
742         {
743             *p_dst++ += byte - 'A' + 10;
744         }
745         idx++;
746     }
747     strval[idx] = '\0';
748     if (idx == BUFSIZ)
749     {
750         /*
751          * Data clipped, eat rest of field
752          */
753         while ((tvb_get_guint8(tvb, tmpoff++)) != '/')
754             ;
755     }
756     if ((tmpoff - *offset) > 1)
757         proto_tree_add_string(tree, field, tvb, *offset,
758                               tmpoff - *offset - 1, strval);
759     *offset = tmpoff;
760 }
761
762 static guint
763 ucp_handle_byte(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
764 {
765     guint        intval = 0;
766
767     if ((intval = tvb_get_guint8(tvb, (*offset)++)) != '/') {
768         proto_tree_add_uint(tree, field, tvb, *offset - 1, 1, intval);
769         (*offset)++;
770     }
771     return intval;
772 }
773
774 static guint
775 ucp_handle_int(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
776 {
777     gint         idx, len;
778     char         *strval;
779     guint        intval = 0;
780
781     idx = tvb_find_guint8(tvb, *offset, -1, '/');
782     if (idx == -1) {
783         /* Force the appropriate exception to be thrown. */
784         len = tvb_length_remaining(tvb, *offset);
785         tvb_ensure_bytes_exist(tvb, *offset, len + 1);
786     } else
787         len = idx - *offset;
788     strval = tvb_get_string(tvb, *offset, len);
789     if (len > 0) {
790         intval = atoi(strval);
791         proto_tree_add_uint(tree, field, tvb, *offset, idx, intval);
792     }
793     g_free(strval);
794     *offset += len;
795     if (idx != -1)
796         *offset += 1;   /* skip terminating '/' */
797     return intval;
798 }
799
800 static void
801 ucp_handle_time(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
802 {
803     gint         idx, len;
804     char         *strval;
805     time_t       tval;
806     nstime_t     tmptime;
807
808     idx = tvb_find_guint8(tvb, *offset, -1, '/');
809     if (idx == -1) {
810         /* Force the appropriate exception to be thrown. */
811         len = tvb_length_remaining(tvb, *offset);
812         tvb_ensure_bytes_exist(tvb, *offset, len + 1);
813     } else
814         len = idx - *offset;
815     strval = tvb_get_string(tvb, *offset, len);
816     if (len > 0) {
817         tval = ucp_mktime(strval);
818         tmptime.secs  = tval;
819         tmptime.nsecs = 0;
820         proto_tree_add_time(tree, field, tvb, *offset, idx, &tmptime);
821     }
822     g_free(strval);
823     *offset += len;
824     if (idx != -1)
825         *offset += 1;   /* skip terminating '/' */
826 }
827
828 static void
829 ucp_handle_data(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
830 {
831     int          tmpoff = *offset;
832
833     while (tvb_get_guint8(tvb, tmpoff++) != '/')
834         ;
835     if ((tmpoff - *offset) > 1)
836         proto_tree_add_item(tree, field, tvb, *offset,
837                             tmpoff - *offset - 1, FALSE);
838     *offset = tmpoff;
839 }
840
841 /*!
842  * Handle the data-field within the UCP-message, according the Message Type
843  *      - 1     Tone only
844  *      - 2     Numeric message
845  *      - 3     Alphanumeric message
846  *      - 4     Transparent (binary) data
847  *      - 5     Standard text handling
848  *      - 6     Alphanumeric message in specified character set
849  *
850  * \param       tree    The protocol tree to add to
851  * \param       tvb     Buffer containing the data
852  * \param       field   The actual field, whose value needs displaying
853  * \param       offset  Location of field within the buffer, returns location
854  *                      of next field.
855  */
856 static void
857 ucp_handle_mt(proto_tree *tree, tvbuff_t *tvb, int *offset)
858 {
859     guint                intval;
860
861     intval = ucp_handle_byte(tree, tvb, hf_ucp_parm_MT, offset);
862     switch (intval) {
863         case '1':                               /* Tone only, no data   */
864             break;
865         case '4':                               /* TMsg, no of bits     */
866             ucp_handle_string(tree, tvb, hf_ucp_parm_NB, offset);
867             /* fall through here for the data piece     */
868         case '2':
869             ucp_handle_data(tree, tvb, hf_ucp_data_section, offset);
870             break;
871         case '3':
872             ucp_handle_IRAstring(tree, tvb, hf_ucp_parm_AMsg, offset);
873             break;
874         case '5':
875             ucp_handle_byte(tree, tvb, hf_ucp_parm_PNC, offset);
876             ucp_handle_string(tree, tvb, hf_ucp_parm_LNo, offset);
877             ucp_handle_string(tree, tvb, hf_ucp_parm_LST, offset);
878             ucp_handle_string(tree, tvb, hf_ucp_parm_TNo, offset);
879             break;
880         case '6':
881             ucp_handle_data(tree, tvb, hf_ucp_data_section, offset);
882             ucp_handle_int(tree, tvb, hf_ucp_parm_CS, offset);
883             break;
884         default:
885             break;              /* No data so ? */
886     }
887 }
888
889 /*!
890  * Handle the data within the 'Extended services' field. Each field having the
891  * format TTLLDD..., TT being the type of service, LL giving the length of the
892  * field, DD... containing the actual data
893  *
894  * \param       tree    The protocol tree to add to
895  * \param       tvb     Buffer containing the extended services data
896  */
897 static void
898 ucp_handle_XSer(proto_tree *tree, tvbuff_t *tvb)
899 {
900     int          offset = 0;
901     guint        intval;
902     int          service;
903     int          len;
904
905     while ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
906         service = AHex2Bin(intval);
907         intval = tvb_get_guint8(tvb, offset++);
908         service = service * 16 + AHex2Bin(intval);
909         intval = tvb_get_guint8(tvb, offset++);
910         len = AHex2Bin(intval);
911         intval = tvb_get_guint8(tvb, offset++);
912         len = len * 16 + AHex2Bin(intval);
913         proto_tree_add_uint(tree, hf_xser_service, tvb, offset,
914                             2 * len, service);
915         offset += (2 * len);
916     }
917 }
918
919 /* Next definitions are just a convenient shorthand to make the coding a
920  * bit more readable instead of summing up all these parameters.
921  */
922 #define UcpHandleString(field)  ucp_handle_string(tree, tvb, (field), &offset)
923
924 #define UcpHandleIRAString(field) \
925                         ucp_handle_IRAstring(tree, tvb, (field), &offset)
926
927 #define UcpHandleByte(field)    ucp_handle_byte(tree, tvb, (field), &offset)
928
929 #define UcpHandleInt(field)     ucp_handle_int(tree, tvb, (field), &offset)
930
931 #define UcpHandleTime(field)    ucp_handle_time(tree, tvb, (field), &offset)
932
933 #define UcpHandleData(field)    ucp_handle_data(tree, tvb, (field), &offset)
934
935 /*!
936  * The next set of routines handle the different operation types,
937  * associated with UCP.
938  */
939 static void
940 add_00O(proto_tree *tree, tvbuff_t *tvb)
941 {                                               /* Enquiry      */
942     int          offset = 1;
943
944     UcpHandleString(hf_ucp_parm_AdC);
945     UcpHandleString(hf_ucp_parm_OAdC);
946     UcpHandleString(hf_ucp_parm_OAC);
947 }
948
949 static void
950 add_00R(proto_tree *tree, tvbuff_t *tvb)
951 {
952     int          offset = 1;
953     guint        intval;
954
955     intval = UcpHandleByte(hf_ucp_parm_ACK);
956     if (intval == 'A')
957     {
958         UcpHandleByte(hf_ucp_parm_BAS);
959         UcpHandleByte(hf_ucp_parm_LAR);
960         UcpHandleByte(hf_ucp_parm_L1R);
961         UcpHandleByte(hf_ucp_parm_L3R);
962         UcpHandleByte(hf_ucp_parm_LCR);
963         UcpHandleByte(hf_ucp_parm_LUR);
964         UcpHandleByte(hf_ucp_parm_LRR);
965         UcpHandleByte(hf_ucp_parm_RT);
966         UcpHandleInt(hf_ucp_parm_NoN);
967         UcpHandleInt(hf_ucp_parm_NoA);
968         UcpHandleInt(hf_ucp_parm_NoB);
969     } else {
970         UcpHandleInt(hf_ucp_parm_EC);
971         UcpHandleString(hf_ucp_parm_SM);
972     }
973 }
974
975 static void
976 add_01O(proto_tree *tree, tvbuff_t *tvb)
977 {                                               /* Call input   */
978     int          offset = 1;
979
980     UcpHandleString(hf_ucp_parm_AdC);
981     UcpHandleString(hf_ucp_parm_OAdC);
982     UcpHandleString(hf_ucp_parm_OAC);
983     ucp_handle_mt(tree, tvb, &offset);
984 }
985
986 static void
987 add_01R(proto_tree *tree, tvbuff_t *tvb)
988 {
989     int          offset = 1;
990     guint        intval;
991
992     intval = UcpHandleByte(hf_ucp_parm_ACK);
993     if (intval == 'N')
994         UcpHandleInt(hf_ucp_parm_EC);
995     UcpHandleString(hf_ucp_parm_SM);
996 }
997
998 static void
999 add_02O(proto_tree *tree, tvbuff_t *tvb)
1000 {                                               /* Multiple address call input*/
1001     int          offset = 1;
1002     guint        intval;
1003     guint        idx;
1004
1005     intval = UcpHandleInt(hf_ucp_parm_NPL);
1006     for (idx = 0; idx < intval; idx++)
1007         UcpHandleString(hf_ucp_parm_AdC);
1008
1009     UcpHandleString(hf_ucp_parm_OAdC);
1010     UcpHandleString(hf_ucp_parm_OAC);
1011     ucp_handle_mt(tree, tvb, &offset);
1012 }
1013
1014 #define add_02R(a, b) add_01R(a,b)
1015
1016 static void
1017 add_03O(proto_tree *tree, tvbuff_t *tvb)
1018 {                                               /* Call input with SS   */
1019     int          offset = 1;
1020     guint        intval;
1021     guint        idx;
1022
1023     UcpHandleString(hf_ucp_parm_AdC);
1024     UcpHandleString(hf_ucp_parm_OAdC);
1025     UcpHandleString(hf_ucp_parm_OAC);
1026     intval = UcpHandleInt(hf_ucp_parm_NPL);
1027     for (idx = 0; idx < intval; idx++)
1028         UcpHandleString(hf_ucp_parm_GA);
1029
1030     UcpHandleByte(hf_ucp_parm_RP);
1031     UcpHandleString(hf_ucp_parm_LRP);
1032     UcpHandleByte(hf_ucp_parm_PR);
1033     UcpHandleString(hf_ucp_parm_LPR);
1034     UcpHandleByte(hf_ucp_parm_UM);
1035     UcpHandleString(hf_ucp_parm_LUM);
1036     UcpHandleByte(hf_ucp_parm_RC);
1037     UcpHandleString(hf_ucp_parm_LRC);
1038     UcpHandleByte(hf_ucp_parm_DD);
1039     UcpHandleTime(hf_ucp_parm_DDT);
1040     ucp_handle_mt(tree, tvb, &offset);
1041 }
1042
1043 #define add_03R(a, b) add_01R(a,b)
1044
1045 static void
1046 add_04O(proto_tree *tree, tvbuff_t *tvb)
1047 {                                               /* Address list information */
1048     int          offset = 1;
1049
1050     UcpHandleString(hf_ucp_parm_GAdC);
1051     UcpHandleString(hf_ucp_parm_AC);
1052     UcpHandleString(hf_ucp_parm_OAdC);
1053     UcpHandleString(hf_ucp_parm_OAC);
1054 }
1055
1056 static void
1057 add_04R(proto_tree *tree, tvbuff_t *tvb)
1058 {
1059     int          offset = 1;
1060     guint        intval;
1061     guint        idx;
1062
1063     intval = UcpHandleByte(hf_ucp_parm_ACK);
1064     if (intval == 'A') {
1065         intval = UcpHandleInt(hf_ucp_parm_NPL);
1066         for (idx = 0; idx < intval; idx++)
1067             UcpHandleString(hf_ucp_parm_AdC);
1068         UcpHandleString(hf_ucp_parm_GAdC);
1069     } else
1070         UcpHandleInt(hf_ucp_parm_EC);
1071     UcpHandleString(hf_ucp_parm_SM);
1072 }
1073
1074 static void
1075 add_05O(proto_tree *tree, tvbuff_t *tvb)
1076 {                                               /* Change address list */
1077     int          offset = 1;
1078     guint        intval;
1079     guint        idx;
1080
1081     UcpHandleString(hf_ucp_parm_GAdC);
1082     UcpHandleString(hf_ucp_parm_AC);
1083     UcpHandleString(hf_ucp_parm_OAdC);
1084     UcpHandleString(hf_ucp_parm_OAC);
1085     intval = UcpHandleInt(hf_ucp_parm_NPL);
1086     for (idx = 0; idx < intval; idx++)
1087         UcpHandleString(hf_ucp_parm_AdC);
1088     UcpHandleByte(hf_ucp_parm_A_D);
1089 }
1090
1091 #define add_05R(a, b) add_01R(a, b)
1092
1093 static void
1094 add_06O(proto_tree *tree, tvbuff_t *tvb)
1095 {                                               /* Advice of accum. charges */
1096     int          offset = 1;
1097
1098     UcpHandleString(hf_ucp_parm_AdC);
1099     UcpHandleString(hf_ucp_parm_AC);
1100 }
1101
1102 static void
1103 add_06R(proto_tree *tree, tvbuff_t *tvb)
1104 {
1105     int          offset = 1;
1106     guint        intval;
1107
1108     intval = UcpHandleByte(hf_ucp_parm_ACK);
1109     if (intval == 'A') {
1110         UcpHandleTime(hf_ucp_parm_CT);
1111         UcpHandleString(hf_ucp_parm_AAC);
1112     } else
1113         UcpHandleInt(hf_ucp_parm_EC);
1114     UcpHandleString(hf_ucp_parm_SM);
1115 }
1116
1117 static void
1118 add_07O(proto_tree *tree, tvbuff_t *tvb)
1119 {                                               /* Password management  */
1120     int          offset = 1;
1121
1122     UcpHandleString(hf_ucp_parm_AdC);
1123     UcpHandleString(hf_ucp_parm_AC);
1124     UcpHandleString(hf_ucp_parm_NAC);
1125 }
1126
1127 #define add_07R(a, b) add_01R(a, b)
1128
1129 static void
1130 add_08O(proto_tree *tree, tvbuff_t *tvb)
1131 {                                               /* Leg. code management */
1132     int          offset = 1;
1133
1134     UcpHandleString(hf_ucp_parm_AdC);
1135     UcpHandleString(hf_ucp_parm_AC);
1136     UcpHandleString(hf_ucp_parm_LAC);
1137     UcpHandleString(hf_ucp_parm_L1P);
1138     UcpHandleString(hf_ucp_parm_L3P);
1139     UcpHandleString(hf_ucp_parm_LRC);
1140     UcpHandleString(hf_ucp_parm_LUM);
1141     UcpHandleString(hf_ucp_parm_LRP);
1142     UcpHandleString(hf_ucp_parm_LST);
1143 }
1144
1145 #define add_08R(a, b) add_01R(a, b)
1146
1147 static void
1148 add_09O(proto_tree *tree, tvbuff_t *tvb)
1149 {                                               /* Standard text information */
1150     int          offset = 1;
1151
1152     UcpHandleString(hf_ucp_parm_LNo);
1153     UcpHandleString(hf_ucp_parm_LST);
1154 }
1155
1156 static void
1157 add_09R(proto_tree *tree, tvbuff_t *tvb)
1158 {
1159     int          offset = 1;
1160     guint        intval;
1161     guint        idx;
1162
1163     intval = UcpHandleByte(hf_ucp_parm_ACK);
1164     if (intval == 'A') {
1165         intval = UcpHandleInt(hf_ucp_parm_NPL);
1166         for (idx = 0; idx < intval; idx++)
1167             UcpHandleString(hf_ucp_parm_LST);
1168     } else
1169         UcpHandleInt(hf_ucp_parm_EC);
1170     UcpHandleString(hf_ucp_parm_SM);
1171 }
1172
1173 static void
1174 add_10O(proto_tree *tree, tvbuff_t *tvb)
1175 {                                               /* Change standard text */
1176     int          offset = 1;
1177
1178     UcpHandleString(hf_ucp_parm_AdC);
1179     UcpHandleString(hf_ucp_parm_AC);
1180     UcpHandleString(hf_ucp_parm_LNo);
1181     UcpHandleString(hf_ucp_parm_TNo);
1182     UcpHandleData(hf_ucp_parm_STx);
1183     UcpHandleInt(hf_ucp_parm_CS);
1184 }
1185
1186 #define add_10R(a, b) add_01R(a, b)
1187
1188 #define add_11O(a, b) add_06O(a, b)             /* Request roaming info */
1189
1190 static void
1191 add_11R(proto_tree *tree, tvbuff_t *tvb)
1192 {
1193     int          offset = 1;
1194     guint        intval;
1195     guint        idx;
1196
1197     intval = UcpHandleByte(hf_ucp_parm_ACK);
1198     if (intval == 'A') {
1199         intval = UcpHandleInt(hf_ucp_parm_NPL);
1200         for (idx = 0; idx < intval; idx++)
1201             UcpHandleString(hf_ucp_parm_GA);
1202     } else
1203         UcpHandleInt(hf_ucp_parm_EC);
1204     UcpHandleString(hf_ucp_parm_SM);
1205 }
1206
1207 static void
1208 add_12O(proto_tree *tree, tvbuff_t *tvb)
1209 {                                               /* Change roaming       */
1210     int          offset = 1;
1211     guint        intval;
1212     guint        idx;
1213
1214     UcpHandleString(hf_ucp_parm_AdC);
1215     UcpHandleString(hf_ucp_parm_AC);
1216     intval = UcpHandleInt(hf_ucp_parm_NPL);
1217     for (idx = 0; idx < intval; idx++)
1218         UcpHandleString(hf_ucp_parm_GA);
1219 }
1220
1221 #define add_12R(a, b) add_01R(a, b)
1222
1223 #define add_13O(a, b) add_06O(a, b)             /* Roaming reset        */
1224
1225 #define add_13R(a, b) add_01R(a, b)
1226
1227 static void
1228 add_14O(proto_tree *tree, tvbuff_t *tvb)
1229 {                                               /* Message retrieval    */
1230     int          offset = 1;
1231
1232     UcpHandleString(hf_ucp_parm_AdC);
1233     UcpHandleString(hf_ucp_parm_AC);
1234     UcpHandleString(hf_ucp_parm_MNo);
1235     UcpHandleByte(hf_ucp_parm_R_T);
1236 }
1237
1238 static void
1239 add_14R(proto_tree *tree, tvbuff_t *tvb)
1240 {
1241     int          offset = 1;
1242     guint        intval;
1243     guint        idx;
1244
1245     intval = UcpHandleByte(hf_ucp_parm_ACK);
1246     if (intval == 'A') {
1247         intval = UcpHandleInt(hf_ucp_parm_NPL);
1248         /*
1249          * Spec is unclear here. Is 'SM' part of the Msg:s field or not?
1250          * For now, assume it is part of it...
1251          */
1252         for (idx = 0; idx < intval; idx++)
1253             UcpHandleData(hf_ucp_data_section);
1254     } else {
1255         UcpHandleInt(hf_ucp_parm_EC);
1256         UcpHandleString(hf_ucp_parm_SM);
1257     }
1258 }
1259
1260 static void
1261 add_15O(proto_tree *tree, tvbuff_t *tvb)
1262 {                                               /* Request call barring */
1263     int          offset = 1;
1264
1265     UcpHandleString(hf_ucp_parm_AdC);
1266     UcpHandleString(hf_ucp_parm_AC);
1267     UcpHandleTime(hf_ucp_parm_ST);
1268     UcpHandleTime(hf_ucp_parm_SP);
1269 }
1270
1271 #define add_15R(a, b) add_01R(a, b)
1272
1273 #define add_16O(a, b) add_06O(a, b)             /* Cancel call barring  */
1274
1275 #define add_16R(a, b) add_01R(a, b)
1276
1277 static void
1278 add_17O(proto_tree *tree, tvbuff_t *tvb)
1279 {                                               /* Request call diversion */
1280     int          offset = 1;
1281
1282     UcpHandleString(hf_ucp_parm_AdC);
1283     UcpHandleString(hf_ucp_parm_AC);
1284     UcpHandleString(hf_ucp_parm_DAdC);
1285     UcpHandleTime(hf_ucp_parm_ST);
1286     UcpHandleTime(hf_ucp_parm_SP);
1287 }
1288
1289 #define add_17R(a, b) add_01R(a, b)
1290
1291 #define add_18O(a, b) add_06O(a, b)             /* Cancel call diversion */
1292
1293 #define add_18R(a, b) add_01R(a, b)
1294
1295 static void
1296 add_19O(proto_tree *tree, tvbuff_t *tvb)
1297 {                                               /* Request deferred delivery*/
1298     int          offset = 1;
1299
1300     UcpHandleString(hf_ucp_parm_AdC);
1301     UcpHandleString(hf_ucp_parm_AC);
1302     UcpHandleTime(hf_ucp_parm_ST);
1303     UcpHandleTime(hf_ucp_parm_SP);
1304 }
1305
1306 #define add_19R(a, b) add_01R(a, b)
1307
1308 #define add_20O(a, b) add_06O(a, b)             /* Cancel deferred delivery */
1309
1310 #define add_20R(a, b) add_01R(a, b)
1311
1312 #define add_21O(a, b) add_06O(a, b)             /* All features reset   */
1313
1314 #define add_21R(a, b) add_01R(a, b)
1315
1316 static void
1317 add_22O(proto_tree *tree, tvbuff_t *tvb)
1318 {                                               /* Call input w. add. CS */
1319     int          offset = 1;
1320
1321     UcpHandleString(hf_ucp_parm_AdC);
1322     UcpHandleString(hf_ucp_parm_OAdC);
1323     UcpHandleString(hf_ucp_parm_OAC);
1324     UcpHandleData(hf_ucp_data_section);
1325     UcpHandleInt(hf_ucp_parm_CS);
1326 }
1327
1328 #define add_22R(a, b) add_01R(a, b)
1329
1330 static void
1331 add_23O(proto_tree *tree, tvbuff_t *tvb)
1332 {                                               /* UCP version status   */
1333     int          offset = 1;
1334
1335     UcpHandleString(hf_ucp_parm_IVR5x);
1336     UcpHandleByte(hf_ucp_parm_REQ_OT);
1337 }
1338
1339 static void
1340 add_23R(proto_tree *tree, tvbuff_t *tvb)
1341 {
1342     int          offset = 1;
1343     guint        intval;
1344     guint        idx;
1345
1346     intval = UcpHandleByte(hf_ucp_parm_ACK);
1347     if (intval == 'A') {
1348         UcpHandleByte(hf_ucp_parm_IVR5x);
1349         intval = UcpHandleInt(hf_ucp_parm_NPL);
1350         for (idx = 0; idx < intval; idx++)
1351             UcpHandleInt(hf_ucp_hdr_OT);
1352     } else
1353         UcpHandleInt(hf_ucp_parm_EC);
1354     UcpHandleString(hf_ucp_parm_SM);
1355 }
1356
1357 static void
1358 add_24O(proto_tree *tree, tvbuff_t *tvb)
1359 {                                               /* Mobile subs. feature stat*/
1360     int          offset = 1;
1361
1362     UcpHandleString(hf_ucp_parm_AdC);
1363     UcpHandleString(hf_ucp_parm_AC);
1364     UcpHandleByte(hf_ucp_parm_SSTAT);
1365 }
1366
1367 static void
1368 add_24R(proto_tree *tree, tvbuff_t *tvb)
1369 {
1370     int          offset = 1;
1371     guint        intval;
1372     guint        idx;
1373
1374     intval = UcpHandleByte(hf_ucp_parm_ACK);
1375     if (intval == 'A') {
1376         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1377             proto_tree_add_text(tree, tvb, offset - 1, 1,
1378                                 "GA roaming definitions");
1379             if (intval == 'N') {
1380                 proto_tree_add_text(tree, tvb, offset -1, 1,
1381                                 "Not subscribed/not allowed");
1382                 offset++;
1383             } else {
1384                 --offset;
1385                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1386                 for (idx = 0; idx < intval; idx++)
1387                     UcpHandleData(hf_ucp_data_section);
1388             }
1389         }
1390         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1391             proto_tree_add_text(tree, tvb, offset - 1, 1,
1392                                 "Call barring definitions");
1393             if (intval == 'N') {
1394                 proto_tree_add_text(tree, tvb, offset -1, 1,
1395                                 "Not subscribed/not allowed");
1396                 offset++;
1397             } else {
1398                 --offset;
1399                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1400                 for (idx = 0; idx < intval; idx++)
1401                     UcpHandleData(hf_ucp_data_section);
1402             }
1403         }
1404         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1405             proto_tree_add_text(tree, tvb, offset - 1, 1,
1406                                 "Deferred delivery definitions");
1407             if (intval == 'N') {
1408                 proto_tree_add_text(tree, tvb, offset -1, 1,
1409                                 "Not subscribed/not allowed");
1410                 offset++;
1411             } else {
1412                 --offset;
1413                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1414                 for (idx = 0; idx < intval; idx++)
1415                     UcpHandleData(hf_ucp_data_section);
1416             }
1417         }
1418         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1419             proto_tree_add_text(tree, tvb, offset - 1, 1,
1420                                 "Diversion definitions");
1421             if (intval == 'N') {
1422                 proto_tree_add_text(tree, tvb, offset -1, 1,
1423                                 "Not subscribed/not allowed");
1424                 offset++;
1425             } else {
1426                 --offset;
1427                 intval = UcpHandleInt(hf_ucp_parm_NPL);
1428                 for (idx = 0; idx < intval; idx++)
1429                     UcpHandleData(hf_ucp_data_section);
1430             }
1431         }
1432         UcpHandleInt(hf_ucp_parm_LMN);
1433         if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1434             if (intval == 'N') {
1435                 proto_tree_add_string(tree, hf_ucp_parm_NMESS_str, tvb,
1436                                 offset -1, 1, "Not subscribed/not allowed");
1437                 offset++;
1438             } else {
1439                 --offset;
1440                 intval = UcpHandleInt(hf_ucp_parm_NMESS);
1441             }
1442         }
1443     } else
1444         UcpHandleInt(hf_ucp_parm_EC);
1445     UcpHandleString(hf_ucp_parm_SM);
1446 }
1447
1448 static void
1449 add_30O(proto_tree *tree, tvbuff_t *tvb)
1450 {                                               /* SMS message transfer */
1451     int          offset = 1;
1452
1453     UcpHandleString(hf_ucp_parm_AdC);
1454     UcpHandleString(hf_ucp_parm_OAdC);
1455     UcpHandleString(hf_ucp_parm_AC);
1456     UcpHandleByte(hf_ucp_parm_NRq);
1457     UcpHandleString(hf_ucp_parm_NAdC);
1458     UcpHandleInt(hf_ucp_parm_NPID);
1459     UcpHandleByte(hf_ucp_parm_DD);
1460     UcpHandleTime(hf_ucp_parm_DDT);
1461     UcpHandleTime(hf_ucp_parm_VP);
1462     UcpHandleData(hf_ucp_data_section);
1463 }
1464
1465 static void
1466 add_30R(proto_tree *tree, tvbuff_t *tvb)
1467 {
1468     int          offset = 1;
1469     guint        intval;
1470
1471     intval = UcpHandleByte(hf_ucp_parm_ACK);
1472     if (intval == 'A')
1473         UcpHandleTime(hf_ucp_parm_MVP);
1474     else
1475         UcpHandleInt(hf_ucp_parm_EC);
1476     UcpHandleString(hf_ucp_parm_SM);
1477 }
1478
1479 static void
1480 add_31O(proto_tree *tree, tvbuff_t *tvb)
1481 {                                               /* SMT alert            */
1482     int          offset = 1;
1483
1484     UcpHandleString(hf_ucp_parm_AdC);
1485     UcpHandleInt(hf_ucp_parm_PID);
1486 }
1487
1488 #define add_31R(a, b) add_01R(a, b)
1489
1490 static void
1491 add_5xO(proto_tree *tree, tvbuff_t *tvb)
1492 {                                               /* 50-series operations */
1493     guint        intval;
1494     int          offset = 1;
1495     int          tmpoff;
1496     proto_item  *ti;
1497     tvbuff_t    *tmptvb;
1498
1499     UcpHandleString(hf_ucp_parm_AdC);
1500     UcpHandleString(hf_ucp_parm_OAdC);
1501     UcpHandleString(hf_ucp_parm_AC);
1502     UcpHandleByte(hf_ucp_parm_NRq);
1503     UcpHandleString(hf_ucp_parm_NAdC);
1504     UcpHandleByte(hf_ucp_parm_NT);
1505     UcpHandleInt(hf_ucp_parm_NPID);
1506     UcpHandleByte(hf_ucp_parm_LRq);
1507     UcpHandleString(hf_ucp_parm_LRAd);
1508     UcpHandleInt(hf_ucp_parm_LPID);
1509     UcpHandleByte(hf_ucp_parm_DD);
1510     UcpHandleTime(hf_ucp_parm_DDT);
1511     UcpHandleTime(hf_ucp_parm_VP);
1512     UcpHandleString(hf_ucp_parm_RPID);
1513     UcpHandleTime(hf_ucp_parm_SCTS);
1514     UcpHandleByte(hf_ucp_parm_Dst);
1515     UcpHandleInt(hf_ucp_parm_Rsn);
1516     UcpHandleTime(hf_ucp_parm_DSCTS);
1517     intval = UcpHandleByte(hf_ucp_parm_MT);
1518     UcpHandleString(hf_ucp_parm_NB);
1519     if (intval != '3')
1520         UcpHandleData(hf_ucp_data_section);
1521     else
1522         UcpHandleIRAString(hf_ucp_parm_AMsg);
1523     UcpHandleByte(hf_ucp_parm_MMS);
1524     UcpHandleByte(hf_ucp_parm_PR);
1525     UcpHandleByte(hf_ucp_parm_DCs);
1526     UcpHandleByte(hf_ucp_parm_MCLs);
1527     UcpHandleByte(hf_ucp_parm_RPI);
1528     if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1529         proto_tree_add_string(tree, hf_ucp_parm_CPg, tvb, offset - 1,1,
1530                               "(reserved for Code Page)");
1531         offset++;
1532     }
1533     if ((intval = tvb_get_guint8(tvb, offset++)) != '/') {
1534         proto_tree_add_string(tree, hf_ucp_parm_RPLy, tvb, offset - 1,1,
1535                               "(reserved for Reply type)");
1536         offset++;
1537     }
1538     UcpHandleString(hf_ucp_parm_OTOA);
1539     UcpHandleString(hf_ucp_parm_HPLMN);
1540     tmpoff = offset;                            /* Extra services       */
1541     while (tvb_get_guint8(tvb, tmpoff++) != '/')
1542         ;
1543     if ((tmpoff - offset) > 1) {
1544         int      len = tmpoff - offset - 1;
1545
1546         ti = proto_tree_add_item(tree, hf_ucp_parm_XSer,tvb,offset,len,FALSE);
1547         tmptvb = tvb_new_subset(tvb, offset, len + 1, len + 1);
1548         proto_item_add_subtree(ti, ett_XSer);
1549         ucp_handle_XSer(ti, tmptvb);
1550     }
1551     offset = tmpoff;
1552     UcpHandleData(hf_ucp_parm_RES4);
1553     UcpHandleData(hf_ucp_parm_RES5);
1554 }
1555
1556 #define add_5xR(a, b) add_30R(a, b)
1557
1558 static void
1559 add_6xO(proto_tree *tree, tvbuff_t *tvb, guint8 OT)
1560 {                                               /* 60-series operations */
1561     int          offset = 1;
1562
1563     UcpHandleString(hf_ucp_parm_OAdC);
1564     UcpHandleByte(hf_ucp_parm_OTON);
1565     UcpHandleByte(hf_ucp_parm_ONPI);
1566     if (OT == 60) {
1567         UcpHandleByte(hf_ucp_parm_STYP0);
1568     } else {
1569         UcpHandleByte(hf_ucp_parm_STYP1);
1570     }
1571     UcpHandleIRAString(hf_ucp_parm_PWD);
1572     UcpHandleIRAString(hf_ucp_parm_NPWD);
1573     UcpHandleString(hf_ucp_parm_VERS);
1574     UcpHandleString(hf_ucp_parm_LAdC);
1575     UcpHandleByte(hf_ucp_parm_LTON);
1576     UcpHandleByte(hf_ucp_parm_LNPI);
1577     UcpHandleInt(hf_ucp_parm_OPID);
1578     UcpHandleData(hf_ucp_parm_RES1);
1579     UcpHandleData(hf_ucp_parm_RES2);
1580 }
1581
1582 #define add_6xR(a, b) add_01R(a, b)
1583
1584 /*
1585  * End of convenient shorthands
1586  */
1587 #undef UcpHandleString
1588 #undef UcpHandleIRAString
1589 #undef UcpHandleByte
1590 #undef UcpHandleInt
1591 #undef UcpHandleTime
1592 #undef UcpHandleData
1593
1594 /* Code to actually dissect the packets */
1595 /*
1596  * Overlapping data for these functions
1597  */
1598 static int       result, endpkt;
1599
1600 /*
1601  * The heuristic dissector
1602  */
1603 static gboolean
1604 dissect_ucp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1605 {
1606     guint8       O_R;           /* Request or response                  */
1607
1608     /* This runs atop TCP, so we are guaranteed that there is at least one
1609        byte in the tvbuff. */
1610     if (tvb_get_guint8(tvb, 0) != UCP_STX)
1611         return FALSE;
1612
1613     result = check_ucp(tvb, &endpkt);
1614
1615     if (result == UCP_MALFORMED)
1616         return FALSE;
1617     if (endpkt < UCP_OT_OFFSET + 1)
1618         /*
1619          * Might be shortened packet but don't handle anyway.
1620          */
1621         return FALSE;
1622
1623     /*
1624      * Try getting the operation-type and whether it's a request/response
1625      */
1626     O_R = tvb_get_guint8(tvb, UCP_O_R_OFFSET);
1627     if (match_strval(O_R, vals_hdr_O_R) == NULL)
1628         return FALSE;
1629     /*
1630      * Ok, looks like a valid packet, go dissect.
1631      */
1632     dissect_ucp(tvb, pinfo, tree);
1633     return TRUE;
1634 }
1635
1636 /*
1637  * The actual dissector
1638  */
1639 static void
1640 dissect_ucp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1641 {
1642     int          offset = 0;    /* Offset in packet within tvbuff       */
1643     int          tmpoff;        /* Local offset value (per field)       */
1644     guint8       O_R;           /* Request or response                  */
1645     guint8       OT;            /* Operation type                       */
1646     guint        intval;
1647     int          i;
1648
1649     /* Set up structures needed to add the protocol subtree and manage it */
1650     proto_item  *ti;
1651     proto_item  *sub_ti;
1652     proto_tree  *ucp_tree;
1653     proto_tree  *sub_tree;
1654     tvbuff_t    *tmp_tvb;
1655
1656     O_R = tvb_get_guint8(tvb, UCP_O_R_OFFSET);
1657     /*
1658      * So do an atoi() on the operation type
1659      */
1660     OT  = tvb_get_guint8(tvb, UCP_OT_OFFSET) - '0';
1661     OT  = 10 * OT + (tvb_get_guint8(tvb, UCP_OT_OFFSET + 1) - '0');
1662
1663     /* Make entries in Protocol column and Info column on summary display */
1664     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1665             col_set_str(pinfo->cinfo, COL_PROTOCOL, "UCP");
1666
1667     if (check_col(pinfo->cinfo, COL_INFO)) {
1668         col_clear(pinfo->cinfo, COL_INFO);
1669         col_append_fstr(pinfo->cinfo, COL_INFO, "%s (%s)",
1670                      val_to_str(OT,  vals_hdr_OT,  "unknown operation"),
1671                      match_strval(O_R, vals_hdr_O_R));
1672         if (result == UCP_SHORTENED)
1673             col_append_str(pinfo->cinfo, COL_INFO, " [short packet]");
1674         else if (result == UCP_INV_CHK)
1675             col_append_str(pinfo->cinfo, COL_INFO, " [checksum invalid]");
1676     }
1677
1678     /* In the interest of speed, if "tree" is NULL, don't do any work not
1679        necessary to generate protocol tree items. */
1680     if (tree) {
1681
1682         /* create display subtree for the protocol */
1683         ti = proto_tree_add_item(tree, proto_ucp, tvb, 0, -1, FALSE);
1684
1685         ucp_tree = proto_item_add_subtree(ti, ett_ucp);
1686         /*
1687          * Process the packet here.
1688          * Transaction number
1689          */
1690         offset++;                               /* Skip <stx>   */
1691         tmpoff = offset;
1692         intval = tvb_get_guint8(tvb, tmpoff++) - '0';
1693         intval = 10 * intval + (tvb_get_guint8(tvb, tmpoff++) - '0');
1694         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_TRN, tvb, offset,
1695                             UCP_TRN_LEN, intval);
1696         offset = tmpoff;
1697
1698         offset++;                               /* Skip '/'     */
1699         intval = 0;
1700         tmpoff = offset;
1701         for (i = 0; i < UCP_LEN_LEN; i++) {     /* Length       */
1702             intval = 10 * intval +
1703                         (tvb_get_guint8(tvb, tmpoff++) - '0');
1704         }
1705         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_LEN, tvb, offset,
1706                             UCP_LEN_LEN, intval);
1707         offset = tmpoff;
1708
1709         offset++;                               /* Operation/Response   */
1710         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_O_R, tvb, offset++,
1711                             UCP_O_R_LEN, O_R);
1712
1713         offset++;                               /* Operation type */
1714         proto_tree_add_uint(ucp_tree, hf_ucp_hdr_OT, tvb, offset,
1715                             UCP_OT_LEN, OT);
1716         offset += UCP_OT_LEN;
1717         /*
1718          * Variable part starts here. Don't dissect if not complete.
1719          */
1720         if (result == UCP_SHORTENED)
1721             return;
1722         tmp_tvb = tvb_new_subset(tvb, offset, -1, -1);
1723         sub_ti = proto_tree_add_item(ucp_tree, hf_ucp_oper_section, tvb,
1724                                      offset, endpkt - offset, FALSE);
1725         sub_tree = proto_item_add_subtree(sub_ti, ett_sub);
1726
1727         switch (OT) {
1728             case  0:
1729                 O_R == 'O' ? add_00O(sub_tree,tmp_tvb) : add_00R(sub_tree,tmp_tvb);
1730                 break;
1731             case  1:
1732                 O_R == 'O' ? add_01O(sub_tree,tmp_tvb) : add_01R(sub_tree,tmp_tvb);
1733                 break;
1734             case  2:
1735                 O_R == 'O' ? add_02O(sub_tree,tmp_tvb) : add_02R(sub_tree,tmp_tvb);
1736                 break;
1737             case  3:
1738                 O_R == 'O' ? add_03O(sub_tree,tmp_tvb) : add_03R(sub_tree,tmp_tvb);
1739                 break;
1740             case  4:
1741                 O_R == 'O' ? add_04O(sub_tree,tmp_tvb) : add_04R(sub_tree,tmp_tvb);
1742                 break;
1743             case  5:
1744                 O_R == 'O' ? add_05O(sub_tree,tmp_tvb) : add_05R(sub_tree,tmp_tvb);
1745                 break;
1746             case  6:
1747                 O_R == 'O' ? add_06O(sub_tree,tmp_tvb) : add_06R(sub_tree,tmp_tvb);
1748                 break;
1749             case  7:
1750                 O_R == 'O' ? add_07O(sub_tree,tmp_tvb) : add_07R(sub_tree,tmp_tvb);
1751                 break;
1752             case  8:
1753                 O_R == 'O' ? add_08O(sub_tree,tmp_tvb) : add_08R(sub_tree,tmp_tvb);
1754                 break;
1755             case  9:
1756                 O_R == 'O' ? add_09O(sub_tree,tmp_tvb) : add_09R(sub_tree,tmp_tvb);
1757                 break;
1758             case 10:
1759                 O_R == 'O' ? add_10O(sub_tree,tmp_tvb) : add_10R(sub_tree,tmp_tvb);
1760                 break;
1761             case 11:
1762                 O_R == 'O' ? add_11O(sub_tree,tmp_tvb) : add_11R(sub_tree,tmp_tvb);
1763                 break;
1764             case 12:
1765                 O_R == 'O' ? add_12O(sub_tree,tmp_tvb) : add_12R(sub_tree,tmp_tvb);
1766                 break;
1767             case 13:
1768                 O_R == 'O' ? add_13O(sub_tree,tmp_tvb) : add_13R(sub_tree,tmp_tvb);
1769                 break;
1770             case 14:
1771                 O_R == 'O' ? add_14O(sub_tree,tmp_tvb) : add_14R(sub_tree,tmp_tvb);
1772                 break;
1773             case 15:
1774                 O_R == 'O' ? add_15O(sub_tree,tmp_tvb) : add_15R(sub_tree,tmp_tvb);
1775                 break;
1776             case 16:
1777                 O_R == 'O' ? add_16O(sub_tree,tmp_tvb) : add_16R(sub_tree,tmp_tvb);
1778                 break;
1779             case 17:
1780                 O_R == 'O' ? add_17O(sub_tree,tmp_tvb) : add_17R(sub_tree,tmp_tvb);
1781                 break;
1782             case 18:
1783                 O_R == 'O' ? add_18O(sub_tree,tmp_tvb) : add_18R(sub_tree,tmp_tvb);
1784                 break;
1785             case 19:
1786                 O_R == 'O' ? add_19O(sub_tree,tmp_tvb) : add_19R(sub_tree,tmp_tvb);
1787                 break;
1788             case 20:
1789                 O_R == 'O' ? add_20O(sub_tree,tmp_tvb) : add_20R(sub_tree,tmp_tvb);
1790                 break;
1791             case 21:
1792                 O_R == 'O' ? add_21O(sub_tree,tmp_tvb) : add_21R(sub_tree,tmp_tvb);
1793                 break;
1794             case 22:
1795                 O_R == 'O' ? add_22O(sub_tree,tmp_tvb) : add_22R(sub_tree,tmp_tvb);
1796                 break;
1797             case 23:
1798                 O_R == 'O' ? add_23O(sub_tree,tmp_tvb) : add_23R(sub_tree,tmp_tvb);
1799                 break;
1800             case 24:
1801                 O_R == 'O' ? add_24O(sub_tree,tmp_tvb) : add_24R(sub_tree,tmp_tvb);
1802                 break;
1803             case 30:
1804                 O_R == 'O' ? add_30O(sub_tree,tmp_tvb) : add_30R(sub_tree,tmp_tvb);
1805                 break;
1806             case 31:
1807                 O_R == 'O' ? add_31O(sub_tree,tmp_tvb) : add_31R(sub_tree,tmp_tvb);
1808                 break;
1809             case 51: case 52: case 53: case 54: case 55: case 56: case 57:
1810             case 58:
1811                 O_R == 'O' ? add_5xO(sub_tree,tmp_tvb) : add_5xR(sub_tree,tmp_tvb);
1812                 break;
1813             case 60: case 61:
1814                 O_R == 'O' ? add_6xO(sub_tree,tmp_tvb,OT) : add_6xR(sub_tree,tmp_tvb);
1815                 break;
1816             default:
1817                 break;
1818         }
1819     }
1820     return;
1821 }
1822
1823 /* Register the protocol with Ethereal */
1824 void
1825 proto_register_ucp(void)
1826 {
1827
1828     /* Setup list of fields     */
1829     static hf_register_info hf[] = {
1830         { &hf_ucp_hdr_TRN,
1831             { "Transaction Reference Number", "ucp.hdr.TRN",
1832               FT_UINT8, BASE_DEC, NULL, 0x00,
1833               "Transaction number for this command, used in windowing.",
1834               HFILL
1835             }
1836         },
1837         { &hf_ucp_hdr_LEN,
1838             { "Length", "ucp.hdr.LEN",
1839               FT_UINT16, BASE_DEC, NULL, 0x00,
1840               "Total number of characters between <stx>...<etx>.",
1841               HFILL
1842             }
1843         },
1844         { &hf_ucp_hdr_O_R,
1845             { "Type", "ucp.hdr.O_R",
1846               FT_UINT8, BASE_DEC, VALS(vals_hdr_O_R), 0x00,
1847               "Your basic 'is a request or response'.",
1848               HFILL
1849             }
1850         },
1851         { &hf_ucp_hdr_OT,
1852             { "Operation", "ucp.hdr.OT",
1853               FT_UINT8, BASE_DEC, VALS(vals_hdr_OT), 0x00,
1854               "The operation that is requested with this message.",
1855               HFILL
1856             }
1857         },
1858         { &hf_ucp_oper_section,
1859             { "Data", "ucp.parm",
1860               FT_NONE, BASE_DEC, NULL, 0x00,
1861               "The actual content of the operation.",
1862               HFILL
1863             }
1864         },
1865         { &hf_ucp_parm_AdC,
1866             { "AdC", "ucp.parm.AdC",
1867               FT_STRING, BASE_NONE, NULL, 0x00,
1868               "Address code recipient.",
1869               HFILL
1870             }
1871         },
1872         { &hf_ucp_parm_OAdC,
1873             { "OAdC", "ucp.parm.OAdC",
1874               FT_STRING, BASE_NONE, NULL, 0x00,
1875               "Address code originator.",
1876               HFILL
1877             }
1878         },
1879         { &hf_ucp_parm_DAdC,
1880             { "DAdC", "ucp.parm.DAdC",
1881               FT_STRING, BASE_NONE, NULL, 0x00,
1882               "Diverted address code.",
1883               HFILL
1884             }
1885         },
1886         { &hf_ucp_parm_AC,
1887             { "AC", "ucp.parm.AC",
1888               FT_STRING, BASE_NONE, NULL, 0x00,
1889               "Authentication code.",
1890               HFILL
1891             }
1892         },
1893         { &hf_ucp_parm_OAC,
1894             { "OAC", "ucp.parm.OAC",
1895               FT_STRING, BASE_NONE, NULL, 0x00,
1896               "Authentication code, originator.",
1897               HFILL
1898             }
1899         },
1900         { &hf_ucp_parm_NAC,
1901             { "NAC", "ucp.parm.NAC",
1902               FT_STRING, BASE_NONE, NULL, 0x00,
1903               "New authentication code.",
1904               HFILL
1905             }
1906         },
1907         { &hf_ucp_parm_BAS,
1908             { "BAS", "ucp.parm.BAS",
1909               FT_UINT8, BASE_DEC, VALS(vals_parm_BAS), 0x00,
1910               "Barring status flag.",
1911               HFILL
1912             }
1913         },
1914         { &hf_ucp_parm_LAR,
1915             { "LAR", "ucp.parm.LAR",
1916               FT_UINT8, BASE_DEC, VALS(vals_parm_LAR), 0x00,
1917               "Leg. code for all calls flag.",
1918               HFILL
1919             }
1920         },
1921         { &hf_ucp_parm_LAC,
1922             { "LAC", "ucp.parm.LAC",
1923               FT_STRING, BASE_NONE, NULL, 0x00,
1924               "New leg. code for all calls.",
1925               HFILL
1926             }
1927         },
1928         { &hf_ucp_parm_L1R,
1929             { "L1R", "ucp.parm.L1R",
1930               FT_UINT8, BASE_DEC, VALS(vals_parm_L1R), 0x00,
1931               "Leg. code for priority 1 flag.",
1932               HFILL
1933             }
1934         },
1935         { &hf_ucp_parm_L1P,
1936             { "L1P", "ucp.parm.L1P",
1937               FT_STRING, BASE_NONE, NULL, 0x00,
1938               "New leg. code for level 1 priority.",
1939               HFILL
1940             }
1941         },
1942         { &hf_ucp_parm_L3R,
1943             { "L3R", "ucp.parm.L3R",
1944               FT_UINT8, BASE_DEC, VALS(vals_parm_L3R), 0x00,
1945               "Leg. code for priority 3 flag.",
1946               HFILL
1947             }
1948         },
1949         { &hf_ucp_parm_L3P,
1950             { "L3P", "ucp.parm.L3P",
1951               FT_STRING, BASE_NONE, NULL, 0x00,
1952               "New leg. code for level 3 priority.",
1953               HFILL
1954             }
1955         },
1956         { &hf_ucp_parm_LCR,
1957             { "LCR", "ucp.parm.LCR",
1958               FT_UINT8, BASE_DEC, VALS(vals_parm_LCR), 0x00,
1959               "Leg. code for reverse charging flag.",
1960               HFILL
1961             }
1962         },
1963         { &hf_ucp_parm_LUR,
1964             { "LUR", "ucp.parm.LUR",
1965               FT_UINT8, BASE_DEC, VALS(vals_parm_LUR), 0x00,
1966               "Leg. code for urgent message flag.",
1967               HFILL
1968             }
1969         },
1970         { &hf_ucp_parm_LRR,
1971             { "LRR", "ucp.parm.LRR",
1972               FT_UINT8, BASE_DEC, VALS(vals_parm_LRR), 0x00,
1973               "Leg. code for repitition flag.",
1974               HFILL
1975             }
1976         },
1977         { &hf_ucp_parm_RT,
1978             { "RT", "ucp.parm.RT",
1979               FT_UINT8, BASE_DEC, VALS(vals_parm_RT), 0x00,
1980               "Receiver type.",
1981               HFILL
1982             }
1983         },
1984         { &hf_ucp_parm_NoN,
1985             { "NoN", "ucp.parm.NoN",
1986               FT_UINT16, BASE_DEC, NULL, 0x00,
1987               "Maximum number of numerical characters accepted.",
1988               HFILL
1989             }
1990         },
1991         { &hf_ucp_parm_NoA,
1992             { "NoA", "ucp.parm.NoA",
1993               FT_UINT16, BASE_DEC, NULL, 0x00,
1994               "Maximum number of alphanumerical characters accepted.",
1995               HFILL
1996             }
1997         },
1998         { &hf_ucp_parm_NoB,
1999             { "NoB", "ucp.parm.NoB",
2000               FT_UINT16, BASE_DEC, NULL, 0x00,
2001               "Maximum number of data bits accepted.",
2002               HFILL
2003             }
2004         },
2005         { &hf_ucp_parm_PNC,
2006             { "PNC", "ucp.parm.PNC",
2007               FT_UINT8, BASE_DEC, VALS(vals_parm_PNC), 0x00,
2008               "Paging network controller.",
2009               HFILL
2010             }
2011         },
2012         { &hf_ucp_parm_AMsg,
2013             { "AMsg", "ucp.parm.AMsg",
2014               FT_STRING, BASE_NONE, NULL, 0x00,
2015               "The alphanumeric message that is being sent.",
2016               HFILL
2017             }
2018         },
2019         { &hf_ucp_parm_LNo,
2020             { "LNo", "ucp.parm.LNo",
2021               FT_STRING, BASE_NONE, NULL, 0x00,
2022               "Standard text list number requested by calling party.",
2023               HFILL
2024             }
2025         },
2026         { &hf_ucp_parm_LST,
2027             { "LST", "ucp.parm.LST",
2028               FT_STRING, BASE_NONE, NULL, 0x00,
2029               "Legitimisation code for standard text.",
2030               HFILL
2031             }
2032         },
2033         { &hf_ucp_parm_TNo,
2034             { "TNo", "ucp.parm.TNo",
2035               FT_STRING, BASE_NONE, NULL, 0x00,
2036               "Standard text number requested by calling party.",
2037               HFILL
2038             }
2039         },
2040         { &hf_ucp_parm_CS,
2041             { "CS", "ucp.parm.CS",
2042               FT_UINT8, BASE_DEC, NULL, 0x00,
2043               "Additional character set number.",
2044               HFILL
2045             }
2046         },
2047         { &hf_ucp_parm_PID,
2048             { "PID", "ucp.parm.PID",
2049               FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
2050               "SMT PID value.",
2051               HFILL
2052             }
2053         },
2054         { &hf_ucp_parm_NPL,
2055             { "NPL", "ucp.parm.NPL",
2056               FT_UINT16, BASE_DEC, NULL, 0x00,
2057               "Number of parameters in the following list.",
2058               HFILL
2059             }
2060         },
2061         { &hf_ucp_parm_GA,
2062             { "GA", "ucp.parm.GA",
2063               FT_STRING, BASE_NONE, NULL, 0x00,
2064               "GA?? haven't got a clue.",
2065               HFILL
2066             }
2067         },
2068         { &hf_ucp_parm_RP,
2069             { "RP", "ucp.parm.RP",
2070               FT_UINT8, BASE_DEC, VALS(vals_parm_RP), 0x00,
2071               "Repitition requested.",
2072               HFILL
2073             }
2074         },
2075         { &hf_ucp_parm_LRP,
2076             { "LRP", "ucp.parm.LRP",
2077               FT_STRING, BASE_DEC, NULL, 0x00,
2078               "Legitimisation code for repitition.",
2079               HFILL
2080             }
2081         },
2082         { &hf_ucp_parm_PR,
2083             { "PR", "ucp.parm.PR",
2084               FT_UINT8, BASE_DEC, NULL, 0x00,
2085               "Priority requested.",
2086               HFILL
2087             }
2088         },
2089         { &hf_ucp_parm_LPR,
2090             { "LPR", "ucp.parm.LPR",
2091               FT_STRING, BASE_DEC, NULL, 0x00,
2092               "Legitimisation code for priority requested.",
2093               HFILL
2094             }
2095         },
2096         { &hf_ucp_parm_UM,
2097             { "UM", "ucp.parm.UM",
2098               FT_UINT8, BASE_DEC, VALS(vals_parm_UM), 0x00,
2099               "Urgent message indicator.",
2100               HFILL
2101             }
2102         },
2103         { &hf_ucp_parm_LUM,
2104             { "LUM", "ucp.parm.LUM",
2105               FT_STRING, BASE_DEC, NULL, 0x00,
2106               "Legitimisation code for urgent message.",
2107               HFILL
2108             }
2109         },
2110         { &hf_ucp_parm_RC,
2111             { "RC", "ucp.parm.RC",
2112               FT_UINT8, BASE_DEC, VALS(vals_parm_RC), 0x00,
2113               "Reverse charging request.",
2114               HFILL
2115             }
2116         },
2117         { &hf_ucp_parm_LRC,
2118             { "LRC", "ucp.parm.LRC",
2119               FT_STRING, BASE_DEC, NULL, 0x00,
2120               "Legitimisation code for reverse charging.",
2121               HFILL
2122             }
2123         },
2124         { &hf_ucp_parm_NRq,
2125             { "NRq", "ucp.parm.NRq",
2126               FT_UINT8, BASE_DEC, VALS(vals_parm_NRq), 0x00,
2127               "Notification request.",
2128               HFILL
2129             }
2130         },
2131         { &hf_ucp_parm_GAdC,
2132             { "GAdC", "ucp.parm.GAdC",
2133               FT_STRING, BASE_NONE, NULL, 0x00,
2134               "Group address code.",
2135               HFILL
2136             }
2137         },
2138         { &hf_ucp_parm_A_D,
2139             { "A_D", "ucp.parm.A_D",
2140               FT_UINT8, BASE_DEC, VALS(vals_parm_A_D), 0x00,
2141               "Add to/delete from fixed subscriber address list record.",
2142               HFILL
2143             }
2144         },
2145         { &hf_ucp_parm_CT,
2146             { "CT", "ucp.parm.CT",
2147               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2148               "Accumulated charges timestamp.",
2149               HFILL
2150             }
2151         },
2152         { &hf_ucp_parm_AAC,
2153             { "AAC", "ucp.parm.AAC",
2154               FT_STRING, BASE_NONE, NULL, 0x00,
2155               "Accumulated charges.",
2156               HFILL
2157             }
2158         },
2159         { &hf_ucp_parm_MNo,
2160             { "MNo", "ucp.parm.MNo",
2161               FT_STRING, BASE_NONE, NULL, 0x00,
2162               "Message number.",
2163               HFILL
2164             }
2165         },
2166         { &hf_ucp_parm_R_T,
2167             { "R_T", "ucp.parm.R_T",
2168               FT_UINT8, BASE_DEC, VALS(vals_parm_R_T), 0x00,
2169               "Message number.",
2170               HFILL
2171             }
2172         },
2173         { &hf_ucp_parm_NAdC,
2174             { "NAdC", "ucp.parm.NAdC",
2175               FT_STRING, BASE_NONE, NULL, 0x00,
2176               "Notification address.",
2177               HFILL
2178             }
2179         },
2180         { &hf_ucp_parm_NT,
2181             { "NT", "ucp.parm.NT",
2182               FT_UINT8, BASE_DEC, VALS(vals_parm_NT), 0x00,
2183               "Notification type.",
2184               HFILL
2185             }
2186         },
2187         { &hf_ucp_parm_IVR5x,
2188             { "IVR5x", "ucp.parm.IVR5x",
2189               FT_STRING, BASE_NONE, NULL, 0x00,
2190               "UCP release number supported/accepted.",
2191               HFILL
2192             }
2193         },
2194         { &hf_ucp_parm_REQ_OT,
2195             { "REQ_OT", "ucp.parm.REQ_OT",
2196               FT_UINT8, BASE_DEC, VALS(vals_parm_REQ_OT), 0x00,
2197               "UCP release number supported/accepted.",
2198               HFILL
2199             }
2200         },
2201         { &hf_ucp_parm_SSTAT,
2202             { "SSTAT", "ucp.parm.SSTAT",
2203               FT_UINT8, BASE_DEC, VALS(vals_parm_SSTAT), 0x00,
2204               "Supplementary services for which status is requested.",
2205               HFILL
2206             }
2207         },
2208         { &hf_ucp_parm_LMN,
2209             { "LMN", "ucp.parm.LMN",
2210               FT_UINT8, BASE_DEC, NULL, 0x00,
2211               "Last message number.",
2212               HFILL
2213             }
2214         },
2215         { &hf_ucp_parm_NMESS,
2216             { "NMESS", "ucp.parm.NMESS",
2217               FT_UINT8, BASE_DEC, NULL, 0x00,
2218               "Number of stored messages.",
2219               HFILL
2220             }
2221         },
2222         { &hf_ucp_parm_NMESS_str,
2223             { "NMESS_str", "ucp.parm.NMESS_str",
2224               FT_STRING, BASE_NONE, NULL, 0x00,
2225               "Number of stored messages.",
2226               HFILL
2227             }
2228         },
2229         { &hf_ucp_parm_NPID,
2230             { "NPID", "ucp.parm.NPID",
2231               FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
2232               "Notification PID value.",
2233               HFILL
2234             }
2235         },
2236         { &hf_ucp_parm_LRq,
2237             { "LRq", "ucp.parm.LRq",
2238               FT_UINT8, BASE_DEC, VALS(vals_parm_LRq), 0x00,
2239               "Last resort address request.",
2240               HFILL
2241             }
2242         },
2243         { &hf_ucp_parm_LRAd,
2244             { "LRAd", "ucp.parm.LRAd",
2245               FT_STRING, BASE_NONE, NULL, 0x00,
2246               "Last resort address.",
2247               HFILL
2248             }
2249         },
2250         { &hf_ucp_parm_LPID,
2251             { "LPID", "ucp.parm.LPID",
2252               FT_UINT16, BASE_DEC, VALS(vals_parm_PID), 0x00,
2253               "Last resort PID value.",
2254               HFILL
2255             }
2256         },
2257         { &hf_ucp_parm_DD,
2258             { "DD", "ucp.parm.DD",
2259               FT_UINT8, BASE_DEC, VALS(vals_parm_DD), 0x00,
2260               "Deferred delivery requested.",
2261               HFILL
2262             }
2263         },
2264         { &hf_ucp_parm_DDT,
2265             { "DDT", "ucp.parm.DDT",
2266               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2267               "Deferred delivery time.",
2268               HFILL
2269             }
2270         },
2271         { &hf_ucp_parm_STx,
2272             { "STx", "ucp.parm.STx",
2273               FT_NONE, BASE_NONE, NULL, 0x00,
2274               "Standard text.",
2275               HFILL
2276             }
2277         },
2278         { &hf_ucp_parm_ST,
2279             { "ST", "ucp.parm.ST",
2280               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2281               "Start time.",
2282               HFILL
2283             }
2284         },
2285         { &hf_ucp_parm_SP,
2286             { "SP", "ucp.parm.SP",
2287               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2288               "Stop time.",
2289               HFILL
2290             }
2291         },
2292         { &hf_ucp_parm_VP,
2293             { "VP", "ucp.parm.VP",
2294               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2295               "Validity period.",
2296               HFILL
2297             }
2298         },
2299         { &hf_ucp_parm_RPID,
2300             { "RPID", "ucp.parm.RPID",
2301               FT_STRING, BASE_NONE, NULL, 0x00,
2302               "Replace PID",
2303               HFILL
2304             }
2305         },
2306         { &hf_ucp_parm_SCTS,
2307             { "SCTS", "ucp.parm.SCTS",
2308               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2309               "Service Centre timestamp.",
2310               HFILL
2311             }
2312         },
2313         { &hf_ucp_parm_Dst,
2314             { "Dst", "ucp.parm.Dst",
2315               FT_UINT8, BASE_DEC, VALS(vals_parm_Dst), 0x00,
2316               "Delivery status.",
2317               HFILL
2318             }
2319         },
2320         { &hf_ucp_parm_Rsn,
2321             { "Rsn", "ucp.parm.Rsn",
2322               FT_UINT16, BASE_DEC, VALS(vals_parm_Rsn), 0x00,
2323               "Reason code.",
2324               HFILL
2325             }
2326         },
2327         { &hf_ucp_parm_DSCTS,
2328             { "DSCTS", "ucp.parm.DSCTS",
2329               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2330               "Delivery timestamp.",
2331               HFILL
2332             }
2333         },
2334         { &hf_ucp_parm_MT,
2335             { "MT", "ucp.parm.MT",
2336               FT_UINT8, BASE_DEC, VALS(vals_parm_MT), 0x00,
2337               "Message type.",
2338               HFILL
2339             }
2340         },
2341         { &hf_ucp_parm_NB,
2342             { "  NB", "ucp.parm.NB",
2343               FT_STRING, BASE_NONE, NULL, 0x00,
2344               "No. of bits in Transparent Data (TD) message.",
2345               HFILL
2346             }
2347         },
2348         { &hf_ucp_data_section,
2349             { "  Data", "ucp.message",
2350               FT_NONE, BASE_NONE, NULL, 0x00,
2351               "The actual message or data.",
2352               HFILL
2353             }
2354         },
2355         { &hf_ucp_parm_MMS,
2356             { "MMS", "ucp.parm.MMS",
2357               FT_UINT8, BASE_DEC, NULL, 0x00,
2358               "More messages to send.",
2359               HFILL
2360             }
2361         },
2362         { &hf_ucp_parm_DCs,
2363             { "DCs", "ucp.parm.DCs",
2364               FT_UINT8, BASE_DEC, VALS(vals_parm_DCs), 0x00,
2365               "Data coding scheme (deprecated).",
2366               HFILL
2367             }
2368         },
2369         { &hf_ucp_parm_MCLs,
2370             { "MCLs", "ucp.parm.MCLs",
2371               FT_UINT8, BASE_DEC, VALS(vals_parm_MCLs), 0x00,
2372               "Message class.",
2373               HFILL
2374             }
2375         },
2376         { &hf_ucp_parm_RPI,
2377             { "RPI", "ucp.parm.RPI",
2378               FT_UINT8, BASE_DEC, VALS(vals_parm_RPI), 0x00,
2379               "Reply path.",
2380               HFILL
2381             }
2382         },
2383         { &hf_ucp_parm_CPg,
2384             { "CPg", "ucp.parm.CPg",
2385               FT_STRING, BASE_NONE, NULL, 0x00,
2386               "Reserved for Code Page.",
2387               HFILL
2388             }
2389         },
2390         { &hf_ucp_parm_RPLy,
2391             { "RPLy", "ucp.parm.RPLy",
2392               FT_STRING, BASE_NONE, NULL, 0x00,
2393               "Reserved for Reply type.",
2394               HFILL
2395             }
2396         },
2397         { &hf_ucp_parm_OTOA,
2398             { "OTOA", "ucp.parm.OTOA",
2399               FT_STRING, BASE_NONE, NULL, 0x00,
2400               "Originator Type Of Address.",
2401               HFILL
2402             }
2403         },
2404         { &hf_ucp_parm_HPLMN,
2405             { "HPLMN", "ucp.parm.HPLMN",
2406               FT_STRING, BASE_NONE, NULL, 0x00,
2407               "Home PLMN address.",
2408               HFILL
2409             }
2410         },
2411         { &hf_ucp_parm_XSer,
2412             { "Extra services:", "ucp.parm.XSer",
2413               FT_NONE, BASE_DEC, NULL, 0x00,
2414               "Extra services.",
2415               HFILL
2416             }
2417         },
2418         { &hf_ucp_parm_RES4,
2419             { "RES4", "ucp.parm.RES4",
2420               FT_STRING, BASE_NONE, NULL, 0x00,
2421               "Reserved for future use.",
2422               HFILL
2423             }
2424         },
2425         { &hf_ucp_parm_RES5,
2426             { "RES5", "ucp.parm.RES5",
2427               FT_STRING, BASE_NONE, NULL, 0x00,
2428               "Reserved for future use.",
2429               HFILL
2430             }
2431         },
2432         { &hf_ucp_parm_OTON,
2433             { "OTON", "ucp.parm.OTON",
2434               FT_UINT8, BASE_DEC, VALS(vals_parm_OTON), 0x00,
2435               "Originator type of number.",
2436               HFILL
2437             }
2438         },
2439         { &hf_ucp_parm_ONPI,
2440             { "ONPI", "ucp.parm.ONPI",
2441               FT_UINT8, BASE_DEC, VALS(vals_parm_ONPI), 0x00,
2442               "Originator numbering plan id.",
2443               HFILL
2444             }
2445         },
2446         { &hf_ucp_parm_STYP0,
2447             { "STYP0", "ucp.parm.STYP0",
2448               FT_UINT8, BASE_DEC, VALS(vals_parm_STYP0), 0x00,
2449               "Subtype of operation.",
2450               HFILL
2451             }
2452         },
2453         { &hf_ucp_parm_STYP1,
2454             { "STYP1", "ucp.parm.STYP1",
2455               FT_UINT8, BASE_DEC, VALS(vals_parm_STYP1), 0x00,
2456               "Subtype of operation.",
2457               HFILL
2458             }
2459         },
2460         { &hf_ucp_parm_PWD,
2461             { "PWD", "ucp.parm.PWD",
2462               FT_STRING, BASE_NONE, NULL, 0x00,
2463               "Current password.",
2464               HFILL
2465             }
2466         },
2467         { &hf_ucp_parm_NPWD,
2468             { "NPWD", "ucp.parm.NPWD",
2469               FT_STRING, BASE_NONE, NULL, 0x00,
2470               "New password.",
2471               HFILL
2472             }
2473         },
2474         { &hf_ucp_parm_VERS,
2475             { "VERS", "ucp.parm.VERS",
2476               FT_STRING, BASE_NONE, NULL, 0x00,
2477               "Version number.",
2478               HFILL
2479             }
2480         },
2481         { &hf_ucp_parm_LAdC,
2482             { "LAdC", "ucp.parm.LAdC",
2483               FT_STRING, BASE_NONE, NULL, 0x00,
2484               "Address for VSMSC list operation.",
2485               HFILL
2486             }
2487         },
2488         { &hf_ucp_parm_LTON,
2489             { "LTON", "ucp.parm.LTON",
2490               FT_UINT8, BASE_DEC, NULL, 0x00,
2491               "Type of number list address.",
2492               HFILL
2493             }
2494         },
2495         { &hf_ucp_parm_LNPI,
2496             { "LNPI", "ucp.parm.LNPI",
2497               FT_UINT8, BASE_DEC, NULL, 0x00,
2498               "Numbering plan id. list address.",
2499               HFILL
2500             }
2501         },
2502         { &hf_ucp_parm_OPID,
2503             { "OPID", "ucp.parm.OPID",
2504               FT_UINT8, BASE_DEC, VALS(vals_parm_OPID), 0x00,
2505               "Originator protocol identifier.",
2506               HFILL
2507             }
2508         },
2509         { &hf_ucp_parm_RES1,
2510             { "RES1", "ucp.parm.RES1",
2511               FT_STRING, BASE_NONE, NULL, 0x00,
2512               "Reserved for future use.",
2513               HFILL
2514             }
2515         },
2516         { &hf_ucp_parm_RES2,
2517             { "RES2", "ucp.parm.RES2",
2518               FT_STRING, BASE_NONE, NULL, 0x00,
2519               "Reserved for future use.",
2520               HFILL
2521             }
2522         },
2523         { &hf_ucp_parm_ACK,
2524             { "(N)Ack", "ucp.parm.ACK",
2525               FT_UINT8, BASE_DEC, VALS(vals_parm_ACK), 0x00,
2526               "Positive or negative acknowledge of the operation.",
2527               HFILL
2528             }
2529         },
2530         { &hf_ucp_parm_MVP,
2531             { "MVP", "ucp.parm.MVP",
2532               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
2533               "Mofified validity period.",
2534               HFILL
2535             }
2536         },
2537         { &hf_ucp_parm_EC,
2538             { "Error code", "ucp.parm.EC",
2539               FT_UINT8, BASE_DEC, VALS(vals_parm_EC), 0x00,
2540               "The result of the requested operation.",
2541               HFILL
2542             }
2543         },
2544         { &hf_ucp_parm_SM,
2545             { "SM", "ucp.parm.SM",
2546               FT_STRING, BASE_NONE, NULL, 0x00,
2547               "System message.",
2548               HFILL
2549             }
2550         },
2551         { &hf_xser_service,
2552             { "Type of service", "ucp.xser.service",
2553               FT_UINT8, BASE_HEX, VALS(vals_xser_service), 0x00,
2554               "The type of service specified.",
2555               HFILL
2556             }
2557         },
2558     };
2559     /* Setup protocol subtree array */
2560     static gint *ett[] = {
2561         &ett_ucp,
2562         &ett_sub,
2563         &ett_XSer
2564     };
2565     /* Register the protocol name and description */
2566     proto_ucp = proto_register_protocol("Universal Computer Protocol",
2567                                         "UCP", "ucp");
2568
2569     /* Required function calls to register header fields and subtrees used */
2570     proto_register_field_array(proto_ucp, hf, array_length(hf));
2571     proto_register_subtree_array(ett, array_length(ett));
2572 }
2573
2574 /*
2575  * If dissector uses sub-dissector registration add a registration routine.
2576  * This format is required because a script is used to find these routines and
2577  * create the code that calls these routines.
2578  */
2579 void
2580 proto_reg_handoff_ucp(void)
2581 {
2582     dissector_handle_t ucp_handle;
2583
2584     /*
2585      * UCP can be spoken on any port so, when not on a specific port, try this
2586      * one whenever TCP is spoken.
2587      */
2588     heur_dissector_add("tcp", dissect_ucp_heur, proto_ucp);
2589
2590     /*
2591      * Also register as one that can be selected by a TCP port number.
2592      */
2593     ucp_handle = create_dissector_handle(dissect_ucp, proto_ucp);
2594     dissector_add_handle("tcp.port", ucp_handle);
2595 }