diff options
Diffstat (limited to 'packet-nlm.c')
-rw-r--r-- | packet-nlm.c | 300 |
1 files changed, 299 insertions, 1 deletions
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 <gerald@ethereal.com> @@ -44,6 +44,8 @@ #include "packet-rpc.h" #include "packet-nfs.h" #include "packet-nlm.h" +#include "prefs.h" +#include <string.h> /* * 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;i<umd->cookie_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 |