1 /* packet-rtse-template.c
2 * Routines for RTSE packet dissection
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/conversation.h>
16 #include <epan/prefs.h>
17 #include <epan/reassemble.h>
18 #include <epan/asn1.h>
19 #include <epan/expert.h>
21 #include <wsutil/array.h>
22 #include <wsutil/str_util.h>
24 #include "packet-ber.h"
25 #include "packet-pres.h"
26 #include "packet-acse.h"
27 #include "packet-ros.h"
28 #include "packet-rtse.h"
30 #define PNAME "X.228 OSI Reliable Transfer Service"
34 void proto_register_rtse(void);
35 void proto_reg_handoff_rtse(void);
37 /* Initialize the protocol and registered fields */
38 static int proto_rtse
;
40 static bool open_request
=false;
41 static uint32_t app_proto
=0;
43 static proto_tree
*top_tree
;
46 static bool rtse_reassemble
= true;
48 #include "packet-rtse-hf.c"
50 /* Initialize the subtree pointers */
52 #include "packet-rtse-ett.c"
54 static expert_field ei_rtse_dissector_oid_not_implemented
;
55 static expert_field ei_rtse_unknown_rtse_pdu
;
56 static expert_field ei_rtse_abstract_syntax
;
58 static dissector_table_t rtse_oid_dissector_table
;
59 static dissector_handle_t rtse_handle
;
60 static int ett_rtse_unknown
;
62 static reassembly_table rtse_reassembly_table
;
64 static int hf_rtse_segment_data
;
65 static int hf_rtse_fragments
;
66 static int hf_rtse_fragment
;
67 static int hf_rtse_fragment_overlap
;
68 static int hf_rtse_fragment_overlap_conflicts
;
69 static int hf_rtse_fragment_multiple_tails
;
70 static int hf_rtse_fragment_too_long_fragment
;
71 static int hf_rtse_fragment_error
;
72 static int hf_rtse_fragment_count
;
73 static int hf_rtse_reassembled_in
;
74 static int hf_rtse_reassembled_length
;
76 static int ett_rtse_fragment
;
77 static int ett_rtse_fragments
;
79 static const fragment_items rtse_frag_items
= {
80 /* Fragment subtrees */
86 &hf_rtse_fragment_overlap
,
87 &hf_rtse_fragment_overlap_conflicts
,
88 &hf_rtse_fragment_multiple_tails
,
89 &hf_rtse_fragment_too_long_fragment
,
90 &hf_rtse_fragment_error
,
91 &hf_rtse_fragment_count
,
92 /* Reassembled in field */
93 &hf_rtse_reassembled_in
,
94 /* Reassembled length field */
95 &hf_rtse_reassembled_length
,
96 /* Reassembled data field */
103 register_rtse_oid_dissector_handle(const char *oid
, dissector_handle_t dissector
, int proto
, const char *name
, bool uses_ros
)
105 /* XXX: Note that this fcn is called from proto_reg_handoff in *other* dissectors ... */
107 static dissector_handle_t ros_handle
= NULL
;
109 if (ros_handle
== NULL
)
110 ros_handle
= find_dissector("ros");
112 /* register RTSE with the BER (ACSE) */
113 register_ber_oid_dissector_handle(oid
, rtse_handle
, proto
, name
);
116 /* make sure we call ROS ... */
117 dissector_add_string("rtse.oid", oid
, ros_handle
);
119 /* and then tell ROS how to dissect the AS*/
120 if (dissector
!= NULL
)
121 register_ros_oid_dissector_handle(oid
, dissector
, proto
, name
, true);
124 /* otherwise we just remember how to dissect the AS */
125 dissector_add_string("rtse.oid", oid
, dissector
);
130 call_rtse_oid_callback(const char *oid
, tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
135 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
137 if ((len
= dissector_try_string_with_data(rtse_oid_dissector_table
, oid
, next_tvb
, pinfo
, tree
, true, data
)) == 0) {
139 proto_tree
*next_tree
;
141 next_tree
= proto_tree_add_subtree_format(tree
, next_tvb
, 0, -1, ett_rtse_unknown
, &item
,
142 "RTSE: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid
);
144 expert_add_info_format(pinfo
, item
, &ei_rtse_dissector_oid_not_implemented
,
145 "RTSE: Dissector for OID %s not implemented", oid
);
146 len
= dissect_unknown_ber(pinfo
, next_tvb
, offset
, next_tree
);
155 call_rtse_external_type_callback(bool implicit_tag _U_
, tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx
, proto_tree
*tree
, int hf_index _U_
)
157 const char *oid
= NULL
;
159 if (actx
->external
.indirect_ref_present
) {
161 oid
= (const char *)find_oid_by_pres_ctx_id(actx
->pinfo
, actx
->external
.indirect_reference
);
164 proto_tree_add_expert_format(tree
, actx
->pinfo
, &ei_rtse_abstract_syntax
, tvb
, offset
, tvb_captured_length_remaining(tvb
, offset
),
165 "Unable to determine abstract syntax for indirect reference: %d.", actx
->external
.indirect_reference
);
166 } else if (actx
->external
.direct_ref_present
) {
167 oid
= actx
->external
.direct_reference
;
171 offset
= call_rtse_oid_callback(oid
, tvb
, offset
, actx
->pinfo
, top_tree
? top_tree
: tree
, actx
->private_data
);
176 #include "packet-rtse-fn.c"
179 * Dissect RTSE PDUs inside a PPDU.
182 dissect_rtse(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
188 proto_tree
*next_tree
=NULL
;
189 tvbuff_t
*next_tvb
= NULL
;
190 tvbuff_t
*data_tvb
= NULL
;
191 fragment_head
*frag_msg
= NULL
;
192 uint32_t fragment_length
;
193 uint32_t rtse_id
= 0;
194 bool data_handled
= false;
195 struct SESSION_DATA_STRUCTURE
* session
;
196 conversation_t
*conversation
= NULL
;
198 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
200 /* do we have application context from the acse dissector? */
203 session
= (struct SESSION_DATA_STRUCTURE
*)data
;
205 /* save parent_tree so subdissectors can create new top nodes */
206 top_tree
=parent_tree
;
208 asn1_ctx
.private_data
= session
;
210 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RTSE");
211 col_clear(pinfo
->cinfo
, COL_INFO
);
213 if (rtse_reassemble
&&
214 ((session
->spdu_type
== SES_DATA_TRANSFER
) ||
215 (session
->spdu_type
== SES_MAJOR_SYNC_POINT
)))
217 /* Use conversation index as fragment id */
218 conversation
= find_conversation_pinfo(pinfo
, 0);
219 if (conversation
!= NULL
) {
220 rtse_id
= conversation
->conv_index
;
222 session
->rtse_reassemble
= true;
224 if (rtse_reassemble
&& session
->spdu_type
== SES_MAJOR_SYNC_POINT
) {
225 frag_msg
= fragment_end_seq_next (&rtse_reassembly_table
,
226 pinfo
, rtse_id
, NULL
);
227 next_tvb
= process_reassembled_data (tvb
, offset
, pinfo
, "Reassembled RTSE",
228 frag_msg
, &rtse_frag_items
, NULL
, parent_tree
);
231 item
= proto_tree_add_item(parent_tree
, proto_rtse
, next_tvb
? next_tvb
: tvb
, 0, -1, ENC_NA
);
232 tree
= proto_item_add_subtree(item
, ett_rtse
);
234 if (rtse_reassemble
&& session
->spdu_type
== SES_DATA_TRANSFER
) {
235 /* strip off the OCTET STRING encoding - including any CONSTRUCTED OCTET STRING */
236 dissect_ber_octet_string(false, &asn1_ctx
, tree
, tvb
, offset
, hf_rtse_segment_data
, &data_tvb
);
239 fragment_length
= tvb_captured_length_remaining (data_tvb
, 0);
240 proto_item_append_text(asn1_ctx
.created_item
, " (%u byte%s)", fragment_length
,
241 plurality(fragment_length
, "", "s"));
242 frag_msg
= fragment_add_seq_next (&rtse_reassembly_table
,
245 fragment_length
, true);
246 if (frag_msg
&& pinfo
->num
!= frag_msg
->reassembled_in
) {
247 /* Add a "Reassembled in" link if not reassembled in this frame */
248 proto_tree_add_uint (tree
, *(rtse_frag_items
.hf_reassembled_in
),
249 data_tvb
, 0, 0, frag_msg
->reassembled_in
);
251 pinfo
->fragmented
= true;
254 fragment_length
= tvb_captured_length_remaining (tvb
, offset
);
257 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[RTSE fragment, %u byte%s]",
258 fragment_length
, plurality(fragment_length
, "", "s"));
259 } else if (rtse_reassemble
&& session
->spdu_type
== SES_MAJOR_SYNC_POINT
) {
261 /* ROS won't do this for us */
262 session
->ros_op
= (ROS_OP_INVOKE
| ROS_OP_ARGUMENT
);
263 /*offset=*/dissect_ber_external_type(false, tree
, next_tvb
, 0, &asn1_ctx
, -1, call_rtse_external_type_callback
);
265 /* Return other than 0 to indicate that we handled this packet */
268 offset
= tvb_captured_length (tvb
);
270 pinfo
->fragmented
= false;
275 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
277 offset
=dissect_rtse_RTSE_apdus(true, tvb
, offset
, &asn1_ctx
, tree
, -1);
278 if (offset
== old_offset
) {
279 next_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1,
280 ett_rtse_unknown
, &item
, "Unknown RTSE PDU");
281 expert_add_info (pinfo
, item
, &ei_rtse_unknown_rtse_pdu
);
282 dissect_unknown_ber(pinfo
, tvb
, offset
, next_tree
);
289 return tvb_captured_length(tvb
);
292 /*--- proto_register_rtse -------------------------------------------*/
293 void proto_register_rtse(void) {
296 static hf_register_info hf
[] =
298 /* Fragment entries */
299 { &hf_rtse_segment_data
,
300 { "RTSE segment data", "rtse.segment", FT_NONE
, BASE_NONE
,
301 NULL
, 0x00, NULL
, HFILL
} },
302 { &hf_rtse_fragments
,
303 { "RTSE fragments", "rtse.fragments", FT_NONE
, BASE_NONE
,
304 NULL
, 0x00, NULL
, HFILL
} },
306 { "RTSE fragment", "rtse.fragment", FT_FRAMENUM
, BASE_NONE
,
307 NULL
, 0x00, NULL
, HFILL
} },
308 { &hf_rtse_fragment_overlap
,
309 { "RTSE fragment overlap", "rtse.fragment.overlap", FT_BOOLEAN
,
310 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
311 { &hf_rtse_fragment_overlap_conflicts
,
312 { "RTSE fragment overlapping with conflicting data",
313 "rtse.fragment.overlap.conflicts", FT_BOOLEAN
, BASE_NONE
,
314 NULL
, 0x0, NULL
, HFILL
} },
315 { &hf_rtse_fragment_multiple_tails
,
316 { "RTSE has multiple tail fragments",
317 "rtse.fragment.multiple_tails", FT_BOOLEAN
, BASE_NONE
,
318 NULL
, 0x0, NULL
, HFILL
} },
319 { &hf_rtse_fragment_too_long_fragment
,
320 { "RTSE fragment too long", "rtse.fragment.too_long_fragment",
321 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
322 { &hf_rtse_fragment_error
,
323 { "RTSE defragmentation error", "rtse.fragment.error", FT_FRAMENUM
,
324 BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
325 { &hf_rtse_fragment_count
,
326 { "RTSE fragment count", "rtse.fragment.count", FT_UINT32
, BASE_DEC
,
327 NULL
, 0x00, NULL
, HFILL
} },
328 { &hf_rtse_reassembled_in
,
329 { "Reassembled RTSE in frame", "rtse.reassembled.in", FT_FRAMENUM
, BASE_NONE
,
330 NULL
, 0x00, "This RTSE packet is reassembled in this frame", HFILL
} },
331 { &hf_rtse_reassembled_length
,
332 { "Reassembled RTSE length", "rtse.reassembled.length", FT_UINT32
, BASE_DEC
,
333 NULL
, 0x00, "The total length of the reassembled payload", HFILL
} },
335 #include "packet-rtse-hfarr.c"
338 /* List of subtrees */
339 static int *ett
[] = {
344 #include "packet-rtse-ettarr.c"
347 static ei_register_info ei
[] = {
348 { &ei_rtse_dissector_oid_not_implemented
, { "rtse.dissector_oid_not_implemented", PI_UNDECODED
, PI_WARN
, "RTSE: Dissector for OID not implemented", EXPFILL
}},
349 { &ei_rtse_unknown_rtse_pdu
, { "rtse.unknown_rtse_pdu", PI_UNDECODED
, PI_WARN
, "Unknown RTSE PDU", EXPFILL
}},
350 { &ei_rtse_abstract_syntax
, { "rtse.bad_abstract_syntax", PI_PROTOCOL
, PI_WARN
, "Unable to determine abstract syntax for indirect reference", EXPFILL
}},
353 expert_module_t
* expert_rtse
;
354 module_t
*rtse_module
;
356 /* Register protocol */
357 proto_rtse
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
358 rtse_handle
= register_dissector("rtse", dissect_rtse
, proto_rtse
);
359 /* Register fields and subtrees */
360 proto_register_field_array(proto_rtse
, hf
, array_length(hf
));
361 proto_register_subtree_array(ett
, array_length(ett
));
362 expert_rtse
= expert_register_protocol(proto_rtse
);
363 expert_register_field_array(expert_rtse
, ei
, array_length(ei
));
365 reassembly_table_register (&rtse_reassembly_table
,
366 &addresses_reassembly_table_functions
);
368 rtse_module
= prefs_register_protocol_subtree("OSI", proto_rtse
, NULL
);
370 prefs_register_bool_preference(rtse_module
, "reassemble",
371 "Reassemble segmented RTSE datagrams",
372 "Whether segmented RTSE datagrams should be reassembled."
373 " To use this option, you must also enable"
374 " \"Allow subdissectors to reassemble TCP streams\""
375 " in the TCP protocol settings.", &rtse_reassemble
);
377 rtse_oid_dissector_table
= register_dissector_table("rtse.oid", "RTSE OID Dissectors", proto_rtse
, FT_STRING
, STRING_CASE_SENSITIVE
);
381 /*--- proto_reg_handoff_rtse --- */
382 void proto_reg_handoff_rtse(void) {
388 * Editor modelines - https://www.wireshark.org/tools/modelines.html
393 * indent-tabs-mode: nil
396 * vi: set shiftwidth=4 tabstop=8 expandtab:
397 * :indentSize=4:tabSize=8:noTabs=true: