From 5b8ad79cb6645bb6d6488c6dc220041a0c8cdeb7 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 8 May 2002 12:51:45 +0000 Subject: [PATCH] Added option to match async NLM MSG with RES packets, to print which MSG packet matches which RES packet and v.v as well as (in RES packets) how long the call took to execute. svn path=/trunk/; revision=5417 --- packet-nlm.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 299 insertions(+), 1 deletion(-) diff --git a/packet-nlm.c b/packet-nlm.c index fc69d52f8a..fb5d880bb8 100644 --- a/packet-nlm.c +++ b/packet-nlm.c @@ -1,7 +1,7 @@ /* packet-nlm.c * Routines for nlm dissection * - * $Id: packet-nlm.c,v 1.25 2002/04/14 23:04:03 guy Exp $ + * $Id: packet-nlm.c,v 1.26 2002/05/08 12:51:45 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -44,6 +44,8 @@ #include "packet-rpc.h" #include "packet-nfs.h" #include "packet-nlm.h" +#include "prefs.h" +#include /* * NFS Lock Manager protocol specs can only be found in actual @@ -82,11 +84,210 @@ static int hf_nlm_share_mode = -1; static int hf_nlm_share_access = -1; static int hf_nlm_share_name = -1; static int hf_nlm_sequence = -1; +static int hf_nlm_request_in = -1; +static int hf_nlm_reply_in = -1; +static int hf_nlm_time = -1; static gint ett_nlm = -1; static gint ett_nlm_lock = -1; + +/* + * stuff to match MSG and RES packets for async NLM + */ + +static gboolean nlm_match_msgres = FALSE; +static GHashTable *nlm_msg_res_unmatched = NULL; +static GHashTable *nlm_msg_res_matched = NULL; + +/* XXX when matching the packets we should really check the conversation (only address + NOT ports) and command type as well. I am lazy and thinks the cookie itself is + good enough for now +*/ +typedef struct _nlm_msg_res_unmatched_data { + int req_frame; + nstime_t ns; + int cookie_len; + char *cookie; +} nlm_msg_res_unmatched_data; + +typedef struct _nlm_msg_res_matched_data { + int req_frame; + int rep_frame; + nstime_t ns; +} nlm_msg_res_matched_data; + +static gboolean +nlm_msg_res_unmatched_free_all(gpointer key_arg _U_, gpointer value, gpointer user_data _U_) +{ + nlm_msg_res_unmatched_data *umd = (nlm_msg_res_unmatched_data *)value; + + g_free(umd->cookie); + g_free(umd); + + return TRUE; +} +static gboolean +nlm_msg_res_matched_free_all(gpointer key_arg _U_, gpointer value, gpointer user_data _U_) +{ + nlm_msg_res_matched_data *md = (nlm_msg_res_matched_data *)value; + + g_free(md); + + return TRUE; +} + +static guint +nlm_msg_res_unmatched_hash(gconstpointer k) +{ + nlm_msg_res_unmatched_data *umd = (nlm_msg_res_unmatched_data *)k; + guint8 hash=0; + int i; + + for(i=0;icookie_len;i++){ + hash^=umd->cookie[i]; + } + + return hash; +} +static guint +nlm_msg_res_matched_hash(gconstpointer k) +{ + guint hash = (guint)k; + + return hash; +} + +static gint +nlm_msg_res_unmatched_equal(gconstpointer k1, gconstpointer k2) +{ + nlm_msg_res_unmatched_data *umd1 = (nlm_msg_res_unmatched_data *)k1; + nlm_msg_res_unmatched_data *umd2 = (nlm_msg_res_unmatched_data *)k2; + + if(umd1->cookie_len!=umd2->cookie_len){ + return 0; + } + + return( !memcmp(umd1->cookie, umd2->cookie, umd1->cookie_len)); +} +static gint +nlm_msg_res_matched_equal(gconstpointer k1, gconstpointer k2) +{ + guint mk1 = (guint)k1; + guint mk2 = (guint)k2; + + return( mk1==mk2 ); +} + +static void +nlm_msg_res_match_init(void) +{ + if(nlm_msg_res_unmatched != NULL){ + g_hash_table_foreach_remove(nlm_msg_res_unmatched, + nlm_msg_res_unmatched_free_all, NULL); + } else { + nlm_msg_res_unmatched=g_hash_table_new(nlm_msg_res_unmatched_hash, + nlm_msg_res_unmatched_equal); + } + + if(nlm_msg_res_matched != NULL){ + g_hash_table_foreach_remove(nlm_msg_res_matched, + nlm_msg_res_matched_free_all, NULL); + } else { + nlm_msg_res_matched=g_hash_table_new(nlm_msg_res_matched_hash, + nlm_msg_res_matched_equal); + } +} + +static void +nlm_print_msgres_reply(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb) +{ + nlm_msg_res_matched_data *md; + + md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num); + if(md){ + nstime_t ns; + proto_tree_add_uint(tree, hf_nlm_request_in, tvb, 0, 0, md->req_frame); + ns.secs= pinfo->fd->abs_secs-md->ns.secs; + ns.nsecs=pinfo->fd->abs_usecs*1000-md->ns.nsecs; + if(ns.nsecs<0){ + ns.nsecs+=1000000000; + ns.secs--; + } + proto_tree_add_time(tree, hf_nlm_time, tvb, 0, 0, &ns); + + } +} + +static void +nlm_print_msgres_request(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb) +{ + nlm_msg_res_matched_data *md; + + md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num); + if(md){ + proto_tree_add_uint(tree, hf_nlm_reply_in, tvb, 0, 0, md->rep_frame); + } +} + +static void +nlm_register_unmatched_res(packet_info *pinfo, tvbuff_t *tvb, int offset) +{ + nlm_msg_res_unmatched_data umd; + nlm_msg_res_unmatched_data *old_umd; + + umd.cookie_len=tvb_get_ntohl(tvb, offset); + umd.cookie=(char *)tvb_get_ptr(tvb, offset+4, -1); + + /* have we seen this cookie before? */ + old_umd=g_hash_table_lookup(nlm_msg_res_unmatched, (gconstpointer)&umd); + if(old_umd){ + nlm_msg_res_matched_data *md; + + md=g_malloc(sizeof(nlm_msg_res_matched_data)); + md->req_frame=old_umd->req_frame; + md->rep_frame=pinfo->fd->num; + md->ns=old_umd->ns; + g_hash_table_insert(nlm_msg_res_matched, (gpointer)md->req_frame, (gpointer)md); + g_hash_table_insert(nlm_msg_res_matched, (gpointer)md->rep_frame, (gpointer)md); + + g_hash_table_remove(nlm_msg_res_unmatched, (gconstpointer)old_umd); + g_free(old_umd->cookie); + g_free(old_umd); + } +} + +static void +nlm_register_unmatched_msg(packet_info *pinfo, tvbuff_t *tvb, int offset) +{ + nlm_msg_res_unmatched_data *umd; + nlm_msg_res_unmatched_data *old_umd; + + /* allocate and build the unmatched structure for this request */ + umd=g_malloc(sizeof(nlm_msg_res_unmatched_data)); + umd->req_frame=pinfo->fd->num; + umd->ns.secs=pinfo->fd->abs_secs; + umd->ns.nsecs=pinfo->fd->abs_usecs*1000; + umd->cookie_len=tvb_get_ntohl(tvb, offset); + umd->cookie=g_malloc(umd->cookie_len); + tvb_memcpy(tvb, (guint8 *)umd->cookie, offset+4, umd->cookie_len); + + /* remove any old duplicates */ + old_umd=g_hash_table_lookup(nlm_msg_res_unmatched, (gconstpointer)umd); + if(old_umd){ + g_hash_table_remove(nlm_msg_res_unmatched, (gconstpointer)old_umd); + g_free(old_umd->cookie); + g_free(old_umd); + } + + /* add new one */ + g_hash_table_insert(nlm_msg_res_unmatched, (gpointer)umd, (gpointer)umd); +} + + + + static const value_string names_nlm_stats[] = { /* NLM_GRANTED is the function number 5 and the state code 0. @@ -190,6 +391,17 @@ static int dissect_nlm_test(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int version) { + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if(rpc_call->proc==6){ /* NLM_TEST_MSG */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_msg(pinfo, tvb, offset); + } else { + nlm_print_msgres_request(pinfo, tree, tvb); + } + } + } + offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset); offset += 4; @@ -201,6 +413,17 @@ static int dissect_nlm_lock(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,int version) { + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if(rpc_call->proc==7){ /* NLM_LOCK_MSG */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_msg(pinfo, tvb, offset); + } else { + nlm_print_msgres_request(pinfo, tree, tvb); + } + } + } + offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); offset = dissect_rpc_bool(tvb, tree, hf_nlm_block, offset); offset = dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset); @@ -214,6 +437,17 @@ static int dissect_nlm_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,int version) { + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if(rpc_call->proc==8){ /* NLM_CANCEL_MSG */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_msg(pinfo, tvb, offset); + } else { + nlm_print_msgres_request(pinfo, tree, tvb); + } + } + } + offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); offset = dissect_rpc_bool(tvb, tree, hf_nlm_block, offset); offset = dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset); @@ -225,6 +459,17 @@ static int dissect_nlm_unlock(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,int version) { + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if(rpc_call->proc==9){ /* NLM_UNLOCK_MSG */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_msg(pinfo, tvb, offset); + } else { + nlm_print_msgres_request(pinfo, tree, tvb); + } + } + } + offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); offset = dissect_lock(tvb, pinfo, tree, version, offset); return offset; @@ -234,6 +479,16 @@ static int dissect_nlm_granted(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,int version) { + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if(rpc_call->proc==10){ /* NLM_GRANTED_MSG */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_msg(pinfo, tvb, offset); + } else { + nlm_print_msgres_request(pinfo, tree, tvb); + } + } + } offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); offset = dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset); offset = dissect_lock(tvb, pinfo, tree, version, offset); @@ -248,6 +503,17 @@ dissect_nlm_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_item* lock_item = NULL; proto_tree* lock_tree = NULL; + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if(rpc_call->proc==11){ /* NLM_TEST_RES */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_res(pinfo, tvb, offset); + } else { + nlm_print_msgres_reply(pinfo, tree, tvb); + } + } + } + offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); if (tree) { @@ -361,6 +627,20 @@ static int dissect_nlm_gen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree) { + if(nlm_match_msgres){ + rpc_call_info_value *rpc_call=pinfo->private_data; + if((rpc_call->proc==12) /* NLM_LOCK_RES */ + || (rpc_call->proc==13) /* NLM_CANCEL_RES */ + || (rpc_call->proc==14) /* NLM_UNLOCK_RES */ + || (rpc_call->proc==15) ){ /* NLM_GRENTED_RES */ + if( (!pinfo->fd->flags.visited) ){ + nlm_register_unmatched_res(pinfo, tvb, offset); + } else { + nlm_print_msgres_reply(pinfo, tree, tvb); + } + } + } + offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset); offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset); return offset; @@ -749,17 +1029,35 @@ proto_register_nlm(void) { &hf_nlm_sequence, { "sequence", "nlm.sequence", FT_INT32, BASE_DEC, NULL, 0, "sequence", HFILL }}, + { &hf_nlm_request_in, { + "Request MSG in", "nlm.msg_in", FT_UINT32, BASE_DEC, + NULL, 0, "The RES packet is a response to the MSG in this packet", HFILL }}, + { &hf_nlm_reply_in, { + "Reply RES in", "nlm.res_in", FT_UINT32, BASE_DEC, + NULL, 0, "The response to this MSG packet is in this packet", HFILL }}, + { &hf_nlm_time, { + "Time from request", "nlm.time", FT_RELATIVE_TIME, BASE_NONE, + NULL, 0, "Time between Request and Reply for async NLM calls", HFILL }}, + }; static gint *ett[] = { &ett_nlm, &ett_nlm_lock, }; + module_t *nlm_module; proto_nlm = proto_register_protocol("Network Lock Manager Protocol", "NLM", "nlm"); proto_register_field_array(proto_nlm, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + + nlm_module = prefs_register_protocol(proto_nlm, NULL); + prefs_register_bool_preference(nlm_module, "nlm_msg_res_matching", + "Match MSG/RES packets for async NLM", + "Whether the dissector will track and match MSG and RES calls for asynchronous NLM", + &nlm_match_msgres); + register_init_routine(nlm_msg_res_match_init); } void