2 * Routines for ISO/OSI network and 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.
34 #include <epan/prefs.h>
35 #include <epan/packet.h>
36 #include <epan/reassemble.h>
37 #include <epan/emem.h>
38 #include "packet-frame.h"
39 #include "packet-osi.h"
40 #include "packet-osi-options.h"
41 #include "packet-isis.h"
42 #include "packet-esis.h"
43 #include <epan/nlpid.h>
44 #include <epan/ipproto.h>
45 #include <epan/expert.h>
46 #include <epan/strutil.h>
48 /* protocols and fields */
50 static int proto_clnp = -1;
51 static gint ett_clnp = -1;
52 static gint ett_clnp_type = -1;
53 static gint ett_clnp_segments = -1;
54 static gint ett_clnp_segment = -1;
55 static gint ett_clnp_disc_pdu = -1;
57 static int hf_clnp_id = -1;
58 static int hf_clnp_length = -1;
59 static int hf_clnp_version = -1;
60 static int hf_clnp_ttl = -1;
61 static int hf_clnp_type = -1;
62 static int hf_clnp_pdu_length = -1;
63 static int hf_clnp_checksum = -1;
64 static int hf_clnp_dest_length = -1;
65 static int hf_clnp_dest = -1;
66 static int hf_clnp_src_length = -1;
67 static int hf_clnp_src = -1;
68 static int hf_clnp_segments = -1;
69 static int hf_clnp_segment = -1;
70 static int hf_clnp_segment_overlap = -1;
71 static int hf_clnp_segment_overlap_conflict = -1;
72 static int hf_clnp_segment_multiple_tails = -1;
73 static int hf_clnp_segment_too_long_segment = -1;
74 static int hf_clnp_segment_error = -1;
75 static int hf_clnp_reassembled_in = -1;
77 static int proto_cotp = -1;
78 static gint ett_cotp = -1;
79 static gint ett_cotp_segments = -1;
80 static gint ett_cotp_segment = -1;
82 static int hf_cotp_srcref = -1;
83 static int hf_cotp_destref = -1;
84 static int hf_cotp_tpdu_number = -1;
85 static int hf_cotp_tpdu_number_extended = -1;
86 static int hf_cotp_next_tpdu_number = -1;
87 static int hf_cotp_next_tpdu_number_extended = -1;
88 static int hf_cotp_eot = -1;
89 static int hf_cotp_eot_extended = -1;
91 static int hf_cotp_li = -1;
92 static int hf_cotp_type = -1;
93 static int hf_cotp_segments = -1;
94 static int hf_cotp_segment = -1;
95 static int hf_cotp_segment_overlap = -1;
96 static int hf_cotp_segment_overlap_conflict = -1;
97 static int hf_cotp_segment_multiple_tails = -1;
98 static int hf_cotp_segment_too_long_segment = -1;
99 static int hf_cotp_segment_error = -1;
100 static int hf_cotp_reassembled_in = -1;
102 static const true_false_string fragment_descriptions = {
107 static int proto_cltp = -1;
108 static gint ett_cltp = -1;
110 static int hf_cltp_li = -1;
111 static int hf_cltp_type = -1;
113 static const fragment_items clnp_frag_items = {
118 &hf_clnp_segment_overlap,
119 &hf_clnp_segment_overlap_conflict,
120 &hf_clnp_segment_multiple_tails,
121 &hf_clnp_segment_too_long_segment,
122 &hf_clnp_segment_error,
123 &hf_clnp_reassembled_in,
127 static const fragment_items cotp_frag_items = {
132 &hf_cotp_segment_overlap,
133 &hf_cotp_segment_overlap_conflict,
134 &hf_cotp_segment_multiple_tails,
135 &hf_cotp_segment_too_long_segment,
136 &hf_cotp_segment_error,
137 &hf_cotp_reassembled_in,
141 static dissector_handle_t clnp_handle;
142 static dissector_handle_t data_handle;
145 * ISO 8473 OSI CLNP definition (see RFC994)
147 * _________________________________
149 * |_________________________________|
151 * |_________________________________|
152 * | Segmentation Part (optional) |
153 * |_________________________________|
154 * | Options Part (optional) |
155 * |_________________________________|
156 * | Data (optional) |
157 * |_________________________________|
160 #define ISO8473_V1 0x01 /* CLNP version 1 */
164 #define CNF_TYPE 0x1f
165 #define CNF_ERR_OK 0x20
166 #define CNF_MORE_SEGS 0x40
167 #define CNF_SEG_OK 0x80
172 #define ERQ_NPDU 0x1E
173 #define ERP_NPDU 0x1F
175 static const value_string npdu_type_abbrev_vals[] = {
184 static const value_string npdu_type_vals[] = {
186 { MD_NPDU, "Multicast Data" },
187 { ER_NPDU, "Error Report" },
188 { ERQ_NPDU, "Echo Request" },
189 { ERP_NPDU, "Echo Response" },
195 #define P_CLNP_PROTO_ID 0
196 #define P_CLNP_HDR_LEN 1
197 #define P_CLNP_VERS 2
199 #define P_CLNP_TYPE 4
200 #define P_CLNP_SEGLEN 5
201 #define P_CLNP_CKSUM 7
202 #define P_CLNP_ADDRESS_PART 9
204 /* Segmentation part */
206 struct clnp_segment {
207 gushort cng_id; /* data unit identifier */
208 gushort cng_off; /* segment offset */
209 gushort cng_tot_len; /* total length */
214 #define NSEL_NET 0x00
219 * ISO8073 OSI COTP definition (see RFC905)
222 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
224 /* TPDU definition */
226 #define ED_TPDU 0x1 /* COTP */
227 #define EA_TPDU 0x2 /* COTP */
228 #define UD_TPDU 0x4 /* CLTP */
229 #define RJ_TPDU 0x5 /* COTP */
230 #define AK_TPDU 0x6 /* COTP */
231 #define ER_TPDU 0x7 /* COTP */
232 #define DR_TPDU 0x8 /* COTP */
233 #define DC_TPDU 0xC /* COTP */
234 #define CC_TPDU 0xD /* COTP */
235 #define CR_TPDU 0xE /* COTP */
236 #define DT_TPDU 0xF /* COTP */
238 static const value_string cotp_tpdu_type_abbrev_vals[] = {
239 { ED_TPDU, "ED Expedited Data" },
240 { EA_TPDU, "EA Expedited Data Acknowledgement" },
241 { RJ_TPDU, "RJ Reject" },
242 { AK_TPDU, "AK Data Acknowledgement" },
243 { ER_TPDU, "ER TPDU Error" },
244 { DR_TPDU, "DR Disconnect Request" },
245 { DC_TPDU, "DC Disconnect Confirm" },
246 { CC_TPDU, "CC Connect Confirm" },
247 { CR_TPDU, "CR Connect Request" },
248 { DT_TPDU, "DT Data" },
252 static const value_string cltp_tpdu_type_abbrev_vals[] = {
264 #define P_TPDU_NR_0_1 2
265 #define P_TPDU_NR_234 4
266 #define P_VAR_PART_NDT 5
267 #define P_VAR_PART_EDT 8
268 #define P_VAR_PART_DC 6
269 #define P_CDT_IN_AK 8
270 #define P_CDT_IN_RJ 8
271 #define P_REJECT_ER 4
272 #define P_REASON_IN_DR 6
273 #define P_CLASS_OPTION 6
275 /* TPDU length indicator */
277 #define LI_NORMAL_DT_CLASS_01 2
278 #define LI_NORMAL_DT_WITH_CHECKSUM 8
279 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
280 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
281 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
282 #define LI_NORMAL_EA_WITH_CHECKSUM 8
283 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
284 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
285 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
286 #define LI_NORMAL_RJ 4
287 #define LI_EXTENDED_RJ 9
293 /* XXX - can we always decide this based on whether the length
294 indicator is odd or not? What if the variable part has an odd
296 #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
300 #define VP_ACK_TIME 0x85
301 #define VP_RES_ERROR 0x86
302 #define VP_PRIORITY 0x87
303 #define VP_TRANSIT_DEL 0x88
304 #define VP_THROUGHPUT 0x89
305 #define VP_SEQ_NR 0x8A /* in AK */
306 #define VP_REASSIGNMENT 0x8B
307 #define VP_FLOW_CNTL 0x8C /* in AK */
308 #define VP_TPDU_SIZE 0xC0
309 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
310 #define VP_DST_TSAP 0xC2
311 #define VP_CHECKSUM 0xC3
312 #define VP_VERSION_NR 0xC4
313 #define VP_PROTECTION 0xC5
314 #define VP_OPT_SEL 0xC6
315 #define VP_PROTO_CLASS 0xC7
316 #define VP_PREF_MAX_TPDU_SIZE 0xF0
317 #define VP_INACTIVITY_TIMER 0xF2
319 static const value_string tp_vpart_type_vals[] = {
320 { VP_ACK_TIME, "ack time" },
321 { VP_RES_ERROR, "res error" },
322 { VP_PRIORITY, "priority" },
323 { VP_TRANSIT_DEL, "transit delay" },
324 { VP_THROUGHPUT, "throughput" },
325 { VP_SEQ_NR, "seq number" },
326 { VP_REASSIGNMENT, "reassignment" },
327 { VP_FLOW_CNTL, "flow control" },
328 { VP_TPDU_SIZE, "tpdu-size" },
329 { VP_SRC_TSAP, "src-tsap" },
330 { VP_DST_TSAP, "dst-tsap" },
331 { VP_CHECKSUM, "checksum" },
332 { VP_VERSION_NR, "version" },
333 { VP_PROTECTION, "protection" },
334 { VP_OPT_SEL, "options" },
335 { VP_PROTO_CLASS, "proto class" },
336 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
340 static int hf_cotp_vp_src_tsap = -1;
341 static int hf_cotp_vp_dst_tsap = -1;
342 static int hf_cotp_vp_src_tsap_bytes = -1;
343 static int hf_cotp_vp_dst_tsap_bytes = -1;
348 #define EXTRACT_SHORT(p) pntohs(p)
349 #define EXTRACT_LONG(p) pntohl(p)
351 /* global variables */
353 /* List of dissectors to call for COTP packets put atop the Inactive
355 static heur_dissector_list_t cotp_is_heur_subdissector_list;
356 /* List of dissectors to call for COTP packets put atop CLNP */
357 static heur_dissector_list_t cotp_heur_subdissector_list;
358 /* List of dissectors to call for CLNP packets */
359 static heur_dissector_list_t clnp_heur_subdissector_list;
362 * Reassembly of CLNP.
364 static GHashTable *clnp_segment_table = NULL;
365 static GHashTable *clnp_reassembled_table = NULL;
368 * Reassembly of COTP.
370 static GHashTable *cotp_segment_table = NULL;
371 static GHashTable *cotp_reassembled_table = NULL;
372 static guint16 cotp_dst_ref = 0;
373 static gboolean cotp_frame_reset = FALSE;
374 static gboolean cotp_last_fragment = FALSE;
376 #define TSAP_DISPLAY_AUTO 0
377 #define TSAP_DISPLAY_STRING 1
378 #define TSAP_DISPLAY_BYTES 2
382 static guint tp_nsap_selector = NSEL_TP;
383 static gboolean always_decode_transport = FALSE;
384 static gboolean clnp_reassemble = TRUE;
385 static gboolean cotp_reassemble = TRUE;
386 static gint32 tsap_display = TSAP_DISPLAY_AUTO;
388 const enum_val_t tsap_display_options[] = {
389 {"auto", "As strings if printable", TSAP_DISPLAY_AUTO},
390 {"string", "As strings", TSAP_DISPLAY_STRING},
391 {"bytes", "As bytes", TSAP_DISPLAY_BYTES},
396 /* function definitions */
398 #define MAX_TSAP_LEN 32
400 static void cotp_frame_end(void)
402 if (!cotp_last_fragment) {
403 /* Last COTP in frame is not fragmentet.
404 * No need for incrementing the dst_ref, so we decrement it here.
408 cotp_frame_reset = TRUE;
411 static gboolean is_all_printable(const guchar *stringtocheck, int length)
413 gboolean allprintable;
417 for (i=0;i<length;i++) {
418 if (!(isascii(stringtocheck[i]) && isprint(stringtocheck[i]))) {
424 } /* is_all_printable */
427 static gchar *print_tsap(const guchar *tsap, int length)
431 gboolean allprintable;
432 size_t index = 0, returned_length;
434 cur=ep_alloc(MAX_TSAP_LEN * 2 + 3);
436 if (length <= 0 || length > MAX_TSAP_LEN)
437 g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "<unsupported TSAP length>");
439 allprintable = is_all_printable(tsap,length);
441 returned_length = g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x");
442 index += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1);
444 while (length != 0) {
446 returned_length = g_snprintf(&cur[index], MAX_TSAP_LEN * 2 + 3 - index, "%c", *tsap ++);
447 index += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - index - 1 );
449 returned_length = g_snprintf(&cur[index], MAX_TSAP_LEN * 2 + 3 - index, "%02x", *tsap ++);
450 index += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - index - 1);
459 static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
460 int vp_length, int class_option,
465 guint16 s, s1,s2,s3,s4;
466 guint32 t1, t2, t3, t4;
467 guint32 pref_max_tpdu_size;
469 while (vp_length != 0) {
470 code = tvb_get_guint8(tvb, offset);
471 proto_tree_add_text(tree, tvb, offset, 1,
472 "Parameter code: 0x%02x (%s)",
474 val_to_str(code, tp_vpart_type_vals, "Unknown"));
480 length = tvb_get_guint8(tvb, offset);
481 proto_tree_add_text(tree, tvb, offset, 1,
482 "Parameter length: %u", length);
489 s = tvb_get_ntohs(tvb, offset);
490 proto_tree_add_text(tree, tvb, offset, length,
491 "Ack time (ms): %u", s);
497 proto_tree_add_text(tree, tvb, offset, 1,
498 "Residual error rate, target value: 10^%u",
499 tvb_get_guint8(tvb, offset));
504 proto_tree_add_text(tree, tvb, offset, 1,
505 "Residual error rate, minimum acceptable: 10^%u",
506 tvb_get_guint8(tvb, offset));
512 proto_tree_add_text(tree, tvb, offset, 1,
513 "Residual error rate, TSDU size of interest: %u",
514 1<<tvb_get_guint8(tvb, offset));
522 s = tvb_get_ntohs(tvb, offset);
523 proto_tree_add_text(tree, tvb, offset, length,
530 s1 = tvb_get_ntohs(tvb, offset);
531 proto_tree_add_text(tree, tvb, offset, 2,
532 "Transit delay, target value, calling-called: %u ms", s1);
537 s2 = tvb_get_ntohs(tvb, offset);
538 proto_tree_add_text(tree, tvb, offset, 2,
539 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
544 s3 = tvb_get_ntohs(tvb, offset);
545 proto_tree_add_text(tree, tvb, offset, 2,
546 "Transit delay, target value, called-calling: %u ms", s3);
551 s4 = tvb_get_ntohs(tvb, offset);
552 proto_tree_add_text(tree, tvb, offset, 2,
553 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
560 t1 = tvb_get_ntoh24(tvb, offset);
561 proto_tree_add_text(tree, tvb, offset, 3,
562 "Maximum throughput, target value, calling-called: %u o/s", t1);
567 t2 = tvb_get_ntoh24(tvb, offset);
568 proto_tree_add_text(tree, tvb, offset, 3,
569 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
574 t3 = tvb_get_ntoh24(tvb, offset);
575 proto_tree_add_text(tree, tvb, offset, 3,
576 "Maximum throughput, target value, called-calling: %u o/s", t3);
581 t4 = tvb_get_ntoh24(tvb, offset);
582 proto_tree_add_text(tree, tvb, offset, 3,
583 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
588 if (length != 0) { /* XXX - should be 0 or 12 */
589 t1 = tvb_get_ntoh24(tvb, offset);
590 proto_tree_add_text(tree, tvb, offset, 3,
591 "Average throughput, target value, calling-called: %u o/s", t1);
596 t2 = tvb_get_ntoh24(tvb, offset);
597 proto_tree_add_text(tree, tvb, offset, 3,
598 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
603 t3 = tvb_get_ntoh24(tvb, offset);
604 proto_tree_add_text(tree, tvb, offset, 3,
605 "Average throughput, target value, called-calling: %u o/s", t3);
610 t4 = tvb_get_ntoh24(tvb, offset);
611 proto_tree_add_text(tree, tvb, offset, 3,
612 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
620 proto_tree_add_text(tree, tvb, offset, 2,
621 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
626 case VP_REASSIGNMENT:
627 proto_tree_add_text(tree, tvb, offset, 2,
628 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
634 proto_tree_add_text(tree, tvb, offset, 4,
635 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
640 proto_tree_add_text(tree, tvb, offset, 2,
641 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
646 proto_tree_add_text(tree, tvb, offset, 2,
647 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
655 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
656 proto_tree_add_text(tree, tvb, offset, length,
657 "TPDU size: %u", 1 << c1);
663 /* if our preference is set to STRING or the
664 TSAP is not printable, add as bytes and hidden as string;
665 otherwise vice-versa */
666 if (tsap_display==TSAP_DISPLAY_STRING ||
667 (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
668 proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
669 print_tsap(tvb_get_ptr(tvb, offset, length),length));
670 proto_tree_add_item_hidden(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, TRUE);
672 proto_tree_add_string_hidden(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
673 print_tsap(tvb_get_ptr(tvb, offset, length),length));
674 proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, TRUE);
681 /* if our preference is set to STRING or the
682 TSAP is not printable, add as bytes and hidden as string;
683 otherwise vice-versa */
684 if (tsap_display==TSAP_DISPLAY_STRING ||
685 (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
686 proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
687 print_tsap(tvb_get_ptr(tvb, offset, length),length));
688 proto_tree_add_item_hidden(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, TRUE);
690 proto_tree_add_string_hidden(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
691 print_tsap(tvb_get_ptr(tvb, offset, length),length));
692 proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, TRUE);
699 proto_tree_add_text(tree, tvb, offset, length,
700 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
706 c1 = tvb_get_guint8(tvb, offset);
707 proto_tree_add_text(tree, tvb, offset, length,
714 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
715 switch (class_option) {
719 proto_tree_add_text(tree, tvb, offset, 1,
720 "Use of network expedited data");
722 proto_tree_add_text(tree, tvb, offset, 1,
723 "Non use of network expedited data");
725 proto_tree_add_text(tree, tvb, offset, 1,
726 "Use of Receipt confirmation");
728 proto_tree_add_text(tree, tvb, offset, 1,
729 "Use of explicit AK variant");
734 proto_tree_add_text(tree, tvb, offset, 1,
735 "Non-use 16 bit checksum in class 4");
737 proto_tree_add_text(tree, tvb, offset, 1,
738 "Use 16 bit checksum ");
742 proto_tree_add_text(tree, tvb, offset, 1,
743 "Use of transport expedited data transfer");
745 proto_tree_add_text(tree, tvb, offset, 1,
746 "Non-use of transport expedited data transfer");
751 case VP_PREF_MAX_TPDU_SIZE:
755 pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
759 pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
763 pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
767 pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
771 proto_tree_add_text(tree, tvb, offset, length,
772 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
776 proto_tree_add_text(tree, tvb, offset, length,
777 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
782 case VP_INACTIVITY_TIMER:
783 proto_tree_add_text(tree, tvb, offset, length,
784 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
789 case VP_PROTECTION: /* user-defined */
790 case VP_PROTO_CLASS: /* todo */
791 default: /* unknown, no decoding */
792 proto_tree_add_text(tree, tvb, offset, length,
793 "Parameter value: <not shown>");
803 static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
804 packet_info *pinfo, proto_tree *tree)
806 proto_tree *cotp_tree;
807 proto_item *ti = NULL;
808 guint16 dst_ref, src_ref;
815 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
817 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
819 reason = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
821 pinfo->clnp_dstref = dst_ref;
822 pinfo->clnp_srcref = src_ref;
824 /* the settings of the TCP srcport and destport are currently disables,
825 * for the following reasons:
826 * a) only used for ISO conversation handling (which currently doesn't work)
827 * b) will prevent "ISO on TCP" (RFC1006) packets from using "follow TCP stream" correctly
829 * A future conversation handling might be able to handle different kinds of conversations
830 * (TCP, ISO, TCP on TCP, ...), but in that case this has to be fixed in any case.
832 /*pinfo->srcport = src_ref;*/
833 /*pinfo->destport = dst_ref;*/
835 case (128+0): str = "Normal Disconnect"; break;
836 case (128+1): str = "Remote transport entity congestion"; break;
837 case (128+2): str = "Connection negotiation failed"; break;
838 case (128+3): str = "Duplicate source reference"; break;
839 case (128+4): str = "Mismatched references"; break;
840 case (128+5): str = "Protocol error"; break;
841 case (128+7): str = "Reference overflow"; break;
842 case (128+8): str = "Connection requestion refused"; break;
843 case (128+10):str = "Header or parameter length invalid"; break;
844 case (0): str = "Reason not specified"; break;
845 case (1): str = "Congestion at TSAP"; break;
846 case (2): str = "Session entity not attached to TSAP"; break;
847 case (3): str = "Address unknown"; break;
851 if (check_col(pinfo->cinfo, COL_INFO))
852 col_append_fstr(pinfo->cinfo, COL_INFO,
853 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
857 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
858 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
859 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
860 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
861 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
862 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset + 4, 2, src_ref);
863 proto_tree_add_text(cotp_tree, tvb, offset + 6, 1,
869 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_CHAT,
870 "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref);
873 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
874 offset += tvb_length_remaining(tvb, offset);
875 /* we dissected all of the containing PDU */
879 } /* ositp_decode_DR */
881 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
882 packet_info *pinfo, proto_tree *tree,
883 gboolean uses_inactive_subset,
884 gboolean *subdissector_found)
886 proto_tree *cotp_tree = NULL;
888 gboolean is_extended;
889 gboolean is_class_234;
891 guint16 *prev_dst_ref;
893 gboolean fragment = FALSE;
894 guint32 fragment_length = 0;
896 fragment_data *fd_head;
898 /* VP_CHECKSUM is the only parameter allowed in the variable part.
899 (This means we may misdissect this if the packet is bad and
900 contains other parameters.) */
903 case LI_NORMAL_DT_WITH_CHECKSUM :
904 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
908 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
909 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
910 if ( tpdu_nr & 0x80 )
911 tpdu_nr = tpdu_nr & 0x7F;
916 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
919 case LI_EXTENDED_DT_WITH_CHECKSUM :
920 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
924 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
925 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
926 if ( tpdu_nr & 0x80000000 )
927 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
932 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
935 case LI_NORMAL_DT_CLASS_01 :
936 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
937 if ( tpdu_nr & 0x80 )
938 tpdu_nr = tpdu_nr & 0x7F;
942 is_class_234 = FALSE;
943 prev_dst_ref = p_get_proto_data (pinfo->fd, proto_clnp);
945 /* First COTP in frame - save previous dst_ref as offset */
946 prev_dst_ref = se_alloc (sizeof (guint32));
947 *prev_dst_ref = cotp_dst_ref;
948 p_add_proto_data (pinfo->fd, proto_clnp, prev_dst_ref);
949 } else if (cotp_frame_reset) {
950 cotp_dst_ref = *prev_dst_ref;
952 cotp_frame_reset = FALSE;
953 cotp_last_fragment = fragment;
954 dst_ref = cotp_dst_ref;
957 register_frame_end_routine(cotp_frame_end);
961 default : /* bad TPDU */
965 pinfo->clnp_dstref = dst_ref;
967 pinfo->fragmented = fragment;
968 if (check_col(pinfo->cinfo, COL_INFO)) {
970 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x",
974 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u)", tpdu_nr);
979 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
980 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
981 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
986 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
993 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
997 ti = proto_tree_add_uint (cotp_tree, hf_cotp_destref, tvb, offset, 0, dst_ref);
998 PROTO_ITEM_SET_GENERATED (ti);
1003 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, 4,
1005 proto_tree_add_item(cotp_tree, hf_cotp_eot_extended, tvb, offset, 4,
1012 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
1014 proto_tree_add_item(cotp_tree, hf_cotp_eot, tvb, offset, 1, FALSE);
1021 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1024 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1025 fragment_length = tvb_length(next_tvb);
1026 if (check_col(pinfo->cinfo, COL_INFO)) {
1028 col_append_fstr(pinfo->cinfo, COL_INFO, " [COTP fragment, %u byte%s]",
1029 fragment_length, plurality(fragment_length, "", "s"));
1031 col_append_fstr(pinfo->cinfo, COL_INFO, " EOT");
1035 if (cotp_reassemble) {
1037 * XXX - these sequence numbers are connection sequence number,
1038 * not segment sequence numbers - the first segment of a
1039 * segmented packet doesn't have a specific sequence number (e.g., 0
1040 * or 1), it has whatever the appropriate sequence number is for
1041 * it in the connection.
1043 * For now, we assume segments arrive in order, and just supply
1044 * the negation of the EOT flag as the "more flags" argument.
1045 * We should probably handle out-of-order packets separately,
1046 * so that we can deliver them in order even when *not*
1049 * Note also that TP0 has no sequence number, and relies on
1050 * the protocol atop which it runs to guarantee in-order delivery.
1052 fd_head = fragment_add_seq_next(next_tvb, 0, pinfo, dst_ref,
1054 cotp_reassembled_table,
1055 fragment_length, fragment);
1056 if (fd_head && fd_head->next) {
1057 /* don't use -1 if fragment length is zero (throws Exception) */
1058 proto_tree_add_text(cotp_tree, tvb, offset, (fragment_length) ? -1 : 0,
1059 "COTP segment data (%u byte%s)", fragment_length,
1060 plurality(fragment_length, "", "s"));
1063 /* This is the last packet */
1064 next_tvb = process_reassembled_data (next_tvb, offset, pinfo,
1065 "Reassembled COTP", fd_head, &cotp_frag_items, NULL, tree);
1066 } else if (pinfo->fd->num != fd_head->reassembled_in) {
1067 /* Add a "Reassembled in" link if not reassembled in this frame */
1068 proto_tree_add_uint (cotp_tree, *(cotp_frag_items.hf_reassembled_in),
1069 next_tvb, 0, 0, fd_head->reassembled_in);
1071 pinfo->fragmented = fragment;
1075 if (uses_inactive_subset) {
1076 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
1078 *subdissector_found = TRUE;
1080 /* Fill in other Dissectors using inactive subset here */
1081 call_dissector(data_handle,next_tvb, pinfo, tree);
1085 * We dissect payload if one of the following is TRUE:
1087 * - Reassembly option for COTP in preferences is unchecked
1088 * - Reassembly option is checked and this packet is the last fragment
1090 if ( (!cotp_reassemble) ||
1091 ((cotp_reassemble) && (!fragment))) {
1092 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1094 *subdissector_found = TRUE;
1096 call_dissector(data_handle,next_tvb, pinfo, tree);
1101 offset += tvb_length_remaining(tvb, offset);
1102 /* we dissected all of the containing PDU */
1106 } /* ositp_decode_DT */
1108 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1109 packet_info *pinfo, proto_tree *tree)
1111 proto_tree *cotp_tree = NULL;
1113 gboolean is_extended;
1118 /* ED TPDUs are never fragmented */
1120 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1121 (This means we may misdissect this if the packet is bad and
1122 contains other parameters.) */
1125 case LI_NORMAL_DT_WITH_CHECKSUM :
1126 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1130 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
1131 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1132 if ( tpdu_nr & 0x80 )
1133 tpdu_nr = tpdu_nr & 0x7F;
1136 is_extended = FALSE;
1139 case LI_EXTENDED_DT_WITH_CHECKSUM :
1140 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1144 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1145 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1146 if ( tpdu_nr & 0x80000000 )
1147 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1153 default : /* bad TPDU */
1157 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1158 pinfo->clnp_dstref = dst_ref;
1160 if (check_col(pinfo->cinfo, COL_INFO))
1161 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1165 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1166 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1167 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1172 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1178 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1184 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb,
1185 offset, 4, tpdu_nr);
1191 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
1199 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1202 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1203 call_dissector(data_handle,next_tvb, pinfo, tree);
1205 offset += tvb_length_remaining(tvb, offset);
1206 /* we dissected all of the containing PDU */
1210 } /* ositp_decode_ED */
1212 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1213 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1215 proto_tree *cotp_tree;
1217 proto_item *item = NULL;
1224 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1226 case LI_EXTENDED_RJ :
1227 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1228 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1234 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1235 pinfo->clnp_dstref = dst_ref;
1237 if (check_col(pinfo->cinfo, COL_INFO))
1238 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1242 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1243 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1244 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1245 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
1246 if (li == LI_NORMAL_RJ)
1247 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1249 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1250 if (li == LI_NORMAL_RJ)
1251 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset + 4,
1254 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1255 offset + 4, 4, tpdu_nr);
1256 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1257 "Credit: 0x%02x", credit);
1263 expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_NOTE,
1264 "Reject(RJ): -> 0x%x", dst_ref);
1268 } /* ositp_decode_RJ */
1270 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1271 packet_info *pinfo, proto_tree *tree,
1272 gboolean uses_inactive_subset,
1273 gboolean *subdissector_found)
1276 /* CC & CR decoding in the same function */
1278 proto_tree *cotp_tree = NULL;
1280 proto_item *item = NULL;
1281 guint16 dst_ref, src_ref;
1282 guchar class_option;
1285 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1287 class_option = tvb_get_guint8(tvb, offset + P_CLASS_OPTION);
1288 if (((class_option & 0xF0) >> 4) > 4) /* class 0..4 allowed */
1291 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1292 pinfo->clnp_srcref = src_ref;
1293 pinfo->clnp_dstref = dst_ref;
1295 if (check_col(pinfo->cinfo, COL_INFO))
1296 col_append_fstr(pinfo->cinfo, COL_INFO,
1297 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1298 (tpdu == CR_TPDU) ? "CR" : "CC",
1303 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1304 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1305 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1310 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1316 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1321 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1325 /* expert info, but only if not encapsulated in TCP/SMB */
1326 /* XXX - the best way to detect seems to be if we have a port set */
1327 if (pinfo->destport == 0) {
1328 expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT,
1329 tpdu == CR_TPDU ? "Connection Request(CR): 0x%x -> 0x%x" : "Connection Confirm(CC): 0x%x -> 0x%x",
1334 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1335 "Class: %1u", (class_option & 0xF0) >> 4);
1336 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1337 "Option: %1u", (class_option & 0x0F));
1343 ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1346 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1347 if (!uses_inactive_subset){
1348 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1350 *subdissector_found = TRUE;
1352 call_dissector(data_handle,next_tvb, pinfo, tree);
1356 call_dissector(data_handle, next_tvb, pinfo, tree);
1357 offset += tvb_length_remaining(tvb, offset);
1358 /* we dissected all of the containing PDU */
1362 } /* ositp_decode_CC */
1364 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1365 packet_info *pinfo, proto_tree *tree)
1367 proto_tree *cotp_tree = NULL;
1369 proto_item *item = NULL;
1370 guint16 dst_ref, src_ref;
1375 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1376 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1377 pinfo->clnp_dstref = dst_ref;
1378 pinfo->clnp_dstref = src_ref;
1380 if (check_col(pinfo->cinfo, COL_INFO))
1381 col_append_fstr(pinfo->cinfo, COL_INFO,
1382 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1387 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1388 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1389 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1394 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1400 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1405 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1410 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1413 expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT,
1414 "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref);
1418 } /* ositp_decode_DC */
1420 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1421 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1423 proto_tree *cotp_tree = NULL;
1432 if (is_LI_NORMAL_AK(li)) {
1434 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1435 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1436 pinfo->clnp_dstref = dst_ref;
1438 if (check_col(pinfo->cinfo, COL_INFO))
1439 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1443 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1444 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1445 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1450 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1451 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1458 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1463 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1470 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1473 } else { /* extended format */
1475 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1476 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1477 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1478 pinfo->clnp_dstref = dst_ref;
1480 if (check_col(pinfo->cinfo, COL_INFO))
1481 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x Credit: %u",
1482 tpdu_nr, dst_ref, cdt_in_ak);
1485 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1486 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1487 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1492 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1498 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1503 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1504 offset, 4, tpdu_nr);
1510 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1511 "Credit: 0x%04x", cdt_in_ak);
1517 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1520 } /* is_LI_NORMAL_AK */
1524 } /* ositp_decode_AK */
1526 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1527 packet_info *pinfo, proto_tree *tree)
1529 proto_tree *cotp_tree = NULL;
1531 gboolean is_extended;
1538 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1539 (This means we may misdissect this if the packet is bad and
1540 contains other parameters.) */
1543 case LI_NORMAL_EA_WITH_CHECKSUM :
1544 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1545 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1549 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1550 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1551 is_extended = FALSE;
1554 case LI_EXTENDED_EA_WITH_CHECKSUM :
1555 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1556 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1560 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1561 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1565 default : /* bad TPDU */
1569 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1570 pinfo->clnp_dstref = dst_ref;
1572 if (check_col(pinfo->cinfo, COL_INFO))
1573 col_append_fstr(pinfo->cinfo, COL_INFO,
1574 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1577 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1578 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1579 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1584 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1590 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1596 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1597 offset, 4, tpdu_nr);
1603 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1611 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1616 } /* ositp_decode_EA */
1618 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1619 packet_info *pinfo, proto_tree *tree)
1621 proto_tree *cotp_tree;
1629 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1631 str = "Reason not specified";
1634 str = "Invalid parameter code";
1637 str = "Invalid TPDU type";
1640 str = "Invalid parameter value";
1646 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1647 pinfo->clnp_dstref = dst_ref;
1649 if (check_col(pinfo->cinfo, COL_INFO))
1650 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1653 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1654 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1655 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1656 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
1657 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1658 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1659 "Reject cause: %s", str);
1666 } /* ositp_decode_ER */
1668 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1669 packet_info *pinfo, proto_tree *tree)
1672 proto_tree *cltp_tree = NULL;
1675 if (check_col(pinfo->cinfo, COL_INFO))
1676 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1679 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1680 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1681 proto_tree_add_uint(cltp_tree, hf_cltp_li, tvb, offset, 1,li);
1686 proto_tree_add_uint(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu);
1692 ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1695 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1696 call_dissector(data_handle,next_tvb, pinfo, tree);
1697 offset += tvb_length_remaining(tvb, offset);
1698 /* we dissected all of the containing PDU */
1702 } /* ositp_decode_UD */
1704 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1707 There doesn't seem to be any way in which the OSI network layer protocol
1708 distinguishes between COTP and CLTP, but the first two octets of both
1709 protocols' headers mean the same thing - length and PDU type - and the
1710 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1711 both of them here. */
1712 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1713 proto_tree *tree, gboolean uses_inactive_subset)
1716 guint8 li, tpdu, cdt;
1717 gboolean first_tpdu = TRUE;
1719 gboolean found_ositp = FALSE;
1720 gboolean is_cltp = FALSE;
1721 gboolean subdissector_found = FALSE;
1723 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_cotp)))
1724 return FALSE; /* COTP has been disabled */
1725 /* XXX - what about CLTP? */
1727 pinfo->current_proto = "COTP";
1729 /* Initialize the COL_INFO field; each of the TPDUs will have its
1730 information appended. */
1731 if (check_col(pinfo->cinfo, COL_INFO))
1732 col_set_str(pinfo->cinfo, COL_INFO, "");
1734 while (tvb_offset_exists(tvb, offset)) {
1736 if (check_col(pinfo->cinfo, COL_INFO))
1737 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1738 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple TPDUs in one packet");
1740 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1741 if (check_col(pinfo->cinfo, COL_INFO))
1742 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1744 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1749 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1750 if (tpdu == UD_TPDU)
1751 pinfo->current_proto = "CLTP"; /* connectionless transport */
1752 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1757 new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1758 uses_inactive_subset, &subdissector_found);
1761 new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1764 new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1765 uses_inactive_subset, &subdissector_found);
1768 new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1771 new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1774 new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1777 new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1780 new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1783 new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1786 new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1790 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1791 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1792 new_offset = -1; /* bad PDU type */
1796 if (new_offset == -1) { /* incorrect TPDU */
1798 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1804 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1805 is either COTP or CLTP. */
1806 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1807 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1811 offset = new_offset;
1815 } /* dissect_ositp_internal */
1817 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1819 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1820 call_dissector(data_handle,tvb, pinfo, tree);
1824 * CLNP part / main entry point
1827 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1829 proto_tree *clnp_tree = NULL;
1831 guint8 cnf_proto_id;
1836 char flag_string[6+1];
1837 const char *pdu_type_string;
1838 proto_tree *type_tree;
1839 guint16 segment_length;
1841 guint16 segment_offset = 0;
1843 cksum_status_t cksum_status;
1845 guchar src_len, dst_len, nsel, opt_len = 0;
1846 const guint8 *dst_addr, *src_addr;
1849 proto_tree *discpdu_tree;
1850 gboolean save_in_error_pkt;
1851 fragment_data *fd_head;
1853 gboolean update_col_info = TRUE;
1854 gboolean save_fragmented;
1856 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1857 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1858 if (check_col(pinfo->cinfo, COL_INFO))
1859 col_clear(pinfo->cinfo, COL_INFO);
1861 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1862 if (cnf_proto_id == NLPID_NULL) {
1863 if (check_col(pinfo->cinfo, COL_INFO))
1864 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1866 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1867 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1868 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1872 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1873 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1877 /* return if version not known */
1878 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1879 if (cnf_vers != ISO8473_V1) {
1880 call_dissector(data_handle,tvb, pinfo, tree);
1884 /* fixed part decoding */
1885 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1886 opt_len = cnf_hdr_len;
1889 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1890 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1891 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1893 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1895 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1897 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1898 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1900 "Holding Time : %u (%u.%u secs)",
1901 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1904 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1905 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1906 "Unknown (0x%02x)");
1907 flag_string[0] = '\0';
1908 if (cnf_type & CNF_SEG_OK)
1909 g_strlcat(flag_string, "S ", 7);
1910 if (cnf_type & CNF_MORE_SEGS)
1911 g_strlcat(flag_string, "M ", 7);
1912 if (cnf_type & CNF_ERR_OK)
1913 g_strlcat(flag_string, "E ", 7);
1915 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1917 "PDU Type : 0x%02x (%s%s)",
1921 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1922 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1923 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1924 "Segmentation permitted",
1925 "Segmentation not permitted"));
1926 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1927 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1930 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1931 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1932 "Report error if PDU discarded",
1933 "Don't report error if PDU discarded"));
1934 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1935 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1936 npdu_type_vals, "%s"));
1939 /* If we don't have the full header - i.e., not enough to see the
1940 segmentation part and determine whether this datagram is segmented
1941 or not - set the Info column now; we'll get an exception before
1942 we set it otherwise. */
1944 if (tvb_length(tvb) < cnf_hdr_len) {
1945 if (check_col(pinfo->cinfo, COL_INFO))
1946 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1949 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1950 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1951 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1953 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1955 switch (cksum_status) {
1959 * No checksum present, or not enough of the header present to
1962 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1965 "Checksum : 0x%04x",
1971 * Checksum is correct.
1973 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1976 "Checksum : 0x%04x (correct)",
1982 * Checksum is not correct.
1984 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1987 "Checksum : 0x%04x (incorrect)",
1991 opt_len -= 9; /* Fixed part of Hesder */
1996 offset = P_CLNP_ADDRESS_PART;
1997 dst_len = tvb_get_guint8(tvb, offset);
1998 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1999 nsel = tvb_get_guint8(tvb, offset + dst_len);
2000 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
2001 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
2004 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
2006 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
2009 print_nsap_net(dst_addr, dst_len));
2010 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
2011 offset + 1 + dst_len, 1, src_len);
2012 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
2013 offset + dst_len + 2, src_len,
2016 print_nsap_net(src_addr, src_len));
2018 opt_len -= dst_len + src_len +2;
2021 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
2022 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
2023 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
2024 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
2026 /* Segmentation Part */
2028 offset += dst_len + src_len + 2;
2030 if (cnf_type & CNF_SEG_OK) {
2031 struct clnp_segment seg; /* XXX - not used */
2032 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
2034 segment_offset = tvb_get_ntohs(tvb, offset + 2);
2035 du_id = tvb_get_ntohs(tvb, offset);
2037 proto_tree_add_text(clnp_tree, tvb, offset, 2,
2038 "Data unit identifier: %06u",
2040 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
2041 "Segment offset : %6u",
2043 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
2044 "Total length : %6u",
2045 tvb_get_ntohs(tvb, offset + 4));
2053 /* To do : decode options */
2055 proto_tree_add_text(clnp_tree, tvb, offset,
2056 cnf_hdr_len - offset,
2057 "Options/Data: <not shown>");
2059 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
2061 dissect_osi_options( opt_len,
2062 tvb, offset, clnp_tree );
2065 /* Length of CLNP datagram plus headers above it. */
2066 len = segment_length;
2068 offset = cnf_hdr_len;
2070 /* If clnp_reassemble is on, this is a segment, we have all the
2071 * data in the segment, and the checksum is valid, then just add the
2072 * segment to the hashtable.
2074 save_fragmented = pinfo->fragmented;
2075 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
2076 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
2077 tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) &&
2078 segment_length > cnf_hdr_len &&
2079 cksum_status != CKSUM_NOT_OK) {
2080 fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table,
2081 clnp_reassembled_table, segment_offset,
2082 segment_length - cnf_hdr_len,
2083 cnf_type & CNF_MORE_SEGS);
2085 next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP",
2086 fd_head, &clnp_frag_items, &update_col_info, clnp_tree);
2088 /* If this is the first segment, dissect its contents, otherwise
2089 just show it as a segment.
2091 XXX - if we eventually don't save the reassembled contents of all
2092 segmented datagrams, we may want to always reassemble. */
2093 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
2094 /* Not the first segment - don't dissect it. */
2097 /* First segment, or not segmented. Dissect what we have here. */
2099 /* Get a tvbuff for the payload. */
2100 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
2103 * If this is the first segment, but not the only segment,
2104 * tell the next protocol that.
2106 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
2107 pinfo->fragmented = TRUE;
2109 pinfo->fragmented = FALSE;
2113 if (next_tvb == NULL) {
2114 /* Just show this as a segment. */
2115 if (check_col(pinfo->cinfo, COL_INFO))
2116 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
2117 pdu_type_string, flag_string, segment_offset);
2119 /* As we haven't reassembled anything, we haven't changed "pi", so
2120 we don't have to restore it. */
2121 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
2123 pinfo->fragmented = save_fragmented;
2127 if (tvb_offset_exists(tvb, offset)) {
2128 switch (cnf_type & CNF_TYPE) {
2132 /* Continue with COTP if any data.
2133 XXX - if this isn't the first Derived PDU of a segmented Initial
2136 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
2137 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
2138 pinfo->fragmented = save_fragmented;
2139 return; /* yes, it appears to be COTP or CLTP */
2142 if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb,
2144 pinfo->fragmented = save_fragmented;
2145 return; /* yes, it appears to be COTP or CLTP */
2151 /* The payload is the header and "none, some, or all of the data
2152 part of the discarded PDU", i.e. it's like an ICMP error;
2153 dissect it as a CLNP PDU. */
2154 if (check_col(pinfo->cinfo, COL_INFO))
2155 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2157 next_length = tvb_length_remaining(tvb, offset);
2158 if (next_length != 0) {
2159 /* We have payload; dissect it. */
2160 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2162 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2164 /* Save the current value of the "we're inside an error packet"
2165 flag, and set that flag; subdissectors may treat packets
2166 that are the payload of error packets differently from
2168 save_in_error_pkt = pinfo->in_error_pkt;
2169 pinfo->in_error_pkt = TRUE;
2171 call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
2173 /* Restore the "we're inside an error packet" flag. */
2174 pinfo->in_error_pkt = save_in_error_pkt;
2177 pinfo->fragmented = save_fragmented;
2178 return; /* we're done with this PDU */
2182 /* XXX - dissect this */
2186 if (check_col(pinfo->cinfo, COL_INFO))
2187 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2188 call_dissector(data_handle,next_tvb, pinfo, tree);
2189 pinfo->fragmented = save_fragmented;
2190 } /* dissect_clnp */
2193 clnp_reassemble_init(void)
2195 fragment_table_init(&clnp_segment_table);
2196 reassembled_table_init(&clnp_reassembled_table);
2201 cotp_reassemble_init(void)
2203 fragment_table_init(&cotp_segment_table);
2204 reassembled_table_init(&cotp_reassembled_table);
2207 void proto_register_clnp(void)
2209 static hf_register_info hf[] = {
2211 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2212 VALS(nlpid_vals), 0x0, "", HFILL }},
2215 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2218 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2221 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2224 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2226 { &hf_clnp_pdu_length,
2227 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2229 { &hf_clnp_checksum,
2230 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2232 { &hf_clnp_dest_length,
2233 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2236 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2238 { &hf_clnp_src_length,
2239 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2242 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2244 { &hf_clnp_segment_overlap,
2245 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2246 "Segment overlaps with other segments", HFILL }},
2248 { &hf_clnp_segment_overlap_conflict,
2249 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2250 "Overlapping segments contained conflicting data", HFILL }},
2252 { &hf_clnp_segment_multiple_tails,
2253 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2254 "Several tails were found when reassembling the packet", HFILL }},
2256 { &hf_clnp_segment_too_long_segment,
2257 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2258 "Segment contained data past end of packet", HFILL }},
2260 { &hf_clnp_segment_error,
2261 { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2262 "Reassembly error due to illegal segments", HFILL }},
2265 { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2266 "CLNP Segment", HFILL }},
2268 { &hf_clnp_segments,
2269 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2270 "CLNP Segments", HFILL }},
2272 { &hf_clnp_reassembled_in,
2273 { "Reassembled CLNP in frame", "clnp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2274 "This CLNP packet is reassembled in this frame", HFILL }}
2276 static gint *ett[] = {
2284 module_t *clnp_module;
2286 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2287 proto_register_field_array(proto_clnp, hf, array_length(hf));
2288 proto_register_subtree_array(ett, array_length(ett));
2289 register_dissector("clnp", dissect_clnp, proto_clnp);
2290 register_heur_dissector_list("clnp", &clnp_heur_subdissector_list);
2291 register_init_routine(clnp_reassemble_init);
2292 register_init_routine(cotp_reassemble_init);
2294 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2295 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2296 "NSAP selector for Transport Protocol (last byte in hex)",
2297 "NSAP selector for Transport Protocol (last byte in hex)",
2298 16, &tp_nsap_selector);
2299 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2300 "Always try to decode NSDU as transport PDUs",
2301 "Always try to decode NSDU as transport PDUs",
2302 &always_decode_transport);
2303 prefs_register_bool_preference(clnp_module, "reassemble",
2304 "Reassemble segmented CLNP datagrams",
2305 "Whether segmented CLNP datagrams should be reassembled",
2310 proto_reg_handoff_clnp(void)
2312 data_handle = find_dissector("data");
2314 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2315 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2316 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2317 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2320 void proto_register_cotp(void)
2322 static hf_register_info hf[] = {
2324 { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
2325 "Source address reference", HFILL}},
2327 { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
2328 "Destination address reference", HFILL}},
2330 { "Length", "cotp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
2331 "Length Indicator, length of this header", HFILL}},
2333 { "PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
2334 "PDU Type - upper nibble of byte", HFILL}},
2335 { &hf_cotp_tpdu_number,
2336 { "TPDU number", "cotp.tpdu-number", FT_UINT8, BASE_HEX, NULL, 0x7f,
2337 "TPDU number", HFILL}},
2338 { &hf_cotp_tpdu_number_extended,
2339 { "TPDU number", "cotp.tpdu-number", FT_UINT32, BASE_HEX, NULL, 0x0 /* XXX - 0x7fff? */,
2340 "TPDU number", HFILL}},
2341 { &hf_cotp_next_tpdu_number,
2342 { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT8, BASE_HEX, NULL, 0x0,
2343 "Your TPDU number", HFILL}},
2344 { &hf_cotp_next_tpdu_number_extended,
2345 { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT32, BASE_HEX, NULL, 0x0,
2346 "Your TPDU number", HFILL}},
2348 { "Last data unit", "cotp.eot", FT_BOOLEAN, 8, TFS(&fragment_descriptions), 0x80,
2349 "Is current TPDU the last data unit of a complete DT TPDU sequence (End of TSDU)?", HFILL}},
2350 { &hf_cotp_eot_extended,
2351 { "Last data unit", "cotp.eot", FT_BOOLEAN, 32, TFS(&fragment_descriptions), 0x80000000,
2352 "Is current TPDU the last data unit of a complete DT TPDU sequence (End of TSDU)?", HFILL}},
2353 { &hf_cotp_segment_overlap,
2354 { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2355 "Segment overlaps with other segments", HFILL }},
2356 { &hf_cotp_segment_overlap_conflict,
2357 { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2358 "Overlapping segments contained conflicting data", HFILL }},
2359 { &hf_cotp_segment_multiple_tails,
2360 { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2361 "Several tails were found when reassembling the packet", HFILL }},
2362 { &hf_cotp_segment_too_long_segment,
2363 { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2364 "Segment contained data past end of packet", HFILL }},
2365 { &hf_cotp_segment_error,
2366 { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2367 "Reassembly error due to illegal segments", HFILL }},
2369 { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2370 "COTP Segment", HFILL }},
2371 { &hf_cotp_segments,
2372 { "COTP Segments", "cotp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2373 "COTP Segments", HFILL }},
2374 { &hf_cotp_reassembled_in,
2375 { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2376 "This COTP packet is reassembled in this frame", HFILL }},
2377 /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as
2378 identifiers of unspecified type and length.
2379 Some implementations of COTP use printable strings, others use raw bytes.
2380 We always add both representations to the tree; one will always be hidden
2381 depending on the tsap display preference */
2382 { &hf_cotp_vp_src_tsap,
2383 { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
2384 "Calling TSAP", HFILL }},
2385 { &hf_cotp_vp_src_tsap_bytes,
2386 { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
2387 "Calling TSAP (bytes representation)", HFILL }},
2388 { &hf_cotp_vp_dst_tsap,
2389 { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
2390 "Called TSAP", HFILL }},
2391 { &hf_cotp_vp_dst_tsap_bytes,
2392 { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
2393 "Called TSAP (bytes representation)", HFILL }},
2396 static gint *ett[] = {
2402 module_t *cotp_module;
2404 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2405 proto_register_field_array(proto_cotp, hf, array_length(hf));
2406 proto_register_subtree_array(ett, array_length(ett));
2407 cotp_module = prefs_register_protocol(proto_cotp, NULL);
2409 prefs_register_bool_preference(cotp_module, "reassemble",
2410 "Reassemble segmented COTP datagrams",
2411 "Whether segmented COTP datagrams should be reassembled."
2412 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2415 prefs_register_enum_preference(cotp_module, "tsap_display",
2416 "Display TSAPs as strings or bytes",
2417 "How TSAPs should be displayed",
2419 tsap_display_options,
2422 /* subdissector code in inactive subset */
2423 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2425 /* other COTP/ISO 8473 subdissectors */
2426 register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2428 /* XXX - what about CLTP and proto_cltp? */
2429 register_dissector("ositp", dissect_ositp, proto_cotp);
2433 proto_reg_handoff_cotp(void)
2435 dissector_handle_t ositp_handle;
2437 ositp_handle = find_dissector("ositp");
2438 dissector_add("ip.proto", IP_PROTO_TP, ositp_handle);
2441 void proto_register_cltp(void)
2443 static hf_register_info hf[] = {
2445 { "Length", "cltp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
2446 "Length Indicator, length of this header", HFILL}},
2448 { "PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
2449 "PDU Type", HFILL}},
2451 static gint *ett[] = {
2455 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2456 proto_register_field_array(proto_cltp, hf, array_length(hf));
2457 proto_register_subtree_array(ett, array_length(ett));