2 * Routines for x25 packet disassembly
3 * Olivier Abad <abad@daba.dhis.net>
5 * $Id: packet-x25.c,v 1.10 1999/11/29 22:44:48 gram 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_ADDR_EXT 0xCB
85 #define X25_FAC_CALL_DEFLECT 0xD1
87 static int proto_x25 = -1;
88 static int hf_x25_qbit = -1;
89 static int hf_x25_dbit = -1;
90 static int hf_x25_mod = -1;
91 static int hf_x25_lcn = -1;
92 static int hf_x25_type = -1;
93 static int hf_x25_p_r = -1;
94 static int hf_x25_mbit = -1;
95 static int hf_x25_p_s = -1;
96 static int proto_ex25 = -1;
97 static int hf_ex25_qbit = -1;
98 static int hf_ex25_dbit = -1;
99 static int hf_ex25_mod = -1;
100 static int hf_ex25_lcn = -1;
101 static int hf_ex25_type = -1;
102 static int hf_ex25_p_r = -1;
103 static int hf_ex25_mbit = -1;
104 static int hf_ex25_p_s = -1;
106 static gint ett_x25 = -1;
108 static const value_string vals_modulo[] = {
114 static const value_string vals_x25_type[] = {
115 { X25_CALL_REQUEST, "Call" },
116 { X25_CALL_ACCEPTED, "Call Accepted" },
117 { X25_CLEAR_REQUEST, "Clear" },
118 { X25_CLEAR_CONFIRMATION, "Clear Confirmation" },
119 { X25_INTERRUPT, "Interrupt" },
120 { X25_INTERRUPT_CONFIRMATION, "Interrupt Confirmation" },
121 { X25_RESET_REQUEST, "Reset" },
122 { X25_RESET_CONFIRMATION, "Reset Confirmation" },
123 { X25_RESTART_REQUEST, "Restart" },
124 { X25_RESTART_CONFIRMATION, "Restart Confirmation" },
125 { X25_REGISTRATION_REQUEST, "Registration" },
126 { X25_REGISTRATION_CONFIRMATION, "Registration Confirmation" },
127 { X25_DIAGNOSTIC, "Diagnostic" },
131 { X25_DATA, "DATA" },
136 * each vc_info node contains :
137 * the time of the first frame using this dissector (secs and usecs)
138 * the time of the last frame using this dissector (0 if it is unknown)
139 * a pointer to the dissector
141 * the "time of first frame" is initialized when a Call Req. is received
142 * the "time of last frame" is initialized when a Clear, Reset, or Restart
145 typedef struct _vc_info {
146 guint32 first_frame_secs, first_frame_usecs;
147 guint32 last_frame_secs, last_frame_usecs;
148 void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
149 struct _vc_info *next;
153 * the hash table will contain linked lists of global_vc_info
154 * each global_vc_info struct contains :
155 * the VC number (the hash table is indexed with VC % 64)
156 * a linked list of vc_info
158 typedef struct _global_vc_info {
161 struct _global_vc_info *next;
164 static global_vc_info *hash_table[64];
167 free_vc_info(vc_info *pt)
183 for (i=0; i<64; i++) {
184 if (hash_table[i]) /* not NULL ==> free */
186 global_vc_info *hash_ent, *hash_ent2;
187 hash_ent2 = hash_ent = hash_table[i];
190 hash_ent2 = hash_ent;
191 hash_ent = hash_ent->next;
192 free_vc_info(hash_ent2->info);
201 x25_hash_add_proto_start(guint16 vc, guint32 frame_secs, guint32 frame_usecs,
202 void (*dissect)(const u_char *, int, frame_data *,
206 global_vc_info *hash_ent;
207 global_vc_info *hash_ent2;
209 if (hash_table[idx] == 0)
211 hash_ent = (global_vc_info *)g_malloc(sizeof(global_vc_info));
213 fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
216 hash_ent->vc_num = vc;
218 hash_ent->info = (vc_info *)g_malloc(sizeof(vc_info));
219 if (!hash_ent->info) {
220 fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
223 hash_ent->info->first_frame_secs = frame_secs;
224 hash_ent->info->first_frame_usecs = frame_usecs;
225 hash_ent->info->last_frame_secs = 0;
226 hash_ent->info->last_frame_usecs = 0;
227 hash_ent->info->dissect = dissect;
228 hash_ent->info->next = 0;
229 hash_table[idx] = hash_ent;
233 hash_ent2 = hash_ent = hash_table[idx];
234 /* search an entry with the same VC number */
235 while (hash_ent != NULL && hash_ent->vc_num != vc) {
236 hash_ent2 = hash_ent;
237 hash_ent = hash_ent->next;
239 if (hash_ent != NULL) /* hash_ent->vc_num == vc */
241 vc_info *vci = hash_ent->info;
242 while (vci->next) vci = vci->next; /* last element */
243 if (vci->dissect == dissect) {
244 vci->last_frame_secs = 0;
245 vci->last_frame_usecs = 0;
248 vci->next = (vc_info *)g_malloc(sizeof(vc_info));
249 if (vci->next == 0) {
250 fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
253 vci->next->first_frame_secs = frame_secs;
254 vci->next->first_frame_usecs = frame_usecs;
255 vci->next->last_frame_secs = 0;
256 vci->next->last_frame_usecs = 0;
257 vci->next->dissect = dissect;
261 else /* new vc number */
263 hash_ent2->next = (global_vc_info *)g_malloc(sizeof(global_vc_info));
264 if (!hash_ent2->next) {
265 fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
268 hash_ent2->next->info = (vc_info *)g_malloc(sizeof(vc_info));
269 if (!hash_ent2->next->info) {
270 fprintf(stderr, "Could not allocate space for hash structure in dissect_x25\n");
273 hash_ent2->next->info->first_frame_secs = frame_secs;
274 hash_ent2->next->info->first_frame_usecs = frame_usecs;
275 hash_ent2->next->info->last_frame_secs = 0;
276 hash_ent2->next->info->last_frame_usecs = 0;
277 hash_ent2->next->info->dissect = dissect;
278 hash_ent2->next->info->next = 0;
284 x25_hash_add_proto_end(guint16 vc, guint32 frame_secs, guint32 frame_usecs)
286 global_vc_info *hash_ent = hash_table[vc%64];
289 if (!hash_ent) return;
290 while(hash_ent->vc_num != vc) hash_ent = hash_ent->next;
291 if (!hash_ent) return;
293 vci = hash_ent->info;
294 while (vci->next) vci = vci->next;
295 vci->last_frame_secs = frame_secs;
296 vci->last_frame_usecs = frame_usecs;
299 void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc))(const u_char *, int, frame_data *, proto_tree *)
301 global_vc_info *hash_ent = hash_table[vc%64];
305 if (!hash_ent) return 0;
307 while(hash_ent && hash_ent->vc_num != vc) hash_ent = hash_ent->next;
308 if (!hash_ent) return 0;
310 /* a hash_ent was found for this VC number */
311 vci2 = vci = hash_ent->info;
313 /* looking for an entry matching our frame time */
314 while (vci && (vci->last_frame_secs < frame_secs ||
315 (vci->last_frame_secs == frame_secs &&
316 vci->last_frame_usecs < frame_usecs))) {
320 /* we reached last record, and previous record has a non zero
321 * last frame time ==> no dissector */
322 if (!vci && (vci2->last_frame_secs || vci2->last_frame_usecs)) return 0;
324 /* we reached last record, and previous record has a zero last frame time
325 * ==> dissector for previous frame has not been "stopped" by a Clear, etc */
327 /* if the start time for vci2 is greater than our frame time
328 * ==> no dissector */
329 if (frame_secs < vci2->first_frame_secs ||
330 (frame_secs == vci2->first_frame_secs &&
331 frame_usecs < vci2->first_frame_usecs))
334 return vci2->dissect;
337 /* our frame time is before vci's end. Check if it is adter vci's start */
338 if (frame_secs < vci->first_frame_secs ||
339 (frame_secs == vci->first_frame_secs &&
340 frame_usecs < vci->first_frame_usecs))
346 static char *clear_code(unsigned char code)
348 static char buffer[25];
350 if (code == 0x00 || (code & 0x80) == 0x80)
351 return "DTE Originated";
353 return "Number Busy";
355 return "Out Of Order";
357 return "Remote Procedure Error";
359 return "Reverse Charging Acceptance Not Subscribed";
361 return "Incompatible Destination";
363 return "Fast Select Acceptance Not Subscribed";
365 return "Destination Absent";
367 return "Invalid Facility Requested";
369 return "Access Barred";
371 return "Local Procedure Error";
373 return "Network Congestion";
375 return "Not Obtainable";
377 return "RPOA Out Of Order";
379 sprintf(buffer, "Unknown %02X", code);
384 static char *clear_diag(unsigned char code)
386 static char buffer[25];
389 return "No additional information";
391 return "Invalid P(S)";
393 return "Invalid P(R)";
395 return "Packet type invalid";
397 return "Packet type invalid for state r1";
399 return "Packet type invalid for state r2";
401 return "Packet type invalid for state r3";
403 return "Packet type invalid for state p1";
405 return "Packet type invalid for state p2";
407 return "Packet type invalid for state p3";
409 return "Packet type invalid for state p4";
411 return "Packet type invalid for state p5";
413 return "Packet type invalid for state p6";
415 return "Packet type invalid for state p7";
417 return "Packet type invalid for state d1";
419 return "Packet type invalid for state d2";
421 return "Packet type invalid for state d3";
423 return "Packet not allowed";
425 return "Unidentifiable packet";
427 return "Call on one-way logical channel";
429 return "Invalid packet type on a PVC";
431 return "Packet on unassigned LC";
433 return "Reject not subscribed to";
435 return "Packet too short";
437 return "Packet too long";
439 return "Invalid general format identifier";
441 return "Restart/registration packet with nonzero bits";
443 return "Packet type not compatible with facility";
445 return "Unauthorised interrupt confirmation";
447 return "Unauthorised interrupt";
449 return "Unauthorised reject";
451 return "Time expired";
453 return "Time expired for incoming call";
455 return "Time expired for clear indication";
457 return "Time expired for reset indication";
459 return "Time expired for restart indication";
461 return "Time expired for call deflection";
463 return "Call set-up/clearing or registration pb.";
465 return "Facility/registration code not allowed";
467 return "Facility parameter not allowed";
469 return "Invalid called DTE address";
471 return "Invalid calling DTE address";
473 return "Invalid facility/registration length";
475 return "Incoming call barred";
477 return "No logical channel available";
479 return "Call collision";
481 return "Duplicate facility requested";
483 return "Non zero address length";
485 return "Non zero facility length";
487 return "Facility not provided when expected";
489 return "Invalid CCITT-specified DTE facility";
491 return "Max. nb of call redir/defl. exceeded";
493 return "Miscellaneous";
495 return "Improper cause code from DTE";
497 return "Not aligned octet";
499 return "Inconsistent Q bit setting";
501 return "NUI problem";
503 return "International problem";
505 return "Remote network problem";
507 return "International protocol problem";
509 return "International link out of order";
511 return "International link busy";
513 return "Transit network facility problem";
515 return "Remote network facility problem";
517 return "International routing problem";
519 return "Temporary routing problem";
521 return "Unknown called DNIC";
523 return "Maintenance action";
525 sprintf(buffer, "Unknown %d", code);
530 static char *reset_code(unsigned char code)
532 static char buffer[25];
534 if (code == 0x00 || (code & 0x80) == 0x80)
535 return "DTE Originated";
537 return "Out of order";
539 return "Remote Procedure Error";
541 return "Local Procedure Error";
543 return "Network Congestion";
545 return "Remote DTE operational";
547 return "Network operational";
549 return "Incompatible Destination";
551 return "Network out of order";
553 sprintf(buffer, "Unknown %02X", code);
558 static char *restart_code(unsigned char code)
560 static char buffer[25];
562 if (code == 0x00 || (code & 0x80) == 0x80)
563 return "DTE Originated";
565 return "Local Procedure Error";
567 return "Network Congestion";
569 return "Network Operational";
571 return "Registration/cancellation confirmed";
573 sprintf(buffer, "Unknown %02X", code);
578 static char *registration_code(unsigned char code)
580 static char buffer[25];
583 return "Invalid facility request";
585 return "Network congestion";
587 return "Local procedure error";
589 return "Registration/cancellation confirmed";
591 sprintf(buffer, "Unknown %02X", code);
597 dump_facilities(proto_tree *tree, int *offset, const guint8 *p)
599 const guint8 *ptr = p;
600 guint32 len; /* facilities length */
604 proto_tree_add_text(tree, *offset, 1,
605 "Facilities length: %d", len);
609 switch(*ptr & X25_FAC_CLASS_MASK) {
610 case X25_FAC_CLASS_A:
612 case X25_FAC_COMP_MARK:
616 proto_tree_add_text(tree, *offset, 2,
617 "Network complementary services - calling DTE");
621 proto_tree_add_text(tree, *offset, 2,
622 "Network complementary services - called DTE");
626 proto_tree_add_text(tree, *offset, 2,
627 "DTE complementary services");
631 proto_tree_add_text(tree, *offset, 2,
636 case X25_FAC_REVERSE:
639 proto_tree_add_text(tree, *offset, 2,
642 proto_tree_add_text(tree, *offset, 2,
643 "No Reverse Charging");
645 proto_tree_add_text(tree, *offset, 2,
646 "Fast select with restriction");
647 else if (ptr[1] & 0x80)
648 proto_tree_add_text(tree, *offset, 2,
649 "Fast select - no restriction");
651 proto_tree_add_text(tree, *offset, 2,
655 case X25_FAC_THROUGHPUT:
657 int called_dte_throughput=0;
658 int calling_dte_throughput=0;
660 if ( (ptr[1] >> 4) >= 3 && (ptr[1] >> 4) <= 13 )
661 called_dte_throughput = 75*2^((ptr[1] >> 4)-3);
662 if ( (ptr[1] & 0x0F) >= 3 && (ptr[1] & 0x0F) <= 13 )
663 calling_dte_throughput = 75*2^((ptr[1] & 0x0F)-3);
664 proto_tree_add_text(tree, *offset, 2,
665 "Throughput: called DTE: %d - calling DTE: %d",
666 called_dte_throughput, calling_dte_throughput);
671 proto_tree_add_text(tree, *offset, 2,
672 "Closed user group: %d%d",
673 ptr[1] >> 4, ptr[1] & 0x0F);
675 case X25_FAC_CALLED_MODIF:
677 proto_tree_add_text(tree, *offset, 2,
678 "Called address modified: %02X",
681 case X25_FAC_CUG_OUTGOING_ACC:
683 proto_tree_add_text(tree, *offset, 2,
684 "CUG with outgoing access: %d%d",
685 ptr[1]>>4, ptr[1] & 0x0F);
687 case X25_FAC_THROUGHPUT_MIN:
689 proto_tree_add_text(tree, *offset, 2,
690 "Minimum throughput class");
692 case X25_FAC_EXPRESS_DATA:
694 proto_tree_add_text(tree, *offset, 2,
695 "Negociation of express data");
699 proto_tree_add_text(tree, *offset, 2,
700 "Unknown facility %02X, value %02X",
708 case X25_FAC_CLASS_B:
710 case X25_FAC_BILATERAL_CUG:
712 proto_tree_add_text(tree, *offset, 3,
713 "Bilateral CUG: %d%d%d%d",
719 case X25_FAC_PACKET_SIZE:
722 int called_dte_size, calling_dte_size;
727 called_dte_size = 16;
730 called_dte_size = 32;
733 called_dte_size = 64;
736 called_dte_size = 128;
739 called_dte_size = 256;
742 called_dte_size = 512;
745 called_dte_size = 1024;
748 called_dte_size = 2048;
751 called_dte_size = 4096;
761 calling_dte_size = 16;
764 calling_dte_size = 32;
767 calling_dte_size = 64;
770 calling_dte_size = 128;
773 calling_dte_size = 256;
776 calling_dte_size = 512;
779 calling_dte_size = 1024;
782 calling_dte_size = 2048;
785 calling_dte_size = 4096;
788 calling_dte_size = 0;
791 proto_tree_add_text(tree, *offset, 3,
792 "Packet Size: called DTE: %d - calling DTE: %d",
797 case X25_FAC_WINDOW_SIZE:
799 proto_tree_add_text(tree, *offset, 3,
800 "Window Size: called DTE: %d - calling DTE: %d",
803 case X25_FAC_RPOA_SELECTION:
805 proto_tree_add_text(tree, *offset, 3,
812 case X25_FAC_TRANSIT_DELAY:
814 proto_tree_add_text(tree, *offset, 3,
816 (ptr[1]<<8) + ptr[2]);
820 proto_tree_add_text(tree, *offset, 3,
821 "Unknown facility %02X, values %02X%02X",
822 ptr[0], ptr[1], ptr[2]);
829 case X25_FAC_CLASS_C:
831 proto_tree_add_text(tree, *offset, 4,
832 "Unknown facility %02X, values %02X%02X%02X",
833 ptr[0], ptr[1], ptr[2], ptr[3]);
838 case X25_FAC_CLASS_D:
840 case X25_FAC_CALL_TRANSFER:
842 proto_tree_add_text(tree, *offset, 2+ptr[1],
843 "Call Transfer: reason = %02X",
846 case X25_FAC_ADDR_EXT:
848 proto_tree_add_text(tree, *offset, 2+ptr[1],
849 "Address extension");
851 case X25_FAC_CALLED_ADDR_EXT:
853 proto_tree_add_text(tree, *offset, 2+ptr[1],
854 "Called address extension");
856 case X25_FAC_ETE_TRANSIT_DELAY:
858 proto_tree_add_text(tree, *offset, 2+ptr[1],
859 "End to end transit delay");
861 case X25_FAC_CALL_DEFLECT:
863 proto_tree_add_text(tree, *offset, 2+ptr[1],
864 "Call deflection: reason = %02X",
869 proto_tree_add_text(tree, *offset, 2+ptr[1],
870 "Unknown facility %02X, length %02X",
873 (*offset) += ptr[1]+2;
882 x25_ntoa(proto_tree *tree, int *offset, const guint8 *p,
883 frame_data *fd, gboolean toa)
887 char addr1[16], addr2[16];
888 char *first, *second;
890 len1 = (*p >> 0) & 0x0F;
891 len2 = (*p >> 4) & 0x0F;
893 proto_tree_add_text(tree, *offset, 1,
894 "%s address length : %d",
895 toa ? "Called" : "Calling",
897 proto_tree_add_text(tree, *offset, 1,
898 "%s address length : %d",
899 toa ? "Calling" : "Called",
908 for (i = 0; i < (len1 + len2); i++) {
911 *first++ = ((*p >> 0) & 0x0F) + '0';
914 *first++ = ((*p >> 4) & 0x0F) + '0';
918 *second++ = ((*p >> 0) & 0x0F) + '0';
921 *second++ = ((*p >> 4) & 0x0F) + '0';
930 if(check_col(fd, COL_RES_DL_DST))
931 col_add_str(fd, COL_RES_DL_DST, addr1);
933 proto_tree_add_text(tree, *offset,
936 toa ? "Called" : "Calling",
940 if(check_col(fd, COL_RES_DL_SRC))
941 col_add_str(fd, COL_RES_DL_SRC, addr2);
943 proto_tree_add_text(tree, *offset + len1/2,
944 (len2+1)/2+(len1%2+(len2+1)%2)/2,
946 toa ? "Calling" : "Called",
949 (*offset) += ((len1 + len2 + 1) / 2);
953 get_x25_pkt_len(const char *data, frame_data *fd, int offset)
955 int length, called_len, calling_len, dte_len, dce_len;
957 /* packet size should always be > 3 */
958 if (fd->cap_len - offset < 3) return fd->cap_len;
960 switch ((guint8)data[2])
962 case X25_CALL_REQUEST:
963 if (fd->cap_len > offset+3) /* pkt size > 3 */
965 called_len = (data[3] >> 0) & 0x0F;
966 calling_len = (data[3] >> 4) & 0x0F;
967 length = 4 + (called_len + calling_len + 1) / 2; /* addr */
968 if (length+offset < fd->cap_len)
969 length += (1 + data[length]); /* facilities */
971 else length = fd->cap_len - offset;
972 return MIN(fd->cap_len-offset,length);
974 case X25_CALL_ACCEPTED:
975 if (fd->cap_len > offset+3) /* pkt size > 3 */
977 called_len = (data[3] >> 0) & 0x0F;
978 calling_len = (data[3] >> 4) & 0x0F;
979 length = 4 + (called_len + calling_len + 1) / 2; /* addr */
980 if (length+offset < fd->cap_len)
981 length += (1 + data[length]); /* facilities */
983 else length = fd->cap_len - offset;
984 return MIN(fd->cap_len-offset,length);
986 case X25_CLEAR_REQUEST:
987 case X25_RESET_REQUEST:
988 case X25_RESTART_REQUEST:
989 return MIN(fd->cap_len-offset,5);
992 return MIN(fd->cap_len-offset,4);
994 case X25_CLEAR_CONFIRMATION:
996 case X25_INTERRUPT_CONFIRMATION:
997 case X25_RESET_CONFIRMATION:
998 case X25_RESTART_CONFIRMATION:
999 return MIN(fd->cap_len-offset,3);
1001 case X25_REGISTRATION_REQUEST:
1002 if (fd->cap_len > offset+3) /* pkt size > 3 */
1004 dce_len = (data[3] >> 0) & 0x0F;
1005 dte_len = (data[3] >> 4) & 0x0F;
1006 length = 4 + (dte_len + dce_len + 1) / 2; /* addr */
1007 if (length+offset < fd->cap_len)
1008 length += (1 + data[length]); /* registration */
1010 else length = fd->cap_len-offset;
1011 return MIN(fd->cap_len-offset,length);
1013 case X25_REGISTRATION_CONFIRMATION:
1014 if (fd->cap_len > offset+5) /* pkt size > 5 */
1016 dce_len = (data[5] >> 0) & 0x0F;
1017 dte_len = (data[5] >> 4) & 0x0F;
1018 length = 6 + (dte_len + dce_len + 1) / 2; /* addr */
1019 if (length+offset < fd->cap_len)
1020 length += (1 + data[length]); /* registration */
1022 else length = fd->cap_len-offset;
1023 return MIN(fd->cap_len-offset,length);
1026 if ((data[2] & 0x01) == X25_DATA) return MIN(fd->cap_len-offset,3);
1028 switch (data[2] & 0x1F)
1031 return MIN(fd->cap_len-offset,3);
1034 return MIN(fd->cap_len-offset,3);
1037 return MIN(fd->cap_len-offset,3);
1044 dissect_x25(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1046 proto_tree *x25_tree=0, *ti;
1047 int localoffset=offset;
1051 void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
1054 if (check_col(fd, COL_PROTOCOL))
1055 col_add_str(fd, COL_PROTOCOL, "X.25");
1057 modulo = ((pd[localoffset] & 0x20) ? 128 : 8);
1058 x25_pkt_len = get_x25_pkt_len(&pd[localoffset], fd, offset);
1059 if (x25_pkt_len < 3) /* packet too short */
1061 if (check_col(fd, COL_INFO))
1062 col_add_str(fd, COL_INFO, "Invalid/short X.25 packet");
1064 proto_tree_add_item_format(tree, (modulo == 8 ? proto_x25 : proto_ex25),
1065 localoffset, fd->cap_len - offset, NULL,
1066 "Invalid/short X.25 packet");
1069 vc = (int)(pd[localoffset] & 0x0F)*256 + (int)pd[localoffset+1];
1071 ti = proto_tree_add_item(tree, (modulo == 8) ? proto_x25 : proto_ex25,
1072 localoffset, x25_pkt_len, NULL);
1073 x25_tree = proto_item_add_subtree(ti, ett_x25);
1074 if (pd[localoffset] & 0x80)
1075 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_qbit : hf_ex25_qbit,
1076 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1077 if (pd[localoffset] & 0x40)
1078 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_dbit : hf_ex25_dbit,
1079 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1080 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_mod : hf_ex25_mod,
1081 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1083 switch (pd[localoffset+2]) {
1084 case X25_CALL_REQUEST:
1085 if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1088 if (check_col(fd, COL_INFO))
1089 col_add_fstr(fd, COL_INFO, "%s VC:%d",
1090 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Inc. call"
1094 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1095 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1096 proto_tree_add_item_format(x25_tree,
1097 (modulo == 8) ? hf_x25_type : hf_ex25_type,
1098 localoffset+2, 1, X25_CALL_REQUEST,
1099 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Incoming call"
1103 if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1104 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1106 if (localoffset < x25_pkt_len+offset) /* facilities */
1107 dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1109 if (localoffset < fd->cap_len) /* user data */
1111 if (pd[localoffset] == 0xCC)
1113 x25_hash_add_proto_start(vc, fd->abs_secs,
1114 fd->abs_usecs, dissect_ip);
1116 proto_tree_add_text(x25_tree, localoffset, 1,
1120 else if (pd[localoffset] == 0x03 &&
1121 pd[localoffset+1] == 0x01 &&
1122 pd[localoffset+2] == 0x01 &&
1123 pd[localoffset+3] == 0x00)
1125 x25_hash_add_proto_start(vc, fd->abs_secs,
1126 fd->abs_usecs, dissect_cotp);
1128 proto_tree_add_text(x25_tree, localoffset, 4,
1134 proto_tree_add_text(x25_tree, localoffset,
1135 fd->cap_len-localoffset, "Data");
1136 localoffset = fd->cap_len;
1140 case X25_CALL_ACCEPTED:
1141 if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1144 if(check_col(fd, COL_INFO))
1145 col_add_fstr(fd, COL_INFO, "%s VC:%d",
1146 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Call conn."
1150 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1151 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1152 proto_tree_add_item_format(x25_tree,
1153 (modulo == 8) ? hf_x25_type : hf_ex25_type,
1154 localoffset+2, 1, X25_CALL_ACCEPTED,
1155 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Call connected"
1159 if (localoffset < x25_pkt_len+offset) /* calling/called addresses */
1160 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1162 if (localoffset < x25_pkt_len+offset) /* facilities */
1163 dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1165 if (localoffset < fd->cap_len) { /* user data */
1167 proto_tree_add_text(x25_tree, localoffset,
1168 fd->cap_len-localoffset, "Data");
1169 localoffset=fd->cap_len;
1172 case X25_CLEAR_REQUEST:
1173 if(check_col(fd, COL_INFO)) {
1174 col_add_fstr(fd, COL_INFO, "%s VC:%d %s - %s",
1175 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Clear ind."
1177 vc, clear_code(pd[localoffset+3]),
1178 clear_diag(pd[localoffset+4]));
1180 x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1182 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1183 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1184 proto_tree_add_item_format(x25_tree,
1185 (modulo == 8) ? hf_x25_type : hf_ex25_type,
1186 localoffset+2, 1, X25_CLEAR_REQUEST,
1187 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Clear indication"
1189 if (localoffset+3 < x25_pkt_len+offset)
1190 proto_tree_add_text(x25_tree, localoffset+3, 1,
1191 "Cause : %s", clear_code(pd[localoffset+3]));
1192 if (localoffset+4 < x25_pkt_len+offset)
1193 proto_tree_add_text(x25_tree, localoffset+4, 1,
1195 clear_diag(pd[localoffset+4]));
1197 localoffset += x25_pkt_len;
1199 case X25_CLEAR_CONFIRMATION:
1200 if (pd[localoffset+2] & 0x80) /* TOA/NPI address format */
1203 if(check_col(fd, COL_INFO))
1204 col_add_fstr(fd, COL_INFO, "Clear Conf. VC:%d", vc);
1206 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1207 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1208 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1209 localoffset+2, 1, X25_CLEAR_CONFIRMATION);
1211 localoffset += x25_pkt_len;
1213 if (localoffset < fd->cap_len) /* extended clear conf format */
1214 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, toa);
1216 if (localoffset < fd->cap_len) /* facilities */
1217 dump_facilities(x25_tree, &localoffset, &pd[localoffset]);
1219 case X25_DIAGNOSTIC:
1220 if(check_col(fd, COL_INFO)) {
1221 col_add_fstr(fd, COL_INFO, "Diag. %d", (int)pd[localoffset+3]);
1224 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1225 localoffset+2, 1, X25_DIAGNOSTIC);
1226 if (localoffset+3 < x25_pkt_len+offset)
1227 proto_tree_add_text(x25_tree, localoffset+3, 1,
1228 "Diagnostic : %d", (int)pd[localoffset+3]);
1230 localoffset += x25_pkt_len;
1233 if(check_col(fd, COL_INFO))
1234 col_add_fstr(fd, COL_INFO, "Interrupt VC:%d", vc);
1236 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1237 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1238 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1239 localoffset+2, 1, X25_INTERRUPT);
1241 localoffset += x25_pkt_len;
1243 case X25_INTERRUPT_CONFIRMATION:
1244 if(check_col(fd, COL_INFO))
1245 col_add_fstr(fd, COL_INFO, "Interrupt Conf. VC:%d", vc);
1247 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1248 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1249 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1250 localoffset+2, 1, X25_INTERRUPT_CONFIRMATION);
1252 localoffset += x25_pkt_len;
1254 case X25_RESET_REQUEST:
1255 if(check_col(fd, COL_INFO)) {
1256 col_add_fstr(fd, COL_INFO, "%s VC:%d %s - Diag.:%d",
1257 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset ind."
1259 vc, reset_code(pd[localoffset+3]),
1260 (int)pd[localoffset+4]);
1262 x25_hash_add_proto_end(vc, fd->abs_secs, fd->abs_usecs);
1264 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1265 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1266 proto_tree_add_item_format(x25_tree,
1267 (modulo == 8) ? hf_x25_type : hf_ex25_type, localoffset+2, 1,
1269 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Reset indication"
1271 if (localoffset+3 < x25_pkt_len+offset)
1272 proto_tree_add_text(x25_tree, localoffset+3, 1,
1273 "Cause : %s", reset_code(pd[localoffset+3]));
1274 if (localoffset+4 < x25_pkt_len+offset)
1275 proto_tree_add_text(x25_tree, localoffset+4, 1,
1276 "Diagnostic : %d", (int)pd[localoffset+4]);
1278 localoffset += x25_pkt_len;
1280 case X25_RESET_CONFIRMATION:
1281 if(check_col(fd, COL_INFO))
1282 col_add_fstr(fd, COL_INFO, "Reset conf. VC:%d", vc);
1284 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1285 localoffset, 2, pd[localoffset]*256+pd[localoffset+1]);
1286 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1287 localoffset+2, 1, X25_RESET_CONFIRMATION);
1289 localoffset += x25_pkt_len;
1291 case X25_RESTART_REQUEST:
1292 if(check_col(fd, COL_INFO)) {
1293 col_add_fstr(fd, COL_INFO, "%s %s - Diag.:%d",
1294 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Restart ind."
1296 restart_code(pd[localoffset+3]),
1297 (int)pd[localoffset+4]);
1300 proto_tree_add_item_format(x25_tree,
1301 (modulo == 8) ? hf_x25_type : hf_ex25_type, localoffset+2, 1,
1302 X25_RESTART_REQUEST,
1303 (fd->pseudo_header.x25.flags & FROM_DCE) ? "Restart indication"
1304 : "Restart request");
1305 if (localoffset+3 < x25_pkt_len+offset)
1306 proto_tree_add_text(x25_tree, localoffset+3, 1,
1307 "Cause : %s", restart_code(pd[localoffset+3]));
1308 if (localoffset+4 < x25_pkt_len+offset)
1309 proto_tree_add_text(x25_tree, localoffset+4, 1,
1310 "Diagnostic : %d", (int)pd[localoffset+4]);
1312 localoffset += x25_pkt_len;
1314 case X25_RESTART_CONFIRMATION:
1315 if(check_col(fd, COL_INFO))
1316 col_add_str(fd, COL_INFO, "Restart conf.");
1318 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1319 localoffset+2, 1, X25_RESTART_CONFIRMATION);
1320 localoffset += x25_pkt_len;
1322 case X25_REGISTRATION_REQUEST:
1323 if(check_col(fd, COL_INFO))
1324 col_add_str(fd, COL_INFO, "Registration req.");
1326 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1327 localoffset+2, 1, X25_REGISTRATION_REQUEST);
1329 if (localoffset < x25_pkt_len+offset)
1330 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, FALSE);
1333 if (localoffset < x25_pkt_len+offset)
1334 proto_tree_add_text(x25_tree, localoffset, 1,
1335 "Registration length: %d", pd[localoffset] & 0x7F);
1336 if (localoffset+1 < x25_pkt_len+offset)
1337 proto_tree_add_text(x25_tree, localoffset+1,
1338 pd[localoffset] & 0x7F, "Registration");
1340 localoffset = fd->cap_len;
1342 case X25_REGISTRATION_CONFIRMATION:
1343 if(check_col(fd, COL_INFO))
1344 col_add_str(fd, COL_INFO, "Registration conf.");
1346 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type,
1347 localoffset+2, 1, X25_REGISTRATION_CONFIRMATION);
1348 if (localoffset+3 < x25_pkt_len+offset)
1349 proto_tree_add_text(x25_tree, localoffset+3, 1,
1350 "Cause: %s", registration_code(pd[localoffset+3]));
1351 if (localoffset+4 < x25_pkt_len+offset)
1352 proto_tree_add_text(x25_tree, localoffset+4, 1,
1353 "Diagnostic: %s", registration_code(pd[localoffset+4]));
1356 if (localoffset < x25_pkt_len+offset)
1357 x25_ntoa(x25_tree, &localoffset, &pd[localoffset], fd, TRUE);
1360 if (localoffset < x25_pkt_len+offset)
1361 proto_tree_add_text(x25_tree, localoffset, 1,
1362 "Registration length: %d", pd[localoffset] & 0x7F);
1363 if (localoffset+1 < x25_pkt_len+offset)
1364 proto_tree_add_text(x25_tree, localoffset+1,
1365 pd[localoffset] & 0x7F, "Registration");
1367 localoffset = fd->cap_len;
1371 if ((pd[localoffset] & 0x01) == X25_DATA)
1373 if(check_col(fd, COL_INFO)) {
1375 col_add_fstr(fd, COL_INFO,
1376 "Data VC:%d P(S):%d P(R):%d %s", vc,
1377 (pd[localoffset] >> 1) & 0x07,
1378 (pd[localoffset] >> 5) & 0x07,
1379 ((pd[localoffset]>>4) & 0x01) ? " M" : "");
1381 col_add_fstr(fd, COL_INFO,
1382 "Data VC:%d P(S):%d P(R):%d %s", vc,
1383 pd[localoffset+1] >> 1,
1384 pd[localoffset] >> 1,
1385 (pd[localoffset+1] & 0x01) ? " M" : "");
1388 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1389 localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1391 proto_tree_add_item_hidden(x25_tree, hf_x25_type, localoffset, 1,
1393 proto_tree_add_item(x25_tree, hf_x25_p_r, localoffset, 1,
1395 if (pd[localoffset] & 0x10)
1396 proto_tree_add_item(x25_tree, hf_x25_mbit, localoffset, 1,
1398 proto_tree_add_item(x25_tree, hf_x25_p_s, localoffset, 1,
1400 proto_tree_add_text(x25_tree, localoffset, 1,
1401 decode_boolean_bitfield(pd[localoffset], 0x01, 1*8,
1405 proto_tree_add_item_hidden(x25_tree, hf_ex25_type, localoffset, 1,
1407 proto_tree_add_item(x25_tree, hf_x25_p_r, localoffset, 1,
1409 proto_tree_add_item(x25_tree, hf_x25_p_s, localoffset+1, 1,
1411 if (pd[localoffset+1] & 0x01)
1412 proto_tree_add_item(x25_tree, hf_ex25_mbit, localoffset+1, 1,
1416 localoffset += (modulo == 8) ? 1 : 2;
1419 switch (pd[localoffset] & 0x1F)
1422 if(check_col(fd, COL_INFO)) {
1424 col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1425 vc, (pd[localoffset] >> 5) & 0x07);
1427 col_add_fstr(fd, COL_INFO, "RR VC:%d P(R):%d",
1428 vc, pd[localoffset+1] >> 1);
1431 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1432 localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1434 proto_tree_add_item(x25_tree, hf_x25_p_r,
1435 localoffset, 1, pd[localoffset]);
1436 proto_tree_add_item(x25_tree, hf_x25_type, localoffset, 1, X25_RR);
1439 proto_tree_add_item(x25_tree, hf_ex25_type, localoffset, 1, X25_RR);
1440 proto_tree_add_item(x25_tree, hf_ex25_p_r,
1441 localoffset+1, 1, pd[localoffset+1]);
1447 if(check_col(fd, COL_INFO)) {
1449 col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1450 vc, (pd[localoffset] >> 5) & 0x07);
1452 col_add_fstr(fd, COL_INFO, "RNR VC:%d P(R):%d",
1453 vc, pd[localoffset+1] >> 1);
1456 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1457 localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1459 proto_tree_add_item(x25_tree, hf_x25_p_r,
1460 localoffset, 1, pd[localoffset]);
1461 proto_tree_add_item(x25_tree, hf_x25_type, localoffset, 1, X25_RNR);
1464 proto_tree_add_item(x25_tree, hf_ex25_type, localoffset, 1, X25_RNR);
1465 proto_tree_add_item(x25_tree, hf_ex25_p_r,
1466 localoffset+1, 1, pd[localoffset+1]);
1472 if(check_col(fd, COL_INFO)) {
1474 col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1475 vc, (pd[localoffset] >> 5) & 0x07);
1477 col_add_fstr(fd, COL_INFO, "REJ VC:%d P(R):%d",
1478 vc, pd[localoffset+1] >> 1);
1481 proto_tree_add_item(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn,
1482 localoffset-2, 2, pd[localoffset-2]*256+pd[localoffset-1]);
1484 proto_tree_add_item(x25_tree, hf_x25_p_r,
1485 localoffset, 1, pd[localoffset]);
1486 proto_tree_add_item(x25_tree, hf_x25_type, localoffset, 1, X25_REJ);
1489 proto_tree_add_item(x25_tree, hf_ex25_type, localoffset, 1, X25_REJ);
1490 proto_tree_add_item(x25_tree, hf_ex25_p_r,
1491 localoffset+1, 1, pd[localoffset+1]);
1495 localoffset += (modulo == 8) ? 1 : 2;
1498 if (localoffset >= fd->cap_len) return;
1500 /* search the dissector in the hash table */
1501 if ((dissect = x25_hash_get_dissect(fd->abs_secs, fd->abs_usecs, vc)))
1502 (*dissect)(pd, localoffset, fd, tree);
1504 if (pd[localoffset] == 0x45) /* If the Call Req. has not been captured,
1505 * assume these packets carry IP */
1507 x25_hash_add_proto_start(vc, fd->abs_secs,
1508 fd->abs_usecs, dissect_ip);
1509 dissect_ip(pd, localoffset, fd, tree);
1512 dissect_data(pd, localoffset, fd, tree);
1518 proto_register_x25(void)
1520 static hf_register_info hf8[] = {
1522 { "Q Bit", "x25.q", FT_BOOLEAN, 2, NULL, 0x8000,
1523 "Qualifier Bit" } },
1525 { "D Bit", "x25.d", FT_BOOLEAN, 2, NULL, 0x4000,
1526 "Delivery Confirmation Bit" } },
1528 { "Modulo", "x25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000,
1529 "Specifies whether the frame is modulo 8 or 128" } },
1531 { "Logical Channel", "x25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF,
1532 "Logical Channel Number" } },
1534 { "Packet Type", "x25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0,
1537 { "P(R)", "x25.p_r", FT_UINT8, BASE_HEX, NULL, 0xE0,
1538 "Packet Receive Sequence Number" } },
1540 { "M Bit", "x25.m", FT_BOOLEAN, 1, NULL, 0x10,
1543 { "P(S)", "x25.p_s", FT_UINT8, BASE_HEX, NULL, 0x0E,
1544 "Packet Send Sequence Number" } },
1547 static hf_register_info hf128[] = {
1549 { "Q Bit", "ex25.q", FT_BOOLEAN, 2, NULL, 0x8000,
1550 "Qualifier Bit" } },
1552 { "D Bit", "ex25.d", FT_BOOLEAN, 2, NULL, 0x4000,
1553 "Delivery Confirmation Bit" } },
1555 { "Modulo", "ex25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000,
1556 "Specifies whether the frame is modulo 8 or 128" } },
1558 { "Logical Channel", "ex25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF,
1559 "Logical Channel Number" } },
1561 { "Packet Type", "ex25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0,
1564 { "P(R)", "ex25.p_r", FT_UINT8, BASE_HEX, NULL, 0xFE,
1565 "Packet Receive Sequence Number" } },
1567 { "M Bit", "ex25.m", FT_BOOLEAN, 1, NULL, 0x01,
1570 { "P(S)", "ex25.p_s", FT_UINT8, BASE_HEX, NULL, 0xFE,
1571 "Packet Send Sequence Number" } },
1573 static gint *ett[] = {
1577 proto_x25 = proto_register_protocol ("X.25", "x25");
1578 proto_ex25 = proto_register_protocol ("Extended X.25 (modulo 128)", "ex25");
1579 proto_register_field_array (proto_x25, hf8, array_length(hf8));
1580 proto_register_field_array (proto_ex25, hf128, array_length(hf128));
1581 proto_register_subtree_array(ett, array_length(ett));