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
This commit is contained in:
Ronnie Sahlberg 2002-05-08 12:51:45 +00:00
parent 7181a4d327
commit 5b8ad79cb6
1 changed files with 299 additions and 1 deletions

View File

@ -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