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