2 * Routines for ISO/OSI transport protocol packet disassembly
5 * Laurent Deniel <laurent.deniel@free.fr>
6 * Ralf Schneider <Ralf.Schneider@t-online.de>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
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.
32 #include <epan/prefs.h>
33 #include <epan/packet.h>
34 #include <epan/reassemble.h>
35 #include <epan/conversation.h>
36 #include <epan/emem.h>
37 #include "packet-frame.h"
38 #include "packet-osi.h"
39 #include "packet-osi-options.h"
40 #include "packet-isis.h"
41 #include "packet-esis.h"
42 #include <epan/nlpid.h>
43 #include <epan/ipproto.h>
44 #include <epan/expert.h>
45 #include <epan/strutil.h>
47 /* protocols and fields */
49 static int proto_clnp;
51 static int proto_cotp = -1;
52 static gint ett_cotp = -1;
53 static gint ett_cotp_segments = -1;
54 static gint ett_cotp_segment = -1;
56 static int hf_cotp_li = -1;
57 static int hf_cotp_type = -1;
58 static int hf_cotp_srcref = -1;
59 static int hf_cotp_destref = -1;
60 static int hf_cotp_class = -1;
61 static int hf_cotp_opts_extended_formats = -1;
62 static int hf_cotp_opts_no_explicit_flow_control = -1;
63 static int hf_cotp_tpdu_number = -1;
64 static int hf_cotp_tpdu_number_extended = -1;
65 static int hf_cotp_next_tpdu_number = -1;
66 static int hf_cotp_next_tpdu_number_extended = -1;
67 static int hf_cotp_eot = -1;
68 static int hf_cotp_eot_extended = -1;
70 static int hf_cotp_segments = -1;
71 static int hf_cotp_segment = -1;
72 static int hf_cotp_segment_overlap = -1;
73 static int hf_cotp_segment_overlap_conflict = -1;
74 static int hf_cotp_segment_multiple_tails = -1;
75 static int hf_cotp_segment_too_long_segment = -1;
76 static int hf_cotp_segment_error = -1;
77 static int hf_cotp_reassembled_in = -1;
78 static int hf_cotp_reassembled_length = -1;
80 static const true_false_string fragment_descriptions = {
85 static int proto_cltp = -1;
86 static gint ett_cltp = -1;
88 static int hf_cltp_li = -1;
89 static int hf_cltp_type = -1;
91 static const fragment_items cotp_frag_items = {
96 &hf_cotp_segment_overlap,
97 &hf_cotp_segment_overlap_conflict,
98 &hf_cotp_segment_multiple_tails,
99 &hf_cotp_segment_too_long_segment,
100 &hf_cotp_segment_error,
101 &hf_cotp_reassembled_in,
102 &hf_cotp_reassembled_length,
106 static dissector_handle_t data_handle;
109 * ISO8073 OSI COTP definition
110 * See http://standards.iso.org/ittf/PubliclyAvailableStandards/index.html
111 * (or RFC905 for historic, and now-outdated information)
114 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
116 /* TPDU definition */
118 #define ED_TPDU 0x1 /* COTP */
119 #define EA_TPDU 0x2 /* COTP */
120 #define UD_TPDU 0x4 /* CLTP */
121 #define RJ_TPDU 0x5 /* COTP */
122 #define AK_TPDU 0x6 /* COTP */
123 #define ER_TPDU 0x7 /* COTP */
124 #define DR_TPDU 0x8 /* COTP */
125 #define DC_TPDU 0xC /* COTP */
126 #define CC_TPDU 0xD /* COTP */
127 #define CR_TPDU 0xE /* COTP */
128 #define DT_TPDU 0xF /* COTP */
130 static const value_string cotp_tpdu_type_abbrev_vals[] = {
131 { ED_TPDU, "ED Expedited Data" },
132 { EA_TPDU, "EA Expedited Data Acknowledgement" },
133 { RJ_TPDU, "RJ Reject" },
134 { AK_TPDU, "AK Data Acknowledgement" },
135 { ER_TPDU, "ER TPDU Error" },
136 { DR_TPDU, "DR Disconnect Request" },
137 { DC_TPDU, "DC Disconnect Confirm" },
138 { CC_TPDU, "CC Connect Confirm" },
139 { CR_TPDU, "CR Connect Request" },
140 { DT_TPDU, "DT Data" },
144 static const value_string cltp_tpdu_type_abbrev_vals[] = {
149 static const value_string class_option_vals[] = {
165 #define P_TPDU_NR_0_1 2
166 #define P_TPDU_NR_234 4
167 #define P_VAR_PART_NDT 5
168 #define P_VAR_PART_EDT 8
169 #define P_VAR_PART_DC 6
170 #define P_CDT_IN_AK 8
171 #define P_CDT_IN_RJ 8
172 #define P_REJECT_ER 4
173 #define P_REASON_IN_DR 6
174 #define P_CLASS_OPTION 6
176 /* TPDU length indicator */
178 #define LI_NORMAL_DT_CLASS_01 2
179 #define LI_NORMAL_DT_WITH_CHECKSUM 8
180 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
181 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
182 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
183 #define LI_NORMAL_EA_WITH_CHECKSUM 8
184 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
185 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
186 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
187 #define LI_NORMAL_RJ 4
188 #define LI_EXTENDED_RJ 9
194 /* XXX - can we always decide this based on whether the length
195 indicator is odd or not? What if the variable part has an odd
197 #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
201 #define VP_ACK_TIME 0x85
202 #define VP_RES_ERROR 0x86
203 #define VP_PRIORITY 0x87
204 #define VP_TRANSIT_DEL 0x88
205 #define VP_THROUGHPUT 0x89
206 #define VP_SEQ_NR 0x8A /* in AK */
207 #define VP_REASSIGNMENT 0x8B
208 #define VP_FLOW_CNTL 0x8C /* in AK */
209 #define VP_TPDU_SIZE 0xC0
210 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
211 #define VP_DST_TSAP 0xC2
212 #define VP_CHECKSUM 0xC3
213 #define VP_VERSION_NR 0xC4
214 #define VP_PROTECTION 0xC5
215 #define VP_OPT_SEL 0xC6
216 #define VP_PROTO_CLASS 0xC7
217 #define VP_PREF_MAX_TPDU_SIZE 0xF0
218 #define VP_INACTIVITY_TIMER 0xF2
220 static const value_string tp_vpart_type_vals[] = {
221 { VP_ACK_TIME, "ack time" },
222 { VP_RES_ERROR, "res error" },
223 { VP_PRIORITY, "priority" },
224 { VP_TRANSIT_DEL, "transit delay" },
225 { VP_THROUGHPUT, "throughput" },
226 { VP_SEQ_NR, "seq number" },
227 { VP_REASSIGNMENT, "reassignment" },
228 { VP_FLOW_CNTL, "flow control" },
229 { VP_TPDU_SIZE, "tpdu-size" },
230 { VP_SRC_TSAP, "src-tsap" },
231 { VP_DST_TSAP, "dst-tsap" },
232 { VP_CHECKSUM, "checksum" },
233 { VP_VERSION_NR, "version" },
234 { VP_PROTECTION, "protection" },
235 { VP_OPT_SEL, "options" },
236 { VP_PROTO_CLASS, "proto class" },
237 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
241 static int hf_cotp_vp_src_tsap = -1;
242 static int hf_cotp_vp_dst_tsap = -1;
243 static int hf_cotp_vp_src_tsap_bytes = -1;
244 static int hf_cotp_vp_dst_tsap_bytes = -1;
246 /* global variables */
248 /* List of dissectors to call for COTP packets put atop the Inactive
250 static heur_dissector_list_t cotp_is_heur_subdissector_list;
251 /* List of dissectors to call for COTP packets put atop CLNP */
252 static heur_dissector_list_t cotp_heur_subdissector_list;
253 /* List of dissectors to call for CLTP packets put atop CLNP */
254 static heur_dissector_list_t cltp_heur_subdissector_list;
257 * Reassembly of COTP.
259 static GHashTable *cotp_segment_table = NULL;
260 static GHashTable *cotp_reassembled_table = NULL;
261 static guint16 cotp_dst_ref = 0;
262 static gboolean cotp_frame_reset = FALSE;
263 static gboolean cotp_last_fragment = FALSE;
265 #define TSAP_DISPLAY_AUTO 0
266 #define TSAP_DISPLAY_STRING 1
267 #define TSAP_DISPLAY_BYTES 2
271 static gboolean cotp_reassemble = TRUE;
272 static gint32 tsap_display = TSAP_DISPLAY_AUTO;
274 const enum_val_t tsap_display_options[] = {
275 {"auto", "As strings if printable", TSAP_DISPLAY_AUTO},
276 {"string", "As strings", TSAP_DISPLAY_STRING},
277 {"bytes", "As bytes", TSAP_DISPLAY_BYTES},
282 /* function definitions */
284 #define MAX_TSAP_LEN 32
286 static void cotp_frame_end(void)
288 if (!cotp_last_fragment) {
289 /* Last COTP in frame is not fragmented.
290 * No need for incrementing the dst_ref, so we decrement it here.
294 cotp_frame_reset = TRUE;
297 static gboolean is_all_printable(const guchar *stringtocheck, int length)
299 gboolean allprintable;
303 for (i=0;i<length;i++) {
304 if (!(isascii(stringtocheck[i]) && isprint(stringtocheck[i]))) {
310 } /* is_all_printable */
313 static gchar *print_tsap(const guchar *tsap, int length)
317 gboolean allprintable;
318 gint idx = 0, returned_length;
320 cur=ep_alloc(MAX_TSAP_LEN * 2 + 3);
322 if (length <= 0 || length > MAX_TSAP_LEN)
323 g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "<unsupported TSAP length>");
325 allprintable = is_all_printable(tsap,length);
327 returned_length = g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x");
328 idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1);
330 while (length != 0) {
332 returned_length = g_snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, "%c", *tsap ++);
333 idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1 );
335 returned_length = g_snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, "%02x", *tsap ++);
336 idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1);
345 static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
346 int vp_length, int class_option,
351 guint16 s, s1,s2,s3,s4;
352 guint32 t1, t2, t3, t4;
353 guint32 pref_max_tpdu_size;
354 proto_item *hidden_item;
356 while (vp_length != 0) {
357 code = tvb_get_guint8(tvb, offset);
358 proto_tree_add_text(tree, tvb, offset, 1,
359 "Parameter code: 0x%02x (%s)",
361 val_to_str(code, tp_vpart_type_vals, "Unknown"));
367 length = tvb_get_guint8(tvb, offset);
368 proto_tree_add_text(tree, tvb, offset, 1,
369 "Parameter length: %u", length);
376 s = tvb_get_ntohs(tvb, offset);
377 proto_tree_add_text(tree, tvb, offset, length,
378 "Ack time (ms): %u", s);
384 proto_tree_add_text(tree, tvb, offset, 1,
385 "Residual error rate, target value: 10^%u",
386 tvb_get_guint8(tvb, offset));
391 proto_tree_add_text(tree, tvb, offset, 1,
392 "Residual error rate, minimum acceptable: 10^%u",
393 tvb_get_guint8(tvb, offset));
399 proto_tree_add_text(tree, tvb, offset, 1,
400 "Residual error rate, TSDU size of interest: %u",
401 1<<tvb_get_guint8(tvb, offset));
408 s = tvb_get_ntohs(tvb, offset);
409 proto_tree_add_text(tree, tvb, offset, length,
416 s1 = tvb_get_ntohs(tvb, offset);
417 proto_tree_add_text(tree, tvb, offset, 2,
418 "Transit delay, target value, calling-called: %u ms", s1);
423 s2 = tvb_get_ntohs(tvb, offset);
424 proto_tree_add_text(tree, tvb, offset, 2,
425 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
430 s3 = tvb_get_ntohs(tvb, offset);
431 proto_tree_add_text(tree, tvb, offset, 2,
432 "Transit delay, target value, called-calling: %u ms", s3);
437 s4 = tvb_get_ntohs(tvb, offset);
438 proto_tree_add_text(tree, tvb, offset, 2,
439 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
445 t1 = tvb_get_ntoh24(tvb, offset);
446 proto_tree_add_text(tree, tvb, offset, 3,
447 "Maximum throughput, target value, calling-called: %u o/s", t1);
452 t2 = tvb_get_ntoh24(tvb, offset);
453 proto_tree_add_text(tree, tvb, offset, 3,
454 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
459 t3 = tvb_get_ntoh24(tvb, offset);
460 proto_tree_add_text(tree, tvb, offset, 3,
461 "Maximum throughput, target value, called-calling: %u o/s", t3);
466 t4 = tvb_get_ntoh24(tvb, offset);
467 proto_tree_add_text(tree, tvb, offset, 3,
468 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
473 if (length != 0) { /* XXX - should be 0 or 12 */
474 t1 = tvb_get_ntoh24(tvb, offset);
475 proto_tree_add_text(tree, tvb, offset, 3,
476 "Average throughput, target value, calling-called: %u o/s", t1);
481 t2 = tvb_get_ntoh24(tvb, offset);
482 proto_tree_add_text(tree, tvb, offset, 3,
483 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
488 t3 = tvb_get_ntoh24(tvb, offset);
489 proto_tree_add_text(tree, tvb, offset, 3,
490 "Average throughput, target value, called-calling: %u o/s", t3);
495 t4 = tvb_get_ntoh24(tvb, offset);
496 proto_tree_add_text(tree, tvb, offset, 3,
497 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
504 proto_tree_add_text(tree, tvb, offset, 2,
505 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
510 case VP_REASSIGNMENT:
511 proto_tree_add_text(tree, tvb, offset, 2,
512 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
518 proto_tree_add_text(tree, tvb, offset, 4,
519 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
524 proto_tree_add_text(tree, tvb, offset, 2,
525 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
530 proto_tree_add_text(tree, tvb, offset, 2,
531 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
538 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
539 proto_tree_add_text(tree, tvb, offset, length,
540 "TPDU size: %u", 1 << c1);
546 /* if our preference is set to STRING or the
547 TSAP is not printable, add as bytes and hidden as string;
548 otherwise vice-versa */
549 if (tsap_display==TSAP_DISPLAY_STRING ||
550 (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
551 proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
552 print_tsap(tvb_get_ptr(tvb, offset, length),length));
553 hidden_item = proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
554 PROTO_ITEM_SET_HIDDEN(hidden_item);
556 hidden_item = proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
557 print_tsap(tvb_get_ptr(tvb, offset, length),length));
558 PROTO_ITEM_SET_HIDDEN(hidden_item);
559 proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
566 /* if our preference is set to STRING or the
567 TSAP is not printable, add as bytes and hidden as string;
568 otherwise vice-versa */
569 if (tsap_display==TSAP_DISPLAY_STRING ||
570 (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
571 proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
572 print_tsap(tvb_get_ptr(tvb, offset, length),length));
573 hidden_item = proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
574 PROTO_ITEM_SET_HIDDEN(hidden_item);
576 hidden_item = proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
577 print_tsap(tvb_get_ptr(tvb, offset, length),length));
578 PROTO_ITEM_SET_HIDDEN(hidden_item);
579 proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
586 proto_tree_add_text(tree, tvb, offset, length,
587 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
593 c1 = tvb_get_guint8(tvb, offset);
594 proto_tree_add_text(tree, tvb, offset, length,
601 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
602 switch (class_option) {
606 proto_tree_add_text(tree, tvb, offset, 1,
607 "Use of network expedited data");
609 proto_tree_add_text(tree, tvb, offset, 1,
610 "Non use of network expedited data");
612 proto_tree_add_text(tree, tvb, offset, 1,
613 "Use of Receipt confirmation");
615 proto_tree_add_text(tree, tvb, offset, 1,
616 "Use of explicit AK variant");
621 proto_tree_add_text(tree, tvb, offset, 1,
622 "Non-use 16 bit checksum in class 4");
624 proto_tree_add_text(tree, tvb, offset, 1,
625 "Use 16 bit checksum ");
629 proto_tree_add_text(tree, tvb, offset, 1,
630 "Use of transport expedited data transfer");
632 proto_tree_add_text(tree, tvb, offset, 1,
633 "Non-use of transport expedited data transfer");
638 case VP_PREF_MAX_TPDU_SIZE:
642 pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
646 pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
650 pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
654 pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
658 proto_tree_add_text(tree, tvb, offset, length,
659 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
663 proto_tree_add_text(tree, tvb, offset, length,
664 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
669 case VP_INACTIVITY_TIMER:
670 proto_tree_add_text(tree, tvb, offset, length,
671 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
676 case VP_PROTECTION: /* user-defined */
677 case VP_PROTO_CLASS: /* todo */
678 default: /* unknown, no decoding */
679 proto_tree_add_text(tree, tvb, offset, length,
680 "Parameter value: <not shown>");
690 static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
691 packet_info *pinfo, proto_tree *tree)
693 proto_tree *cotp_tree;
694 proto_item *ti = NULL;
695 guint16 dst_ref, src_ref;
702 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
704 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
706 reason = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
708 pinfo->clnp_dstref = dst_ref;
709 pinfo->clnp_srcref = src_ref;
711 /* the settings of the TCP srcport and destport are currently disables,
712 * for the following reasons:
713 * a) only used for ISO conversation handling (which currently doesn't work)
714 * b) will prevent "ISO on TCP" (RFC1006) packets from using "follow TCP stream" correctly
716 * A future conversation handling might be able to handle different kinds of conversations
717 * (TCP, ISO, TCP on TCP, ...), but in that case this has to be fixed in any case.
719 /*pinfo->srcport = src_ref;*/
720 /*pinfo->destport = dst_ref;*/
722 case (128+0): str = "Normal Disconnect"; break;
723 case (128+1): str = "Remote transport entity congestion"; break;
724 case (128+2): str = "Connection negotiation failed"; break;
725 case (128+3): str = "Duplicate source reference"; break;
726 case (128+4): str = "Mismatched references"; break;
727 case (128+5): str = "Protocol error"; break;
728 case (128+7): str = "Reference overflow"; break;
729 case (128+8): str = "Connection request refused"; break;
730 case (128+10):str = "Header or parameter length invalid"; break;
731 case (0): str = "Reason not specified"; break;
732 case (1): str = "Congestion at TSAP"; break;
733 case (2): str = "Session entity not attached to TSAP"; break;
734 case (3): str = "Address unknown"; break;
738 if (check_col(pinfo->cinfo, COL_INFO))
739 col_append_fstr(pinfo->cinfo, COL_INFO,
740 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
744 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
745 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
746 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
747 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
748 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
749 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset + 4, 2, src_ref);
750 proto_tree_add_text(cotp_tree, tvb, offset + 6, 1,
756 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_CHAT,
757 "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref);
760 call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree);
761 offset += tvb_length_remaining(tvb, offset);
762 /* we dissected all of the containing PDU */
766 } /* ositp_decode_DR */
768 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
769 packet_info *pinfo, proto_tree *tree,
770 gboolean uses_inactive_subset,
771 gboolean *subdissector_found)
773 proto_tree *cotp_tree = NULL;
775 gboolean is_extended;
776 gboolean is_class_234;
778 guint32 *prev_dst_ref;
780 gboolean fragment = FALSE;
781 guint32 fragment_length = 0;
783 fragment_data *fd_head;
784 conversation_t *conv;
786 /* VP_CHECKSUM is the only parameter allowed in the variable part.
787 (This means we may misdissect this if the packet is bad and
788 contains other parameters.) */
791 case LI_NORMAL_DT_WITH_CHECKSUM :
792 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
796 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
797 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
798 if ( tpdu_nr & 0x80 )
799 tpdu_nr = tpdu_nr & 0x7F;
804 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
807 case LI_EXTENDED_DT_WITH_CHECKSUM :
808 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
812 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
813 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
814 if ( tpdu_nr & 0x80000000 )
815 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
820 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
823 case LI_NORMAL_DT_CLASS_01 :
824 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
825 if ( tpdu_nr & 0x80 )
826 tpdu_nr = tpdu_nr & 0x7F;
830 is_class_234 = FALSE;
831 prev_dst_ref = p_get_proto_data (pinfo->fd, proto_clnp);
833 /* First COTP in frame - save previous dst_ref as offset */
834 prev_dst_ref = se_alloc (sizeof (guint32));
835 *prev_dst_ref = cotp_dst_ref;
836 p_add_proto_data (pinfo->fd, proto_clnp, prev_dst_ref);
837 } else if (cotp_frame_reset) {
838 cotp_dst_ref = *prev_dst_ref;
840 cotp_frame_reset = FALSE;
841 cotp_last_fragment = fragment;
842 dst_ref = cotp_dst_ref;
843 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
844 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
846 /* Found a conversation, also use index for the generated dst_ref */
847 dst_ref += (conv->index << 16);
851 register_frame_end_routine(cotp_frame_end);
855 default : /* bad TPDU */
859 pinfo->clnp_dstref = dst_ref;
861 pinfo->fragmented = fragment;
862 if (check_col(pinfo->cinfo, COL_INFO)) {
864 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x",
868 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u)", tpdu_nr);
873 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
874 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
875 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
880 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
887 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
891 ti = proto_tree_add_uint (cotp_tree, hf_cotp_destref, tvb, offset, 0, dst_ref);
892 PROTO_ITEM_SET_GENERATED (ti);
897 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, 4,
899 proto_tree_add_item(cotp_tree, hf_cotp_eot_extended, tvb, offset, 4,
906 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
908 proto_tree_add_item(cotp_tree, hf_cotp_eot, tvb, offset, 1, ENC_BIG_ENDIAN);
915 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
918 next_tvb = tvb_new_subset_remaining(tvb, offset);
919 fragment_length = tvb_length(next_tvb);
920 if (check_col(pinfo->cinfo, COL_INFO)) {
922 col_append_fstr(pinfo->cinfo, COL_INFO, " [COTP fragment, %u byte%s]",
923 fragment_length, plurality(fragment_length, "", "s"));
925 col_append_fstr(pinfo->cinfo, COL_INFO, " EOT");
929 if (cotp_reassemble) {
931 * XXX - these sequence numbers are connection sequence number,
932 * not segment sequence numbers - the first segment of a
933 * segmented packet doesn't have a specific sequence number (e.g., 0
934 * or 1), it has whatever the appropriate sequence number is for
935 * it in the connection.
937 * For now, we assume segments arrive in order, and just supply
938 * the negation of the EOT flag as the "more flags" argument.
939 * We should probably handle out-of-order packets separately,
940 * so that we can deliver them in order even when *not*
943 * Note also that TP0 has no sequence number, and relies on
944 * the protocol atop which it runs to guarantee in-order delivery.
946 fd_head = fragment_add_seq_next(next_tvb, 0, pinfo, dst_ref,
948 cotp_reassembled_table,
949 fragment_length, fragment);
950 if (fd_head && fd_head->next) {
951 /* don't use -1 if fragment length is zero (throws Exception) */
952 proto_tree_add_text(cotp_tree, tvb, offset, (fragment_length) ? -1 : 0,
953 "COTP segment data (%u byte%s)", fragment_length,
954 plurality(fragment_length, "", "s"));
957 /* This is the last packet */
958 next_tvb = process_reassembled_data (next_tvb, offset, pinfo,
959 "Reassembled COTP", fd_head, &cotp_frag_items, NULL, tree);
960 } else if (pinfo->fd->num != fd_head->reassembled_in) {
961 /* Add a "Reassembled in" link if not reassembled in this frame */
962 proto_tree_add_uint (cotp_tree, *(cotp_frag_items.hf_reassembled_in),
963 next_tvb, 0, 0, fd_head->reassembled_in);
965 pinfo->fragmented = fragment;
969 if (uses_inactive_subset) {
970 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
972 *subdissector_found = TRUE;
974 /* Fill in other Dissectors using inactive subset here */
975 call_dissector(data_handle,next_tvb, pinfo, tree);
979 * We dissect payload if one of the following is TRUE:
981 * - Reassembly option for COTP in preferences is unchecked
982 * - Reassembly option is checked and this packet is the last fragment
984 if ( (!cotp_reassemble) ||
985 ((cotp_reassemble) && (!fragment))) {
986 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
988 *subdissector_found = TRUE;
990 call_dissector(data_handle,next_tvb, pinfo, tree);
995 offset += tvb_length_remaining(tvb, offset);
996 /* we dissected all of the containing PDU */
1000 } /* ositp_decode_DT */
1002 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1003 packet_info *pinfo, proto_tree *tree)
1005 proto_tree *cotp_tree = NULL;
1007 gboolean is_extended;
1012 /* ED TPDUs are never fragmented */
1014 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1015 (This means we may misdissect this if the packet is bad and
1016 contains other parameters.) */
1019 case LI_NORMAL_DT_WITH_CHECKSUM :
1020 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1024 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
1025 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1026 if ( tpdu_nr & 0x80 )
1027 tpdu_nr = tpdu_nr & 0x7F;
1030 is_extended = FALSE;
1033 case LI_EXTENDED_DT_WITH_CHECKSUM :
1034 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1038 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1039 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1040 if ( tpdu_nr & 0x80000000 )
1041 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1047 default : /* bad TPDU */
1051 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1052 pinfo->clnp_dstref = dst_ref;
1054 if (check_col(pinfo->cinfo, COL_INFO))
1055 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1059 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1060 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1061 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1066 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1072 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1078 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb,
1079 offset, 4, tpdu_nr);
1085 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
1093 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1096 next_tvb = tvb_new_subset_remaining(tvb, offset);
1097 call_dissector(data_handle,next_tvb, pinfo, tree);
1099 offset += tvb_length_remaining(tvb, offset);
1100 /* we dissected all of the containing PDU */
1104 } /* ositp_decode_ED */
1106 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1107 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1109 proto_tree *cotp_tree;
1111 proto_item *item = NULL;
1118 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1120 case LI_EXTENDED_RJ :
1121 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1122 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1128 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1129 pinfo->clnp_dstref = dst_ref;
1131 if (check_col(pinfo->cinfo, COL_INFO))
1132 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1136 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1137 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1138 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1139 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
1140 if (li == LI_NORMAL_RJ)
1141 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1143 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1144 if (li == LI_NORMAL_RJ)
1145 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset + 4,
1148 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1149 offset + 4, 4, tpdu_nr);
1150 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1151 "Credit: 0x%02x", credit);
1157 expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_NOTE,
1158 "Reject(RJ): -> 0x%x", dst_ref);
1162 } /* ositp_decode_RJ */
1164 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1165 packet_info *pinfo, proto_tree *tree,
1166 gboolean uses_inactive_subset,
1167 gboolean *subdissector_found)
1170 /* CC & CR decoding in the same function */
1172 proto_tree *cotp_tree = NULL;
1174 proto_item *item = NULL;
1175 guint16 dst_ref, src_ref;
1176 guchar class_option;
1179 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1181 class_option = tvb_get_guint8(tvb, offset + P_CLASS_OPTION);
1182 if (((class_option & 0xF0) >> 4) > 4) /* class 0..4 allowed */
1185 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1186 pinfo->clnp_srcref = src_ref;
1187 pinfo->clnp_dstref = dst_ref;
1189 if (check_col(pinfo->cinfo, COL_INFO))
1190 col_append_fstr(pinfo->cinfo, COL_INFO,
1191 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1192 (tpdu == CR_TPDU) ? "CR" : "CC",
1197 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1198 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1199 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1204 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1210 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1215 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1219 /* expert info, but only if not encapsulated in TCP/SMB */
1220 /* XXX - the best way to detect seems to be if we have a port set */
1221 if (pinfo->destport == 0) {
1222 expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT,
1223 tpdu == CR_TPDU ? "Connection Request(CR): 0x%x -> 0x%x" : "Connection Confirm(CC): 0x%x -> 0x%x",
1228 proto_tree_add_uint(cotp_tree, hf_cotp_class, tvb, offset, 1, class_option);
1229 proto_tree_add_boolean(cotp_tree, hf_cotp_opts_extended_formats, tvb, offset, 1, class_option);
1230 proto_tree_add_boolean(cotp_tree, hf_cotp_opts_no_explicit_flow_control, tvb, offset, 1, class_option);
1236 ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1239 next_tvb = tvb_new_subset_remaining(tvb, offset);
1240 if (!uses_inactive_subset){
1241 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1243 *subdissector_found = TRUE;
1245 call_dissector(data_handle,next_tvb, pinfo, tree);
1249 call_dissector(data_handle, next_tvb, pinfo, tree);
1250 offset += tvb_length_remaining(tvb, offset);
1251 /* we dissected all of the containing PDU */
1255 } /* ositp_decode_CC */
1257 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1258 packet_info *pinfo, proto_tree *tree)
1260 proto_tree *cotp_tree = NULL;
1262 proto_item *item = NULL;
1263 guint16 dst_ref, src_ref;
1268 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1269 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1270 pinfo->clnp_dstref = dst_ref;
1271 pinfo->clnp_dstref = src_ref;
1273 if (check_col(pinfo->cinfo, COL_INFO))
1274 col_append_fstr(pinfo->cinfo, COL_INFO,
1275 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1280 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1281 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1282 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1287 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1293 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1298 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1303 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1306 expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT,
1307 "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref);
1311 } /* ositp_decode_DC */
1313 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1314 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1316 proto_tree *cotp_tree = NULL;
1325 if (is_LI_NORMAL_AK(li)) {
1327 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1328 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1329 pinfo->clnp_dstref = dst_ref;
1331 if (check_col(pinfo->cinfo, COL_INFO))
1332 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1336 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1337 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1338 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1343 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1344 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1351 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1356 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1363 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1366 } else { /* extended format */
1368 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1369 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1370 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1371 pinfo->clnp_dstref = dst_ref;
1373 if (check_col(pinfo->cinfo, COL_INFO))
1374 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x Credit: %u",
1375 tpdu_nr, dst_ref, cdt_in_ak);
1378 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1379 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1380 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1385 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1391 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1396 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1397 offset, 4, tpdu_nr);
1403 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1404 "Credit: 0x%04x", cdt_in_ak);
1410 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1413 } /* is_LI_NORMAL_AK */
1417 } /* ositp_decode_AK */
1419 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1420 packet_info *pinfo, proto_tree *tree)
1422 proto_tree *cotp_tree = NULL;
1424 gboolean is_extended;
1431 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1432 (This means we may misdissect this if the packet is bad and
1433 contains other parameters.) */
1436 case LI_NORMAL_EA_WITH_CHECKSUM :
1437 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1438 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1442 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1443 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1444 is_extended = FALSE;
1447 case LI_EXTENDED_EA_WITH_CHECKSUM :
1448 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1449 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1453 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1454 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1458 default : /* bad TPDU */
1462 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1463 pinfo->clnp_dstref = dst_ref;
1465 if (check_col(pinfo->cinfo, COL_INFO))
1466 col_append_fstr(pinfo->cinfo, COL_INFO,
1467 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1470 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1471 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1472 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1477 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1483 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1489 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1490 offset, 4, tpdu_nr);
1496 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1504 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1509 } /* ositp_decode_EA */
1511 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1512 packet_info *pinfo, proto_tree *tree)
1514 proto_tree *cotp_tree;
1522 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1524 str = "Reason not specified";
1527 str = "Invalid parameter code";
1530 str = "Invalid TPDU type";
1533 str = "Invalid parameter value";
1539 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1540 pinfo->clnp_dstref = dst_ref;
1542 if (check_col(pinfo->cinfo, COL_INFO))
1543 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1546 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1547 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1548 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1549 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
1550 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1551 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1552 "Reject cause: %s", str);
1559 } /* ositp_decode_ER */
1561 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1562 packet_info *pinfo, proto_tree *tree,
1563 gboolean *subdissector_found)
1566 proto_tree *cltp_tree = NULL;
1569 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1572 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1573 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1574 proto_tree_add_uint(cltp_tree, hf_cltp_li, tvb, offset, 1,li);
1579 proto_tree_add_uint(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu);
1585 ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1588 next_tvb = tvb_new_subset_remaining(tvb, offset);
1590 if (dissector_try_heuristic(cltp_heur_subdissector_list, next_tvb,
1592 *subdissector_found = TRUE;
1594 call_dissector(data_handle,next_tvb, pinfo, tree);
1598 /*call_dissector(data_handle,next_tvb, pinfo, tree); */
1602 offset += tvb_length_remaining(tvb, offset);
1603 /* we dissected all of the containing PDU */
1607 } /* ositp_decode_UD */
1609 /* Returns the offset past the last valid COTP or CLTP PDU if we found
1610 at least one valid COTP or CLTP PDU, 0 otherwise.
1612 There doesn't seem to be any way in which the OSI network layer protocol
1613 distinguishes between COTP and CLTP, but the first two octets of both
1614 protocols' headers mean the same thing - length and PDU type - and the
1615 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1616 both of them here. */
1617 static gint dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1618 proto_tree *tree, gboolean uses_inactive_subset)
1621 guint8 li, tpdu, cdt;
1622 gboolean first_tpdu = TRUE;
1624 gboolean found_ositp = FALSE;
1625 gboolean is_cltp = FALSE;
1626 gboolean subdissector_found = FALSE;
1628 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_cotp)))
1629 return FALSE; /* COTP has been disabled */
1630 /* XXX - what about CLTP? */
1632 pinfo->current_proto = "COTP";
1634 /* Initialize the COL_INFO field; each of the TPDUs will have its
1635 information appended. */
1636 if (check_col(pinfo->cinfo, COL_INFO))
1637 col_set_str(pinfo->cinfo, COL_INFO, "");
1639 while (tvb_offset_exists(tvb, offset)) {
1641 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1642 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple TPDUs in one packet");
1644 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1645 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1647 call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset),
1652 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1653 if (tpdu == UD_TPDU)
1654 pinfo->current_proto = "CLTP"; /* connectionless transport */
1655 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1660 new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1661 uses_inactive_subset, &subdissector_found);
1664 new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1667 new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1668 uses_inactive_subset, &subdissector_found);
1671 new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1674 new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1677 new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1680 new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1683 new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1686 new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1689 new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree, &subdissector_found);
1693 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1694 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1695 new_offset = -1; /* bad PDU type */
1699 if (new_offset == -1) { /* incorrect TPDU */
1701 call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset),
1707 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1708 is either COTP or CLTP. */
1709 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1710 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1714 offset = new_offset;
1717 return found_ositp ? offset : 0;
1718 } /* dissect_ositp_internal */
1720 static gint dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1722 return dissect_ositp_internal(tvb, pinfo, tree, FALSE);
1725 static gint dissect_ositp_inactive(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1727 return dissect_ositp_internal(tvb, pinfo, tree, TRUE);
1731 cotp_reassemble_init(void)
1733 fragment_table_init(&cotp_segment_table);
1734 reassembled_table_init(&cotp_reassembled_table);
1738 void proto_register_cotp(void)
1740 static hf_register_info hf[] = {
1742 { "Length", "cotp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
1743 "Length Indicator, length of this header", HFILL}},
1745 { "PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
1746 "PDU Type - upper nibble of byte", HFILL}},
1748 { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
1749 "Source address reference", HFILL}},
1751 { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
1752 "Destination address reference", HFILL}},
1754 { "Class", "cotp.class", FT_UINT8, BASE_DEC, NULL, 0xF0,
1755 "Transport protocol class", HFILL}},
1756 { &hf_cotp_opts_extended_formats,
1757 { "Extended formats", "cotp.opts.extended_formats", FT_BOOLEAN, 8, NULL, 0x02,
1758 "Use of extended formats in classes 2, 3, and 4", HFILL}},
1759 { &hf_cotp_opts_no_explicit_flow_control,
1760 { "No explicit flow control", "cotp.opts.no_explicit_flow_control", FT_BOOLEAN, 8, NULL, 0x01,
1761 "No explicit flow control in class 2", HFILL}},
1762 { &hf_cotp_tpdu_number,
1763 { "TPDU number", "cotp.tpdu-number", FT_UINT8, BASE_HEX, NULL, 0x7f,
1765 { &hf_cotp_tpdu_number_extended,
1766 { "TPDU number", "cotp.tpdu-number", FT_UINT32, BASE_HEX, NULL, 0x0 /* XXX - 0x7fff? */,
1768 { &hf_cotp_next_tpdu_number,
1769 { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT8, BASE_HEX, NULL, 0x0,
1771 { &hf_cotp_next_tpdu_number_extended,
1772 { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT32, BASE_HEX, NULL, 0x0,
1775 { "Last data unit", "cotp.eot", FT_BOOLEAN, 8, TFS(&fragment_descriptions), 0x80,
1776 "Is current TPDU the last data unit of a complete DT TPDU sequence (End of TSDU)?", HFILL}},
1777 { &hf_cotp_eot_extended,
1778 { "Last data unit", "cotp.eot", FT_BOOLEAN, 32, TFS(&fragment_descriptions), 0x80000000,
1779 "Is current TPDU the last data unit of a complete DT TPDU sequence (End of TSDU)?", HFILL}},
1780 { &hf_cotp_segment_overlap,
1781 { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1782 "Segment overlaps with other segments", HFILL }},
1783 { &hf_cotp_segment_overlap_conflict,
1784 { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1785 "Overlapping segments contained conflicting data", HFILL }},
1786 { &hf_cotp_segment_multiple_tails,
1787 { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1788 "Several tails were found when reassembling the packet", HFILL }},
1789 { &hf_cotp_segment_too_long_segment,
1790 { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1791 "Segment contained data past end of packet", HFILL }},
1792 { &hf_cotp_segment_error,
1793 { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1794 "Reassembly error due to illegal segments", HFILL }},
1796 { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1798 { &hf_cotp_segments,
1799 { "COTP Segments", "cotp.segments", FT_NONE, BASE_NONE, NULL, 0x0,
1801 { &hf_cotp_reassembled_in,
1802 { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1803 "This COTP packet is reassembled in this frame", HFILL }},
1804 { &hf_cotp_reassembled_length,
1805 { "Reassembled COTP length", "cotp.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
1806 "The total length of the reassembled payload", HFILL }},
1807 /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as
1808 identifiers of unspecified type and length.
1809 Some implementations of COTP use printable strings, others use raw bytes.
1810 We always add both representations to the tree; one will always be hidden
1811 depending on the tsap display preference */
1812 { &hf_cotp_vp_src_tsap,
1813 { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
1814 "Calling TSAP", HFILL }},
1815 { &hf_cotp_vp_src_tsap_bytes,
1816 { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
1817 "Calling TSAP (bytes representation)", HFILL }},
1818 { &hf_cotp_vp_dst_tsap,
1819 { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
1820 "Called TSAP", HFILL }},
1821 { &hf_cotp_vp_dst_tsap_bytes,
1822 { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
1823 "Called TSAP (bytes representation)", HFILL }},
1826 static gint *ett[] = {
1832 module_t *cotp_module;
1834 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
1835 proto_register_field_array(proto_cotp, hf, array_length(hf));
1836 proto_register_subtree_array(ett, array_length(ett));
1837 cotp_module = prefs_register_protocol(proto_cotp, NULL);
1839 prefs_register_bool_preference(cotp_module, "reassemble",
1840 "Reassemble segmented COTP datagrams",
1841 "Whether segmented COTP datagrams should be reassembled."
1842 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1845 prefs_register_enum_preference(cotp_module, "tsap_display",
1846 "Display TSAPs as strings or bytes",
1847 "How TSAPs should be displayed",
1849 tsap_display_options,
1852 /* subdissector code in inactive subset */
1853 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
1855 /* other COTP/ISO 8473 subdissectors */
1856 register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
1858 /* XXX - what about CLTP and proto_cltp? */
1859 new_register_dissector("ositp", dissect_ositp, proto_cotp);
1860 new_register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp);
1862 register_init_routine(cotp_reassemble_init);
1865 void proto_register_cltp(void)
1867 static hf_register_info hf[] = {
1869 { "Length", "cltp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
1870 "Length Indicator, length of this header", HFILL}},
1872 { "PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
1875 static gint *ett[] = {
1879 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
1880 proto_register_field_array(proto_cltp, hf, array_length(hf));
1881 proto_register_subtree_array(ett, array_length(ett));
1883 register_heur_dissector_list("cltp", &cltp_heur_subdissector_list);
1888 proto_reg_handoff_cotp(void)
1890 dissector_handle_t ositp_handle;
1892 ositp_handle = find_dissector("ositp");
1893 dissector_add_uint("ip.proto", IP_PROTO_TP, ositp_handle);
1895 data_handle = find_dissector("data");
1897 proto_clnp = proto_get_id_by_filter_name("clnp");