Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-nlm.c
index 7232bf1866cda966e2878ed9cebb125bbdbe5192..17154de517de28c3a5a2e6ff363abecdf4a25f0e 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-nlm.c
  * Routines for nlm dissection
  *
- * $Id: packet-nlm.c,v 1.18 2001/06/18 02:17:50 guy Exp $
+ * $Id: packet-nlm.c,v 1.28 2002/08/02 23:35:55 jmayer Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -9,7 +9,7 @@
  *
  * Copied from packet-mount.c
  *
- * 2001-JAN  Ronnie Sahlberg <rsahlber@bigpond.net.au>
+ * 2001-JAN  Ronnie Sahlberg <See AUTHORS for email>
  *  Updates to version 1 of the protocol.
  *  Added version 3 of the protocol.
  *  Added version 4 of the protocol.
 #endif
 
 
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 
 #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
@@ -68,8 +66,11 @@ static int hf_nlm_lock_caller_name = -1;
 static int hf_nlm_lock_owner = -1;
 static int hf_nlm_lock_svid = -1;
 static int hf_nlm_lock_l_offset = -1;
+static int hf_nlm_lock_l_offset64 = -1;
 static int hf_nlm_lock_l_len = -1;
+static int hf_nlm_lock_l_len64 = -1;
 static int hf_nlm_reclaim = -1;
+static int hf_nlm_stat = -1;
 static int hf_nlm_state = -1;
 static int hf_nlm_test_stat = -1;
 static int hf_nlm_test_stat_stat = -1;
@@ -79,12 +80,245 @@ 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;
 
 
-const value_string names_nlm_state[] =
+
+/* 
+ * 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_match_fhandle_reply(packet_info *pinfo, proto_tree *tree)
+{
+       nlm_msg_res_matched_data *md;
+
+       md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num);
+       if(md && md->rep_frame){
+               nfs_fhandle_data_t *fhd;
+               fhd=(nfs_fhandle_data_t *)g_hash_table_lookup(
+                       nfs_fhandle_frame_table, 
+                       (gconstpointer)md->req_frame);
+               if(fhd){
+                       dissect_fhandle_hidden(pinfo,
+                               tree, fhd);
+               }
+       }
+}
+static void
+nlm_match_fhandle_request(packet_info *pinfo, proto_tree *tree)
+{
+       nlm_msg_res_matched_data *md;
+
+       md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num);
+       if(md && md->rep_frame){
+               nfs_fhandle_data_t *fhd;
+               fhd=(nfs_fhandle_data_t *)g_hash_table_lookup(
+                       nfs_fhandle_frame_table, 
+                       (gconstpointer)md->rep_frame);
+               if(fhd){
+                       dissect_fhandle_hidden(pinfo,
+                               tree, fhd);
+               }
+       }
+}
+
+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.
         * So we use for the state the postfix _S.
@@ -113,7 +347,7 @@ const value_string names_nlm_state[] =
 };
 
 
-const value_string names_fsh_mode[] =
+static const value_string names_fsh_mode[] =
 {
 #define FSM_DN 0
                {       FSM_DN,         "deny none"     },
@@ -128,7 +362,7 @@ const value_string names_fsh_mode[] =
 };
 
 
-const value_string names_fsh_access[] =
+static const value_string names_fsh_access[] =
 {
 #define FSA_NONE       0
                {       FSA_NONE,       "no access"     },
@@ -157,26 +391,26 @@ dissect_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int version, i
 
        if (tree) {
                lock_item = proto_tree_add_item(tree, hf_nlm_lock, tvb,
-                               offset, tvb_length_remaining(tvb, offset), FALSE);
+                               offset, -1, FALSE);
                if (lock_item)
                        lock_tree = proto_item_add_subtree(lock_item, ett_nlm_lock);
        }
 
-       offset = dissect_rpc_string(tvb,pinfo,lock_tree,
+       offset = dissect_rpc_string(tvb,lock_tree,
                        hf_nlm_lock_caller_name, offset, NULL);
        offset = dissect_nfs_fh3(tvb, offset, pinfo, lock_tree,"fh");
 
-       offset = dissect_rpc_data(tvb, pinfo, lock_tree, hf_nlm_lock_owner, offset);
+       offset = dissect_rpc_data(tvb, lock_tree, hf_nlm_lock_owner, offset);
 
-       offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_lock_svid, offset);
+       offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_svid, offset);
 
        if (version == 4) {
-               offset = dissect_rpc_uint64(tvb, pinfo, lock_tree, hf_nlm_lock_l_offset, offset);
-               offset = dissect_rpc_uint64(tvb, pinfo, lock_tree, hf_nlm_lock_l_len, offset);
+               offset = dissect_rpc_uint64(tvb, lock_tree, hf_nlm_lock_l_offset64, offset);
+               offset = dissect_rpc_uint64(tvb, lock_tree, hf_nlm_lock_l_len64, offset);
        }
        else {
-               offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_lock_l_offset, offset);
-               offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_lock_l_len, offset);
+               offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_l_offset, offset);
+               offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_l_len, offset);
        }
 
        return offset;
@@ -187,8 +421,24 @@ static int
 dissect_nlm_test(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree, int version)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
-       dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_exclusive, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_request(pinfo, tree);
+                       }
+               }
+       }
+       
+       offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
+       dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset);
        offset += 4;
        offset = dissect_lock(tvb, pinfo, tree, version, offset);
        return offset;
@@ -198,12 +448,28 @@ static int
 dissect_nlm_lock(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree,int version)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_block, offset);
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_exclusive, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_request(pinfo, tree);
+                       }
+               }
+       }
+       
+       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);
        offset = dissect_lock(tvb, pinfo, tree, version, offset);
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_reclaim, offset);
-       offset = dissect_rpc_uint32(tvb, pinfo, tree, hf_nlm_state, offset);
+       offset = dissect_rpc_bool(tvb, tree, hf_nlm_reclaim, offset);
+       offset = dissect_rpc_uint32(tvb, tree, hf_nlm_state, offset);
        return offset;
 }
 
@@ -211,9 +477,25 @@ static int
 dissect_nlm_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree,int version)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_block, offset);
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_exclusive, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_request(pinfo, tree);
+                       }
+               }
+       }
+
+       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);
        offset = dissect_lock(tvb, pinfo, tree, version, offset);
        return offset;
 }
@@ -222,7 +504,23 @@ static int
 dissect_nlm_unlock(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree,int version)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_request(pinfo, tree);
+                       }
+               }
+       }
+       
+       offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
        offset = dissect_lock(tvb, pinfo, tree, version, offset);
        return offset;
 }
@@ -231,67 +529,95 @@ static int
 dissect_nlm_granted(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree,int version)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_exclusive, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_request(pinfo, tree);
+                       }
+               }
+       }
+
+       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);
        return offset;
 }
 
 
 static int
-dissect_nlm_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_nlm_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
     proto_tree *tree,int version)
 {
        proto_item* lock_item = NULL;
        proto_tree* lock_tree = NULL;
 
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_reply(pinfo, tree);
+                       }
+               }
+       }
+
+       offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
 
        if (tree) {
                lock_item = proto_tree_add_item(tree, hf_nlm_test_stat, tvb,
-                               offset, 
-                               tvb_length_remaining(tvb, offset),
-                               FALSE);
+                               offset, -1, FALSE);
                if (lock_item)
                        lock_tree = proto_item_add_subtree(lock_item, 
                                ett_nlm_lock);
        }
 
-       offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_test_stat_stat,
+       offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_test_stat_stat,
            offset);
 
        /* last structure is optional, only supplied for stat==1 (LOCKED) */
-       if(!tvb_length_remaining(tvb, offset)){
+       if(tvb_reported_length_remaining(tvb, offset) == 0){
                return offset;
        }
 
        if (tree) {
                lock_item = proto_tree_add_item(lock_tree, hf_nlm_holder, tvb,
-                               offset, 
-                               tvb_length_remaining(tvb, offset), 
-                               FALSE);
+                               offset, -1, FALSE);
                if (lock_item)
                        lock_tree = proto_item_add_subtree(lock_item, 
                                ett_nlm_lock);
        }
 
-       offset = dissect_rpc_bool(tvb, pinfo, lock_tree, hf_nlm_exclusive,
+       offset = dissect_rpc_bool(tvb, lock_tree, hf_nlm_exclusive,
            offset);
-       offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_lock_svid,
+       offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_svid,
            offset);
-       offset = dissect_rpc_data(tvb, pinfo, lock_tree, hf_nlm_lock_owner,
+       offset = dissect_rpc_data(tvb, lock_tree, hf_nlm_lock_owner,
            offset);
 
        if (version == 4) {
-               offset = dissect_rpc_uint64(tvb, pinfo, lock_tree,
-                   hf_nlm_lock_l_offset, offset);
-               offset = dissect_rpc_uint64(tvb, pinfo, lock_tree,
-                   hf_nlm_lock_l_len, offset);
+               offset = dissect_rpc_uint64(tvb, lock_tree,
+                   hf_nlm_lock_l_offset64, offset);
+               offset = dissect_rpc_uint64(tvb, lock_tree,
+                   hf_nlm_lock_l_len64, offset);
        }
        else {
-               offset = dissect_rpc_uint32(tvb, pinfo, lock_tree,
+               offset = dissect_rpc_uint32(tvb, lock_tree,
                    hf_nlm_lock_l_offset, offset);
-               offset = dissect_rpc_uint32(tvb, pinfo, lock_tree,
+               offset = dissect_rpc_uint32(tvb, lock_tree,
                    hf_nlm_lock_l_len, offset);
        }
 
@@ -301,56 +627,54 @@ dissect_nlm_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
 static int
 dissect_nlm_share(tvbuff_t *tvb, int offset, packet_info *pinfo,
-    proto_tree *tree,int version)
+    proto_tree *tree,int version _U_)
 {
        proto_item* lock_item = NULL;
        proto_tree* lock_tree = NULL;
 
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
+       offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
 
        if (tree) {
                lock_item = proto_tree_add_item(tree, hf_nlm_share, tvb,
-                               offset, 
-                               tvb_length_remaining(tvb, offset), 
-                               FALSE);
+                               offset, -1, FALSE);
                if (lock_item)
                        lock_tree = proto_item_add_subtree(lock_item, 
                                ett_nlm_lock);
        }
 
-       offset = dissect_rpc_string(tvb,pinfo,lock_tree,
+       offset = dissect_rpc_string(tvb,lock_tree,
                        hf_nlm_lock_caller_name, offset, NULL);
        
        offset = dissect_nfs_fh3(tvb, offset, pinfo, lock_tree, "fh");
 
-       offset = dissect_rpc_data(tvb, pinfo, lock_tree, hf_nlm_lock_owner, offset);
+       offset = dissect_rpc_data(tvb, lock_tree, hf_nlm_lock_owner, offset);
 
-       offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_share_mode, offset);
-       offset = dissect_rpc_uint32(tvb, pinfo, lock_tree, hf_nlm_share_access, offset);
+       offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_share_mode, offset);
+       offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_share_access, offset);
 
 
-       offset = dissect_rpc_bool(tvb, pinfo, tree, hf_nlm_reclaim, offset);
+       offset = dissect_rpc_bool(tvb, tree, hf_nlm_reclaim, offset);
        return offset;
 }
 
 static int
-dissect_nlm_shareres(tvbuff_t *tvb, int offset, packet_info *pinfo,
-    proto_tree *tree, int version)
+dissect_nlm_shareres(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, int version _U_)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
-       offset = dissect_rpc_uint32(tvb, pinfo, tree, hf_nlm_state, offset);
-       offset = dissect_rpc_uint32(tvb, pinfo, tree, hf_nlm_sequence, offset);
+       offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
+       offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset);
+       offset = dissect_rpc_uint32(tvb, tree, hf_nlm_sequence, offset);
        return offset;
 }
 
 static int
-dissect_nlm_freeall(tvbuff_t *tvb, int offset, packet_info *pinfo,
-    proto_tree *tree,int version)
+dissect_nlm_freeall(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree,int version _U_)
 {
-       offset = dissect_rpc_string(tvb,pinfo,tree,
+       offset = dissect_rpc_string(tvb,tree,
                        hf_nlm_share_name, offset, NULL);
 
-       offset = dissect_rpc_uint32(tvb, pinfo, tree, hf_nlm_state, offset);
+       offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset);
 
        return offset;
 }
@@ -361,11 +685,30 @@ dissect_nlm_freeall(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
 /* This function is identical for all NLM protocol versions (1-4)*/
 static int
-dissect_nlm_gen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_nlm_gen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
     proto_tree *tree)
 {
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_nlm_cookie, offset);
-       offset = dissect_rpc_uint32(tvb, pinfo, tree, hf_nlm_state, offset);
+       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);
+                       }
+                       /* for the fhandle matching that finds both request and 
+                          response packet */
+                       if(nfs_fhandle_reqrep_matching){
+                               nlm_match_fhandle_reply(pinfo, tree);
+                       }
+               }
+       }
+
+       offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
+       offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset);
        return offset;
 }
 
@@ -707,9 +1050,15 @@ proto_register_nlm(void)
                { &hf_nlm_lock_svid, {
                        "svid", "nlm.lock.svid", FT_UINT32, BASE_DEC,
                        NULL, 0, "svid", HFILL }},
+               { &hf_nlm_lock_l_offset64, {
+                       "l_offset", "nlm.lock.l_offset", FT_UINT64, BASE_DEC,
+                       NULL, 0, "l_offset", HFILL }},
                { &hf_nlm_lock_l_offset, {
                        "l_offset", "nlm.lock.l_offset", FT_UINT32, BASE_DEC,
                        NULL, 0, "l_offset", HFILL }},
+               { &hf_nlm_lock_l_len64, {
+                       "l_len", "nlm.lock.l_len", FT_UINT64, BASE_DEC,
+                       NULL, 0, "l_len", HFILL }},
                { &hf_nlm_lock_l_len, {
                        "l_len", "nlm.lock.l_len", FT_UINT32, BASE_DEC,
                        NULL, 0, "l_len", HFILL }},
@@ -718,13 +1067,16 @@ proto_register_nlm(void)
                        &yesno, 0, "reclaim", HFILL }},
                { &hf_nlm_state, {
                        "state", "nlm.state", FT_UINT32, BASE_DEC,
-                       VALS(names_nlm_state), 0, "state", HFILL }},
+                       NULL, 0, "STATD state", HFILL }},
+               { &hf_nlm_stat, {
+                       "stat", "nlm.stat", FT_UINT32, BASE_DEC,
+                       VALS(names_nlm_stats), 0, "stat", HFILL }},
                { &hf_nlm_test_stat, {
                        "test_stat", "nlm.test_stat", FT_NONE, 0,
                        NULL, 0, "test_stat", HFILL }},
                { &hf_nlm_test_stat_stat, {
                        "stat", "nlm.test_stat.stat", FT_UINT32, BASE_DEC,
-                       VALS(names_nlm_state), 0, "stat", HFILL }},
+                       VALS(names_nlm_stats), 0, "stat", HFILL }},
                { &hf_nlm_holder, {
                        "holder", "nlm.holder", FT_NONE, 0,
                        NULL, 0, "holder", HFILL }},
@@ -743,17 +1095,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