2005-09-04 16:22:12 +00:00
/* packet-ros_asn1.c
* Routines for ROS packet dissection
* Graeme Lunt 2005
*
* $ Id $
*
2006-05-21 05:12:17 +00:00
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
2005-09-04 16:22:12 +00:00
* Copyright 1998 Gerald Combs
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2012-06-28 22:56:06 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2005-09-04 16:22:12 +00:00
*/
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <glib.h>
# include <epan/packet.h>
# include <epan/conversation.h>
2006-05-01 10:17:59 +00:00
# include <epan/emem.h>
2007-05-13 20:58:29 +00:00
# include <epan/asn1.h>
2009-05-20 09:27:45 +00:00
# include <epan/expert.h>
2005-09-04 16:22:12 +00:00
# include "packet-ber.h"
2005-09-04 20:30:31 +00:00
# include "packet-pres.h"
2005-09-04 16:22:12 +00:00
# include "packet-ros.h"
# define PNAME "X.880 OSI Remote Operations Service"
# define PSNAME "ROS"
# define PFNAME "ros"
/* Initialize the protocol and registered fields */
2009-10-11 16:24:29 +00:00
static int proto_ros = - 1 ;
2005-09-04 16:22:12 +00:00
static proto_tree * top_tree = NULL ;
static guint32 opcode ;
2006-05-01 10:17:59 +00:00
static guint32 invokeid ;
2005-09-04 16:22:12 +00:00
2005-10-24 21:42:19 +00:00
static dissector_handle_t ros_handle = NULL ;
2006-05-01 10:17:59 +00:00
typedef struct ros_conv_info_t {
struct ros_conv_info_t * next ;
GHashTable * unmatched ; /* unmatched operations */
GHashTable * matched ; /* matched operations */
} ros_conv_info_t ;
static ros_conv_info_t * ros_info_items = NULL ;
typedef struct ros_call_response {
gboolean is_request ;
guint32 req_frame ;
nstime_t req_time ;
guint32 rep_frame ;
guint invokeId ;
} ros_call_response_t ;
static int hf_ros_response_in = - 1 ;
static int hf_ros_response_to = - 1 ;
static int hf_ros_time = - 1 ;
2005-09-04 16:22:12 +00:00
# include "packet-ros-hf.c"
/* Initialize the subtree pointers */
static gint ett_ros = - 1 ;
# include "packet-ros-ett.c"
static dissector_table_t ros_oid_dissector_table = NULL ;
2007-12-03 19:29:24 +00:00
2005-09-04 16:22:12 +00:00
static GHashTable * oid_table = NULL ;
2007-12-03 19:29:24 +00:00
static GHashTable * protocol_table = NULL ;
2005-09-04 16:22:12 +00:00
static gint ett_ros_unknown = - 1 ;
void
2005-10-24 21:42:19 +00:00
register_ros_oid_dissector_handle ( const char * oid , dissector_handle_t dissector , int proto _U_ , const char * name , gboolean uses_rtse )
2005-09-04 16:22:12 +00:00
{
dissector_add_string ( " ros.oid " , oid , dissector ) ;
g_hash_table_insert ( oid_table , ( gpointer ) oid , ( gpointer ) name ) ;
2005-10-24 21:42:19 +00:00
if ( ! uses_rtse )
/* if we are not using RTSE, then we must register ROS with BER (ACSE) */
register_ber_oid_dissector_handle ( oid , ros_handle , proto , name ) ;
2005-09-04 16:22:12 +00:00
}
2007-12-03 19:29:24 +00:00
void
register_ros_protocol_info ( const char * oid , const ros_info_t * rinfo , int proto _U_ , const char * name , gboolean uses_rtse )
{
2009-10-18 20:13:56 +00:00
g_hash_table_insert ( protocol_table , ( gpointer ) oid , ( gpointer ) rinfo ) ;
2007-12-03 19:29:24 +00:00
g_hash_table_insert ( oid_table , ( gpointer ) oid , ( gpointer ) name ) ;
if ( ! uses_rtse )
/* if we are not using RTSE, then we must register ROS with BER (ACSE) */
register_ber_oid_dissector_handle ( oid , ros_handle , proto , name ) ;
}
2010-01-28 14:43:01 +00:00
static new_dissector_t ros_lookup_opr_dissector ( gint32 opcode_lcl , const ros_opr_t * operations , gboolean argument )
2007-12-03 19:29:24 +00:00
{
/* we don't know what order asn2wrs/module definition is, so ... */
if ( operations ) {
2009-10-18 20:13:56 +00:00
for ( ; operations - > arg_pdu ! = ( new_dissector_t ) ( - 1 ) ; operations + + )
2010-01-28 14:43:01 +00:00
if ( operations - > opcode = = opcode_lcl )
2007-12-03 19:29:24 +00:00
return argument ? operations - > arg_pdu : operations - > res_pdu ;
2009-10-18 20:13:56 +00:00
2007-12-03 19:29:24 +00:00
}
return NULL ;
}
static new_dissector_t ros_lookup_err_dissector ( gint32 errcode , const ros_err_t * errors )
{
/* we don't know what order asn2wrs/module definition is, so ... */
if ( errors ) {
for ( ; errors - > err_pdu ! = ( new_dissector_t ) ( - 1 ) ; errors + + ) {
2009-10-18 20:13:56 +00:00
if ( errors - > errcode = = errcode )
2007-12-03 19:29:24 +00:00
return errors - > err_pdu ;
}
}
return NULL ;
}
static gboolean ros_try_string ( const char * oid , tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
ros_info_t * rinfo ;
2010-01-28 14:43:01 +00:00
gint32 opcode_lcl = 0 ;
2007-12-03 19:29:24 +00:00
const gchar * opname = NULL ;
const gchar * suffix = NULL ;
new_dissector_t opdissector = NULL ;
const value_string * lookup ;
proto_item * item = NULL ;
proto_tree * ros_tree = NULL ;
2010-06-09 14:45:38 +00:00
struct SESSION_DATA_STRUCTURE * session = NULL ;
session = ( ( struct SESSION_DATA_STRUCTURE * ) ( pinfo - > private_data ) ) ;
2007-12-03 19:29:24 +00:00
2010-06-09 14:45:38 +00:00
if ( ( session ! = NULL ) & & ( ( rinfo = ( ros_info_t * ) g_hash_table_lookup ( protocol_table , oid ) ) ! = NULL ) ) {
2007-12-03 19:29:24 +00:00
if ( tree ) {
2011-07-19 18:48:31 +00:00
item = proto_tree_add_item ( tree , * ( rinfo - > proto ) , tvb , 0 , - 1 , ENC_NA ) ;
2007-12-03 19:29:24 +00:00
ros_tree = proto_item_add_subtree ( item , * ( rinfo - > ett_proto ) ) ;
}
2010-01-27 14:54:48 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , rinfo - > name ) ;
2007-12-03 19:29:24 +00:00
/* if this is a bind operation */
if ( ( session - > ros_op & ROS_OP_TYPE_MASK ) = = ROS_OP_BIND ) {
/* use the in-built operation codes */
if ( ( session - > ros_op & ROS_OP_PDU_MASK ) = = ROS_OP_ERROR )
2010-01-28 14:43:01 +00:00
opcode_lcl = err_ros_bind ;
2007-12-03 19:29:24 +00:00
else
2010-01-28 14:43:01 +00:00
opcode_lcl = op_ros_bind ;
2009-10-18 20:13:56 +00:00
} else
2007-12-03 19:29:24 +00:00
/* otherwise just take the opcode */
2010-01-28 14:43:01 +00:00
opcode_lcl = session - > ros_op & ROS_OP_OPCODE_MASK ;
2007-12-03 19:29:24 +00:00
/* default lookup in the operations */
lookup = rinfo - > opr_code_strings ;
switch ( session - > ros_op & ROS_OP_PDU_MASK ) {
2009-10-18 20:13:56 +00:00
case ROS_OP_ARGUMENT :
2010-01-28 14:43:01 +00:00
opdissector = ros_lookup_opr_dissector ( opcode_lcl , rinfo - > opr_code_dissectors , TRUE ) ;
2007-12-03 19:29:24 +00:00
suffix = " _argument " ;
break ;
2009-10-18 20:13:56 +00:00
case ROS_OP_RESULT :
2010-01-28 14:43:01 +00:00
opdissector = ros_lookup_opr_dissector ( opcode_lcl , rinfo - > opr_code_dissectors , FALSE ) ;
2007-12-03 19:29:24 +00:00
suffix = " _result " ;
break ;
2009-10-18 20:13:56 +00:00
case ROS_OP_ERROR :
2010-01-28 14:43:01 +00:00
opdissector = ros_lookup_err_dissector ( opcode_lcl , rinfo - > err_code_dissectors ) ;
2007-12-03 19:29:24 +00:00
lookup = rinfo - > err_code_strings ;
break ;
default :
break ;
}
if ( opdissector ) {
2010-01-28 14:43:01 +00:00
opname = val_to_str ( opcode_lcl , lookup , " Unknown opcode (%d) " ) ;
2007-12-03 19:29:24 +00:00
if ( check_col ( pinfo - > cinfo , COL_INFO ) ) {
col_set_str ( pinfo - > cinfo , COL_INFO , opname ) ;
if ( suffix )
2008-10-31 17:27:51 +00:00
col_append_str ( pinfo - > cinfo , COL_INFO , suffix ) ;
2007-12-03 19:29:24 +00:00
}
2009-10-18 20:13:56 +00:00
2011-11-14 17:35:04 +00:00
( * opdissector ) ( tvb , pinfo , ros_tree ) ;
2007-12-03 19:29:24 +00:00
return TRUE ;
}
}
return FALSE ;
}
2010-06-09 14:45:38 +00:00
int
2005-09-04 16:22:12 +00:00
call_ros_oid_callback ( const char * oid , tvbuff_t * tvb , int offset , packet_info * pinfo , proto_tree * tree )
{
tvbuff_t * next_tvb ;
next_tvb = tvb_new_subset ( tvb , offset , tvb_length_remaining ( tvb , offset ) , tvb_reported_length_remaining ( tvb , offset ) ) ;
2007-12-03 19:29:24 +00:00
if ( ! ros_try_string ( oid , next_tvb , pinfo , tree ) & &
! dissector_try_string ( ros_oid_dissector_table , oid , next_tvb , pinfo , tree ) ) {
2009-05-20 09:27:45 +00:00
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 ) ;
proto_tree * next_tree = proto_item_add_subtree ( item , ett_ros_unknown ) ;
2005-09-04 16:22:12 +00:00
2009-05-20 09:27:45 +00:00
expert_add_info_format ( pinfo , item , PI_UNDECODED , PI_WARN ,
" ROS: Dissector for OID %s not implemented " , oid ) ;
2005-09-04 16:22:12 +00:00
dissect_unknown_ber ( pinfo , next_tvb , offset , next_tree ) ;
}
2009-10-18 20:13:56 +00:00
/*XXX until we change the #.REGISTER signature for _PDU()s
2005-09-04 16:22:12 +00:00
* into new_dissector_t we have to do this kludge with
* manually step past the content in the ANY type .
*/
offset + = tvb_length_remaining ( tvb , offset ) ;
return offset ;
}
2005-09-04 20:30:31 +00:00
2006-05-01 10:17:59 +00:00
static guint
ros_info_hash_matched ( gconstpointer k )
{
const ros_call_response_t * key = k ;
return key - > invokeId ;
}
static gint
ros_info_equal_matched ( gconstpointer k1 , gconstpointer k2 )
{
const ros_call_response_t * key1 = k1 ;
const ros_call_response_t * key2 = k2 ;
if ( key1 - > req_frame & & key2 - > req_frame & & ( key1 - > req_frame ! = key2 - > req_frame ) ) {
return 0 ;
}
/* a response may span multiple frames
if ( key1 - > rep_frame & & key2 - > rep_frame & & ( key1 - > rep_frame ! = key2 - > rep_frame ) ) {
return 0 ;
}
*/
return key1 - > invokeId = = key2 - > invokeId ;
}
static guint
ros_info_hash_unmatched ( gconstpointer k )
{
const ros_call_response_t * key = k ;
return key - > invokeId ;
}
static gint
ros_info_equal_unmatched ( gconstpointer k1 , gconstpointer k2 )
{
const ros_call_response_t * key1 = k1 ;
const ros_call_response_t * key2 = k2 ;
return key1 - > invokeId = = key2 - > invokeId ;
}
static ros_call_response_t *
ros_match_call_response ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , guint invokeId , gboolean isInvoke )
{
ros_call_response_t rcr , * rcrp = NULL ;
ros_conv_info_t * ros_info = ros_info_items ;
/* first see if we have already matched this */
rcr . invokeId = invokeId ;
rcr . is_request = isInvoke ;
if ( isInvoke ) {
rcr . req_frame = pinfo - > fd - > num ;
rcr . rep_frame = 0 ;
} else {
rcr . req_frame = 0 ;
rcr . rep_frame = pinfo - > fd - > num ;
}
2009-10-18 20:13:56 +00:00
2006-05-01 10:17:59 +00:00
rcrp = g_hash_table_lookup ( ros_info - > matched , & rcr ) ;
if ( rcrp ) {
/* we have found a match */
rcrp - > is_request = rcr . is_request ;
} else {
2009-10-18 20:13:56 +00:00
2006-05-01 10:17:59 +00:00
/* we haven't found a match - try and match it up */
if ( isInvoke ) {
/* this a a request - add it to the unmatched list */
/* check that we dont already have one of those in the
unmatched list and if so remove it */
rcr . invokeId = invokeId ;
rcrp = g_hash_table_lookup ( ros_info - > unmatched , & rcr ) ;
if ( rcrp ) {
g_hash_table_remove ( ros_info - > unmatched , rcrp ) ;
}
2009-10-18 20:13:56 +00:00
2006-05-01 10:17:59 +00:00
/* if we cant reuse the old one, grab a new chunk */
if ( ! rcrp ) {
rcrp = se_alloc ( sizeof ( ros_call_response_t ) ) ;
}
rcrp - > invokeId = invokeId ;
rcrp - > req_frame = pinfo - > fd - > num ;
rcrp - > req_time = pinfo - > fd - > abs_ts ;
rcrp - > rep_frame = 0 ;
rcrp - > is_request = TRUE ;
g_hash_table_insert ( ros_info - > unmatched , rcrp , rcrp ) ;
return NULL ;
} else {
/* this is a result - it should be in our unmatched list */
rcr . invokeId = invokeId ;
rcrp = g_hash_table_lookup ( ros_info - > unmatched , & rcr ) ;
if ( rcrp ) {
if ( ! rcrp - > rep_frame ) {
g_hash_table_remove ( ros_info - > unmatched , rcrp ) ;
rcrp - > rep_frame = pinfo - > fd - > num ;
rcrp - > is_request = FALSE ;
g_hash_table_insert ( ros_info - > matched , rcrp , rcrp ) ;
}
}
}
}
if ( rcrp ) { /* we have found a match */
2007-11-13 10:26:30 +00:00
proto_item * item = NULL ;
2006-05-01 10:17:59 +00:00
if ( rcrp - > is_request ) {
2007-11-13 10:26:30 +00:00
item = proto_tree_add_uint ( tree , hf_ros_response_in , tvb , 0 , 0 , rcrp - > rep_frame ) ;
PROTO_ITEM_SET_GENERATED ( item ) ;
2006-05-01 10:17:59 +00:00
} else {
nstime_t ns ;
2007-11-13 10:26:30 +00:00
item = proto_tree_add_uint ( tree , hf_ros_response_to , tvb , 0 , 0 , rcrp - > req_frame ) ;
PROTO_ITEM_SET_GENERATED ( item ) ;
2006-05-01 10:17:59 +00:00
nstime_delta ( & ns , & pinfo - > fd - > abs_ts , & rcrp - > req_time ) ;
2007-11-13 10:26:30 +00:00
item = proto_tree_add_time ( tree , hf_ros_time , tvb , 0 , 0 , & ns ) ;
PROTO_ITEM_SET_GENERATED ( item ) ;
2006-05-01 10:17:59 +00:00
}
}
2009-10-18 20:13:56 +00:00
2006-05-01 10:17:59 +00:00
return rcrp ;
}
# include "packet-ros-fn.c"
2005-09-04 20:30:31 +00:00
2005-09-04 16:22:12 +00:00
/*
* Dissect ROS PDUs inside a PPDU .
*/
static void
dissect_ros ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * parent_tree )
{
int offset = 0 ;
int old_offset ;
proto_item * item = NULL ;
proto_tree * tree = NULL ;
2008-04-13 16:11:15 +00:00
proto_tree * next_tree = NULL ;
2006-05-01 10:17:59 +00:00
conversation_t * conversation ;
ros_conv_info_t * ros_info = NULL ;
2007-05-13 20:58:29 +00:00
asn1_ctx_t asn1_ctx ;
asn1_ctx_init ( & asn1_ctx , ASN1_ENC_BER , TRUE , pinfo ) ;
2005-09-04 16:22:12 +00:00
/* save parent_tree so subdissectors can create new top nodes */
top_tree = parent_tree ;
/* do we have application context from the acse dissector? */
if ( ! pinfo - > private_data ) {
if ( parent_tree ) {
proto_tree_add_text ( parent_tree , tvb , offset , - 1 ,
" Internal error:can't get application context from ACSE dissector. " ) ;
2009-10-18 20:13:56 +00:00
}
2005-09-04 16:22:12 +00:00
return ;
}
2010-05-13 18:55:31 +00:00
conversation = find_or_create_conversation ( pinfo ) ;
2006-05-01 10:17:59 +00:00
/*
* Do we already have our info
*/
ros_info = conversation_get_proto_data ( conversation , proto_ros ) ;
if ( ros_info = = NULL ) {
/* No. Attach that information to the conversation. */
2009-10-18 20:13:56 +00:00
ros_info = g_malloc ( sizeof ( ros_conv_info_t ) ) ;
2006-05-01 10:17:59 +00:00
ros_info - > matched = g_hash_table_new ( ros_info_hash_matched , ros_info_equal_matched ) ;
ros_info - > unmatched = g_hash_table_new ( ros_info_hash_unmatched , ros_info_equal_unmatched ) ;
2009-10-18 20:13:56 +00:00
2006-05-01 10:17:59 +00:00
conversation_add_proto_data ( conversation , proto_ros , ros_info ) ;
2009-10-18 20:13:56 +00:00
2006-05-01 10:17:59 +00:00
ros_info - > next = ros_info_items ;
ros_info_items = ros_info ;
}
/* pinfo->private_data = ros_info; */
2005-09-04 16:22:12 +00:00
if ( parent_tree ) {
2011-07-19 18:48:31 +00:00
item = proto_tree_add_item ( parent_tree , proto_ros , tvb , 0 , - 1 , ENC_NA ) ;
2005-09-04 16:22:12 +00:00
tree = proto_item_add_subtree ( item , ett_ros ) ;
}
2009-08-09 06:26:46 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " ROS " ) ;
2009-08-09 07:36:13 +00:00
col_clear ( pinfo - > cinfo , COL_INFO ) ;
2005-09-04 16:22:12 +00:00
while ( tvb_reported_length_remaining ( tvb , offset ) > 0 ) {
old_offset = offset ;
2007-05-13 20:58:29 +00:00
offset = dissect_ros_ROS ( FALSE , tvb , offset , & asn1_ctx , tree , - 1 ) ;
2005-09-04 16:22:12 +00:00
if ( offset = = old_offset ) {
2008-04-13 16:11:15 +00:00
item = proto_tree_add_text ( tree , tvb , offset , - 1 , " Unknown ROS PDU " ) ;
if ( item ) {
2009-05-20 09:27:45 +00:00
expert_add_info_format ( pinfo , item , PI_UNDECODED , PI_WARN , " Unknown ROS PDU " ) ;
2008-04-13 16:11:15 +00:00
next_tree = proto_item_add_subtree ( item , ett_ros_unknown ) ;
dissect_unknown_ber ( pinfo , tvb , offset , next_tree ) ;
}
2005-09-04 16:22:12 +00:00
break ;
}
}
}
2006-05-01 10:17:59 +00:00
static void
ros_reinit ( void )
{
ros_conv_info_t * ros_info ;
/* Free up state attached to the ros_info structures */
2009-10-18 20:13:56 +00:00
for ( ros_info = ros_info_items ; ros_info ! = NULL ; ) {
ros_conv_info_t * last ;
2006-05-01 10:17:59 +00:00
g_hash_table_destroy ( ros_info - > matched ) ;
ros_info - > matched = NULL ;
g_hash_table_destroy ( ros_info - > unmatched ) ;
ros_info - > unmatched = NULL ;
2009-10-18 20:13:56 +00:00
last = ros_info ;
ros_info = ros_info - > next ;
g_free ( last ) ;
2006-05-01 10:17:59 +00:00
}
ros_info_items = NULL ;
}
2005-09-04 16:22:12 +00:00
/*--- proto_register_ros -------------------------------------------*/
void proto_register_ros ( void ) {
/* List of fields */
static hf_register_info hf [ ] =
{
2006-05-01 10:17:59 +00:00
{ & hf_ros_response_in ,
{ " Response In " , " ros.response_in " ,
2009-07-07 09:02:59 +00:00
FT_FRAMENUM , BASE_NONE , NULL , 0x0 ,
2006-05-01 10:17:59 +00:00
" The response to this remote operation invocation is in this frame " , HFILL } } ,
{ & hf_ros_response_to ,
{ " Response To " , " ros.response_to " ,
2009-07-07 09:02:59 +00:00
FT_FRAMENUM , BASE_NONE , NULL , 0x0 ,
2006-05-01 10:17:59 +00:00
" This is a response to the remote operation invocation in this frame " , HFILL } } ,
{ & hf_ros_time ,
{ " Time " , " ros.time " ,
FT_RELATIVE_TIME , BASE_NONE , NULL , 0x0 ,
" The time between the Invoke and the Response " , HFILL } } ,
2005-09-04 16:22:12 +00:00
# include "packet-ros-hfarr.c"
} ;
/* List of subtrees */
static gint * ett [ ] = {
& ett_ros ,
& ett_ros_unknown ,
# include "packet-ros-ettarr.c"
} ;
/* Register protocol */
proto_ros = proto_register_protocol ( PNAME , PSNAME , PFNAME ) ;
register_dissector ( " ros " , dissect_ros , proto_ros ) ;
/* Register fields and subtrees */
proto_register_field_array ( proto_ros , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
ros_oid_dissector_table = register_dissector_table ( " ros.oid " , " ROS OID Dissectors " , FT_STRING , BASE_NONE ) ;
oid_table = g_hash_table_new ( g_str_hash , g_str_equal ) ;
2007-12-03 19:29:24 +00:00
protocol_table = g_hash_table_new ( g_str_hash , g_str_equal ) ;
2005-12-14 21:02:56 +00:00
ros_handle = find_dissector ( " ros " ) ;
2006-05-01 10:17:59 +00:00
register_init_routine ( ros_reinit ) ;
2005-09-04 16:22:12 +00:00
}
/*--- proto_reg_handoff_ros --- */
void proto_reg_handoff_ros ( void ) {
2005-10-24 21:42:19 +00:00
2005-09-04 16:22:12 +00:00
}