Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-ositp.c
blob9d5a4d815604907682f95364676083b9618a00f7
1 /* packet-ositp.c
2 * Routines for ISO/OSI transport protocol (connection-oriented
3 * and connectionless) 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 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/prefs.h>
19 #include <epan/reassemble.h>
20 #include <epan/conversation.h>
21 #include <epan/ipproto.h>
22 #include <epan/expert.h>
23 #include <epan/proto_data.h>
24 #include <epan/tfs.h>
25 #include <wsutil/array.h>
27 #include <wsutil/str_util.h>
28 #include "packet-frame.h"
29 #include "packet-osi.h"
31 void proto_register_cotp(void);
32 void proto_register_cltp(void);
33 void proto_reg_handoff_cotp(void);
35 /* protocols and fields */
37 static int proto_clnp;
39 static int proto_cotp;
40 static int ett_cotp;
41 static int ett_cotp_segments;
42 static int ett_cotp_segment;
44 static int hf_cotp_li;
45 static int hf_cotp_type;
46 static int hf_cotp_srcref;
47 static int hf_cotp_destref;
48 static int hf_cotp_class;
49 static int hf_cotp_opts_extended_formats;
50 static int hf_cotp_opts_no_explicit_flow_control;
51 static int hf_cotp_tpdu_number;
52 static int hf_cotp_tpdu_number_extended;
53 static int hf_cotp_next_tpdu_number;
54 static int hf_cotp_next_tpdu_number_extended;
55 static int hf_cotp_eot;
56 static int hf_cotp_eot_extended;
57 /* Generated from convert_proto_tree_add_text.pl */
58 static int hf_cotp_parameter_code;
59 static int hf_cotp_parameter_length;
60 static int hf_cotp_parameter_value;
61 static int hf_cotp_atn_extended_checksum16;
62 static int hf_cotp_atn_extended_checksum32;
63 static int hf_cotp_atn_extended_checksum_status;
64 static int hf_cotp_ack_time;
65 static int hf_cotp_res_error_rate_target_value;
66 static int hf_cotp_res_error_rate_min_accept;
67 static int hf_cotp_res_error_rate_tdsu;
68 static int hf_cotp_vp_priority;
69 static int hf_cotp_transit_delay_targ_calling_called;
70 static int hf_cotp_transit_delay_max_accept_calling_called;
71 static int hf_cotp_transit_delay_targ_called_calling;
72 static int hf_cotp_transit_delay_max_accept_called_calling;
73 static int hf_cotp_max_throughput_targ_calling_called;
74 static int hf_cotp_max_throughput_min_accept_calling_called;
75 static int hf_cotp_max_throughput_targ_called_calling;
76 static int hf_cotp_max_throughput_min_accept_called_calling;
77 static int hf_cotp_avg_throughput_targ_calling_called;
78 static int hf_cotp_avg_throughput_min_accept_calling_called;
79 static int hf_cotp_avg_throughput_targ_called_calling;
80 static int hf_cotp_avg_throughput_min_accept_called_calling;
81 static int hf_cotp_sequence_number;
82 static int hf_cotp_reassignment_time;
83 static int hf_cotp_lower_window_edge;
84 static int hf_cotp_credit;
85 static int hf_cotp_tpdu_size;
86 static int hf_cotp_checksum;
87 static int hf_cotp_checksum_status;
88 static int hf_cotp_vp_version_nr;
89 static int hf_cotp_network_expedited_data;
90 static int hf_cotp_vp_opt_sel_class1_use;
91 static int hf_cotp_use_16_bit_checksum;
92 static int hf_cotp_transport_expedited_data_transfer;
93 static int hf_cotp_preferred_maximum_tpdu_size;
94 static int hf_cotp_inactivity_timer;
95 static int hf_cotp_cause;
96 static int hf_cotp_segment_data;
97 static int hf_cotp_credit_cdt;
98 static int hf_cotp_reject_cause;
100 static int hf_cotp_segments;
101 static int hf_cotp_segment;
102 static int hf_cotp_segment_overlap;
103 static int hf_cotp_segment_overlap_conflict;
104 static int hf_cotp_segment_multiple_tails;
105 static int hf_cotp_segment_too_long_segment;
106 static int hf_cotp_segment_error;
107 static int hf_cotp_segment_count;
108 static int hf_cotp_reassembled_in;
109 static int hf_cotp_reassembled_length;
111 static expert_field ei_cotp_disconnect_confirm;
112 static expert_field ei_cotp_multiple_tpdus;
113 static expert_field ei_cotp_reject;
114 static expert_field ei_cotp_connection;
115 static expert_field ei_cotp_disconnect_request;
116 static expert_field ei_cotp_preferred_maximum_tpdu_size;
117 static expert_field ei_cotp_atn_extended_checksum;
118 static expert_field ei_cotp_checksum;
121 static int proto_cltp;
122 static int ett_cltp;
124 static int hf_cltp_li;
125 static int hf_cltp_type;
127 static const fragment_items cotp_frag_items = {
128 &ett_cotp_segment,
129 &ett_cotp_segments,
130 &hf_cotp_segments,
131 &hf_cotp_segment,
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_segment_count,
138 &hf_cotp_reassembled_in,
139 &hf_cotp_reassembled_length,
140 /* Reassembled data field */
141 NULL,
142 "segments"
145 static dissector_handle_t rdp_cr_handle;
146 static dissector_handle_t rdp_cc_handle;
147 static dissector_handle_t ositp_handle;
151 * ISO8073 OSI COTP definition
152 * See http://standards.iso.org/ittf/PubliclyAvailableStandards/index.html
153 * (or RFC905 for historic, and now-outdated information)
156 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
158 /* TPDU definition */
160 #define ED_TPDU 0x1 /* COTP */
161 #define EA_TPDU 0x2 /* COTP */
162 #define UD_TPDU 0x4 /* CLTP */
163 #define RJ_TPDU 0x5 /* COTP */
164 #define AK_TPDU 0x6 /* COTP */
165 #define ER_TPDU 0x7 /* COTP */
166 #define DR_TPDU 0x8 /* COTP */
167 #define DC_TPDU 0xC /* COTP */
168 #define CC_TPDU 0xD /* COTP */
169 #define CR_TPDU 0xE /* COTP */
170 #define DT_TPDU 0xF /* COTP */
172 static const value_string cotp_tpdu_type_abbrev_vals[] = {
173 { ED_TPDU, "ED Expedited Data" },
174 { EA_TPDU, "EA Expedited Data Acknowledgement" },
175 { RJ_TPDU, "RJ Reject" },
176 { AK_TPDU, "AK Data Acknowledgement" },
177 { ER_TPDU, "ER TPDU Error" },
178 { DR_TPDU, "DR Disconnect Request" },
179 { DC_TPDU, "DC Disconnect Confirm" },
180 { CC_TPDU, "CC Connect Confirm" },
181 { CR_TPDU, "CR Connect Request" },
182 { DT_TPDU, "DT Data" },
183 { 0, NULL }
186 static const value_string cltp_tpdu_type_abbrev_vals[] = {
187 { UD_TPDU, "UD" },
188 { 0, NULL }
191 #if 0
192 static const value_string class_option_vals[] = {
193 {0, "Class 0"},
194 {1, "Class 1"},
195 {2, "Class 2"},
196 {3, "Class 3"},
197 {4, "Class 4"},
198 {0, NULL}
200 #endif
202 /* field position */
204 #define P_LI 0
205 #define P_TPDU 1
206 #define P_CDT 1
207 #define P_DST_REF 2
208 #define P_SRC_REF 4
209 #define P_TPDU_NR_0_1 2
210 #define P_TPDU_NR_234 4
211 #define P_VAR_PART_NDT 5
212 #define P_VAR_PART_EDT 8
213 #define P_VAR_PART_DC 6
214 #define P_CDT_IN_AK 8
215 #define P_CDT_IN_RJ 8
216 #define P_REJECT_ER 4
217 #define P_REASON_IN_DR 6
218 #define P_CLASS_OPTION 6
221 * TPDU length indicator values.
222 * Checksum parameter is 4 octets - 1 octet of parameter code, 1 octet
223 * of parameter length, 2 octets of checksum.
226 #define LI_NORMAL_DT_CLASS_01 2
227 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
228 #define LI_NORMAL_DT_WITH_CHECKSUM (LI_NORMAL_DT_WITHOUT_CHECKSUM+4)
229 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
230 #define LI_EXTENDED_DT_WITH_CHECKSUM (LI_EXTENDED_DT_WITHOUT_CHECKSUM+4)
231 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
232 #define LI_NORMAL_EA_WITH_CHECKSUM (LI_NORMAL_EA_WITHOUT_CHECKSUM+4)
233 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
234 #define LI_EXTENDED_EA_WITH_CHECKSUM (LI_EXTENDED_EA_WITHOUT_CHECKSUM+4)
235 #define LI_NORMAL_RJ 4
236 #define LI_EXTENDED_RJ 9
237 #define LI_MIN_DR 6
238 #define LI_MAX_DC 9
239 #define LI_MAX_AK 27
240 #define LI_MAX_EA 11
241 #define LI_MAX_ER 8
242 /* XXX - can we always decide this based on whether the length
243 indicator is odd or not? What if the variable part has an odd
244 number of octets? */
245 #define is_LI_NORMAL_AK(p) ((p & 0x01) == 0)
248 * Modified TPDU length indicator values due to ATN 4-octet extended
249 * checksum.
250 * Checksum parameter is 6 octets - 1 octet of parameter code, 1 octet
251 * of parameter length, 4 octets of checksum. That adds 2 octets to
252 * the lengths with a 2-octet checksum.
254 #define LI_ATN_NORMAL_DT_WITH_CHECKSUM (LI_NORMAL_DT_WITH_CHECKSUM+2)
255 #define LI_ATN_EXTENDED_DT_WITH_CHECKSUM (LI_EXTENDED_DT_WITH_CHECKSUM+2)
256 #define LI_ATN_NORMAL_EA_WITH_CHECKSUM (LI_NORMAL_EA_WITH_CHECKSUM+2)
257 #define LI_ATN_EXTENDED_EA_WITH_CHECKSUM (LI_EXTENDED_EA_WITH_CHECKSUM+2)
258 #define LI_ATN_NORMAL_RJ (LI_NORMAL_RJ+2)
259 #define LI_ATN_EXTENDED_RJ (LI_EXTENDED_RJ+2)
260 #define LI_ATN_MAX_DC (LI_MAX_DC+2)
261 #define LI_ATN_MAX_AK (LI_MAX_AK+2+1) /* +1 for padding? */
262 #define LI_ATN_MAX_EA (LI_MAX_EA+2)
263 #define LI_ATN_MAX_ER (LI_MAX_ER+2)
265 /* variant part */
267 #define VP_ACK_TIME 0x85
268 #define VP_RES_ERROR 0x86
269 #define VP_PRIORITY 0x87
270 #define VP_TRANSIT_DEL 0x88
271 #define VP_THROUGHPUT 0x89
272 #define VP_SEQ_NR 0x8A /* in AK */
273 #define VP_REASSIGNMENT 0x8B
274 #define VP_FLOW_CNTL 0x8C /* in AK */
275 #define VP_TPDU_SIZE 0xC0
276 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
277 #define VP_DST_TSAP 0xC2
278 #define VP_CHECKSUM 0xC3
279 #define VP_VERSION_NR 0xC4
280 #define VP_PROTECTION 0xC5
281 #define VP_OPT_SEL 0xC6
282 #define VP_PROTO_CLASS 0xC7
283 #define VP_CLEARING_INFO 0xE0 /* in DR */
284 #define VP_PREF_MAX_TPDU_SIZE 0xF0
285 #define VP_INACTIVITY_TIMER 0xF2
287 /* ATN */
288 /* Parameter codes with bits 7 and 8 are explicitly not */
289 /* assigned by ISO/IEC 8073, nor is their use precluded. */
290 /* Parameter codes for ATN defined in ICAO doc 9507 Ed3 SV 5 section 5.5.2.4.3.1 */
291 #define VP_ATN_EC_32 0x08 /* 4 octet ATN Extended Transport Checksum parameter */
292 #define VP_ATN_EC_16 0x09 /* 2 octet ATN Extended Transport Checksum parameter */
293 /* ATN end */
295 static const value_string tp_vpart_type_vals[] = {
296 { VP_ATN_EC_16, "ATN extended checksum - 16 bit" },
297 { VP_ATN_EC_32, "ATN extended checksum - 32 bit" },
298 { VP_ACK_TIME, "ack time" },
299 { VP_RES_ERROR, "res error" },
300 { VP_PRIORITY, "priority" },
301 { VP_TRANSIT_DEL, "transit delay" },
302 { VP_THROUGHPUT, "throughput" },
303 { VP_SEQ_NR, "seq number" },
304 { VP_REASSIGNMENT, "reassignment" },
305 { VP_FLOW_CNTL, "flow control" },
306 { VP_TPDU_SIZE, "tpdu-size" },
307 { VP_SRC_TSAP, "src-tsap" },
308 { VP_DST_TSAP, "dst-tsap" },
309 { VP_CHECKSUM, "checksum" },
310 { VP_VERSION_NR, "version" },
311 { VP_PROTECTION, "protection" },
312 { VP_OPT_SEL, "options" },
313 { VP_PROTO_CLASS, "proto class" },
314 { VP_CLEARING_INFO, "additional connection clearing info" },
315 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
316 { VP_INACTIVITY_TIMER, "inactivity timer" },
317 { 0, NULL }
320 static int hf_cotp_vp_src_tsap;
321 static int hf_cotp_vp_dst_tsap;
322 static int hf_cotp_vp_src_tsap_bytes;
323 static int hf_cotp_vp_dst_tsap_bytes;
325 /* global variables */
327 /* List of dissectors to call for the variable part of CR PDUs. */
328 static heur_dissector_list_t cotp_cr_heur_subdissector_list;
329 /* List of dissectors to call for the variable part of CC PDUs. */
330 static heur_dissector_list_t cotp_cc_heur_subdissector_list;
331 /* List of dissectors to call for COTP packets put atop the Inactive
332 Subset of CLNP. */
333 static heur_dissector_list_t cotp_is_heur_subdissector_list;
334 /* List of dissectors to call for COTP packets put atop CLNP */
335 static heur_dissector_list_t cotp_heur_subdissector_list;
336 /* List of dissectors to call for CLTP packets put atop CLNP */
337 static heur_dissector_list_t cltp_heur_subdissector_list;
340 * Reassembly of COTP.
342 static reassembly_table cotp_reassembly_table;
343 static uint16_t cotp_dst_ref;
344 static bool cotp_frame_reset;
345 static bool cotp_last_fragment;
347 #define TSAP_DISPLAY_AUTO 0
348 #define TSAP_DISPLAY_STRING 1
349 #define TSAP_DISPLAY_BYTES 2
351 /* options */
352 static bool cotp_reassemble = true;
353 static int32_t tsap_display = TSAP_DISPLAY_AUTO;
354 static bool cotp_decode_atn;
356 static const enum_val_t tsap_display_options[] = {
357 {"auto", "As strings if printable", TSAP_DISPLAY_AUTO},
358 {"string", "As strings", TSAP_DISPLAY_STRING},
359 {"bytes", "As bytes", TSAP_DISPLAY_BYTES},
360 {NULL, NULL, -1}
363 /* function definitions */
365 #define MAX_TSAP_LEN 32
367 static void cotp_frame_end(void)
369 if (!cotp_last_fragment) {
370 /* Last COTP in frame is not fragmented.
371 * No need for incrementing the dst_ref, so we decrement it here.
373 cotp_dst_ref--;
375 cotp_frame_reset = true;
378 static char *print_tsap(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int length)
380 const unsigned char *tsap = tvb_get_ptr(tvb, offset, length);
381 char *cur;
382 bool allprintable;
383 int idx = 0, returned_length;
385 cur=(char *)wmem_alloc(scope, MAX_TSAP_LEN * 2 + 3);
386 cur[0] = '\0';
387 if (length <= 0 || length > MAX_TSAP_LEN)
388 snprintf(cur, MAX_TSAP_LEN * 2 + 3, "<unsupported TSAP length>");
389 else {
390 allprintable = tvb_ascii_isprint(tvb, offset, length);
391 if (!allprintable) {
392 returned_length = snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x");
393 idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1);
395 while (length != 0) {
396 if (allprintable) {
397 returned_length = snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx,
398 "%c", *tsap ++);
399 idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1);
400 } else {
401 returned_length = snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx,
402 "%02x", *tsap ++);
403 idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1);
405 length --;
408 return cur;
410 } /* print_tsap */
412 static const true_false_string tfs_vp_opt_sel_class1_use = { "Receipt confirmation", "Explicit AK variant" };
414 static bool ositp_decode_var_part(tvbuff_t *tvb, int offset, int vp_length,
415 int class_option, int tpdu_len,
416 packet_info *pinfo, proto_tree *tree)
418 uint8_t code, length;
419 uint8_t c1;
420 uint16_t s;
421 uint32_t offset_iso8073_checksum = 0;
422 int32_t i = 0;
423 uint8_t tmp_code = 0;
424 unsigned tmp_len = 0;
425 uint32_t pref_max_tpdu_size;
426 proto_item *hidden_item;
428 while (vp_length != 0) {
429 code = tvb_get_uint8(tvb, offset);
430 proto_tree_add_item(tree, hf_cotp_parameter_code, tvb, offset, 1, ENC_NA);
431 offset += 1;
432 vp_length -= 1;
434 if (vp_length == 0)
435 break;
436 length = tvb_get_uint8(tvb, offset);
437 proto_tree_add_item(tree, hf_cotp_parameter_length, tvb, offset, 1, ENC_NA);
438 offset += 1;
439 vp_length -= 1;
441 switch (code) {
443 case VP_ATN_EC_16 : /* ATN */
444 if (cotp_decode_atn) {
445 uint16_t sum;
446 /* if an alternate OSI checksum is present in the currently unprocessed
447 * VP section to the checksum algorithm has to know.
448 * this may be the case for backward compatible CR TPDU */
449 if (!offset_iso8073_checksum) {
450 /* search following parameters in VP part for ISO checksum */
451 for (i = offset + length; i < vp_length;) {
452 tmp_code = tvb_get_uint8(tvb, i++);
453 tmp_len = tvb_get_uint8(tvb, i++);
454 if (tmp_code == VP_CHECKSUM) {
455 offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */
456 break;
458 i += tmp_len;
461 sum = check_atn_ec_16(tvb, tpdu_len , offset,
462 offset_iso8073_checksum,
463 pinfo->dst.len, (const uint8_t *)pinfo->dst.data,
464 pinfo->src.len, (const uint8_t *)pinfo->src.data);
465 proto_tree_add_checksum(tree, tvb, offset, hf_cotp_atn_extended_checksum16, hf_cotp_atn_extended_checksum_status, &ei_cotp_atn_extended_checksum,
466 pinfo, sum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
467 } else {
468 proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>");
470 offset += length;
471 vp_length -= length;
472 break;
474 case VP_ATN_EC_32 : /* ATN */
475 if (cotp_decode_atn) {
476 uint32_t sum;
477 /* if an alternate OSI checksum is present in the currently unprocessed
478 * VP section the checksum algorithm has to know.
479 * this may be the case for backward compatible CR TPDU */
480 if (!offset_iso8073_checksum) {
481 /* search following parameters in VP part for ISO checksum */
482 for (i = offset + length; i < vp_length;) {
483 tmp_code = tvb_get_uint8(tvb, i++);
484 tmp_len = tvb_get_uint8(tvb, i++);
485 if (tmp_code == VP_CHECKSUM) {
486 offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */
487 break;
489 i += tmp_len;
492 sum = check_atn_ec_32(tvb, tpdu_len , offset,
493 offset_iso8073_checksum,
494 pinfo->dst.len, (const uint8_t *)pinfo->dst.data,
495 pinfo->src.len, (const uint8_t *)pinfo->src.data);
496 proto_tree_add_checksum(tree, tvb, offset, hf_cotp_atn_extended_checksum32, hf_cotp_atn_extended_checksum_status, &ei_cotp_atn_extended_checksum,
497 pinfo, sum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
498 } else {
499 proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>");
501 offset += length;
502 vp_length -= length;
503 break;
505 case VP_ACK_TIME:
506 proto_tree_add_item(tree, hf_cotp_ack_time, tvb, offset, length, ENC_BIG_ENDIAN);
507 offset += length;
508 vp_length -= length;
509 break;
511 case VP_RES_ERROR:
512 s = tvb_get_uint8(tvb, offset);
513 proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_target_value, tvb, offset, 1, s, "10^%u", s);
514 offset += 1;
515 vp_length -= 1;
517 s = tvb_get_uint8(tvb, offset);
518 proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_min_accept, tvb, offset, 1, s, "10^%u", s);
519 offset += 1;
520 vp_length -= 1;
522 s = tvb_get_uint8(tvb, offset);
523 proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_tdsu, tvb, offset, 1, s, "2^%u", s);
524 offset += 1;
525 vp_length -= 1;
526 break;
528 case VP_PRIORITY:
529 proto_tree_add_item(tree, hf_cotp_vp_priority, tvb, offset, 2, ENC_BIG_ENDIAN);
530 offset += length;
531 vp_length -= length;
532 break;
534 case VP_TRANSIT_DEL:
535 proto_tree_add_item(tree, hf_cotp_transit_delay_targ_calling_called, tvb, offset, 2, ENC_BIG_ENDIAN);
536 offset += 2;
537 vp_length -= 2;
539 proto_tree_add_item(tree, hf_cotp_transit_delay_max_accept_calling_called, tvb, offset, 2, ENC_BIG_ENDIAN);
540 offset += 2;
541 vp_length -= 2;
543 proto_tree_add_item(tree, hf_cotp_transit_delay_targ_called_calling, tvb, offset, 2, ENC_BIG_ENDIAN);
544 offset += 2;
545 vp_length -= 2;
547 proto_tree_add_item(tree, hf_cotp_transit_delay_max_accept_called_calling, tvb, offset, 2, ENC_BIG_ENDIAN);
548 offset += 2;
549 vp_length -= 2;
550 break;
552 case VP_THROUGHPUT:
553 proto_tree_add_item(tree, hf_cotp_max_throughput_targ_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN);
554 offset += 3;
555 length -= 3;
556 vp_length -= 3;
558 proto_tree_add_item(tree, hf_cotp_max_throughput_min_accept_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN);
559 offset += 3;
560 length -= 3;
561 vp_length -= 3;
563 proto_tree_add_item(tree, hf_cotp_max_throughput_targ_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN);
564 offset += 3;
565 length -= 3;
566 vp_length -= 3;
568 proto_tree_add_item(tree, hf_cotp_max_throughput_min_accept_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN);
569 offset += 3;
570 length -= 3;
571 vp_length -= 3;
573 if (length != 0) { /* XXX - should be 0 or 12 */
574 proto_tree_add_item(tree, hf_cotp_avg_throughput_targ_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN);
575 offset += 3;
576 vp_length -= 3;
578 proto_tree_add_item(tree, hf_cotp_avg_throughput_min_accept_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN);
579 offset += 3;
580 vp_length -= 3;
582 proto_tree_add_item(tree, hf_cotp_avg_throughput_targ_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN);
583 offset += 3;
584 vp_length -= 3;
586 proto_tree_add_item(tree, hf_cotp_avg_throughput_min_accept_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN);
587 offset += 3;
588 vp_length -= 3;
590 break;
592 case VP_SEQ_NR:
593 proto_tree_add_item(tree, hf_cotp_sequence_number, tvb, offset, 2, ENC_BIG_ENDIAN);
594 offset += length;
595 vp_length -= length;
596 break;
598 case VP_REASSIGNMENT:
599 proto_tree_add_item(tree, hf_cotp_reassignment_time, tvb, offset, 2, ENC_BIG_ENDIAN);
600 offset += length;
601 vp_length -= length;
602 break;
604 case VP_FLOW_CNTL:
605 proto_tree_add_item(tree, hf_cotp_lower_window_edge, tvb, offset, 4, ENC_BIG_ENDIAN);
606 offset += 4;
607 vp_length -= 4;
609 proto_tree_add_item(tree, hf_cotp_sequence_number, tvb, offset, 2, ENC_BIG_ENDIAN);
610 offset += 2;
611 vp_length -= 2;
613 proto_tree_add_item(tree, hf_cotp_credit, tvb, offset, 2, ENC_BIG_ENDIAN);
614 offset += 2;
615 vp_length -= 2;
617 break;
619 case VP_TPDU_SIZE:
620 c1 = tvb_get_uint8(tvb, offset) & 0x0F;
621 proto_tree_add_uint(tree, hf_cotp_tpdu_size, tvb, offset, 1, 1 << c1);
622 offset += length;
623 vp_length -= length;
624 break;
626 case VP_SRC_TSAP:
627 /* if our preference is set to STRING or the TSAP is not printable,
628 * add as bytes and hidden as string; otherwise vice-versa */
629 if (tsap_display==TSAP_DISPLAY_STRING ||
630 (tsap_display==TSAP_DISPLAY_AUTO &&
631 tvb_ascii_isprint(tvb, offset, length))) {
632 proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
633 print_tsap(pinfo->pool, tvb, offset, length));
634 hidden_item = proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb,
635 offset, length, ENC_NA);
636 proto_item_set_hidden(hidden_item);
637 } else {
638 hidden_item = proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb,
639 offset, length,
640 print_tsap(pinfo->pool, tvb, offset, length));
641 proto_item_set_hidden(hidden_item);
642 proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset,
643 length, ENC_NA);
645 offset += length;
646 vp_length -= length;
647 break;
649 case VP_DST_TSAP:
650 /* if our preference is set to STRING or the TSAP is not printable,
651 * add as bytes and hidden as string; otherwise vice-versa */
652 if (tsap_display==TSAP_DISPLAY_STRING ||
653 (tsap_display==TSAP_DISPLAY_AUTO &&
654 tvb_ascii_isprint(tvb, offset, length))) {
655 proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
656 print_tsap(pinfo->pool, tvb, offset, length));
657 hidden_item = proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb,
658 offset, length, ENC_NA);
659 proto_item_set_hidden(hidden_item);
660 } else {
661 hidden_item = proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb,
662 offset, length,
663 print_tsap(pinfo->pool, tvb, offset, length));
664 proto_item_set_hidden(hidden_item);
665 proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset,
666 length, ENC_NA);
668 offset += length;
669 vp_length -= length;
670 break;
672 case VP_CHECKSUM:
673 offset_iso8073_checksum = offset; /* save ISO 8073 checksum offset for ATN extended checksum calculation */
675 if (tvb_get_ntohs(tvb, offset) == 0) {
676 /* No checksum present */
677 proto_tree_add_checksum(tree, tvb, offset, hf_cotp_checksum, hf_cotp_checksum_status, &ei_cotp_checksum, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NOT_PRESENT);
678 } else {
679 uint32_t calc_c0 = 0, calc_c1 = 0;
681 if (osi_calc_checksum(tvb, 0, length, &calc_c0, &calc_c1)) {
682 /* Successfully processed checksum, verify it */
683 proto_tree_add_checksum(tree, tvb, offset, hf_cotp_checksum, hf_cotp_checksum_status, &ei_cotp_checksum, pinfo, calc_c0 | calc_c1, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
684 } else {
685 proto_tree_add_checksum(tree, tvb, offset, hf_cotp_checksum, hf_cotp_checksum_status, &ei_cotp_checksum, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
689 offset += length;
690 vp_length -= length;
691 break;
693 case VP_VERSION_NR:
694 proto_tree_add_item(tree, hf_cotp_vp_version_nr, tvb, offset, 1, ENC_NA);
695 offset += length;
696 vp_length -= length;
697 break;
699 case VP_OPT_SEL:
700 switch (class_option) {
702 case 1:
703 proto_tree_add_item(tree, hf_cotp_network_expedited_data, tvb, offset, 1, ENC_NA);
705 proto_tree_add_item(tree, hf_cotp_vp_opt_sel_class1_use, tvb, offset, 1, ENC_NA);
706 break;
708 case 4:
709 proto_tree_add_item(tree, hf_cotp_use_16_bit_checksum, tvb, offset, 1, ENC_NA);
710 break;
713 proto_tree_add_item(tree, hf_cotp_transport_expedited_data_transfer, tvb, offset, 1, ENC_NA);
714 offset += length;
715 vp_length -= length;
716 break;
718 case VP_PREF_MAX_TPDU_SIZE:
719 switch (length) {
721 case 1:
722 pref_max_tpdu_size = tvb_get_uint8(tvb, offset);
723 break;
725 case 2:
726 pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
727 break;
729 case 3:
730 pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
731 break;
733 case 4:
734 pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
735 break;
737 default:
738 proto_tree_add_expert_format(tree, pinfo, &ei_cotp_preferred_maximum_tpdu_size, tvb, offset, length,
739 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)", length);
740 return false;
742 proto_tree_add_uint(tree, hf_cotp_preferred_maximum_tpdu_size, tvb, offset, length, pref_max_tpdu_size*128);
743 offset += length;
744 vp_length -= length;
745 break;
747 case VP_INACTIVITY_TIMER:
748 proto_tree_add_item(tree, hf_cotp_inactivity_timer, tvb, offset, length, ENC_BIG_ENDIAN);
749 offset += length;
750 vp_length -= length;
751 break;
753 case VP_PROTECTION: /* user-defined */
754 case VP_PROTO_CLASS: /* todo */
755 case VP_CLEARING_INFO: /* user-defined */
756 default: /* unknown, no decoding */
757 proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>");
758 offset += length;
759 vp_length -= length;
760 break;
762 } /* while */
764 return true;
767 static const value_string cotp_cause_vals[] = {
768 { 0, "Reason not specified" },
769 { 1, "Congestion at TSAP" },
770 { 2, "Session entity not attached to TSAP" },
771 { 3, "Address unknown" },
772 { 128+0, "Normal Disconnect" },
773 { 128+1, "Remote transport entity congestion" },
774 { 128+2, "Connection negotiation failed" },
775 { 128+3, "Duplicate source reference" },
776 { 128+4, "Mismatched references" },
777 { 128+5, "Protocol error" },
778 { 128+7, "Reference overflow" },
779 { 128+8, "Connection request refused" },
780 { 128+10, "Header or parameter length invalid" },
781 { 0, NULL }
784 static int ositp_decode_DR(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
785 packet_info *pinfo, proto_tree *tree)
787 proto_tree *cotp_tree = NULL;
788 proto_item *ti = NULL;
789 uint16_t dst_ref, src_ref;
790 unsigned char reason;
791 unsigned tpdu_len;
793 /* ATN TPDU's tend to be larger than normal OSI,
794 * so nothing to do with respect to LI checks */
795 if (li < LI_MIN_DR)
796 return -1;
798 /* DR TPDUs can have user data, so they run to the end of the containing PDU */
799 tpdu_len = tvb_reported_length_remaining(tvb, offset);
801 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
803 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
805 reason = tvb_get_uint8(tvb, offset + P_REASON_IN_DR);
807 pinfo->clnp_dstref = dst_ref;
808 pinfo->clnp_srcref = src_ref;
810 /* the settings of the TCP srcport and destport are currently disabled,
811 * for the following reasons:
812 * a) only used for ISO conversation handling (which currently doesn't work)
813 * b) will prevent "ISO on TCP" (RFC1006) packets from using
814 * "follow TCP stream" correctly
816 * A future conversation handling might be able to handle different kinds of
817 * conversations (TCP, ISO, TCP on TCP, ...), but in that case this has to be
818 * fixed in any case.
820 /*pinfo->srcport = src_ref;*/
821 /*pinfo->destport = dst_ref;*/
822 if (try_val_to_str(reason, cotp_cause_vals) == NULL)
823 return -1;
825 col_append_fstr(pinfo->cinfo, COL_INFO,
826 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x", src_ref, dst_ref);
828 if (tree) {
829 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
830 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
831 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
832 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
833 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2,
834 dst_ref);
835 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset + 4, 2,
836 src_ref);
837 proto_tree_add_item(cotp_tree, hf_cotp_cause, tvb, offset + 6, 1, ENC_NA);
839 offset += 7;
840 li -= 6;
842 if (tree)
843 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
844 offset += li;
846 expert_add_info_format(pinfo, ti, &ei_cotp_disconnect_request, "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref);
848 /* User data */
849 call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
850 offset += tvb_captured_length_remaining(tvb, offset);
851 /* we dissected all of the containing PDU */
853 return offset;
855 } /* ositp_decode_DR */
857 static int ositp_decode_DT(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
858 packet_info *pinfo, proto_tree *tree,
859 bool uses_inactive_subset,
860 bool *subdissector_found)
862 proto_tree *cotp_tree = NULL;
863 proto_item *ti;
864 bool is_extended;
865 bool is_class_234;
866 uint32_t dst_ref;
867 uint32_t *prev_dst_ref;
868 unsigned tpdu_nr;
869 bool fragment = false;
870 uint32_t fragment_length = 0;
871 tvbuff_t *next_tvb;
872 fragment_head *fd_head;
873 conversation_t *conv;
874 unsigned tpdu_len;
875 heur_dtbl_entry_t *hdtbl_entry;
877 /* DT TPDUs have user data, so they run to the end of the containing PDU */
878 tpdu_len = tvb_reported_length_remaining(tvb, offset);
880 /* The fixed part is 2 octets long, not including the length indicator,
881 for classes 0 and 1; it is at least 4 octets long, not including
882 the length indicator, for classes 2, 3, and 4. */
883 is_class_234 = (li > LI_NORMAL_DT_CLASS_01);
885 /* note: in the ATN the user is up to chose between 3 different checksums:
886 * standard OSI, 2 or 4 octet extended checksum.
887 * The differences for DT are that the TPDU headers may be enlarged by 2
888 * octets and that checksum related option codes and option lengths are
889 * different. To not mess up the original OSI dissector LI checking was
890 * implemented separately. */
891 if (!cotp_decode_atn) { /* non ATN, plain OSI*/
892 /* VP_CHECKSUM is the only parameter allowed in the variable part.
893 * (This means we may misdissect this if the packet is bad and
894 * contains other parameters.).
896 * XXX - not true; ISO/IEC 8073:1997 (E) says that "if the use of
897 * non-blocking expedited data transfer service is negotiated (class
898 * 4 only), the variable part shall contain the ED-TPDU-NR for the
899 * first DT-TPDU created from a T-DATA request subsequent to the
900 * T-EXPEDITED DATA request". */
901 switch (li) {
903 case LI_NORMAL_DT_WITH_CHECKSUM :
904 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
905 return -1;
906 /* FALLTHROUGH */
908 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
909 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
910 if (tpdu_nr & 0x80)
911 tpdu_nr = tpdu_nr & 0x7F;
912 else
913 fragment = true;
914 is_extended = false;
915 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
916 break;
918 case LI_EXTENDED_DT_WITH_CHECKSUM :
919 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
920 return -1;
921 /* FALLTHROUGH */
923 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
924 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
925 if (tpdu_nr & 0x80000000)
926 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
927 else
928 fragment = true;
929 is_extended = true;
930 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
931 break;
933 case LI_NORMAL_DT_CLASS_01 :
934 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_0_1);
935 if (tpdu_nr & 0x80)
936 tpdu_nr = tpdu_nr & 0x7F;
937 else
938 fragment = true;
939 is_extended = false;
940 prev_dst_ref = (uint32_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_clnp, 0);
941 if (!prev_dst_ref) {
942 /* First COTP in frame - save previous dst_ref as offset */
943 prev_dst_ref = wmem_new(wmem_file_scope(), uint32_t);
944 *prev_dst_ref = cotp_dst_ref;
945 p_add_proto_data(wmem_file_scope(), pinfo, proto_clnp, 0, prev_dst_ref);
946 } else if (cotp_frame_reset) {
947 cotp_dst_ref = *prev_dst_ref;
949 cotp_frame_reset = false;
950 cotp_last_fragment = fragment;
951 dst_ref = cotp_dst_ref;
952 conv = find_conversation_pinfo(pinfo, 0);
953 if (conv) {
954 /* Found a conversation, also use index for the generated dst_ref */
955 dst_ref += (conv->conv_index << 16);
957 if (!fragment) {
958 cotp_dst_ref++;
959 register_frame_end_routine(pinfo, cotp_frame_end);
961 break;
963 default : /* bad TPDU */
964 return -1;
965 } /* li */
966 } else {
967 /* check ATN class4 TPDU's here */
969 /* check packet length indicators of DaTa(DT) TPDU
970 * note: use of checksum depends on the selected RER
971 * (high:non-use medium:16-bit OSI/16-bit ext.ATN low:32-bit ext. ATN)
973 * note: sole use of TP4 class in the ATN
974 * note: normal/extended TPDU numbering is negociable */
975 switch (li) {
977 /* normal DT with 2 octets of OSI or of ATN Extended Checksum */
978 case LI_NORMAL_DT_WITH_CHECKSUM :
979 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM &&
980 tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16)
981 return -1;
982 /* FALLTHROUGH */
984 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
985 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
986 if (tpdu_nr & 0x80)
987 tpdu_nr = tpdu_nr & 0x7F;
988 else
989 fragment = true;
990 is_extended = false;
991 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
992 break;
994 /* extended DT with 2 octets of OSI or of ATN Extended Checksum */
995 case LI_EXTENDED_DT_WITH_CHECKSUM :
996 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM &&
997 tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16)
998 return -1;
999 /* FALLTHROUGH */
1001 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1002 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1003 if (tpdu_nr & 0x80000000)
1004 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1005 else
1006 fragment = true;
1007 is_extended = true;
1008 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1009 break;
1011 /* normal DT with ATN Extended Checksum (4 octets)*/
1012 case LI_ATN_NORMAL_DT_WITH_CHECKSUM :
1013 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32)
1014 return -1;
1016 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1018 if (tpdu_nr & 0x80)
1019 tpdu_nr = tpdu_nr & 0x7F;
1020 else
1021 fragment = true;
1022 is_extended = false;
1023 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1024 break;
1026 /* extended DT with 4 octets ATN Extended Checksum */
1027 case LI_ATN_EXTENDED_DT_WITH_CHECKSUM:
1028 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32)
1029 return -1;
1031 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1032 if (tpdu_nr & 0x80000000)
1033 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1034 else
1035 fragment = true;
1036 is_extended = true;
1037 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1038 break;
1040 default : /* bad TPDU */
1041 return -1;
1042 } /* li */
1043 } /* cotp_decode_atn */
1045 pinfo->clnp_dstref = dst_ref;
1047 pinfo->fragmented = fragment;
1048 if (is_class_234) {
1049 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x",
1050 tpdu_nr, dst_ref);
1051 } else {
1052 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u)", tpdu_nr);
1055 if (tree) {
1056 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1057 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1058 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1060 offset += 1;
1062 if (tree) {
1063 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1065 offset += 1;
1066 li -= 1;
1068 if (is_class_234) {
1069 if (tree)
1070 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1071 offset += 2;
1072 li -= 2;
1073 } else if (tree) {
1074 ti = proto_tree_add_uint (cotp_tree, hf_cotp_destref, tvb, offset, 0,
1075 dst_ref);
1076 proto_item_set_generated (ti);
1079 if (is_extended) {
1080 if (tree) {
1081 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset,
1082 4, tpdu_nr);
1083 proto_tree_add_item(cotp_tree, hf_cotp_eot_extended, tvb, offset, 4,
1084 ENC_BIG_ENDIAN);
1086 offset += 4;
1087 li -= 4;
1088 } else {
1089 if (tree) {
1090 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
1091 tpdu_nr);
1092 proto_tree_add_item(cotp_tree, hf_cotp_eot, tvb, offset, 1,
1093 ENC_BIG_ENDIAN);
1095 offset += 1;
1096 li -= 1;
1099 if (tree)
1100 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
1101 offset += li;
1103 next_tvb = tvb_new_subset_remaining(tvb, offset);
1104 fragment_length = tvb_captured_length(next_tvb);
1105 if (fragment) {
1106 col_append_fstr(pinfo->cinfo, COL_INFO, " [COTP fragment, %u byte%s]",
1107 fragment_length, plurality(fragment_length, "", "s"));
1108 } else {
1109 col_append_str(pinfo->cinfo, COL_INFO, " EOT");
1112 if (cotp_reassemble) {
1114 * XXX - these sequence numbers are connection sequence number,
1115 * not segment sequence numbers - the first segment of a
1116 * segmented packet doesn't have a specific sequence number (e.g., 0
1117 * or 1), it has whatever the appropriate sequence number is for
1118 * it in the connection.
1120 * For now, we assume segments arrive in order, and just supply
1121 * the negation of the EOT flag as the "more flags" argument.
1122 * We should probably handle out-of-order packets separately,
1123 * so that we can deliver them in order even when *not*
1124 * reassembling.
1126 * Note also that TP0 has no sequence number, and relies on
1127 * the protocol atop which it runs to guarantee in-order delivery.
1129 fd_head = fragment_add_seq_next(&cotp_reassembly_table, next_tvb, 0, pinfo,
1130 dst_ref, NULL, fragment_length, fragment);
1131 if (fd_head && fd_head->next) {
1132 /* don't use -1 if fragment length is zero (throws Exception) */
1133 proto_tree_add_bytes_format(cotp_tree, hf_cotp_segment_data, tvb, offset, (fragment_length) ? -1 : 0,
1134 NULL, "COTP segment data (%u byte%s)", fragment_length,
1135 plurality(fragment_length, "", "s"));
1137 if (!fragment) {
1138 /* This is the last packet */
1139 next_tvb = process_reassembled_data (next_tvb, offset, pinfo,
1140 "Reassembled COTP", fd_head,
1141 &cotp_frag_items, NULL, tree);
1142 } else if (pinfo->num != fd_head->reassembled_in) {
1143 /* Add a "Reassembled in" link if not reassembled in this frame */
1144 proto_tree_add_uint(cotp_tree, *(cotp_frag_items.hf_reassembled_in),
1145 next_tvb, 0, 0, fd_head->reassembled_in);
1147 pinfo->fragmented = fragment;
1151 if (uses_inactive_subset) {
1152 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
1153 pinfo, tree, &hdtbl_entry, NULL)) {
1154 *subdissector_found = true;
1155 } else {
1156 /* Fill in other Dissectors using inactive subset here */
1157 call_data_dissector(next_tvb, pinfo, tree);
1159 } else {
1161 * We dissect payload if one of the following is true:
1163 * - Reassembly option for COTP in preferences is unchecked
1164 * - Reassembly option is checked and this packet is the last fragment
1166 if ((!cotp_reassemble) || ((cotp_reassemble) && (!fragment))) {
1167 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo,
1168 tree, &hdtbl_entry, NULL)) {
1169 *subdissector_found = true;
1170 } else {
1171 call_data_dissector(next_tvb, pinfo, tree);
1176 offset += tvb_captured_length_remaining(tvb, offset);
1177 /* we dissected all of the containing PDU */
1179 return offset;
1181 } /* ositp_decode_DT */
1183 static int ositp_decode_ED(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1184 packet_info *pinfo, proto_tree *tree,
1185 bool uses_inactive_subset,
1186 bool *subdissector_found)
1188 proto_tree *cotp_tree = NULL;
1189 proto_item *ti;
1190 bool is_extended;
1191 uint16_t dst_ref;
1192 unsigned tpdu_nr;
1193 tvbuff_t *next_tvb;
1194 unsigned tpdu_len;
1195 heur_dtbl_entry_t *hdtbl_entry;
1197 /* ED TPDUs have user data, so they run to the end of the containing PDU */
1198 tpdu_len = tvb_reported_length_remaining(tvb, offset);
1200 /* note: in the ATN the user is up to chose between 3 different checksums:
1201 * standard OSI, 2 or 4 octet extended checksum.
1202 * The differences for ED (as for DT) are that the TPDU headers may be
1203 * enlarged by 2 octets and that checksum related option codes and option
1204 * lengths are different. To not mess up the original OSI dissector LI
1205 * checking was implemented separately.
1207 * note: this could not be tested, because no sample was avail for expedited
1208 * data */
1209 if (!cotp_decode_atn) { /* non ATN, plain OSI*/
1210 /* ED TPDUs are never fragmented */
1212 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1213 (This means we may misdissect this if the packet is bad and
1214 contains other parameters.) */
1215 switch (li) {
1217 case LI_NORMAL_DT_WITH_CHECKSUM :
1218 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1219 return -1;
1220 /* FALLTHROUGH */
1222 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
1223 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1224 if (tpdu_nr & 0x80)
1225 tpdu_nr = tpdu_nr & 0x7F;
1226 else
1227 return -1;
1228 is_extended = false;
1229 break;
1231 case LI_EXTENDED_DT_WITH_CHECKSUM :
1232 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1233 return -1;
1234 /* FALLTHROUGH */
1236 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1237 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1238 if (tpdu_nr & 0x80000000)
1239 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1240 else
1241 return -1;
1242 is_extended = true;
1243 break;
1245 default : /* bad TPDU */
1246 return -1;
1247 } /* li */
1248 } else {
1249 /* check packet length indicators of ATN Expedited Data (ED) TPDU
1250 * note: use of checksum depends on the selected RER
1251 * (high:non-use medium:16-bit OSI/16-bit ext.ATN low:32-bit ext. ATN)
1253 * note: sole use of TP4 class in the ATN
1254 * note: normal/extended TPDU numbering is negociable */
1255 switch (li) {
1257 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
1258 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1259 if (tpdu_nr & 0x80)
1260 tpdu_nr = tpdu_nr & 0x7F;
1261 else
1262 return -1;
1263 is_extended = false;
1264 break;
1266 case LI_NORMAL_DT_WITH_CHECKSUM :
1267 if ((tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) &&
1268 (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16))
1269 return -1;
1271 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1272 if (tpdu_nr & 0x80)
1273 tpdu_nr = tpdu_nr & 0x7F;
1274 else
1275 return -1;
1276 is_extended = false;
1277 break;
1279 case LI_ATN_NORMAL_DT_WITH_CHECKSUM :
1280 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32)
1281 return -1;
1283 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1284 if (tpdu_nr & 0x80)
1285 tpdu_nr = tpdu_nr & 0x7F;
1286 else
1287 return -1;
1288 is_extended = false;
1289 break;
1291 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1292 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1293 if (tpdu_nr & 0x80000000)
1294 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1295 else
1296 return -1;
1297 is_extended = true;
1298 break;
1300 case LI_EXTENDED_DT_WITH_CHECKSUM :
1301 if ((tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) &&
1302 (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16))
1303 return -1;
1305 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1306 if (tpdu_nr & 0x80000000)
1307 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1308 else
1309 return -1;
1310 is_extended = true;
1311 break;
1313 case LI_ATN_EXTENDED_DT_WITH_CHECKSUM :
1314 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32)
1315 return -1;
1317 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1318 if (tpdu_nr & 0x80000000)
1319 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1320 else
1321 return -1;
1322 is_extended = true;
1323 break;
1325 default : /* bad TPDU */
1326 return -1;
1327 } /* li */
1328 } /* cotp_decode_atn */
1330 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1331 pinfo->clnp_dstref = dst_ref;
1333 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1334 tpdu_nr, dst_ref);
1336 if (tree) {
1337 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1338 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1339 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1341 offset += 1;
1343 if (tree) {
1344 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1346 offset += 1;
1347 li -= 1;
1349 if (tree)
1350 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1351 offset += 2;
1352 li -= 2;
1354 if (is_extended) {
1355 if (tree) {
1356 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset,
1357 4, tpdu_nr);
1359 offset += 4;
1360 li -= 4;
1361 } else {
1362 if (tree) {
1363 proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
1364 tpdu_nr);
1366 offset += 1;
1367 li -= 1;
1370 if (tree)
1371 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
1372 offset += li;
1375 * Tell subdissectors that this is in an ED packet?
1377 next_tvb = tvb_new_subset_remaining(tvb, offset);
1378 if (uses_inactive_subset) {
1379 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
1380 pinfo, tree, &hdtbl_entry, NULL)) {
1381 *subdissector_found = true;
1382 } else {
1383 /* Fill in other Dissectors using inactive subset here */
1384 call_data_dissector(next_tvb, pinfo, tree);
1386 } else {
1388 * ED TPDUs are never fragmented
1390 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo,
1391 tree, &hdtbl_entry, NULL)) {
1392 *subdissector_found = true;
1393 } else {
1394 call_data_dissector(next_tvb, pinfo, tree);
1398 offset += tvb_captured_length_remaining(tvb, offset);
1399 /* we dissected all of the containing PDU */
1401 return offset;
1403 } /* ositp_decode_ED */
1405 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1406 uint8_t cdt, packet_info *pinfo, proto_tree *tree)
1408 proto_tree *cotp_tree;
1409 proto_item *ti;
1410 proto_item *item = NULL;
1411 uint16_t dst_ref;
1412 unsigned tpdu_nr;
1413 uint16_t credit = 0;
1415 /* note: in the ATN the user is up to chose between 3 different checksums:
1416 * standard OSI, 2 or 4 octet extended checksum.
1417 * The difference for RJ is that the TPDU header may be enlarged by 2 octets
1418 * for checksum parameters are not going to be checked here */
1419 if (!cotp_decode_atn) { /* non ATN, plain OSI */
1420 switch(li) {
1421 case LI_NORMAL_RJ :
1422 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1423 break;
1424 case LI_EXTENDED_RJ :
1425 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1426 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1427 break;
1428 default :
1429 return -1;
1431 } else {
1432 switch(li) {
1433 /* normal with 2 octets of OSI or ATN checksum */
1434 case LI_NORMAL_RJ :
1435 /* with 4 octets of ATN checksum */
1436 case LI_ATN_NORMAL_RJ :
1437 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1438 break;
1439 /* extended with 2 octets of OSI or ATN checksum */
1440 case LI_EXTENDED_RJ :
1441 /* with 4 octets of ATN checksum */
1442 case LI_ATN_EXTENDED_RJ :
1443 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1444 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1445 break;
1446 default :
1447 return -1;
1451 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1452 pinfo->clnp_dstref = dst_ref;
1454 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1455 tpdu_nr, dst_ref);
1457 if (tree) {
1458 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1459 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1460 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1461 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1,
1462 tpdu);
1463 if (li == LI_NORMAL_RJ) {
1464 proto_tree_add_uint(cotp_tree, hf_cotp_credit_cdt, tvb, offset + 1, 1, cdt);
1466 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2,
1467 dst_ref);
1468 if (li == LI_NORMAL_RJ)
1469 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset + 4,
1470 1, tpdu_nr);
1471 else {
1472 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1473 offset + 4, 4, tpdu_nr);
1474 proto_tree_add_uint(cotp_tree, hf_cotp_credit, tvb, offset + 8, 2, credit);
1478 offset += li + 1;
1480 expert_add_info_format(pinfo, item, &ei_cotp_reject, "Reject(RJ): -> 0x%x", dst_ref);
1482 return offset;
1484 } /* ositp_decode_RJ */
1486 static int ositp_decode_CR_CC(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1487 packet_info *pinfo, proto_tree *tree,
1488 bool uses_inactive_subset,
1489 bool *subdissector_found)
1491 /* note: in the ATN the user is up to chose between 3 different checksums:
1492 * standard OSI, 2 or 4 octet extended checksum.
1493 * Nothing has to be done here, for all ATN specifics are handled in VP. */
1495 /* CC & CR decoding in the same function */
1497 proto_tree *cotp_tree = NULL;
1498 proto_item *ti;
1499 proto_item *item = NULL;
1500 uint16_t dst_ref, src_ref;
1501 uint8_t class_option;
1502 tvbuff_t *next_tvb;
1503 unsigned tpdu_len;
1504 heur_dtbl_entry_t *hdtbl_entry;
1505 static int * const class_options[] = {
1506 &hf_cotp_class,
1507 &hf_cotp_opts_extended_formats,
1508 &hf_cotp_opts_no_explicit_flow_control,
1509 NULL,
1512 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1514 class_option = tvb_get_uint8(tvb, offset + P_CLASS_OPTION);
1515 if (((class_option & 0xF0) >> 4) > 4) /* class 0..4 allowed */
1516 return -1;
1518 /* CR and CC TPDUs can have user data, so they run to the end of the
1519 * containing PDU */
1520 tpdu_len = tvb_reported_length_remaining(tvb, offset);
1522 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1523 pinfo->clnp_srcref = src_ref;
1524 pinfo->clnp_dstref = dst_ref;
1526 col_append_fstr(pinfo->cinfo, COL_INFO,
1527 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1528 (tpdu == CR_TPDU) ? "CR" : "CC", src_ref, dst_ref);
1530 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1531 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1532 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1533 offset += 1;
1535 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1536 offset += 1;
1537 li -= 1;
1539 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1540 offset += 2;
1541 li -= 2;
1543 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1544 offset += 2;
1545 li -= 2;
1547 /* expert info, but only if not encapsulated in TCP/SMB */
1548 /* XXX - the best way to detect seems to be if we have a port set */
1549 if (pinfo->destport == 0) {
1550 expert_add_info_format(pinfo, item, &ei_cotp_connection, "Connection %s: 0x%x -> 0x%x", tpdu == CR_TPDU ? "Request(CR)" : "Confirm(CC)", src_ref, dst_ref);
1553 proto_tree_add_bitmask_list(cotp_tree, tvb, offset, 1, class_options, ENC_NA);
1554 offset += 1;
1555 li -= 1;
1557 if (li > 0) {
1558 /* There's more data left, so we have the variable part.
1560 Microsoft's RDP hijacks the variable part of CR and CC PDUs
1561 for their own user data (RDP runs atop Class 0, which doesn't
1562 support user data).
1564 Try what heuristic dissectors we have. */
1565 next_tvb = tvb_new_subset_length(tvb, offset, li);
1566 if (dissector_try_heuristic((tpdu == CR_TPDU) ?
1567 cotp_cr_heur_subdissector_list :
1568 cotp_cc_heur_subdissector_list,
1569 next_tvb, pinfo, tree, &hdtbl_entry, NULL)) {
1570 /* A subdissector claimed this, so it really belongs to them. */
1571 *subdissector_found = true;
1572 } else {
1573 /* No heuristic dissector claimed it, so dissect it as a regular
1574 variable part. */
1575 ositp_decode_var_part(tvb, offset, li, class_option, tpdu_len, pinfo,
1576 cotp_tree);
1578 offset += li;
1582 * XXX - tell the subdissector that this is user data in a CR or
1583 * CC packet rather than a DT packet?
1585 if (tvb_captured_length_remaining(tvb, offset)) {
1586 next_tvb = tvb_new_subset_remaining(tvb, offset);
1587 if (!uses_inactive_subset){
1588 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo,
1589 tree, &hdtbl_entry, NULL)) {
1590 *subdissector_found = true;
1591 } else {
1592 call_data_dissector(next_tvb, pinfo, tree);
1595 else
1596 call_data_dissector( next_tvb, pinfo, tree);
1597 offset += tvb_captured_length_remaining(tvb, offset);
1598 /* we dissected all of the containing PDU */
1601 return offset;
1603 } /* ositp_decode_CR_CC */
1605 static int ositp_decode_DC(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1606 packet_info *pinfo, proto_tree *tree)
1608 proto_tree *cotp_tree = NULL;
1609 proto_item *ti;
1610 proto_item *item = NULL;
1611 uint16_t dst_ref, src_ref;
1612 unsigned tpdu_len;
1614 /* ATN may use checksums different from OSI */
1615 /* which may result in different TPDU header length. */
1616 if (!cotp_decode_atn) {
1617 if (li > LI_MAX_DC)
1618 return -1;
1619 } else {
1620 if (li > LI_ATN_MAX_DC)
1621 return -1;
1624 /* DC TPDUs have no user data, so the length indicator determines the
1625 * length */
1626 tpdu_len = li + 1;
1628 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1629 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1630 pinfo->clnp_dstref = dst_ref;
1631 pinfo->clnp_srcref = src_ref;
1633 col_append_fstr(pinfo->cinfo, COL_INFO,
1634 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x", src_ref, dst_ref);
1636 if (tree) {
1637 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1638 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1639 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1641 offset += 1;
1643 if (tree) {
1644 item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1646 offset += 1;
1647 li -= 1;
1649 if (tree)
1650 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1651 offset += 2;
1652 li -= 2;
1654 if (tree)
1655 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1656 offset += 2;
1657 li -= 2;
1659 if (tree)
1660 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
1661 offset += li;
1663 expert_add_info_format(pinfo, item, &ei_cotp_disconnect_confirm, "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref);
1665 return offset;
1667 } /* ositp_decode_DC */
1669 static int ositp_decode_AK(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1670 uint8_t cdt, packet_info *pinfo, proto_tree *tree)
1672 proto_tree *cotp_tree = NULL;
1673 proto_item *ti;
1674 uint16_t dst_ref;
1675 unsigned tpdu_nr;
1676 uint16_t cdt_in_ak;
1677 unsigned tpdu_len;
1679 if (!cotp_decode_atn) {
1680 if (li > LI_MAX_AK)
1681 return -1;
1682 } else {
1683 if (li > LI_ATN_MAX_AK)
1684 return -1;
1687 /* AK TPDUs have no user data, so the length indicator determines the
1688 * length */
1689 tpdu_len = li + 1;
1691 /* is_LI_NORMAL_AK() works for normal ATN AK's, */
1692 /* for the TPDU header size may be enlarged by 2 octets */
1693 if (is_LI_NORMAL_AK(li)) {
1695 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1696 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1697 pinfo->clnp_dstref = dst_ref;
1699 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1700 tpdu_nr, dst_ref);
1702 if (tree) {
1703 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1704 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1705 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1707 offset += 1;
1709 if (tree) {
1710 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1711 proto_tree_add_uint(cotp_tree, hf_cotp_credit_cdt, tvb, offset, 1, cdt);
1713 offset += 1;
1714 li -= 1;
1716 if (tree)
1717 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1718 offset += 2;
1719 li -= 2;
1721 if (tree) {
1722 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1723 tpdu_nr);
1725 offset += 1;
1726 li -= 1;
1728 if (tree)
1729 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
1730 offset += li;
1732 } else { /* extended format */
1734 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1735 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1736 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1737 pinfo->clnp_dstref = dst_ref;
1739 col_append_fstr(pinfo->cinfo, COL_INFO,
1740 "AK TPDU (%u) dst-ref: 0x%04x Credit: %u",
1741 tpdu_nr, dst_ref, cdt_in_ak);
1743 if (tree) {
1744 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1745 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1746 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1748 offset += 1;
1750 if (tree) {
1751 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1753 offset += 1;
1754 li -= 1;
1756 if (tree)
1757 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1758 offset += 2;
1759 li -= 2;
1761 if (tree) {
1762 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1763 offset, 4, tpdu_nr);
1765 offset += 4;
1766 li -= 4;
1768 if (tree) {
1769 proto_tree_add_uint(cotp_tree, hf_cotp_credit, tvb, offset, 2, cdt_in_ak);
1771 offset += 2;
1772 li -= 2;
1774 if (tree)
1775 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
1776 offset += li;
1778 } /* is_LI_NORMAL_AK */
1780 return offset;
1782 } /* ositp_decode_AK */
1784 static int ositp_decode_EA(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1785 packet_info *pinfo, proto_tree *tree)
1787 proto_tree *cotp_tree = NULL;
1788 proto_item *ti;
1789 bool is_extended;
1790 uint16_t dst_ref;
1791 unsigned tpdu_nr;
1792 unsigned tpdu_len;
1794 /* Due to different checksums in the ATN the TPDU header sizes
1795 * as well as the checksum parameters may be different than plain OSI EA
1796 * because these are heavily checked for EA these checks had to be
1797 * re-implemented.
1798 * note: this could not be tested, because no sample was avail for expedited
1799 * data */
1800 if (!cotp_decode_atn) {
1801 if (li > LI_MAX_EA)
1802 return -1;
1804 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1805 (This means we may misdissect this if the packet is bad and
1806 contains other parameters.) */
1807 switch (li) {
1809 case LI_NORMAL_EA_WITH_CHECKSUM :
1810 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1811 tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1812 return -1;
1813 /* FALLTHROUGH */
1815 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1816 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1817 is_extended = false;
1818 break;
1820 case LI_EXTENDED_EA_WITH_CHECKSUM :
1821 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1822 tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1823 return -1;
1824 /* FALLTHROUGH */
1826 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1827 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1828 is_extended = true;
1829 break;
1831 default : /* bad TPDU */
1832 return -1;
1833 } /* li */
1834 } else { /* cotp_decode_atn */
1835 /* check for ATN length: TPDU may be 2 octets longer due to checksum */
1836 if (li > LI_ATN_MAX_EA)
1837 return -1;
1839 switch (li) {
1841 /* extended TPDU numbering EA with no checksum */
1842 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1843 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1844 is_extended = false;
1845 break;
1847 /* normal TPDU numbering EA with 2 octets of OSI or ATN extended
1848 * checksum */
1849 case LI_NORMAL_EA_WITH_CHECKSUM :
1850 /* check checksum parameter (in VP) parameter code octet */
1851 if ((tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) &&
1852 (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16))
1853 return -1;
1855 /* check checksum parameter (in VP) length octet */
1856 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1857 return -1;
1859 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1860 is_extended = false;
1861 break;
1863 /* normal TPDU numbering EA with 4 octets of ATN extended checksum */
1864 case LI_ATN_NORMAL_EA_WITH_CHECKSUM :
1865 /* check checksum parameter (in VP) parameter code octet */
1866 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32)
1867 return -1;
1869 /* check checksum parameter (in VP) length octet */
1870 if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 4)
1871 return -1;
1873 tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234);
1874 is_extended = false;
1875 break;
1877 /* extended TPDU numbering EA with no checksum */
1878 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1879 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1880 is_extended = true;
1881 break;
1883 /* extended TPDU numbering EA with 2 octets of OSI or ATN extended
1884 * checksum */
1885 case LI_EXTENDED_EA_WITH_CHECKSUM :
1886 /* check checksum parameter (in VP) parameter code octet */
1887 if ((tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) &&
1888 (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16))
1889 return -1;
1891 /* check checksum parameter (in VP) length octet */
1892 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1893 return -1;
1895 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1896 is_extended = true;
1897 break;
1899 /* extended EA with 4 octets ATN extended checksum */
1900 case LI_ATN_EXTENDED_EA_WITH_CHECKSUM :
1901 /* check checksum parameter (in VP) parameter code octet */
1902 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32)
1903 return -1;
1905 /* check checksum parameter (in VP) length octet */
1906 if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1907 return -1;
1909 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1910 is_extended = true;
1911 break;
1913 default : /* bad TPDU */
1914 return -1;
1918 /* ER TPDUs have no user data, so the length indicator determines the
1919 * length */
1920 tpdu_len = li + 1;
1922 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1923 pinfo->clnp_dstref = dst_ref;
1925 col_append_fstr(pinfo->cinfo, COL_INFO, "EA TPDU (%u) dst-ref: 0x%04x",
1926 tpdu_nr, dst_ref);
1928 if (tree) {
1929 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
1930 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1931 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1933 offset += 1;
1935 if (tree) {
1936 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1938 offset += 1;
1939 li -= 1;
1941 if (tree)
1942 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1943 offset += 2;
1944 li -= 2;
1946 if (is_extended) {
1947 if (tree) {
1948 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1949 offset, 4, tpdu_nr);
1951 offset += 4;
1952 li -= 4;
1953 } else {
1954 if (tree) {
1955 proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1956 tpdu_nr);
1958 offset += 1;
1959 li -= 1;
1962 if (tree)
1963 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
1964 offset += li;
1966 return offset;
1968 } /* ositp_decode_EA */
1970 static const value_string cotp_reject_vals[] = {
1971 { 0, "Reason not specified" },
1972 { 1, "Invalid parameter code" },
1973 { 2, "Invalid TPDU type" },
1974 { 3, "Invalid parameter value" },
1975 { 0, NULL }
1978 static int ositp_decode_ER(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
1979 packet_info *pinfo, proto_tree *tree)
1981 proto_tree *cotp_tree = NULL;
1982 proto_item *ti;
1983 uint16_t dst_ref;
1984 uint8_t tpdu_len;
1986 /* ATN: except for modified LI checking nothing to be done here */
1987 if (!cotp_decode_atn) {
1988 if (li > LI_MAX_ER)
1989 return -1;
1990 } else {
1991 if (li > LI_ATN_MAX_ER)
1992 return -1;
1995 /* ER TPDUs have no user data, so the length indicator determines the
1996 * length */
1997 tpdu_len = li + 1;
1999 if(try_val_to_str(tvb_get_uint8(tvb, offset + P_REJECT_ER), cotp_reject_vals) == NULL)
2000 return -1;
2002 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
2003 pinfo->clnp_dstref = dst_ref;
2005 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
2007 if (tree) {
2008 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA);
2009 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
2010 proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
2011 proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu);
2012 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2,
2013 dst_ref);
2014 proto_tree_add_item(cotp_tree, hf_cotp_reject_cause, tvb, offset + 4, 1, ENC_NA);
2016 offset += 5;
2017 li -= 4;
2019 if (tree)
2020 ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree);
2021 offset += li;
2023 return offset;
2025 } /* ositp_decode_ER */
2027 static int ositp_decode_UD(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu,
2028 packet_info *pinfo, proto_tree *tree,
2029 bool *subdissector_found)
2031 proto_item *ti;
2032 proto_tree *cltp_tree = NULL;
2033 tvbuff_t *next_tvb;
2034 unsigned tpdu_len;
2035 heur_dtbl_entry_t *hdtbl_entry;
2037 /* UD TPDUs have user data, so they run to the end of the containing PDU */
2038 tpdu_len = tvb_reported_length_remaining(tvb, offset);
2040 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
2042 if (tree) {
2043 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, ENC_NA);
2044 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
2045 proto_tree_add_uint(cltp_tree, hf_cltp_li, tvb, offset, 1,li);
2047 offset += 1;
2049 if (tree) {
2050 proto_tree_add_uint(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu);
2052 offset += 1;
2053 li -= 1;
2055 if (tree)
2056 ositp_decode_var_part(tvb, offset, li, 0, tpdu_len, pinfo, cltp_tree);
2057 offset += li;
2059 next_tvb = tvb_new_subset_remaining(tvb, offset);
2061 if (dissector_try_heuristic(cltp_heur_subdissector_list, next_tvb,
2062 pinfo, tree, &hdtbl_entry, NULL)) {
2063 *subdissector_found = true;
2064 } else {
2065 call_data_dissector(next_tvb, pinfo, tree);
2069 /*call_data_dissector(next_tvb, pinfo, tree); */
2071 offset += tvb_captured_length_remaining(tvb, offset);
2072 /* we dissected all of the containing PDU */
2074 return offset;
2076 } /* ositp_decode_UD */
2078 /* Returns the offset past the last valid COTP or CLTP PDU if we found
2079 at least one valid COTP or CLTP PDU, 0 otherwise.
2081 There doesn't seem to be any way in which the OSI network layer protocol
2082 distinguishes between COTP and CLTP, but the first two octets of both
2083 protocols' headers mean the same thing - length and PDU type - and the
2084 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
2085 both of them here. */
2086 static int dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
2087 proto_tree *tree,
2088 bool uses_inactive_subset)
2090 int offset = 0;
2091 uint8_t li, tpdu, cdt;
2092 bool first_tpdu = true;
2093 int new_offset;
2094 bool found_ositp = false;
2095 bool is_cltp = false;
2096 bool subdissector_found = false;
2098 /* Initialize the COL_INFO field; each of the TPDUs will have its
2099 information appended. */
2100 col_clear(pinfo->cinfo, COL_INFO);
2102 while (tvb_offset_exists(tvb, offset)) {
2103 if (!first_tpdu) {
2104 col_append_str(pinfo->cinfo, COL_INFO, ", ");
2105 expert_add_info(pinfo, NULL, &ei_cotp_multiple_tpdus);
2106 /* adjust tvb and offset to the start of the current PDU */
2107 tvb = tvb_new_subset_remaining(tvb, offset);
2108 offset = 0 ;
2110 if ((li = tvb_get_uint8(tvb, offset + P_LI)) == 0) {
2111 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
2112 if (!first_tpdu)
2113 call_data_dissector( tvb_new_subset_remaining(tvb, offset),
2114 pinfo, tree);
2115 return found_ositp;
2118 tpdu = (tvb_get_uint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
2119 if (tpdu == UD_TPDU)
2120 pinfo->current_proto = "CLTP"; /* connectionless transport */
2121 cdt = tvb_get_uint8(tvb, offset + P_CDT) & 0x0F;
2123 switch (tpdu) {
2124 case CC_TPDU :
2125 case CR_TPDU :
2126 new_offset = ositp_decode_CR_CC(tvb, offset, li, tpdu, pinfo, tree,
2127 uses_inactive_subset, &subdissector_found);
2128 break;
2129 case DR_TPDU :
2130 new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
2131 break;
2132 case DT_TPDU :
2133 new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
2134 uses_inactive_subset, &subdissector_found);
2135 break;
2136 case ED_TPDU :
2137 new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree,
2138 uses_inactive_subset, &subdissector_found);
2139 break;
2140 case RJ_TPDU :
2141 new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
2142 break;
2143 case DC_TPDU :
2144 new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
2145 break;
2146 case AK_TPDU :
2147 new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
2148 break;
2149 case EA_TPDU :
2150 new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
2151 break;
2152 case ER_TPDU :
2153 new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
2154 break;
2155 case UD_TPDU :
2156 new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree,
2157 &subdissector_found);
2158 is_cltp = true;
2159 break;
2160 default :
2161 if (first_tpdu)
2162 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)",
2163 tpdu);
2164 new_offset = -1; /* bad PDU type */
2165 break;
2168 if (new_offset == -1) { /* incorrect TPDU */
2169 if (!first_tpdu)
2170 call_data_dissector( tvb_new_subset_remaining(tvb, offset),
2171 pinfo, tree);
2172 break;
2175 if (first_tpdu) {
2176 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
2177 is either COTP or CLTP. */
2178 if (!subdissector_found)
2179 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
2180 found_ositp = true;
2183 offset = new_offset;
2184 first_tpdu = false;
2186 return found_ositp ? offset : 0;
2187 } /* dissect_ositp_internal */
2189 static int dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2190 void *data _U_)
2192 return dissect_ositp_internal(tvb, pinfo, tree, false);
2195 static int dissect_ositp_inactive(tvbuff_t *tvb, packet_info *pinfo,
2196 proto_tree *tree, void *data _U_)
2198 return dissect_ositp_internal(tvb, pinfo, tree, true);
2201 static bool
2202 test_cltp_var_part(tvbuff_t *tvb)
2204 int offset = 0;
2205 uint8_t li;
2206 while (tvb_captured_length_remaining(tvb, offset)) {
2207 if (tvb_captured_length_remaining(tvb, offset) < 2) {
2208 return false;
2210 switch (tvb_get_uint8(tvb, offset++)) {
2211 /* These are the only 3 legal parameters for CLTP per RFC 1240 and X.234 */
2212 case VP_SRC_TSAP:
2213 case VP_DST_TSAP:
2214 case VP_CHECKSUM: // Not required as redundant with UDP checksum, per RFC 1240
2215 break;
2216 default:
2217 return false;
2219 li = tvb_get_uint8(tvb, offset++);
2220 if (li == 255) {
2221 return false;
2223 if (tvb_captured_length_remaining(tvb, offset) < li) {
2224 return false;
2226 offset += li;
2228 return true;
2231 static bool
2232 dissect_cltp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
2233 void *data)
2235 uint8_t li, tpdu, spdu;
2236 int offset = 0;
2238 /* RFC 1240: OSI Connectionless Transport Services on top of UDP
2239 * was made Historic by RFC 2556, which noted that "at this time
2240 * there do not seem to be any implementations" and recommended
2241 * TPKT (RFC 2126, ISO Transport Service on top of TCP) instead.
2244 /* First, check do we have at least 2 bytes (length + tpdu) */
2245 if (tvb_captured_length(tvb) < 2) {
2246 return false;
2249 li = tvb_get_uint8(tvb, offset++);
2251 /* LI must include TPDU, and 255 is reserved */
2252 if (li == 0 || li == 255) {
2253 return false;
2256 /* Is it OSI on top of the UDP? */
2257 tpdu = (tvb_get_uint8(tvb, offset++) & 0xF0) >> 4;
2258 if (tpdu != UD_TPDU) {
2259 return false;
2262 /* LI includes TPDU */
2263 li--;
2265 if (!test_cltp_var_part(tvb_new_subset_length(tvb, offset, li))) {
2266 return false;
2268 offset += li;
2270 /* Since R-GOOSE is the only known user of CLTP over UDP, just
2271 * check for that.
2274 /* Check do we have SPDU ID byte, too */
2275 if (tvb_captured_length_remaining(tvb, offset) < 1) {
2276 return false;
2279 /* And let's see if it is GOOSE SPDU */
2280 spdu = tvb_get_uint8(tvb, offset);
2281 if (spdu != 0xA1) {
2282 return false;
2285 dissect_ositp(tvb, pinfo, parent_tree, data);
2286 return true;
2289 static void
2290 cotp_reassemble_init(void)
2292 cotp_dst_ref = 0;
2295 void proto_register_cotp(void)
2297 static hf_register_info hf[] = {
2298 { &hf_cotp_li,
2299 { "Length", "cotp.li", FT_UINT8, BASE_DEC,
2300 NULL, 0x0, "Length Indicator, length of this header", HFILL}},
2301 { &hf_cotp_type,
2302 { "PDU Type", "cotp.type", FT_UINT8, BASE_HEX,
2303 VALS(cotp_tpdu_type_abbrev_vals), 0x0,
2304 "PDU Type - upper nibble of byte", HFILL}},
2305 { &hf_cotp_srcref,
2306 { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX,
2307 NULL, 0x0, "Source address reference", HFILL}},
2308 { &hf_cotp_destref,
2309 { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX,
2310 NULL, 0x0, "Destination address reference", HFILL}},
2311 { &hf_cotp_class,
2312 { "Class", "cotp.class", FT_UINT8, BASE_DEC, NULL,
2313 0xF0, "Transport protocol class", HFILL}},
2314 { &hf_cotp_opts_extended_formats,
2315 { "Extended formats", "cotp.opts.extended_formats", FT_BOOLEAN, 8,
2316 NULL, 0x02, "Use of extended formats in classes 2, 3, and 4", HFILL}},
2317 { &hf_cotp_opts_no_explicit_flow_control,
2318 { "No explicit flow control", "cotp.opts.no_explicit_flow_control",
2319 FT_BOOLEAN, 8, NULL, 0x01, "No explicit flow control in class 2",
2320 HFILL}},
2321 { &hf_cotp_tpdu_number,
2322 { "TPDU number", "cotp.tpdu-number", FT_UINT8, BASE_HEX,
2323 NULL, 0x7f, NULL, HFILL}},
2324 { &hf_cotp_tpdu_number_extended,
2325 { "TPDU number", "cotp.tpdu-number", FT_UINT32, BASE_HEX,
2326 NULL, 0x0 /* XXX - 0x7fff? */, NULL, HFILL}},
2327 { &hf_cotp_next_tpdu_number,
2328 { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT8, BASE_HEX,
2329 NULL, 0x0, NULL, HFILL}},
2330 { &hf_cotp_next_tpdu_number_extended,
2331 { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT32, BASE_HEX,
2332 NULL, 0x0, NULL, HFILL}},
2333 { &hf_cotp_eot,
2334 { "Last data unit", "cotp.eot", FT_BOOLEAN, 8,
2335 TFS(&tfs_yes_no), 0x80,
2336 "Is current TPDU the last data unit of a complete DT TPDU sequence "
2337 "(End of TSDU)?", HFILL}},
2338 { &hf_cotp_eot_extended,
2339 { "Last data unit", "cotp.eot", FT_BOOLEAN, 32,
2340 TFS(&tfs_yes_no), 0x80000000,
2341 "Is current TPDU the last data unit of a complete DT TPDU sequence "
2342 "(End of TSDU)?", HFILL}},
2343 { &hf_cotp_segment_overlap,
2344 { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE,
2345 NULL, 0x0, "Segment overlaps with other segments", HFILL }},
2346 { &hf_cotp_segment_overlap_conflict,
2347 { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict",
2348 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2349 "Overlapping segments contained conflicting data", HFILL }},
2350 { &hf_cotp_segment_multiple_tails,
2351 { "Multiple tail segments found", "cotp.segment.multipletails",
2352 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2353 "Several tails were found when reassembling the packet", HFILL }},
2354 { &hf_cotp_segment_too_long_segment,
2355 { "Segment too long", "cotp.segment.toolongsegment",
2356 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2357 "Segment contained data past end of packet", HFILL }},
2358 { &hf_cotp_segment_error,
2359 { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE,
2360 NULL, 0x0, "Reassembly error due to illegal segments", HFILL }},
2361 { &hf_cotp_segment_count,
2362 { "Segment count", "cotp.segment.count", FT_UINT32, BASE_DEC,
2363 NULL, 0x0, NULL, HFILL }},
2364 { &hf_cotp_segment,
2365 { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE,
2366 NULL, 0x0, NULL, HFILL }},
2367 { &hf_cotp_segments,
2368 { "COTP Segments", "cotp.segments", FT_NONE, BASE_NONE,
2369 NULL, 0x0, NULL, HFILL }},
2370 { &hf_cotp_reassembled_in,
2371 { "Reassembled COTP in frame", "cotp.reassembled_in",
2372 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2373 "This COTP packet is reassembled in this frame", HFILL }},
2374 { &hf_cotp_reassembled_length,
2375 { "Reassembled COTP length", "cotp.reassembled.length",
2376 FT_UINT32, BASE_DEC, NULL, 0x0,
2377 "The total length of the reassembled payload", HFILL }},
2378 /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as
2379 identifiers of unspecified type and length.
2380 Some implementations of COTP use printable strings, others use raw bytes.
2381 We always add both representations to the tree; one will always be hidden
2382 depending on the tsap display preference */
2383 { &hf_cotp_vp_src_tsap,
2384 { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE,
2385 NULL, 0x0, "Calling TSAP", HFILL }},
2386 { &hf_cotp_vp_src_tsap_bytes,
2387 { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE,
2388 NULL, 0x0, "Calling TSAP (bytes representation)", HFILL }},
2389 { &hf_cotp_vp_dst_tsap,
2390 { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE,
2391 NULL, 0x0, "Called TSAP", HFILL }},
2392 { &hf_cotp_vp_dst_tsap_bytes,
2393 { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE,
2394 NULL, 0x0, "Called TSAP (bytes representation)", HFILL }},
2395 /* Generated from convert_proto_tree_add_text.pl */
2396 { &hf_cotp_parameter_code, { "Parameter code", "cotp.parameter_code", FT_UINT8, BASE_HEX, VALS(tp_vpart_type_vals), 0x0, NULL, HFILL }},
2397 { &hf_cotp_parameter_length, { "Parameter length", "cotp.parameter_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2398 { &hf_cotp_parameter_value, { "Parameter value", "cotp.parameter_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2399 { &hf_cotp_atn_extended_checksum16, { "ATN extended checksum", "cotp.atn_extended_checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2400 { &hf_cotp_atn_extended_checksum32, { "ATN extended checksum", "cotp.atn_extended_checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2401 { &hf_cotp_atn_extended_checksum_status, { "ATN extended checksum Status", "cotp.atn_extended_checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
2402 { &hf_cotp_ack_time, { "Ack time (ms)", "cotp.ack_time", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2403 { &hf_cotp_res_error_rate_target_value, { "Residual error rate, target value", "cotp.res_error_rate.target_value", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2404 { &hf_cotp_res_error_rate_min_accept, { "Residual error rate, minimum acceptable", "cotp.res_error_rate.min_accept", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2405 { &hf_cotp_res_error_rate_tdsu, { "Residual error rate, TSDU size of interest", "cotp.res_error_rate.tdsu", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2406 { &hf_cotp_vp_priority, { "Priority", "cotp.vp_priority", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2407 { &hf_cotp_transit_delay_targ_calling_called, { "Transit delay, target value, calling-called (ms)", "cotp.transit_delay.targ_calling_called", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2408 { &hf_cotp_transit_delay_max_accept_calling_called, { "Transit delay, maximum acceptable, calling-called (ms)", "cotp.transit_delay.max_accept_calling_called", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2409 { &hf_cotp_transit_delay_targ_called_calling, { "Transit delay, target value, called-calling (ms)", "cotp.transit_delay.targ_called_calling", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2410 { &hf_cotp_transit_delay_max_accept_called_calling, { "Transit delay, maximum acceptable, called-calling (ms)", "cotp.transit_delay.max_accept_called_calling", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2411 { &hf_cotp_max_throughput_targ_calling_called, { "Maximum throughput, target value, calling-called (o/s)", "cotp.max_throughput.targ_calling_called", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2412 { &hf_cotp_max_throughput_min_accept_calling_called, { "Maximum throughput, minimum acceptable, calling-called (o/s)", "cotp.max_throughput.min_accept_calling_called", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2413 { &hf_cotp_max_throughput_targ_called_calling, { "Maximum throughput, target value, called-calling (o/s)", "cotp.max_throughput.targ_called_calling", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2414 { &hf_cotp_max_throughput_min_accept_called_calling, { "Maximum throughput, minimum acceptable, called-calling (o/s)", "cotp.max_throughput.min_accept_called_calling", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2415 { &hf_cotp_avg_throughput_targ_calling_called, { "Average throughput, target value, calling-called (o/s)", "cotp.avg_throughput.targ_calling_called", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2416 { &hf_cotp_avg_throughput_min_accept_calling_called, { "Average throughput, minimum acceptable, calling-called (o/s)", "cotp.avg_throughput.min_accept_calling_called", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2417 { &hf_cotp_avg_throughput_targ_called_calling, { "Average throughput, target value, called-calling (o/s)", "cotp.avg_throughput.targ_called_calling", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2418 { &hf_cotp_avg_throughput_min_accept_called_calling, { "Average throughput, minimum acceptable, called-calling (o/s)", "cotp.avg_throughput.min_accept_called_calling", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2419 { &hf_cotp_sequence_number, { "Sequence number", "cotp.sequence_number", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2420 { &hf_cotp_reassignment_time, { "Reassignment time (secs)", "cotp.reassignment_time", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2421 { &hf_cotp_lower_window_edge, { "Lower window edge", "cotp.lower_window_edge", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2422 { &hf_cotp_credit, { "Credit", "cotp.credit", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2423 { &hf_cotp_tpdu_size, { "TPDU size", "cotp.tpdu_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2424 { &hf_cotp_checksum, { "Checksum", "cotp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2425 { &hf_cotp_checksum_status, { "Checksum Status", "cotp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
2426 { &hf_cotp_vp_version_nr, { "Version", "cotp.vp_version_nr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2427 { &hf_cotp_network_expedited_data, { "Use of network expedited data", "cotp.network_expedited_data", FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x08, NULL, HFILL }},
2428 { &hf_cotp_vp_opt_sel_class1_use, { "Use", "cotp.vp_opt_sel_class1_use", FT_BOOLEAN, 8, TFS(&tfs_vp_opt_sel_class1_use), 0x04, NULL, HFILL }},
2429 { &hf_cotp_use_16_bit_checksum, { "16 bit checksum", "cotp.use_16_bit_checksum", FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x02, NULL, HFILL }},
2430 { &hf_cotp_transport_expedited_data_transfer, { "Transport expedited data transfer", "cotp.transport_expedited_data_transfer", FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x01, NULL, HFILL }},
2431 { &hf_cotp_preferred_maximum_tpdu_size, { "Preferred maximum TPDU size", "cotp.preferred_maximum_tpdu_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2432 { &hf_cotp_inactivity_timer, { "Inactivity timer (ms)", "cotp.inactivity_timer", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2433 { &hf_cotp_cause, { "Cause", "cotp.cause", FT_UINT8, BASE_DEC, VALS(cotp_cause_vals), 0x0, NULL, HFILL }},
2434 { &hf_cotp_segment_data, { "COTP segment data", "cotp.segment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2435 { &hf_cotp_credit_cdt, { "Credit", "cotp.credit", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2436 { &hf_cotp_reject_cause, { "Reject cause", "cotp.reject_cause", FT_UINT8, BASE_DEC, VALS(cotp_reject_vals), 0x0, NULL, HFILL }},
2438 static int *ett[] = {
2439 &ett_cotp,
2440 &ett_cotp_segment,
2441 &ett_cotp_segments
2443 static ei_register_info ei[] = {
2444 { &ei_cotp_disconnect_request, { "cotp.disconnect_request", PI_SEQUENCE, PI_CHAT, "Disconnect Request(DR)", EXPFILL }},
2445 { &ei_cotp_reject, { "cotp.reject", PI_SEQUENCE, PI_NOTE, "Reject(RJ)", EXPFILL }},
2446 { &ei_cotp_connection, { "cotp.connection", PI_SEQUENCE, PI_CHAT, "Connection", EXPFILL }},
2447 { &ei_cotp_disconnect_confirm, { "cotp.disconnect_confirm", PI_SEQUENCE, PI_CHAT, "Disconnect Confirm(DC)", EXPFILL }},
2448 { &ei_cotp_multiple_tpdus, { "cotp.multiple_tpdus", PI_SEQUENCE, PI_NOTE, "Multiple TPDUs in one packet", EXPFILL }},
2449 { &ei_cotp_preferred_maximum_tpdu_size, { "cotp.preferred_maximum_tpdu_size.invalid", PI_PROTOCOL, PI_WARN, "Preferred maximum TPDU size: bogus length", EXPFILL }},
2450 { &ei_cotp_atn_extended_checksum, { "cotp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
2451 { &ei_cotp_checksum, { "cotp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
2454 module_t *cotp_module;
2455 expert_module_t* expert_cotp;
2457 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2458 proto_register_field_array(proto_cotp, hf, array_length(hf));
2459 proto_register_subtree_array(ett, array_length(ett));
2460 expert_cotp = expert_register_protocol(proto_cotp);
2461 expert_register_field_array(expert_cotp, ei, array_length(ei));
2462 cotp_module = prefs_register_protocol(proto_cotp, NULL);
2464 prefs_register_bool_preference(cotp_module, "reassemble",
2465 "Reassemble segmented COTP datagrams",
2466 "Whether segmented COTP datagrams should be "
2467 "reassembled. To use this option, you must "
2468 "also enable \"Allow subdissectors to "
2469 "reassemble TCP streams\" in the TCP "
2470 "protocol settings.",
2471 &cotp_reassemble);
2473 prefs_register_enum_preference(cotp_module, "tsap_display",
2474 "Display TSAPs as strings or bytes",
2475 "How TSAPs should be displayed",
2476 &tsap_display, tsap_display_options, false);
2478 prefs_register_bool_preference(cotp_module, "decode_atn", "Decode ATN TPDUs",
2479 "Whether to decode OSI TPDUs with ATN "
2480 "(Aeronautical Telecommunications Network) "
2481 "extensions. To use this option, you must "
2482 "also enable \"Always try to decode NSDU as "
2483 "transport PDUs\" in the CLNP protocol "
2484 "settings.", &cotp_decode_atn);
2486 /* For handling protocols hijacking the variable part of CR or CC PDUs */
2487 cotp_cr_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_cr", "COTP CR (Connect Request) payload", proto_cotp);
2488 cotp_cc_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_cc", "COTP CC (Connect Confirm) payload", proto_cotp);
2490 /* subdissector code in inactive subset */
2491 cotp_is_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_is", "COTP IS (Inactive Subset) payload", proto_cotp);
2493 /* other COTP/ISO 8473 subdissectors */
2494 cotp_heur_subdissector_list = register_heur_dissector_list_with_description("cotp", "COTP DT (Data) payload", proto_cotp);
2496 /* XXX - what about CLTP and proto_cltp? */
2497 ositp_handle = register_dissector("ositp", dissect_ositp, proto_cotp);
2498 register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp);
2500 register_init_routine(cotp_reassemble_init);
2502 * XXX - this is a connection-oriented transport-layer protocol,
2503 * so we should probably use more than just network-layer
2504 * endpoint addresses to match segments together, but the functions
2505 * in addresses_ports_reassembly_table_functions do matching based
2506 * on port numbers, so they won't let us ensure that segments from
2507 * different connections don't get assembled together.
2509 reassembly_table_register(&cotp_reassembly_table,
2510 &addresses_reassembly_table_functions);
2513 void proto_register_cltp(void)
2515 static hf_register_info hf[] = {
2516 { &hf_cltp_li,
2517 { "Length", "cltp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
2518 "Length Indicator, length of this header", HFILL}},
2519 { &hf_cltp_type,
2520 { "PDU Type", "cltp.type", FT_UINT8, BASE_HEX,
2521 VALS(cltp_tpdu_type_abbrev_vals), 0x0, NULL, HFILL}}
2523 static int *ett[] = {
2524 &ett_cltp
2527 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2528 proto_register_field_array(proto_cltp, hf, array_length(hf));
2529 proto_register_subtree_array(ett, array_length(ett));
2531 cltp_heur_subdissector_list = register_heur_dissector_list_with_description("cltp", "CLTP data atop CLNP", proto_cltp);
2534 void
2535 proto_reg_handoff_cotp(void)
2537 dissector_add_uint("ip.proto", IP_PROTO_TP, ositp_handle);
2539 rdp_cr_handle = find_dissector("rdp_cr");
2540 rdp_cc_handle = find_dissector("rdp_cc");
2542 proto_clnp = proto_get_id_by_filter_name("clnp");
2544 /* Actual implementations of R-GOOSE seem to use UDP port 102, registered
2545 * for ISO-TSAP, cf. TPKT. Perhaps we should just register ositp_handle
2546 * to UDP port 102 instead of having a heuristic dissector?
2548 heur_dissector_add("udp", dissect_cltp_heur, "CLTP over UDP",
2549 "cltp_udp", proto_cltp, HEURISTIC_ENABLE);
2553 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2555 * Local variables:
2556 * c-basic-offset: 2
2557 * tab-width: 8
2558 * indent-tabs-mode: nil
2559 * End:
2561 * vi: set shiftwidth=2 tabstop=8 expandtab:
2562 * :indentSize=2:tabSize=8:noTabs=true: