2 * Routines for x25 packet disassembly
3 * Olivier Abad <abad@daba.dhis.net>
5 * $Id: packet-x25.c,v 1.13 1999/12/10 07:02:29 oabad Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
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.
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.
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.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
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
61 #define X25_FAC_CLASS_MASK 0xC0
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
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
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;
107 static gint ett_x25 = -1;
108 static gint ett_x25_fac = -1;
110 static const value_string vals_modulo[] = {
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" },
133 { X25_DATA, "DATA" },
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
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
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;
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
160 typedef struct _global_vc_info {
163 struct _global_vc_info *next;
166 static global_vc_info *hash_table[64];
169 free_vc_info(vc_info *pt)
185 for (i=0; i<64; i++) {
186 if (hash_table[i]) /* not NULL ==> free */
188 global_vc_info *hash_ent, *hash_ent2;
189 hash_ent2 = hash_ent = hash_table[i];
192 hash_ent2 = hash_ent;
193 hash_ent = hash_ent->next;
194 free_vc_info(hash_ent2->info);
203 x25_hash_add_proto_start(guint16 vc, guint32 frame_secs, guint32 frame_usecs,
204 void (*dissect)(const u_char *, int, frame_data *,
208 global_vc_info *hash_ent;
209 global_vc_info *hash_ent2;
211 if (hash_table[idx] == 0)
213 hash_ent = (global_vc_info *)g_malloc(sizeof(global_vc_info));
215 fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
218 hash_ent->vc_num = vc;
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");
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;
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;
241 if (hash_ent != NULL) /* hash_ent->vc_num == vc */
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;
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");
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;
263 else /* new vc number */
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");
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");
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;
286 x25_hash_add_proto_end(guint16 vc, guint32 frame_secs, guint32 frame_usecs)
288 global_vc_info *hash_ent = hash_table[vc%64];
291 if (!hash_ent) return;
292 while(hash_ent->vc_num != vc) hash_ent = hash_ent->next;
293 if (!hash_ent) return;
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;
301 void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc))(const u_char *, int, frame_data *, proto_tree *)
303 global_vc_info *hash_ent = hash_table[vc%64];
307 if (!hash_ent) return 0;
309 while(hash_ent && hash_ent->vc_num != vc) hash_ent = hash_ent->next;
310 if (!hash_ent) return 0;
312 /* a hash_ent was found for this VC number */
313 vci2 = vci = hash_ent->info;
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))) {
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;
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 */
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))
336 return vci2->dissect;
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))
348 static char *clear_code(unsigned char code)
350 static char buffer[25];
352 if (code == 0x00 || (code & 0x80) == 0x80)
353 return "DTE Originated";
355 return "Number Busy";
357 return "Out Of Order";
359 return "Remote Procedure Error";
361 return "Reverse Charging Acceptance Not Subscribed";
363 return "Incompatible Destination";
365 return "Fast Select Acceptance Not Subscribed";
367 return "Destination Absent";
369 return "Invalid Facility Requested";
371 return "Access Barred";
373 return "Local Procedure Error";
375 return "Network Congestion";
377 return "Not Obtainable";
379 return "RPOA Out Of Order";
381 sprintf(buffer, "Unknown %02X", code);
386 static char *clear_diag(unsigned char code)
388 static char buffer[25];
391 return "No additional information";
393 return "Invalid P(S)";
395 return "Invalid P(R)";
397 return "Packet type invalid";
399 return "Packet type invalid for state r1";
401 return "Packet type invalid for state r2";
403 return "Packet type invalid for state r3";
405 return "Packet type invalid for state p1";
407 return "Packet type invalid for state p2";
409 return "Packet type invalid for state p3";
411 return "Packet type invalid for state p4";
413 return "Packet type invalid for state p5";
415 return "Packet type invalid for state p6";
417 return "Packet type invalid for state p7";
419 return "Packet type invalid for state d1";
421 return "Packet type invalid for state d2";
423 return "Packet type invalid for state d3";
425 return "Packet not allowed";
427 return "Unidentifiable packet";
429 return "Call on one-way logical channel";
431 return "Invalid packet type on a PVC";
433 return "Packet on unassigned LC";
435 return "Reject not subscribed to";
437 return "Packet too short";
439 return "Packet too long";
441 return "Invalid general format identifier";
443 return "Restart/registration packet with nonzero bits";
445 return "Packet type not compatible with facility";
447 return "Unauthorised interrupt confirmation";
449 return "Unauthorised interrupt";
451 return "Unauthorised reject";
453 return "Time expired";
455 return "Time expired for incoming call";
457 return "Time expired for clear indication";
459 return "Time expired for reset indication";
461 return "Time expired for restart indication";
463 return "Time expired for call deflection";
465 return "Call set-up/clearing or registration pb.";
467 return "Facility/registration code not allowed";
469 return "Facility parameter not allowed";
471 return "Invalid called DTE address";
473 return "Invalid calling DTE address";
475 return "Invalid facility/registration length";
477 return "Incoming call barred";
479 return "No logical channel available";
481 return "Call collision";
483 return "Duplicate facility requested";
485 return "Non zero address length";
487 return "Non zero facility length";
489 return "Facility not provided when expected";
491 return "Invalid CCITT-specified DTE facility";
493 return "Max. nb of call redir/defl. exceeded";
495 return "Miscellaneous";
497 return "Improper cause code from DTE";
499 return "Not aligned octet";
501 return "Inconsistent Q bit setting";
503 return "NUI problem";
505 return "International problem";
507 return "Remote network problem";
509 return "International protocol problem";
511 return "International link out of order";
513 return "International link busy";
515 return "Transit network facility problem";
517 return "Remote network facility problem";
519 return "International routing problem";
521 return "Temporary routing problem";
523 return "Unknown called DNIC";
525 return "Maintenance action";
527 sprintf(buffer, "Unknown %d", code);
532 static char *reset_code(unsigned char code)
534 static char buffer[25];
536 if (code == 0x00 || (code & 0x80) == 0x80)
537 return "DTE Originated";
539 return "Out of order";
541 return "Remote Procedure Error";
543 return "Local Procedure Error";
545 return "Network Congestion";
547 return "Remote DTE operational";
549 return "Network operational";
551 return "Incompatible Destination";
553 return "Network out of order";
555 sprintf(buffer, "Unknown %02X", code);
560 static char *restart_code(unsigned char code)
562 static char buffer[25];
564 if (code == 0x00 || (code & 0x80) == 0x80)
565 return "DTE Originated";
567 return "Local Procedure Error";
569 return "Network Congestion";
571 return "Network Operational";
573 return "Registration/cancellation confirmed";
575 sprintf(buffer, "Unknown %02X", code);
580 static char *registration_code(unsigned char code)
582 static char buffer[25];
585 return "Invalid facility request";
587 return "Network congestion";
589 return "Local procedure error";
591 return "Registration/cancellation confirmed";
593 sprintf(buffer, "Unknown %02X", code);
599 dump_facilities(proto_tree *tree, int *offset, const guint8 *p)
601 const guint8 *ptr = p;
602 guint32 len; /* facilities length */
604 proto_tree *fac_tree = 0;
608 ti = proto_tree_add_text(tree, *offset, len + 1,
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);
617 switch(*ptr & X25_FAC_CLASS_MASK) {
618 case X25_FAC_CLASS_A:
620 case X25_FAC_COMP_MARK:
622 proto_tree_add_text(fac_tree, *offset, 1, "Code : 00 (Marker)");
626 proto_tree_add_text(fac_tree, *offset+1, 1,
627 "Parameter : 00 (Network complementary "
628 "services - calling DTE)");
632 proto_tree_add_text(fac_tree, *offset+1, 1,
633 "Parameter : FF (Network complementary "
634 "services - called DTE)");
638 proto_tree_add_text(fac_tree, *offset+1, 1,
639 "Parameter : 0F (DTE complementary "
644 proto_tree_add_text(fac_tree, *offset+1, 1,
645 "Parameter : %02X (Unknown marker)",
650 case X25_FAC_REVERSE:
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",
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");
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"));
671 case X25_FAC_THROUGHPUT:
675 proto_tree_add_text(fac_tree, *offset, 1, "Code : %02X (Throughput "
676 "class negociation)", *ptr);
688 sprintf(tmpbuf, "From the called DTE : %%u (%d bps)",
689 75*(1<<((ptr[1] >> 4)-3)));
692 sprintf(tmpbuf, "From the called DTE : %%u (48000 bps)");
695 sprintf(tmpbuf, "From the called DTE : %%u (64000 bps)");
698 sprintf(tmpbuf, "From the called DTE : %%u (Reserved)");
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)
713 sprintf(tmpbuf, "From the calling DTE : %%u (%d bps)",
714 75*(1<<((ptr[1] & 0x0F)-3)));
717 sprintf(tmpbuf, "From the calling DTE : %%u (48000 bps)");
720 sprintf(tmpbuf, "From the calling DTE : %%u (64000 bps)");
723 sprintf(tmpbuf, "From the calling DTE : %%u (Reserved)");
725 proto_tree_add_text(fac_tree, *offset+1, 1,
726 decode_numeric_bitfield(ptr[1], 0x0F, 1*8, tmpbuf));
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]);
737 case X25_FAC_CALLED_MODIF:
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]);
745 case X25_FAC_CUG_OUTGOING_ACC:
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]);
753 case X25_FAC_THROUGHPUT_MIN:
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]);
761 case X25_FAC_EXPRESS_DATA:
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]);
771 proto_tree_add_text(fac_tree, *offset, 1, "Code : %02X (Unknown)",
773 proto_tree_add_text(fac_tree, *offset+1, 1,
774 "Parameter %02X", ptr[1]);
782 case X25_FAC_CLASS_B:
784 case X25_FAC_BILATERAL_CUG:
786 proto_tree_add_text(fac_tree, *offset, 3,
787 "Bilateral CUG: %d%d%d%d",
793 case X25_FAC_PACKET_SIZE:
796 int called_dte_size, calling_dte_size;
801 called_dte_size = 16;
804 called_dte_size = 32;
807 called_dte_size = 64;
810 called_dte_size = 128;
813 called_dte_size = 256;
816 called_dte_size = 512;
819 called_dte_size = 1024;
822 called_dte_size = 2048;
825 called_dte_size = 4096;
835 calling_dte_size = 16;
838 calling_dte_size = 32;
841 calling_dte_size = 64;
844 calling_dte_size = 128;
847 calling_dte_size = 256;
850 calling_dte_size = 512;
853 calling_dte_size = 1024;
856 calling_dte_size = 2048;
859 calling_dte_size = 4096;
862 calling_dte_size = 0;
865 proto_tree_add_text(fac_tree, *offset, 3,
866 "Packet Size: called DTE: %d - calling DTE: %d",
871 case X25_FAC_WINDOW_SIZE:
873 proto_tree_add_text(fac_tree, *offset, 3,
874 "Window Size: called DTE: %d - calling DTE: %d",
877 case X25_FAC_RPOA_SELECTION:
879 proto_tree_add_text(fac_tree, *offset, 3,
886 case X25_FAC_TRANSIT_DELAY:
888 proto_tree_add_text(fac_tree, *offset, 3,
890 (ptr[1]<<8) + ptr[2]);
894 proto_tree_add_text(fac_tree, *offset, 3,
895 "Unknown facility %02X, values %02X%02X",
896 ptr[0], ptr[1], ptr[2]);
903 case X25_FAC_CLASS_C:
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]);
912 case X25_FAC_CLASS_D:
914 case X25_FAC_CALL_TRANSFER:
916 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
917 "Call Transfer: reason = %02X",
920 case X25_FAC_CALLING_ADDR_EXT:
922 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
923 "Calling address extension");
925 case X25_FAC_CALLED_ADDR_EXT:
927 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
928 "Called address extension");
930 case X25_FAC_ETE_TRANSIT_DELAY:
932 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
933 "End to end transit delay");
935 case X25_FAC_CALL_DEFLECT:
937 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
938 "Call deflection: reason = %02X",
941 case X25_FAC_PRIORITY:
943 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
948 proto_tree_add_text(fac_tree, *offset, 2+ptr[1],
949 "Unknown facility %02X, length %02X",
952 (*offset) += ptr[1]+2;
961 x25_ntoa(proto_tree *tree, int *offset, const guint8 *p,
962 frame_data *fd, gboolean toa)
966 char addr1[16], addr2[16];
967 char *first, *second;
969 len1 = (*p >> 0) & 0x0F;
970 len2 = (*p >> 4) & 0x0F;
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"));
985 for (i = 0; i < (len1 + len2); i++) {
988 *first++ = ((*p >> 0) & 0x0F) + '0';
991 *first++ = ((*p >> 4) & 0x0F) + '0';
995 *second++ = ((*p >> 0) & 0x0F) + '0';
998 *second++ = ((*p >> 4) & 0x0F) + '0';
1007 if(check_col(fd, COL_RES_DL_DST))
1008 col_add_str(fd, COL_RES_DL_DST, addr1);
1010 proto_tree_add_text(tree, *offset,
1013 toa ? "Called" : "Calling",
1017 if(check_col(fd, COL_RES_DL_SRC))
1018 col_add_str(fd, COL_RES_DL_SRC, addr2);
1020 proto_tree_add_text(tree, *offset + len1/2,
1021 (len2+1)/2+(len1%2+(len2+1)%2)/2,
1023 toa ? "Calling" : "Called",
1026 (*offset) += ((len1 + len2 + 1) / 2);
1030 get_x25_pkt_len(const char *data, frame_data *fd, int offset)
1032 int length, called_len, calling_len, dte_len, dce_len;
1034 /* packet size should always be > 3 */
1035 if (fd->cap_len - offset < 3) return fd->cap_len;
1037 switch ((guint8)data[2])
1039 case X25_CALL_REQUEST:
1040 if (fd->cap_len > offset+3) /* pkt size > 3 */
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 */
1048 else length = fd->cap_len - offset;
1049 return MIN(fd->cap_len-offset,length);
1051 case X25_CALL_ACCEPTED:
1052 if (fd->cap_len > offset+3) /* pkt size > 3 */
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 */
1060 else length = fd->cap_len - offset;
1061 return MIN(fd->cap_len-offset,length);
1063 case X25_CLEAR_REQUEST:
1064 case X25_RESET_REQUEST:
1065 case X25_RESTART_REQUEST:
1066 return MIN(fd->cap_len-offset,5);
1068 case X25_DIAGNOSTIC:
1069 return MIN(fd->cap_len-offset,4);
1071 case X25_CLEAR_CONFIRMATION:
1073 case X25_INTERRUPT_CONFIRMATION:
1074 case X25_RESET_CONFIRMATION:
1075 case X25_RESTART_CONFIRMATION:
1076 return MIN(fd->cap_len-offset,3);
1078 case X25_REGISTRATION_REQUEST:
1079 if (fd->cap_len > offset+3) /* pkt size > 3 */
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 */
1087 else length = fd->cap_len-offset;
1088 return MIN(fd->cap_len-offset,length);
1090 case X25_REGISTRATION_CONFIRMATION:
1091 if (fd->cap_len > offset+5) /* pkt size > 5 */
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 */
1099 else length = fd->cap_len-offset;
1100 return MIN(fd->cap_len-offset,length);
1103 if ((data[2] & 0x01) == X25_DATA) return MIN(fd->cap_len-offset,3);
1105 switch (data[2] & 0x1F)
1108 return MIN(fd->cap_len-offset,3);
1111 return MIN(fd->cap_len-offset,3);
1114 return MIN(fd->cap_len-offset,3);
1121 dissect_x25(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1123 proto_tree *x25_tree=0, *ti;
1124 int localoffset=offset;
1128 void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
1131 if (check_col(fd, COL_PROTOCOL))
1132 col_add_str(fd, COL_PROTOCOL, "X.25");
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 */
1138 if (check_col(fd, COL_INFO))
1139 col_add_str(fd, COL_INFO, "Invalid/short X.25 packet");
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");
1146 vc = (int)(pd[localoffset] & 0x0F)*256 + (int)pd[localoffset+1];
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]);
1160 switch (pd[localoffset+2]) {
1161 case X25_CALL_REQUEST:
1162 if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
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"
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"
1180 if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1181 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1183 if (localoffset < x25_pkt_len+offset) /* facilities */
1184 dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1186 if (localoffset < fd->cap_len) /* user data */
1188 if (pd[localoffset] == 0xCC)
1190 x25_hash_add_proto_start(vc, fd->abs_secs,
1191 fd->abs_usecs, dissect_ip);
1193 proto_tree_add_text(x25_tree, localoffset, 1,
1197 else if (pd[localoffset] == 0x03 &&
1198 pd[localoffset+1] == 0x01 &&
1199 pd[localoffset+2] == 0x01 &&
1200 pd[localoffset+3] == 0x00)
1202 x25_hash_add_proto_start(vc, fd->abs_secs,
1203 fd->abs_usecs, dissect_cotp);
1205 proto_tree_add_text(x25_tree, localoffset, 4,
1211 proto_tree_add_text(x25_tree, localoffset,
1212 fd->cap_len-localoffset, "Data");
1213 localoffset = fd->cap_len;
1217 case X25_CALL_ACCEPTED:
1218 if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
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."
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"
1236 if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1237 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1239 if (localoffset < x25_pkt_len+offset) /* facilities */
1240 dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1242 if (localoffset < fd->cap_len) { /* user data */
1244 proto_tree_add_text(x25_tree, localoffset,
1245 fd->cap_len-localoffset, "Data");
1246 localoffset=fd->cap_len;
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."
1254 vc, clear_code(pd[localoffset+3]),
1255 clear_diag(pd[localoffset+4]));
1257 x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
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"
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,
1272 clear_diag(pd[localoffset+4]));
1274 localoffset += x25_pkt_len;
1276 case X25_CLEAR_CONFIRMATION:
1277 if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1280 if(check_col(fd, COL_INFO))
1281 col_add_fstr(fd, COL_INFO, "Clear Conf. VC:%d", vc);
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);
1288 localoffset += x25_pkt_len;
1290 if (localoffset < fd->cap_len) /* extended clear conf format */
1291 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1293 if (localoffset < fd->cap_len) /* facilities */
1294 dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1296 case X25_DIAGNOSTIC:
1297 if(check_col(fd, COL_INFO)) {
1298 col_add_fstr(fd, COL_INFO, "Diag. %d", (int)pd[localoffset+3]);
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]);
1307 localoffset += x25_pkt_len;
1310 if(check_col(fd, COL_INFO))
1311 col_add_fstr(fd, COL_INFO, "Interrupt VC:%d", vc);
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);
1318 localoffset += x25_pkt_len;
1320 case X25_INTERRUPT_CONFIRMATION:
1321 if(check_col(fd, COL_INFO))
1322 col_add_fstr(fd, COL_INFO, "Interrupt Conf. VC:%d", vc);
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);
1329 localoffset += x25_pkt_len;
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."
1336 vc, reset_code(pd[localoffset+3]),
1337 (int)pd[localoffset+4]);
1339 x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
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,
1346 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset indication"
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]);
1355 localoffset += x25_pkt_len;
1357 case X25_RESET_CONFIRMATION:
1358 if(check_col(fd, COL_INFO))
1359 col_add_fstr(fd, COL_INFO, "Reset conf. VC:%d", vc);
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);
1366 localoffset += x25_pkt_len;
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."
1373 restart_code(pd[localoffset+3]),
1374 (int)pd[localoffset+4]);
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]);
1389 localoffset += x25_pkt_len;
1391 case X25_RESTART_CONFIRMATION:
1392 if(check_col(fd, COL_INFO))
1393 col_add_str(fd, COL_INFO, "Restart conf.");
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;
1399 case X25_REGISTRATION_REQUEST:
1400 if(check_col(fd, COL_INFO))
1401 col_add_str(fd, COL_INFO, "Registration req.");
1403 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1404 localoffset+2, 1, X25_REGISTRATION_REQUEST);
1406 if (localoffset < x25_pkt_len+offset)
1407 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, FALSE);
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");
1417 localoffset = fd->cap_len;
1419 case X25_REGISTRATION_CONFIRMATION:
1420 if(check_col(fd, COL_INFO))
1421 col_add_str(fd, COL_INFO, "Registration conf.");
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]));
1433 if (localoffset < x25_pkt_len+offset)
1434 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, TRUE);
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");
1444 localoffset = fd->cap_len;
1448 if ((pd[localoffset] & 0x01) == X25_DATA)
1450 if(check_col(fd, COL_INFO)) {
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" : "");
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" : "");
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]);
1468 proto_tree_add_item_hidden(x25_tree, hf_x25_type, localoffset, 1,
1470 proto_tree_add_item(x25_tree, hf_x25_p_r, localoffset, 1,
1472 if (pd[localoffset] & 0x10)
1473 proto_tree_add_item(x25_tree, hf_x25_mbit, localoffset, 1,
1475 proto_tree_add_item(x25_tree, hf_x25_p_s, localoffset, 1,
1477 proto_tree_add_text(x25_tree, localoffset, 1,
1478 decode_boolean_bitfield(pd[localoffset], 0x01, 1*8,
1482 proto_tree_add_item_hidden(x25_tree, hf_ex25_type, localoffset, 1,
1484 proto_tree_add_item(x25_tree, hf_x25_p_r, localoffset, 1,
1486 proto_tree_add_item(x25_tree, hf_x25_p_s, localoffset+1, 1,
1488 if (pd[localoffset+1] & 0x01)
1489 proto_tree_add_item(x25_tree, hf_ex25_mbit, localoffset+1, 1,
1493 localoffset += (modulo == 8) ? 1 : 2;
1496 switch (pd[localoffset] & 0x1F)
1499 if(check_col(fd, COL_INFO)) {
1501 col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1502 vc, (pd[localoffset] >> 5) & 0x07);
1504 col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1505 vc, pd[localoffset+1] >> 1);
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]);
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);
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]);
1524 if(check_col(fd, COL_INFO)) {
1526 col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1527 vc, (pd[localoffset] >> 5) & 0x07);
1529 col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1530 vc, pd[localoffset+1] >> 1);
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]);
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);
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]);
1549 if(check_col(fd, COL_INFO)) {
1551 col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1552 vc, (pd[localoffset] >> 5) & 0x07);
1554 col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1555 vc, pd[localoffset+1] >> 1);
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]);
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);
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]);
1572 localoffset += (modulo == 8) ? 1 : 2;
1575 if (localoffset >= fd->cap_len) return;
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);
1581 if (pd[localoffset] == 0x45) /* If the Call Req. has not been captured,
1582 * assume these packets carry IP */
1584 x25_hash_add_proto_start(vc, fd->abs_secs,
1585 fd->abs_usecs, dissect_ip);
1586 dissect_ip(pd, localoffset, fd, tree);
1589 dissect_data(pd, localoffset, fd, tree);
1595 proto_register_x25(void)
1597 static hf_register_info hf8[] = {
1599 { "Q Bit", "x25.q", FT_BOOLEAN, 2, NULL, 0x8000,
1600 "Qualifier Bit" } },
1602 { "D Bit", "x25.d", FT_BOOLEAN, 2, NULL, 0x4000,
1603 "Delivery Confirmation Bit" } },
1605 { "Modulo", "x25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000,
1606 "Specifies whether the frame is modulo 8 or 128" } },
1608 { "Logical Channel", "x25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF,
1609 "Logical Channel Number" } },
1611 { "Packet Type", "x25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0,
1614 { "P(R)", "x25.p_r", FT_UINT8, BASE_HEX, NULL, 0xE0,
1615 "Packet Receive Sequence Number" } },
1617 { "M Bit", "x25.m", FT_BOOLEAN, 1, NULL, 0x10,
1620 { "P(S)", "x25.p_s", FT_UINT8, BASE_HEX, NULL, 0x0E,
1621 "Packet Send Sequence Number" } },
1624 static hf_register_info hf128[] = {
1626 { "Q Bit", "ex25.q", FT_BOOLEAN, 2, NULL, 0x8000,
1627 "Qualifier Bit" } },
1629 { "D Bit", "ex25.d", FT_BOOLEAN, 2, NULL, 0x4000,
1630 "Delivery Confirmation Bit" } },
1632 { "Modulo", "ex25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000,
1633 "Specifies whether the frame is modulo 8 or 128" } },
1635 { "Logical Channel", "ex25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF,
1636 "Logical Channel Number" } },
1638 { "Packet Type", "ex25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0,
1641 { "P(R)", "ex25.p_r", FT_UINT8, BASE_HEX, NULL, 0xFE,
1642 "Packet Receive Sequence Number" } },
1644 { "M Bit", "ex25.m", FT_BOOLEAN, 1, NULL, 0x01,
1647 { "P(S)", "ex25.p_s", FT_UINT8, BASE_HEX, NULL, 0xFE,
1648 "Packet Send Sequence Number" } },
1650 static gint *ett[] = {
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));