/src/wireshark/epan/dissectors/packet-ositp.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-ositp.c |
2 | | * Routines for ISO/OSI transport protocol (connection-oriented |
3 | | * and connectionless) packet disassembly |
4 | | * |
5 | | * Laurent Deniel <laurent.deniel@free.fr> |
6 | | * Ralf Schneider <Ralf.Schneider@t-online.de> |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
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> |
26 | | |
27 | | #include <wsutil/str_util.h> |
28 | | #include "packet-frame.h" |
29 | | #include "packet-osi.h" |
30 | | |
31 | | void proto_register_cotp(void); |
32 | | void proto_register_cltp(void); |
33 | | void proto_reg_handoff_cotp(void); |
34 | | |
35 | | /* protocols and fields */ |
36 | | |
37 | | static int proto_clnp; |
38 | | |
39 | | static int proto_cotp; |
40 | | static int ett_cotp; |
41 | | static int ett_cotp_segments; |
42 | | static int ett_cotp_segment; |
43 | | |
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; |
99 | | |
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; |
110 | | |
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; |
119 | | |
120 | | |
121 | | static int proto_cltp; |
122 | | static int ett_cltp; |
123 | | |
124 | | static int hf_cltp_li; |
125 | | static int hf_cltp_type; |
126 | | |
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" |
143 | | }; |
144 | | |
145 | | static dissector_handle_t rdp_cr_handle; |
146 | | static dissector_handle_t rdp_cc_handle; |
147 | | static dissector_handle_t ositp_handle; |
148 | | |
149 | | |
150 | | /* |
151 | | * ISO8073 OSI COTP definition |
152 | | * See http://standards.iso.org/ittf/PubliclyAvailableStandards/index.html |
153 | | * (or RFC905 for historic, and now-outdated information) |
154 | | */ |
155 | | |
156 | | /* don't use specific TPDU types to avoid alignment problems & copy overhead */ |
157 | | |
158 | | /* TPDU definition */ |
159 | | |
160 | 150 | #define ED_TPDU 0x1 /* COTP */ |
161 | 164 | #define EA_TPDU 0x2 /* COTP */ |
162 | 9.46k | #define UD_TPDU 0x4 /* CLTP */ |
163 | 63 | #define RJ_TPDU 0x5 /* COTP */ |
164 | 78 | #define AK_TPDU 0x6 /* COTP */ |
165 | 33 | #define ER_TPDU 0x7 /* COTP */ |
166 | 128 | #define DR_TPDU 0x8 /* COTP */ |
167 | 48 | #define DC_TPDU 0xC /* COTP */ |
168 | 183 | #define CC_TPDU 0xD /* COTP */ |
169 | 1.23k | #define CR_TPDU 0xE /* COTP */ |
170 | 6.28k | #define DT_TPDU 0xF /* COTP */ |
171 | | |
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 } |
184 | | }; |
185 | | |
186 | | static const value_string cltp_tpdu_type_abbrev_vals[] = { |
187 | | { UD_TPDU, "UD" }, |
188 | | { 0, NULL } |
189 | | }; |
190 | | |
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} |
199 | | }; |
200 | | #endif |
201 | | |
202 | | /* field position */ |
203 | | |
204 | 8.34k | #define P_LI 0 |
205 | 8.10k | #define P_TPDU 1 |
206 | 8.10k | #define P_CDT 1 |
207 | 1.36k | #define P_DST_REF 2 |
208 | 493 | #define P_SRC_REF 4 |
209 | 5.37k | #define P_TPDU_NR_0_1 2 |
210 | 948 | #define P_TPDU_NR_234 4 |
211 | 72 | #define P_VAR_PART_NDT 5 |
212 | 34 | #define P_VAR_PART_EDT 8 |
213 | | #define P_VAR_PART_DC 6 |
214 | 19 | #define P_CDT_IN_AK 8 |
215 | 2 | #define P_CDT_IN_RJ 8 |
216 | 24 | #define P_REJECT_ER 4 |
217 | 83 | #define P_REASON_IN_DR 6 |
218 | 378 | #define P_CLASS_OPTION 6 |
219 | | |
220 | | /* |
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. |
224 | | */ |
225 | | |
226 | 11.6k | #define LI_NORMAL_DT_CLASS_01 2 |
227 | 731 | #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4 |
228 | 64 | #define LI_NORMAL_DT_WITH_CHECKSUM (LI_NORMAL_DT_WITHOUT_CHECKSUM+4) |
229 | 182 | #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7 |
230 | 20 | #define LI_EXTENDED_DT_WITH_CHECKSUM (LI_EXTENDED_DT_WITHOUT_CHECKSUM+4) |
231 | 16 | #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4 |
232 | 8 | #define LI_NORMAL_EA_WITH_CHECKSUM (LI_NORMAL_EA_WITHOUT_CHECKSUM+4) |
233 | 49 | #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7 |
234 | 14 | #define LI_EXTENDED_EA_WITH_CHECKSUM (LI_EXTENDED_EA_WITHOUT_CHECKSUM+4) |
235 | 50 | #define LI_NORMAL_RJ 4 |
236 | 2 | #define LI_EXTENDED_RJ 9 |
237 | 128 | #define LI_MIN_DR 6 |
238 | 48 | #define LI_MAX_DC 9 |
239 | 78 | #define LI_MAX_AK 27 |
240 | 164 | #define LI_MAX_EA 11 |
241 | 33 | #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 | 58 | #define is_LI_NORMAL_AK(p) ((p & 0x01) == 0) |
246 | | |
247 | | /* |
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. |
253 | | */ |
254 | 0 | #define LI_ATN_NORMAL_DT_WITH_CHECKSUM (LI_NORMAL_DT_WITH_CHECKSUM+2) |
255 | 0 | #define LI_ATN_EXTENDED_DT_WITH_CHECKSUM (LI_EXTENDED_DT_WITH_CHECKSUM+2) |
256 | 0 | #define LI_ATN_NORMAL_EA_WITH_CHECKSUM (LI_NORMAL_EA_WITH_CHECKSUM+2) |
257 | 0 | #define LI_ATN_EXTENDED_EA_WITH_CHECKSUM (LI_EXTENDED_EA_WITH_CHECKSUM+2) |
258 | 0 | #define LI_ATN_NORMAL_RJ (LI_NORMAL_RJ+2) |
259 | 0 | #define LI_ATN_EXTENDED_RJ (LI_EXTENDED_RJ+2) |
260 | 0 | #define LI_ATN_MAX_DC (LI_MAX_DC+2) |
261 | 0 | #define LI_ATN_MAX_AK (LI_MAX_AK+2+1) /* +1 for padding? */ |
262 | 0 | #define LI_ATN_MAX_EA (LI_MAX_EA+2) |
263 | 0 | #define LI_ATN_MAX_ER (LI_MAX_ER+2) |
264 | | |
265 | | /* variant part */ |
266 | | |
267 | 24 | #define VP_ACK_TIME 0x85 |
268 | 74 | #define VP_RES_ERROR 0x86 |
269 | 28 | #define VP_PRIORITY 0x87 |
270 | 77 | #define VP_TRANSIT_DEL 0x88 |
271 | 26 | #define VP_THROUGHPUT 0x89 |
272 | 9 | #define VP_SEQ_NR 0x8A /* in AK */ |
273 | 8 | #define VP_REASSIGNMENT 0x8B |
274 | 87 | #define VP_FLOW_CNTL 0x8C /* in AK */ |
275 | 16 | #define VP_TPDU_SIZE 0xC0 |
276 | 45 | #define VP_SRC_TSAP 0xC1 /* in CR/CC */ |
277 | 22 | #define VP_DST_TSAP 0xC2 |
278 | 163 | #define VP_CHECKSUM 0xC3 |
279 | 9 | #define VP_VERSION_NR 0xC4 |
280 | 0 | #define VP_PROTECTION 0xC5 |
281 | 9 | #define VP_OPT_SEL 0xC6 |
282 | 0 | #define VP_PROTO_CLASS 0xC7 |
283 | 0 | #define VP_CLEARING_INFO 0xE0 /* in DR */ |
284 | 21 | #define VP_PREF_MAX_TPDU_SIZE 0xF0 |
285 | 5 | #define VP_INACTIVITY_TIMER 0xF2 |
286 | | |
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 | 79 | #define VP_ATN_EC_32 0x08 /* 4 octet ATN Extended Transport Checksum parameter */ |
292 | 48 | #define VP_ATN_EC_16 0x09 /* 2 octet ATN Extended Transport Checksum parameter */ |
293 | | /* ATN end */ |
294 | | |
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 } |
318 | | }; |
319 | | |
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; |
324 | | |
325 | | /* global variables */ |
326 | | |
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; |
338 | | |
339 | | /* |
340 | | * Reassembly of COTP. |
341 | | */ |
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; |
346 | | |
347 | 124 | #define TSAP_DISPLAY_AUTO 0 |
348 | 124 | #define TSAP_DISPLAY_STRING 1 |
349 | | #define TSAP_DISPLAY_BYTES 2 |
350 | | |
351 | | /* options */ |
352 | | static bool cotp_reassemble = true; |
353 | | static int32_t tsap_display = TSAP_DISPLAY_AUTO; |
354 | | static bool cotp_decode_atn; |
355 | | |
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} |
361 | | }; |
362 | | |
363 | | /* function definitions */ |
364 | | |
365 | 90 | #define MAX_TSAP_LEN 32 |
366 | | |
367 | | static void cotp_frame_end(void) |
368 | 2.12k | { |
369 | 2.12k | 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. |
372 | | */ |
373 | 1.11k | cotp_dst_ref--; |
374 | 1.11k | } |
375 | 2.12k | cotp_frame_reset = true; |
376 | 2.12k | } |
377 | | |
378 | | static char *print_tsap(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int length) |
379 | 56 | { |
380 | 56 | const unsigned char *tsap = tvb_get_ptr(tvb, offset, length); |
381 | 56 | char *cur; |
382 | 56 | bool allprintable; |
383 | 56 | int idx = 0, returned_length; |
384 | | |
385 | 56 | cur=(char *)wmem_alloc(scope, MAX_TSAP_LEN * 2 + 3); |
386 | 56 | cur[0] = '\0'; |
387 | 56 | if (length <= 0 || length > MAX_TSAP_LEN) |
388 | 41 | snprintf(cur, MAX_TSAP_LEN * 2 + 3, "<unsupported TSAP length>"); |
389 | 15 | else { |
390 | 15 | allprintable = tvb_ascii_isprint(tvb, offset, length); |
391 | 15 | if (!allprintable) { |
392 | 13 | returned_length = snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x"); |
393 | 13 | idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1); |
394 | 13 | } |
395 | 121 | while (length != 0) { |
396 | 106 | if (allprintable) { |
397 | 4 | returned_length = snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, |
398 | 4 | "%c", *tsap ++); |
399 | 4 | idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1); |
400 | 102 | } else { |
401 | 102 | returned_length = snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, |
402 | 102 | "%02x", *tsap ++); |
403 | 102 | idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1); |
404 | 102 | } |
405 | 106 | length --; |
406 | 106 | } |
407 | 15 | } |
408 | 56 | return cur; |
409 | | |
410 | 56 | } /* print_tsap */ |
411 | | |
412 | | static const true_false_string tfs_vp_opt_sel_class1_use = { "Receipt confirmation", "Explicit AK variant" }; |
413 | | |
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) |
417 | 6.79k | { |
418 | 6.79k | uint8_t code, length; |
419 | 6.79k | uint8_t c1; |
420 | 6.79k | uint16_t s; |
421 | 6.79k | uint32_t offset_iso8073_checksum = 0; |
422 | 6.79k | int32_t i = 0; |
423 | 6.79k | uint8_t tmp_code = 0; |
424 | 6.79k | unsigned tmp_len = 0; |
425 | 6.79k | uint32_t pref_max_tpdu_size; |
426 | 6.79k | proto_item *hidden_item; |
427 | | |
428 | 9.17k | while (vp_length != 0) { |
429 | 2.90k | code = tvb_get_uint8(tvb, offset); |
430 | 2.90k | proto_tree_add_item(tree, hf_cotp_parameter_code, tvb, offset, 1, ENC_NA); |
431 | 2.90k | offset += 1; |
432 | 2.90k | vp_length -= 1; |
433 | | |
434 | 2.90k | if (vp_length == 0) |
435 | 128 | break; |
436 | 2.78k | length = tvb_get_uint8(tvb, offset); |
437 | 2.78k | proto_tree_add_item(tree, hf_cotp_parameter_length, tvb, offset, 1, ENC_NA); |
438 | 2.78k | offset += 1; |
439 | 2.78k | vp_length -= 1; |
440 | | |
441 | 2.78k | switch (code) { |
442 | | |
443 | 48 | case VP_ATN_EC_16 : /* ATN */ |
444 | 48 | if (cotp_decode_atn) { |
445 | 0 | 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 | 0 | if (!offset_iso8073_checksum) { |
450 | | /* search following parameters in VP part for ISO checksum */ |
451 | 0 | for (i = offset + length; i < vp_length;) { |
452 | 0 | tmp_code = tvb_get_uint8(tvb, i++); |
453 | 0 | tmp_len = tvb_get_uint8(tvb, i++); |
454 | 0 | if (tmp_code == VP_CHECKSUM) { |
455 | 0 | offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */ |
456 | 0 | break; |
457 | 0 | } |
458 | 0 | i += tmp_len; |
459 | 0 | } |
460 | 0 | } |
461 | 0 | sum = check_atn_ec_16(tvb, tpdu_len , offset, |
462 | 0 | offset_iso8073_checksum, |
463 | 0 | pinfo->dst.len, (const uint8_t *)pinfo->dst.data, |
464 | 0 | pinfo->src.len, (const uint8_t *)pinfo->src.data); |
465 | 0 | proto_tree_add_checksum(tree, tvb, offset, hf_cotp_atn_extended_checksum16, hf_cotp_atn_extended_checksum_status, &ei_cotp_atn_extended_checksum, |
466 | 0 | pinfo, sum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO); |
467 | 48 | } else { |
468 | 48 | proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>"); |
469 | 48 | } |
470 | 48 | offset += length; |
471 | 48 | vp_length -= length; |
472 | 48 | break; |
473 | | |
474 | 79 | case VP_ATN_EC_32 : /* ATN */ |
475 | 79 | if (cotp_decode_atn) { |
476 | 0 | 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 | 0 | if (!offset_iso8073_checksum) { |
481 | | /* search following parameters in VP part for ISO checksum */ |
482 | 0 | for (i = offset + length; i < vp_length;) { |
483 | 0 | tmp_code = tvb_get_uint8(tvb, i++); |
484 | 0 | tmp_len = tvb_get_uint8(tvb, i++); |
485 | 0 | if (tmp_code == VP_CHECKSUM) { |
486 | 0 | offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */ |
487 | 0 | break; |
488 | 0 | } |
489 | 0 | i += tmp_len; |
490 | 0 | } |
491 | 0 | } |
492 | 0 | sum = check_atn_ec_32(tvb, tpdu_len , offset, |
493 | 0 | offset_iso8073_checksum, |
494 | 0 | pinfo->dst.len, (const uint8_t *)pinfo->dst.data, |
495 | 0 | pinfo->src.len, (const uint8_t *)pinfo->src.data); |
496 | 0 | proto_tree_add_checksum(tree, tvb, offset, hf_cotp_atn_extended_checksum32, hf_cotp_atn_extended_checksum_status, &ei_cotp_atn_extended_checksum, |
497 | 0 | pinfo, sum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO); |
498 | 79 | } else { |
499 | 79 | proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>"); |
500 | 79 | } |
501 | 79 | offset += length; |
502 | 79 | vp_length -= length; |
503 | 79 | break; |
504 | | |
505 | 24 | case VP_ACK_TIME: |
506 | 24 | proto_tree_add_item(tree, hf_cotp_ack_time, tvb, offset, length, ENC_BIG_ENDIAN); |
507 | 24 | offset += length; |
508 | 24 | vp_length -= length; |
509 | 24 | break; |
510 | | |
511 | 74 | case VP_RES_ERROR: |
512 | 74 | s = tvb_get_uint8(tvb, offset); |
513 | 74 | proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_target_value, tvb, offset, 1, s, "10^%u", s); |
514 | 74 | offset += 1; |
515 | 74 | vp_length -= 1; |
516 | | |
517 | 74 | s = tvb_get_uint8(tvb, offset); |
518 | 74 | proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_min_accept, tvb, offset, 1, s, "10^%u", s); |
519 | 74 | offset += 1; |
520 | 74 | vp_length -= 1; |
521 | | |
522 | 74 | s = tvb_get_uint8(tvb, offset); |
523 | 74 | proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_tdsu, tvb, offset, 1, s, "2^%u", s); |
524 | 74 | offset += 1; |
525 | 74 | vp_length -= 1; |
526 | 74 | break; |
527 | | |
528 | 28 | case VP_PRIORITY: |
529 | 28 | proto_tree_add_item(tree, hf_cotp_vp_priority, tvb, offset, 2, ENC_BIG_ENDIAN); |
530 | 28 | offset += length; |
531 | 28 | vp_length -= length; |
532 | 28 | break; |
533 | | |
534 | 77 | case VP_TRANSIT_DEL: |
535 | 77 | proto_tree_add_item(tree, hf_cotp_transit_delay_targ_calling_called, tvb, offset, 2, ENC_BIG_ENDIAN); |
536 | 77 | offset += 2; |
537 | 77 | vp_length -= 2; |
538 | | |
539 | 77 | proto_tree_add_item(tree, hf_cotp_transit_delay_max_accept_calling_called, tvb, offset, 2, ENC_BIG_ENDIAN); |
540 | 77 | offset += 2; |
541 | 77 | vp_length -= 2; |
542 | | |
543 | 77 | proto_tree_add_item(tree, hf_cotp_transit_delay_targ_called_calling, tvb, offset, 2, ENC_BIG_ENDIAN); |
544 | 77 | offset += 2; |
545 | 77 | vp_length -= 2; |
546 | | |
547 | 77 | proto_tree_add_item(tree, hf_cotp_transit_delay_max_accept_called_calling, tvb, offset, 2, ENC_BIG_ENDIAN); |
548 | 77 | offset += 2; |
549 | 77 | vp_length -= 2; |
550 | 77 | break; |
551 | | |
552 | 26 | case VP_THROUGHPUT: |
553 | 26 | proto_tree_add_item(tree, hf_cotp_max_throughput_targ_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
554 | 26 | offset += 3; |
555 | 26 | length -= 3; |
556 | 26 | vp_length -= 3; |
557 | | |
558 | 26 | proto_tree_add_item(tree, hf_cotp_max_throughput_min_accept_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
559 | 26 | offset += 3; |
560 | 26 | length -= 3; |
561 | 26 | vp_length -= 3; |
562 | | |
563 | 26 | proto_tree_add_item(tree, hf_cotp_max_throughput_targ_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
564 | 26 | offset += 3; |
565 | 26 | length -= 3; |
566 | 26 | vp_length -= 3; |
567 | | |
568 | 26 | proto_tree_add_item(tree, hf_cotp_max_throughput_min_accept_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
569 | 26 | offset += 3; |
570 | 26 | length -= 3; |
571 | 26 | vp_length -= 3; |
572 | | |
573 | 26 | if (length != 0) { /* XXX - should be 0 or 12 */ |
574 | 24 | proto_tree_add_item(tree, hf_cotp_avg_throughput_targ_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
575 | 24 | offset += 3; |
576 | 24 | vp_length -= 3; |
577 | | |
578 | 24 | proto_tree_add_item(tree, hf_cotp_avg_throughput_min_accept_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
579 | 24 | offset += 3; |
580 | 24 | vp_length -= 3; |
581 | | |
582 | 24 | proto_tree_add_item(tree, hf_cotp_avg_throughput_targ_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
583 | 24 | offset += 3; |
584 | 24 | vp_length -= 3; |
585 | | |
586 | 24 | proto_tree_add_item(tree, hf_cotp_avg_throughput_min_accept_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
587 | 24 | offset += 3; |
588 | 24 | vp_length -= 3; |
589 | 24 | } |
590 | 26 | break; |
591 | | |
592 | 9 | case VP_SEQ_NR: |
593 | 9 | proto_tree_add_item(tree, hf_cotp_sequence_number, tvb, offset, 2, ENC_BIG_ENDIAN); |
594 | 9 | offset += length; |
595 | 9 | vp_length -= length; |
596 | 9 | break; |
597 | | |
598 | 8 | case VP_REASSIGNMENT: |
599 | 8 | proto_tree_add_item(tree, hf_cotp_reassignment_time, tvb, offset, 2, ENC_BIG_ENDIAN); |
600 | 8 | offset += length; |
601 | 8 | vp_length -= length; |
602 | 8 | break; |
603 | | |
604 | 87 | case VP_FLOW_CNTL: |
605 | 87 | proto_tree_add_item(tree, hf_cotp_lower_window_edge, tvb, offset, 4, ENC_BIG_ENDIAN); |
606 | 87 | offset += 4; |
607 | 87 | vp_length -= 4; |
608 | | |
609 | 87 | proto_tree_add_item(tree, hf_cotp_sequence_number, tvb, offset, 2, ENC_BIG_ENDIAN); |
610 | 87 | offset += 2; |
611 | 87 | vp_length -= 2; |
612 | | |
613 | 87 | proto_tree_add_item(tree, hf_cotp_credit, tvb, offset, 2, ENC_BIG_ENDIAN); |
614 | 87 | offset += 2; |
615 | 87 | vp_length -= 2; |
616 | | |
617 | 87 | break; |
618 | | |
619 | 16 | case VP_TPDU_SIZE: |
620 | 16 | c1 = tvb_get_uint8(tvb, offset) & 0x0F; |
621 | 16 | proto_tree_add_uint(tree, hf_cotp_tpdu_size, tvb, offset, 1, 1 << c1); |
622 | 16 | offset += length; |
623 | 16 | vp_length -= length; |
624 | 16 | break; |
625 | | |
626 | 43 | 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 | 43 | if (tsap_display==TSAP_DISPLAY_STRING || |
630 | 43 | (tsap_display==TSAP_DISPLAY_AUTO && |
631 | 43 | tvb_ascii_isprint(tvb, offset, length))) { |
632 | 21 | proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length, |
633 | 21 | print_tsap(pinfo->pool, tvb, offset, length)); |
634 | 21 | hidden_item = proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, |
635 | 21 | offset, length, ENC_NA); |
636 | 21 | proto_item_set_hidden(hidden_item); |
637 | 22 | } else { |
638 | 22 | hidden_item = proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, |
639 | 22 | offset, length, |
640 | 22 | print_tsap(pinfo->pool, tvb, offset, length)); |
641 | 22 | proto_item_set_hidden(hidden_item); |
642 | 22 | proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, |
643 | 22 | length, ENC_NA); |
644 | 22 | } |
645 | 43 | offset += length; |
646 | 43 | vp_length -= length; |
647 | 43 | break; |
648 | | |
649 | 19 | 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 | 19 | if (tsap_display==TSAP_DISPLAY_STRING || |
653 | 19 | (tsap_display==TSAP_DISPLAY_AUTO && |
654 | 19 | tvb_ascii_isprint(tvb, offset, length))) { |
655 | 3 | proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length, |
656 | 3 | print_tsap(pinfo->pool, tvb, offset, length)); |
657 | 3 | hidden_item = proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, |
658 | 3 | offset, length, ENC_NA); |
659 | 3 | proto_item_set_hidden(hidden_item); |
660 | 16 | } else { |
661 | 16 | hidden_item = proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, |
662 | 16 | offset, length, |
663 | 16 | print_tsap(pinfo->pool, tvb, offset, length)); |
664 | 16 | proto_item_set_hidden(hidden_item); |
665 | 16 | proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, |
666 | 16 | length, ENC_NA); |
667 | 16 | } |
668 | 19 | offset += length; |
669 | 19 | vp_length -= length; |
670 | 19 | break; |
671 | | |
672 | 30 | case VP_CHECKSUM: |
673 | 30 | offset_iso8073_checksum = offset; /* save ISO 8073 checksum offset for ATN extended checksum calculation */ |
674 | | |
675 | 30 | if (tvb_get_ntohs(tvb, offset) == 0) { |
676 | | /* No checksum present */ |
677 | 7 | 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 | 23 | } else { |
679 | 23 | uint32_t calc_c0 = 0, calc_c1 = 0; |
680 | | |
681 | 23 | if (osi_calc_checksum(tvb, 0, length, &calc_c0, &calc_c1)) { |
682 | | /* Successfully processed checksum, verify it */ |
683 | 21 | 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 | 21 | } else { |
685 | 2 | 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); |
686 | 2 | } |
687 | 23 | } |
688 | | |
689 | 30 | offset += length; |
690 | 30 | vp_length -= length; |
691 | 30 | break; |
692 | | |
693 | 9 | case VP_VERSION_NR: |
694 | 9 | proto_tree_add_item(tree, hf_cotp_vp_version_nr, tvb, offset, 1, ENC_NA); |
695 | 9 | offset += length; |
696 | 9 | vp_length -= length; |
697 | 9 | break; |
698 | | |
699 | 9 | case VP_OPT_SEL: |
700 | 9 | switch (class_option) { |
701 | | |
702 | 0 | case 1: |
703 | 0 | proto_tree_add_item(tree, hf_cotp_network_expedited_data, tvb, offset, 1, ENC_NA); |
704 | |
|
705 | 0 | proto_tree_add_item(tree, hf_cotp_vp_opt_sel_class1_use, tvb, offset, 1, ENC_NA); |
706 | 0 | break; |
707 | | |
708 | 3 | case 4: |
709 | 3 | proto_tree_add_item(tree, hf_cotp_use_16_bit_checksum, tvb, offset, 1, ENC_NA); |
710 | 3 | break; |
711 | 9 | } |
712 | | |
713 | 9 | proto_tree_add_item(tree, hf_cotp_transport_expedited_data_transfer, tvb, offset, 1, ENC_NA); |
714 | 9 | offset += length; |
715 | 9 | vp_length -= length; |
716 | 9 | break; |
717 | | |
718 | 21 | case VP_PREF_MAX_TPDU_SIZE: |
719 | 21 | switch (length) { |
720 | | |
721 | 1 | case 1: |
722 | 1 | pref_max_tpdu_size = tvb_get_uint8(tvb, offset); |
723 | 1 | break; |
724 | | |
725 | 0 | case 2: |
726 | 0 | pref_max_tpdu_size = tvb_get_ntohs(tvb, offset); |
727 | 0 | break; |
728 | | |
729 | 6 | case 3: |
730 | 6 | pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset); |
731 | 6 | break; |
732 | | |
733 | 0 | case 4: |
734 | 0 | pref_max_tpdu_size = tvb_get_ntohl(tvb, offset); |
735 | 0 | break; |
736 | | |
737 | 14 | default: |
738 | 14 | proto_tree_add_expert_format(tree, pinfo, &ei_cotp_preferred_maximum_tpdu_size, tvb, offset, length, |
739 | 14 | "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)", length); |
740 | 14 | return false; |
741 | 21 | } |
742 | 7 | proto_tree_add_uint(tree, hf_cotp_preferred_maximum_tpdu_size, tvb, offset, length, pref_max_tpdu_size*128); |
743 | 7 | offset += length; |
744 | 7 | vp_length -= length; |
745 | 7 | break; |
746 | | |
747 | 5 | case VP_INACTIVITY_TIMER: |
748 | 5 | proto_tree_add_item(tree, hf_cotp_inactivity_timer, tvb, offset, length, ENC_BIG_ENDIAN); |
749 | 5 | offset += length; |
750 | 5 | vp_length -= length; |
751 | 5 | break; |
752 | | |
753 | 0 | case VP_PROTECTION: /* user-defined */ |
754 | 0 | case VP_PROTO_CLASS: /* todo */ |
755 | 0 | case VP_CLEARING_INFO: /* user-defined */ |
756 | 2.07k | default: /* unknown, no decoding */ |
757 | 2.07k | proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>"); |
758 | 2.07k | offset += length; |
759 | 2.07k | vp_length -= length; |
760 | 2.07k | break; |
761 | 2.78k | } |
762 | 2.78k | } /* while */ |
763 | | |
764 | 6.39k | return true; |
765 | 6.79k | } |
766 | | |
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 } |
782 | | }; |
783 | | |
784 | | static int ositp_decode_DR(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
785 | | packet_info *pinfo, proto_tree *tree) |
786 | 128 | { |
787 | 128 | proto_tree *cotp_tree = NULL; |
788 | 128 | proto_item *ti = NULL; |
789 | 128 | uint16_t dst_ref, src_ref; |
790 | 128 | unsigned char reason; |
791 | 128 | unsigned tpdu_len; |
792 | | |
793 | | /* ATN TPDU's tend to be larger than normal OSI, |
794 | | * so nothing to do with respect to LI checks */ |
795 | 128 | if (li < LI_MIN_DR) |
796 | 45 | return -1; |
797 | | |
798 | | /* DR TPDUs can have user data, so they run to the end of the containing PDU */ |
799 | 83 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
800 | | |
801 | 83 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
802 | | |
803 | 83 | src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); |
804 | | |
805 | 83 | reason = tvb_get_uint8(tvb, offset + P_REASON_IN_DR); |
806 | | |
807 | 83 | pinfo->clnp_dstref = dst_ref; |
808 | 83 | pinfo->clnp_srcref = src_ref; |
809 | | |
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 |
815 | | * |
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. |
819 | | */ |
820 | | /*pinfo->srcport = src_ref;*/ |
821 | | /*pinfo->destport = dst_ref;*/ |
822 | 83 | if (try_val_to_str(reason, cotp_cause_vals) == NULL) |
823 | 26 | return -1; |
824 | | |
825 | 57 | col_append_fstr(pinfo->cinfo, COL_INFO, |
826 | 57 | "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x", src_ref, dst_ref); |
827 | | |
828 | 57 | if (tree) { |
829 | 56 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
830 | 56 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
831 | 56 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
832 | 56 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu); |
833 | 56 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, |
834 | 56 | dst_ref); |
835 | 56 | proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset + 4, 2, |
836 | 56 | src_ref); |
837 | 56 | proto_tree_add_item(cotp_tree, hf_cotp_cause, tvb, offset + 6, 1, ENC_NA); |
838 | 56 | } |
839 | 57 | offset += 7; |
840 | 57 | li -= 6; |
841 | | |
842 | 57 | if (tree) |
843 | 56 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
844 | 57 | offset += li; |
845 | | |
846 | 57 | expert_add_info_format(pinfo, ti, &ei_cotp_disconnect_request, "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref); |
847 | | |
848 | | /* User data */ |
849 | 57 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
850 | 57 | offset += tvb_captured_length_remaining(tvb, offset); |
851 | | /* we dissected all of the containing PDU */ |
852 | | |
853 | 57 | return offset; |
854 | | |
855 | 83 | } /* ositp_decode_DR */ |
856 | | |
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) |
861 | 6.28k | { |
862 | 6.28k | proto_tree *cotp_tree = NULL; |
863 | 6.28k | proto_item *ti; |
864 | 6.28k | bool is_extended; |
865 | 6.28k | bool is_class_234; |
866 | 6.28k | uint32_t dst_ref; |
867 | 6.28k | uint32_t *prev_dst_ref; |
868 | 6.28k | unsigned tpdu_nr; |
869 | 6.28k | bool fragment = false; |
870 | 6.28k | uint32_t fragment_length = 0; |
871 | 6.28k | tvbuff_t *next_tvb; |
872 | 6.28k | fragment_head *fd_head; |
873 | 6.28k | conversation_t *conv; |
874 | 6.28k | unsigned tpdu_len; |
875 | 6.28k | heur_dtbl_entry_t *hdtbl_entry; |
876 | | |
877 | | /* DT TPDUs have user data, so they run to the end of the containing PDU */ |
878 | 6.28k | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
879 | | |
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 | 6.28k | is_class_234 = (li > LI_NORMAL_DT_CLASS_01); |
884 | | |
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 | 6.28k | 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.). |
895 | | |
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 | 6.28k | switch (li) { |
902 | | |
903 | 8 | case LI_NORMAL_DT_WITH_CHECKSUM : |
904 | 8 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) |
905 | 8 | return -1; |
906 | | /* FALLTHROUGH */ |
907 | | |
908 | 649 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
909 | 649 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
910 | 649 | if (tpdu_nr & 0x80) |
911 | 276 | tpdu_nr = tpdu_nr & 0x7F; |
912 | 373 | else |
913 | 373 | fragment = true; |
914 | 649 | is_extended = false; |
915 | 649 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
916 | 649 | break; |
917 | | |
918 | 19 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
919 | 19 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) |
920 | 19 | return -1; |
921 | | /* FALLTHROUGH */ |
922 | | |
923 | 125 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
924 | 125 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
925 | 125 | if (tpdu_nr & 0x80000000) |
926 | 53 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
927 | 72 | else |
928 | 72 | fragment = true; |
929 | 125 | is_extended = true; |
930 | 125 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
931 | 125 | break; |
932 | | |
933 | 5.37k | case LI_NORMAL_DT_CLASS_01 : |
934 | 5.37k | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_0_1); |
935 | 5.37k | if (tpdu_nr & 0x80) |
936 | 2.12k | tpdu_nr = tpdu_nr & 0x7F; |
937 | 3.24k | else |
938 | 3.24k | fragment = true; |
939 | 5.37k | is_extended = false; |
940 | 5.37k | prev_dst_ref = (uint32_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_clnp, 0); |
941 | 5.37k | if (!prev_dst_ref) { |
942 | | /* First COTP in frame - save previous dst_ref as offset */ |
943 | 1.16k | prev_dst_ref = wmem_new(wmem_file_scope(), uint32_t); |
944 | 1.16k | *prev_dst_ref = cotp_dst_ref; |
945 | 1.16k | p_add_proto_data(wmem_file_scope(), pinfo, proto_clnp, 0, prev_dst_ref); |
946 | 4.20k | } else if (cotp_frame_reset) { |
947 | 0 | cotp_dst_ref = *prev_dst_ref; |
948 | 0 | } |
949 | 5.37k | cotp_frame_reset = false; |
950 | 5.37k | cotp_last_fragment = fragment; |
951 | 5.37k | dst_ref = cotp_dst_ref; |
952 | 5.37k | conv = find_conversation_pinfo(pinfo, 0); |
953 | 5.37k | if (conv) { |
954 | | /* Found a conversation, also use index for the generated dst_ref */ |
955 | 437 | dst_ref += (conv->conv_index << 16); |
956 | 437 | } |
957 | 5.37k | if (!fragment) { |
958 | 2.12k | cotp_dst_ref++; |
959 | 2.12k | register_frame_end_routine(pinfo, cotp_frame_end); |
960 | 2.12k | } |
961 | 5.37k | break; |
962 | | |
963 | 118 | default : /* bad TPDU */ |
964 | 118 | return -1; |
965 | 6.28k | } /* li */ |
966 | 6.28k | } else { |
967 | | /* check ATN class4 TPDU's here */ |
968 | | |
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) |
972 | | * |
973 | | * note: sole use of TP4 class in the ATN |
974 | | * note: normal/extended TPDU numbering is negociable */ |
975 | 0 | switch (li) { |
976 | | |
977 | | /* normal DT with 2 octets of OSI or of ATN Extended Checksum */ |
978 | 0 | case LI_NORMAL_DT_WITH_CHECKSUM : |
979 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM && |
980 | 0 | tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16) |
981 | 0 | return -1; |
982 | | /* FALLTHROUGH */ |
983 | | |
984 | 0 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
985 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
986 | 0 | if (tpdu_nr & 0x80) |
987 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
988 | 0 | else |
989 | 0 | fragment = true; |
990 | 0 | is_extended = false; |
991 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
992 | 0 | break; |
993 | | |
994 | | /* extended DT with 2 octets of OSI or of ATN Extended Checksum */ |
995 | 0 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
996 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM && |
997 | 0 | tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16) |
998 | 0 | return -1; |
999 | | /* FALLTHROUGH */ |
1000 | | |
1001 | 0 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1002 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1003 | 0 | if (tpdu_nr & 0x80000000) |
1004 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1005 | 0 | else |
1006 | 0 | fragment = true; |
1007 | 0 | is_extended = true; |
1008 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1009 | 0 | break; |
1010 | | |
1011 | | /* normal DT with ATN Extended Checksum (4 octets)*/ |
1012 | 0 | case LI_ATN_NORMAL_DT_WITH_CHECKSUM : |
1013 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32) |
1014 | 0 | return -1; |
1015 | | |
1016 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1017 | |
|
1018 | 0 | if (tpdu_nr & 0x80) |
1019 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1020 | 0 | else |
1021 | 0 | fragment = true; |
1022 | 0 | is_extended = false; |
1023 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1024 | 0 | break; |
1025 | | |
1026 | | /* extended DT with 4 octets ATN Extended Checksum */ |
1027 | 0 | case LI_ATN_EXTENDED_DT_WITH_CHECKSUM: |
1028 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32) |
1029 | 0 | return -1; |
1030 | | |
1031 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1032 | 0 | if (tpdu_nr & 0x80000000) |
1033 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1034 | 0 | else |
1035 | 0 | fragment = true; |
1036 | 0 | is_extended = true; |
1037 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1038 | 0 | break; |
1039 | | |
1040 | 0 | default : /* bad TPDU */ |
1041 | 0 | return -1; |
1042 | 0 | } /* li */ |
1043 | 0 | } /* cotp_decode_atn */ |
1044 | | |
1045 | 6.13k | pinfo->clnp_dstref = dst_ref; |
1046 | | |
1047 | 6.13k | pinfo->fragmented = fragment; |
1048 | 6.13k | if (is_class_234) { |
1049 | 769 | col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x", |
1050 | 769 | tpdu_nr, dst_ref); |
1051 | 5.36k | } else { |
1052 | 5.36k | col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u)", tpdu_nr); |
1053 | 5.36k | } |
1054 | | |
1055 | 6.13k | if (tree) { |
1056 | 6.13k | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1057 | 6.13k | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1058 | 6.13k | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1059 | 6.13k | } |
1060 | 6.13k | offset += 1; |
1061 | | |
1062 | 6.13k | if (tree) { |
1063 | 6.13k | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1064 | 6.13k | } |
1065 | 6.13k | offset += 1; |
1066 | 6.13k | li -= 1; |
1067 | | |
1068 | 6.13k | if (is_class_234) { |
1069 | 769 | if (tree) |
1070 | 769 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1071 | 769 | offset += 2; |
1072 | 769 | li -= 2; |
1073 | 5.36k | } else if (tree) { |
1074 | 5.36k | ti = proto_tree_add_uint (cotp_tree, hf_cotp_destref, tvb, offset, 0, |
1075 | 5.36k | dst_ref); |
1076 | 5.36k | proto_item_set_generated (ti); |
1077 | 5.36k | } |
1078 | | |
1079 | 6.13k | if (is_extended) { |
1080 | 124 | if (tree) { |
1081 | 124 | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, |
1082 | 124 | 4, tpdu_nr); |
1083 | 124 | proto_tree_add_item(cotp_tree, hf_cotp_eot_extended, tvb, offset, 4, |
1084 | 124 | ENC_BIG_ENDIAN); |
1085 | 124 | } |
1086 | 124 | offset += 4; |
1087 | 124 | li -= 4; |
1088 | 6.00k | } else { |
1089 | 6.00k | if (tree) { |
1090 | 6.00k | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1, |
1091 | 6.00k | tpdu_nr); |
1092 | 6.00k | proto_tree_add_item(cotp_tree, hf_cotp_eot, tvb, offset, 1, |
1093 | 6.00k | ENC_BIG_ENDIAN); |
1094 | 6.00k | } |
1095 | 6.00k | offset += 1; |
1096 | 6.00k | li -= 1; |
1097 | 6.00k | } |
1098 | | |
1099 | 6.13k | if (tree) |
1100 | 6.13k | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1101 | 6.13k | offset += li; |
1102 | | |
1103 | 6.13k | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1104 | 6.13k | fragment_length = tvb_captured_length(next_tvb); |
1105 | 6.13k | if (fragment) { |
1106 | 3.67k | col_append_fstr(pinfo->cinfo, COL_INFO, " [COTP fragment, %u byte%s]", |
1107 | 3.67k | fragment_length, plurality(fragment_length, "", "s")); |
1108 | 3.67k | } else { |
1109 | 2.45k | col_append_str(pinfo->cinfo, COL_INFO, " EOT"); |
1110 | 2.45k | } |
1111 | | |
1112 | 6.13k | if (cotp_reassemble) { |
1113 | | /* |
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. |
1119 | | * |
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. |
1125 | | * |
1126 | | * Note also that TP0 has no sequence number, and relies on |
1127 | | * the protocol atop which it runs to guarantee in-order delivery. |
1128 | | */ |
1129 | 6.13k | fd_head = fragment_add_seq_next(&cotp_reassembly_table, next_tvb, 0, pinfo, |
1130 | 6.13k | dst_ref, NULL, fragment_length, fragment); |
1131 | 6.13k | if (fd_head && fd_head->next) { |
1132 | | /* don't use -1 if fragment length is zero (throws Exception) */ |
1133 | 1.11k | proto_tree_add_bytes_format(cotp_tree, hf_cotp_segment_data, tvb, offset, (fragment_length) ? -1 : 0, |
1134 | 1.11k | NULL, "COTP segment data (%u byte%s)", fragment_length, |
1135 | 1.11k | plurality(fragment_length, "", "s")); |
1136 | | |
1137 | 1.11k | if (!fragment) { |
1138 | | /* This is the last packet */ |
1139 | 1.11k | next_tvb = process_reassembled_data (next_tvb, offset, pinfo, |
1140 | 1.11k | "Reassembled COTP", fd_head, |
1141 | 1.11k | &cotp_frag_items, NULL, tree); |
1142 | 1.11k | } else if (pinfo->num != fd_head->reassembled_in) { |
1143 | | /* Add a "Reassembled in" link if not reassembled in this frame */ |
1144 | 0 | proto_tree_add_uint(cotp_tree, *(cotp_frag_items.hf_reassembled_in), |
1145 | 0 | next_tvb, 0, 0, fd_head->reassembled_in); |
1146 | 0 | } |
1147 | 1.11k | pinfo->fragmented = fragment; |
1148 | 1.11k | } |
1149 | 6.13k | } |
1150 | | |
1151 | 6.13k | if (uses_inactive_subset) { |
1152 | 5.89k | if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb, |
1153 | 5.89k | pinfo, tree, &hdtbl_entry, NULL)) { |
1154 | 1.42k | *subdissector_found = true; |
1155 | 4.47k | } else { |
1156 | | /* Fill in other Dissectors using inactive subset here */ |
1157 | 4.47k | call_data_dissector(next_tvb, pinfo, tree); |
1158 | 4.47k | } |
1159 | 5.89k | } else { |
1160 | | /* |
1161 | | * We dissect payload if one of the following is true: |
1162 | | * |
1163 | | * - Reassembly option for COTP in preferences is unchecked |
1164 | | * - Reassembly option is checked and this packet is the last fragment |
1165 | | */ |
1166 | 232 | if ((!cotp_reassemble) || ((cotp_reassemble) && (!fragment))) { |
1167 | 225 | if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo, |
1168 | 225 | tree, &hdtbl_entry, NULL)) { |
1169 | 52 | *subdissector_found = true; |
1170 | 173 | } else { |
1171 | 173 | call_data_dissector(next_tvb, pinfo, tree); |
1172 | 173 | } |
1173 | 225 | } |
1174 | 232 | } |
1175 | | |
1176 | 6.13k | offset += tvb_captured_length_remaining(tvb, offset); |
1177 | | /* we dissected all of the containing PDU */ |
1178 | | |
1179 | 6.13k | return offset; |
1180 | | |
1181 | 6.28k | } /* ositp_decode_DT */ |
1182 | | |
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) |
1187 | 150 | { |
1188 | 150 | proto_tree *cotp_tree = NULL; |
1189 | 150 | proto_item *ti; |
1190 | 150 | bool is_extended; |
1191 | 150 | uint16_t dst_ref; |
1192 | 150 | unsigned tpdu_nr; |
1193 | 150 | tvbuff_t *next_tvb; |
1194 | 150 | unsigned tpdu_len; |
1195 | 150 | heur_dtbl_entry_t *hdtbl_entry; |
1196 | | |
1197 | | /* ED TPDUs have user data, so they run to the end of the containing PDU */ |
1198 | 150 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
1199 | | |
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. |
1206 | | * |
1207 | | * note: this could not be tested, because no sample was avail for expedited |
1208 | | * data */ |
1209 | 150 | if (!cotp_decode_atn) { /* non ATN, plain OSI*/ |
1210 | | /* ED TPDUs are never fragmented */ |
1211 | | |
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 | 150 | switch (li) { |
1216 | | |
1217 | 56 | case LI_NORMAL_DT_WITH_CHECKSUM : |
1218 | 56 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) |
1219 | 56 | return -1; |
1220 | | /* FALLTHROUGH */ |
1221 | | |
1222 | 18 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
1223 | 18 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1224 | 18 | if (tpdu_nr & 0x80) |
1225 | 4 | tpdu_nr = tpdu_nr & 0x7F; |
1226 | 14 | else |
1227 | 14 | return -1; |
1228 | 4 | is_extended = false; |
1229 | 4 | break; |
1230 | | |
1231 | 1 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
1232 | 1 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) |
1233 | 1 | return -1; |
1234 | | /* FALLTHROUGH */ |
1235 | | |
1236 | 37 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1237 | 37 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1238 | 37 | if (tpdu_nr & 0x80000000) |
1239 | 33 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1240 | 4 | else |
1241 | 4 | return -1; |
1242 | 33 | is_extended = true; |
1243 | 33 | break; |
1244 | | |
1245 | 38 | default : /* bad TPDU */ |
1246 | 38 | return -1; |
1247 | 150 | } /* li */ |
1248 | 150 | } 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) |
1252 | | * |
1253 | | * note: sole use of TP4 class in the ATN |
1254 | | * note: normal/extended TPDU numbering is negociable */ |
1255 | 0 | switch (li) { |
1256 | | |
1257 | 0 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
1258 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1259 | 0 | if (tpdu_nr & 0x80) |
1260 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1261 | 0 | else |
1262 | 0 | return -1; |
1263 | 0 | is_extended = false; |
1264 | 0 | break; |
1265 | | |
1266 | 0 | case LI_NORMAL_DT_WITH_CHECKSUM : |
1267 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) && |
1268 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16)) |
1269 | 0 | return -1; |
1270 | | |
1271 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1272 | 0 | if (tpdu_nr & 0x80) |
1273 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1274 | 0 | else |
1275 | 0 | return -1; |
1276 | 0 | is_extended = false; |
1277 | 0 | break; |
1278 | | |
1279 | 0 | case LI_ATN_NORMAL_DT_WITH_CHECKSUM : |
1280 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32) |
1281 | 0 | return -1; |
1282 | | |
1283 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1284 | 0 | if (tpdu_nr & 0x80) |
1285 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1286 | 0 | else |
1287 | 0 | return -1; |
1288 | 0 | is_extended = false; |
1289 | 0 | break; |
1290 | | |
1291 | 0 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1292 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1293 | 0 | if (tpdu_nr & 0x80000000) |
1294 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1295 | 0 | else |
1296 | 0 | return -1; |
1297 | 0 | is_extended = true; |
1298 | 0 | break; |
1299 | | |
1300 | 0 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
1301 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) && |
1302 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16)) |
1303 | 0 | return -1; |
1304 | | |
1305 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1306 | 0 | if (tpdu_nr & 0x80000000) |
1307 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1308 | 0 | else |
1309 | 0 | return -1; |
1310 | 0 | is_extended = true; |
1311 | 0 | break; |
1312 | | |
1313 | 0 | case LI_ATN_EXTENDED_DT_WITH_CHECKSUM : |
1314 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32) |
1315 | 0 | return -1; |
1316 | | |
1317 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1318 | 0 | if (tpdu_nr & 0x80000000) |
1319 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1320 | 0 | else |
1321 | 0 | return -1; |
1322 | 0 | is_extended = true; |
1323 | 0 | break; |
1324 | | |
1325 | 0 | default : /* bad TPDU */ |
1326 | 0 | return -1; |
1327 | 0 | } /* li */ |
1328 | 0 | } /* cotp_decode_atn */ |
1329 | | |
1330 | 37 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1331 | 37 | pinfo->clnp_dstref = dst_ref; |
1332 | | |
1333 | 37 | col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x", |
1334 | 37 | tpdu_nr, dst_ref); |
1335 | | |
1336 | 37 | if (tree) { |
1337 | 37 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1338 | 37 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1339 | 37 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1340 | 37 | } |
1341 | 37 | offset += 1; |
1342 | | |
1343 | 37 | if (tree) { |
1344 | 37 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1345 | 37 | } |
1346 | 37 | offset += 1; |
1347 | 37 | li -= 1; |
1348 | | |
1349 | 37 | if (tree) |
1350 | 37 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1351 | 37 | offset += 2; |
1352 | 37 | li -= 2; |
1353 | | |
1354 | 37 | if (is_extended) { |
1355 | 33 | if (tree) { |
1356 | 33 | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, |
1357 | 33 | 4, tpdu_nr); |
1358 | 33 | } |
1359 | 33 | offset += 4; |
1360 | 33 | li -= 4; |
1361 | 33 | } else { |
1362 | 4 | if (tree) { |
1363 | 4 | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1, |
1364 | 4 | tpdu_nr); |
1365 | 4 | } |
1366 | 4 | offset += 1; |
1367 | 4 | li -= 1; |
1368 | 4 | } |
1369 | | |
1370 | 37 | if (tree) |
1371 | 37 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1372 | 37 | offset += li; |
1373 | | |
1374 | | /* |
1375 | | * Tell subdissectors that this is in an ED packet? |
1376 | | */ |
1377 | 37 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1378 | 37 | if (uses_inactive_subset) { |
1379 | 20 | if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb, |
1380 | 20 | pinfo, tree, &hdtbl_entry, NULL)) { |
1381 | 1 | *subdissector_found = true; |
1382 | 19 | } else { |
1383 | | /* Fill in other Dissectors using inactive subset here */ |
1384 | 19 | call_data_dissector(next_tvb, pinfo, tree); |
1385 | 19 | } |
1386 | 20 | } else { |
1387 | | /* |
1388 | | * ED TPDUs are never fragmented |
1389 | | */ |
1390 | 17 | if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo, |
1391 | 17 | tree, &hdtbl_entry, NULL)) { |
1392 | 2 | *subdissector_found = true; |
1393 | 15 | } else { |
1394 | 15 | call_data_dissector(next_tvb, pinfo, tree); |
1395 | 15 | } |
1396 | 17 | } |
1397 | | |
1398 | 37 | offset += tvb_captured_length_remaining(tvb, offset); |
1399 | | /* we dissected all of the containing PDU */ |
1400 | | |
1401 | 37 | return offset; |
1402 | | |
1403 | 150 | } /* ositp_decode_ED */ |
1404 | | |
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) |
1407 | 63 | { |
1408 | 63 | proto_tree *cotp_tree; |
1409 | 63 | proto_item *ti; |
1410 | 63 | proto_item *item = NULL; |
1411 | 63 | uint16_t dst_ref; |
1412 | 63 | unsigned tpdu_nr; |
1413 | 63 | uint16_t credit = 0; |
1414 | | |
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 | 63 | if (!cotp_decode_atn) { /* non ATN, plain OSI */ |
1420 | 63 | switch(li) { |
1421 | 16 | case LI_NORMAL_RJ : |
1422 | 16 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1423 | 16 | break; |
1424 | 2 | case LI_EXTENDED_RJ : |
1425 | 2 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1426 | 2 | credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ); |
1427 | 2 | break; |
1428 | 45 | default : |
1429 | 45 | return -1; |
1430 | 63 | } |
1431 | 63 | } else { |
1432 | 0 | switch(li) { |
1433 | | /* normal with 2 octets of OSI or ATN checksum */ |
1434 | 0 | case LI_NORMAL_RJ : |
1435 | | /* with 4 octets of ATN checksum */ |
1436 | 0 | case LI_ATN_NORMAL_RJ : |
1437 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1438 | 0 | break; |
1439 | | /* extended with 2 octets of OSI or ATN checksum */ |
1440 | 0 | case LI_EXTENDED_RJ : |
1441 | | /* with 4 octets of ATN checksum */ |
1442 | 0 | case LI_ATN_EXTENDED_RJ : |
1443 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1444 | 0 | credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ); |
1445 | 0 | break; |
1446 | 0 | default : |
1447 | 0 | return -1; |
1448 | 0 | } |
1449 | 0 | } |
1450 | | |
1451 | 17 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1452 | 17 | pinfo->clnp_dstref = dst_ref; |
1453 | | |
1454 | 17 | col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x", |
1455 | 17 | tpdu_nr, dst_ref); |
1456 | | |
1457 | 17 | if (tree) { |
1458 | 17 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1459 | 17 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1460 | 17 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1461 | 17 | item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, |
1462 | 17 | tpdu); |
1463 | 17 | if (li == LI_NORMAL_RJ) { |
1464 | 15 | proto_tree_add_uint(cotp_tree, hf_cotp_credit_cdt, tvb, offset + 1, 1, cdt); |
1465 | 15 | } |
1466 | 17 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, |
1467 | 17 | dst_ref); |
1468 | 17 | if (li == LI_NORMAL_RJ) |
1469 | 15 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset + 4, |
1470 | 15 | 1, tpdu_nr); |
1471 | 2 | else { |
1472 | 2 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb, |
1473 | 2 | offset + 4, 4, tpdu_nr); |
1474 | 2 | proto_tree_add_uint(cotp_tree, hf_cotp_credit, tvb, offset + 8, 2, credit); |
1475 | 2 | } |
1476 | 17 | } |
1477 | | |
1478 | 17 | offset += li + 1; |
1479 | | |
1480 | 17 | expert_add_info_format(pinfo, item, &ei_cotp_reject, "Reject(RJ): -> 0x%x", dst_ref); |
1481 | | |
1482 | 17 | return offset; |
1483 | | |
1484 | 63 | } /* ositp_decode_RJ */ |
1485 | | |
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) |
1490 | 378 | { |
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. */ |
1494 | | |
1495 | | /* CC & CR decoding in the same function */ |
1496 | | |
1497 | 378 | proto_tree *cotp_tree = NULL; |
1498 | 378 | proto_item *ti; |
1499 | 378 | proto_item *item = NULL; |
1500 | 378 | uint16_t dst_ref, src_ref; |
1501 | 378 | uint8_t class_option; |
1502 | 378 | tvbuff_t *next_tvb; |
1503 | 378 | unsigned tpdu_len; |
1504 | 378 | heur_dtbl_entry_t *hdtbl_entry; |
1505 | 378 | static int * const class_options[] = { |
1506 | 378 | &hf_cotp_class, |
1507 | 378 | &hf_cotp_opts_extended_formats, |
1508 | 378 | &hf_cotp_opts_no_explicit_flow_control, |
1509 | 378 | NULL, |
1510 | 378 | }; |
1511 | | |
1512 | 378 | src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); |
1513 | | |
1514 | 378 | class_option = tvb_get_uint8(tvb, offset + P_CLASS_OPTION); |
1515 | 378 | if (((class_option & 0xF0) >> 4) > 4) /* class 0..4 allowed */ |
1516 | 70 | return -1; |
1517 | | |
1518 | | /* CR and CC TPDUs can have user data, so they run to the end of the |
1519 | | * containing PDU */ |
1520 | 308 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
1521 | | |
1522 | 308 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1523 | 308 | pinfo->clnp_srcref = src_ref; |
1524 | 308 | pinfo->clnp_dstref = dst_ref; |
1525 | | |
1526 | 308 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1527 | 308 | "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x", |
1528 | 308 | (tpdu == CR_TPDU) ? "CR" : "CC", src_ref, dst_ref); |
1529 | | |
1530 | 308 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1531 | 308 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1532 | 308 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1533 | 308 | offset += 1; |
1534 | | |
1535 | 308 | item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1536 | 308 | offset += 1; |
1537 | 308 | li -= 1; |
1538 | | |
1539 | 308 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1540 | 308 | offset += 2; |
1541 | 308 | li -= 2; |
1542 | | |
1543 | 308 | proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref); |
1544 | 308 | offset += 2; |
1545 | 308 | li -= 2; |
1546 | | |
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 | 308 | if (pinfo->destport == 0) { |
1550 | 268 | 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); |
1551 | 268 | } |
1552 | | |
1553 | 308 | proto_tree_add_bitmask_list(cotp_tree, tvb, offset, 1, class_options, ENC_NA); |
1554 | 308 | offset += 1; |
1555 | 308 | li -= 1; |
1556 | | |
1557 | 308 | if (li > 0) { |
1558 | | /* There's more data left, so we have the variable part. |
1559 | | |
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). |
1563 | | |
1564 | | Try what heuristic dissectors we have. */ |
1565 | 278 | next_tvb = tvb_new_subset_length(tvb, offset, li); |
1566 | 278 | if (dissector_try_heuristic((tpdu == CR_TPDU) ? |
1567 | 167 | cotp_cr_heur_subdissector_list : |
1568 | 278 | cotp_cc_heur_subdissector_list, |
1569 | 278 | next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { |
1570 | | /* A subdissector claimed this, so it really belongs to them. */ |
1571 | 29 | *subdissector_found = true; |
1572 | 249 | } else { |
1573 | | /* No heuristic dissector claimed it, so dissect it as a regular |
1574 | | variable part. */ |
1575 | 249 | ositp_decode_var_part(tvb, offset, li, class_option, tpdu_len, pinfo, |
1576 | 249 | cotp_tree); |
1577 | 249 | } |
1578 | 278 | offset += li; |
1579 | 278 | } |
1580 | | |
1581 | | /* |
1582 | | * XXX - tell the subdissector that this is user data in a CR or |
1583 | | * CC packet rather than a DT packet? |
1584 | | */ |
1585 | 308 | if (tvb_captured_length_remaining(tvb, offset)) { |
1586 | 74 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1587 | 74 | if (!uses_inactive_subset){ |
1588 | 72 | if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo, |
1589 | 72 | tree, &hdtbl_entry, NULL)) { |
1590 | 19 | *subdissector_found = true; |
1591 | 53 | } else { |
1592 | 53 | call_data_dissector(next_tvb, pinfo, tree); |
1593 | 53 | } |
1594 | 72 | } |
1595 | 2 | else |
1596 | 2 | call_data_dissector( next_tvb, pinfo, tree); |
1597 | 74 | offset += tvb_captured_length_remaining(tvb, offset); |
1598 | | /* we dissected all of the containing PDU */ |
1599 | 74 | } |
1600 | | |
1601 | 308 | return offset; |
1602 | | |
1603 | 378 | } /* ositp_decode_CR_CC */ |
1604 | | |
1605 | | static int ositp_decode_DC(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1606 | | packet_info *pinfo, proto_tree *tree) |
1607 | 48 | { |
1608 | 48 | proto_tree *cotp_tree = NULL; |
1609 | 48 | proto_item *ti; |
1610 | 48 | proto_item *item = NULL; |
1611 | 48 | uint16_t dst_ref, src_ref; |
1612 | 48 | unsigned tpdu_len; |
1613 | | |
1614 | | /* ATN may use checksums different from OSI */ |
1615 | | /* which may result in different TPDU header length. */ |
1616 | 48 | if (!cotp_decode_atn) { |
1617 | 48 | if (li > LI_MAX_DC) |
1618 | 16 | return -1; |
1619 | 48 | } else { |
1620 | 0 | if (li > LI_ATN_MAX_DC) |
1621 | 0 | return -1; |
1622 | 0 | } |
1623 | | |
1624 | | /* DC TPDUs have no user data, so the length indicator determines the |
1625 | | * length */ |
1626 | 32 | tpdu_len = li + 1; |
1627 | | |
1628 | 32 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1629 | 32 | src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); |
1630 | 32 | pinfo->clnp_dstref = dst_ref; |
1631 | 32 | pinfo->clnp_srcref = src_ref; |
1632 | | |
1633 | 32 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1634 | 32 | "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x", src_ref, dst_ref); |
1635 | | |
1636 | 32 | if (tree) { |
1637 | 31 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1638 | 31 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1639 | 31 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1640 | 31 | } |
1641 | 32 | offset += 1; |
1642 | | |
1643 | 32 | if (tree) { |
1644 | 31 | item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1645 | 31 | } |
1646 | 32 | offset += 1; |
1647 | 32 | li -= 1; |
1648 | | |
1649 | 32 | if (tree) |
1650 | 31 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1651 | 32 | offset += 2; |
1652 | 32 | li -= 2; |
1653 | | |
1654 | 32 | if (tree) |
1655 | 31 | proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref); |
1656 | 32 | offset += 2; |
1657 | 32 | li -= 2; |
1658 | | |
1659 | 32 | if (tree) |
1660 | 31 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1661 | 32 | offset += li; |
1662 | | |
1663 | 32 | expert_add_info_format(pinfo, item, &ei_cotp_disconnect_confirm, "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref); |
1664 | | |
1665 | 32 | return offset; |
1666 | | |
1667 | 48 | } /* ositp_decode_DC */ |
1668 | | |
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) |
1671 | 78 | { |
1672 | 78 | proto_tree *cotp_tree = NULL; |
1673 | 78 | proto_item *ti; |
1674 | 78 | uint16_t dst_ref; |
1675 | 78 | unsigned tpdu_nr; |
1676 | 78 | uint16_t cdt_in_ak; |
1677 | 78 | unsigned tpdu_len; |
1678 | | |
1679 | 78 | if (!cotp_decode_atn) { |
1680 | 78 | if (li > LI_MAX_AK) |
1681 | 20 | return -1; |
1682 | 78 | } else { |
1683 | 0 | if (li > LI_ATN_MAX_AK) |
1684 | 0 | return -1; |
1685 | 0 | } |
1686 | | |
1687 | | /* AK TPDUs have no user data, so the length indicator determines the |
1688 | | * length */ |
1689 | 58 | tpdu_len = li + 1; |
1690 | | |
1691 | | /* is_LI_NORMAL_AK() works for normal ATN AK's, */ |
1692 | | /* for the TPDU header size may be enlarged by 2 octets */ |
1693 | 58 | if (is_LI_NORMAL_AK(li)) { |
1694 | | |
1695 | 39 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1696 | 39 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1697 | 39 | pinfo->clnp_dstref = dst_ref; |
1698 | | |
1699 | 39 | col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", |
1700 | 39 | tpdu_nr, dst_ref); |
1701 | | |
1702 | 39 | if (tree) { |
1703 | 38 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1704 | 38 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1705 | 38 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1706 | 38 | } |
1707 | 39 | offset += 1; |
1708 | | |
1709 | 39 | if (tree) { |
1710 | 38 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1711 | 38 | proto_tree_add_uint(cotp_tree, hf_cotp_credit_cdt, tvb, offset, 1, cdt); |
1712 | 38 | } |
1713 | 39 | offset += 1; |
1714 | 39 | li -= 1; |
1715 | | |
1716 | 39 | if (tree) |
1717 | 38 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1718 | 39 | offset += 2; |
1719 | 39 | li -= 2; |
1720 | | |
1721 | 39 | if (tree) { |
1722 | 38 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1, |
1723 | 38 | tpdu_nr); |
1724 | 38 | } |
1725 | 39 | offset += 1; |
1726 | 39 | li -= 1; |
1727 | | |
1728 | 39 | if (tree) |
1729 | 38 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1730 | 39 | offset += li; |
1731 | | |
1732 | 39 | } else { /* extended format */ |
1733 | | |
1734 | 19 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1735 | 19 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1736 | 19 | cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK); |
1737 | 19 | pinfo->clnp_dstref = dst_ref; |
1738 | | |
1739 | 19 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1740 | 19 | "AK TPDU (%u) dst-ref: 0x%04x Credit: %u", |
1741 | 19 | tpdu_nr, dst_ref, cdt_in_ak); |
1742 | | |
1743 | 19 | if (tree) { |
1744 | 19 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1745 | 19 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1746 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1747 | 19 | } |
1748 | 19 | offset += 1; |
1749 | | |
1750 | 19 | if (tree) { |
1751 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1752 | 19 | } |
1753 | 19 | offset += 1; |
1754 | 19 | li -= 1; |
1755 | | |
1756 | 19 | if (tree) |
1757 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1758 | 19 | offset += 2; |
1759 | 19 | li -= 2; |
1760 | | |
1761 | 19 | if (tree) { |
1762 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb, |
1763 | 19 | offset, 4, tpdu_nr); |
1764 | 19 | } |
1765 | 19 | offset += 4; |
1766 | 19 | li -= 4; |
1767 | | |
1768 | 19 | if (tree) { |
1769 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_credit, tvb, offset, 2, cdt_in_ak); |
1770 | 19 | } |
1771 | 19 | offset += 2; |
1772 | 19 | li -= 2; |
1773 | | |
1774 | 19 | if (tree) |
1775 | 19 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1776 | 19 | offset += li; |
1777 | | |
1778 | 19 | } /* is_LI_NORMAL_AK */ |
1779 | | |
1780 | 58 | return offset; |
1781 | | |
1782 | 78 | } /* ositp_decode_AK */ |
1783 | | |
1784 | | static int ositp_decode_EA(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1785 | | packet_info *pinfo, proto_tree *tree) |
1786 | 164 | { |
1787 | 164 | proto_tree *cotp_tree = NULL; |
1788 | 164 | proto_item *ti; |
1789 | 164 | bool is_extended; |
1790 | 164 | uint16_t dst_ref; |
1791 | 164 | unsigned tpdu_nr; |
1792 | 164 | unsigned tpdu_len; |
1793 | | |
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 | 164 | if (!cotp_decode_atn) { |
1801 | 164 | if (li > LI_MAX_EA) |
1802 | 49 | return -1; |
1803 | | |
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 | 115 | switch (li) { |
1808 | | |
1809 | 8 | case LI_NORMAL_EA_WITH_CHECKSUM : |
1810 | 8 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM || |
1811 | 8 | tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 2) |
1812 | 8 | return -1; |
1813 | | /* FALLTHROUGH */ |
1814 | | |
1815 | 8 | case LI_NORMAL_EA_WITHOUT_CHECKSUM : |
1816 | 8 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1817 | 8 | is_extended = false; |
1818 | 8 | break; |
1819 | | |
1820 | 14 | case LI_EXTENDED_EA_WITH_CHECKSUM : |
1821 | 14 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM || |
1822 | 14 | tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) |
1823 | 14 | return -1; |
1824 | | /* FALLTHROUGH */ |
1825 | | |
1826 | 35 | case LI_EXTENDED_EA_WITHOUT_CHECKSUM : |
1827 | 35 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1828 | 35 | is_extended = true; |
1829 | 35 | break; |
1830 | | |
1831 | 50 | default : /* bad TPDU */ |
1832 | 50 | return -1; |
1833 | 115 | } /* li */ |
1834 | 115 | } else { /* cotp_decode_atn */ |
1835 | | /* check for ATN length: TPDU may be 2 octets longer due to checksum */ |
1836 | 0 | if (li > LI_ATN_MAX_EA) |
1837 | 0 | return -1; |
1838 | | |
1839 | 0 | switch (li) { |
1840 | | |
1841 | | /* extended TPDU numbering EA with no checksum */ |
1842 | 0 | case LI_NORMAL_EA_WITHOUT_CHECKSUM : |
1843 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1844 | 0 | is_extended = false; |
1845 | 0 | break; |
1846 | | |
1847 | | /* normal TPDU numbering EA with 2 octets of OSI or ATN extended |
1848 | | * checksum */ |
1849 | 0 | case LI_NORMAL_EA_WITH_CHECKSUM : |
1850 | | /* check checksum parameter (in VP) parameter code octet */ |
1851 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) && |
1852 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16)) |
1853 | 0 | return -1; |
1854 | | |
1855 | | /* check checksum parameter (in VP) length octet */ |
1856 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 2) |
1857 | 0 | return -1; |
1858 | | |
1859 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1860 | 0 | is_extended = false; |
1861 | 0 | break; |
1862 | | |
1863 | | /* normal TPDU numbering EA with 4 octets of ATN extended checksum */ |
1864 | 0 | case LI_ATN_NORMAL_EA_WITH_CHECKSUM : |
1865 | | /* check checksum parameter (in VP) parameter code octet */ |
1866 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32) |
1867 | 0 | return -1; |
1868 | | |
1869 | | /* check checksum parameter (in VP) length octet */ |
1870 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 4) |
1871 | 0 | return -1; |
1872 | | |
1873 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1874 | 0 | is_extended = false; |
1875 | 0 | break; |
1876 | | |
1877 | | /* extended TPDU numbering EA with no checksum */ |
1878 | 0 | case LI_EXTENDED_EA_WITHOUT_CHECKSUM : |
1879 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1880 | 0 | is_extended = true; |
1881 | 0 | break; |
1882 | | |
1883 | | /* extended TPDU numbering EA with 2 octets of OSI or ATN extended |
1884 | | * checksum */ |
1885 | 0 | case LI_EXTENDED_EA_WITH_CHECKSUM : |
1886 | | /* check checksum parameter (in VP) parameter code octet */ |
1887 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) && |
1888 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16)) |
1889 | 0 | return -1; |
1890 | | |
1891 | | /* check checksum parameter (in VP) length octet */ |
1892 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) |
1893 | 0 | return -1; |
1894 | | |
1895 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1896 | 0 | is_extended = true; |
1897 | 0 | break; |
1898 | | |
1899 | | /* extended EA with 4 octets ATN extended checksum */ |
1900 | 0 | case LI_ATN_EXTENDED_EA_WITH_CHECKSUM : |
1901 | | /* check checksum parameter (in VP) parameter code octet */ |
1902 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32) |
1903 | 0 | return -1; |
1904 | | |
1905 | | /* check checksum parameter (in VP) length octet */ |
1906 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) |
1907 | 0 | return -1; |
1908 | | |
1909 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1910 | 0 | is_extended = true; |
1911 | 0 | break; |
1912 | | |
1913 | 0 | default : /* bad TPDU */ |
1914 | 0 | return -1; |
1915 | 0 | } |
1916 | 0 | } |
1917 | | |
1918 | | /* ER TPDUs have no user data, so the length indicator determines the |
1919 | | * length */ |
1920 | 43 | tpdu_len = li + 1; |
1921 | | |
1922 | 43 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1923 | 43 | pinfo->clnp_dstref = dst_ref; |
1924 | | |
1925 | 43 | col_append_fstr(pinfo->cinfo, COL_INFO, "EA TPDU (%u) dst-ref: 0x%04x", |
1926 | 43 | tpdu_nr, dst_ref); |
1927 | | |
1928 | 43 | if (tree) { |
1929 | 43 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1930 | 43 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1931 | 43 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1932 | 43 | } |
1933 | 43 | offset += 1; |
1934 | | |
1935 | 43 | if (tree) { |
1936 | 43 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1937 | 43 | } |
1938 | 43 | offset += 1; |
1939 | 43 | li -= 1; |
1940 | | |
1941 | 43 | if (tree) |
1942 | 43 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1943 | 43 | offset += 2; |
1944 | 43 | li -= 2; |
1945 | | |
1946 | 43 | if (is_extended) { |
1947 | 35 | if (tree) { |
1948 | 35 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb, |
1949 | 35 | offset, 4, tpdu_nr); |
1950 | 35 | } |
1951 | 35 | offset += 4; |
1952 | 35 | li -= 4; |
1953 | 35 | } else { |
1954 | 8 | if (tree) { |
1955 | 8 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1, |
1956 | 8 | tpdu_nr); |
1957 | 8 | } |
1958 | 8 | offset += 1; |
1959 | 8 | li -= 1; |
1960 | 8 | } |
1961 | | |
1962 | 43 | if (tree) |
1963 | 43 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1964 | 43 | offset += li; |
1965 | | |
1966 | 43 | return offset; |
1967 | | |
1968 | 164 | } /* ositp_decode_EA */ |
1969 | | |
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 } |
1976 | | }; |
1977 | | |
1978 | | static int ositp_decode_ER(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1979 | | packet_info *pinfo, proto_tree *tree) |
1980 | 33 | { |
1981 | 33 | proto_tree *cotp_tree = NULL; |
1982 | 33 | proto_item *ti; |
1983 | 33 | uint16_t dst_ref; |
1984 | 33 | uint8_t tpdu_len; |
1985 | | |
1986 | | /* ATN: except for modified LI checking nothing to be done here */ |
1987 | 33 | if (!cotp_decode_atn) { |
1988 | 33 | if (li > LI_MAX_ER) |
1989 | 9 | return -1; |
1990 | 33 | } else { |
1991 | 0 | if (li > LI_ATN_MAX_ER) |
1992 | 0 | return -1; |
1993 | 0 | } |
1994 | | |
1995 | | /* ER TPDUs have no user data, so the length indicator determines the |
1996 | | * length */ |
1997 | 24 | tpdu_len = li + 1; |
1998 | | |
1999 | 24 | if(try_val_to_str(tvb_get_uint8(tvb, offset + P_REJECT_ER), cotp_reject_vals) == NULL) |
2000 | 11 | return -1; |
2001 | | |
2002 | 13 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
2003 | 13 | pinfo->clnp_dstref = dst_ref; |
2004 | | |
2005 | 13 | col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref); |
2006 | | |
2007 | 13 | if (tree) { |
2008 | 11 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
2009 | 11 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
2010 | 11 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
2011 | 11 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu); |
2012 | 11 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, |
2013 | 11 | dst_ref); |
2014 | 11 | proto_tree_add_item(cotp_tree, hf_cotp_reject_cause, tvb, offset + 4, 1, ENC_NA); |
2015 | 11 | } |
2016 | 13 | offset += 5; |
2017 | 13 | li -= 4; |
2018 | | |
2019 | 13 | if (tree) |
2020 | 11 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
2021 | 13 | offset += li; |
2022 | | |
2023 | 13 | return offset; |
2024 | | |
2025 | 24 | } /* ositp_decode_ER */ |
2026 | | |
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) |
2030 | 198 | { |
2031 | 198 | proto_item *ti; |
2032 | 198 | proto_tree *cltp_tree = NULL; |
2033 | 198 | tvbuff_t *next_tvb; |
2034 | 198 | unsigned tpdu_len; |
2035 | 198 | heur_dtbl_entry_t *hdtbl_entry; |
2036 | | |
2037 | | /* UD TPDUs have user data, so they run to the end of the containing PDU */ |
2038 | 198 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
2039 | | |
2040 | 198 | col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU"); |
2041 | | |
2042 | 198 | if (tree) { |
2043 | 198 | ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, ENC_NA); |
2044 | 198 | cltp_tree = proto_item_add_subtree(ti, ett_cltp); |
2045 | 198 | proto_tree_add_uint(cltp_tree, hf_cltp_li, tvb, offset, 1,li); |
2046 | 198 | } |
2047 | 198 | offset += 1; |
2048 | | |
2049 | 198 | if (tree) { |
2050 | 198 | proto_tree_add_uint(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu); |
2051 | 198 | } |
2052 | 198 | offset += 1; |
2053 | 198 | li -= 1; |
2054 | | |
2055 | 198 | if (tree) |
2056 | 198 | ositp_decode_var_part(tvb, offset, li, 0, tpdu_len, pinfo, cltp_tree); |
2057 | 198 | offset += li; |
2058 | | |
2059 | 198 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
2060 | | |
2061 | 198 | if (dissector_try_heuristic(cltp_heur_subdissector_list, next_tvb, |
2062 | 198 | pinfo, tree, &hdtbl_entry, NULL)) { |
2063 | 22 | *subdissector_found = true; |
2064 | 176 | } else { |
2065 | 176 | call_data_dissector(next_tvb, pinfo, tree); |
2066 | 176 | } |
2067 | | |
2068 | | |
2069 | | /*call_data_dissector(next_tvb, pinfo, tree); */ |
2070 | | |
2071 | 198 | offset += tvb_captured_length_remaining(tvb, offset); |
2072 | | /* we dissected all of the containing PDU */ |
2073 | | |
2074 | 198 | return offset; |
2075 | | |
2076 | 198 | } /* ositp_decode_UD */ |
2077 | | |
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. |
2080 | | |
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) |
2089 | 8.68k | { |
2090 | 8.68k | int offset = 0; |
2091 | 8.68k | uint8_t li, tpdu, cdt; |
2092 | 8.68k | bool first_tpdu = true; |
2093 | 8.68k | int new_offset; |
2094 | 8.68k | bool found_ositp = false; |
2095 | 8.68k | bool is_cltp = false; |
2096 | 8.68k | bool subdissector_found = false; |
2097 | | |
2098 | | /* Initialize the COL_INFO field; each of the TPDUs will have its |
2099 | | information appended. */ |
2100 | 8.68k | col_clear(pinfo->cinfo, COL_INFO); |
2101 | | |
2102 | 12.4k | while (tvb_offset_exists(tvb, offset)) { |
2103 | 8.34k | if (!first_tpdu) { |
2104 | 82 | col_append_str(pinfo->cinfo, COL_INFO, ", "); |
2105 | 82 | expert_add_info(pinfo, NULL, &ei_cotp_multiple_tpdus); |
2106 | | /* adjust tvb and offset to the start of the current PDU */ |
2107 | 82 | tvb = tvb_new_subset_remaining(tvb, offset); |
2108 | 82 | offset = 0 ; |
2109 | 82 | } |
2110 | 8.34k | if ((li = tvb_get_uint8(tvb, offset + P_LI)) == 0) { |
2111 | 247 | col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero"); |
2112 | 247 | if (!first_tpdu) |
2113 | 14 | call_data_dissector( tvb_new_subset_remaining(tvb, offset), |
2114 | 14 | pinfo, tree); |
2115 | 247 | return found_ositp; |
2116 | 247 | } |
2117 | | |
2118 | 8.10k | tpdu = (tvb_get_uint8(tvb, offset + P_TPDU) >> 4) & 0x0F; |
2119 | 8.10k | if (tpdu == UD_TPDU) |
2120 | 198 | pinfo->current_proto = "CLTP"; /* connectionless transport */ |
2121 | 8.10k | cdt = tvb_get_uint8(tvb, offset + P_CDT) & 0x0F; |
2122 | | |
2123 | 8.10k | switch (tpdu) { |
2124 | 183 | case CC_TPDU : |
2125 | 378 | case CR_TPDU : |
2126 | 378 | new_offset = ositp_decode_CR_CC(tvb, offset, li, tpdu, pinfo, tree, |
2127 | 378 | uses_inactive_subset, &subdissector_found); |
2128 | 378 | break; |
2129 | 128 | case DR_TPDU : |
2130 | 128 | new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree); |
2131 | 128 | break; |
2132 | 6.28k | case DT_TPDU : |
2133 | 6.28k | new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree, |
2134 | 6.28k | uses_inactive_subset, &subdissector_found); |
2135 | 6.28k | break; |
2136 | 150 | case ED_TPDU : |
2137 | 150 | new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree, |
2138 | 150 | uses_inactive_subset, &subdissector_found); |
2139 | 150 | break; |
2140 | 63 | case RJ_TPDU : |
2141 | 63 | new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree); |
2142 | 63 | break; |
2143 | 48 | case DC_TPDU : |
2144 | 48 | new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree); |
2145 | 48 | break; |
2146 | 78 | case AK_TPDU : |
2147 | 78 | new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree); |
2148 | 78 | break; |
2149 | 164 | case EA_TPDU : |
2150 | 164 | new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree); |
2151 | 164 | break; |
2152 | 33 | case ER_TPDU : |
2153 | 33 | new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree); |
2154 | 33 | break; |
2155 | 198 | case UD_TPDU : |
2156 | 198 | new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree, |
2157 | 198 | &subdissector_found); |
2158 | 198 | is_cltp = true; |
2159 | 198 | break; |
2160 | 510 | default : |
2161 | 510 | if (first_tpdu) |
2162 | 482 | col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", |
2163 | 482 | tpdu); |
2164 | 510 | new_offset = -1; /* bad PDU type */ |
2165 | 510 | break; |
2166 | 8.10k | } |
2167 | | |
2168 | 4.87k | if (new_offset == -1) { /* incorrect TPDU */ |
2169 | 1.13k | if (!first_tpdu) |
2170 | 43 | call_data_dissector( tvb_new_subset_remaining(tvb, offset), |
2171 | 43 | pinfo, tree); |
2172 | 1.13k | break; |
2173 | 1.13k | } |
2174 | | |
2175 | 3.74k | 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 | 3.72k | if (!subdissector_found) |
2179 | 2.17k | col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP"); |
2180 | 3.72k | found_ositp = true; |
2181 | 3.72k | } |
2182 | | |
2183 | 3.74k | offset = new_offset; |
2184 | 3.74k | first_tpdu = false; |
2185 | 3.74k | } |
2186 | 5.20k | return found_ositp ? offset : 0; |
2187 | 8.68k | } /* dissect_ositp_internal */ |
2188 | | |
2189 | | static int dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
2190 | | void *data _U_) |
2191 | 488 | { |
2192 | 488 | return dissect_ositp_internal(tvb, pinfo, tree, false); |
2193 | 488 | } |
2194 | | |
2195 | | static int dissect_ositp_inactive(tvbuff_t *tvb, packet_info *pinfo, |
2196 | | proto_tree *tree, void *data _U_) |
2197 | 8.19k | { |
2198 | 8.19k | return dissect_ositp_internal(tvb, pinfo, tree, true); |
2199 | 8.19k | } |
2200 | | |
2201 | | static bool |
2202 | | test_cltp_var_part(tvbuff_t *tvb) |
2203 | 106 | { |
2204 | 106 | int offset = 0; |
2205 | 106 | uint8_t li; |
2206 | 109 | while (tvb_captured_length_remaining(tvb, offset)) { |
2207 | 95 | if (tvb_captured_length_remaining(tvb, offset) < 2) { |
2208 | 6 | return false; |
2209 | 6 | } |
2210 | 89 | switch (tvb_get_uint8(tvb, offset++)) { |
2211 | | /* These are the only 3 legal parameters for CLTP per RFC 1240 and X.234 */ |
2212 | 2 | case VP_SRC_TSAP: |
2213 | 3 | case VP_DST_TSAP: |
2214 | 5 | case VP_CHECKSUM: // Not required as redundant with UDP checksum, per RFC 1240 |
2215 | 5 | break; |
2216 | 84 | default: |
2217 | 84 | return false; |
2218 | 89 | } |
2219 | 5 | li = tvb_get_uint8(tvb, offset++); |
2220 | 5 | if (li == 255) { |
2221 | 1 | return false; |
2222 | 1 | } |
2223 | 4 | if (tvb_captured_length_remaining(tvb, offset) < li) { |
2224 | 1 | return false; |
2225 | 1 | } |
2226 | 3 | offset += li; |
2227 | 3 | } |
2228 | 14 | return true; |
2229 | 106 | } |
2230 | | |
2231 | | static bool |
2232 | | dissect_cltp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, |
2233 | | void *data) |
2234 | 1.54k | { |
2235 | 1.54k | uint8_t li, tpdu, spdu; |
2236 | 1.54k | int offset = 0; |
2237 | | |
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. |
2242 | | */ |
2243 | | |
2244 | | /* First, check do we have at least 2 bytes (length + tpdu) */ |
2245 | 1.54k | if (tvb_captured_length(tvb) < 2) { |
2246 | 3 | return false; |
2247 | 3 | } |
2248 | | |
2249 | 1.54k | li = tvb_get_uint8(tvb, offset++); |
2250 | | |
2251 | | /* LI must include TPDU, and 255 is reserved */ |
2252 | 1.54k | if (li == 0 || li == 255) { |
2253 | 383 | return false; |
2254 | 383 | } |
2255 | | |
2256 | | /* Is it OSI on top of the UDP? */ |
2257 | 1.16k | tpdu = (tvb_get_uint8(tvb, offset++) & 0xF0) >> 4; |
2258 | 1.16k | if (tpdu != UD_TPDU) { |
2259 | 1.05k | return false; |
2260 | 1.05k | } |
2261 | | |
2262 | | /* LI includes TPDU */ |
2263 | 106 | li--; |
2264 | | |
2265 | 106 | if (!test_cltp_var_part(tvb_new_subset_length(tvb, offset, li))) { |
2266 | 92 | return false; |
2267 | 92 | } |
2268 | 14 | offset += li; |
2269 | | |
2270 | | /* Since R-GOOSE is the only known user of CLTP over UDP, just |
2271 | | * check for that. |
2272 | | */ |
2273 | | |
2274 | | /* Check do we have SPDU ID byte, too */ |
2275 | 14 | if (tvb_captured_length_remaining(tvb, offset) < 1) { |
2276 | 7 | return false; |
2277 | 7 | } |
2278 | | |
2279 | | /* And let's see if it is GOOSE SPDU */ |
2280 | 7 | spdu = tvb_get_uint8(tvb, offset); |
2281 | 7 | if (spdu != 0xA1) { |
2282 | 5 | return false; |
2283 | 5 | } |
2284 | | |
2285 | 2 | dissect_ositp(tvb, pinfo, parent_tree, data); |
2286 | 2 | return true; |
2287 | 7 | } |
2288 | | |
2289 | | static void |
2290 | | cotp_reassemble_init(void) |
2291 | 14 | { |
2292 | 14 | cotp_dst_ref = 0; |
2293 | 14 | } |
2294 | | |
2295 | | void proto_register_cotp(void) |
2296 | 14 | { |
2297 | 14 | static hf_register_info hf[] = { |
2298 | 14 | { &hf_cotp_li, |
2299 | 14 | { "Length", "cotp.li", FT_UINT8, BASE_DEC, |
2300 | 14 | NULL, 0x0, "Length Indicator, length of this header", HFILL}}, |
2301 | 14 | { &hf_cotp_type, |
2302 | 14 | { "PDU Type", "cotp.type", FT_UINT8, BASE_HEX, |
2303 | 14 | VALS(cotp_tpdu_type_abbrev_vals), 0x0, |
2304 | 14 | "PDU Type - upper nibble of byte", HFILL}}, |
2305 | 14 | { &hf_cotp_srcref, |
2306 | 14 | { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, |
2307 | 14 | NULL, 0x0, "Source address reference", HFILL}}, |
2308 | 14 | { &hf_cotp_destref, |
2309 | 14 | { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, |
2310 | 14 | NULL, 0x0, "Destination address reference", HFILL}}, |
2311 | 14 | { &hf_cotp_class, |
2312 | 14 | { "Class", "cotp.class", FT_UINT8, BASE_DEC, NULL, |
2313 | 14 | 0xF0, "Transport protocol class", HFILL}}, |
2314 | 14 | { &hf_cotp_opts_extended_formats, |
2315 | 14 | { "Extended formats", "cotp.opts.extended_formats", FT_BOOLEAN, 8, |
2316 | 14 | NULL, 0x02, "Use of extended formats in classes 2, 3, and 4", HFILL}}, |
2317 | 14 | { &hf_cotp_opts_no_explicit_flow_control, |
2318 | 14 | { "No explicit flow control", "cotp.opts.no_explicit_flow_control", |
2319 | 14 | FT_BOOLEAN, 8, NULL, 0x01, "No explicit flow control in class 2", |
2320 | 14 | HFILL}}, |
2321 | 14 | { &hf_cotp_tpdu_number, |
2322 | 14 | { "TPDU number", "cotp.tpdu-number", FT_UINT8, BASE_HEX, |
2323 | 14 | NULL, 0x7f, NULL, HFILL}}, |
2324 | 14 | { &hf_cotp_tpdu_number_extended, |
2325 | 14 | { "TPDU number", "cotp.tpdu-number", FT_UINT32, BASE_HEX, |
2326 | 14 | NULL, 0x0 /* XXX - 0x7fff? */, NULL, HFILL}}, |
2327 | 14 | { &hf_cotp_next_tpdu_number, |
2328 | 14 | { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT8, BASE_HEX, |
2329 | 14 | NULL, 0x0, NULL, HFILL}}, |
2330 | 14 | { &hf_cotp_next_tpdu_number_extended, |
2331 | 14 | { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT32, BASE_HEX, |
2332 | 14 | NULL, 0x0, NULL, HFILL}}, |
2333 | 14 | { &hf_cotp_eot, |
2334 | 14 | { "Last data unit", "cotp.eot", FT_BOOLEAN, 8, |
2335 | 14 | TFS(&tfs_yes_no), 0x80, |
2336 | 14 | "Is current TPDU the last data unit of a complete DT TPDU sequence " |
2337 | 14 | "(End of TSDU)?", HFILL}}, |
2338 | 14 | { &hf_cotp_eot_extended, |
2339 | 14 | { "Last data unit", "cotp.eot", FT_BOOLEAN, 32, |
2340 | 14 | TFS(&tfs_yes_no), 0x80000000, |
2341 | 14 | "Is current TPDU the last data unit of a complete DT TPDU sequence " |
2342 | 14 | "(End of TSDU)?", HFILL}}, |
2343 | 14 | { &hf_cotp_segment_overlap, |
2344 | 14 | { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, |
2345 | 14 | NULL, 0x0, "Segment overlaps with other segments", HFILL }}, |
2346 | 14 | { &hf_cotp_segment_overlap_conflict, |
2347 | 14 | { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", |
2348 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
2349 | 14 | "Overlapping segments contained conflicting data", HFILL }}, |
2350 | 14 | { &hf_cotp_segment_multiple_tails, |
2351 | 14 | { "Multiple tail segments found", "cotp.segment.multipletails", |
2352 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
2353 | 14 | "Several tails were found when reassembling the packet", HFILL }}, |
2354 | 14 | { &hf_cotp_segment_too_long_segment, |
2355 | 14 | { "Segment too long", "cotp.segment.toolongsegment", |
2356 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
2357 | 14 | "Segment contained data past end of packet", HFILL }}, |
2358 | 14 | { &hf_cotp_segment_error, |
2359 | 14 | { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, |
2360 | 14 | NULL, 0x0, "Reassembly error due to illegal segments", HFILL }}, |
2361 | 14 | { &hf_cotp_segment_count, |
2362 | 14 | { "Segment count", "cotp.segment.count", FT_UINT32, BASE_DEC, |
2363 | 14 | NULL, 0x0, NULL, HFILL }}, |
2364 | 14 | { &hf_cotp_segment, |
2365 | 14 | { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, |
2366 | 14 | NULL, 0x0, NULL, HFILL }}, |
2367 | 14 | { &hf_cotp_segments, |
2368 | 14 | { "COTP Segments", "cotp.segments", FT_NONE, BASE_NONE, |
2369 | 14 | NULL, 0x0, NULL, HFILL }}, |
2370 | 14 | { &hf_cotp_reassembled_in, |
2371 | 14 | { "Reassembled COTP in frame", "cotp.reassembled_in", |
2372 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
2373 | 14 | "This COTP packet is reassembled in this frame", HFILL }}, |
2374 | 14 | { &hf_cotp_reassembled_length, |
2375 | 14 | { "Reassembled COTP length", "cotp.reassembled.length", |
2376 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
2377 | 14 | "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 | 14 | { &hf_cotp_vp_src_tsap, |
2384 | 14 | { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, |
2385 | 14 | NULL, 0x0, "Calling TSAP", HFILL }}, |
2386 | 14 | { &hf_cotp_vp_src_tsap_bytes, |
2387 | 14 | { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, |
2388 | 14 | NULL, 0x0, "Calling TSAP (bytes representation)", HFILL }}, |
2389 | 14 | { &hf_cotp_vp_dst_tsap, |
2390 | 14 | { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, |
2391 | 14 | NULL, 0x0, "Called TSAP", HFILL }}, |
2392 | 14 | { &hf_cotp_vp_dst_tsap_bytes, |
2393 | 14 | { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, |
2394 | 14 | NULL, 0x0, "Called TSAP (bytes representation)", HFILL }}, |
2395 | | /* Generated from convert_proto_tree_add_text.pl */ |
2396 | 14 | { &hf_cotp_parameter_code, { "Parameter code", "cotp.parameter_code", FT_UINT8, BASE_HEX, VALS(tp_vpart_type_vals), 0x0, NULL, HFILL }}, |
2397 | 14 | { &hf_cotp_parameter_length, { "Parameter length", "cotp.parameter_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2398 | 14 | { &hf_cotp_parameter_value, { "Parameter value", "cotp.parameter_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2399 | 14 | { &hf_cotp_atn_extended_checksum16, { "ATN extended checksum", "cotp.atn_extended_checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2400 | 14 | { &hf_cotp_atn_extended_checksum32, { "ATN extended checksum", "cotp.atn_extended_checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2401 | 14 | { &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 | 14 | { &hf_cotp_ack_time, { "Ack time (ms)", "cotp.ack_time", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2403 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &hf_cotp_vp_priority, { "Priority", "cotp.vp_priority", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2407 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &hf_cotp_sequence_number, { "Sequence number", "cotp.sequence_number", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2420 | 14 | { &hf_cotp_reassignment_time, { "Reassignment time (secs)", "cotp.reassignment_time", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2421 | 14 | { &hf_cotp_lower_window_edge, { "Lower window edge", "cotp.lower_window_edge", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2422 | 14 | { &hf_cotp_credit, { "Credit", "cotp.credit", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2423 | 14 | { &hf_cotp_tpdu_size, { "TPDU size", "cotp.tpdu_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2424 | 14 | { &hf_cotp_checksum, { "Checksum", "cotp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2425 | 14 | { &hf_cotp_checksum_status, { "Checksum Status", "cotp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }}, |
2426 | 14 | { &hf_cotp_vp_version_nr, { "Version", "cotp.vp_version_nr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2427 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &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 | 14 | { &hf_cotp_preferred_maximum_tpdu_size, { "Preferred maximum TPDU size", "cotp.preferred_maximum_tpdu_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2432 | 14 | { &hf_cotp_inactivity_timer, { "Inactivity timer (ms)", "cotp.inactivity_timer", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2433 | 14 | { &hf_cotp_cause, { "Cause", "cotp.cause", FT_UINT8, BASE_DEC, VALS(cotp_cause_vals), 0x0, NULL, HFILL }}, |
2434 | 14 | { &hf_cotp_segment_data, { "COTP segment data", "cotp.segment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2435 | 14 | { &hf_cotp_credit_cdt, { "Credit", "cotp.credit", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2436 | 14 | { &hf_cotp_reject_cause, { "Reject cause", "cotp.reject_cause", FT_UINT8, BASE_DEC, VALS(cotp_reject_vals), 0x0, NULL, HFILL }}, |
2437 | 14 | }; |
2438 | 14 | static int *ett[] = { |
2439 | 14 | &ett_cotp, |
2440 | 14 | &ett_cotp_segment, |
2441 | 14 | &ett_cotp_segments |
2442 | 14 | }; |
2443 | 14 | static ei_register_info ei[] = { |
2444 | 14 | { &ei_cotp_disconnect_request, { "cotp.disconnect_request", PI_SEQUENCE, PI_CHAT, "Disconnect Request(DR)", EXPFILL }}, |
2445 | 14 | { &ei_cotp_reject, { "cotp.reject", PI_SEQUENCE, PI_NOTE, "Reject(RJ)", EXPFILL }}, |
2446 | 14 | { &ei_cotp_connection, { "cotp.connection", PI_SEQUENCE, PI_CHAT, "Connection", EXPFILL }}, |
2447 | 14 | { &ei_cotp_disconnect_confirm, { "cotp.disconnect_confirm", PI_SEQUENCE, PI_CHAT, "Disconnect Confirm(DC)", EXPFILL }}, |
2448 | 14 | { &ei_cotp_multiple_tpdus, { "cotp.multiple_tpdus", PI_SEQUENCE, PI_NOTE, "Multiple TPDUs in one packet", EXPFILL }}, |
2449 | 14 | { &ei_cotp_preferred_maximum_tpdu_size, { "cotp.preferred_maximum_tpdu_size.invalid", PI_PROTOCOL, PI_WARN, "Preferred maximum TPDU size: bogus length", EXPFILL }}, |
2450 | 14 | { &ei_cotp_atn_extended_checksum, { "cotp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, |
2451 | 14 | { &ei_cotp_checksum, { "cotp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, |
2452 | 14 | }; |
2453 | | |
2454 | 14 | module_t *cotp_module; |
2455 | 14 | expert_module_t* expert_cotp; |
2456 | | |
2457 | 14 | proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp"); |
2458 | 14 | proto_register_field_array(proto_cotp, hf, array_length(hf)); |
2459 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
2460 | 14 | expert_cotp = expert_register_protocol(proto_cotp); |
2461 | 14 | expert_register_field_array(expert_cotp, ei, array_length(ei)); |
2462 | 14 | cotp_module = prefs_register_protocol(proto_cotp, NULL); |
2463 | | |
2464 | 14 | prefs_register_bool_preference(cotp_module, "reassemble", |
2465 | 14 | "Reassemble segmented COTP datagrams", |
2466 | 14 | "Whether segmented COTP datagrams should be " |
2467 | 14 | "reassembled. To use this option, you must " |
2468 | 14 | "also enable \"Allow subdissectors to " |
2469 | 14 | "reassemble TCP streams\" in the TCP " |
2470 | 14 | "protocol settings.", |
2471 | 14 | &cotp_reassemble); |
2472 | | |
2473 | 14 | prefs_register_enum_preference(cotp_module, "tsap_display", |
2474 | 14 | "Display TSAPs as strings or bytes", |
2475 | 14 | "How TSAPs should be displayed", |
2476 | 14 | &tsap_display, tsap_display_options, false); |
2477 | | |
2478 | 14 | prefs_register_bool_preference(cotp_module, "decode_atn", "Decode ATN TPDUs", |
2479 | 14 | "Whether to decode OSI TPDUs with ATN " |
2480 | 14 | "(Aeronautical Telecommunications Network) " |
2481 | 14 | "extensions. To use this option, you must " |
2482 | 14 | "also enable \"Always try to decode NSDU as " |
2483 | 14 | "transport PDUs\" in the CLNP protocol " |
2484 | 14 | "settings.", &cotp_decode_atn); |
2485 | | |
2486 | | /* For handling protocols hijacking the variable part of CR or CC PDUs */ |
2487 | 14 | cotp_cr_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_cr", "COTP CR (Connect Request) payload", proto_cotp); |
2488 | 14 | cotp_cc_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_cc", "COTP CC (Connect Confirm) payload", proto_cotp); |
2489 | | |
2490 | | /* subdissector code in inactive subset */ |
2491 | 14 | cotp_is_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_is", "COTP IS (Inactive Subset) payload", proto_cotp); |
2492 | | |
2493 | | /* other COTP/ISO 8473 subdissectors */ |
2494 | 14 | cotp_heur_subdissector_list = register_heur_dissector_list_with_description("cotp", "COTP DT (Data) payload", proto_cotp); |
2495 | | |
2496 | | /* XXX - what about CLTP and proto_cltp? */ |
2497 | 14 | ositp_handle = register_dissector("ositp", dissect_ositp, proto_cotp); |
2498 | 14 | register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp); |
2499 | | |
2500 | 14 | register_init_routine(cotp_reassemble_init); |
2501 | | /* |
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. |
2508 | | */ |
2509 | 14 | reassembly_table_register(&cotp_reassembly_table, |
2510 | 14 | &addresses_reassembly_table_functions); |
2511 | 14 | } |
2512 | | |
2513 | | void proto_register_cltp(void) |
2514 | 14 | { |
2515 | 14 | static hf_register_info hf[] = { |
2516 | 14 | { &hf_cltp_li, |
2517 | 14 | { "Length", "cltp.li", FT_UINT8, BASE_DEC, NULL, 0x0, |
2518 | 14 | "Length Indicator, length of this header", HFILL}}, |
2519 | 14 | { &hf_cltp_type, |
2520 | 14 | { "PDU Type", "cltp.type", FT_UINT8, BASE_HEX, |
2521 | 14 | VALS(cltp_tpdu_type_abbrev_vals), 0x0, NULL, HFILL}} |
2522 | 14 | }; |
2523 | 14 | static int *ett[] = { |
2524 | 14 | &ett_cltp |
2525 | 14 | }; |
2526 | | |
2527 | 14 | proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp"); |
2528 | 14 | proto_register_field_array(proto_cltp, hf, array_length(hf)); |
2529 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
2530 | | |
2531 | 14 | cltp_heur_subdissector_list = register_heur_dissector_list_with_description("cltp", "CLTP data atop CLNP", proto_cltp); |
2532 | 14 | } |
2533 | | |
2534 | | void |
2535 | | proto_reg_handoff_cotp(void) |
2536 | 14 | { |
2537 | 14 | dissector_add_uint("ip.proto", IP_PROTO_TP, ositp_handle); |
2538 | | |
2539 | 14 | rdp_cr_handle = find_dissector("rdp_cr"); |
2540 | 14 | rdp_cc_handle = find_dissector("rdp_cc"); |
2541 | | |
2542 | 14 | proto_clnp = proto_get_id_by_filter_name("clnp"); |
2543 | | |
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? |
2547 | | */ |
2548 | 14 | heur_dissector_add("udp", dissect_cltp_heur, "CLTP over UDP", |
2549 | 14 | "cltp_udp", proto_cltp, HEURISTIC_ENABLE); |
2550 | 14 | } |
2551 | | |
2552 | | /* |
2553 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
2554 | | * |
2555 | | * Local variables: |
2556 | | * c-basic-offset: 2 |
2557 | | * tab-width: 8 |
2558 | | * indent-tabs-mode: nil |
2559 | | * End: |
2560 | | * |
2561 | | * vi: set shiftwidth=2 tabstop=8 expandtab: |
2562 | | * :indentSize=2:tabSize=8:noTabs=true: |
2563 | | */ |