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