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