aboutsummaryrefslogtreecommitdiffstats
path: root/packet-nlm.c
diff options
context:
space:
mode:
Diffstat (limited to 'packet-nlm.c')
-rw-r--r--packet-nlm.c300
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