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