Add tvbuff class.
[obnox/wireshark/wip.git] / packet-x25.c
1 /* packet-x25.c
2  * Routines for x25 packet disassembly
3  * Olivier Abad <abad@daba.dhis.net>
4  *
5  * $Id: packet-x25.c,v 1.25 2000/05/11 08:15:56 gram Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <stdio.h>
36 #include <glib.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include "etypes.h"
40 #include "packet.h"
41 #include "packet-ip.h"
42 #include "packet-osi.h"
43 #include "packet-clnp.h"
44 #include "nlpid.h"
45
46 #define FROM_DCE                        0x80
47
48 #define X25_CALL_REQUEST                0x0B
49 #define X25_CALL_ACCEPTED               0x0F
50 #define X25_CLEAR_REQUEST               0x13
51 #define X25_CLEAR_CONFIRMATION          0x17
52 #define X25_INTERRUPT                   0x23
53 #define X25_INTERRUPT_CONFIRMATION      0x27
54 #define X25_RESET_REQUEST               0x1B
55 #define X25_RESET_CONFIRMATION          0x1F
56 #define X25_RESTART_REQUEST             0xFB
57 #define X25_RESTART_CONFIRMATION        0xFF
58 #define X25_REGISTRATION_REQUEST        0xF3
59 #define X25_REGISTRATION_CONFIRMATION   0xF7
60 #define X25_DIAGNOSTIC                  0xF1
61 #define X25_RR                          0x01
62 #define X25_RNR                         0x05
63 #define X25_REJ                         0x09
64 #define X25_DATA                        0x00
65
66 #define X25_FAC_CLASS_MASK              0xC0
67
68 #define X25_FAC_CLASS_A                 0x00
69 #define X25_FAC_CLASS_B                 0x40
70 #define X25_FAC_CLASS_C                 0x80
71 #define X25_FAC_CLASS_D                 0xC0
72
73 #define X25_FAC_COMP_MARK               0x00
74 #define X25_FAC_REVERSE                 0x01
75 #define X25_FAC_THROUGHPUT              0x02
76 #define X25_FAC_CUG                     0x03
77 #define X25_FAC_CALLED_MODIF            0x08
78 #define X25_FAC_CUG_OUTGOING_ACC        0x09
79 #define X25_FAC_THROUGHPUT_MIN          0x0A
80 #define X25_FAC_EXPRESS_DATA            0x0B
81 #define X25_FAC_BILATERAL_CUG           0x41
82 #define X25_FAC_PACKET_SIZE             0x42
83 #define X25_FAC_WINDOW_SIZE             0x43
84 #define X25_FAC_RPOA_SELECTION          0x44
85 #define X25_FAC_TRANSIT_DELAY           0x49
86 #define X25_FAC_CALL_TRANSFER           0xC3
87 #define X25_FAC_CALLED_ADDR_EXT         0xC9
88 #define X25_FAC_ETE_TRANSIT_DELAY       0xCA
89 #define X25_FAC_CALLING_ADDR_EXT        0xCB
90 #define X25_FAC_CALL_DEFLECT            0xD1
91 #define X25_FAC_PRIORITY                0xD2
92
93 static int proto_x25 = -1;
94 static int hf_x25_qbit = -1;
95 static int hf_x25_dbit = -1;
96 static int hf_x25_mod = -1;
97 static int hf_x25_lcn = -1;
98 static int hf_x25_type = -1;
99 static int hf_x25_p_r = -1;
100 static int hf_x25_mbit = -1;
101 static int hf_x25_p_s = -1;
102 static int proto_ex25 = -1;
103 static int hf_ex25_qbit = -1;
104 static int hf_ex25_dbit = -1;
105 static int hf_ex25_mod = -1;
106 static int hf_ex25_lcn = -1;
107 static int hf_ex25_type = -1;
108 static int hf_ex25_p_r = -1;
109 static int hf_ex25_mbit = -1;
110 static int hf_ex25_p_s = -1;
111
112 static gint ett_x25 = -1;
113 static gint ett_x25_fac = -1;
114 static gint ett_x25_fac_unknown = -1;
115 static gint ett_x25_fac_mark = -1;
116 static gint ett_x25_fac_reverse = -1;
117 static gint ett_x25_fac_throughput = -1;
118 static gint ett_x25_fac_cug = -1;
119 static gint ett_x25_fac_called_modif = -1;
120 static gint ett_x25_fac_cug_outgoing_acc = -1;
121 static gint ett_x25_fac_throughput_min = -1;
122 static gint ett_x25_fac_express_data = -1;
123 static gint ett_x25_fac_bilateral_cug = -1;
124 static gint ett_x25_fac_packet_size = -1;
125 static gint ett_x25_fac_window_size = -1;
126 static gint ett_x25_fac_rpoa_selection = -1;
127 static gint ett_x25_fac_transit_delay = -1;
128 static gint ett_x25_fac_call_transfer = -1;
129 static gint ett_x25_fac_called_addr_ext = -1;
130 static gint ett_x25_fac_ete_transit_delay = -1;
131 static gint ett_x25_fac_calling_addr_ext = -1;
132 static gint ett_x25_fac_call_deflect = -1;
133 static gint ett_x25_fac_priority = -1;
134
135 static const value_string vals_modulo[] = {
136         { 1, "8" },
137         { 2, "128" },
138         { 0, NULL}
139 };
140
141 static const value_string vals_x25_type[] = {
142         { X25_CALL_REQUEST, "Call" },
143         { X25_CALL_ACCEPTED, "Call Accepted" },
144         { X25_CLEAR_REQUEST, "Clear" },
145         { X25_CLEAR_CONFIRMATION, "Clear Confirmation" },
146         { X25_INTERRUPT, "Interrupt" },
147         { X25_INTERRUPT_CONFIRMATION, "Interrupt Confirmation" },
148         { X25_RESET_REQUEST, "Reset" },
149         { X25_RESET_CONFIRMATION, "Reset Confirmation" },
150         { X25_RESTART_REQUEST, "Restart" },
151         { X25_RESTART_CONFIRMATION, "Restart Confirmation" },
152         { X25_REGISTRATION_REQUEST, "Registration" },
153         { X25_REGISTRATION_CONFIRMATION, "Registration Confirmation" },
154         { X25_DIAGNOSTIC, "Diagnostic" },
155         { X25_RR, "RR" },
156         { X25_RNR, "RNR" },
157         { X25_REJ, "REJ" },
158         { X25_DATA, "DATA" },
159         { 0,   NULL}
160 };
161
162 /*
163  * each vc_info node contains :
164  *   the time of the first frame using this dissector (secs and usecs)
165  *   the time of the last frame using this dissector (0 if it is unknown)
166  *   a pointer to the dissector
167  *
168  * the "time of first frame" is initialized when a Call Req. is received
169  * the "time of last frame" is initialized when a Clear, Reset, or Restart
170  * is received
171  */
172 typedef struct _vc_info {
173         guint32 first_frame_secs, first_frame_usecs;
174         guint32 last_frame_secs, last_frame_usecs;
175         void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
176         struct _vc_info *next;
177 } vc_info;
178
179 /*
180  * the hash table will contain linked lists of global_vc_info
181  * each global_vc_info struct contains :
182  *   the VC number (the hash table is indexed with VC % 64)
183  *   a linked list of vc_info
184  */
185 typedef struct _global_vc_info {
186         int vc_num;
187         vc_info *info;
188         struct _global_vc_info *next;
189 } global_vc_info;
190
191 static global_vc_info *hash_table[64];
192
193 void
194 free_vc_info(vc_info *pt)
195 {
196   vc_info *vci = pt;
197
198   while (pt) {
199     vci = pt;
200     pt = pt->next;
201     g_free(vci);
202   }
203 }
204
205 static void
206 reinit_x25_hashtable(void)
207 {
208   int i;
209
210   for (i=0; i<64; i++) {
211     if (hash_table[i]) /* not NULL ==> free */
212     {
213       global_vc_info *hash_ent, *hash_ent2;
214       hash_ent2 = hash_ent = hash_table[i];
215       while (hash_ent)
216       {
217         hash_ent2 = hash_ent;
218         hash_ent = hash_ent->next;
219         free_vc_info(hash_ent2->info);
220         g_free(hash_ent2);
221       }
222       hash_table[i]=0;
223     }
224   }
225 }
226
227 void
228 x25_hash_add_proto_start(guint16 vc, guint32 frame_secs, guint32 frame_usecs,
229                          void (*dissect)(const u_char *, int, frame_data *,
230                                        proto_tree *))
231 {
232   int idx = vc % 64;
233   global_vc_info *hash_ent;
234   global_vc_info *hash_ent2;
235
236   if (hash_table[idx] == 0)
237   {
238     hash_ent = (global_vc_info *)g_malloc(sizeof(global_vc_info));
239     if (!hash_ent) {
240       fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
241       exit(1);
242     }
243     hash_ent->vc_num = vc;
244     hash_ent->next=0;
245     hash_ent->info = (vc_info *)g_malloc(sizeof(vc_info));
246     if (!hash_ent->info) {
247       fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
248       exit(1);
249     }
250     hash_ent->info->first_frame_secs = frame_secs;
251     hash_ent->info->first_frame_usecs = frame_usecs;
252     hash_ent->info->last_frame_secs = 0;
253     hash_ent->info->last_frame_usecs = 0;
254     hash_ent->info->dissect = dissect;
255     hash_ent->info->next = 0;
256     hash_table[idx] = hash_ent;
257   }
258   else
259   {
260     hash_ent2 = hash_ent = hash_table[idx];
261     /* search an entry with the same VC number */
262     while (hash_ent != NULL && hash_ent->vc_num != vc) {
263       hash_ent2 = hash_ent;
264       hash_ent = hash_ent->next;
265     }
266     if (hash_ent != NULL) /* hash_ent->vc_num == vc */
267     {
268       vc_info *vci = hash_ent->info;
269       while (vci->next) vci = vci->next; /* last element */
270       if (vci->dissect == dissect) {
271         vci->last_frame_secs = 0;
272         vci->last_frame_usecs = 0;
273       }
274       else {
275         vci->next = (vc_info *)g_malloc(sizeof(vc_info));
276         if (vci->next == 0) {
277           fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
278           exit(1);
279         }
280         vci->next->first_frame_secs = frame_secs;
281         vci->next->first_frame_usecs = frame_usecs;
282         vci->next->last_frame_secs = 0;
283         vci->next->last_frame_usecs = 0;
284         vci->next->dissect = dissect;
285         vci->next->next = 0;
286       }
287     }
288     else /* new vc number */
289     {
290       hash_ent2->next = (global_vc_info *)g_malloc(sizeof(global_vc_info));
291       if (!hash_ent2->next) {
292         fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
293         exit(1);
294       }
295       hash_ent2->next->info = (vc_info *)g_malloc(sizeof(vc_info));
296       if (!hash_ent2->next->info) {
297         fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
298         exit(1);
299       }
300       hash_ent2->next->info->first_frame_secs = frame_secs;
301       hash_ent2->next->info->first_frame_usecs = frame_usecs;
302       hash_ent2->next->info->last_frame_secs = 0;
303       hash_ent2->next->info->last_frame_usecs = 0;
304       hash_ent2->next->info->dissect = dissect;
305       hash_ent2->next->info->next = 0;
306     }
307   }
308 }
309
310 void
311 x25_hash_add_proto_end(guint16 vc, guint32 frame_secs, guint32 frame_usecs)
312 {
313   global_vc_info *hash_ent = hash_table[vc%64];
314   vc_info *vci;
315
316   if (!hash_ent) return;
317   while(hash_ent->vc_num != vc) hash_ent = hash_ent->next;
318   if (!hash_ent) return;
319
320   vci = hash_ent->info;
321   while (vci->next) vci = vci->next;
322   vci->last_frame_secs = frame_secs;
323   vci->last_frame_usecs = frame_usecs;
324 }
325
326 void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc))(const u_char *, int, frame_data *, proto_tree *)
327 {
328   global_vc_info *hash_ent = hash_table[vc%64];
329   vc_info *vci;
330   vc_info *vci2;
331
332   if (!hash_ent) return 0;
333
334   while(hash_ent && hash_ent->vc_num != vc) hash_ent = hash_ent->next;
335   if (!hash_ent) return 0;
336
337   /* a hash_ent was found for this VC number */
338   vci2 = vci = hash_ent->info;
339
340   /* looking for an entry matching our frame time */
341   while (vci && (vci->last_frame_secs < frame_secs ||
342                  (vci->last_frame_secs == frame_secs &&
343                   vci->last_frame_usecs < frame_usecs))) {
344     vci2 = vci;
345     vci = vci->next;
346   }
347   /* we reached last record, and previous record has a non zero
348    * last frame time ==> no dissector */
349   if (!vci && (vci2->last_frame_secs || vci2->last_frame_usecs)) return 0;
350
351   /* we reached last record, and previous record has a zero last frame time
352    * ==> dissector for previous frame has not been "stopped" by a Clear, etc */
353   if (!vci) {
354     /* if the start time for vci2 is greater than our frame time
355      * ==> no dissector */
356     if (frame_secs < vci2->first_frame_secs ||
357         (frame_secs == vci2->first_frame_secs &&
358          frame_usecs < vci2->first_frame_usecs))
359       return 0;
360     else
361       return vci2->dissect;
362   }
363
364   /* our frame time is before vci's end. Check if it is adter vci's start */
365   if (frame_secs < vci->first_frame_secs ||
366       (frame_secs == vci->first_frame_secs &&
367        frame_usecs < vci->first_frame_usecs))
368     return 0;
369   else
370     return vci->dissect;
371 }
372
373 static char *clear_code(unsigned char code)
374 {
375     static char buffer[25];
376
377     if (code == 0x00 || (code & 0x80) == 0x80)
378         return "DTE Originated";
379     if (code == 0x01)
380         return "Number Busy";
381     if (code == 0x09)
382         return "Out Of Order";
383     if (code == 0x11)
384         return "Remote Procedure Error";
385     if (code == 0x19)
386         return "Reverse Charging Acceptance Not Subscribed";
387     if (code == 0x21)
388         return "Incompatible Destination";
389     if (code == 0x29)
390         return "Fast Select Acceptance Not Subscribed";
391     if (code == 0x39)
392         return "Destination Absent";
393     if (code == 0x03)
394         return "Invalid Facility Requested";
395     if (code == 0x0B)
396         return "Access Barred";
397     if (code == 0x13)
398         return "Local Procedure Error";
399     if (code == 0x05)
400         return "Network Congestion";
401     if (code == 0x0D)
402         return "Not Obtainable";
403     if (code == 0x15)
404         return "RPOA Out Of Order";
405
406     sprintf(buffer, "Unknown %02X", code);
407
408     return buffer;
409 }
410
411 static char *clear_diag(unsigned char code)
412 {
413     static char buffer[25];
414
415     if (code == 0)
416         return "No additional information";
417     if (code == 1)
418         return "Invalid P(S)";
419     if (code == 2)
420         return "Invalid P(R)";
421     if (code == 16)
422         return "Packet type invalid";
423     if (code == 17)
424         return "Packet type invalid for state r1";
425     if (code == 18)
426         return "Packet type invalid for state r2";
427     if (code == 19)
428         return "Packet type invalid for state r3";
429     if (code == 20)
430         return "Packet type invalid for state p1";
431     if (code == 21)
432         return "Packet type invalid for state p2";
433     if (code == 22)
434         return "Packet type invalid for state p3";
435     if (code == 23)
436         return "Packet type invalid for state p4";
437     if (code == 24)
438         return "Packet type invalid for state p5";
439     if (code == 25)
440         return "Packet type invalid for state p6";
441     if (code == 26)
442         return "Packet type invalid for state p7";
443     if (code == 27)
444         return "Packet type invalid for state d1";
445     if (code == 28)
446         return "Packet type invalid for state d2";
447     if (code == 29)
448         return "Packet type invalid for state d3";
449     if (code == 32)
450         return "Packet not allowed";
451     if (code == 33)
452         return "Unidentifiable packet";
453     if (code == 34)
454         return "Call on one-way logical channel";
455     if (code == 35)
456         return "Invalid packet type on a PVC";
457     if (code == 36)
458         return "Packet on unassigned LC";
459     if (code == 37)
460         return "Reject not subscribed to";
461     if (code == 38)
462         return "Packet too short";
463     if (code == 39)
464         return "Packet too long";
465     if (code == 40)
466         return "Invalid general format identifier";
467     if (code == 41)
468         return "Restart/registration packet with nonzero bits";
469     if (code == 42)
470         return "Packet type not compatible with facility";
471     if (code == 43)
472         return "Unauthorised interrupt confirmation";
473     if (code == 44)
474         return "Unauthorised interrupt";
475     if (code == 45)
476         return "Unauthorised reject";
477     if (code == 48)
478         return "Time expired";
479     if (code == 49)
480         return "Time expired for incoming call";
481     if (code == 50)
482         return "Time expired for clear indication";
483     if (code == 51)
484         return "Time expired for reset indication";
485     if (code == 52)
486         return "Time expired for restart indication";
487     if (code == 53)
488         return "Time expired for call deflection";
489     if (code == 64)
490         return "Call set-up/clearing or registration pb.";
491     if (code == 65)
492         return "Facility/registration code not allowed";
493     if (code == 66)
494         return "Facility parameter not allowed";
495     if (code == 67)
496         return "Invalid called DTE address";
497     if (code == 68)
498         return "Invalid calling DTE address";
499     if (code == 69)
500         return "Invalid facility/registration length";
501     if (code == 70)
502         return "Incoming call barred";
503     if (code == 71)
504         return "No logical channel available";
505     if (code == 72)
506         return "Call collision";
507     if (code == 73)
508         return "Duplicate facility requested";
509     if (code == 74)
510         return "Non zero address length";
511     if (code == 75)
512         return "Non zero facility length";
513     if (code == 76)
514         return "Facility not provided when expected";
515     if (code == 77)
516         return "Invalid CCITT-specified DTE facility";
517     if (code == 78)
518         return "Max. nb of call redir/defl. exceeded";
519     if (code == 80)
520         return "Miscellaneous";
521     if (code == 81)
522         return "Improper cause code from DTE";
523     if (code == 82)
524         return "Not aligned octet";
525     if (code == 83)
526         return "Inconsistent Q bit setting";
527     if (code == 84)
528         return "NUI problem";
529     if (code == 112)
530         return "International problem";
531     if (code == 113)
532         return "Remote network problem";
533     if (code == 114)
534         return "International protocol problem";
535     if (code == 115)
536         return "International link out of order";
537     if (code == 116)
538         return "International link busy";
539     if (code == 117)
540         return "Transit network facility problem";
541     if (code == 118)
542         return "Remote network facility problem";
543     if (code == 119)
544         return "International routing problem";
545     if (code == 120)
546         return "Temporary routing problem";
547     if (code == 121)
548         return "Unknown called DNIC";
549     if (code == 122)
550         return "Maintenance action";
551
552     sprintf(buffer, "Unknown %d", code);
553
554     return buffer;
555 }
556
557 static char *reset_code(unsigned char code)
558 {
559     static char buffer[25];
560
561     if (code == 0x00 || (code & 0x80) == 0x80)
562         return "DTE Originated";
563     if (code == 0x01)
564         return "Out of order";
565     if (code == 0x03)
566         return "Remote Procedure Error";
567     if (code == 0x05)
568         return "Local Procedure Error";
569     if (code == 0x07)
570         return "Network Congestion";
571     if (code == 0x09)
572         return "Remote DTE operational";
573     if (code == 0x0F)
574         return "Network operational";
575     if (code == 0x11)
576         return "Incompatible Destination";
577     if (code == 0x1D)
578         return "Network out of order";
579
580     sprintf(buffer, "Unknown %02X", code);
581
582     return buffer;
583 }
584
585 static char *restart_code(unsigned char code)
586 {
587     static char buffer[25];
588
589     if (code == 0x00 || (code & 0x80) == 0x80)
590         return "DTE Originated";
591     if (code == 0x01)
592         return "Local Procedure Error";
593     if (code == 0x03)
594         return "Network Congestion";
595     if (code == 0x07)
596         return "Network Operational";
597     if (code == 0x7F)
598         return "Registration/cancellation confirmed";
599
600     sprintf(buffer, "Unknown %02X", code);
601
602     return buffer;
603 }
604
605 static char *registration_code(unsigned char code)
606 {
607     static char buffer[25];
608
609     if (code == 0x03)
610         return "Invalid facility request";
611     if (code == 0x05)
612         return "Network congestion";
613     if (code == 0x13)
614         return "Local procedure error";
615     if (code == 0x7F)
616         return "Registration/cancellation confirmed";
617
618     sprintf(buffer, "Unknown %02X", code);
619
620     return buffer;
621 }
622
623 void
624 dump_facilities(proto_tree *tree, int *offset, const guint8 *p)
625 {
626     const guint8 *ptr = p;
627     guint32 len;      /* facilities length */
628     proto_item *ti=0;
629     proto_tree *fac_tree = 0;
630     proto_tree *fac_subtree;
631
632     len = *ptr++;
633     if (len && tree) {
634         ti = proto_tree_add_text(tree, NullTVB, *offset, len + 1,
635                                  "Facilities");
636         fac_tree = proto_item_add_subtree(ti, ett_x25_fac);
637         proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
638                             "Facilities length: %d", len);
639     }
640     (*offset)++;
641
642     while (len > 0) {
643         switch(*ptr & X25_FAC_CLASS_MASK) {
644         case X25_FAC_CLASS_A:
645             switch (*ptr) {
646             case X25_FAC_COMP_MARK:
647                 if (fac_tree)
648                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
649                             "Code : 00 (Marker)");
650                 switch (ptr[1]) {
651                 case 0x00:
652                     if (fac_tree) {
653                         fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_mark);
654                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
655                                             "Parameter : 00 (Network complementary "
656                                             "services - calling DTE)");
657                     }
658                     break;
659                 case 0xFF:
660                     if (fac_tree) {
661                         fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_mark);
662                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
663                                             "Parameter : FF (Network complementary "
664                                             "services - called DTE)");
665                     }
666                     break;
667                 case 0x0F:
668                     if (fac_tree) {
669                         fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_mark);
670                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
671                                             "Parameter : 0F (DTE complementary "
672                                             "services)");
673                     }
674                     break;
675                 default:
676                     if (fac_tree) {
677                         fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_mark);
678                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
679                                             "Parameter : %02X (Unknown marker)",
680                                             ptr[1]);
681                     }
682                     break;
683                 }
684                 break;
685             case X25_FAC_REVERSE:
686                 if (fac_tree) {
687                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
688                             "(Reverse charging / Fast select)", *ptr);
689                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_reverse);
690                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1, "Parameter : %02X",
691                             ptr[1]);
692                     if (ptr[1] & 0xC0)
693                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
694                                 "11.. .... = Fast select with restriction");
695                     else if (ptr[1] & 0x80)
696                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
697                                 "10.. .... = Fast select - no restriction");
698                     else
699                         proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
700                                 "00.. .... = Fast select not requested");
701                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
702                             decode_boolean_bitfield(ptr[1], 0x01, 1*8,
703                                 "Reverse charging requested",
704                                 "Reverse charging not requested"));
705                 }
706                 break;
707             case X25_FAC_THROUGHPUT:
708                 if (fac_tree) {
709                     char tmpbuf[80];
710
711                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
712                             "(Throughput class negociation)", *ptr);
713                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_throughput);
714                     switch (ptr[1] >> 4)
715                     {
716                     case 3:
717                     case 4:
718                     case 5:
719                     case 6:
720                     case 7:
721                     case 8:
722                     case 9:
723                     case 10:
724                     case 11:
725                         sprintf(tmpbuf, "From the called DTE : %%u (%d bps)",
726                                 75*(1<<((ptr[1] >> 4)-3)));
727                         break;
728                     case 12:
729                         sprintf(tmpbuf, "From the called DTE : %%u (48000 bps)");
730                         break;
731                     case 13:
732                         sprintf(tmpbuf, "From the called DTE : %%u (64000 bps)");
733                         break;
734                     default:
735                         sprintf(tmpbuf, "From the called DTE : %%u (Reserved)");
736                     }
737                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
738                             decode_numeric_bitfield(ptr[1], 0xF0, 1*8, tmpbuf));
739                     switch (ptr[1] & 0x0F)
740                     {
741                     case 3:
742                     case 4:
743                     case 5:
744                     case 6:
745                     case 7:
746                     case 8:
747                     case 9:
748                     case 10:
749                     case 11:
750                         sprintf(tmpbuf, "From the calling DTE : %%u (%d bps)",
751                                 75*(1<<((ptr[1] & 0x0F)-3)));
752                         break;
753                     case 12:
754                         sprintf(tmpbuf, "From the calling DTE : %%u (48000 bps)");
755                         break;
756                     case 13:
757                         sprintf(tmpbuf, "From the calling DTE : %%u (64000 bps)");
758                         break;
759                     default:
760                         sprintf(tmpbuf, "From the calling DTE : %%u (Reserved)");
761                     }
762                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
763                             decode_numeric_bitfield(ptr[1], 0x0F, 1*8, tmpbuf));
764                 }
765                 break;
766             case X25_FAC_CUG:
767                 if (fac_tree) {
768                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
769                             "(Closed user group selection)", *ptr);
770                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_cug);
771                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
772                             "Closed user group: %02X", ptr[1]);
773                 }
774                 break;
775             case X25_FAC_CALLED_MODIF:
776                 if (fac_tree) {
777                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
778                             "(Called address modified)", *ptr);
779                     fac_subtree = proto_item_add_subtree(ti,
780                             ett_x25_fac_called_modif);
781                     proto_tree_add_text(fac_tree, NullTVB, *offset, 2,
782                             "Parameter %02X", ptr[1]);
783                 }
784                 break;
785             case X25_FAC_CUG_OUTGOING_ACC:
786                 if (fac_tree) {
787                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
788                             "(Closed user group with outgoing access selection)",
789                             *ptr);
790                     fac_subtree = proto_item_add_subtree(ti,
791                             ett_x25_fac_cug_outgoing_acc);
792                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
793                             "Closed user group: %02X", ptr[1]);
794                 }
795                 break;
796             case X25_FAC_THROUGHPUT_MIN:
797                 if (fac_tree) {
798                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
799                             "(Minimum throughput class)", *ptr);
800                     fac_subtree = proto_item_add_subtree(ti,
801                             ett_x25_fac_throughput_min);
802                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
803                             "Parameter %02X", ptr[1]);
804                 }
805                 break;
806             case X25_FAC_EXPRESS_DATA:
807                 if (fac_tree) {
808                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
809                             "(Negociation of express data)", *ptr);
810                     fac_subtree = proto_item_add_subtree(ti,
811                             ett_x25_fac_express_data);
812                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
813                             "Parameter %02X", ptr[1]);
814                 }
815                 break;
816             default:
817                 if (fac_tree) {
818                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
819                             "Code : %02X (Unknown class A)", *ptr);
820                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_unknown);
821                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
822                             "Parameter %02X", ptr[1]);
823                 }
824                 break;
825             }
826             (*offset) += 2;
827             len -= 2;
828             ptr += 2;
829             break;
830         case X25_FAC_CLASS_B:
831             switch (*ptr) {
832             case X25_FAC_BILATERAL_CUG:
833                 if (fac_tree) {
834                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
835                             "(Bilateral closed user group selection)", *ptr);
836                     fac_subtree = proto_item_add_subtree(ti,
837                             ett_x25_fac_bilateral_cug);
838                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 2,
839                                         "Bilateral CUG: %02X%02X",
840                                         ptr[1], ptr[2]);
841                 }
842                 break;
843             case X25_FAC_PACKET_SIZE:
844                 if (fac_tree)
845                 {
846                     char tmpbuf[80];
847
848                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
849                             "(Packet size)", *ptr);
850                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_packet_size);
851                     switch (ptr[1])
852                     {
853                     case 0x04:
854                         sprintf(tmpbuf, "From the called DTE : %%u (16)");
855                         break;
856                     case 0x05:
857                         sprintf(tmpbuf, "From the called DTE : %%u (32)");
858                         break;
859                     case 0x06:
860                         sprintf(tmpbuf, "From the called DTE : %%u (64)");
861                         break;
862                     case 0x07:
863                         sprintf(tmpbuf, "From the called DTE : %%u (128)");
864                         break;
865                     case 0x08:
866                         sprintf(tmpbuf, "From the called DTE : %%u (256)");
867                         break;
868                     case 0x0D:
869                         sprintf(tmpbuf, "From the called DTE : %%u (512)");
870                         break;
871                     case 0x0C:
872                         sprintf(tmpbuf, "From the called DTE : %%u (1024)");
873                         break;
874                     case 0x0E:
875                         sprintf(tmpbuf, "From the called DTE : %%u (2048)");
876                         break;
877                     case 0x0F:
878                         sprintf(tmpbuf, "From the called DTE : %%u (4096)");
879                         break;
880                     default:
881                         sprintf(tmpbuf, "From the called DTE : %%u (Unknown)");
882                         break;
883                     }
884                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
885                             decode_numeric_bitfield(ptr[1], 0x0F, 1*8, tmpbuf));
886
887                     switch (ptr[2])
888                     {
889                     case 0x04:
890                         sprintf(tmpbuf, "From the calling DTE : %%u (16)");
891                         break;
892                     case 0x05:
893                         sprintf(tmpbuf, "From the calling DTE : %%u (32)");
894                         break;
895                     case 0x06:
896                         sprintf(tmpbuf, "From the calling DTE : %%u (64)");
897                         break;
898                     case 0x07:
899                         sprintf(tmpbuf, "From the calling DTE : %%u (128)");
900                         break;
901                     case 0x08:
902                         sprintf(tmpbuf, "From the calling DTE : %%u (256)");
903                         break;
904                     case 0x0D:
905                         sprintf(tmpbuf, "From the calling DTE : %%u (512)");
906                         break;
907                     case 0x0C:
908                         sprintf(tmpbuf, "From the calling DTE : %%u (1024)");
909                         break;
910                     case 0x0E:
911                         sprintf(tmpbuf, "From the calling DTE : %%u (2048)");
912                         break;
913                     case 0x0F:
914                         sprintf(tmpbuf, "From the calling DTE : %%u (4096)");
915                         break;
916                     default:
917                         sprintf(tmpbuf, "From the calling DTE : %%u (Unknown)");
918                         break;
919                     }
920                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
921                             decode_numeric_bitfield(ptr[2], 0x0F, 1*8, tmpbuf));
922                 }
923                 break;
924             case X25_FAC_WINDOW_SIZE:
925                 if (fac_tree) {
926                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
927                             "(Window size)", *ptr);
928                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_window_size);
929                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
930                             decode_numeric_bitfield(ptr[1], 0x7F, 1*8,
931                             "From the called DTE: %u"));
932                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
933                             decode_numeric_bitfield(ptr[2], 0x7F, 1*8,
934                             "From the calling DTE: %u"));
935                 }
936                 break;
937             case X25_FAC_RPOA_SELECTION:
938                 if (fac_tree) {
939                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
940                             "(RPOA selection)", *ptr);
941                     fac_subtree = proto_item_add_subtree(ti,
942                             ett_x25_fac_rpoa_selection);
943                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 2,
944                                         "Data network identification code : %02X%02X",
945                                         ptr[1], ptr[2]);
946                 }
947                 break;
948             case X25_FAC_TRANSIT_DELAY:
949                 if (fac_tree) {
950                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
951                             "(Transit delay selection and indication)", *ptr);
952                     fac_subtree = proto_item_add_subtree(ti,
953                             ett_x25_fac_transit_delay);
954                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 2,
955                                         "Transit delay: %d ms",
956                                         (ptr[1]<<8) + ptr[2]);
957                 }
958                 break;
959             default:
960                 if (fac_tree) {
961                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
962                             "Code : %02X (Unknown class B)", *ptr);
963                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_unknown);
964                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 2,
965                             "Parameter %02X%02X", ptr[1], ptr[2]);
966                 }
967                 break;
968             }
969             (*offset) += 3;
970             len -= 3;
971             ptr += 3;
972             break;
973         case X25_FAC_CLASS_C:
974             if (fac_tree) {
975                 ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
976                         "Code : %02X (Unknown class C)", *ptr);
977                 fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_unknown);
978                 proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 3,
979                         "Parameter %02X%02X%02X",
980                         ptr[1], ptr[2], ptr[3]);
981             }
982             (*offset) += 4;
983             len -= 4;
984             ptr += 4;
985             break;
986         case X25_FAC_CLASS_D:
987             switch (*ptr) {
988             case X25_FAC_CALL_TRANSFER:
989                 if (fac_tree) {
990                     int i;
991                     char tmpbuf[256];
992
993                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
994                             "(Call redirection or deflection notification)", *ptr);
995                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_call_transfer);
996                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
997                             "Length : %u", ptr[1]);
998                     if ((ptr[2] & 0xC0) == 0xC0) {
999                         proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1000                                 "Reason : call deflection by the originally "
1001                                 "called DTE address");
1002                     }
1003                     else {
1004                         switch (ptr[2]) {
1005                         case 0x01:
1006                             proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1007                                     "Reason : originally called DTE busy");
1008                             break;
1009                         case 0x07:
1010                             proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1011                                     "Reason : call dist. within a hunt group");
1012                             break;
1013                         case 0x09:
1014                             proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1015                                     "Reason : originally called DTE out of order");
1016                             break;
1017                         case 0x0F:
1018                             proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1019                                     "Reason : systematic call redirection");
1020                             break;
1021                         default:
1022                             proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1023                                     "Reason : unknown");
1024                             break;
1025                         }
1026                     }
1027                     proto_tree_add_text(fac_subtree, NullTVB, *offset+3, 1,
1028                             "Number of semi-octets in DTE address : %u", ptr[3]);
1029                     for (i = 0; i < ptr[3]; i++) {
1030                         if (i % 2 == 0) {
1031                             tmpbuf[i] = ((ptr[4+i/2] >> 4) & 0x0F) + '0';
1032                             /* if > 9, convert to the right hexadecimal letter */
1033                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1034                         } else {
1035                             tmpbuf[i] = (ptr[4+i/2] & 0x0F) + '0';
1036                             /* if > 9, convert to the right hexadecimal letter */
1037                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1038                         }
1039                     }
1040                     tmpbuf[i] = 0;
1041                     proto_tree_add_text(fac_subtree, NullTVB, *offset+4, ptr[1] - 2,
1042                             "DTE address : %s", tmpbuf);
1043                 }
1044                 break;
1045             case X25_FAC_CALLING_ADDR_EXT:
1046                 if (fac_tree) {
1047                     int i;
1048                     char tmpbuf[256];
1049
1050                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
1051                             "(Calling address extension)", *ptr);
1052                     fac_subtree = proto_item_add_subtree(ti,
1053                             ett_x25_fac_calling_addr_ext);
1054                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
1055                             "Length : %u", ptr[1]);
1056                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1057                             "Number of semi-octets in DTE address : %u", ptr[2]);
1058                     for (i = 0; i < ptr[2]; i++) {
1059                         if (i % 2 == 0) {
1060                             tmpbuf[i] = ((ptr[3+i/2] >> 4) & 0x0F) + '0';
1061                             /* if > 9, convert to the right hexadecimal letter */
1062                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1063                         } else {
1064                             tmpbuf[i] = (ptr[3+i/2] & 0x0F) + '0';
1065                             /* if > 9, convert to the right hexadecimal letter */
1066                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1067                         }
1068                     }
1069                     tmpbuf[i] = 0;
1070                     proto_tree_add_text(fac_subtree, NullTVB, *offset+3, ptr[1] - 1,
1071                             "DTE address : %s", tmpbuf);
1072                 }
1073                 break;
1074             case X25_FAC_CALLED_ADDR_EXT:
1075                 if (fac_tree) {
1076                     int i;
1077                     char tmpbuf[256];
1078
1079                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
1080                             "(Called address extension)", *ptr);
1081                     fac_subtree = proto_item_add_subtree(ti,
1082                             ett_x25_fac_called_addr_ext);
1083                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
1084                             "Length : %u", ptr[1]);
1085                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1086                             "Number of semi-octets in DTE address : %u", ptr[2]);
1087                     for (i = 0; i < ptr[2]; i++) {
1088                         if (i % 2 == 0) {
1089                             tmpbuf[i] = ((ptr[3+i/2] >> 4) & 0x0F) + '0';
1090                             /* if > 9, convert to the right hexadecimal letter */
1091                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1092                         } else {
1093                             tmpbuf[i] = (ptr[3+i/2] & 0x0F) + '0';
1094                             /* if > 9, convert to the right hexadecimal letter */
1095                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1096                         }
1097                     }
1098                     tmpbuf[i] = 0;
1099                     proto_tree_add_text(fac_subtree, NullTVB, *offset+3, ptr[1] - 1,
1100                             "DTE address : %s", tmpbuf);
1101                 }
1102                 break;
1103             case X25_FAC_ETE_TRANSIT_DELAY:
1104                 if (fac_tree) {
1105                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
1106                             "(End to end transit delay)", *ptr);
1107                     fac_subtree = proto_item_add_subtree(ti,
1108                             ett_x25_fac_ete_transit_delay);
1109                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
1110                             "Length : %u", ptr[1]);
1111                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, ptr[1], "Value");
1112                 }
1113                 break;
1114             case X25_FAC_CALL_DEFLECT:
1115                 if (fac_tree) {
1116                     int i;
1117                     char tmpbuf[256];
1118
1119                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1, "Code : %02X "
1120                             "(Call deflection selection)", *ptr);
1121                     fac_subtree = proto_item_add_subtree(ti,
1122                             ett_x25_fac_call_deflect);
1123                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
1124                             "Length : %u", ptr[1]);
1125                     if ((ptr[2] & 0xC0) == 0xC0)
1126                         proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1127                                 "Reason : call DTE originated");
1128                     else
1129                         proto_tree_add_text(fac_subtree, NullTVB, *offset+2, 1,
1130                                 "Reason : unknown");
1131                     proto_tree_add_text(fac_subtree, NullTVB, *offset+3, 1,
1132                             "Number of semi-octets in the alternative DTE address : %u",
1133                             ptr[3]);
1134                     for (i = 0; i < ptr[3]; i++) {
1135                         if (i % 2 == 0) {
1136                             tmpbuf[i] = ((ptr[4+i/2] >> 4) & 0x0F) + '0';
1137                             /* if > 9, convert to the right hexadecimal letter */
1138                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1139                         } else {
1140                             tmpbuf[i] = (ptr[4+i/2] & 0x0F) + '0';
1141                             /* if > 9, convert to the right hexadecimal letter */
1142                             if (tmpbuf[i] > '9') tmpbuf[i] += ('A' - '0' - 10);
1143                         }
1144                     }
1145                     tmpbuf[i] = 0;
1146                     proto_tree_add_text(fac_subtree, NullTVB, *offset+4, ptr[1] - 2,
1147                             "Alternative DTE address : %s", tmpbuf);
1148                 }
1149                 break;
1150             case X25_FAC_PRIORITY:
1151                 if (fac_tree) {
1152                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
1153                             "Code : %02X (Priority)", *ptr);
1154                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_priority);
1155                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
1156                             "Length : %u", ptr[1]);
1157                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, ptr[1], "Value");
1158                 }
1159                 break;
1160             default:
1161                 if (fac_tree) {
1162                     ti = proto_tree_add_text(fac_tree, NullTVB, *offset, 1,
1163                             "Code : %02X (Unknown class D)", *ptr);
1164                     fac_subtree = proto_item_add_subtree(ti, ett_x25_fac_unknown);
1165                     proto_tree_add_text(fac_subtree, NullTVB, *offset+1, 1,
1166                             "Length : %u", ptr[1]);
1167                     proto_tree_add_text(fac_subtree, NullTVB, *offset+2, ptr[1], "Value");
1168                 }
1169             }
1170             (*offset) += ptr[1]+2;
1171             len -= ptr[1]+2;
1172             ptr += ptr[1]+2;
1173             break;
1174         }
1175     }
1176 }
1177
1178 void
1179 x25_ntoa(proto_tree *tree, int *offset, const guint8 *p,
1180          frame_data *fd, gboolean toa)
1181 {
1182     int len1, len2;
1183     int i;
1184     char addr1[16], addr2[16];
1185     char *first, *second;
1186
1187     len1  = (*p >> 4) & 0x0F;
1188     len2 = (*p >> 0) & 0x0F;
1189     if (tree) {
1190         proto_tree_add_text(tree, NullTVB, *offset, 1,
1191                 decode_numeric_bitfield(*p, 0xF0, 1*8,
1192                     toa ? "Called address length : %u" :
1193                           "Calling address length : %u"));
1194         proto_tree_add_text(tree, NullTVB, *offset, 1,
1195                 decode_numeric_bitfield(*p, 0x0F, 1*8,
1196                     toa ? "Calling address length : %u" :
1197                           "Called address length : %u"));
1198     }
1199     (*offset)++;
1200
1201     p++;
1202
1203     first=addr1;
1204     second=addr2;
1205     for (i = 0; i < (len1 + len2); i++) {
1206         if (i < len1) {
1207             if (i % 2 != 0) {
1208                 *first++ = ((*p >> 0) & 0x0F) + '0';
1209                 p++;
1210             } else {
1211                 *first++ = ((*p >> 4) & 0x0F) + '0';
1212             }
1213         } else {
1214             if (i % 2 != 0) {
1215                 *second++ = ((*p >> 0) & 0x0F) + '0';
1216                 p++;
1217             } else {
1218                 *second++ = ((*p >> 4) & 0x0F) + '0';
1219             }
1220         }
1221     }
1222
1223     *first  = '\0';
1224     *second = '\0';
1225
1226     if (len1) {
1227         if (toa) {
1228             if (check_col(fd, COL_RES_DL_DST))
1229                 col_add_str(fd, COL_RES_DL_DST, addr1);
1230         }
1231         else {
1232             if(check_col(fd, COL_RES_DL_SRC))
1233                 col_add_str(fd, COL_RES_DL_SRC, addr1);
1234         }
1235         if (tree)
1236             proto_tree_add_text(tree, NullTVB, *offset,
1237                                 (len1 + 1) / 2,
1238                                 "%s address : %s",
1239                                 toa ? "Called" : "Calling",
1240                                 addr1);
1241     }
1242     if (len2) {
1243         if (toa) {
1244             if (check_col(fd, COL_RES_DL_SRC))
1245                 col_add_str(fd, COL_RES_DL_SRC, addr2);
1246         }
1247         else {
1248             if(check_col(fd, COL_RES_DL_DST))
1249                 col_add_str(fd, COL_RES_DL_DST, addr2);
1250         }
1251         if (tree)
1252             proto_tree_add_text(tree, NullTVB, *offset + len1/2,
1253                                 (len2+1)/2+(len1%2+(len2+1)%2)/2,
1254                                 "%s address : %s",
1255                                 toa ? "Calling" : "Called",
1256                                 addr2);
1257     }
1258     (*offset) += ((len1 + len2 + 1) / 2);
1259 }
1260
1261 int
1262 get_x25_pkt_len(const char *data, frame_data *fd, int offset)
1263 {
1264     int length, called_len, calling_len, dte_len, dce_len;
1265
1266     /* packet size should always be > 3 */
1267     if (!BYTES_ARE_IN_FRAME(offset, 3)) return END_OF_FRAME;
1268
1269     switch ((guint8)data[2])
1270     {
1271     case X25_CALL_REQUEST:
1272         if (BYTES_ARE_IN_FRAME(offset, 4)) /* pkt size >= 4 */
1273         {
1274             called_len  = (data[3] >> 0) & 0x0F;
1275             calling_len = (data[3] >> 4) & 0x0F;
1276             length = 4 + (called_len + calling_len + 1) / 2; /* addr */
1277             if (length+offset < pi.captured_len)
1278                 length += (1 + data[length]); /* facilities */
1279         }
1280         else length = END_OF_FRAME;
1281         return MIN(END_OF_FRAME,length);
1282
1283     case X25_CALL_ACCEPTED:
1284         if (BYTES_ARE_IN_FRAME(offset, 4)) /* pkt size >= 4 */
1285         {
1286             called_len  = (data[3] >> 0) & 0x0F;
1287             calling_len = (data[3] >> 4) & 0x0F;
1288             length = 4 + (called_len + calling_len + 1) / 2; /* addr */
1289             if (length+offset < pi.captured_len)
1290                 length += (1 + data[length]); /* facilities */
1291         }
1292         else length = END_OF_FRAME;
1293         return MIN(END_OF_FRAME,length);
1294
1295     case X25_CLEAR_REQUEST:
1296     case X25_RESET_REQUEST:
1297     case X25_RESTART_REQUEST:
1298         return MIN(END_OF_FRAME,5);
1299
1300     case X25_DIAGNOSTIC:
1301         return MIN(END_OF_FRAME,4);
1302
1303     case X25_CLEAR_CONFIRMATION:
1304     case X25_INTERRUPT:
1305     case X25_INTERRUPT_CONFIRMATION:
1306     case X25_RESET_CONFIRMATION:
1307     case X25_RESTART_CONFIRMATION:
1308         return MIN(END_OF_FRAME,3);
1309
1310     case X25_REGISTRATION_REQUEST:
1311         if (BYTES_ARE_IN_FRAME(offset, 4)) /* pkt size >= 4 */
1312         {
1313             dce_len  = (data[3] >> 0) & 0x0F;
1314             dte_len = (data[3] >> 4) & 0x0F;
1315             length = 4 + (dte_len + dce_len + 1) / 2; /* addr */
1316             if (length+offset < pi.captured_len)
1317                 length += (1 + data[length]); /* registration */
1318         }
1319         else length = END_OF_FRAME;
1320         return MIN(END_OF_FRAME,length);
1321
1322     case X25_REGISTRATION_CONFIRMATION:
1323         if (BYTES_ARE_IN_FRAME(offset, 6)) /* pkt size >= 6 */
1324         {
1325             dce_len  = (data[5] >> 0) & 0x0F;
1326             dte_len = (data[5] >> 4) & 0x0F;
1327             length = 6 + (dte_len + dce_len + 1) / 2; /* addr */
1328             if (length+offset < pi.captured_len)
1329                 length += (1 + data[length]); /* registration */
1330         }
1331         else length = END_OF_FRAME;
1332         return MIN(END_OF_FRAME,length);
1333     }
1334             
1335     if ((data[2] & 0x01) == X25_DATA) return MIN(END_OF_FRAME,3);
1336
1337     switch (data[2] & 0x1F)
1338     {
1339     case X25_RR:
1340         return MIN(END_OF_FRAME,3);
1341
1342     case X25_RNR:
1343         return MIN(END_OF_FRAME,3);
1344
1345     case X25_REJ:
1346         return MIN(END_OF_FRAME,3);
1347     }
1348
1349     return 0;
1350 }
1351
1352 #define PRT_ID_ISO_8073 0x01
1353
1354 static const value_string prt_id_vals[] = {
1355         {PRT_ID_ISO_8073, "ISO 8073 COTP"},
1356         {0x02,            "ISO 8602"},
1357         {0x03,            "ISO 10732 in conjunction with ISO 8073"},
1358         {0x04,            "ISO 10736 in conjunction with ISO 8602"},
1359         {0x00,            NULL}
1360 };
1361
1362 static const value_string sharing_strategy_vals[] = {
1363         {0x00,            "No sharing"},
1364         {0x00,            NULL}
1365 };
1366
1367 void
1368 dissect_x25(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1369 {
1370     proto_tree *x25_tree=0, *ti;
1371     int localoffset=offset;
1372     int x25_pkt_len;
1373     int modulo;
1374     guint16 vc;
1375     void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
1376     gboolean toa;         /* TOA/NPI address format */
1377
1378     if (check_col(fd, COL_PROTOCOL))
1379         col_add_str(fd, COL_PROTOCOL, "X.25");
1380
1381     modulo = ((pd[localoffset] & 0x20) ? 128 : 8);
1382
1383     if (pd[localoffset] & 0x80) toa = TRUE;
1384     else toa = FALSE;
1385
1386     x25_pkt_len = get_x25_pkt_len(&pd[localoffset], fd, offset);
1387     if (x25_pkt_len < 3) /* packet too short */
1388     {
1389         if (check_col(fd, COL_INFO))
1390             col_add_str(fd, COL_INFO, "Invalid/short X.25 packet");
1391         if (tree)
1392             proto_tree_add_protocol_format(tree, (modulo == 8 ? proto_x25 : proto_ex25), NullTVB,
1393                             localoffset, END_OF_FRAME,
1394                             "Invalid/short X.25 packet");
1395         return;
1396     }
1397     vc = (int)(pd[localoffset] & 0x0F)*256 + (int)pd[localoffset+1];
1398     if (tree) {
1399         ti = proto_tree_add_item(tree, (modulo == 8) ? proto_x25 : proto_ex25, NullTVB,
1400                 localoffset, x25_pkt_len, NULL);
1401         x25_tree = proto_item_add_subtree(ti, ett_x25);
1402         if (pd[localoffset] & 0x80)
1403             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_qbit : hf_ex25_qbit, NullTVB,
1404                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1405         if (pd[localoffset] & 0x40)
1406             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_dbit : hf_ex25_dbit, NullTVB,
1407                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1408         proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_mod : hf_ex25_mod, NullTVB,
1409                 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1410     }
1411     switch (pd[localoffset+2]) {
1412     case X25_CALL_REQUEST:
1413         if (check_col(fd, COL_INFO))
1414             col_add_fstr(fd, COL_INFO, "%s VC:%d",
1415                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Inc. call"
1416                                                              : "Call req." ,
1417                     vc);
1418         if (x25_tree) {
1419             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1420                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1421             proto_tree_add_uint_format(x25_tree,
1422                     (modulo == 8) ? hf_x25_type : hf_ex25_type,
1423                     NullTVB, localoffset+2, 1, X25_CALL_REQUEST,
1424                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Incoming call"
1425                                                              : "Call request");
1426         }
1427         localoffset += 3;
1428         if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1429             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1430
1431         if (localoffset < x25_pkt_len+offset) /* facilities */
1432             dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1433
1434         if (IS_DATA_IN_FRAME(localoffset)) /* user data */
1435         {
1436             guint8 spi;
1437             guint8 prt_id;
1438
1439             /* Compare the first octet of the CALL REQUEST packet with
1440                various ISO 9577 NLPIDs, as per Annex A of ISO 9577. */
1441             spi = pd[localoffset];
1442             switch (spi) {
1443
1444             /* XXX - handle other NLPIDs, e.g. PPP? */
1445
1446             case NLPID_IP:
1447                 x25_hash_add_proto_start(vc, fd->abs_secs,
1448                                          fd->abs_usecs, dissect_ip);
1449                 if (x25_tree)
1450                     proto_tree_add_text(x25_tree, NullTVB, localoffset, 1,
1451                                         "X.224 secondary protocol ID: IP");
1452                 localoffset++;
1453                 break;
1454
1455             default:
1456                 if ((pd[localoffset] >= 0x03 && pd[localoffset] <= 0x82)
1457                     && pd[localoffset+1] == 0x01) {
1458                     /* ISO 9577 claims that a SPI in that range is a
1459                        length field for X.224/ISO 8073 or X.264/ISO 11570;
1460                        however, some of them collide with NLPIDs such
1461                        as 0x81 for ISO 8473 CLNP or ISO 8542 ESIS, so
1462                        I don't know how you run those over X.25, assuming
1463                        you do.
1464
1465                        I'm also not sure what the "or" means there; it
1466                        looks as if X.264 specifies the layout of a
1467                        "UN TPDU" ("Use of network connection TPDU"),
1468                        which specifies the transport protocol to use
1469                        over this network connection, and 0x03 0x01 0x01
1470                        0x00 is such a TPDU, with a length of 3, a UN
1471                        field of 1 (as is required), a PRT-ID ("protocol
1472                        identifier") field of 1 (X.224/ISO 8073, a/k/a
1473                        COTP service), and a SHARE ("sharing strategy")
1474                        field of 0 ("no sharing", which is the only one
1475                        allowed).
1476
1477                        So we'll assume that's what it is, as the SPI
1478                        is in the right range for a length, and the UN
1479                        field is 0x01. */
1480                     prt_id = pd[localoffset+2];
1481                     if (x25_tree) {
1482                         proto_tree_add_text(x25_tree, NullTVB, localoffset, 1,
1483                                         "X.264 length indicator: %u",
1484                                         pd[localoffset]);
1485                         proto_tree_add_text(x25_tree, NullTVB, localoffset+1, 1,
1486                                         "X.264 UN TPDU identifier: 0x%02X",
1487                                         pd[localoffset+1]);
1488                         proto_tree_add_text(x25_tree, NullTVB, localoffset+2, 1,
1489                                         "X.264 protocol identifier: %s",
1490                                         val_to_str(prt_id, prt_id_vals, "Unknown (0x%02X)"));
1491                         proto_tree_add_text(x25_tree, NullTVB, localoffset+3, 1,
1492                                         "X.264 sharing strategy: %s",
1493                                         val_to_str(pd[localoffset+3], sharing_strategy_vals, "Unknown (0x%02X)"));
1494                     }
1495
1496                     /* XXX - dissect the variable part? */
1497
1498                     /* The length doesn't include the length octet itself. */
1499                     localoffset += pd[localoffset] + 1;
1500
1501                     switch (prt_id) {
1502
1503                     case PRT_ID_ISO_8073:
1504                         /* ISO 8073 COTP */
1505                         x25_hash_add_proto_start(vc, fd->abs_secs,
1506                                          fd->abs_usecs, dissect_cotp);
1507                         break;
1508
1509                     default:
1510                         goto unknown;
1511                     }
1512                 } else {
1513                 unknown:
1514                     if (x25_tree) {
1515                         if (IS_DATA_IN_FRAME(localoffset))
1516                            proto_tree_add_text(x25_tree, NullTVB, localoffset,
1517                                         pi.captured_len-localoffset, "Data");
1518                     }
1519                     localoffset = pi.captured_len;
1520                 }
1521             }
1522         }
1523         break;
1524     case X25_CALL_ACCEPTED:
1525         if(check_col(fd, COL_INFO))
1526             col_add_fstr(fd, COL_INFO, "%s VC:%d",
1527                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Call conn."
1528                                                              : "Call acc." ,
1529                     vc);
1530         if (x25_tree) {
1531             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1532                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1533             proto_tree_add_uint_format(x25_tree,
1534                     (modulo == 8) ? hf_x25_type : hf_ex25_type,
1535                     NullTVB, localoffset+2, 1, X25_CALL_ACCEPTED,
1536                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Call connected"
1537                                                              : "Call accepted");
1538         }
1539         localoffset += 3;
1540         if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1541             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1542
1543         if (localoffset < x25_pkt_len+offset) /* facilities */
1544             dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1545
1546         if (IS_DATA_IN_FRAME(localoffset)) { /* user data */
1547             if (x25_tree)
1548                 proto_tree_add_text(x25_tree, NullTVB, localoffset,
1549                                     pi.captured_len-localoffset, "Data");
1550             localoffset=pi.captured_len;
1551         }
1552         break;
1553     case X25_CLEAR_REQUEST:
1554         if(check_col(fd, COL_INFO)) {
1555             col_add_fstr(fd, COL_INFO, "%s VC:%d %s - %s",
1556                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Clear ind."
1557                                                              : "Clear req." ,
1558                     vc, clear_code(pd[localoffset+3]),
1559                     clear_diag(pd[localoffset+4]));
1560         }
1561         x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1562         if (x25_tree) {
1563             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1564                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1565             proto_tree_add_uint_format(x25_tree,
1566                     (modulo == 8) ? hf_x25_type : hf_ex25_type,
1567                     NullTVB, localoffset+2, 1, X25_CLEAR_REQUEST,
1568                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Clear indication"
1569                                                              : "Clear request");
1570             if (localoffset+3 < x25_pkt_len+offset)
1571                 proto_tree_add_text(x25_tree, NullTVB, localoffset+3, 1,
1572                         "Cause : %s", clear_code(pd[localoffset+3]));
1573             if (localoffset+4 < x25_pkt_len+offset)
1574                 proto_tree_add_text(x25_tree, NullTVB, localoffset+4, 1,
1575                         "Diagnostic : %s",
1576                         clear_diag(pd[localoffset+4]));
1577         }
1578         localoffset += x25_pkt_len;
1579         break;
1580     case X25_CLEAR_CONFIRMATION:
1581         if(check_col(fd, COL_INFO))
1582             col_add_fstr(fd, COL_INFO, "Clear Conf. VC:%d", vc);
1583         if (x25_tree) {
1584             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1585                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1586             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1587                     localoffset+2, 1, X25_CLEAR_CONFIRMATION);
1588         }
1589         localoffset += x25_pkt_len;
1590
1591         if (IS_DATA_IN_FRAME(localoffset)) /* extended clear conf format */
1592             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1593
1594         if (IS_DATA_IN_FRAME(localoffset)) /* facilities */
1595             dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1596         break;
1597     case X25_DIAGNOSTIC:
1598         if(check_col(fd, COL_INFO)) {
1599             col_add_fstr(fd, COL_INFO, "Diag. %d", (int)pd[localoffset+3]);
1600         }
1601         if (x25_tree) {
1602             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1603                     localoffset+2, 1, X25_DIAGNOSTIC);
1604             if (localoffset+3 < x25_pkt_len+offset)
1605                 proto_tree_add_text(x25_tree, NullTVB, localoffset+3, 1,
1606                         "Diagnostic : %d", (int)pd[localoffset+3]);
1607         }
1608         localoffset += x25_pkt_len;
1609         break;
1610     case X25_INTERRUPT:
1611         if(check_col(fd, COL_INFO))
1612             col_add_fstr(fd, COL_INFO, "Interrupt VC:%d", vc);
1613         if (x25_tree) {
1614             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1615                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1616             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1617                     localoffset+2, 1, X25_INTERRUPT);
1618         }
1619         localoffset += x25_pkt_len;
1620         break;
1621     case X25_INTERRUPT_CONFIRMATION:
1622         if(check_col(fd, COL_INFO))
1623             col_add_fstr(fd, COL_INFO, "Interrupt Conf. VC:%d", vc);
1624         if (x25_tree) {
1625             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1626                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1627             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1628                     localoffset+2, 1, X25_INTERRUPT_CONFIRMATION);
1629         }
1630         localoffset += x25_pkt_len;
1631         break;
1632     case X25_RESET_REQUEST:
1633         if(check_col(fd, COL_INFO)) {
1634             col_add_fstr(fd, COL_INFO, "%s VC:%d %s - Diag.:%d",
1635                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset ind."
1636                                                              : "Reset req.",
1637                     vc, reset_code(pd[localoffset+3]),
1638                     (int)pd[localoffset+4]);
1639         }
1640         x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1641         if (x25_tree) {
1642             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1643                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1644             proto_tree_add_uint_format(x25_tree,
1645                     (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB, localoffset+2, 1,
1646                     X25_RESET_REQUEST,
1647                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset indication"
1648                                                              : "Reset request");
1649             if (localoffset+3 < x25_pkt_len+offset)
1650                 proto_tree_add_text(x25_tree, NullTVB, localoffset+3, 1,
1651                         "Cause : %s", reset_code(pd[localoffset+3]));
1652             if (localoffset+4 < x25_pkt_len+offset)
1653                 proto_tree_add_text(x25_tree, NullTVB, localoffset+4, 1,
1654                         "Diagnostic : %d", (int)pd[localoffset+4]);
1655         }
1656         localoffset += x25_pkt_len;
1657         break;
1658     case X25_RESET_CONFIRMATION:
1659         if(check_col(fd, COL_INFO))
1660             col_add_fstr(fd, COL_INFO, "Reset conf. VC:%d", vc);
1661         if (x25_tree) {
1662             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1663                     localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1664             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1665                     localoffset+2, 1, X25_RESET_CONFIRMATION);
1666         }
1667         localoffset += x25_pkt_len;
1668         break;
1669     case X25_RESTART_REQUEST:
1670         if(check_col(fd, COL_INFO)) {
1671             col_add_fstr(fd, COL_INFO, "%s %s - Diag.:%d",
1672                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Restart ind."
1673                                                              : "Restart req.",
1674                     restart_code(pd[localoffset+3]),
1675                     (int)pd[localoffset+4]);
1676         }
1677         if (x25_tree) {
1678             proto_tree_add_uint_format(x25_tree,
1679                     (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB, localoffset+2, 1,
1680                     X25_RESTART_REQUEST,
1681                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Restart indication"
1682                                                              : "Restart request");
1683             if (localoffset+3 < x25_pkt_len+offset)
1684                 proto_tree_add_text(x25_tree, NullTVB, localoffset+3, 1,
1685                         "Cause : %s", restart_code(pd[localoffset+3]));
1686             if (localoffset+4 < x25_pkt_len+offset)
1687                 proto_tree_add_text(x25_tree, NullTVB, localoffset+4, 1,
1688                         "Diagnostic : %d", (int)pd[localoffset+4]);
1689         }
1690         localoffset += x25_pkt_len;
1691         break;
1692     case X25_RESTART_CONFIRMATION:
1693         if(check_col(fd, COL_INFO))
1694             col_add_str(fd, COL_INFO, "Restart conf.");
1695         if (x25_tree)
1696             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1697                     localoffset+2, 1, X25_RESTART_CONFIRMATION);
1698         localoffset += x25_pkt_len;
1699         break;
1700     case X25_REGISTRATION_REQUEST:
1701         if(check_col(fd, COL_INFO))
1702             col_add_str(fd, COL_INFO, "Registration req.");
1703         if (x25_tree)
1704             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1705                     localoffset+2, 1, X25_REGISTRATION_REQUEST);
1706         localoffset += 3;
1707         if (localoffset < x25_pkt_len+offset)
1708             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, FALSE);
1709
1710         if (x25_tree) {
1711             if (localoffset < x25_pkt_len+offset)
1712                 proto_tree_add_text(x25_tree, NullTVB, localoffset, 1,
1713                         "Registration length: %d", pd[localoffset] & 0x7F);
1714             if (localoffset+1 < x25_pkt_len+offset)
1715                 proto_tree_add_text(x25_tree, NullTVB, localoffset+1,
1716                         pd[localoffset] & 0x7F, "Registration");
1717         }
1718         localoffset = pi.captured_len;
1719         break;
1720     case X25_REGISTRATION_CONFIRMATION:
1721         if(check_col(fd, COL_INFO))
1722             col_add_str(fd, COL_INFO, "Registration conf.");
1723         if (x25_tree) {
1724             proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, NullTVB,
1725                     localoffset+2, 1, X25_REGISTRATION_CONFIRMATION);
1726             if (localoffset+3 < x25_pkt_len+offset)
1727                 proto_tree_add_text(x25_tree, NullTVB, localoffset+3, 1,
1728                         "Cause: %s", registration_code(pd[localoffset+3]));
1729             if (localoffset+4 < x25_pkt_len+offset)
1730                 proto_tree_add_text(x25_tree, NullTVB, localoffset+4, 1,
1731                         "Diagnostic: %s", registration_code(pd[localoffset+4]));
1732         }
1733         localoffset += 5;
1734         if (localoffset < x25_pkt_len+offset)
1735             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, TRUE);
1736
1737         if (x25_tree) {
1738             if (localoffset < x25_pkt_len+offset)
1739                 proto_tree_add_text(x25_tree, NullTVB, localoffset, 1,
1740                         "Registration length: %d", pd[localoffset] & 0x7F);
1741             if (localoffset+1 < x25_pkt_len+offset)
1742                 proto_tree_add_text(x25_tree, NullTVB, localoffset+1,
1743                         pd[localoffset] & 0x7F, "Registration");
1744         }
1745         localoffset = pi.captured_len;
1746         break;
1747     default :
1748         localoffset += 2;
1749         if ((pd[localoffset] & 0x01) == X25_DATA)
1750         {
1751             if(check_col(fd, COL_INFO)) {
1752                 if (modulo == 8)
1753                     col_add_fstr(fd, COL_INFO,
1754                             "Data VC:%d P(S):%d P(R):%d %s", vc,
1755                             (pd[localoffset] >> 1) & 0x07,
1756                             (pd[localoffset] >> 5) & 0x07,
1757                             ((pd[localoffset]>>4) & 0x01) ? " M" : "");
1758                 else
1759                     col_add_fstr(fd, COL_INFO,
1760                             "Data VC:%d P(S):%d P(R):%d %s", vc,
1761                             pd[localoffset+1] >> 1,
1762                             pd[localoffset] >> 1,
1763                             (pd[localoffset+1] & 0x01) ? " M" : "");
1764             }
1765             if (x25_tree) {
1766                 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1767                         localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1768                 if (modulo == 8) {
1769                     proto_tree_add_item_hidden(x25_tree, hf_x25_type, NullTVB, localoffset, 1,
1770                             X25_DATA);
1771                     proto_tree_add_item(x25_tree, hf_x25_p_r, NullTVB, localoffset, 1,
1772                             pd[localoffset]);
1773                     if (pd[localoffset] & 0x10)
1774                         proto_tree_add_item(x25_tree, hf_x25_mbit, NullTVB, localoffset, 1,
1775                             pd[localoffset]);
1776                     proto_tree_add_item(x25_tree, hf_x25_p_s, NullTVB, localoffset, 1,
1777                             pd[localoffset]);
1778                     proto_tree_add_text(x25_tree, NullTVB, localoffset, 1,
1779                             decode_boolean_bitfield(pd[localoffset], 0x01, 1*8,
1780                                 NULL, "DATA"));
1781                 }
1782                 else {
1783                     proto_tree_add_item_hidden(x25_tree, hf_ex25_type, NullTVB, localoffset, 1,
1784                             X25_DATA);
1785                     proto_tree_add_item(x25_tree, hf_x25_p_r, NullTVB, localoffset, 1,
1786                             pd[localoffset]);
1787                     proto_tree_add_item(x25_tree, hf_x25_p_s, NullTVB, localoffset+1, 1,
1788                             pd[localoffset+1]);
1789                     if (pd[localoffset+1] & 0x01)
1790                         proto_tree_add_item(x25_tree, hf_ex25_mbit, NullTVB, localoffset+1, 1,
1791                             pd[localoffset+1]);
1792                 }
1793             }
1794             localoffset += (modulo == 8) ? 1 : 2;
1795             break;
1796         }
1797         switch (pd[localoffset] & 0x1F)
1798         {
1799         case X25_RR:
1800             if(check_col(fd, COL_INFO)) {
1801                 if (modulo == 8)
1802                     col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1803                             vc, (pd[localoffset] >> 5) & 0x07);
1804                 else
1805                     col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1806                             vc, pd[localoffset+1] >> 1);
1807             }
1808             if (x25_tree) {
1809                 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1810                         localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1811                 if (modulo == 8) {
1812                     proto_tree_add_item(x25_tree, hf_x25_p_r, NullTVB,
1813                             localoffset, 1, pd[localoffset]);
1814                     proto_tree_add_item(x25_tree, hf_x25_type, NullTVB, localoffset, 1, X25_RR);
1815                 }
1816                 else {
1817                     proto_tree_add_item(x25_tree, hf_ex25_type, NullTVB, localoffset, 1, X25_RR);
1818                     proto_tree_add_item(x25_tree, hf_ex25_p_r, NullTVB,
1819                             localoffset+1, 1, pd[localoffset+1]);
1820                 }
1821             }
1822             break;
1823
1824         case X25_RNR:
1825             if(check_col(fd, COL_INFO)) {
1826                 if (modulo == 8)
1827                     col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1828                             vc, (pd[localoffset] >> 5) & 0x07);
1829                 else
1830                     col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1831                             vc, pd[localoffset+1] >> 1);
1832             }
1833             if (x25_tree) {
1834                 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1835                         localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1836                 if (modulo == 8) {
1837                     proto_tree_add_item(x25_tree, hf_x25_p_r, NullTVB,
1838                             localoffset, 1, pd[localoffset]);
1839                     proto_tree_add_item(x25_tree, hf_x25_type, NullTVB, localoffset, 1, X25_RNR);
1840                 }
1841                 else {
1842                     proto_tree_add_item(x25_tree, hf_ex25_type, NullTVB, localoffset, 1, X25_RNR);
1843                     proto_tree_add_item(x25_tree, hf_ex25_p_r, NullTVB,
1844                             localoffset+1, 1, pd[localoffset+1]);
1845                 }
1846             }
1847             break;
1848
1849         case X25_REJ:
1850             if(check_col(fd, COL_INFO)) {
1851                 if (modulo == 8)
1852                     col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1853                             vc, (pd[localoffset] >> 5) & 0x07);
1854                 else
1855                     col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1856                             vc, pd[localoffset+1] >> 1);
1857             }
1858             if (x25_tree) {
1859                 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, NullTVB,
1860                         localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1861                 if (modulo == 8) {
1862                     proto_tree_add_item(x25_tree, hf_x25_p_r, NullTVB,
1863                             localoffset, 1, pd[localoffset]);
1864                     proto_tree_add_item(x25_tree, hf_x25_type, NullTVB, localoffset, 1, X25_REJ);
1865                 }
1866                 else {
1867                     proto_tree_add_item(x25_tree, hf_ex25_type, NullTVB, localoffset, 1, X25_REJ);
1868                     proto_tree_add_item(x25_tree, hf_ex25_p_r, NullTVB,
1869                             localoffset+1, 1, pd[localoffset+1]);
1870                 }
1871             }
1872         }
1873         localoffset += (modulo == 8) ? 1 : 2;
1874     }
1875
1876     if (!IS_DATA_IN_FRAME(localoffset)) return;
1877
1878     /* search the dissector in the hash table */
1879     if ((dissect = x25_hash_get_dissect(fd->abs_secs, fd->abs_usecs, vc)))
1880       (*dissect)(pd, localoffset, fd, tree);
1881     else {
1882       if (pd[localoffset] == 0x45) /* If the Call Req. has not been captured,
1883                                     * assume these packets carry IP */
1884       {
1885           x25_hash_add_proto_start(vc, fd->abs_secs,
1886                                    fd->abs_usecs, dissect_ip);
1887           dissect_ip(pd, localoffset, fd, tree);
1888       }
1889       else {
1890           dissect_data(pd, localoffset, fd, tree);
1891       }
1892     }
1893 }
1894
1895 void
1896 proto_register_x25(void)
1897 {
1898     static hf_register_info hf8[] = {
1899         { &hf_x25_qbit,
1900           { "Q Bit", "x25.q", FT_BOOLEAN, 2, NULL, 0x8000,
1901                 "Qualifier Bit" } },
1902         { &hf_x25_qbit,
1903           { "D Bit", "x25.d", FT_BOOLEAN, 2, NULL, 0x4000,
1904                 "Delivery Confirmation Bit" } },
1905         { &hf_x25_mod,
1906           { "Modulo", "x25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000,
1907                 "Specifies whether the frame is modulo 8 or 128" } },
1908         { &hf_x25_lcn,
1909           { "Logical Channel", "x25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF,
1910                 "Logical Channel Number" } },
1911         { &hf_x25_type,
1912           { "Packet Type", "x25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0,
1913                 "Packet Type" } },
1914         { &hf_x25_p_r,
1915           { "P(R)", "x25.p_r", FT_UINT8, BASE_HEX, NULL, 0xE0,
1916                 "Packet Receive Sequence Number" } },
1917         { &hf_x25_mbit,
1918           { "M Bit", "x25.m", FT_BOOLEAN, 1, NULL, 0x10,
1919                 "More Bit" } },
1920         { &hf_x25_p_s,
1921           { "P(S)", "x25.p_s", FT_UINT8, BASE_HEX, NULL, 0x0E,
1922                 "Packet Send Sequence Number" } },
1923     };
1924
1925     static hf_register_info hf128[] = {
1926         { &hf_ex25_qbit,
1927           { "Q Bit", "ex25.q", FT_BOOLEAN, 2, NULL, 0x8000,
1928                 "Qualifier Bit" } },
1929         { &hf_ex25_qbit,
1930           { "D Bit", "ex25.d", FT_BOOLEAN, 2, NULL, 0x4000,
1931                 "Delivery Confirmation Bit" } },
1932         { &hf_ex25_mod,
1933           { "Modulo", "ex25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000,
1934                 "Specifies whether the frame is modulo 8 or 128" } },
1935         { &hf_ex25_lcn,
1936           { "Logical Channel", "ex25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF,
1937                 "Logical Channel Number" } },
1938         { &hf_ex25_type,
1939           { "Packet Type", "ex25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0,
1940                 "Packet Type" } },
1941         { &hf_ex25_p_r,
1942           { "P(R)", "ex25.p_r", FT_UINT8, BASE_HEX, NULL, 0xFE,
1943                 "Packet Receive Sequence Number" } },
1944         { &hf_ex25_mbit,
1945           { "M Bit", "ex25.m", FT_BOOLEAN, 1, NULL, 0x01,
1946                 "More Bit" } },
1947         { &hf_ex25_p_s,
1948           { "P(S)", "ex25.p_s", FT_UINT8, BASE_HEX, NULL, 0xFE,
1949                 "Packet Send Sequence Number" } },
1950     };
1951     static gint *ett[] = {
1952         &ett_x25,
1953         &ett_x25_fac,
1954         &ett_x25_fac_unknown,
1955         &ett_x25_fac_mark,
1956         &ett_x25_fac_reverse,
1957         &ett_x25_fac_throughput,
1958         &ett_x25_fac_cug,
1959         &ett_x25_fac_called_modif,
1960         &ett_x25_fac_cug_outgoing_acc,
1961         &ett_x25_fac_throughput_min,
1962         &ett_x25_fac_express_data,
1963         &ett_x25_fac_bilateral_cug,
1964         &ett_x25_fac_packet_size,
1965         &ett_x25_fac_window_size,
1966         &ett_x25_fac_rpoa_selection,
1967         &ett_x25_fac_transit_delay,
1968         &ett_x25_fac_call_transfer,
1969         &ett_x25_fac_called_addr_ext,
1970         &ett_x25_fac_ete_transit_delay,
1971         &ett_x25_fac_calling_addr_ext,
1972         &ett_x25_fac_call_deflect,
1973         &ett_x25_fac_priority
1974     };
1975
1976     proto_x25 = proto_register_protocol ("X.25", "x25");
1977     proto_ex25 = proto_register_protocol ("Extended X.25 (modulo 128)", "ex25");
1978     proto_register_field_array (proto_x25, hf8, array_length(hf8));
1979     proto_register_field_array (proto_ex25, hf128, array_length(hf128));
1980     proto_register_subtree_array(ett, array_length(ett));
1981     register_init_routine(&reinit_x25_hashtable);
1982 }
1983
1984 void
1985 proto_reg_handoff_x25(void)
1986 {
1987         dissector_add("ethertype", ETHERTYPE_X25L3, dissect_x25);
1988 }