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