2 * Routines for ROS packet dissection
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <epan/packet.h>
30 #include <epan/conversation.h>
31 #include <epan/wmem/wmem.h>
32 #include <epan/asn1.h>
33 #include <epan/expert.h>
35 #include "packet-ber.h"
36 #include "packet-pres.h"
37 #include "packet-ros.h"
39 #define PNAME "X.880 OSI Remote Operations Service"
43 void proto_register_ros(void);
44 void proto_reg_handoff_ros(void);
46 /* Initialize the protocol and registered fields */
47 static int proto_ros
= -1;
49 static proto_tree
*top_tree
=NULL
;
50 static guint32 opcode
;
51 static guint32 invokeid
;
53 static dissector_handle_t ros_handle
= NULL
;
55 typedef struct ros_conv_info_t
{
56 struct ros_conv_info_t
*next
;
57 GHashTable
*unmatched
; /* unmatched operations */
58 GHashTable
*matched
; /* matched operations */
61 static ros_conv_info_t
*ros_info_items
= NULL
;
63 typedef struct ros_call_response
{
69 } ros_call_response_t
;
71 static int hf_ros_response_in
= -1;
72 static int hf_ros_response_to
= -1;
73 static int hf_ros_time
= -1;
76 #include "packet-ros-hf.c"
78 /* Initialize the subtree pointers */
79 static gint ett_ros
= -1;
80 #include "packet-ros-ett.c"
82 static expert_field ei_ros_dissector_oid_not_implemented
= EI_INIT
;
83 static expert_field ei_ros_unknown_ros_pdu
= EI_INIT
;
85 static dissector_table_t ros_oid_dissector_table
=NULL
;
87 static GHashTable
*oid_table
=NULL
;
88 static GHashTable
*protocol_table
=NULL
;
89 static gint ett_ros_unknown
= -1;
92 register_ros_oid_dissector_handle(const char *oid
, dissector_handle_t dissector
, int proto _U_
, const char *name
, gboolean uses_rtse
)
94 dissector_add_string("ros.oid", oid
, dissector
);
95 g_hash_table_insert(oid_table
, (gpointer
)oid
, (gpointer
)name
);
98 /* if we are not using RTSE, then we must register ROS with BER (ACSE) */
99 register_ber_oid_dissector_handle(oid
, ros_handle
, proto
, name
);
103 register_ros_protocol_info(const char *oid
, const ros_info_t
*rinfo
, int proto _U_
, const char *name
, gboolean uses_rtse
)
105 g_hash_table_insert(protocol_table
, (gpointer
)oid
, (gpointer
)rinfo
);
106 g_hash_table_insert(oid_table
, (gpointer
)oid
, (gpointer
)name
);
109 /* if we are not using RTSE, then we must register ROS with BER (ACSE) */
110 register_ber_oid_dissector_handle(oid
, ros_handle
, proto
, name
);
113 static new_dissector_t
ros_lookup_opr_dissector(gint32 opcode_lcl
, const ros_opr_t
*operations
, gboolean argument
)
115 /* we don't know what order asn2wrs/module definition is, so ... */
117 for(;operations
->arg_pdu
!= (new_dissector_t
)(-1); operations
++)
118 if(operations
->opcode
== opcode_lcl
)
119 return argument
? operations
->arg_pdu
: operations
->res_pdu
;
125 static new_dissector_t
ros_lookup_err_dissector(gint32 errcode
, const ros_err_t
*errors
)
127 /* we don't know what order asn2wrs/module definition is, so ... */
129 for(;errors
->err_pdu
!= (new_dissector_t
) (-1); errors
++) {
130 if(errors
->errcode
== errcode
)
131 return errors
->err_pdu
;
138 static gboolean
ros_try_string(const char *oid
, tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, struct SESSION_DATA_STRUCTURE
* session
)
141 gint32 opcode_lcl
= 0;
142 const gchar
*opname
= NULL
;
143 const gchar
*suffix
= NULL
;
144 new_dissector_t opdissector
= NULL
;
145 const value_string
*lookup
;
146 proto_item
*item
=NULL
;
147 proto_tree
*ros_tree
=NULL
;
149 if((session
!= NULL
) && ((rinfo
= (ros_info_t
*)g_hash_table_lookup(protocol_table
, oid
)) != NULL
)) {
152 item
= proto_tree_add_item(tree
, *(rinfo
->proto
), tvb
, 0, -1, ENC_NA
);
153 ros_tree
= proto_item_add_subtree(item
, *(rinfo
->ett_proto
));
156 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, rinfo
->name
);
158 /* if this is a bind operation */
159 if((session
->ros_op
& ROS_OP_TYPE_MASK
) == ROS_OP_BIND
) {
160 /* use the in-built operation codes */
161 if((session
->ros_op
& ROS_OP_PDU_MASK
) == ROS_OP_ERROR
)
162 opcode_lcl
= err_ros_bind
;
164 opcode_lcl
= op_ros_bind
;
166 /* otherwise just take the opcode */
167 opcode_lcl
= session
->ros_op
& ROS_OP_OPCODE_MASK
;
169 /* default lookup in the operations */
170 lookup
= rinfo
->opr_code_strings
;
172 switch(session
->ros_op
& ROS_OP_PDU_MASK
) {
173 case ROS_OP_ARGUMENT
:
174 opdissector
= ros_lookup_opr_dissector(opcode_lcl
, rinfo
->opr_code_dissectors
, TRUE
);
175 suffix
= "_argument";
178 opdissector
= ros_lookup_opr_dissector(opcode_lcl
, rinfo
->opr_code_dissectors
, FALSE
);
182 opdissector
= ros_lookup_err_dissector(opcode_lcl
, rinfo
->err_code_dissectors
);
183 lookup
= rinfo
->err_code_strings
;
191 opname
= val_to_str(opcode_lcl
, lookup
, "Unknown opcode (%d)");
193 col_set_str(pinfo
->cinfo
, COL_INFO
, opname
);
195 col_append_str(pinfo
->cinfo
, COL_INFO
, suffix
);
197 (*opdissector
)(tvb
, pinfo
, ros_tree
, NULL
);
207 call_ros_oid_callback(const char *oid
, tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, struct SESSION_DATA_STRUCTURE
* session
)
211 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
213 if(!ros_try_string(oid
, next_tvb
, pinfo
, tree
, session
) &&
214 !dissector_try_string(ros_oid_dissector_table
, oid
, next_tvb
, pinfo
, tree
, session
)){
215 proto_item
*item
=proto_tree_add_text(tree
, next_tvb
, 0, tvb_length_remaining(tvb
, offset
), "ROS: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid
);
216 proto_tree
*next_tree
=proto_item_add_subtree(item
, ett_ros_unknown
);
218 expert_add_info_format(pinfo
, item
, &ei_ros_dissector_oid_not_implemented
,
219 "ROS: Dissector for OID %s not implemented", oid
);
220 dissect_unknown_ber(pinfo
, next_tvb
, offset
, next_tree
);
223 /*XXX until we change the #.REGISTER signature for _PDU()s
224 * into new_dissector_t we have to do this kludge with
225 * manually step past the content in the ANY type.
227 offset
+=tvb_length_remaining(tvb
, offset
);
234 ros_info_hash_matched(gconstpointer k
)
236 const ros_call_response_t
*key
= (const ros_call_response_t
*)k
;
238 return key
->invokeId
;
242 ros_info_equal_matched(gconstpointer k1
, gconstpointer k2
)
244 const ros_call_response_t
*key1
= (const ros_call_response_t
*)k1
;
245 const ros_call_response_t
*key2
= (const ros_call_response_t
*)k2
;
247 if( key1
->req_frame
&& key2
->req_frame
&& (key1
->req_frame
!=key2
->req_frame
) ){
250 /* a response may span multiple frames
251 if( key1->rep_frame && key2->rep_frame && (key1->rep_frame!=key2->rep_frame) ){
256 return key1
->invokeId
==key2
->invokeId
;
260 ros_info_hash_unmatched(gconstpointer k
)
262 const ros_call_response_t
*key
= (const ros_call_response_t
*)k
;
264 return key
->invokeId
;
268 ros_info_equal_unmatched(gconstpointer k1
, gconstpointer k2
)
270 const ros_call_response_t
*key1
= (const ros_call_response_t
*)k1
;
271 const ros_call_response_t
*key2
= (const ros_call_response_t
*)k2
;
273 return key1
->invokeId
==key2
->invokeId
;
276 static ros_call_response_t
*
277 ros_match_call_response(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint invokeId
, gboolean isInvoke
)
279 ros_call_response_t rcr
, *rcrp
=NULL
;
280 ros_conv_info_t
*ros_info
= ros_info_items
;
282 /* first see if we have already matched this */
284 rcr
.invokeId
=invokeId
;
285 rcr
.is_request
= isInvoke
;
288 rcr
.req_frame
=pinfo
->fd
->num
;
292 rcr
.rep_frame
=pinfo
->fd
->num
;
295 rcrp
=(ros_call_response_t
*)g_hash_table_lookup(ros_info
->matched
, &rcr
);
298 /* we have found a match */
299 rcrp
->is_request
=rcr
.is_request
;
303 /* we haven't found a match - try and match it up */
306 /* this a a request - add it to the unmatched list */
308 /* check that we dont already have one of those in the
309 unmatched list and if so remove it */
311 rcr
.invokeId
=invokeId
;
313 rcrp
=(ros_call_response_t
*)g_hash_table_lookup(ros_info
->unmatched
, &rcr
);
316 g_hash_table_remove(ros_info
->unmatched
, rcrp
);
319 /* if we cant reuse the old one, grab a new chunk */
321 rcrp
=wmem_new(wmem_file_scope(), ros_call_response_t
);
323 rcrp
->invokeId
=invokeId
;
324 rcrp
->req_frame
=pinfo
->fd
->num
;
325 rcrp
->req_time
=pinfo
->fd
->abs_ts
;
327 rcrp
->is_request
=TRUE
;
328 g_hash_table_insert(ros_info
->unmatched
, rcrp
, rcrp
);
333 /* this is a result - it should be in our unmatched list */
335 rcr
.invokeId
=invokeId
;
336 rcrp
=(ros_call_response_t
*)g_hash_table_lookup(ros_info
->unmatched
, &rcr
);
340 if(!rcrp
->rep_frame
){
341 g_hash_table_remove(ros_info
->unmatched
, rcrp
);
342 rcrp
->rep_frame
=pinfo
->fd
->num
;
343 rcrp
->is_request
=FALSE
;
344 g_hash_table_insert(ros_info
->matched
, rcrp
, rcrp
);
350 if(rcrp
){ /* we have found a match */
351 proto_item
*item
= NULL
;
353 if(rcrp
->is_request
){
354 item
=proto_tree_add_uint(tree
, hf_ros_response_in
, tvb
, 0, 0, rcrp
->rep_frame
);
355 PROTO_ITEM_SET_GENERATED (item
);
358 item
=proto_tree_add_uint(tree
, hf_ros_response_to
, tvb
, 0, 0, rcrp
->req_frame
);
359 PROTO_ITEM_SET_GENERATED (item
);
360 nstime_delta(&ns
, &pinfo
->fd
->abs_ts
, &rcrp
->req_time
);
361 item
=proto_tree_add_time(tree
, hf_ros_time
, tvb
, 0, 0, &ns
);
362 PROTO_ITEM_SET_GENERATED (item
);
369 #include "packet-ros-fn.c"
372 * Dissect ROS PDUs inside a PPDU.
375 dissect_ros(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
381 proto_tree
*next_tree
=NULL
;
382 conversation_t
*conversation
;
383 ros_conv_info_t
*ros_info
= NULL
;
385 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, TRUE
, pinfo
);
387 /* save parent_tree so subdissectors can create new top nodes */
388 top_tree
=parent_tree
;
390 /* do we have application context from the acse dissector? */
393 proto_tree_add_text(parent_tree
, tvb
, offset
, -1,
394 "Internal error:can't get application context from ACSE dissector.");
399 asn1_ctx
.private_data
= data
;
400 conversation
= find_or_create_conversation(pinfo
);
403 * Do we already have our info
405 ros_info
= (ros_conv_info_t
*)conversation_get_proto_data(conversation
, proto_ros
);
406 if (ros_info
== NULL
) {
408 /* No. Attach that information to the conversation. */
410 ros_info
= (ros_conv_info_t
*)g_malloc(sizeof(ros_conv_info_t
));
411 ros_info
->matched
=g_hash_table_new(ros_info_hash_matched
, ros_info_equal_matched
);
412 ros_info
->unmatched
=g_hash_table_new(ros_info_hash_unmatched
, ros_info_equal_unmatched
);
414 conversation_add_proto_data(conversation
, proto_ros
, ros_info
);
416 ros_info
->next
= ros_info_items
;
417 ros_info_items
= ros_info
;
420 item
= proto_tree_add_item(parent_tree
, proto_ros
, tvb
, 0, -1, ENC_NA
);
421 tree
= proto_item_add_subtree(item
, ett_ros
);
423 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ROS");
424 col_clear(pinfo
->cinfo
, COL_INFO
);
426 while (tvb_reported_length_remaining(tvb
, offset
) > 0){
428 offset
=dissect_ros_ROS(FALSE
, tvb
, offset
, &asn1_ctx
, tree
, -1);
429 if(offset
== old_offset
){
430 item
= proto_tree_add_text(tree
, tvb
, offset
, -1,"Unknown ROS PDU");
433 expert_add_info(pinfo
, item
, &ei_ros_unknown_ros_pdu
);
434 next_tree
=proto_item_add_subtree(item
, ett_ros_unknown
);
435 dissect_unknown_ber(pinfo
, tvb
, offset
, next_tree
);
442 return tvb_length(tvb
);
448 ros_conv_info_t
*ros_info
;
450 /* Free up state attached to the ros_info structures */
451 for (ros_info
= ros_info_items
; ros_info
!= NULL
; ) {
452 ros_conv_info_t
*last
;
454 g_hash_table_destroy(ros_info
->matched
);
455 ros_info
->matched
=NULL
;
456 g_hash_table_destroy(ros_info
->unmatched
);
457 ros_info
->unmatched
=NULL
;
460 ros_info
= ros_info
->next
;
464 ros_info_items
= NULL
;
468 /*--- proto_register_ros -------------------------------------------*/
469 void proto_register_ros(void) {
472 static hf_register_info hf
[] =
474 { &hf_ros_response_in
,
475 { "Response In", "ros.response_in",
476 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
477 "The response to this remote operation invocation is in this frame", HFILL
}},
478 { &hf_ros_response_to
,
479 { "Response To", "ros.response_to",
480 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
481 "This is a response to the remote operation invocation in this frame", HFILL
}},
483 { "Time", "ros.time",
484 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
485 "The time between the Invoke and the Response", HFILL
}},
487 #include "packet-ros-hfarr.c"
490 /* List of subtrees */
491 static gint
*ett
[] = {
494 #include "packet-ros-ettarr.c"
497 static ei_register_info ei
[] = {
498 { &ei_ros_dissector_oid_not_implemented
, { "ros.dissector_oid_not_implemented", PI_UNDECODED
, PI_WARN
, "ROS: Dissector for OID not implemented", EXPFILL
}},
499 { &ei_ros_unknown_ros_pdu
, { "ros.unknown_ros_pdu", PI_UNDECODED
, PI_WARN
, "Unknown ROS PDU", EXPFILL
}},
502 expert_module_t
* expert_ros
;
504 /* Register protocol */
505 proto_ros
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
506 new_register_dissector("ros", dissect_ros
, proto_ros
);
507 /* Register fields and subtrees */
508 proto_register_field_array(proto_ros
, hf
, array_length(hf
));
509 proto_register_subtree_array(ett
, array_length(ett
));
510 expert_ros
= expert_register_protocol(proto_ros
);
511 expert_register_field_array(expert_ros
, ei
, array_length(ei
));
513 ros_oid_dissector_table
= register_dissector_table("ros.oid", "ROS OID Dissectors", FT_STRING
, BASE_NONE
);
514 oid_table
=g_hash_table_new(g_str_hash
, g_str_equal
);
515 protocol_table
=g_hash_table_new(g_str_hash
, g_str_equal
);
517 ros_handle
= find_dissector("ros");
519 register_init_routine(ros_reinit
);
523 /*--- proto_reg_handoff_ros --- */
524 void proto_reg_handoff_ros(void) {