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