/src/wireshark/epan/dissectors/packet-ositp.c
Line | Count | Source |
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/expert.h> |
22 | | #include <epan/proto_data.h> |
23 | | #include <epan/tfs.h> |
24 | | #include <epan/iana-info.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 | 137 | #define ED_TPDU 0x1 /* COTP */ |
161 | 149 | #define EA_TPDU 0x2 /* COTP */ |
162 | 9.76k | #define UD_TPDU 0x4 /* CLTP */ |
163 | 64 | #define RJ_TPDU 0x5 /* COTP */ |
164 | 101 | #define AK_TPDU 0x6 /* COTP */ |
165 | 116 | #define ER_TPDU 0x7 /* COTP */ |
166 | 164 | #define DR_TPDU 0x8 /* COTP */ |
167 | 29 | #define DC_TPDU 0xC /* COTP */ |
168 | 136 | #define CC_TPDU 0xD /* COTP */ |
169 | 1.07k | #define CR_TPDU 0xE /* COTP */ |
170 | 6.69k | #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.61k | #define P_LI 0 |
205 | 8.40k | #define P_TPDU 1 |
206 | 8.40k | #define P_CDT 1 |
207 | 1.47k | #define P_DST_REF 2 |
208 | 436 | #define P_SRC_REF 4 |
209 | 5.52k | #define P_TPDU_NR_0_1 2 |
210 | 1.15k | #define P_TPDU_NR_234 4 |
211 | 32 | #define P_VAR_PART_NDT 5 |
212 | 22 | #define P_VAR_PART_EDT 8 |
213 | | #define P_VAR_PART_DC 6 |
214 | 21 | #define P_CDT_IN_AK 8 |
215 | 0 | #define P_CDT_IN_RJ 8 |
216 | 99 | #define P_REJECT_ER 4 |
217 | 115 | #define P_REASON_IN_DR 6 |
218 | 305 | #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 | 5.52k | #define LI_NORMAL_DT_CLASS_01 2 |
227 | 846 | #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4 |
228 | 24 | #define LI_NORMAL_DT_WITH_CHECKSUM (LI_NORMAL_DT_WITHOUT_CHECKSUM+4) |
229 | 217 | #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7 |
230 | 20 | #define LI_EXTENDED_DT_WITH_CHECKSUM (LI_EXTENDED_DT_WITHOUT_CHECKSUM+4) |
231 | 24 | #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4 |
232 | 8 | #define LI_NORMAL_EA_WITH_CHECKSUM (LI_NORMAL_EA_WITHOUT_CHECKSUM+4) |
233 | 16 | #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7 |
234 | 2 | #define LI_EXTENDED_EA_WITH_CHECKSUM (LI_EXTENDED_EA_WITHOUT_CHECKSUM+4) |
235 | 57 | #define LI_NORMAL_RJ 4 |
236 | 0 | #define LI_EXTENDED_RJ 9 |
237 | 164 | #define LI_MIN_DR 6 |
238 | 29 | #define LI_MAX_DC 9 |
239 | 101 | #define LI_MAX_AK 27 |
240 | 149 | #define LI_MAX_EA 11 |
241 | 116 | #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 | 84 | #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 | 11 | #define VP_ACK_TIME 0x85 |
268 | 36 | #define VP_RES_ERROR 0x86 |
269 | 17 | #define VP_PRIORITY 0x87 |
270 | 82 | #define VP_TRANSIT_DEL 0x88 |
271 | 29 | #define VP_THROUGHPUT 0x89 |
272 | 15 | #define VP_SEQ_NR 0x8A /* in AK */ |
273 | 10 | #define VP_REASSIGNMENT 0x8B |
274 | 68 | #define VP_FLOW_CNTL 0x8C /* in AK */ |
275 | 17 | #define VP_TPDU_SIZE 0xC0 |
276 | 35 | #define VP_SRC_TSAP 0xC1 /* in CR/CC */ |
277 | 23 | #define VP_DST_TSAP 0xC2 |
278 | 87 | #define VP_CHECKSUM 0xC3 |
279 | 8 | #define VP_VERSION_NR 0xC4 |
280 | 0 | #define VP_PROTECTION 0xC5 |
281 | 32 | #define VP_OPT_SEL 0xC6 |
282 | 0 | #define VP_PROTO_CLASS 0xC7 |
283 | 1 | #define VP_CLEARING_INFO 0xE0 /* in DR */ |
284 | 23 | #define VP_PREF_MAX_TPDU_SIZE 0xF0 |
285 | 8 | #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 | 107 | #define VP_ATN_EC_32 0x08 /* 4 octet ATN Extended Transport Checksum parameter */ |
292 | 59 | #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 | | |
344 | 98 | #define TSAP_DISPLAY_AUTO 0 |
345 | 98 | #define TSAP_DISPLAY_STRING 1 |
346 | | #define TSAP_DISPLAY_BYTES 2 |
347 | | |
348 | | /* options */ |
349 | | static bool cotp_reassemble = true; |
350 | | static int32_t tsap_display = TSAP_DISPLAY_AUTO; |
351 | | static bool cotp_decode_atn; |
352 | | |
353 | | static const enum_val_t tsap_display_options[] = { |
354 | | {"auto", "As strings if printable", TSAP_DISPLAY_AUTO}, |
355 | | {"string", "As strings", TSAP_DISPLAY_STRING}, |
356 | | {"bytes", "As bytes", TSAP_DISPLAY_BYTES}, |
357 | | {NULL, NULL, -1} |
358 | | }; |
359 | | |
360 | | /* function definitions */ |
361 | | |
362 | 83 | #define MAX_TSAP_LEN 32 |
363 | | |
364 | | typedef struct _cotp_flow_info_t { |
365 | | uint16_t ref; // The dst-ref of this flow |
366 | | uint16_t frag_id; |
367 | | bool ref_set; // False if didn't get the CC/CR TPDU |
368 | | bool last_fragment; |
369 | | } cotp_flow_info_t; |
370 | | |
371 | | typedef struct _cotp_conv_info_t { |
372 | | cotp_flow_info_t flow[2]; |
373 | | cotp_flow_info_t *fwd; |
374 | | cotp_flow_info_t *rev; |
375 | | } cotp_conv_info_t; |
376 | | |
377 | | static cotp_conv_info_t *get_cotp_conv_info(packet_info *pinfo) |
378 | 5.56k | { |
379 | 5.56k | conversation_t *conv; |
380 | 5.56k | cotp_conv_info_t *conv_info; |
381 | 5.56k | int direction; |
382 | | |
383 | 5.56k | conv = find_or_create_conversation(pinfo); |
384 | 5.56k | conv_info = conversation_get_proto_data(conv, proto_cotp); |
385 | 5.56k | if (!conv_info) { |
386 | 536 | conv_info = wmem_new0(wmem_file_scope(), cotp_conv_info_t); |
387 | 536 | conversation_add_proto_data(conv, proto_cotp, conv_info); |
388 | 536 | } |
389 | | |
390 | | /* check direction; first compare addreses, then ports. */ |
391 | 5.56k | direction = cmp_address(&pinfo->src, &pinfo->dst); |
392 | 5.56k | if (direction==0) { |
393 | 97 | direction = (pinfo->srcport > pinfo->destport) ? 1 : -1; |
394 | 97 | } |
395 | | |
396 | 5.56k | if (direction >= 0) { |
397 | 1.93k | conv_info->fwd = &(conv_info->flow[0]); |
398 | 1.93k | conv_info->rev = &(conv_info->flow[1]); |
399 | 3.62k | } else { |
400 | 3.62k | conv_info->fwd = &(conv_info->flow[1]); |
401 | 3.62k | conv_info->rev = &(conv_info->flow[0]); |
402 | 3.62k | } |
403 | | |
404 | 5.56k | return conv_info; |
405 | 5.56k | } |
406 | | |
407 | | static uint16_t get_cotp_frag_id(packet_info *pinfo, cotp_flow_info_t *flow_info, bool fragment) |
408 | 5.50k | { |
409 | | /* When using fragment_add_seq_next and there is a possibility of multiple |
410 | | * TSDUs being completed in the same frame, each TSDU needs a unique ID/ |
411 | | * sequence number in order to properly retrieve the reassembly on the |
412 | | * later passes. As COTP Class 0 doesn't provide that, we want to assign |
413 | | * our own. If a TSDU doesn't complete in a frame, we need to keep using |
414 | | * that ID in subsequent frames with TPDUs from the same conversation until |
415 | | * it does. We also need to keep track of that ID in file scoped data so |
416 | | * that we have it on the later, not necessarily sequential, passes. |
417 | | * |
418 | | * Cf. with epan/frame.h and with the streaming_data functions in |
419 | | * epan/reassemble.h for other approaches with this same issue. */ |
420 | 5.50k | uint16_t frag_id; |
421 | 5.50k | unsigned flow_index = 0; |
422 | 5.50k | bool flow_first_seen = true; |
423 | 5.50k | wmem_list_t *used_flow_list; |
424 | 5.50k | uint32_t *prev_dst_ref; |
425 | | |
426 | | /* Have we seen this COTP flow before on this frame? |
427 | | * Using a list here is a bit of extra work that guards against |
428 | | * unusual captures with multiple TCP/TPKT streams on the same |
429 | | * frame (e.g., DVB-S2 GSE). */ |
430 | 5.50k | used_flow_list = (wmem_list_t *)p_get_proto_data(pinfo->pool, pinfo, proto_cotp, 0); |
431 | 5.50k | if (!used_flow_list) { |
432 | 1.20k | used_flow_list = wmem_list_new(pinfo->pool); |
433 | 1.20k | p_add_proto_data(pinfo->pool, pinfo, proto_cotp, 0, used_flow_list); |
434 | 4.30k | } else { |
435 | 4.30k | if (wmem_list_find(used_flow_list, flow_info)) { |
436 | 4.21k | flow_first_seen = false; |
437 | 4.21k | } else { |
438 | 91 | flow_index = wmem_list_count(used_flow_list); |
439 | 91 | } |
440 | 4.30k | } |
441 | 5.50k | wmem_list_append(used_flow_list, flow_info); |
442 | 5.50k | if (flow_first_seen) { |
443 | | /* If this is the first time this COTP conversation has been |
444 | | * seen in this frame on this pass, and last TPDU completed a |
445 | | * TSDU, then we can reset the fragment number back to zero. |
446 | | * (We don't really have to do this.) */ |
447 | 1.29k | if (!flow_info->last_fragment) { |
448 | 753 | flow_info->frag_id = 0; |
449 | 753 | } |
450 | | |
451 | | /* If this is the first sequential pass through the frame, then |
452 | | * we save the fragment number for this converation. If not, we |
453 | | * restore the conversation fragment number to what it was at |
454 | | * this point in the first pass. */ |
455 | 1.29k | prev_dst_ref = (uint32_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_cotp, flow_index); |
456 | 1.29k | if (!prev_dst_ref) { |
457 | 1.29k | DISSECTOR_ASSERT(!PINFO_FD_VISITED(pinfo)); |
458 | 1.29k | prev_dst_ref = wmem_new(wmem_file_scope(), uint32_t); |
459 | 1.29k | *prev_dst_ref = flow_info->frag_id; |
460 | 1.29k | p_add_proto_data(wmem_file_scope(), pinfo, proto_cotp, flow_index, prev_dst_ref); |
461 | 1.29k | } else { |
462 | 0 | flow_info->frag_id = *prev_dst_ref; |
463 | 0 | } |
464 | 1.29k | } |
465 | 5.50k | frag_id = flow_info->frag_id; |
466 | | /* We update the conversation info frag id even on later passes, so |
467 | | * that we only have to store as proto data the first fragment ID |
468 | | * for the conversation. */ |
469 | 5.50k | flow_info->last_fragment = fragment; |
470 | 5.50k | if (!fragment) { |
471 | 1.93k | flow_info->frag_id++; |
472 | 1.93k | } |
473 | 5.50k | return frag_id; |
474 | 5.50k | } |
475 | | |
476 | | static char *print_tsap(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int length) |
477 | 46 | { |
478 | 46 | const unsigned char *tsap = tvb_get_ptr(tvb, offset, length); |
479 | 46 | char *cur; |
480 | 46 | bool allprintable; |
481 | 46 | int idx = 0, returned_length; |
482 | | |
483 | 46 | cur=(char *)wmem_alloc(scope, MAX_TSAP_LEN * 2 + 3); |
484 | 46 | cur[0] = '\0'; |
485 | 46 | if (length <= 0 || length > MAX_TSAP_LEN) |
486 | 46 | snprintf(cur, MAX_TSAP_LEN * 2 + 3, "<unsupported TSAP length>"); |
487 | 18 | else { |
488 | 18 | allprintable = tvb_ascii_isprint(tvb, offset, length); |
489 | 18 | if (!allprintable) { |
490 | 13 | returned_length = snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x"); |
491 | 13 | idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1); |
492 | 13 | } |
493 | 107 | while (length != 0) { |
494 | 89 | if (allprintable) { |
495 | 6 | returned_length = snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, |
496 | 6 | "%c", *tsap ++); |
497 | 6 | idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1); |
498 | 83 | } else { |
499 | 83 | returned_length = snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, |
500 | 83 | "%02x", *tsap ++); |
501 | 83 | idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1); |
502 | 83 | } |
503 | 89 | length --; |
504 | 89 | } |
505 | 18 | } |
506 | 46 | return cur; |
507 | | |
508 | 46 | } /* print_tsap */ |
509 | | |
510 | | static const true_false_string tfs_vp_opt_sel_class1_use = { "Receipt confirmation", "Explicit AK variant" }; |
511 | | |
512 | | static bool ositp_decode_var_part(tvbuff_t *tvb, int offset, int vp_length, |
513 | | int class_option, int tpdu_len, |
514 | | packet_info *pinfo, proto_tree *tree) |
515 | 6.97k | { |
516 | 6.97k | uint8_t code, length; |
517 | 6.97k | uint8_t c1; |
518 | 6.97k | uint16_t s; |
519 | 6.97k | uint32_t offset_iso8073_checksum = 0; |
520 | 6.97k | int32_t i = 0; |
521 | 6.97k | uint8_t tmp_code = 0; |
522 | 6.97k | unsigned tmp_len = 0; |
523 | 6.97k | uint32_t pref_max_tpdu_size; |
524 | 6.97k | proto_item *hidden_item; |
525 | | |
526 | 9.32k | while (vp_length != 0) { |
527 | 2.85k | proto_tree_add_item_ret_uint8(tree, hf_cotp_parameter_code, tvb, offset, 1, ENC_NA, &code); |
528 | 2.85k | offset += 1; |
529 | 2.85k | vp_length -= 1; |
530 | | |
531 | 2.85k | if (vp_length == 0) |
532 | 134 | break; |
533 | 2.72k | proto_tree_add_item_ret_uint8(tree, hf_cotp_parameter_length, tvb, offset, 1, ENC_NA, &length); |
534 | 2.72k | offset += 1; |
535 | 2.72k | vp_length -= 1; |
536 | | |
537 | 2.72k | switch (code) { |
538 | | |
539 | 59 | case VP_ATN_EC_16 : /* ATN */ |
540 | 59 | if (cotp_decode_atn) { |
541 | 0 | uint16_t sum; |
542 | | /* if an alternate OSI checksum is present in the currently unprocessed |
543 | | * VP section to the checksum algorithm has to know. |
544 | | * this may be the case for backward compatible CR TPDU */ |
545 | 0 | if (!offset_iso8073_checksum) { |
546 | | /* search following parameters in VP part for ISO checksum */ |
547 | 0 | for (i = offset + length; i < vp_length;) { |
548 | 0 | tmp_code = tvb_get_uint8(tvb, i++); |
549 | 0 | tmp_len = tvb_get_uint8(tvb, i++); |
550 | 0 | if (tmp_code == VP_CHECKSUM) { |
551 | 0 | offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */ |
552 | 0 | break; |
553 | 0 | } |
554 | 0 | i += tmp_len; |
555 | 0 | } |
556 | 0 | } |
557 | 0 | sum = check_atn_ec_16(tvb, tpdu_len , offset, |
558 | 0 | offset_iso8073_checksum, |
559 | 0 | pinfo->dst.len, (const uint8_t *)pinfo->dst.data, |
560 | 0 | pinfo->src.len, (const uint8_t *)pinfo->src.data); |
561 | 0 | proto_tree_add_checksum(tree, tvb, offset, hf_cotp_atn_extended_checksum16, hf_cotp_atn_extended_checksum_status, &ei_cotp_atn_extended_checksum, |
562 | 0 | pinfo, sum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO); |
563 | 59 | } else { |
564 | 59 | proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>"); |
565 | 59 | } |
566 | 59 | offset += length; |
567 | 59 | vp_length -= length; |
568 | 59 | break; |
569 | | |
570 | 107 | case VP_ATN_EC_32 : /* ATN */ |
571 | 107 | if (cotp_decode_atn) { |
572 | 0 | uint32_t sum; |
573 | | /* if an alternate OSI checksum is present in the currently unprocessed |
574 | | * VP section the checksum algorithm has to know. |
575 | | * this may be the case for backward compatible CR TPDU */ |
576 | 0 | if (!offset_iso8073_checksum) { |
577 | | /* search following parameters in VP part for ISO checksum */ |
578 | 0 | for (i = offset + length; i < vp_length;) { |
579 | 0 | tmp_code = tvb_get_uint8(tvb, i++); |
580 | 0 | tmp_len = tvb_get_uint8(tvb, i++); |
581 | 0 | if (tmp_code == VP_CHECKSUM) { |
582 | 0 | offset_iso8073_checksum = i; /* save ISO 8073 checksum offset for ATN extended checksum calculation */ |
583 | 0 | break; |
584 | 0 | } |
585 | 0 | i += tmp_len; |
586 | 0 | } |
587 | 0 | } |
588 | 0 | sum = check_atn_ec_32(tvb, tpdu_len , offset, |
589 | 0 | offset_iso8073_checksum, |
590 | 0 | pinfo->dst.len, (const uint8_t *)pinfo->dst.data, |
591 | 0 | pinfo->src.len, (const uint8_t *)pinfo->src.data); |
592 | 0 | proto_tree_add_checksum(tree, tvb, offset, hf_cotp_atn_extended_checksum32, hf_cotp_atn_extended_checksum_status, &ei_cotp_atn_extended_checksum, |
593 | 0 | pinfo, sum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO); |
594 | 107 | } else { |
595 | 107 | proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>"); |
596 | 107 | } |
597 | 107 | offset += length; |
598 | 107 | vp_length -= length; |
599 | 107 | break; |
600 | | |
601 | 11 | case VP_ACK_TIME: |
602 | 11 | proto_tree_add_item(tree, hf_cotp_ack_time, tvb, offset, length, ENC_BIG_ENDIAN); |
603 | 11 | offset += length; |
604 | 11 | vp_length -= length; |
605 | 11 | break; |
606 | | |
607 | 36 | case VP_RES_ERROR: |
608 | 36 | s = tvb_get_uint8(tvb, offset); |
609 | 36 | proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_target_value, tvb, offset, 1, s, "10^%u", s); |
610 | 36 | offset += 1; |
611 | 36 | vp_length -= 1; |
612 | | |
613 | 36 | s = tvb_get_uint8(tvb, offset); |
614 | 36 | proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_min_accept, tvb, offset, 1, s, "10^%u", s); |
615 | 36 | offset += 1; |
616 | 36 | vp_length -= 1; |
617 | | |
618 | 36 | s = tvb_get_uint8(tvb, offset); |
619 | 36 | proto_tree_add_uint_format_value(tree, hf_cotp_res_error_rate_tdsu, tvb, offset, 1, s, "2^%u", s); |
620 | 36 | offset += 1; |
621 | 36 | vp_length -= 1; |
622 | 36 | break; |
623 | | |
624 | 17 | case VP_PRIORITY: |
625 | 17 | proto_tree_add_item(tree, hf_cotp_vp_priority, tvb, offset, 2, ENC_BIG_ENDIAN); |
626 | 17 | offset += length; |
627 | 17 | vp_length -= length; |
628 | 17 | break; |
629 | | |
630 | 82 | case VP_TRANSIT_DEL: |
631 | 82 | proto_tree_add_item(tree, hf_cotp_transit_delay_targ_calling_called, tvb, offset, 2, ENC_BIG_ENDIAN); |
632 | 82 | offset += 2; |
633 | 82 | vp_length -= 2; |
634 | | |
635 | 82 | proto_tree_add_item(tree, hf_cotp_transit_delay_max_accept_calling_called, tvb, offset, 2, ENC_BIG_ENDIAN); |
636 | 82 | offset += 2; |
637 | 82 | vp_length -= 2; |
638 | | |
639 | 82 | proto_tree_add_item(tree, hf_cotp_transit_delay_targ_called_calling, tvb, offset, 2, ENC_BIG_ENDIAN); |
640 | 82 | offset += 2; |
641 | 82 | vp_length -= 2; |
642 | | |
643 | 82 | proto_tree_add_item(tree, hf_cotp_transit_delay_max_accept_called_calling, tvb, offset, 2, ENC_BIG_ENDIAN); |
644 | 82 | offset += 2; |
645 | 82 | vp_length -= 2; |
646 | 82 | break; |
647 | | |
648 | 29 | case VP_THROUGHPUT: |
649 | 29 | proto_tree_add_item(tree, hf_cotp_max_throughput_targ_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
650 | 29 | offset += 3; |
651 | 29 | length -= 3; |
652 | 29 | vp_length -= 3; |
653 | | |
654 | 29 | proto_tree_add_item(tree, hf_cotp_max_throughput_min_accept_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
655 | 29 | offset += 3; |
656 | 29 | length -= 3; |
657 | 29 | vp_length -= 3; |
658 | | |
659 | 29 | proto_tree_add_item(tree, hf_cotp_max_throughput_targ_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
660 | 29 | offset += 3; |
661 | 29 | length -= 3; |
662 | 29 | vp_length -= 3; |
663 | | |
664 | 29 | proto_tree_add_item(tree, hf_cotp_max_throughput_min_accept_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
665 | 29 | offset += 3; |
666 | 29 | length -= 3; |
667 | 29 | vp_length -= 3; |
668 | | |
669 | 29 | if (length != 0) { /* XXX - should be 0 or 12 */ |
670 | 29 | proto_tree_add_item(tree, hf_cotp_avg_throughput_targ_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
671 | 29 | offset += 3; |
672 | 29 | vp_length -= 3; |
673 | | |
674 | 29 | proto_tree_add_item(tree, hf_cotp_avg_throughput_min_accept_calling_called, tvb, offset, 3, ENC_BIG_ENDIAN); |
675 | 29 | offset += 3; |
676 | 29 | vp_length -= 3; |
677 | | |
678 | 29 | proto_tree_add_item(tree, hf_cotp_avg_throughput_targ_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
679 | 29 | offset += 3; |
680 | 29 | vp_length -= 3; |
681 | | |
682 | 29 | proto_tree_add_item(tree, hf_cotp_avg_throughput_min_accept_called_calling, tvb, offset, 3, ENC_BIG_ENDIAN); |
683 | 29 | offset += 3; |
684 | 29 | vp_length -= 3; |
685 | 29 | } |
686 | 29 | break; |
687 | | |
688 | 15 | case VP_SEQ_NR: |
689 | 15 | proto_tree_add_item(tree, hf_cotp_sequence_number, tvb, offset, 2, ENC_BIG_ENDIAN); |
690 | 15 | offset += length; |
691 | 15 | vp_length -= length; |
692 | 15 | break; |
693 | | |
694 | 10 | case VP_REASSIGNMENT: |
695 | 10 | proto_tree_add_item(tree, hf_cotp_reassignment_time, tvb, offset, 2, ENC_BIG_ENDIAN); |
696 | 10 | offset += length; |
697 | 10 | vp_length -= length; |
698 | 10 | break; |
699 | | |
700 | 68 | case VP_FLOW_CNTL: |
701 | 68 | proto_tree_add_item(tree, hf_cotp_lower_window_edge, tvb, offset, 4, ENC_BIG_ENDIAN); |
702 | 68 | offset += 4; |
703 | 68 | vp_length -= 4; |
704 | | |
705 | 68 | proto_tree_add_item(tree, hf_cotp_sequence_number, tvb, offset, 2, ENC_BIG_ENDIAN); |
706 | 68 | offset += 2; |
707 | 68 | vp_length -= 2; |
708 | | |
709 | 68 | proto_tree_add_item(tree, hf_cotp_credit, tvb, offset, 2, ENC_BIG_ENDIAN); |
710 | 68 | offset += 2; |
711 | 68 | vp_length -= 2; |
712 | | |
713 | 68 | break; |
714 | | |
715 | 17 | case VP_TPDU_SIZE: |
716 | 17 | c1 = tvb_get_uint8(tvb, offset) & 0x0F; |
717 | 17 | proto_tree_add_uint(tree, hf_cotp_tpdu_size, tvb, offset, 1, 1 << c1); |
718 | 17 | offset += length; |
719 | 17 | vp_length -= length; |
720 | 17 | break; |
721 | | |
722 | 31 | case VP_SRC_TSAP: |
723 | | /* if our preference is set to STRING or the TSAP is not printable, |
724 | | * add as bytes and hidden as string; otherwise vice-versa */ |
725 | 31 | if (tsap_display==TSAP_DISPLAY_STRING || |
726 | 31 | (tsap_display==TSAP_DISPLAY_AUTO && |
727 | 31 | tvb_ascii_isprint(tvb, offset, length))) { |
728 | 9 | proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length, |
729 | 9 | print_tsap(pinfo->pool, tvb, offset, length)); |
730 | 9 | hidden_item = proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, |
731 | 9 | offset, length, ENC_NA); |
732 | 9 | proto_item_set_hidden(hidden_item); |
733 | 22 | } else { |
734 | 22 | hidden_item = proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, |
735 | 22 | offset, length, |
736 | 22 | print_tsap(pinfo->pool, tvb, offset, length)); |
737 | 22 | proto_item_set_hidden(hidden_item); |
738 | 22 | proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, |
739 | 22 | length, ENC_NA); |
740 | 22 | } |
741 | 31 | offset += length; |
742 | 31 | vp_length -= length; |
743 | 31 | break; |
744 | | |
745 | 18 | case VP_DST_TSAP: |
746 | | /* if our preference is set to STRING or the TSAP is not printable, |
747 | | * add as bytes and hidden as string; otherwise vice-versa */ |
748 | 18 | if (tsap_display==TSAP_DISPLAY_STRING || |
749 | 18 | (tsap_display==TSAP_DISPLAY_AUTO && |
750 | 18 | tvb_ascii_isprint(tvb, offset, length))) { |
751 | 5 | proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length, |
752 | 5 | print_tsap(pinfo->pool, tvb, offset, length)); |
753 | 5 | hidden_item = proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, |
754 | 5 | offset, length, ENC_NA); |
755 | 5 | proto_item_set_hidden(hidden_item); |
756 | 13 | } else { |
757 | 13 | hidden_item = proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, |
758 | 13 | offset, length, |
759 | 13 | print_tsap(pinfo->pool, tvb, offset, length)); |
760 | 13 | proto_item_set_hidden(hidden_item); |
761 | 13 | proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, |
762 | 13 | length, ENC_NA); |
763 | 13 | } |
764 | 18 | offset += length; |
765 | 18 | vp_length -= length; |
766 | 18 | break; |
767 | | |
768 | 16 | case VP_CHECKSUM: |
769 | 16 | offset_iso8073_checksum = offset; /* save ISO 8073 checksum offset for ATN extended checksum calculation */ |
770 | | |
771 | 16 | if (tvb_get_ntohs(tvb, offset) == 0) { |
772 | | /* No checksum present */ |
773 | 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_NOT_PRESENT); |
774 | 14 | } else { |
775 | 14 | uint32_t calc_c0 = 0, calc_c1 = 0; |
776 | | |
777 | 14 | if (osi_calc_checksum(tvb, 0, tpdu_len, &calc_c0, &calc_c1)) { |
778 | | /* Successfully processed checksum, verify it */ |
779 | 14 | 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); |
780 | 14 | } else { |
781 | 0 | 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); |
782 | 0 | } |
783 | 14 | } |
784 | | |
785 | 16 | offset += length; |
786 | 16 | vp_length -= length; |
787 | 16 | break; |
788 | | |
789 | 8 | case VP_VERSION_NR: |
790 | 8 | proto_tree_add_item(tree, hf_cotp_vp_version_nr, tvb, offset, 1, ENC_NA); |
791 | 8 | offset += length; |
792 | 8 | vp_length -= length; |
793 | 8 | break; |
794 | | |
795 | 32 | case VP_OPT_SEL: |
796 | 32 | switch (class_option) { |
797 | | |
798 | 6 | case 1: |
799 | 6 | proto_tree_add_item(tree, hf_cotp_network_expedited_data, tvb, offset, 1, ENC_NA); |
800 | | |
801 | 6 | proto_tree_add_item(tree, hf_cotp_vp_opt_sel_class1_use, tvb, offset, 1, ENC_NA); |
802 | 6 | break; |
803 | | |
804 | 16 | case 4: |
805 | 16 | proto_tree_add_item(tree, hf_cotp_use_16_bit_checksum, tvb, offset, 1, ENC_NA); |
806 | 16 | break; |
807 | 32 | } |
808 | | |
809 | 32 | proto_tree_add_item(tree, hf_cotp_transport_expedited_data_transfer, tvb, offset, 1, ENC_NA); |
810 | 32 | offset += length; |
811 | 32 | vp_length -= length; |
812 | 32 | break; |
813 | | |
814 | 23 | case VP_PREF_MAX_TPDU_SIZE: |
815 | 23 | switch (length) { |
816 | | |
817 | 2 | case 1: |
818 | 2 | pref_max_tpdu_size = tvb_get_uint8(tvb, offset); |
819 | 2 | break; |
820 | | |
821 | 2 | case 2: |
822 | 2 | pref_max_tpdu_size = tvb_get_ntohs(tvb, offset); |
823 | 2 | break; |
824 | | |
825 | 2 | case 3: |
826 | 2 | pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset); |
827 | 2 | break; |
828 | | |
829 | 0 | case 4: |
830 | 0 | pref_max_tpdu_size = tvb_get_ntohl(tvb, offset); |
831 | 0 | break; |
832 | | |
833 | 17 | default: |
834 | 17 | proto_tree_add_expert_format(tree, pinfo, &ei_cotp_preferred_maximum_tpdu_size, tvb, offset, length, |
835 | 17 | "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)", length); |
836 | 17 | return false; |
837 | 23 | } |
838 | 6 | proto_tree_add_uint(tree, hf_cotp_preferred_maximum_tpdu_size, tvb, offset, length, pref_max_tpdu_size*128); |
839 | 6 | offset += length; |
840 | 6 | vp_length -= length; |
841 | 6 | break; |
842 | | |
843 | 8 | case VP_INACTIVITY_TIMER: |
844 | 8 | proto_tree_add_item(tree, hf_cotp_inactivity_timer, tvb, offset, length, ENC_BIG_ENDIAN); |
845 | 8 | offset += length; |
846 | 8 | vp_length -= length; |
847 | 8 | break; |
848 | | |
849 | 0 | case VP_PROTECTION: /* user-defined */ |
850 | 0 | case VP_PROTO_CLASS: /* todo */ |
851 | 1 | case VP_CLEARING_INFO: /* user-defined */ |
852 | 2.07k | default: /* unknown, no decoding */ |
853 | 2.07k | proto_tree_add_bytes_format_value(tree, hf_cotp_parameter_value, tvb, offset, length, NULL, "<not shown>"); |
854 | 2.07k | offset += length; |
855 | 2.07k | vp_length -= length; |
856 | 2.07k | break; |
857 | 2.72k | } |
858 | 2.72k | } /* while */ |
859 | | |
860 | 6.60k | return true; |
861 | 6.97k | } |
862 | | |
863 | | static const value_string cotp_cause_vals[] = { |
864 | | { 0, "Reason not specified" }, |
865 | | { 1, "Congestion at TSAP" }, |
866 | | { 2, "Session entity not attached to TSAP" }, |
867 | | { 3, "Address unknown" }, |
868 | | { 128+0, "Normal Disconnect" }, |
869 | | { 128+1, "Remote transport entity congestion" }, |
870 | | { 128+2, "Connection negotiation failed" }, |
871 | | { 128+3, "Duplicate source reference" }, |
872 | | { 128+4, "Mismatched references" }, |
873 | | { 128+5, "Protocol error" }, |
874 | | { 128+7, "Reference overflow" }, |
875 | | { 128+8, "Connection request refused" }, |
876 | | { 128+10, "Header or parameter length invalid" }, |
877 | | { 0, NULL } |
878 | | }; |
879 | | |
880 | | static int ositp_decode_DR(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
881 | | packet_info *pinfo, proto_tree *tree) |
882 | 164 | { |
883 | 164 | proto_tree *cotp_tree = NULL; |
884 | 164 | proto_item *ti = NULL; |
885 | 164 | uint16_t dst_ref, src_ref; |
886 | 164 | unsigned char reason; |
887 | 164 | unsigned tpdu_len; |
888 | | |
889 | | /* ATN TPDU's tend to be larger than normal OSI, |
890 | | * so nothing to do with respect to LI checks */ |
891 | 164 | if (li < LI_MIN_DR) |
892 | 49 | return -1; |
893 | | |
894 | | /* DR TPDUs can have user data, so they run to the end of the containing PDU */ |
895 | 115 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
896 | | |
897 | 115 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
898 | | |
899 | 115 | src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); |
900 | | |
901 | 115 | reason = tvb_get_uint8(tvb, offset + P_REASON_IN_DR); |
902 | | |
903 | 115 | pinfo->clnp_dstref = dst_ref; |
904 | 115 | pinfo->clnp_srcref = src_ref; |
905 | | |
906 | | /* the settings of the TCP srcport and destport are currently disabled, |
907 | | * for the following reasons: |
908 | | * a) only used for ISO conversation handling (which currently doesn't work) |
909 | | * b) will prevent "ISO on TCP" (RFC1006) packets from using |
910 | | * "follow TCP stream" correctly |
911 | | * |
912 | | * A future conversation handling might be able to handle different kinds of |
913 | | * conversations (TCP, ISO, TCP on TCP, ...), but in that case this has to be |
914 | | * fixed in any case. |
915 | | */ |
916 | | /*pinfo->srcport = src_ref;*/ |
917 | | /*pinfo->destport = dst_ref;*/ |
918 | 115 | if (try_val_to_str(reason, cotp_cause_vals) == NULL) |
919 | 53 | return -1; |
920 | | |
921 | 62 | col_append_fstr(pinfo->cinfo, COL_INFO, |
922 | 62 | "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x", src_ref, dst_ref); |
923 | | |
924 | 62 | if (tree) { |
925 | 60 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
926 | 60 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
927 | 60 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
928 | 60 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu); |
929 | 60 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, |
930 | 60 | dst_ref); |
931 | 60 | proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset + 4, 2, |
932 | 60 | src_ref); |
933 | 60 | proto_tree_add_item(cotp_tree, hf_cotp_cause, tvb, offset + 6, 1, ENC_NA); |
934 | 60 | } |
935 | 62 | offset += 7; |
936 | 62 | li -= 6; |
937 | | |
938 | 62 | if (tree) |
939 | 60 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
940 | 62 | offset += li; |
941 | | |
942 | 62 | expert_add_info_format(pinfo, ti, &ei_cotp_disconnect_request, "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref); |
943 | | |
944 | | /* User data */ |
945 | 62 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
946 | 62 | offset += tvb_captured_length_remaining(tvb, offset); |
947 | | /* we dissected all of the containing PDU */ |
948 | | |
949 | 62 | return offset; |
950 | | |
951 | 115 | } /* ositp_decode_DR */ |
952 | | |
953 | | static int ositp_decode_DT(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
954 | | packet_info *pinfo, proto_tree *tree, |
955 | | bool uses_inactive_subset, |
956 | | bool *subdissector_found) |
957 | 6.69k | { |
958 | 6.69k | proto_tree *cotp_tree = NULL; |
959 | 6.69k | proto_item *ti; |
960 | 6.69k | bool is_extended; |
961 | 6.69k | bool is_class_234; |
962 | 6.69k | cotp_conv_info_t *conv_info; |
963 | 6.69k | uint32_t dst_ref; |
964 | 6.69k | unsigned tpdu_nr; |
965 | 6.69k | bool fragment = false; |
966 | 6.69k | uint32_t fragment_length = 0; |
967 | 6.69k | tvbuff_t *next_tvb; |
968 | 6.69k | fragment_head *fd_head; |
969 | 6.69k | unsigned tpdu_len; |
970 | 6.69k | heur_dtbl_entry_t *hdtbl_entry; |
971 | | |
972 | | /* DT TPDUs have user data, so they run to the end of the containing PDU */ |
973 | 6.69k | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
974 | | |
975 | | /* The fixed part is 2 octets long, not including the length indicator, |
976 | | for classes 0 and 1; it is at least 4 octets long, not including |
977 | | the length indicator, for classes 2, 3, and 4. */ |
978 | 6.69k | is_class_234 = true; |
979 | | |
980 | | /* note: in the ATN the user is up to chose between 3 different checksums: |
981 | | * standard OSI, 2 or 4 octet extended checksum. |
982 | | * The differences for DT are that the TPDU headers may be enlarged by 2 |
983 | | * octets and that checksum related option codes and option lengths are |
984 | | * different. To not mess up the original OSI dissector LI checking was |
985 | | * implemented separately. */ |
986 | 6.69k | if (!cotp_decode_atn) { /* non ATN, plain OSI*/ |
987 | | /* VP_CHECKSUM is the only parameter allowed in the variable part. |
988 | | * (This means we may misdissect this if the packet is bad and |
989 | | * contains other parameters.). |
990 | | |
991 | | * XXX - not true; ISO/IEC 8073:1997 (E) says that "if the use of |
992 | | * non-blocking expedited data transfer service is negotiated (class |
993 | | * 4 only), the variable part shall contain the ED-TPDU-NR for the |
994 | | * first DT-TPDU created from a T-DATA request subsequent to the |
995 | | * T-EXPEDITED DATA request". */ |
996 | 6.69k | switch (li) { |
997 | | |
998 | 20 | case LI_NORMAL_DT_WITH_CHECKSUM : |
999 | 20 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) |
1000 | 20 | return -1; |
1001 | | /* FALLTHROUGH */ |
1002 | | |
1003 | 725 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
1004 | 725 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1005 | 725 | if (tpdu_nr & 0x80) |
1006 | 249 | tpdu_nr = tpdu_nr & 0x7F; |
1007 | 476 | else |
1008 | 476 | fragment = true; |
1009 | 725 | is_extended = false; |
1010 | 725 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1011 | 725 | break; |
1012 | | |
1013 | 19 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
1014 | 19 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) |
1015 | 19 | return -1; |
1016 | | /* FALLTHROUGH */ |
1017 | | |
1018 | 186 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1019 | 186 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1020 | 186 | if (tpdu_nr & 0x80000000) |
1021 | 55 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1022 | 131 | else |
1023 | 131 | fragment = true; |
1024 | 186 | is_extended = true; |
1025 | 186 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1026 | 186 | break; |
1027 | | |
1028 | 5.52k | case LI_NORMAL_DT_CLASS_01 : |
1029 | 5.52k | is_class_234 = false; |
1030 | 5.52k | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_0_1); |
1031 | 5.52k | if (tpdu_nr & 0x80) |
1032 | 1.93k | tpdu_nr = tpdu_nr & 0x7F; |
1033 | 3.59k | else |
1034 | 3.59k | fragment = true; |
1035 | 5.52k | is_extended = false; |
1036 | | /* For these classes the DST_REF is not included, we have to get |
1037 | | * it from the underlying transport and generate a frag id. */ |
1038 | 5.52k | conv_info = get_cotp_conv_info(pinfo); |
1039 | 5.52k | dst_ref = conv_info->fwd->ref; // Note this may default to zero if not set |
1040 | 5.52k | break; |
1041 | | |
1042 | 211 | default : /* bad TPDU */ |
1043 | 211 | return -1; |
1044 | 6.69k | } /* li */ |
1045 | 6.69k | } else { |
1046 | | /* check ATN class4 TPDU's here */ |
1047 | | |
1048 | | /* check packet length indicators of DaTa(DT) TPDU |
1049 | | * note: use of checksum depends on the selected RER |
1050 | | * (high:non-use medium:16-bit OSI/16-bit ext.ATN low:32-bit ext. ATN) |
1051 | | * |
1052 | | * note: sole use of TP4 class in the ATN |
1053 | | * note: normal/extended TPDU numbering is negociable */ |
1054 | 0 | switch (li) { |
1055 | | |
1056 | | /* normal DT with 2 octets of OSI or of ATN Extended Checksum */ |
1057 | 0 | case LI_NORMAL_DT_WITH_CHECKSUM : |
1058 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM && |
1059 | 0 | tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16) |
1060 | 0 | return -1; |
1061 | | /* FALLTHROUGH */ |
1062 | | |
1063 | 0 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
1064 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1065 | 0 | if (tpdu_nr & 0x80) |
1066 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1067 | 0 | else |
1068 | 0 | fragment = true; |
1069 | 0 | is_extended = false; |
1070 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1071 | 0 | break; |
1072 | | |
1073 | | /* extended DT with 2 octets of OSI or of ATN Extended Checksum */ |
1074 | 0 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
1075 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM && |
1076 | 0 | tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16) |
1077 | 0 | return -1; |
1078 | | /* FALLTHROUGH */ |
1079 | | |
1080 | 0 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1081 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1082 | 0 | if (tpdu_nr & 0x80000000) |
1083 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1084 | 0 | else |
1085 | 0 | fragment = true; |
1086 | 0 | is_extended = true; |
1087 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1088 | 0 | break; |
1089 | | |
1090 | | /* normal DT with ATN Extended Checksum (4 octets)*/ |
1091 | 0 | case LI_ATN_NORMAL_DT_WITH_CHECKSUM : |
1092 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32) |
1093 | 0 | return -1; |
1094 | | |
1095 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1096 | |
|
1097 | 0 | if (tpdu_nr & 0x80) |
1098 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1099 | 0 | else |
1100 | 0 | fragment = true; |
1101 | 0 | is_extended = false; |
1102 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1103 | 0 | break; |
1104 | | |
1105 | | /* extended DT with 4 octets ATN Extended Checksum */ |
1106 | 0 | case LI_ATN_EXTENDED_DT_WITH_CHECKSUM: |
1107 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32) |
1108 | 0 | return -1; |
1109 | | |
1110 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1111 | 0 | if (tpdu_nr & 0x80000000) |
1112 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1113 | 0 | else |
1114 | 0 | fragment = true; |
1115 | 0 | is_extended = true; |
1116 | 0 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1117 | 0 | break; |
1118 | | |
1119 | 0 | default : /* bad TPDU */ |
1120 | 0 | return -1; |
1121 | 0 | } /* li */ |
1122 | 0 | } /* cotp_decode_atn */ |
1123 | | |
1124 | 6.33k | pinfo->clnp_dstref = dst_ref; |
1125 | | |
1126 | 6.33k | pinfo->fragmented = fragment; |
1127 | 6.33k | if (is_class_234 || conv_info->fwd->ref_set) { |
1128 | 845 | col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x", |
1129 | 845 | tpdu_nr, dst_ref); |
1130 | 5.48k | } else { |
1131 | 5.48k | col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u)", tpdu_nr); |
1132 | 5.48k | } |
1133 | | |
1134 | 6.33k | if (tree) { |
1135 | 6.33k | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1136 | 6.33k | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1137 | 6.33k | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1138 | 6.33k | } |
1139 | 6.33k | offset += 1; |
1140 | | |
1141 | 6.33k | if (tree) { |
1142 | 6.33k | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1143 | 6.33k | } |
1144 | 6.33k | offset += 1; |
1145 | 6.33k | li -= 1; |
1146 | | |
1147 | 6.33k | if (is_class_234) { |
1148 | 831 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1149 | 831 | offset += 2; |
1150 | 831 | li -= 2; |
1151 | 5.50k | } else if (conv_info->fwd->ref_set) { |
1152 | 14 | ti = proto_tree_add_uint (cotp_tree, hf_cotp_destref, tvb, offset, 0, |
1153 | 14 | conv_info->fwd->ref); |
1154 | 14 | proto_item_set_generated (ti); |
1155 | 14 | } |
1156 | | |
1157 | 6.33k | if (is_extended) { |
1158 | 182 | if (tree) { |
1159 | 182 | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, |
1160 | 182 | 4, tpdu_nr); |
1161 | 182 | proto_tree_add_item(cotp_tree, hf_cotp_eot_extended, tvb, offset, 4, |
1162 | 182 | ENC_BIG_ENDIAN); |
1163 | 182 | } |
1164 | 182 | offset += 4; |
1165 | 182 | li -= 4; |
1166 | 6.15k | } else { |
1167 | 6.15k | if (tree) { |
1168 | 6.15k | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1, |
1169 | 6.15k | tpdu_nr); |
1170 | 6.15k | proto_tree_add_item(cotp_tree, hf_cotp_eot, tvb, offset, 1, |
1171 | 6.15k | ENC_BIG_ENDIAN); |
1172 | 6.15k | } |
1173 | 6.15k | offset += 1; |
1174 | 6.15k | li -= 1; |
1175 | 6.15k | } |
1176 | | |
1177 | 6.33k | if (tree) |
1178 | 6.33k | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1179 | 6.33k | offset += li; |
1180 | | |
1181 | 6.33k | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1182 | 6.33k | fragment_length = tvb_captured_length(next_tvb); |
1183 | 6.33k | if (fragment) { |
1184 | 4.09k | col_append_fstr(pinfo->cinfo, COL_INFO, " [COTP fragment, %u byte%s]", |
1185 | 4.09k | fragment_length, plurality(fragment_length, "", "s")); |
1186 | 4.09k | } else { |
1187 | 2.23k | col_append_str(pinfo->cinfo, COL_INFO, " EOT"); |
1188 | 2.23k | } |
1189 | | |
1190 | 6.33k | if (cotp_reassemble) { |
1191 | | /* |
1192 | | * XXX - these sequence numbers are connection sequence number, |
1193 | | * not segment sequence numbers - the first segment of a |
1194 | | * segmented packet doesn't have a specific sequence number (e.g., 0 |
1195 | | * or 1), it has whatever the appropriate sequence number is for |
1196 | | * it in the connection. |
1197 | | * |
1198 | | * For now, we assume segments arrive in order, and just supply |
1199 | | * the negation of the EOT flag as the "more flags" argument. |
1200 | | * We should probably handle out-of-order packets separately, |
1201 | | * so that we can deliver them in order even when *not* |
1202 | | * reassembling. |
1203 | | * |
1204 | | * Note also that TP0 has no sequence number, and relies on |
1205 | | * the protocol atop which it runs to guarantee in-order delivery. |
1206 | | * |
1207 | | * Class 2-4 should do something similar to Class 0/1 in obtaining a |
1208 | | * unique fragment id, if it's possible for more than one reassembly |
1209 | | * for a given dst_ref to complete in the same frame. |
1210 | | */ |
1211 | 6.33k | uint32_t frag_id; |
1212 | 6.33k | if (is_class_234) { |
1213 | 831 | frag_id = dst_ref; |
1214 | 5.50k | } else { |
1215 | 5.50k | frag_id = get_cotp_frag_id(pinfo, conv_info->fwd, fragment); |
1216 | 5.50k | } |
1217 | 6.33k | fd_head = fragment_add_seq_next(&cotp_reassembly_table, next_tvb, 0, pinfo, |
1218 | 6.33k | frag_id, NULL, fragment_length, fragment); |
1219 | 6.33k | if (fd_head && fd_head->next) { |
1220 | | /* don't use -1 if fragment length is zero (throws Exception) */ |
1221 | 1.21k | proto_tree_add_bytes_format(cotp_tree, hf_cotp_segment_data, tvb, offset, (fragment_length) ? -1 : 0, |
1222 | 1.21k | NULL, "COTP segment data (%u byte%s)", fragment_length, |
1223 | 1.21k | plurality(fragment_length, "", "s")); |
1224 | | |
1225 | 1.21k | if (!fragment) { |
1226 | | /* This is the last packet */ |
1227 | 1.21k | next_tvb = process_reassembled_data (next_tvb, offset, pinfo, |
1228 | 1.21k | "Reassembled COTP", fd_head, |
1229 | 1.21k | &cotp_frag_items, NULL, tree); |
1230 | 1.21k | } else if (pinfo->num != fd_head->reassembled_in) { |
1231 | | /* Add a "Reassembled in" link if not reassembled in this frame */ |
1232 | 0 | proto_tree_add_uint(cotp_tree, *(cotp_frag_items.hf_reassembled_in), |
1233 | 0 | next_tvb, 0, 0, fd_head->reassembled_in); |
1234 | 0 | } |
1235 | 1.21k | pinfo->fragmented = fragment; |
1236 | 1.21k | } |
1237 | 6.33k | } |
1238 | | |
1239 | 6.33k | if (uses_inactive_subset) { |
1240 | 6.29k | if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb, |
1241 | 6.29k | pinfo, tree, &hdtbl_entry, NULL)) { |
1242 | 1.45k | *subdissector_found = true; |
1243 | 4.84k | } else { |
1244 | | /* Fill in other Dissectors using inactive subset here */ |
1245 | 4.84k | call_data_dissector(next_tvb, pinfo, tree); |
1246 | 4.84k | } |
1247 | 6.29k | } else { |
1248 | | /* |
1249 | | * We dissect payload if one of the following is true: |
1250 | | * |
1251 | | * - Reassembly option for COTP in preferences is unchecked |
1252 | | * - Reassembly option is checked and this packet is the last fragment |
1253 | | */ |
1254 | 38 | if (!cotp_reassemble || !fragment) { |
1255 | 35 | if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo, |
1256 | 35 | tree, &hdtbl_entry, NULL)) { |
1257 | 3 | *subdissector_found = true; |
1258 | 32 | } else { |
1259 | 32 | call_data_dissector(next_tvb, pinfo, tree); |
1260 | 32 | } |
1261 | 35 | } |
1262 | 38 | } |
1263 | | |
1264 | 6.33k | offset += tvb_captured_length_remaining(tvb, offset); |
1265 | | /* we dissected all of the containing PDU */ |
1266 | | |
1267 | 6.33k | return offset; |
1268 | | |
1269 | 6.69k | } /* ositp_decode_DT */ |
1270 | | |
1271 | | static int ositp_decode_ED(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1272 | | packet_info *pinfo, proto_tree *tree, |
1273 | | bool uses_inactive_subset, |
1274 | | bool *subdissector_found) |
1275 | 137 | { |
1276 | 137 | proto_tree *cotp_tree = NULL; |
1277 | 137 | proto_item *ti; |
1278 | 137 | bool is_extended; |
1279 | 137 | uint16_t dst_ref; |
1280 | 137 | unsigned tpdu_nr; |
1281 | 137 | tvbuff_t *next_tvb; |
1282 | 137 | unsigned tpdu_len; |
1283 | 137 | heur_dtbl_entry_t *hdtbl_entry; |
1284 | | |
1285 | | /* ED TPDUs have user data, so they run to the end of the containing PDU */ |
1286 | 137 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
1287 | | |
1288 | | /* note: in the ATN the user is up to chose between 3 different checksums: |
1289 | | * standard OSI, 2 or 4 octet extended checksum. |
1290 | | * The differences for ED (as for DT) are that the TPDU headers may be |
1291 | | * enlarged by 2 octets and that checksum related option codes and option |
1292 | | * lengths are different. To not mess up the original OSI dissector LI |
1293 | | * checking was implemented separately. |
1294 | | * |
1295 | | * note: this could not be tested, because no sample was avail for expedited |
1296 | | * data */ |
1297 | 137 | if (!cotp_decode_atn) { /* non ATN, plain OSI*/ |
1298 | | /* ED TPDUs are never fragmented */ |
1299 | | |
1300 | | /* VP_CHECKSUM is the only parameter allowed in the variable part. |
1301 | | (This means we may misdissect this if the packet is bad and |
1302 | | contains other parameters.) */ |
1303 | 137 | switch (li) { |
1304 | | |
1305 | 4 | case LI_NORMAL_DT_WITH_CHECKSUM : |
1306 | 4 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) |
1307 | 4 | return -1; |
1308 | | /* FALLTHROUGH */ |
1309 | | |
1310 | 97 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
1311 | 97 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1312 | 97 | if (tpdu_nr & 0x80) |
1313 | 31 | tpdu_nr = tpdu_nr & 0x7F; |
1314 | 66 | else |
1315 | 66 | return -1; |
1316 | 31 | is_extended = false; |
1317 | 31 | break; |
1318 | | |
1319 | 1 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
1320 | 1 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) |
1321 | 1 | return -1; |
1322 | | /* FALLTHROUGH */ |
1323 | | |
1324 | 11 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1325 | 11 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1326 | 11 | if (tpdu_nr & 0x80000000) |
1327 | 2 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1328 | 9 | else |
1329 | 9 | return -1; |
1330 | 2 | is_extended = true; |
1331 | 2 | break; |
1332 | | |
1333 | 24 | default : /* bad TPDU */ |
1334 | 24 | return -1; |
1335 | 137 | } /* li */ |
1336 | 137 | } else { |
1337 | | /* check packet length indicators of ATN Expedited Data (ED) TPDU |
1338 | | * note: use of checksum depends on the selected RER |
1339 | | * (high:non-use medium:16-bit OSI/16-bit ext.ATN low:32-bit ext. ATN) |
1340 | | * |
1341 | | * note: sole use of TP4 class in the ATN |
1342 | | * note: normal/extended TPDU numbering is negociable */ |
1343 | 0 | switch (li) { |
1344 | | |
1345 | 0 | case LI_NORMAL_DT_WITHOUT_CHECKSUM : |
1346 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1347 | 0 | if (tpdu_nr & 0x80) |
1348 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1349 | 0 | else |
1350 | 0 | return -1; |
1351 | 0 | is_extended = false; |
1352 | 0 | break; |
1353 | | |
1354 | 0 | case LI_NORMAL_DT_WITH_CHECKSUM : |
1355 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) && |
1356 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16)) |
1357 | 0 | return -1; |
1358 | | |
1359 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1360 | 0 | if (tpdu_nr & 0x80) |
1361 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1362 | 0 | else |
1363 | 0 | return -1; |
1364 | 0 | is_extended = false; |
1365 | 0 | break; |
1366 | | |
1367 | 0 | case LI_ATN_NORMAL_DT_WITH_CHECKSUM : |
1368 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32) |
1369 | 0 | return -1; |
1370 | | |
1371 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1372 | 0 | if (tpdu_nr & 0x80) |
1373 | 0 | tpdu_nr = tpdu_nr & 0x7F; |
1374 | 0 | else |
1375 | 0 | return -1; |
1376 | 0 | is_extended = false; |
1377 | 0 | break; |
1378 | | |
1379 | 0 | case LI_EXTENDED_DT_WITHOUT_CHECKSUM : |
1380 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1381 | 0 | if (tpdu_nr & 0x80000000) |
1382 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1383 | 0 | else |
1384 | 0 | return -1; |
1385 | 0 | is_extended = true; |
1386 | 0 | break; |
1387 | | |
1388 | 0 | case LI_EXTENDED_DT_WITH_CHECKSUM : |
1389 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) && |
1390 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16)) |
1391 | 0 | return -1; |
1392 | | |
1393 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1394 | 0 | if (tpdu_nr & 0x80000000) |
1395 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1396 | 0 | else |
1397 | 0 | return -1; |
1398 | 0 | is_extended = true; |
1399 | 0 | break; |
1400 | | |
1401 | 0 | case LI_ATN_EXTENDED_DT_WITH_CHECKSUM : |
1402 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32) |
1403 | 0 | return -1; |
1404 | | |
1405 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1406 | 0 | if (tpdu_nr & 0x80000000) |
1407 | 0 | tpdu_nr = tpdu_nr & 0x7FFFFFFF; |
1408 | 0 | else |
1409 | 0 | return -1; |
1410 | 0 | is_extended = true; |
1411 | 0 | break; |
1412 | | |
1413 | 0 | default : /* bad TPDU */ |
1414 | 0 | return -1; |
1415 | 0 | } /* li */ |
1416 | 0 | } /* cotp_decode_atn */ |
1417 | | |
1418 | 33 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1419 | 33 | pinfo->clnp_dstref = dst_ref; |
1420 | | |
1421 | 33 | col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x", |
1422 | 33 | tpdu_nr, dst_ref); |
1423 | | |
1424 | 33 | if (tree) { |
1425 | 33 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1426 | 33 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1427 | 33 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1428 | 33 | } |
1429 | 33 | offset += 1; |
1430 | | |
1431 | 33 | if (tree) { |
1432 | 33 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1433 | 33 | } |
1434 | 33 | offset += 1; |
1435 | 33 | li -= 1; |
1436 | | |
1437 | 33 | if (tree) |
1438 | 33 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1439 | 33 | offset += 2; |
1440 | 33 | li -= 2; |
1441 | | |
1442 | 33 | if (is_extended) { |
1443 | 2 | if (tree) { |
1444 | 2 | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, |
1445 | 2 | 4, tpdu_nr); |
1446 | 2 | } |
1447 | 2 | offset += 4; |
1448 | 2 | li -= 4; |
1449 | 31 | } else { |
1450 | 31 | if (tree) { |
1451 | 31 | proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1, |
1452 | 31 | tpdu_nr); |
1453 | 31 | } |
1454 | 31 | offset += 1; |
1455 | 31 | li -= 1; |
1456 | 31 | } |
1457 | | |
1458 | 33 | if (tree) |
1459 | 33 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1460 | 33 | offset += li; |
1461 | | |
1462 | | /* |
1463 | | * Tell subdissectors that this is in an ED packet? |
1464 | | */ |
1465 | 33 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1466 | 33 | if (uses_inactive_subset) { |
1467 | 25 | if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb, |
1468 | 25 | pinfo, tree, &hdtbl_entry, NULL)) { |
1469 | 8 | *subdissector_found = true; |
1470 | 17 | } else { |
1471 | | /* Fill in other Dissectors using inactive subset here */ |
1472 | 17 | call_data_dissector(next_tvb, pinfo, tree); |
1473 | 17 | } |
1474 | 25 | } else { |
1475 | | /* |
1476 | | * ED TPDUs are never fragmented |
1477 | | */ |
1478 | 8 | if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo, |
1479 | 8 | tree, &hdtbl_entry, NULL)) { |
1480 | 2 | *subdissector_found = true; |
1481 | 6 | } else { |
1482 | 6 | call_data_dissector(next_tvb, pinfo, tree); |
1483 | 6 | } |
1484 | 8 | } |
1485 | | |
1486 | 33 | offset += tvb_captured_length_remaining(tvb, offset); |
1487 | | /* we dissected all of the containing PDU */ |
1488 | | |
1489 | 33 | return offset; |
1490 | | |
1491 | 137 | } /* ositp_decode_ED */ |
1492 | | |
1493 | | static int ositp_decode_RJ(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1494 | | uint8_t cdt, packet_info *pinfo, proto_tree *tree) |
1495 | 64 | { |
1496 | 64 | proto_tree *cotp_tree; |
1497 | 64 | proto_item *ti; |
1498 | 64 | proto_item *item = NULL; |
1499 | 64 | uint16_t dst_ref; |
1500 | 64 | unsigned tpdu_nr; |
1501 | 64 | uint16_t credit = 0; |
1502 | | |
1503 | | /* note: in the ATN the user is up to chose between 3 different checksums: |
1504 | | * standard OSI, 2 or 4 octet extended checksum. |
1505 | | * The difference for RJ is that the TPDU header may be enlarged by 2 octets |
1506 | | * for checksum parameters are not going to be checked here */ |
1507 | 64 | if (!cotp_decode_atn) { /* non ATN, plain OSI */ |
1508 | 64 | switch(li) { |
1509 | 19 | case LI_NORMAL_RJ : |
1510 | 19 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1511 | 19 | break; |
1512 | 0 | case LI_EXTENDED_RJ : |
1513 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1514 | 0 | credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ); |
1515 | 0 | break; |
1516 | 45 | default : |
1517 | 45 | return -1; |
1518 | 64 | } |
1519 | 64 | } else { |
1520 | 0 | switch(li) { |
1521 | | /* normal with 2 octets of OSI or ATN checksum */ |
1522 | 0 | case LI_NORMAL_RJ : |
1523 | | /* with 4 octets of ATN checksum */ |
1524 | 0 | case LI_ATN_NORMAL_RJ : |
1525 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1526 | 0 | break; |
1527 | | /* extended with 2 octets of OSI or ATN checksum */ |
1528 | 0 | case LI_EXTENDED_RJ : |
1529 | | /* with 4 octets of ATN checksum */ |
1530 | 0 | case LI_ATN_EXTENDED_RJ : |
1531 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1532 | 0 | credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ); |
1533 | 0 | break; |
1534 | 0 | default : |
1535 | 0 | return -1; |
1536 | 0 | } |
1537 | 0 | } |
1538 | | |
1539 | 19 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1540 | 19 | pinfo->clnp_dstref = dst_ref; |
1541 | | |
1542 | 19 | col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x", |
1543 | 19 | tpdu_nr, dst_ref); |
1544 | | |
1545 | 19 | if (tree) { |
1546 | 19 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1547 | 19 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1548 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1549 | 19 | item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, |
1550 | 19 | tpdu); |
1551 | 19 | if (li == LI_NORMAL_RJ) { |
1552 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_credit_cdt, tvb, offset + 1, 1, cdt); |
1553 | 19 | } |
1554 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, |
1555 | 19 | dst_ref); |
1556 | 19 | if (li == LI_NORMAL_RJ) |
1557 | 19 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset + 4, |
1558 | 19 | 1, tpdu_nr); |
1559 | 0 | else { |
1560 | 0 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb, |
1561 | 0 | offset + 4, 4, tpdu_nr); |
1562 | 0 | proto_tree_add_uint(cotp_tree, hf_cotp_credit, tvb, offset + 8, 2, credit); |
1563 | 0 | } |
1564 | 19 | } |
1565 | | |
1566 | 19 | offset += li + 1; |
1567 | | |
1568 | 19 | expert_add_info_format(pinfo, item, &ei_cotp_reject, "Reject(RJ): -> 0x%x", dst_ref); |
1569 | | |
1570 | 19 | return offset; |
1571 | | |
1572 | 64 | } /* ositp_decode_RJ */ |
1573 | | |
1574 | | static int ositp_decode_CR_CC(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1575 | | packet_info *pinfo, proto_tree *tree, |
1576 | | bool uses_inactive_subset, |
1577 | | bool *subdissector_found) |
1578 | 305 | { |
1579 | | /* note: in the ATN the user is up to chose between 3 different checksums: |
1580 | | * standard OSI, 2 or 4 octet extended checksum. |
1581 | | * Nothing has to be done here, for all ATN specifics are handled in VP. */ |
1582 | | |
1583 | | /* CC & CR decoding in the same function */ |
1584 | | |
1585 | 305 | proto_tree *cotp_tree = NULL; |
1586 | 305 | proto_item *ti; |
1587 | 305 | proto_item *item = NULL; |
1588 | 305 | uint16_t dst_ref, src_ref; |
1589 | 305 | uint8_t class_option; |
1590 | 305 | tvbuff_t *next_tvb; |
1591 | 305 | unsigned tpdu_len; |
1592 | 305 | heur_dtbl_entry_t *hdtbl_entry; |
1593 | 305 | static int * const class_options[] = { |
1594 | 305 | &hf_cotp_class, |
1595 | 305 | &hf_cotp_opts_extended_formats, |
1596 | 305 | &hf_cotp_opts_no_explicit_flow_control, |
1597 | 305 | NULL, |
1598 | 305 | }; |
1599 | | |
1600 | 305 | src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); |
1601 | | |
1602 | 305 | class_option = tvb_get_uint8(tvb, offset + P_CLASS_OPTION); |
1603 | 305 | if (((class_option & 0xF0) >> 4) > 4) /* class 0..4 allowed */ |
1604 | 44 | return -1; |
1605 | | |
1606 | | /* CR and CC TPDUs can have user data, so they run to the end of the |
1607 | | * containing PDU */ |
1608 | 261 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
1609 | | |
1610 | 261 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1611 | 261 | pinfo->clnp_srcref = src_ref; |
1612 | 261 | pinfo->clnp_dstref = dst_ref; |
1613 | | |
1614 | 261 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1615 | 261 | "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x", |
1616 | 261 | (tpdu == CR_TPDU) ? "CR" : "CC", src_ref, dst_ref); |
1617 | | |
1618 | 261 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1619 | 261 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1620 | 261 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1621 | 261 | offset += 1; |
1622 | | |
1623 | 261 | item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1624 | 261 | offset += 1; |
1625 | 261 | li -= 1; |
1626 | | |
1627 | 261 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1628 | 261 | offset += 2; |
1629 | 261 | li -= 2; |
1630 | | |
1631 | 261 | proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref); |
1632 | 261 | offset += 2; |
1633 | 261 | li -= 2; |
1634 | | |
1635 | | /* expert info, but only if not encapsulated in TCP/SMB */ |
1636 | | /* XXX - the best way to detect seems to be if we have a port set */ |
1637 | 261 | if (pinfo->destport == 0) { |
1638 | 195 | 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); |
1639 | 195 | } else { |
1640 | 66 | cotp_conv_info_t *conv_info = get_cotp_conv_info(pinfo); |
1641 | 66 | conv_info->rev->ref = src_ref; |
1642 | 66 | conv_info->rev->ref_set = true; |
1643 | 66 | if (tpdu == CR_TPDU) { |
1644 | 39 | conv_info->fwd->ref = dst_ref; |
1645 | 39 | conv_info->fwd->ref_set = true; |
1646 | 39 | } |
1647 | 66 | } |
1648 | | |
1649 | 261 | proto_tree_add_bitmask_list(cotp_tree, tvb, offset, 1, class_options, ENC_NA); |
1650 | 261 | offset += 1; |
1651 | 261 | li -= 1; |
1652 | | |
1653 | 261 | if (li > 0) { |
1654 | | /* There's more data left, so we have the variable part. |
1655 | | |
1656 | | Microsoft's RDP hijacks the variable part of CR and CC PDUs |
1657 | | for their own user data (RDP runs atop Class 0, which doesn't |
1658 | | support user data). |
1659 | | |
1660 | | Try what heuristic dissectors we have. */ |
1661 | 252 | next_tvb = tvb_new_subset_length(tvb, offset, li); |
1662 | 252 | if (dissector_try_heuristic((tpdu == CR_TPDU) ? |
1663 | 155 | cotp_cr_heur_subdissector_list : |
1664 | 252 | cotp_cc_heur_subdissector_list, |
1665 | 252 | next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { |
1666 | | /* A subdissector claimed this, so it really belongs to them. */ |
1667 | 21 | *subdissector_found = true; |
1668 | 231 | } else { |
1669 | | /* No heuristic dissector claimed it, so dissect it as a regular |
1670 | | variable part. */ |
1671 | 231 | ositp_decode_var_part(tvb, offset, li, class_option, tpdu_len, pinfo, |
1672 | 231 | cotp_tree); |
1673 | 231 | } |
1674 | 252 | offset += li; |
1675 | 252 | } |
1676 | | |
1677 | | /* |
1678 | | * XXX - tell the subdissector that this is user data in a CR or |
1679 | | * CC packet rather than a DT packet? |
1680 | | */ |
1681 | 261 | if (tvb_captured_length_remaining(tvb, offset)) { |
1682 | 33 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1683 | 33 | if (!uses_inactive_subset){ |
1684 | 25 | if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb, pinfo, |
1685 | 25 | tree, &hdtbl_entry, NULL)) { |
1686 | 9 | *subdissector_found = true; |
1687 | 16 | } else { |
1688 | 16 | call_data_dissector(next_tvb, pinfo, tree); |
1689 | 16 | } |
1690 | 25 | } |
1691 | 8 | else |
1692 | 8 | call_data_dissector( next_tvb, pinfo, tree); |
1693 | 33 | offset += tvb_captured_length_remaining(tvb, offset); |
1694 | | /* we dissected all of the containing PDU */ |
1695 | 33 | } |
1696 | | |
1697 | 261 | return offset; |
1698 | | |
1699 | 305 | } /* ositp_decode_CR_CC */ |
1700 | | |
1701 | | static int ositp_decode_DC(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1702 | | packet_info *pinfo, proto_tree *tree) |
1703 | 29 | { |
1704 | 29 | proto_tree *cotp_tree = NULL; |
1705 | 29 | proto_item *ti; |
1706 | 29 | proto_item *item = NULL; |
1707 | 29 | uint16_t dst_ref, src_ref; |
1708 | 29 | unsigned tpdu_len; |
1709 | | |
1710 | | /* ATN may use checksums different from OSI */ |
1711 | | /* which may result in different TPDU header length. */ |
1712 | 29 | if (!cotp_decode_atn) { |
1713 | 29 | if (li > LI_MAX_DC) |
1714 | 13 | return -1; |
1715 | 29 | } else { |
1716 | 0 | if (li > LI_ATN_MAX_DC) |
1717 | 0 | return -1; |
1718 | 0 | } |
1719 | | |
1720 | | /* DC TPDUs have no user data, so the length indicator determines the |
1721 | | * length */ |
1722 | 16 | tpdu_len = li + 1; |
1723 | | |
1724 | 16 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1725 | 16 | src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF); |
1726 | 16 | pinfo->clnp_dstref = dst_ref; |
1727 | 16 | pinfo->clnp_srcref = src_ref; |
1728 | | |
1729 | 16 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1730 | 16 | "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x", src_ref, dst_ref); |
1731 | | |
1732 | 16 | if (tree) { |
1733 | 16 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1734 | 16 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1735 | 16 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1736 | 16 | } |
1737 | 16 | offset += 1; |
1738 | | |
1739 | 16 | if (tree) { |
1740 | 16 | item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1741 | 16 | } |
1742 | 16 | offset += 1; |
1743 | 16 | li -= 1; |
1744 | | |
1745 | 16 | if (tree) |
1746 | 16 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1747 | 16 | offset += 2; |
1748 | 16 | li -= 2; |
1749 | | |
1750 | 16 | if (tree) |
1751 | 16 | proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref); |
1752 | 16 | offset += 2; |
1753 | 16 | li -= 2; |
1754 | | |
1755 | 16 | if (tree) |
1756 | 16 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1757 | 16 | offset += li; |
1758 | | |
1759 | 16 | expert_add_info_format(pinfo, item, &ei_cotp_disconnect_confirm, "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref); |
1760 | | |
1761 | 16 | return offset; |
1762 | | |
1763 | 29 | } /* ositp_decode_DC */ |
1764 | | |
1765 | | static int ositp_decode_AK(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1766 | | uint8_t cdt, packet_info *pinfo, proto_tree *tree) |
1767 | 101 | { |
1768 | 101 | proto_tree *cotp_tree = NULL; |
1769 | 101 | proto_item *ti; |
1770 | 101 | uint16_t dst_ref; |
1771 | 101 | unsigned tpdu_nr; |
1772 | 101 | uint16_t cdt_in_ak; |
1773 | 101 | unsigned tpdu_len; |
1774 | | |
1775 | 101 | if (!cotp_decode_atn) { |
1776 | 101 | if (li > LI_MAX_AK) |
1777 | 17 | return -1; |
1778 | 101 | } else { |
1779 | 0 | if (li > LI_ATN_MAX_AK) |
1780 | 0 | return -1; |
1781 | 0 | } |
1782 | | |
1783 | | /* AK TPDUs have no user data, so the length indicator determines the |
1784 | | * length */ |
1785 | 84 | tpdu_len = li + 1; |
1786 | | |
1787 | | /* is_LI_NORMAL_AK() works for normal ATN AK's, */ |
1788 | | /* for the TPDU header size may be enlarged by 2 octets */ |
1789 | 84 | if (is_LI_NORMAL_AK(li)) { |
1790 | | |
1791 | 63 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1792 | 63 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1793 | 63 | pinfo->clnp_dstref = dst_ref; |
1794 | | |
1795 | 63 | col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", |
1796 | 63 | tpdu_nr, dst_ref); |
1797 | | |
1798 | 63 | if (tree) { |
1799 | 62 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1800 | 62 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1801 | 62 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1802 | 62 | } |
1803 | 63 | offset += 1; |
1804 | | |
1805 | 63 | if (tree) { |
1806 | 62 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1807 | 62 | proto_tree_add_uint(cotp_tree, hf_cotp_credit_cdt, tvb, offset, 1, cdt); |
1808 | 62 | } |
1809 | 63 | offset += 1; |
1810 | 63 | li -= 1; |
1811 | | |
1812 | 63 | if (tree) |
1813 | 62 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1814 | 63 | offset += 2; |
1815 | 63 | li -= 2; |
1816 | | |
1817 | 63 | if (tree) { |
1818 | 62 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1, |
1819 | 62 | tpdu_nr); |
1820 | 62 | } |
1821 | 63 | offset += 1; |
1822 | 63 | li -= 1; |
1823 | | |
1824 | 63 | if (tree) |
1825 | 62 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1826 | 63 | offset += li; |
1827 | | |
1828 | 63 | } else { /* extended format */ |
1829 | | |
1830 | 21 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
1831 | 21 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1832 | 21 | cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK); |
1833 | 21 | pinfo->clnp_dstref = dst_ref; |
1834 | | |
1835 | 21 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1836 | 21 | "AK TPDU (%u) dst-ref: 0x%04x Credit: %u", |
1837 | 21 | tpdu_nr, dst_ref, cdt_in_ak); |
1838 | | |
1839 | 21 | if (tree) { |
1840 | 9 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
1841 | 9 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
1842 | 9 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
1843 | 9 | } |
1844 | 21 | offset += 1; |
1845 | | |
1846 | 21 | if (tree) { |
1847 | 9 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
1848 | 9 | } |
1849 | 21 | offset += 1; |
1850 | 21 | li -= 1; |
1851 | | |
1852 | 21 | if (tree) |
1853 | 9 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
1854 | 21 | offset += 2; |
1855 | 21 | li -= 2; |
1856 | | |
1857 | 21 | if (tree) { |
1858 | 9 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb, |
1859 | 9 | offset, 4, tpdu_nr); |
1860 | 9 | } |
1861 | 21 | offset += 4; |
1862 | 21 | li -= 4; |
1863 | | |
1864 | 21 | if (tree) { |
1865 | 9 | proto_tree_add_uint(cotp_tree, hf_cotp_credit, tvb, offset, 2, cdt_in_ak); |
1866 | 9 | } |
1867 | 21 | offset += 2; |
1868 | 21 | li -= 2; |
1869 | | |
1870 | 21 | if (tree) |
1871 | 9 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
1872 | 21 | offset += li; |
1873 | | |
1874 | 21 | } /* is_LI_NORMAL_AK */ |
1875 | | |
1876 | 84 | return offset; |
1877 | | |
1878 | 101 | } /* ositp_decode_AK */ |
1879 | | |
1880 | | static int ositp_decode_EA(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
1881 | | packet_info *pinfo, proto_tree *tree) |
1882 | 149 | { |
1883 | 149 | proto_tree *cotp_tree = NULL; |
1884 | 149 | proto_item *ti; |
1885 | 149 | bool is_extended; |
1886 | 149 | uint16_t dst_ref; |
1887 | 149 | unsigned tpdu_nr; |
1888 | 149 | unsigned tpdu_len; |
1889 | | |
1890 | | /* Due to different checksums in the ATN the TPDU header sizes |
1891 | | * as well as the checksum parameters may be different than plain OSI EA |
1892 | | * because these are heavily checked for EA these checks had to be |
1893 | | * re-implemented. |
1894 | | * note: this could not be tested, because no sample was avail for expedited |
1895 | | * data */ |
1896 | 149 | if (!cotp_decode_atn) { |
1897 | 149 | if (li > LI_MAX_EA) |
1898 | 63 | return -1; |
1899 | | |
1900 | | /* VP_CHECKSUM is the only parameter allowed in the variable part. |
1901 | | (This means we may misdissect this if the packet is bad and |
1902 | | contains other parameters.) */ |
1903 | 86 | switch (li) { |
1904 | | |
1905 | 8 | case LI_NORMAL_EA_WITH_CHECKSUM : |
1906 | 8 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM || |
1907 | 0 | tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 2) |
1908 | 8 | return -1; |
1909 | | /* FALLTHROUGH */ |
1910 | | |
1911 | 16 | case LI_NORMAL_EA_WITHOUT_CHECKSUM : |
1912 | 16 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1913 | 16 | is_extended = false; |
1914 | 16 | break; |
1915 | | |
1916 | 2 | case LI_EXTENDED_EA_WITH_CHECKSUM : |
1917 | 2 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM || |
1918 | 0 | tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) |
1919 | 2 | return -1; |
1920 | | /* FALLTHROUGH */ |
1921 | | |
1922 | 14 | case LI_EXTENDED_EA_WITHOUT_CHECKSUM : |
1923 | 14 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1924 | 14 | is_extended = true; |
1925 | 14 | break; |
1926 | | |
1927 | 46 | default : /* bad TPDU */ |
1928 | 46 | return -1; |
1929 | 86 | } /* li */ |
1930 | 86 | } else { /* cotp_decode_atn */ |
1931 | | /* check for ATN length: TPDU may be 2 octets longer due to checksum */ |
1932 | 0 | if (li > LI_ATN_MAX_EA) |
1933 | 0 | return -1; |
1934 | | |
1935 | 0 | switch (li) { |
1936 | | |
1937 | | /* extended TPDU numbering EA with no checksum */ |
1938 | 0 | case LI_NORMAL_EA_WITHOUT_CHECKSUM : |
1939 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1940 | 0 | is_extended = false; |
1941 | 0 | break; |
1942 | | |
1943 | | /* normal TPDU numbering EA with 2 octets of OSI or ATN extended |
1944 | | * checksum */ |
1945 | 0 | case LI_NORMAL_EA_WITH_CHECKSUM : |
1946 | | /* check checksum parameter (in VP) parameter code octet */ |
1947 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM) && |
1948 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_16)) |
1949 | 0 | return -1; |
1950 | | |
1951 | | /* check checksum parameter (in VP) length octet */ |
1952 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 2) |
1953 | 0 | return -1; |
1954 | | |
1955 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1956 | 0 | is_extended = false; |
1957 | 0 | break; |
1958 | | |
1959 | | /* normal TPDU numbering EA with 4 octets of ATN extended checksum */ |
1960 | 0 | case LI_ATN_NORMAL_EA_WITH_CHECKSUM : |
1961 | | /* check checksum parameter (in VP) parameter code octet */ |
1962 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT) != VP_ATN_EC_32) |
1963 | 0 | return -1; |
1964 | | |
1965 | | /* check checksum parameter (in VP) length octet */ |
1966 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_NDT + 1) != 4) |
1967 | 0 | return -1; |
1968 | | |
1969 | 0 | tpdu_nr = tvb_get_uint8(tvb, offset + P_TPDU_NR_234); |
1970 | 0 | is_extended = false; |
1971 | 0 | break; |
1972 | | |
1973 | | /* extended TPDU numbering EA with no checksum */ |
1974 | 0 | case LI_EXTENDED_EA_WITHOUT_CHECKSUM : |
1975 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1976 | 0 | is_extended = true; |
1977 | 0 | break; |
1978 | | |
1979 | | /* extended TPDU numbering EA with 2 octets of OSI or ATN extended |
1980 | | * checksum */ |
1981 | 0 | case LI_EXTENDED_EA_WITH_CHECKSUM : |
1982 | | /* check checksum parameter (in VP) parameter code octet */ |
1983 | 0 | if ((tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM) && |
1984 | 0 | (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_16)) |
1985 | 0 | return -1; |
1986 | | |
1987 | | /* check checksum parameter (in VP) length octet */ |
1988 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) |
1989 | 0 | return -1; |
1990 | | |
1991 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
1992 | 0 | is_extended = true; |
1993 | 0 | break; |
1994 | | |
1995 | | /* extended EA with 4 octets ATN extended checksum */ |
1996 | 0 | case LI_ATN_EXTENDED_EA_WITH_CHECKSUM : |
1997 | | /* check checksum parameter (in VP) parameter code octet */ |
1998 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT) != VP_ATN_EC_32) |
1999 | 0 | return -1; |
2000 | | |
2001 | | /* check checksum parameter (in VP) length octet */ |
2002 | 0 | if (tvb_get_uint8(tvb, offset + P_VAR_PART_EDT + 1) != 2) |
2003 | 0 | return -1; |
2004 | | |
2005 | 0 | tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234); |
2006 | 0 | is_extended = true; |
2007 | 0 | break; |
2008 | | |
2009 | 0 | default : /* bad TPDU */ |
2010 | 0 | return -1; |
2011 | 0 | } |
2012 | 0 | } |
2013 | | |
2014 | | /* ER TPDUs have no user data, so the length indicator determines the |
2015 | | * length */ |
2016 | 29 | tpdu_len = li + 1; |
2017 | | |
2018 | 29 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
2019 | 29 | pinfo->clnp_dstref = dst_ref; |
2020 | | |
2021 | 29 | col_append_fstr(pinfo->cinfo, COL_INFO, "EA TPDU (%u) dst-ref: 0x%04x", |
2022 | 29 | tpdu_nr, dst_ref); |
2023 | | |
2024 | 29 | if (tree) { |
2025 | 29 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
2026 | 29 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
2027 | 29 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
2028 | 29 | } |
2029 | 29 | offset += 1; |
2030 | | |
2031 | 29 | if (tree) { |
2032 | 29 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); |
2033 | 29 | } |
2034 | 29 | offset += 1; |
2035 | 29 | li -= 1; |
2036 | | |
2037 | 29 | if (tree) |
2038 | 29 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref); |
2039 | 29 | offset += 2; |
2040 | 29 | li -= 2; |
2041 | | |
2042 | 29 | if (is_extended) { |
2043 | 14 | if (tree) { |
2044 | 14 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb, |
2045 | 14 | offset, 4, tpdu_nr); |
2046 | 14 | } |
2047 | 14 | offset += 4; |
2048 | 14 | li -= 4; |
2049 | 15 | } else { |
2050 | 15 | if (tree) { |
2051 | 15 | proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1, |
2052 | 15 | tpdu_nr); |
2053 | 15 | } |
2054 | 15 | offset += 1; |
2055 | 15 | li -= 1; |
2056 | 15 | } |
2057 | | |
2058 | 29 | if (tree) |
2059 | 29 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
2060 | 29 | offset += li; |
2061 | | |
2062 | 29 | return offset; |
2063 | | |
2064 | 149 | } /* ositp_decode_EA */ |
2065 | | |
2066 | | static const value_string cotp_reject_vals[] = { |
2067 | | { 0, "Reason not specified" }, |
2068 | | { 1, "Invalid parameter code" }, |
2069 | | { 2, "Invalid TPDU type" }, |
2070 | | { 3, "Invalid parameter value" }, |
2071 | | { 0, NULL } |
2072 | | }; |
2073 | | |
2074 | | static int ositp_decode_ER(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
2075 | | packet_info *pinfo, proto_tree *tree) |
2076 | 116 | { |
2077 | 116 | proto_tree *cotp_tree = NULL; |
2078 | 116 | proto_item *ti; |
2079 | 116 | uint16_t dst_ref; |
2080 | 116 | uint8_t tpdu_len; |
2081 | | |
2082 | | /* ATN: except for modified LI checking nothing to be done here */ |
2083 | 116 | if (!cotp_decode_atn) { |
2084 | 116 | if (li > LI_MAX_ER) |
2085 | 17 | return -1; |
2086 | 116 | } else { |
2087 | 0 | if (li > LI_ATN_MAX_ER) |
2088 | 0 | return -1; |
2089 | 0 | } |
2090 | | |
2091 | | /* ER TPDUs have no user data, so the length indicator determines the |
2092 | | * length */ |
2093 | 99 | tpdu_len = li + 1; |
2094 | | |
2095 | 99 | if(try_val_to_str(tvb_get_uint8(tvb, offset + P_REJECT_ER), cotp_reject_vals) == NULL) |
2096 | 88 | return -1; |
2097 | | |
2098 | 11 | dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF); |
2099 | 11 | pinfo->clnp_dstref = dst_ref; |
2100 | | |
2101 | 11 | col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref); |
2102 | | |
2103 | 11 | if (tree) { |
2104 | 11 | ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_NA); |
2105 | 11 | cotp_tree = proto_item_add_subtree(ti, ett_cotp); |
2106 | 11 | proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); |
2107 | 11 | proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu); |
2108 | 11 | proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, |
2109 | 11 | dst_ref); |
2110 | 11 | proto_tree_add_item(cotp_tree, hf_cotp_reject_cause, tvb, offset + 4, 1, ENC_NA); |
2111 | 11 | } |
2112 | 11 | offset += 5; |
2113 | 11 | li -= 4; |
2114 | | |
2115 | 11 | if (tree) |
2116 | 11 | ositp_decode_var_part(tvb, offset, li, 4, tpdu_len, pinfo, cotp_tree); |
2117 | 11 | offset += li; |
2118 | | |
2119 | 11 | return offset; |
2120 | | |
2121 | 99 | } /* ositp_decode_ER */ |
2122 | | |
2123 | | static int ositp_decode_UD(tvbuff_t *tvb, int offset, uint8_t li, uint8_t tpdu, |
2124 | | packet_info *pinfo, proto_tree *tree, |
2125 | | bool *subdissector_found) |
2126 | 201 | { |
2127 | 201 | proto_item *ti; |
2128 | 201 | proto_tree *cltp_tree = NULL; |
2129 | 201 | tvbuff_t *next_tvb; |
2130 | 201 | unsigned tpdu_len; |
2131 | 201 | heur_dtbl_entry_t *hdtbl_entry; |
2132 | | |
2133 | | /* UD TPDUs have user data, so they run to the end of the containing PDU */ |
2134 | 201 | tpdu_len = tvb_reported_length_remaining(tvb, offset); |
2135 | | |
2136 | 201 | col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU"); |
2137 | | |
2138 | 201 | if (tree) { |
2139 | 201 | ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, ENC_NA); |
2140 | 201 | cltp_tree = proto_item_add_subtree(ti, ett_cltp); |
2141 | 201 | proto_tree_add_uint(cltp_tree, hf_cltp_li, tvb, offset, 1,li); |
2142 | 201 | } |
2143 | 201 | offset += 1; |
2144 | | |
2145 | 201 | if (tree) { |
2146 | 201 | proto_tree_add_uint(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu); |
2147 | 201 | } |
2148 | 201 | offset += 1; |
2149 | 201 | li -= 1; |
2150 | | |
2151 | 201 | if (tree) |
2152 | 201 | ositp_decode_var_part(tvb, offset, li, 0, tpdu_len, pinfo, cltp_tree); |
2153 | 201 | offset += li; |
2154 | | |
2155 | 201 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
2156 | | |
2157 | 201 | if (dissector_try_heuristic(cltp_heur_subdissector_list, next_tvb, |
2158 | 201 | pinfo, tree, &hdtbl_entry, NULL)) { |
2159 | 12 | *subdissector_found = true; |
2160 | 189 | } else { |
2161 | 189 | call_data_dissector(next_tvb, pinfo, tree); |
2162 | 189 | } |
2163 | | |
2164 | | |
2165 | | /*call_data_dissector(next_tvb, pinfo, tree); */ |
2166 | | |
2167 | 201 | offset += tvb_captured_length_remaining(tvb, offset); |
2168 | | /* we dissected all of the containing PDU */ |
2169 | | |
2170 | 201 | return offset; |
2171 | | |
2172 | 201 | } /* ositp_decode_UD */ |
2173 | | |
2174 | | /* Returns the offset past the last valid COTP or CLTP PDU if we found |
2175 | | at least one valid COTP or CLTP PDU, 0 otherwise. |
2176 | | |
2177 | | There doesn't seem to be any way in which the OSI network layer protocol |
2178 | | distinguishes between COTP and CLTP, but the first two octets of both |
2179 | | protocols' headers mean the same thing - length and PDU type - and the |
2180 | | only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle |
2181 | | both of them here. */ |
2182 | | static int dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo, |
2183 | | proto_tree *tree, |
2184 | | bool uses_inactive_subset) |
2185 | 9.21k | { |
2186 | 9.21k | int offset = 0; |
2187 | 9.21k | uint8_t li, tpdu, cdt; |
2188 | 9.21k | bool first_tpdu = true; |
2189 | 9.21k | int new_offset; |
2190 | 9.21k | bool found_ositp = false; |
2191 | 9.21k | bool is_cltp = false; |
2192 | 9.21k | bool subdissector_found = false; |
2193 | | |
2194 | | /* Initialize the COL_INFO field; each of the TPDUs will have its |
2195 | | information appended. */ |
2196 | 9.21k | col_clear(pinfo->cinfo, COL_INFO); |
2197 | | |
2198 | 13.2k | while (tvb_offset_exists(tvb, offset)) { |
2199 | 8.61k | if (!first_tpdu) { |
2200 | 79 | col_append_str(pinfo->cinfo, COL_INFO, ", "); |
2201 | 79 | expert_add_info(pinfo, NULL, &ei_cotp_multiple_tpdus); |
2202 | | /* adjust tvb and offset to the start of the current PDU */ |
2203 | 79 | tvb = tvb_new_subset_remaining(tvb, offset); |
2204 | 79 | offset = 0 ; |
2205 | 79 | } |
2206 | 8.61k | if ((li = tvb_get_uint8(tvb, offset + P_LI)) == 0) { |
2207 | 214 | col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero"); |
2208 | 214 | if (!first_tpdu) |
2209 | 19 | call_data_dissector( tvb_new_subset_remaining(tvb, offset), |
2210 | 19 | pinfo, tree); |
2211 | 214 | return found_ositp; |
2212 | 214 | } |
2213 | | |
2214 | 8.40k | tpdu = (tvb_get_uint8(tvb, offset + P_TPDU) >> 4) & 0x0F; |
2215 | 8.40k | if (tpdu == UD_TPDU) |
2216 | 201 | pinfo->current_proto = "CLTP"; /* connectionless transport */ |
2217 | 8.40k | cdt = tvb_get_uint8(tvb, offset + P_CDT) & 0x0F; |
2218 | | |
2219 | 8.40k | switch (tpdu) { |
2220 | 136 | case CC_TPDU : |
2221 | 305 | case CR_TPDU : |
2222 | 305 | new_offset = ositp_decode_CR_CC(tvb, offset, li, tpdu, pinfo, tree, |
2223 | 305 | uses_inactive_subset, &subdissector_found); |
2224 | 305 | break; |
2225 | 164 | case DR_TPDU : |
2226 | 164 | new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree); |
2227 | 164 | break; |
2228 | 6.69k | case DT_TPDU : |
2229 | 6.69k | new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree, |
2230 | 6.69k | uses_inactive_subset, &subdissector_found); |
2231 | 6.69k | break; |
2232 | 137 | case ED_TPDU : |
2233 | 137 | new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree, |
2234 | 137 | uses_inactive_subset, &subdissector_found); |
2235 | 137 | break; |
2236 | 64 | case RJ_TPDU : |
2237 | 64 | new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree); |
2238 | 64 | break; |
2239 | 29 | case DC_TPDU : |
2240 | 29 | new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree); |
2241 | 29 | break; |
2242 | 101 | case AK_TPDU : |
2243 | 101 | new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree); |
2244 | 101 | break; |
2245 | 149 | case EA_TPDU : |
2246 | 149 | new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree); |
2247 | 149 | break; |
2248 | 116 | case ER_TPDU : |
2249 | 116 | new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree); |
2250 | 116 | break; |
2251 | 201 | case UD_TPDU : |
2252 | 201 | new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree, |
2253 | 201 | &subdissector_found); |
2254 | 201 | is_cltp = true; |
2255 | 201 | break; |
2256 | 409 | default : |
2257 | 409 | if (first_tpdu) |
2258 | 403 | col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", |
2259 | 403 | tpdu); |
2260 | 409 | new_offset = -1; /* bad PDU type */ |
2261 | 409 | break; |
2262 | 8.40k | } |
2263 | | |
2264 | 5.19k | if (new_offset == -1) { /* incorrect TPDU */ |
2265 | 1.20k | if (!first_tpdu) |
2266 | 33 | call_data_dissector( tvb_new_subset_remaining(tvb, offset), |
2267 | 33 | pinfo, tree); |
2268 | 1.20k | break; |
2269 | 1.20k | } |
2270 | | |
2271 | 3.98k | if (first_tpdu) { |
2272 | | /* Well, we found at least one valid COTP or CLTP PDU, so I guess this |
2273 | | is either COTP or CLTP. */ |
2274 | 3.96k | if (!subdissector_found) |
2275 | 2.46k | col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP"); |
2276 | 3.96k | found_ositp = true; |
2277 | 3.96k | } |
2278 | | |
2279 | 3.98k | offset = new_offset; |
2280 | 3.98k | first_tpdu = false; |
2281 | 3.98k | } |
2282 | 5.80k | return found_ositp ? offset : 0; |
2283 | 9.21k | } /* dissect_ositp_internal */ |
2284 | | |
2285 | | static int dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
2286 | | void *data _U_) |
2287 | 168 | { |
2288 | 168 | return dissect_ositp_internal(tvb, pinfo, tree, false); |
2289 | 168 | } |
2290 | | |
2291 | | static int dissect_ositp_inactive(tvbuff_t *tvb, packet_info *pinfo, |
2292 | | proto_tree *tree, void *data _U_) |
2293 | 9.05k | { |
2294 | 9.05k | return dissect_ositp_internal(tvb, pinfo, tree, true); |
2295 | 9.05k | } |
2296 | | |
2297 | | static bool |
2298 | | test_cltp_var_part(tvbuff_t *tvb) |
2299 | 153 | { |
2300 | 153 | int offset = 0; |
2301 | 153 | uint8_t li; |
2302 | 157 | while (tvb_captured_length_remaining(tvb, offset)) { |
2303 | 143 | if (tvb_captured_length_remaining(tvb, offset) < 2) { |
2304 | 3 | return false; |
2305 | 3 | } |
2306 | 140 | switch (tvb_get_uint8(tvb, offset++)) { |
2307 | | /* These are the only 3 legal parameters for CLTP per RFC 1240 and X.234 */ |
2308 | 4 | case VP_SRC_TSAP: |
2309 | 5 | case VP_DST_TSAP: |
2310 | 7 | case VP_CHECKSUM: // Not required as redundant with UDP checksum, per RFC 1240 |
2311 | 7 | break; |
2312 | 133 | default: |
2313 | 133 | return false; |
2314 | 140 | } |
2315 | 7 | li = tvb_get_uint8(tvb, offset++); |
2316 | 7 | if (li == 255) { |
2317 | 1 | return false; |
2318 | 1 | } |
2319 | 6 | if (tvb_captured_length_remaining(tvb, offset) < li) { |
2320 | 2 | return false; |
2321 | 2 | } |
2322 | 4 | offset += li; |
2323 | 4 | } |
2324 | 14 | return true; |
2325 | 153 | } |
2326 | | |
2327 | | static bool |
2328 | | dissect_cltp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, |
2329 | | void *data) |
2330 | 1.64k | { |
2331 | 1.64k | uint8_t li, tpdu, spdu; |
2332 | 1.64k | int offset = 0; |
2333 | | |
2334 | | /* RFC 1240: OSI Connectionless Transport Services on top of UDP |
2335 | | * was made Historic by RFC 2556, which noted that "at this time |
2336 | | * there do not seem to be any implementations" and recommended |
2337 | | * TPKT (RFC 2126, ISO Transport Service on top of TCP) instead. |
2338 | | */ |
2339 | | |
2340 | | /* First, check do we have at least 2 bytes (length + tpdu) */ |
2341 | 1.64k | if (tvb_captured_length(tvb) < 2) { |
2342 | 106 | return false; |
2343 | 106 | } |
2344 | | |
2345 | 1.53k | li = tvb_get_uint8(tvb, offset++); |
2346 | | |
2347 | | /* LI must include TPDU, and 255 is reserved */ |
2348 | 1.53k | if (li == 0 || li == 255) { |
2349 | 370 | return false; |
2350 | 370 | } |
2351 | | |
2352 | | /* Is it OSI on top of the UDP? */ |
2353 | 1.16k | tpdu = (tvb_get_uint8(tvb, offset++) & 0xF0) >> 4; |
2354 | 1.16k | if (tpdu != UD_TPDU) { |
2355 | 1.01k | return false; |
2356 | 1.01k | } |
2357 | | |
2358 | | /* LI includes TPDU */ |
2359 | 153 | li--; |
2360 | | |
2361 | 153 | if (!test_cltp_var_part(tvb_new_subset_length(tvb, offset, li))) { |
2362 | 139 | return false; |
2363 | 139 | } |
2364 | 14 | offset += li; |
2365 | | |
2366 | | /* Since R-GOOSE is the only known user of CLTP over UDP, just |
2367 | | * check for that. |
2368 | | */ |
2369 | | |
2370 | | /* Check do we have SPDU ID byte, too */ |
2371 | 14 | if (tvb_captured_length_remaining(tvb, offset) < 1) { |
2372 | 8 | return false; |
2373 | 8 | } |
2374 | | |
2375 | | /* And let's see if it is GOOSE SPDU */ |
2376 | 6 | spdu = tvb_get_uint8(tvb, offset); |
2377 | 6 | if (spdu != 0xA1) { |
2378 | 2 | return false; |
2379 | 2 | } |
2380 | | |
2381 | 4 | dissect_ositp(tvb, pinfo, parent_tree, data); |
2382 | 4 | return true; |
2383 | 6 | } |
2384 | | |
2385 | | void proto_register_cotp(void) |
2386 | 16 | { |
2387 | 16 | static hf_register_info hf[] = { |
2388 | 16 | { &hf_cotp_li, |
2389 | 16 | { "Length", "cotp.li", FT_UINT8, BASE_DEC, |
2390 | 16 | NULL, 0x0, "Length Indicator, length of this header", HFILL}}, |
2391 | 16 | { &hf_cotp_type, |
2392 | 16 | { "PDU Type", "cotp.type", FT_UINT8, BASE_HEX, |
2393 | 16 | VALS(cotp_tpdu_type_abbrev_vals), 0x0, |
2394 | 16 | "PDU Type - upper nibble of byte", HFILL}}, |
2395 | 16 | { &hf_cotp_srcref, |
2396 | 16 | { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, |
2397 | 16 | NULL, 0x0, "Source address reference", HFILL}}, |
2398 | 16 | { &hf_cotp_destref, |
2399 | 16 | { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, |
2400 | 16 | NULL, 0x0, "Destination address reference", HFILL}}, |
2401 | 16 | { &hf_cotp_class, |
2402 | 16 | { "Class", "cotp.class", FT_UINT8, BASE_DEC, NULL, |
2403 | 16 | 0xF0, "Transport protocol class", HFILL}}, |
2404 | 16 | { &hf_cotp_opts_extended_formats, |
2405 | 16 | { "Extended formats", "cotp.opts.extended_formats", FT_BOOLEAN, 8, |
2406 | 16 | NULL, 0x02, "Use of extended formats in classes 2, 3, and 4", HFILL}}, |
2407 | 16 | { &hf_cotp_opts_no_explicit_flow_control, |
2408 | 16 | { "No explicit flow control", "cotp.opts.no_explicit_flow_control", |
2409 | 16 | FT_BOOLEAN, 8, NULL, 0x01, "No explicit flow control in class 2", |
2410 | 16 | HFILL}}, |
2411 | 16 | { &hf_cotp_tpdu_number, |
2412 | 16 | { "TPDU number", "cotp.tpdu-number", FT_UINT8, BASE_HEX, |
2413 | 16 | NULL, 0x7f, NULL, HFILL}}, |
2414 | 16 | { &hf_cotp_tpdu_number_extended, |
2415 | 16 | { "TPDU number", "cotp.tpdu-number", FT_UINT32, BASE_HEX, |
2416 | 16 | NULL, 0x0 /* XXX - 0x7fff? */, NULL, HFILL}}, |
2417 | 16 | { &hf_cotp_next_tpdu_number, |
2418 | 16 | { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT8, BASE_HEX, |
2419 | 16 | NULL, 0x0, NULL, HFILL}}, |
2420 | 16 | { &hf_cotp_next_tpdu_number_extended, |
2421 | 16 | { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT32, BASE_HEX, |
2422 | 16 | NULL, 0x0, NULL, HFILL}}, |
2423 | 16 | { &hf_cotp_eot, |
2424 | 16 | { "Last data unit", "cotp.eot", FT_BOOLEAN, 8, |
2425 | 16 | TFS(&tfs_yes_no), 0x80, |
2426 | 16 | "Is current TPDU the last data unit of a complete DT TPDU sequence " |
2427 | 16 | "(End of TSDU)?", HFILL}}, |
2428 | 16 | { &hf_cotp_eot_extended, |
2429 | 16 | { "Last data unit", "cotp.eot", FT_BOOLEAN, 32, |
2430 | 16 | TFS(&tfs_yes_no), 0x80000000, |
2431 | 16 | "Is current TPDU the last data unit of a complete DT TPDU sequence " |
2432 | 16 | "(End of TSDU)?", HFILL}}, |
2433 | 16 | { &hf_cotp_segment_overlap, |
2434 | 16 | { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, |
2435 | 16 | NULL, 0x0, "Segment overlaps with other segments", HFILL }}, |
2436 | 16 | { &hf_cotp_segment_overlap_conflict, |
2437 | 16 | { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", |
2438 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
2439 | 16 | "Overlapping segments contained conflicting data", HFILL }}, |
2440 | 16 | { &hf_cotp_segment_multiple_tails, |
2441 | 16 | { "Multiple tail segments found", "cotp.segment.multipletails", |
2442 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
2443 | 16 | "Several tails were found when reassembling the packet", HFILL }}, |
2444 | 16 | { &hf_cotp_segment_too_long_segment, |
2445 | 16 | { "Segment too long", "cotp.segment.toolongsegment", |
2446 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
2447 | 16 | "Segment contained data past end of packet", HFILL }}, |
2448 | 16 | { &hf_cotp_segment_error, |
2449 | 16 | { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, |
2450 | 16 | NULL, 0x0, "Reassembly error due to illegal segments", HFILL }}, |
2451 | 16 | { &hf_cotp_segment_count, |
2452 | 16 | { "Segment count", "cotp.segment.count", FT_UINT32, BASE_DEC, |
2453 | 16 | NULL, 0x0, NULL, HFILL }}, |
2454 | 16 | { &hf_cotp_segment, |
2455 | 16 | { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, |
2456 | 16 | NULL, 0x0, NULL, HFILL }}, |
2457 | 16 | { &hf_cotp_segments, |
2458 | 16 | { "COTP Segments", "cotp.segments", FT_NONE, BASE_NONE, |
2459 | 16 | NULL, 0x0, NULL, HFILL }}, |
2460 | 16 | { &hf_cotp_reassembled_in, |
2461 | 16 | { "Reassembled COTP in frame", "cotp.reassembled_in", |
2462 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
2463 | 16 | "This COTP packet is reassembled in this frame", HFILL }}, |
2464 | 16 | { &hf_cotp_reassembled_length, |
2465 | 16 | { "Reassembled COTP length", "cotp.reassembled.length", |
2466 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, |
2467 | 16 | "The total length of the reassembled payload", HFILL }}, |
2468 | | /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as |
2469 | | identifiers of unspecified type and length. |
2470 | | Some implementations of COTP use printable strings, others use raw bytes. |
2471 | | We always add both representations to the tree; one will always be hidden |
2472 | | depending on the tsap display preference */ |
2473 | 16 | { &hf_cotp_vp_src_tsap, |
2474 | 16 | { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, |
2475 | 16 | NULL, 0x0, "Calling TSAP", HFILL }}, |
2476 | 16 | { &hf_cotp_vp_src_tsap_bytes, |
2477 | 16 | { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, |
2478 | 16 | NULL, 0x0, "Calling TSAP (bytes representation)", HFILL }}, |
2479 | 16 | { &hf_cotp_vp_dst_tsap, |
2480 | 16 | { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, |
2481 | 16 | NULL, 0x0, "Called TSAP", HFILL }}, |
2482 | 16 | { &hf_cotp_vp_dst_tsap_bytes, |
2483 | 16 | { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, |
2484 | 16 | NULL, 0x0, "Called TSAP (bytes representation)", HFILL }}, |
2485 | | /* Generated from convert_proto_tree_add_text.pl */ |
2486 | 16 | { &hf_cotp_parameter_code, { "Parameter code", "cotp.parameter_code", FT_UINT8, BASE_HEX, VALS(tp_vpart_type_vals), 0x0, NULL, HFILL }}, |
2487 | 16 | { &hf_cotp_parameter_length, { "Parameter length", "cotp.parameter_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2488 | 16 | { &hf_cotp_parameter_value, { "Parameter value", "cotp.parameter_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2489 | 16 | { &hf_cotp_atn_extended_checksum16, { "ATN extended checksum", "cotp.atn_extended_checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2490 | 16 | { &hf_cotp_atn_extended_checksum32, { "ATN extended checksum", "cotp.atn_extended_checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2491 | 16 | { &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 }}, |
2492 | 16 | { &hf_cotp_ack_time, { "Ack time (ms)", "cotp.ack_time", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2493 | 16 | { &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 }}, |
2494 | 16 | { &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 }}, |
2495 | 16 | { &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 }}, |
2496 | 16 | { &hf_cotp_vp_priority, { "Priority", "cotp.vp_priority", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2497 | 16 | { &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 }}, |
2498 | 16 | { &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 }}, |
2499 | 16 | { &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 }}, |
2500 | 16 | { &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 }}, |
2501 | 16 | { &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 }}, |
2502 | 16 | { &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 }}, |
2503 | 16 | { &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 }}, |
2504 | 16 | { &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 }}, |
2505 | 16 | { &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 }}, |
2506 | 16 | { &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 }}, |
2507 | 16 | { &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 }}, |
2508 | 16 | { &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 }}, |
2509 | 16 | { &hf_cotp_sequence_number, { "Sequence number", "cotp.sequence_number", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2510 | 16 | { &hf_cotp_reassignment_time, { "Reassignment time (secs)", "cotp.reassignment_time", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2511 | 16 | { &hf_cotp_lower_window_edge, { "Lower window edge", "cotp.lower_window_edge", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2512 | 16 | { &hf_cotp_credit, { "Credit", "cotp.credit", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2513 | 16 | { &hf_cotp_tpdu_size, { "TPDU size", "cotp.tpdu_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2514 | 16 | { &hf_cotp_checksum, { "Checksum", "cotp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2515 | 16 | { &hf_cotp_checksum_status, { "Checksum Status", "cotp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }}, |
2516 | 16 | { &hf_cotp_vp_version_nr, { "Version", "cotp.vp_version_nr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2517 | 16 | { &hf_cotp_network_expedited_data, { "Use of network expedited data", "cotp.network_expedited_data", FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x08, NULL, HFILL }}, |
2518 | 16 | { &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 }}, |
2519 | 16 | { &hf_cotp_use_16_bit_checksum, { "16 bit checksum", "cotp.use_16_bit_checksum", FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x02, NULL, HFILL }}, |
2520 | 16 | { &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 }}, |
2521 | 16 | { &hf_cotp_preferred_maximum_tpdu_size, { "Preferred maximum TPDU size", "cotp.preferred_maximum_tpdu_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2522 | 16 | { &hf_cotp_inactivity_timer, { "Inactivity timer (ms)", "cotp.inactivity_timer", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2523 | 16 | { &hf_cotp_cause, { "Cause", "cotp.cause", FT_UINT8, BASE_DEC, VALS(cotp_cause_vals), 0x0, NULL, HFILL }}, |
2524 | 16 | { &hf_cotp_segment_data, { "COTP segment data", "cotp.segment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2525 | 16 | { &hf_cotp_credit_cdt, { "Credit", "cotp.credit", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2526 | 16 | { &hf_cotp_reject_cause, { "Reject cause", "cotp.reject_cause", FT_UINT8, BASE_DEC, VALS(cotp_reject_vals), 0x0, NULL, HFILL }}, |
2527 | 16 | }; |
2528 | 16 | static int *ett[] = { |
2529 | 16 | &ett_cotp, |
2530 | 16 | &ett_cotp_segment, |
2531 | 16 | &ett_cotp_segments |
2532 | 16 | }; |
2533 | 16 | static ei_register_info ei[] = { |
2534 | 16 | { &ei_cotp_disconnect_request, { "cotp.disconnect_request", PI_SEQUENCE, PI_CHAT, "Disconnect Request(DR)", EXPFILL }}, |
2535 | 16 | { &ei_cotp_reject, { "cotp.reject", PI_SEQUENCE, PI_NOTE, "Reject(RJ)", EXPFILL }}, |
2536 | 16 | { &ei_cotp_connection, { "cotp.connection", PI_SEQUENCE, PI_CHAT, "Connection", EXPFILL }}, |
2537 | 16 | { &ei_cotp_disconnect_confirm, { "cotp.disconnect_confirm", PI_SEQUENCE, PI_CHAT, "Disconnect Confirm(DC)", EXPFILL }}, |
2538 | 16 | { &ei_cotp_multiple_tpdus, { "cotp.multiple_tpdus", PI_SEQUENCE, PI_NOTE, "Multiple TPDUs in one packet", EXPFILL }}, |
2539 | 16 | { &ei_cotp_preferred_maximum_tpdu_size, { "cotp.preferred_maximum_tpdu_size.invalid", PI_PROTOCOL, PI_WARN, "Preferred maximum TPDU size: bogus length", EXPFILL }}, |
2540 | 16 | { &ei_cotp_atn_extended_checksum, { "cotp.bad_atn_ext_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, |
2541 | 16 | { &ei_cotp_checksum, { "cotp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, |
2542 | 16 | }; |
2543 | | |
2544 | 16 | module_t *cotp_module; |
2545 | 16 | expert_module_t* expert_cotp; |
2546 | | |
2547 | 16 | proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp"); |
2548 | 16 | proto_register_field_array(proto_cotp, hf, array_length(hf)); |
2549 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
2550 | 16 | expert_cotp = expert_register_protocol(proto_cotp); |
2551 | 16 | expert_register_field_array(expert_cotp, ei, array_length(ei)); |
2552 | 16 | cotp_module = prefs_register_protocol(proto_cotp, NULL); |
2553 | | |
2554 | 16 | prefs_register_bool_preference(cotp_module, "reassemble", |
2555 | 16 | "Reassemble segmented COTP datagrams", |
2556 | 16 | "Whether segmented COTP datagrams should be " |
2557 | 16 | "reassembled. To use this option, you must " |
2558 | 16 | "also enable \"Allow subdissectors to " |
2559 | 16 | "reassemble TCP streams\" in the TCP " |
2560 | 16 | "protocol settings.", |
2561 | 16 | &cotp_reassemble); |
2562 | | |
2563 | 16 | prefs_register_enum_preference(cotp_module, "tsap_display", |
2564 | 16 | "Display TSAPs as strings or bytes", |
2565 | 16 | "How TSAPs should be displayed", |
2566 | 16 | &tsap_display, tsap_display_options, false); |
2567 | | |
2568 | 16 | prefs_register_bool_preference(cotp_module, "decode_atn", "Decode ATN TPDUs", |
2569 | 16 | "Whether to decode OSI TPDUs with ATN " |
2570 | 16 | "(Aeronautical Telecommunications Network) " |
2571 | 16 | "extensions. To use this option, you must " |
2572 | 16 | "also enable \"Always try to decode NSDU as " |
2573 | 16 | "transport PDUs\" in the CLNP protocol " |
2574 | 16 | "settings.", &cotp_decode_atn); |
2575 | | |
2576 | | /* For handling protocols hijacking the variable part of CR or CC PDUs */ |
2577 | 16 | cotp_cr_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_cr", "COTP CR (Connect Request) payload", proto_cotp); |
2578 | 16 | cotp_cc_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_cc", "COTP CC (Connect Confirm) payload", proto_cotp); |
2579 | | |
2580 | | /* subdissector code in inactive subset */ |
2581 | 16 | cotp_is_heur_subdissector_list = register_heur_dissector_list_with_description("cotp_is", "COTP IS (Inactive Subset) payload", proto_cotp); |
2582 | | |
2583 | | /* other COTP/ISO 8473 subdissectors */ |
2584 | 16 | cotp_heur_subdissector_list = register_heur_dissector_list_with_description("cotp", "COTP DT (Data) payload", proto_cotp); |
2585 | | |
2586 | | /* XXX - what about CLTP and proto_cltp? */ |
2587 | 16 | ositp_handle = register_dissector("ositp", dissect_ositp, proto_cotp); |
2588 | 16 | register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp); |
2589 | | |
2590 | | /* |
2591 | | * XXX - this is a connection-oriented transport-layer protocol, |
2592 | | * so we should probably use more than just network-layer |
2593 | | * endpoint addresses to match segments together, but the functions |
2594 | | * in addresses_ports_reassembly_table_functions do matching based |
2595 | | * on port numbers, so they won't let us ensure that segments from |
2596 | | * different connections don't get assembled together. |
2597 | | */ |
2598 | 16 | reassembly_table_register(&cotp_reassembly_table, |
2599 | 16 | &addresses_reassembly_table_functions); |
2600 | 16 | } |
2601 | | |
2602 | | void proto_register_cltp(void) |
2603 | 16 | { |
2604 | 16 | static hf_register_info hf[] = { |
2605 | 16 | { &hf_cltp_li, |
2606 | 16 | { "Length", "cltp.li", FT_UINT8, BASE_DEC, NULL, 0x0, |
2607 | 16 | "Length Indicator, length of this header", HFILL}}, |
2608 | 16 | { &hf_cltp_type, |
2609 | 16 | { "PDU Type", "cltp.type", FT_UINT8, BASE_HEX, |
2610 | 16 | VALS(cltp_tpdu_type_abbrev_vals), 0x0, NULL, HFILL}} |
2611 | 16 | }; |
2612 | 16 | static int *ett[] = { |
2613 | 16 | &ett_cltp |
2614 | 16 | }; |
2615 | | |
2616 | 16 | proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp"); |
2617 | 16 | proto_register_field_array(proto_cltp, hf, array_length(hf)); |
2618 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
2619 | | |
2620 | 16 | cltp_heur_subdissector_list = register_heur_dissector_list_with_description("cltp", "CLTP data atop CLNP", proto_cltp); |
2621 | 16 | } |
2622 | | |
2623 | | void |
2624 | | proto_reg_handoff_cotp(void) |
2625 | 16 | { |
2626 | 16 | dissector_add_uint("ip.proto", IP_PROTO_TP, ositp_handle); |
2627 | | |
2628 | 16 | rdp_cr_handle = find_dissector("rdp_cr"); |
2629 | 16 | rdp_cc_handle = find_dissector("rdp_cc"); |
2630 | | |
2631 | 16 | proto_clnp = proto_get_id_by_filter_name("clnp"); |
2632 | | |
2633 | | /* Actual implementations of R-GOOSE seem to use UDP port 102, registered |
2634 | | * for ISO-TSAP, cf. TPKT. Perhaps we should just register ositp_handle |
2635 | | * to UDP port 102 instead of having a heuristic dissector? |
2636 | | */ |
2637 | 16 | heur_dissector_add("udp", dissect_cltp_heur, "CLTP over UDP", |
2638 | 16 | "cltp_udp", proto_cltp, HEURISTIC_ENABLE); |
2639 | 16 | } |
2640 | | |
2641 | | /* |
2642 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
2643 | | * |
2644 | | * Local variables: |
2645 | | * c-basic-offset: 2 |
2646 | | * tab-width: 8 |
2647 | | * indent-tabs-mode: nil |
2648 | | * End: |
2649 | | * |
2650 | | * vi: set shiftwidth=2 tabstop=8 expandtab: |
2651 | | * :indentSize=2:tabSize=8:noTabs=true: |
2652 | | */ |