48f7b67c92bd6d5204af22fb6bbcf3f1b0c47045
[obnox/wireshark/wip.git] / packet-x25.c
1 /* packet-x25.c
2  * Routines for x25 packet disassembly
3  * Olivier Abad <abad@daba.dhis.org>
4  *
5  * $Id: packet-x25.c,v 1.7 1999/10/12 06:20:20 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 "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_ADDR_EXT                0xCB
85 #define X25_FAC_CALL_DEFLECT            0xD1
86
87 int proto_x25 = -1;
88 int hf_x25_lcn = -1;
89 int hf_x25_type = -1;
90
91 /*
92  * each vc_info node contains :
93  *   the time of the first frame using this dissector (secs and usecs)
94  *   the time of the last frame using this dissector (0 if it is unknown)
95  *   a pointer to the dissector
96  *
97  * the "time of first frame" is initialized when a Call Req. is received
98  * the "time of last frame" is initialized when a Clear, Reset, or Restart
99  * is received
100  */
101 typedef struct _vc_info {
102         guint32 first_frame_secs, first_frame_usecs;
103         guint32 last_frame_secs, last_frame_usecs;
104         void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
105         struct _vc_info *next;
106 } vc_info;
107
108 /*
109  * the hash table will contain linked lists of global_vc_info
110  * each global_vc_info struct contains :
111  *   the VC number (the hash table is indexed with VC % 64)
112  *   a linked list of vc_info
113  */
114 typedef struct _global_vc_info {
115         int vc_num;
116         vc_info *info;
117         struct _global_vc_info *next;
118 } global_vc_info;
119
120 static global_vc_info *hash_table[64];
121
122 void
123 free_vc_info(vc_info *pt)
124 {
125   vc_info *vci = pt;
126
127   while (pt) {
128     vci = pt;
129     pt = pt->next;
130     g_free(vci);
131   }
132 }
133
134 void
135 init_dissect_x25()
136 {
137   int i;
138
139   for (i=0; i<64; i++) {
140     if (hash_table[i]) /* not NULL ==> free */
141     {
142       global_vc_info *hash_ent, *hash_ent2;
143       hash_ent2 = hash_ent = hash_table[i];
144       while (hash_ent)
145       {
146         hash_ent2 = hash_ent;
147         hash_ent = hash_ent->next;
148         free_vc_info(hash_ent2->info);
149         g_free(hash_ent2);
150       }
151       hash_table[i]=0;
152     }
153   }
154 }
155
156 void
157 x25_hash_add_proto_start(guint16 vc, guint32 frame_secs, guint32 frame_usecs,
158                          void (*dissect)(const u_char *, int, frame_data *,
159                                        proto_tree *))
160 {
161   int idx = vc % 64;
162   global_vc_info *hash_ent;
163   global_vc_info *hash_ent2;
164
165   if (hash_table[idx] == 0)
166   {
167     hash_ent = (global_vc_info *)g_malloc(sizeof(global_vc_info));
168     if (!hash_ent) {
169       fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
170       exit(1);
171     }
172     hash_ent->vc_num = vc;
173     hash_ent->next=0;
174     hash_ent->info = (vc_info *)g_malloc(sizeof(vc_info));
175     if (!hash_ent->info) {
176       fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
177       exit(1);
178     }
179     hash_ent->info->first_frame_secs = frame_secs;
180     hash_ent->info->first_frame_usecs = frame_usecs;
181     hash_ent->info->last_frame_secs = 0;
182     hash_ent->info->last_frame_usecs = 0;
183     hash_ent->info->dissect = dissect;
184     hash_ent->info->next = 0;
185     hash_table[idx] = hash_ent;
186   }
187   else
188   {
189     hash_ent2 = hash_ent = hash_table[idx];
190     /* search an entry with the same VC number */
191     while (hash_ent != NULL && hash_ent->vc_num != vc) {
192       hash_ent2 = hash_ent;
193       hash_ent = hash_ent->next;
194     }
195     if (hash_ent != NULL) /* hash_ent->vc_num == vc */
196     {
197       vc_info *vci = hash_ent->info;
198       while (vci->next) vci = vci->next; /* last element */
199       if (vci->dissect == dissect) {
200         vci->last_frame_secs = 0;
201         vci->last_frame_usecs = 0;
202       }
203       else {
204         vci->next = (vc_info *)g_malloc(sizeof(vc_info));
205         if (vci->next == 0) {
206           fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
207           exit(1);
208         }
209         vci->next->first_frame_secs = frame_secs;
210         vci->next->first_frame_usecs = frame_usecs;
211         vci->next->last_frame_secs = 0;
212         vci->next->last_frame_usecs = 0;
213         vci->next->dissect = dissect;
214         vci->next->next = 0;
215       }
216     }
217     else /* new vc number */
218     {
219       hash_ent2->next = (global_vc_info *)g_malloc(sizeof(global_vc_info));
220       if (!hash_ent2->next) {
221         fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
222         exit(1);
223       }
224       hash_ent2->next->info = (vc_info *)g_malloc(sizeof(vc_info));
225       if (!hash_ent2->next->info) {
226         fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
227         exit(1);
228       }
229       hash_ent2->next->info->first_frame_secs = frame_secs;
230       hash_ent2->next->info->first_frame_usecs = frame_usecs;
231       hash_ent2->next->info->last_frame_secs = 0;
232       hash_ent2->next->info->last_frame_usecs = 0;
233       hash_ent2->next->info->dissect = dissect;
234       hash_ent2->next->info->next = 0;
235     }
236   }
237 }
238
239 void
240 x25_hash_add_proto_end(guint16 vc, guint32 frame_secs, guint32 frame_usecs)
241 {
242   global_vc_info *hash_ent = hash_table[vc%64];
243   vc_info *vci;
244
245   if (!hash_ent) return;
246   while(hash_ent->vc_num != vc) hash_ent = hash_ent->next;
247   if (!hash_ent) return;
248
249   vci = hash_ent->info;
250   while (vci->next) vci = vci->next;
251   vci->last_frame_secs = frame_secs;
252   vci->last_frame_usecs = frame_usecs;
253 }
254
255 void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc))(const u_char *, int, frame_data *, proto_tree *)
256 {
257   global_vc_info *hash_ent = hash_table[vc%64];
258   vc_info *vci;
259   vc_info *vci2;
260
261   if (!hash_ent) return 0;
262
263   while(hash_ent && hash_ent->vc_num != vc) hash_ent = hash_ent->next;
264   if (!hash_ent) return 0;
265
266   /* a hash_ent was found for this VC number */
267   vci2 = vci = hash_ent->info;
268
269   /* looking for an entry matching our frame time */
270   while (vci && (vci->last_frame_secs < frame_secs ||
271                  (vci->last_frame_secs == frame_secs &&
272                   vci->last_frame_usecs < frame_usecs))) {
273     vci2 = vci;
274     vci = vci->next;
275   }
276   /* we reached last record, and previous record has a non zero
277    * last frame time ==> no dissector */
278   if (!vci && (vci2->last_frame_secs || vci2->last_frame_usecs)) return 0;
279
280   /* we reached last record, and previous record has a zero last frame time
281    * ==> dissector for previous frame has not been "stopped" by a Clear, etc */
282   if (!vci) {
283     /* if the start time for vci2 is greater than our frame time
284      * ==> no dissector */
285     if (frame_secs < vci2->first_frame_secs ||
286         (frame_secs == vci2->first_frame_secs &&
287          frame_usecs < vci2->first_frame_usecs))
288       return 0;
289     else
290       return vci2->dissect;
291   }
292
293   /* our frame time is before vci's end. Check if it is adter vci's start */
294   if (frame_secs < vci->first_frame_secs ||
295       (frame_secs == vci->first_frame_secs &&
296        frame_usecs < vci->first_frame_usecs))
297     return 0;
298   else
299     return vci->dissect;
300 }
301
302 static char *clear_code(unsigned char code)
303 {
304     static char buffer[25];
305
306     if (code == 0x00 || (code & 0x80) == 0x80)
307         return "DTE Originated";
308     if (code == 0x01)
309         return "Number Busy";
310     if (code == 0x09)
311         return "Out Of Order";
312     if (code == 0x11)
313         return "Remote Procedure Error";
314     if (code == 0x19)
315         return "Reverse Charging Acceptance Not Subscribed";
316     if (code == 0x21)
317         return "Incompatible Destination";
318     if (code == 0x29)
319         return "Fast Select Acceptance Not Subscribed";
320     if (code == 0x39)
321         return "Destination Absent";
322     if (code == 0x03)
323         return "Invalid Facility Requested";
324     if (code == 0x0B)
325         return "Access Barred";
326     if (code == 0x13)
327         return "Local Procedure Error";
328     if (code == 0x05)
329         return "Network Congestion";
330     if (code == 0x0D)
331         return "Not Obtainable";
332     if (code == 0x15)
333         return "RPOA Out Of Order";
334
335     sprintf(buffer, "Unknown %02X", code);
336
337     return buffer;
338 }
339
340 static char *clear_diag(unsigned char code)
341 {
342     static char buffer[25];
343
344     if (code == 0)
345         return "No additional information";
346     if (code == 1)
347         return "Invalid P(S)";
348     if (code == 2)
349         return "Invalid P(R)";
350     if (code == 16)
351         return "Packet type invalid";
352     if (code == 17)
353         return "Packet type invalid for state r1";
354     if (code == 18)
355         return "Packet type invalid for state r2";
356     if (code == 19)
357         return "Packet type invalid for state r3";
358     if (code == 20)
359         return "Packet type invalid for state p1";
360     if (code == 21)
361         return "Packet type invalid for state p2";
362     if (code == 22)
363         return "Packet type invalid for state p3";
364     if (code == 23)
365         return "Packet type invalid for state p4";
366     if (code == 24)
367         return "Packet type invalid for state p5";
368     if (code == 25)
369         return "Packet type invalid for state p6";
370     if (code == 26)
371         return "Packet type invalid for state p7";
372     if (code == 27)
373         return "Packet type invalid for state d1";
374     if (code == 28)
375         return "Packet type invalid for state d2";
376     if (code == 29)
377         return "Packet type invalid for state d3";
378     if (code == 32)
379         return "Packet not allowed";
380     if (code == 33)
381         return "Unidentifiable packet";
382     if (code == 34)
383         return "Call on one-way logical channel";
384     if (code == 35)
385         return "Invalid packet type on a PVC";
386     if (code == 36)
387         return "Packet on unassigned LC";
388     if (code == 37)
389         return "Reject not subscribed to";
390     if (code == 38)
391         return "Packet too short";
392     if (code == 39)
393         return "Packet too long";
394     if (code == 40)
395         return "Invalid general format identifier";
396     if (code == 41)
397         return "Restart/registration packet with nonzero bits";
398     if (code == 42)
399         return "Packet type not compatible with facility";
400     if (code == 43)
401         return "Unauthorised interrupt confirmation";
402     if (code == 44)
403         return "Unauthorised interrupt";
404     if (code == 45)
405         return "Unauthorised reject";
406     if (code == 48)
407         return "Time expired";
408     if (code == 49)
409         return "Time expired for incoming call";
410     if (code == 50)
411         return "Time expired for clear indication";
412     if (code == 51)
413         return "Time expired for reset indication";
414     if (code == 52)
415         return "Time expired for restart indication";
416     if (code == 53)
417         return "Time expired for call deflection";
418     if (code == 64)
419         return "Call set-up/clearing or registration pb.";
420     if (code == 65)
421         return "Facility/registration code not allowed";
422     if (code == 66)
423         return "Facility parameter not allowed";
424     if (code == 67)
425         return "Invalid called DTE address";
426     if (code == 68)
427         return "Invalid calling DTE address";
428     if (code == 69)
429         return "Invalid facility/registration length";
430     if (code == 70)
431         return "Incoming call barred";
432     if (code == 71)
433         return "No logical channel available";
434     if (code == 72)
435         return "Call collision";
436     if (code == 73)
437         return "Duplicate facility requested";
438     if (code == 74)
439         return "Non zero address length";
440     if (code == 75)
441         return "Non zero facility length";
442     if (code == 76)
443         return "Facility not provided when expected";
444     if (code == 77)
445         return "Invalid CCITT-specified DTE facility";
446     if (code == 78)
447         return "Max. nb of call redir/defl. exceeded";
448     if (code == 80)
449         return "Miscellaneous";
450     if (code == 81)
451         return "Improper cause code from DTE";
452     if (code == 82)
453         return "Not aligned octet";
454     if (code == 83)
455         return "Inconsistent Q bit setting";
456     if (code == 84)
457         return "NUI problem";
458     if (code == 112)
459         return "International problem";
460     if (code == 113)
461         return "Remote network problem";
462     if (code == 114)
463         return "International protocol problem";
464     if (code == 115)
465         return "International link out of order";
466     if (code == 116)
467         return "International link busy";
468     if (code == 117)
469         return "Transit network facility problem";
470     if (code == 118)
471         return "Remote network facility problem";
472     if (code == 119)
473         return "International routing problem";
474     if (code == 120)
475         return "Temporary routing problem";
476     if (code == 121)
477         return "Unknown called DNIC";
478     if (code == 122)
479         return "Maintenance action";
480
481     sprintf(buffer, "Unknown %d", code);
482
483     return buffer;
484 }
485
486 static char *reset_code(unsigned char code)
487 {
488     static char buffer[25];
489
490     if (code == 0x00 || (code & 0x80) == 0x80)
491         return "DTE Originated";
492     if (code == 0x01)
493         return "Out of order";
494     if (code == 0x03)
495         return "Remote Procedure Error";
496     if (code == 0x05)
497         return "Local Procedure Error";
498     if (code == 0x07)
499         return "Network Congestion";
500     if (code == 0x09)
501         return "Remote DTE operational";
502     if (code == 0x0F)
503         return "Network operational";
504     if (code == 0x11)
505         return "Incompatible Destination";
506     if (code == 0x1D)
507         return "Network out of order";
508
509     sprintf(buffer, "Unknown %02X", code);
510
511     return buffer;
512 }
513
514 static char *restart_code(unsigned char code)
515 {
516     static char buffer[25];
517
518     if (code == 0x00 || (code & 0x80) == 0x80)
519         return "DTE Originated";
520     if (code == 0x01)
521         return "Local Procedure Error";
522     if (code == 0x03)
523         return "Network Congestion";
524     if (code == 0x07)
525         return "Network Operational";
526     if (code == 0x7F)
527         return "Registration/cancellation confirmed";
528
529     sprintf(buffer, "Unknown %02X", code);
530
531     return buffer;
532 }
533
534 static char *registration_code(unsigned char code)
535 {
536     static char buffer[25];
537
538     if (code == 0x03)
539         return "Invalid facility request";
540     if (code == 0x05)
541         return "Network congestion";
542     if (code == 0x13)
543         return "Local procedure error";
544     if (code == 0x7F)
545         return "Registration/cancellation confirmed";
546
547     sprintf(buffer, "Unknown %02X", code);
548
549     return buffer;
550 }
551
552 void
553 dump_facilities(proto_tree *tree, int *offset, const guint8 *p)
554 {
555     const guint8 *ptr = p;
556     guint32 len;      /* facilities length */
557
558     len = *ptr++;
559     if (len && tree)
560         proto_tree_add_text(tree, *offset, 1,
561                             "Facilities length: %d", len);
562     (*offset)++;
563
564     while (len > 0) {
565         switch(*ptr & X25_FAC_CLASS_MASK) {
566         case X25_FAC_CLASS_A:
567             switch (*ptr) {
568             case X25_FAC_COMP_MARK:
569                 switch (ptr[1]) {
570                 case 0x00:
571                     if (tree)
572                         proto_tree_add_text(tree, *offset, 2,
573                                             "Network complementary services - calling DTE");
574                     break;
575                 case 0xFF:
576                     if (tree)
577                         proto_tree_add_text(tree, *offset, 2,
578                                             "Network complementary services - called DTE");
579                     break;
580                 case 0x0F:
581                     if (tree)
582                         proto_tree_add_text(tree, *offset, 2,
583                                             "DTE complementary services");
584                     break;
585                 default:
586                     if (tree)
587                         proto_tree_add_text(tree, *offset, 2,
588                                             "Unknown marker");
589                     break;
590                 }
591                 break;
592             case X25_FAC_REVERSE:
593                 if (tree) {
594                     if (ptr[1] & 0x01)
595                         proto_tree_add_text(tree, *offset, 2,
596                                             "Reverse Charging");
597                     else
598                         proto_tree_add_text(tree, *offset, 2,
599                                             "No Reverse Charging");
600                     if (ptr[1] & 0xC0)
601                         proto_tree_add_text(tree, *offset, 2,
602                                             "Fast select with restriction");
603                     else if (ptr[1] & 0x80)
604                         proto_tree_add_text(tree, *offset, 2,
605                                             "Fast select - no restriction");
606                     else
607                         proto_tree_add_text(tree, *offset, 2,
608                                             "No Fast select");
609                 }
610                 break;
611             case X25_FAC_THROUGHPUT:
612                 if (tree) {
613                     int called_dte_throughput=0;
614                     int calling_dte_throughput=0;
615
616                     if ( (ptr[1] >> 4) >= 3 && (ptr[1] >> 4) <= 13 )
617                         called_dte_throughput = 75*2^((ptr[1] >> 4)-3);
618                     if ( (ptr[1] & 0x0F) >= 3 && (ptr[1] & 0x0F) <= 13 )
619                         calling_dte_throughput = 75*2^((ptr[1] & 0x0F)-3);
620                     proto_tree_add_text(tree, *offset, 2,
621                             "Throughput: called DTE: %d - calling DTE: %d",
622                             called_dte_throughput, calling_dte_throughput);
623                 }
624                 break;
625             case X25_FAC_CUG:
626                 if (tree)
627                     proto_tree_add_text(tree, *offset, 2,
628                                         "Closed user group: %d%d",
629                                         ptr[1] >> 4, ptr[1] & 0x0F);
630                 break;
631             case X25_FAC_CALLED_MODIF:
632                 if (tree)
633                     proto_tree_add_text(tree, *offset, 2,
634                                         "Called address modified: %02X",
635                                         ptr[1]);
636                 break;
637             case X25_FAC_CUG_OUTGOING_ACC:
638                 if (tree)
639                     proto_tree_add_text(tree, *offset, 2,
640                                         "CUG with outgoing access: %d%d",
641                                         ptr[1]>>4, ptr[1] & 0x0F);
642                 break;
643             case X25_FAC_THROUGHPUT_MIN:
644                 if (tree)
645                     proto_tree_add_text(tree, *offset, 2,
646                                         "Minimum throughput class");
647                 break;
648             case X25_FAC_EXPRESS_DATA:
649                 if (tree)
650                     proto_tree_add_text(tree, *offset, 2,
651                                         "Negociation of express data");
652                 break;
653             default:
654                 if (tree)
655                     proto_tree_add_text(tree, *offset, 2,
656                                         "Unknown facility %02X, value %02X",
657                                         ptr[0], ptr[1]);
658                 break;
659             }
660             (*offset) += 2;
661             len -= 2;
662             ptr += 2;
663             break;
664         case X25_FAC_CLASS_B:
665             switch (*ptr) {
666             case X25_FAC_BILATERAL_CUG:
667                 if (tree)
668                     proto_tree_add_text(tree, *offset, 3,
669                                         "Bilateral CUG: %d%d%d%d",
670                                         ptr[1] >> 4,
671                                         ptr[1] & 0x0F,
672                                         ptr[2] >> 4,
673                                         ptr[2] & 0x0F);
674                 break;
675             case X25_FAC_PACKET_SIZE:
676                 if (tree)
677                 {
678                     int called_dte_size, calling_dte_size;
679
680                     switch (ptr[1])
681                     {
682                     case 0x04:
683                         called_dte_size = 16;
684                         break;
685                     case 0x05:
686                         called_dte_size = 32;
687                         break;
688                     case 0x06:
689                         called_dte_size = 64;
690                         break;
691                     case 0x07:
692                         called_dte_size = 128;
693                         break;
694                     case 0x08:
695                         called_dte_size = 256;
696                         break;
697                     case 0x0D:
698                         called_dte_size = 512;
699                         break;
700                     case 0x0C:
701                         called_dte_size = 1024;
702                         break;
703                     case 0x0E:
704                         called_dte_size = 2048;
705                         break;
706                     case 0x0F:
707                         called_dte_size = 4096;
708                         break;
709                     default:
710                         called_dte_size = 0;
711                         break;
712                     }
713
714                     switch (ptr[2])
715                     {
716                     case 0x04:
717                         calling_dte_size = 16;
718                         break;
719                     case 0x05:
720                         calling_dte_size = 32;
721                         break;
722                     case 0x06:
723                         calling_dte_size = 64;
724                         break;
725                     case 0x07:
726                         calling_dte_size = 128;
727                         break;
728                     case 0x08:
729                         calling_dte_size = 256;
730                         break;
731                     case 0x0D:
732                         calling_dte_size = 512;
733                         break;
734                     case 0x0C:
735                         calling_dte_size = 1024;
736                         break;
737                     case 0x0E:
738                         calling_dte_size = 2048;
739                         break;
740                     case 0x0F:
741                         calling_dte_size = 4096;
742                         break;
743                     default:
744                         calling_dte_size = 0;
745                         break;
746                     }
747                     proto_tree_add_text(tree, *offset, 3,
748                             "Packet Size: called DTE: %d - calling DTE: %d",
749                             called_dte_size,
750                             calling_dte_size);
751                 }
752                 break;
753             case X25_FAC_WINDOW_SIZE:
754                 if (tree)
755                     proto_tree_add_text(tree, *offset, 3,
756                             "Window Size: called DTE: %d - calling DTE: %d",
757                             ptr[1], ptr[2]);
758                 break;
759             case X25_FAC_RPOA_SELECTION:
760                 if (tree)
761                     proto_tree_add_text(tree, *offset, 3,
762                                         "RPOA: %d%d%d%d",
763                                         ptr[1] >> 4,
764                                         ptr[1] & 0x0F,
765                                         ptr[2] >> 4,
766                                         ptr[2] & 0x0F);
767                 break;
768             case X25_FAC_TRANSIT_DELAY:
769                 if (tree)
770                     proto_tree_add_text(tree, *offset, 3,
771                                         "Transit delay: %d",
772                                         (ptr[1]<<8) + ptr[2]);
773                 break;
774             default:
775                 if (tree)
776                     proto_tree_add_text(tree, *offset, 3,
777                                         "Unknown facility %02X, values %02X%02X",
778                                         ptr[0], ptr[1], ptr[2]);
779                 break;
780             }
781             (*offset) += 3;
782             len -= 3;
783             ptr += 3;
784             break;
785         case X25_FAC_CLASS_C:
786             if (tree)
787                 proto_tree_add_text(tree, *offset, 4,
788                                     "Unknown facility %02X, values %02X%02X%02X",
789                                     ptr[0], ptr[1], ptr[2], ptr[3]);
790             (*offset) += 4;
791             len -= 4;
792             ptr += 4;
793             break;
794         case X25_FAC_CLASS_D:
795             switch (*ptr) {
796             case X25_FAC_CALL_TRANSFER:
797                 if (tree)
798                     proto_tree_add_text(tree, *offset, 2+ptr[1],
799                                         "Call Transfer: reason = %02X",
800                                         ptr[2]);
801                 break;
802             case X25_FAC_ADDR_EXT:
803                 if (tree)
804                     proto_tree_add_text(tree, *offset, 2+ptr[1],
805                                         "Address extension");
806                 break;
807             case X25_FAC_CALLED_ADDR_EXT:
808                 if (tree)
809                     proto_tree_add_text(tree, *offset, 2+ptr[1],
810                                         "Called address extension");
811                 break;
812             case X25_FAC_ETE_TRANSIT_DELAY:
813                 if (tree)
814                     proto_tree_add_text(tree, *offset, 2+ptr[1],
815                                         "End to end transit delay");
816                 break;
817             case X25_FAC_CALL_DEFLECT:
818                 if (tree)
819                     proto_tree_add_text(tree, *offset, 2+ptr[1],
820                                         "Call deflection: reason = %02X",
821                                         ptr[2]);
822                 break;
823             default:
824                 if (tree)
825                     proto_tree_add_text(tree, *offset, 2+ptr[1],
826                                         "Unknown facility %02X, length %02X",
827                                         ptr[0], ptr[1]);
828             }
829             (*offset) += ptr[1]+2;
830             len -= ptr[1]+2;
831             ptr += ptr[1]+2;
832             break;
833         }
834     }
835 }
836
837 void
838 x25_ntoa(proto_tree *tree, int *offset, const guint8 *p,
839          frame_data *fd, gboolean toa)
840 {
841     int len1, len2;
842     int i;
843     char addr1[16], addr2[16];
844     char *first, *second;
845
846     len1  = (*p >> 0) & 0x0F;
847     len2 = (*p >> 4) & 0x0F;
848     if (tree) {
849         proto_tree_add_text(tree, *offset, 1,
850                 "%s address length : %d",
851                 toa ? "Called" : "Calling",
852                 len1);
853         proto_tree_add_text(tree, *offset, 1,
854                 "%s address length : %d",
855                 toa ? "Calling" : "Called",
856                 len2);
857     }
858     (*offset)++;
859
860     p++;
861
862     first=addr1;
863     second=addr2;
864     for (i = 0; i < (len1 + len2); i++) {
865         if (i < len1) {
866             if (i % 2 != 0) {
867                 *first++ = ((*p >> 0) & 0x0F) + '0';
868                 p++;
869             } else {
870                 *first++ = ((*p >> 4) & 0x0F) + '0';
871             }
872         } else {
873             if (i % 2 != 0) {
874                 *second++ = ((*p >> 0) & 0x0F) + '0';
875                 p++;
876             } else {
877                 *second++ = ((*p >> 4) & 0x0F) + '0';
878             }
879         }
880     }
881
882     *first  = '\0';
883     *second = '\0';
884
885     if (len1) {
886         if(check_col(fd, COL_RES_DL_DST))
887             col_add_str(fd, COL_RES_DL_DST, addr1);
888         if (tree)
889             proto_tree_add_text(tree, *offset,
890                                 (len1 + 1) / 2,
891                                 "%s address : %s",
892                                 toa ? "Called" : "Calling",
893                                 addr1);
894     }
895     if (len2) {
896         if(check_col(fd, COL_RES_DL_SRC))
897             col_add_str(fd, COL_RES_DL_SRC, addr2);
898         if (tree)
899             proto_tree_add_text(tree, *offset + len1/2,
900                                 (len2+1)/2+(len1%2+(len2+1)%2)/2,
901                                 "%s address : %s",
902                                 toa ? "Calling" : "Called",
903                                 addr2);
904     }
905     (*offset) += ((len1 + len2 + 1) / 2);
906 }
907
908 int
909 get_x25_pkt_len(const char *data, frame_data *fd, int offset)
910 {
911     int length, called_len, calling_len, dte_len, dce_len;
912
913     /* packet size should always be > 3 */
914     if (fd->cap_len - offset < 3) return fd->cap_len;
915
916     switch ((guint8)data[2])
917     {
918     case X25_CALL_REQUEST:
919         if (fd->cap_len > offset+3) /* pkt size > 3 */
920         {
921             called_len  = (data[3] >> 0) & 0x0F;
922             calling_len = (data[3] >> 4) & 0x0F;
923             length = 4 + (called_len + calling_len + 1) / 2; /* addr */
924             if (length+offset < fd->cap_len)
925                 length += (1 + data[length]); /* facilities */
926         }
927         else length = fd->cap_len - offset;
928         return MIN(fd->cap_len-offset,length);
929
930     case X25_CALL_ACCEPTED:
931         if (fd->cap_len > offset+3) /* pkt size > 3 */
932         {
933             called_len  = (data[3] >> 0) & 0x0F;
934             calling_len = (data[3] >> 4) & 0x0F;
935             length = 4 + (called_len + calling_len + 1) / 2; /* addr */
936             if (length+offset < fd->cap_len)
937                 length += (1 + data[length]); /* facilities */
938         }
939         else length = fd->cap_len - offset;
940         return MIN(fd->cap_len-offset,length);
941
942     case X25_CLEAR_REQUEST:
943     case X25_RESET_REQUEST:
944     case X25_RESTART_REQUEST:
945         return MIN(fd->cap_len-offset,5);
946
947     case X25_DIAGNOSTIC:
948         return MIN(fd->cap_len-offset,4);
949
950     case X25_CLEAR_CONFIRMATION:
951     case X25_INTERRUPT:
952     case X25_INTERRUPT_CONFIRMATION:
953     case X25_RESET_CONFIRMATION:
954     case X25_RESTART_CONFIRMATION:
955         return MIN(fd->cap_len-offset,3);
956
957     case X25_REGISTRATION_REQUEST:
958         if (fd->cap_len > offset+3) /* pkt size > 3 */
959         {
960             dce_len  = (data[3] >> 0) & 0x0F;
961             dte_len = (data[3] >> 4) & 0x0F;
962             length = 4 + (dte_len + dce_len + 1) / 2; /* addr */
963             if (length+offset < fd->cap_len)
964                 length += (1 + data[length]); /* registration */
965         }
966         else length = fd->cap_len-offset;
967         return MIN(fd->cap_len-offset,length);
968
969     case X25_REGISTRATION_CONFIRMATION:
970         if (fd->cap_len > offset+5) /* pkt size > 5 */
971         {
972             dce_len  = (data[5] >> 0) & 0x0F;
973             dte_len = (data[5] >> 4) & 0x0F;
974             length = 6 + (dte_len + dce_len + 1) / 2; /* addr */
975             if (length+offset < fd->cap_len)
976                 length += (1 + data[length]); /* registration */
977         }
978         else length = fd->cap_len-offset;
979         return MIN(fd->cap_len-offset,length);
980     }
981             
982     if ((data[2] & 0x01) == X25_DATA) return MIN(fd->cap_len-offset,3);
983
984     switch (data[2] & 0x1F)
985     {
986     case X25_RR:
987         return MIN(fd->cap_len-offset,3);
988
989     case X25_RNR:
990         return MIN(fd->cap_len-offset,3);
991
992     case X25_REJ:
993         return MIN(fd->cap_len-offset,3);
994     }
995
996     return 0;
997 }
998
999 void
1000 dissect_x25(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1001 {
1002     proto_tree *x25_tree=0, *ti;
1003     int localoffset=offset;
1004     int x25_pkt_len;
1005     int modulo;
1006     guint16 vc;
1007     void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
1008     gboolean toa=FALSE;
1009
1010     if (check_col(fd, COL_PROTOCOL))
1011         col_add_str(fd, COL_PROTOCOL, "X.25");
1012
1013     modulo = ((pd[localoffset] & 0x20) ? 128 : 8);
1014     x25_pkt_len = get_x25_pkt_len(&pd[localoffset], fd, offset);
1015     if (x25_pkt_len < 3) /* packet too short */
1016     {
1017         if (check_col(fd, COL_INFO))
1018             col_add_str(fd, COL_INFO, "Invalid/short X.25 packet");
1019         if (tree)
1020             proto_tree_add_item_format(tree, proto_x25, localoffset,
1021                     fd->cap_len - offset, NULL, "Invalid/short X.25 packet");
1022         return;
1023     }
1024     vc = (int)(pd[localoffset] & 0x0F) + (int)pd[localoffset+1];
1025     if (tree) {
1026         ti = proto_tree_add_item(tree, proto_x25, localoffset, x25_pkt_len,
1027                                  NULL);
1028         x25_tree = proto_item_add_subtree(ti, ETT_X25);
1029         proto_tree_add_text(x25_tree, localoffset, 1,
1030                             "GFI : Q: %d, D: %d, Mod: %d",
1031                             (pd[localoffset] & 0x80) ? 1 : 0,
1032                             (pd[localoffset] & 0x40) ? 1 : 0,
1033                             modulo);
1034         proto_tree_add_item_format(x25_tree, hf_x25_lcn, localoffset, 2,
1035                                    (int)(pd[localoffset] & 0x0F) +
1036                                    (int)pd[localoffset+1],
1037                                    "Logical channel : %3.3X",
1038                                    vc);
1039     }
1040     switch (pd[localoffset+2]) {
1041     case X25_CALL_REQUEST:
1042         if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1043             toa = TRUE;
1044
1045         if(check_col(fd, COL_INFO))
1046             col_add_fstr(fd, COL_INFO, "%s VC:%d",
1047                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Inc. call"
1048                                                              : "Call req." ,
1049                     vc);
1050         if (x25_tree)
1051             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1052                     "CALL",
1053                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Incoming call"
1054                                                              : "Call request");
1055         localoffset += 3;
1056         if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1057             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1058
1059         if (localoffset < x25_pkt_len+offset) /* facilities */
1060             dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1061
1062         if (localoffset < fd->cap_len) /* user data */
1063         {
1064             if (pd[localoffset] == 0xCC)
1065             {
1066                 x25_hash_add_proto_start(vc, fd->abs_secs,
1067                                          fd->abs_usecs, dissect_ip);
1068                 if (x25_tree)
1069                     proto_tree_add_text(x25_tree, localoffset, 1,
1070                                         "pid = IP");
1071                 localoffset++;
1072             }
1073             else if (pd[localoffset] == 0x03 &&
1074                      pd[localoffset+1] == 0x01 &&
1075                      pd[localoffset+2] == 0x01 &&
1076                      pd[localoffset+3] == 0x00)
1077             {
1078                 x25_hash_add_proto_start(vc, fd->abs_secs,
1079                                          fd->abs_usecs, dissect_cotp);
1080                 if (x25_tree)
1081                     proto_tree_add_text(x25_tree, localoffset, 4,
1082                                         "pid = COTP");
1083                 localoffset += 4;
1084             }
1085             else {
1086                 if (x25_tree)
1087                     proto_tree_add_text(x25_tree, localoffset,
1088                                         fd->cap_len-localoffset, "Data");
1089                 localoffset = fd->cap_len;
1090             }
1091         }
1092         break;
1093     case X25_CALL_ACCEPTED:
1094         if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1095             toa = TRUE;
1096
1097         if(check_col(fd, COL_INFO))
1098             col_add_fstr(fd, COL_INFO, "%s VC:%d",
1099                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Call conn."
1100                                                              : "Call acc." ,
1101                     vc);
1102         if (x25_tree)
1103             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1104                     "CALL ACC",
1105                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Call connected"
1106                                                              : "Call accepted");
1107         localoffset += 3;
1108         if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1109             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1110
1111         if (localoffset < x25_pkt_len+offset) /* facilities */
1112             dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1113
1114         if (localoffset < fd->cap_len) { /* user data */
1115             if (x25_tree)
1116                 proto_tree_add_text(x25_tree, localoffset,
1117                                     fd->cap_len-localoffset, "Data");
1118             localoffset=fd->cap_len;
1119         }
1120         break;
1121     case X25_CLEAR_REQUEST:
1122         if(check_col(fd, COL_INFO)) {
1123             col_add_fstr(fd, COL_INFO, "%s VC:%d %s - %s",
1124                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Clear ind."
1125                                                              : "Clear req." ,
1126                     vc, clear_code(pd[localoffset+3]),
1127                     clear_diag(pd[localoffset+4]));
1128         }
1129         x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1130         if (x25_tree) {
1131             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1132                     "CLEAR",
1133                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Clear indication"
1134                                                              : "Clear request");
1135             if (localoffset+3 < x25_pkt_len+offset)
1136                 proto_tree_add_text(x25_tree, localoffset+3, 1,
1137                         "Cause : %s", clear_code(pd[localoffset+3]));
1138             if (localoffset+4 < x25_pkt_len+offset)
1139                 proto_tree_add_text(x25_tree, localoffset+4, 1,
1140                         "Diagnostic : %s",
1141                         clear_diag(pd[localoffset+4]));
1142         }
1143         localoffset += x25_pkt_len;
1144         break;
1145     case X25_CLEAR_CONFIRMATION:
1146         if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1147             toa = TRUE;
1148
1149         if(check_col(fd, COL_INFO))
1150             col_add_fstr(fd, COL_INFO, "Clear Conf. VC:%d", vc);
1151         if (x25_tree)
1152             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1153                                        "CLEAR CONF", "Clear confirmation");
1154         localoffset += x25_pkt_len;
1155
1156         if (localoffset < fd->cap_len) /* extended clear conf format */
1157             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1158
1159         if (localoffset < fd->cap_len) /* facilities */
1160             dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1161         break;
1162     case X25_DIAGNOSTIC:
1163         if(check_col(fd, COL_INFO)) {
1164             col_add_fstr(fd, COL_INFO, "Diag. VC:%d %d",
1165                     vc, (int)pd[localoffset+3]);
1166         }
1167         if (x25_tree) {
1168             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1169                                        "DIAG", "Diagnostic");
1170             if (localoffset+3 < x25_pkt_len+offset)
1171                 proto_tree_add_text(x25_tree, localoffset+3, 1,
1172                         "Diagnostic : %d", (int)pd[localoffset+3]);
1173         }
1174         localoffset += x25_pkt_len;
1175         break;
1176     case X25_INTERRUPT:
1177         if(check_col(fd, COL_INFO))
1178             col_add_fstr(fd, COL_INFO, "Interrupt VC:%d", vc);
1179         if (x25_tree)
1180             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1181                                        "INTR", "Interrupt");
1182         localoffset += x25_pkt_len;
1183         break;
1184     case X25_INTERRUPT_CONFIRMATION:
1185         if(check_col(fd, COL_INFO))
1186             col_add_fstr(fd, COL_INFO, "Interrupt Conf. VC:%d", vc);
1187         if (x25_tree)
1188             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1189                                        "INTR CONF", "Interrupt confirmation");
1190         localoffset += x25_pkt_len;
1191         break;
1192     case X25_RESET_REQUEST:
1193         if(check_col(fd, COL_INFO)) {
1194             col_add_fstr(fd, COL_INFO, "%s VC:%d %s - Diag.:%d",
1195                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset ind."
1196                                                              : "Reset req.",
1197                     vc, reset_code(pd[localoffset+3]),
1198                     (int)pd[localoffset+4]);
1199         }
1200         x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1201         if (x25_tree) {
1202             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1203                     "RESET",
1204                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset indication"
1205                                                              : "Reset request");
1206             if (localoffset+3 < x25_pkt_len+offset)
1207                 proto_tree_add_text(x25_tree, localoffset+3, 1,
1208                         "Cause : %s", reset_code(pd[localoffset+3]));
1209             if (localoffset+4 < x25_pkt_len+offset)
1210                 proto_tree_add_text(x25_tree, localoffset+4, 1,
1211                         "Diagnostic : %d", (int)pd[localoffset+4]);
1212         }
1213         localoffset += x25_pkt_len;
1214         break;
1215     case X25_RESET_CONFIRMATION:
1216         if(check_col(fd, COL_INFO))
1217             col_add_fstr(fd, COL_INFO, "Reset conf. VC:%d", vc);
1218         if (x25_tree)
1219             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1220                                        "RESET CONF", "Reset confirmation");
1221         localoffset += x25_pkt_len;
1222         break;
1223     case X25_RESTART_REQUEST:
1224         if(check_col(fd, COL_INFO)) {
1225             col_add_fstr(fd, COL_INFO, "%s VC:%d %s - Diag.:%d",
1226                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Restart ind."
1227                                                              : "Restart req.",
1228                     vc, restart_code(pd[localoffset+3]),
1229                     (int)pd[localoffset+4]);
1230         }
1231         x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1232         if (x25_tree) {
1233             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1234                     "RESTART",
1235                     (fd->pseudo_header.x25.flags & FROM_DCE) ? "Restart indication"
1236                                                              : "Restart request");
1237             if (localoffset+3 < x25_pkt_len+offset)
1238                 proto_tree_add_text(x25_tree, localoffset+3, 1,
1239                         "Cause : %s", restart_code(pd[localoffset+3]));
1240             if (localoffset+4 < x25_pkt_len+offset)
1241                 proto_tree_add_text(x25_tree, localoffset+4, 1,
1242                         "Diagnostic : %d", (int)pd[localoffset+4]);
1243         }
1244         localoffset += x25_pkt_len;
1245         break;
1246     case X25_RESTART_CONFIRMATION:
1247         if(check_col(fd, COL_INFO))
1248             col_add_fstr(fd, COL_INFO, "Restart conf. VC:%d", vc);
1249         if (x25_tree)
1250             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1251                                        "RESTART CONF", "Restart confirmation");
1252         localoffset += x25_pkt_len;
1253         break;
1254     case X25_REGISTRATION_REQUEST:
1255         if(check_col(fd, COL_INFO))
1256             col_add_fstr(fd, COL_INFO, "Registration req. VC:%d", vc);
1257         if (x25_tree)
1258             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1259                                        "REG REQ", "Registration request");
1260         localoffset += 3;
1261         if (localoffset < x25_pkt_len+offset)
1262             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, FALSE);
1263
1264         if (x25_tree) {
1265             if (localoffset < x25_pkt_len+offset)
1266                 proto_tree_add_text(x25_tree, localoffset, 1,
1267                         "Registration length: %d", pd[localoffset] & 0x7F);
1268             if (localoffset+1 < x25_pkt_len+offset)
1269                 proto_tree_add_text(x25_tree, localoffset+1,
1270                         pd[localoffset] & 0x7F, "Registration");
1271         }
1272         localoffset = fd->cap_len;
1273         break;
1274     case X25_REGISTRATION_CONFIRMATION:
1275         if(check_col(fd, COL_INFO))
1276             col_add_fstr(fd, COL_INFO, "Registration conf. VC:%d", vc);
1277         if (x25_tree) {
1278             proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset+2, 1,
1279                                        "REG CONF", "Registration confirmation");
1280             if (localoffset+3 < x25_pkt_len+offset)
1281                 proto_tree_add_text(x25_tree, localoffset+3, 1,
1282                         "Cause: %s", registration_code(pd[localoffset+3]));
1283             if (localoffset+4 < x25_pkt_len+offset)
1284                 proto_tree_add_text(x25_tree, localoffset+4, 1,
1285                         "Diagnostic: %s", registration_code(pd[localoffset+4]));
1286         }
1287         localoffset += 5;
1288         if (localoffset < x25_pkt_len+offset)
1289             x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, TRUE);
1290
1291         if (x25_tree) {
1292             if (localoffset < x25_pkt_len+offset)
1293                 proto_tree_add_text(x25_tree, localoffset, 1,
1294                         "Registration length: %d", pd[localoffset] & 0x7F);
1295             if (localoffset+1 < x25_pkt_len+offset)
1296                 proto_tree_add_text(x25_tree, localoffset+1,
1297                         pd[localoffset] & 0x7F, "Registration");
1298         }
1299         localoffset = fd->cap_len;
1300         break;
1301     default :
1302         localoffset += 2;
1303         if ((pd[localoffset] & 0x01) == X25_DATA)
1304         {
1305             if(check_col(fd, COL_INFO)) {
1306                 if (modulo == 8)
1307                     col_add_fstr(fd, COL_INFO,
1308                             "Data VC:%d P(S):%d P(R):%d %s", vc,
1309                             (pd[localoffset] >> 1) & 0x07,
1310                             (pd[localoffset] >> 5) & 0x07,
1311                             ((pd[localoffset]>>4) & 0x01) ? " M" : "");
1312                 else
1313                     col_add_fstr(fd, COL_INFO,
1314                             "Data VC:%d P(S):%d P(R):%d %s", vc,
1315                             pd[localoffset+1] >> 1,
1316                             pd[localoffset] >> 1,
1317                             (pd[localoffset+1] & 0x01) ? " M" : "");
1318             }
1319             if (x25_tree) {
1320                 proto_tree_add_item_format(x25_tree, hf_x25_type, localoffset,
1321                                            1, "DATA", "X.25 Data");
1322                 if (modulo == 8) {
1323                     proto_tree_add_text(x25_tree, localoffset, 1,
1324                             "          %d%d%d..... : P(R) = %d",
1325                             (pd[localoffset] >> 7) & 0x01,
1326                             (pd[localoffset] >> 6) & 0x01,
1327                             (pd[localoffset] >> 5) & 0x01,
1328                             (pd[localoffset] >> 5) & 0x07);
1329                     proto_tree_add_text(x25_tree, localoffset, 1,
1330                             "          ...%d.... : More bit",
1331                             (pd[localoffset] >> 4) & 0x01);
1332                     proto_tree_add_text(x25_tree, localoffset, 1,
1333                             "          ....%d%d%d. : P(S) = %d",
1334                             (pd[localoffset] >> 3) & 0x01,
1335                             (pd[localoffset] >> 2) & 0x01,
1336                             (pd[localoffset] >> 1) & 0x01,
1337                             (pd[localoffset] >> 1) & 0x07);
1338                     proto_tree_add_text(x25_tree, localoffset, 1,
1339                             "          .......0 : Packet type id = DATA");
1340                 }
1341                 else {
1342                     proto_tree_add_text(x25_tree, localoffset+1, 1,
1343                             "          %d%d%d%d%d%d%d. : P(S) = %d",
1344                             (pd[localoffset+1] >> 7) & 0x01,
1345                             (pd[localoffset+1] >> 6) & 0x01,
1346                             (pd[localoffset+1] >> 5) & 0x01,
1347                             (pd[localoffset+1] >> 4) & 0x01,
1348                             (pd[localoffset+1] >> 3) & 0x01,
1349                             (pd[localoffset+1] >> 2) & 0x01,
1350                             (pd[localoffset+1] >> 1) & 0x01,
1351                             pd[localoffset+1] >> 1);
1352                     proto_tree_add_text(x25_tree, localoffset, 1,
1353                             "          .......%d : More bit",
1354                             pd[localoffset+1] & 0x01);
1355                 }
1356             }
1357             localoffset += (modulo == 8) ? 1 : 2;
1358             break;
1359         }
1360         switch (pd[localoffset] & 0x1F)
1361         {
1362         case X25_RR:
1363             if(check_col(fd, COL_INFO)) {
1364                 if (modulo == 8)
1365                     col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1366                             vc, (pd[localoffset] >> 5) & 0x07);
1367                 else
1368                     col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1369                             vc, pd[localoffset+1] >> 1);
1370             }
1371             if (x25_tree) {
1372                 if (modulo == 8)
1373                     proto_tree_add_item_format(x25_tree, hf_x25_type,
1374                             localoffset, 1, "RR", "RR P(R):%d",
1375                             (pd[localoffset] >> 5) & 0x07);
1376                 else
1377                     proto_tree_add_item_format(x25_tree, hf_x25_type,
1378                             localoffset, 2, "RR", "RR P(R):%d",
1379                             pd[localoffset+1] >> 1);
1380             }
1381             break;
1382
1383         case X25_RNR:
1384             if(check_col(fd, COL_INFO)) {
1385                 if (modulo == 8)
1386                     col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1387                             vc, (pd[localoffset] >> 5) & 0x07);
1388                 else
1389                     col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1390                             vc, pd[localoffset+1] >> 1);
1391             }
1392             if (x25_tree) {
1393                 if (modulo == 8)
1394                     proto_tree_add_item_format(x25_tree, hf_x25_type,
1395                             localoffset, 1, "RNR", "RNR P(R):%d",
1396                             (pd[localoffset] >> 5) & 0x07);
1397                 else
1398                     proto_tree_add_item_format(x25_tree, hf_x25_type,
1399                             localoffset, 2, "RNR", "RNR P(R):%d",
1400                             pd[localoffset+1] >> 1);
1401             }
1402             break;
1403
1404         case X25_REJ:
1405             if(check_col(fd, COL_INFO)) {
1406                 if (modulo == 8)
1407                     col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1408                             vc, (pd[localoffset] >> 5) & 0x07);
1409                 else
1410                     col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1411                             vc, pd[localoffset+1] >> 1);
1412             }
1413             if (x25_tree) {
1414                 if (modulo == 8)
1415                     proto_tree_add_item_format(x25_tree, hf_x25_type,
1416                             localoffset, 1, "REJ", "REJ P(R):%d",
1417                             (pd[localoffset] >> 5) & 0x07);
1418                 else
1419                     proto_tree_add_item_format(x25_tree, hf_x25_type,
1420                             localoffset, 2, "REJ", "REJ P(R):%d",
1421                             pd[localoffset+1] >> 1);
1422             }
1423         }
1424         localoffset += (modulo == 8) ? 1 : 2;
1425     }
1426
1427     if (localoffset >= fd->cap_len) return;
1428
1429     /* search the dissector in the hash table */
1430     if ((dissect = x25_hash_get_dissect(fd->abs_secs, fd->abs_usecs, vc)))
1431       (*dissect)(pd, localoffset, fd, tree);
1432     else {
1433       if (pd[localoffset] == 0x45) /* If the Call Req. has not been captured,
1434                                     * assume these packets carry IP */
1435       {
1436           x25_hash_add_proto_start(vc, fd->abs_secs,
1437                                    fd->abs_usecs, dissect_ip);
1438           dissect_ip(pd, localoffset, fd, tree);
1439       }
1440       else {
1441           dissect_data(pd, localoffset, fd, tree);
1442       }
1443     }
1444 }
1445
1446 void
1447 proto_register_x25(void)
1448 {
1449     static hf_register_info hf[] = {
1450         { &hf_x25_lcn,
1451           { "Logical Channel", "x25.lcn", FT_UINT16, BASE_DEC, NULL, 0x0,
1452                 "" } },
1453
1454         { &hf_x25_type,
1455           { "Packet Type", "x25.type", FT_STRING, BASE_NONE, NULL, 0x0,
1456                 "" } },
1457     };
1458
1459     proto_x25 = proto_register_protocol ("X.25", "x25");
1460     proto_register_field_array (proto_x25, hf, array_length(hf));
1461 }