Update Laurent Meyer's e-mail address.
[obnox/wireshark/wip.git] / packet-nlm.c
1 /* packet-nlm.c
2  * Routines for nlm dissection
3  *
4  * $Id: packet-nlm.c,v 1.34 2003/01/28 23:56:39 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * Copied from packet-mount.c
11  *
12  * 2001-JAN  Ronnie Sahlberg <See AUTHORS for email>
13  *  Updates to version 1 of the protocol.
14  *  Added version 3 of the protocol.
15  *  Added version 4 of the protocol.
16  *
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  */
32
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38
39
40 #include "packet-rpc.h"
41 #include "packet-nfs.h"
42 #include "packet-nlm.h"
43 #include "prefs.h"
44 #include <string.h>
45
46 /*
47  * NFS Lock Manager protocol specs can only be found in actual
48  * implementations or in the nice book:
49  * Brent Callaghan: "NFS Illustrated", Addison-Wesley, ISBN 0-201-32570-5
50  * which I use here as reference (BC).
51  *
52  * They can also be found if you go to
53  *
54  *      http://www.opengroup.org/publications/catalog/c702.htm
55  *
56  * and follow the links to the HTML version of the document.
57  */
58
59 static int proto_nlm = -1;
60 static int hf_nlm_procedure_v1 = -1;
61 static int hf_nlm_procedure_v2 = -1;
62 static int hf_nlm_procedure_v3 = -1;
63 static int hf_nlm_procedure_v4 = -1;
64 static int hf_nlm_cookie = -1;
65 static int hf_nlm_block = -1;
66 static int hf_nlm_exclusive = -1;
67 static int hf_nlm_lock = -1;
68 static int hf_nlm_lock_caller_name = -1;
69 static int hf_nlm_lock_owner = -1;
70 static int hf_nlm_lock_svid = -1;
71 static int hf_nlm_lock_l_offset = -1;
72 static int hf_nlm_lock_l_offset64 = -1;
73 static int hf_nlm_lock_l_len = -1;
74 static int hf_nlm_lock_l_len64 = -1;
75 static int hf_nlm_reclaim = -1;
76 static int hf_nlm_stat = -1;
77 static int hf_nlm_state = -1;
78 static int hf_nlm_test_stat = -1;
79 static int hf_nlm_test_stat_stat = -1;
80 static int hf_nlm_holder = -1;
81 static int hf_nlm_share = -1;
82 static int hf_nlm_share_mode = -1;
83 static int hf_nlm_share_access = -1;
84 static int hf_nlm_share_name = -1;
85 static int hf_nlm_sequence = -1;
86 static int hf_nlm_request_in = -1;
87 static int hf_nlm_reply_in = -1;
88 static int hf_nlm_time = -1;
89
90 static gint ett_nlm = -1;
91 static gint ett_nlm_lock = -1;
92
93
94
95 /*
96  * stuff to match MSG and RES packets for async NLM
97  */
98
99 static gboolean nlm_match_msgres = FALSE;
100 static GHashTable *nlm_msg_res_unmatched = NULL;
101 static GHashTable *nlm_msg_res_matched = NULL;
102
103 /* XXX  when matching the packets we should really check the conversation (only address
104         NOT ports) and command type as well. I am lazy and thinks the cookie itself is
105         good enough for now
106 */
107 typedef struct _nlm_msg_res_unmatched_data {
108         int req_frame;
109         nstime_t ns;
110         int cookie_len;
111         const char *cookie;
112 } nlm_msg_res_unmatched_data;
113
114 typedef struct _nlm_msg_res_matched_data {
115         int req_frame;
116         int rep_frame;
117         nstime_t ns;
118 } nlm_msg_res_matched_data;
119
120 static gboolean
121 nlm_msg_res_unmatched_free_all(gpointer key_arg _U_, gpointer value, gpointer user_data _U_)
122 {
123         nlm_msg_res_unmatched_data *umd = (nlm_msg_res_unmatched_data *)value;
124
125         g_free((gpointer)umd->cookie);
126         g_free(umd);
127
128         return TRUE;
129 }
130 static gboolean
131 nlm_msg_res_matched_free_all(gpointer key_arg _U_, gpointer value, gpointer user_data _U_)
132 {
133         nlm_msg_res_matched_data *md = (nlm_msg_res_matched_data *)value;
134
135         g_free(md);
136
137         return TRUE;
138 }
139
140 static guint
141 nlm_msg_res_unmatched_hash(gconstpointer k)
142 {
143         const nlm_msg_res_unmatched_data *umd = (const nlm_msg_res_unmatched_data *)k;
144         guint8 hash=0;
145         int i;
146
147         for(i=0;i<umd->cookie_len;i++){
148                 hash^=umd->cookie[i];
149         }
150
151         return hash;
152 }
153 static guint
154 nlm_msg_res_matched_hash(gconstpointer k)
155 {
156         guint hash = (guint)k;
157
158         return hash;
159 }
160
161 static gint
162 nlm_msg_res_unmatched_equal(gconstpointer k1, gconstpointer k2)
163 {
164         const nlm_msg_res_unmatched_data *umd1 = (const nlm_msg_res_unmatched_data *)k1;
165         const nlm_msg_res_unmatched_data *umd2 = (const nlm_msg_res_unmatched_data *)k2;
166
167         if(umd1->cookie_len!=umd2->cookie_len){
168                 return 0;
169         }
170
171         return( !memcmp(umd1->cookie, umd2->cookie, umd1->cookie_len));
172 }
173 static gint
174 nlm_msg_res_matched_equal(gconstpointer k1, gconstpointer k2)
175 {
176         guint mk1 = (guint)k1;
177         guint mk2 = (guint)k2;
178
179         return( mk1==mk2 );
180 }
181
182 static void
183 nlm_msg_res_match_init(void)
184 {
185         if(nlm_msg_res_unmatched != NULL){
186                 g_hash_table_foreach_remove(nlm_msg_res_unmatched,
187                                 nlm_msg_res_unmatched_free_all, NULL);
188         } else {
189                 nlm_msg_res_unmatched=g_hash_table_new(nlm_msg_res_unmatched_hash,
190                         nlm_msg_res_unmatched_equal);
191         }
192
193         if(nlm_msg_res_matched != NULL){
194                 g_hash_table_foreach_remove(nlm_msg_res_matched,
195                                 nlm_msg_res_matched_free_all, NULL);
196         } else {
197                 nlm_msg_res_matched=g_hash_table_new(nlm_msg_res_matched_hash,
198                         nlm_msg_res_matched_equal);
199         }
200 }
201
202 static void
203 nlm_print_msgres_reply(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
204 {
205         nlm_msg_res_matched_data *md;
206
207         md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num);
208         if(md){
209                 nstime_t ns;
210                 proto_tree_add_uint(tree, hf_nlm_request_in, tvb, 0, 0, md->req_frame);
211                 ns.secs= pinfo->fd->abs_secs-md->ns.secs;
212                 ns.nsecs=pinfo->fd->abs_usecs*1000-md->ns.nsecs;
213                 if(ns.nsecs<0){
214                         ns.nsecs+=1000000000;
215                         ns.secs--;
216                 }
217                 proto_tree_add_time(tree, hf_nlm_time, tvb, 0, 0, &ns);
218
219         }
220 }
221
222 static void
223 nlm_print_msgres_request(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
224 {
225         nlm_msg_res_matched_data *md;
226
227         md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num);
228         if(md){
229                 proto_tree_add_uint(tree, hf_nlm_reply_in, tvb, 0, 0, md->rep_frame);
230         }
231 }
232 static void
233 nlm_match_fhandle_reply(packet_info *pinfo, proto_tree *tree)
234 {
235         nlm_msg_res_matched_data *md;
236
237         md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num);
238         if(md && md->rep_frame){
239                 nfs_fhandle_data_t *fhd;
240                 fhd=(nfs_fhandle_data_t *)g_hash_table_lookup(
241                         nfs_fhandle_frame_table,
242                         (gconstpointer)md->req_frame);
243                 if(fhd){
244                         dissect_fhandle_hidden(pinfo,
245                                 tree, fhd);
246                 }
247         }
248 }
249 static void
250 nlm_match_fhandle_request(packet_info *pinfo, proto_tree *tree)
251 {
252         nlm_msg_res_matched_data *md;
253
254         md=g_hash_table_lookup(nlm_msg_res_matched, (gconstpointer)pinfo->fd->num);
255         if(md && md->rep_frame){
256                 nfs_fhandle_data_t *fhd;
257                 fhd=(nfs_fhandle_data_t *)g_hash_table_lookup(
258                         nfs_fhandle_frame_table,
259                         (gconstpointer)md->rep_frame);
260                 if(fhd){
261                         dissect_fhandle_hidden(pinfo,
262                                 tree, fhd);
263                 }
264         }
265 }
266
267 static void
268 nlm_register_unmatched_res(packet_info *pinfo, tvbuff_t *tvb, int offset)
269 {
270         nlm_msg_res_unmatched_data umd;
271         nlm_msg_res_unmatched_data *old_umd;
272
273         umd.cookie_len=tvb_get_ntohl(tvb, offset);
274         umd.cookie=(const char *)tvb_get_ptr(tvb, offset+4, -1);
275
276         /* have we seen this cookie before? */
277         old_umd=g_hash_table_lookup(nlm_msg_res_unmatched, (gconstpointer)&umd);
278         if(old_umd){
279                 nlm_msg_res_matched_data *md;
280
281                 md=g_malloc(sizeof(nlm_msg_res_matched_data));
282                 md->req_frame=old_umd->req_frame;
283                 md->rep_frame=pinfo->fd->num;
284                 md->ns=old_umd->ns;
285                 g_hash_table_insert(nlm_msg_res_matched, (gpointer)md->req_frame, (gpointer)md);
286                 g_hash_table_insert(nlm_msg_res_matched, (gpointer)md->rep_frame, (gpointer)md);
287
288                 g_hash_table_remove(nlm_msg_res_unmatched, (gconstpointer)old_umd);
289                 g_free((gpointer)old_umd->cookie);
290                 g_free(old_umd);
291         }
292 }
293
294 static void
295 nlm_register_unmatched_msg(packet_info *pinfo, tvbuff_t *tvb, int offset)
296 {
297         nlm_msg_res_unmatched_data *umd;
298         nlm_msg_res_unmatched_data *old_umd;
299         char *cookie;
300
301         /* allocate and build the unmatched structure for this request */
302         umd=g_malloc(sizeof(nlm_msg_res_unmatched_data));
303         umd->req_frame=pinfo->fd->num;
304         umd->ns.secs=pinfo->fd->abs_secs;
305         umd->ns.nsecs=pinfo->fd->abs_usecs*1000;
306         umd->cookie_len=tvb_get_ntohl(tvb, offset);
307         cookie=g_malloc(umd->cookie_len);
308         tvb_memcpy(tvb, (guint8 *)cookie, offset+4, umd->cookie_len);
309         umd->cookie=cookie;
310
311         /* remove any old duplicates */
312         old_umd=g_hash_table_lookup(nlm_msg_res_unmatched, (gconstpointer)umd);
313         if(old_umd){
314                 g_hash_table_remove(nlm_msg_res_unmatched, (gconstpointer)old_umd);
315                 g_free((gpointer)old_umd->cookie);
316                 g_free(old_umd);
317         }
318
319         /* add new one */
320         g_hash_table_insert(nlm_msg_res_unmatched, (gpointer)umd, (gpointer)umd);
321 }
322
323
324
325
326 static const value_string names_nlm_stats[] =
327 {
328         /* NLM_GRANTED is the function number 5 and the state code 0.
329          * So we use for the state the postfix _S.
330          */
331 #define NLM_GRANTED_S           0
332                 {       NLM_GRANTED_S,  "NLM_GRANTED"   },
333 #define NLM_DENIED              1
334                 {       NLM_DENIED,     "NLM_DENIED"    },
335 #define NLM_DENIED_NOLOCKS      2
336                 {       NLM_DENIED_NOLOCKS,     "NLM_DENIED_NOLOCKS"    },
337 #define NLM_BLOCKED             3
338                 {       NLM_BLOCKED,    "NLM_BLOCKED"           },
339 #define NLM_DENIED_GRACE_PERIOD 4
340                 {       NLM_DENIED_GRACE_PERIOD,        "NLM_DENIED_GRACE_PERIOD"       },
341 #define NLM_DEADLCK             5
342                 {       NLM_DEADLCK,    "NLM_DEADLCK"   },
343 #define NLM_ROFS                6
344                 {       NLM_ROFS,       "NLM_ROFS"      },
345 #define NLM_STALE_FH            7
346                 {       NLM_STALE_FH,   "NLM_STALE_FH"  },
347 #define NLM_BIG                 8
348                 {       NLM_BIG,        "NLM_BIG"       },
349 #define NLM_FAILED              9
350                 {       NLM_FAILED,     "NLM_FAILED"    },
351                 {       0,              NULL            }
352 };
353
354
355 static const value_string names_fsh_mode[] =
356 {
357 #define FSM_DN  0
358                 {       FSM_DN,         "deny none"     },
359 #define FSM_DR  1
360                 {       FSM_DR,         "deny read"     },
361 #define FSM_DW  2
362                 {       FSM_DW,         "deny write"    },
363 #define FSM_DRW 3
364                 {       FSM_DRW,        "deny read/write"       },
365
366                 {       0,              NULL    }
367 };
368
369
370 static const value_string names_fsh_access[] =
371 {
372 #define FSA_NONE        0
373                 {       FSA_NONE,       "no access"     },
374 #define FSA_R   1
375                 {       FSA_R,          "read-only"     },
376 #define FSA_W   2
377                 {       FSA_W,          "write-only"    },
378 #define FSA_RW  3
379                 {       FSA_RW,         "read/write"    },
380                 {       0,              NULL    }
381 };
382
383
384
385
386
387
388 /* **************************** */
389 /* generic dissecting functions */
390 /* **************************** */
391 static int
392 dissect_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int version, int offset)
393 {
394         proto_item* lock_item = NULL;
395         proto_tree* lock_tree = NULL;
396
397         if (tree) {
398                 lock_item = proto_tree_add_item(tree, hf_nlm_lock, tvb,
399                                 offset, -1, FALSE);
400                 if (lock_item)
401                         lock_tree = proto_item_add_subtree(lock_item, ett_nlm_lock);
402         }
403
404         offset = dissect_rpc_string(tvb,lock_tree,
405                         hf_nlm_lock_caller_name, offset, NULL);
406         offset = dissect_nfs_fh3(tvb, offset, pinfo, lock_tree,"fh");
407
408         offset = dissect_rpc_data(tvb, lock_tree, hf_nlm_lock_owner, offset);
409
410         offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_svid, offset);
411
412         if (version == 4) {
413                 offset = dissect_rpc_uint64(tvb, lock_tree, hf_nlm_lock_l_offset64, offset);
414                 offset = dissect_rpc_uint64(tvb, lock_tree, hf_nlm_lock_l_len64, offset);
415         }
416         else {
417                 offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_l_offset, offset);
418                 offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_l_len, offset);
419         }
420
421         return offset;
422 }
423
424
425 static int
426 dissect_nlm_test(tvbuff_t *tvb, int offset, packet_info *pinfo,
427     proto_tree *tree, int version)
428 {
429         if(nlm_match_msgres){
430                 rpc_call_info_value *rpc_call=pinfo->private_data;
431                 if(rpc_call->proc==6){  /* NLM_TEST_MSG */
432                         if( (!pinfo->fd->flags.visited) ){
433                                 nlm_register_unmatched_msg(pinfo, tvb, offset);
434                         } else {
435                                 nlm_print_msgres_request(pinfo, tree, tvb);
436                         }
437                         /* for the fhandle matching that finds both request and
438                            response packet */
439                         if(nfs_fhandle_reqrep_matching){
440                                 nlm_match_fhandle_request(pinfo, tree);
441                         }
442                 }
443         }
444
445         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
446         dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset);
447         offset += 4;
448         offset = dissect_lock(tvb, pinfo, tree, version, offset);
449         return offset;
450 }
451
452 static int
453 dissect_nlm_lock(tvbuff_t *tvb, int offset, packet_info *pinfo,
454     proto_tree *tree,int version)
455 {
456         if(nlm_match_msgres){
457                 rpc_call_info_value *rpc_call=pinfo->private_data;
458                 if(rpc_call->proc==7){  /* NLM_LOCK_MSG */
459                         if( (!pinfo->fd->flags.visited) ){
460                                 nlm_register_unmatched_msg(pinfo, tvb, offset);
461                         } else {
462                                 nlm_print_msgres_request(pinfo, tree, tvb);
463                         }
464                         /* for the fhandle matching that finds both request and
465                            response packet */
466                         if(nfs_fhandle_reqrep_matching){
467                                 nlm_match_fhandle_request(pinfo, tree);
468                         }
469                 }
470         }
471
472         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
473         offset = dissect_rpc_bool(tvb, tree, hf_nlm_block, offset);
474         offset = dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset);
475         offset = dissect_lock(tvb, pinfo, tree, version, offset);
476         offset = dissect_rpc_bool(tvb, tree, hf_nlm_reclaim, offset);
477         offset = dissect_rpc_uint32(tvb, tree, hf_nlm_state, offset);
478         return offset;
479 }
480
481 static int
482 dissect_nlm_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
483     proto_tree *tree,int version)
484 {
485         if(nlm_match_msgres){
486                 rpc_call_info_value *rpc_call=pinfo->private_data;
487                 if(rpc_call->proc==8){  /* NLM_CANCEL_MSG */
488                         if( (!pinfo->fd->flags.visited) ){
489                                 nlm_register_unmatched_msg(pinfo, tvb, offset);
490                         } else {
491                                 nlm_print_msgres_request(pinfo, tree, tvb);
492                         }
493                         /* for the fhandle matching that finds both request and
494                            response packet */
495                         if(nfs_fhandle_reqrep_matching){
496                                 nlm_match_fhandle_request(pinfo, tree);
497                         }
498                 }
499         }
500
501         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
502         offset = dissect_rpc_bool(tvb, tree, hf_nlm_block, offset);
503         offset = dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset);
504         offset = dissect_lock(tvb, pinfo, tree, version, offset);
505         return offset;
506 }
507
508 static int
509 dissect_nlm_unlock(tvbuff_t *tvb, int offset, packet_info *pinfo,
510     proto_tree *tree,int version)
511 {
512         if(nlm_match_msgres){
513                 rpc_call_info_value *rpc_call=pinfo->private_data;
514                 if(rpc_call->proc==9){  /* NLM_UNLOCK_MSG */
515                         if( (!pinfo->fd->flags.visited) ){
516                                 nlm_register_unmatched_msg(pinfo, tvb, offset);
517                         } else {
518                                 nlm_print_msgres_request(pinfo, tree, tvb);
519                         }
520                         /* for the fhandle matching that finds both request and
521                            response packet */
522                         if(nfs_fhandle_reqrep_matching){
523                                 nlm_match_fhandle_request(pinfo, tree);
524                         }
525                 }
526         }
527
528         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
529         offset = dissect_lock(tvb, pinfo, tree, version, offset);
530         return offset;
531 }
532
533 static int
534 dissect_nlm_granted(tvbuff_t *tvb, int offset, packet_info *pinfo,
535     proto_tree *tree,int version)
536 {
537         if(nlm_match_msgres){
538                 rpc_call_info_value *rpc_call=pinfo->private_data;
539                 if(rpc_call->proc==10){ /* NLM_GRANTED_MSG */
540                         if( (!pinfo->fd->flags.visited) ){
541                                 nlm_register_unmatched_msg(pinfo, tvb, offset);
542                         } else {
543                                 nlm_print_msgres_request(pinfo, tree, tvb);
544                         }
545                         /* for the fhandle matching that finds both request and
546                            response packet */
547                         if(nfs_fhandle_reqrep_matching){
548                                 nlm_match_fhandle_request(pinfo, tree);
549                         }
550                 }
551         }
552
553         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
554         offset = dissect_rpc_bool(tvb, tree, hf_nlm_exclusive, offset);
555         offset = dissect_lock(tvb, pinfo, tree, version, offset);
556         return offset;
557 }
558
559
560 static int
561 dissect_nlm_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
562     proto_tree *tree,int version)
563 {
564         proto_item* lock_item = NULL;
565         proto_tree* lock_tree = NULL;
566
567         if(nlm_match_msgres){
568                 rpc_call_info_value *rpc_call=pinfo->private_data;
569                 if(rpc_call->proc==11){ /* NLM_TEST_RES */
570                         if( (!pinfo->fd->flags.visited) ){
571                                 nlm_register_unmatched_res(pinfo, tvb, offset);
572                         } else {
573                                 nlm_print_msgres_reply(pinfo, tree, tvb);
574                         }
575                         /* for the fhandle matching that finds both request and
576                            response packet */
577                         if(nfs_fhandle_reqrep_matching){
578                                 nlm_match_fhandle_reply(pinfo, tree);
579                         }
580                 }
581         }
582
583         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
584
585         if (tree) {
586                 lock_item = proto_tree_add_item(tree, hf_nlm_test_stat, tvb,
587                                 offset, -1, FALSE);
588                 if (lock_item)
589                         lock_tree = proto_item_add_subtree(lock_item,
590                                 ett_nlm_lock);
591         }
592
593         offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_test_stat_stat,
594             offset);
595
596         /* last structure is optional, only supplied for stat==1 (LOCKED) */
597         if(tvb_reported_length_remaining(tvb, offset) == 0){
598                 return offset;
599         }
600
601         if (tree) {
602                 lock_item = proto_tree_add_item(lock_tree, hf_nlm_holder, tvb,
603                                 offset, -1, FALSE);
604                 if (lock_item)
605                         lock_tree = proto_item_add_subtree(lock_item,
606                                 ett_nlm_lock);
607         }
608
609         offset = dissect_rpc_bool(tvb, lock_tree, hf_nlm_exclusive,
610             offset);
611         offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_lock_svid,
612             offset);
613         offset = dissect_rpc_data(tvb, lock_tree, hf_nlm_lock_owner,
614             offset);
615
616         if (version == 4) {
617                 offset = dissect_rpc_uint64(tvb, lock_tree,
618                     hf_nlm_lock_l_offset64, offset);
619                 offset = dissect_rpc_uint64(tvb, lock_tree,
620                     hf_nlm_lock_l_len64, offset);
621         }
622         else {
623                 offset = dissect_rpc_uint32(tvb, lock_tree,
624                     hf_nlm_lock_l_offset, offset);
625                 offset = dissect_rpc_uint32(tvb, lock_tree,
626                     hf_nlm_lock_l_len, offset);
627         }
628
629         return offset;
630 }
631
632
633 static int
634 dissect_nlm_share(tvbuff_t *tvb, int offset, packet_info *pinfo,
635     proto_tree *tree,int version _U_)
636 {
637         proto_item* lock_item = NULL;
638         proto_tree* lock_tree = NULL;
639
640         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
641
642         if (tree) {
643                 lock_item = proto_tree_add_item(tree, hf_nlm_share, tvb,
644                                 offset, -1, FALSE);
645                 if (lock_item)
646                         lock_tree = proto_item_add_subtree(lock_item,
647                                 ett_nlm_lock);
648         }
649
650         offset = dissect_rpc_string(tvb,lock_tree,
651                         hf_nlm_lock_caller_name, offset, NULL);
652
653         offset = dissect_nfs_fh3(tvb, offset, pinfo, lock_tree, "fh");
654
655         offset = dissect_rpc_data(tvb, lock_tree, hf_nlm_lock_owner, offset);
656
657         offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_share_mode, offset);
658         offset = dissect_rpc_uint32(tvb, lock_tree, hf_nlm_share_access, offset);
659
660
661         offset = dissect_rpc_bool(tvb, tree, hf_nlm_reclaim, offset);
662         return offset;
663 }
664
665 static int
666 dissect_nlm_shareres(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
667     proto_tree *tree, int version _U_)
668 {
669         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
670         offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset);
671         offset = dissect_rpc_uint32(tvb, tree, hf_nlm_sequence, offset);
672         return offset;
673 }
674
675 static int
676 dissect_nlm_freeall(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
677     proto_tree *tree,int version _U_)
678 {
679         offset = dissect_rpc_string(tvb,tree,
680                         hf_nlm_share_name, offset, NULL);
681
682         offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset);
683
684         return offset;
685 }
686
687
688 /* RPC functions */
689
690
691 /* This function is identical for all NLM protocol versions (1-4)*/
692 static int
693 dissect_nlm_gen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
694     proto_tree *tree)
695 {
696         if(nlm_match_msgres){
697                 rpc_call_info_value *rpc_call=pinfo->private_data;
698                 if((rpc_call->proc==12)  /* NLM_LOCK_RES */
699                 || (rpc_call->proc==13)  /* NLM_CANCEL_RES */
700                 || (rpc_call->proc==14)  /* NLM_UNLOCK_RES */
701                 || (rpc_call->proc==15) ){      /* NLM_GRENTED_RES */
702                         if( (!pinfo->fd->flags.visited) ){
703                                 nlm_register_unmatched_res(pinfo, tvb, offset);
704                         } else {
705                                 nlm_print_msgres_reply(pinfo, tree, tvb);
706                         }
707                         /* for the fhandle matching that finds both request and
708                            response packet */
709                         if(nfs_fhandle_reqrep_matching){
710                                 nlm_match_fhandle_reply(pinfo, tree);
711                         }
712                 }
713         }
714
715         offset = dissect_rpc_data(tvb, tree, hf_nlm_cookie, offset);
716         offset = dissect_rpc_uint32(tvb, tree, hf_nlm_stat, offset);
717         return offset;
718 }
719
720 static int
721 dissect_nlm1_test(tvbuff_t *tvb, int offset, packet_info *pinfo,
722     proto_tree *tree)
723 {
724         return dissect_nlm_test(tvb,offset,pinfo,tree,1);
725 }
726
727 static int
728 dissect_nlm4_test(tvbuff_t *tvb, int offset, packet_info *pinfo,
729     proto_tree *tree)
730 {
731         return dissect_nlm_test(tvb,offset,pinfo,tree,4);
732 }
733
734
735 static int
736 dissect_nlm1_lock(tvbuff_t *tvb, int offset, packet_info *pinfo,
737     proto_tree *tree)
738 {
739         return dissect_nlm_lock(tvb,offset,pinfo,tree,1);
740 }
741
742 static int
743 dissect_nlm4_lock(tvbuff_t *tvb, int offset, packet_info *pinfo,
744     proto_tree *tree)
745 {
746         return dissect_nlm_lock(tvb,offset,pinfo,tree,4);
747 }
748
749
750 static int
751 dissect_nlm1_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
752     proto_tree *tree)
753 {
754         return dissect_nlm_cancel(tvb,offset,pinfo,tree,1);
755 }
756
757 static int
758 dissect_nlm4_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
759     proto_tree *tree)
760 {
761         return dissect_nlm_cancel(tvb,offset,pinfo,tree,4);
762 }
763
764
765 static int
766 dissect_nlm1_unlock(tvbuff_t *tvb, int offset, packet_info *pinfo,
767     proto_tree *tree)
768 {
769         return dissect_nlm_unlock(tvb,offset,pinfo,tree,1);
770 }
771
772 static int
773 dissect_nlm4_unlock(tvbuff_t *tvb, int offset, packet_info *pinfo,
774     proto_tree *tree)
775 {
776         return dissect_nlm_unlock(tvb,offset,pinfo,tree,4);
777 }
778
779
780 static int
781 dissect_nlm1_granted(tvbuff_t *tvb, int offset, packet_info *pinfo,
782     proto_tree *tree)
783 {
784         return dissect_nlm_granted(tvb,offset,pinfo,tree,1);
785 }
786
787 static int
788 dissect_nlm4_granted(tvbuff_t *tvb, int offset, packet_info *pinfo,
789     proto_tree *tree)
790 {
791         return dissect_nlm_granted(tvb,offset,pinfo,tree,4);
792 }
793
794
795 static int
796 dissect_nlm1_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo,
797     proto_tree *tree)
798 {
799         return dissect_nlm_test_res(tvb,offset,pinfo,tree,1);
800 }
801
802 static int
803 dissect_nlm4_test_res(tvbuff_t *tvb, int offset, packet_info *pinfo,
804     proto_tree *tree)
805 {
806         return dissect_nlm_test_res(tvb,offset,pinfo,tree,4);
807 }
808
809 static int
810 dissect_nlm3_share(tvbuff_t *tvb, int offset, packet_info *pinfo,
811     proto_tree *tree)
812 {
813         return dissect_nlm_share(tvb,offset,pinfo,tree,3);
814 }
815
816 static int
817 dissect_nlm4_share(tvbuff_t *tvb, int offset, packet_info *pinfo,
818     proto_tree *tree)
819 {
820         return dissect_nlm_share(tvb,offset,pinfo,tree,4);
821 }
822
823 static int
824 dissect_nlm3_shareres(tvbuff_t *tvb, int offset, packet_info *pinfo,
825     proto_tree *tree)
826 {
827         return dissect_nlm_shareres(tvb,offset,pinfo,tree,3);
828 }
829
830 static int
831 dissect_nlm4_shareres(tvbuff_t *tvb, int offset, packet_info *pinfo,
832     proto_tree *tree)
833 {
834         return dissect_nlm_shareres(tvb,offset,pinfo,tree,4);
835 }
836
837 static int
838 dissect_nlm3_freeall(tvbuff_t *tvb, int offset, packet_info *pinfo,
839     proto_tree *tree)
840 {
841         return dissect_nlm_freeall(tvb,offset,pinfo,tree,3);
842 }
843
844 static int
845 dissect_nlm4_freeall(tvbuff_t *tvb, int offset, packet_info *pinfo,
846     proto_tree *tree)
847 {
848         return dissect_nlm_freeall(tvb,offset,pinfo,tree,4);
849 }
850
851
852
853
854 /* proc number, "proc name", dissect_request, dissect_reply */
855 /* NULL as function pointer means: type of arguments is "void". */
856 /* NLM protocol version 1 */
857 static const vsff nlm1_proc[] = {
858         { NLM_NULL,             "NULL",
859                 NULL,                           NULL },
860         { NLM_TEST,             "TEST",
861                 dissect_nlm1_test,              dissect_nlm1_test_res },
862         { NLM_LOCK,             "LOCK",
863                 dissect_nlm1_lock,              dissect_nlm_gen_reply },
864         { NLM_CANCEL,           "CANCEL",
865                 dissect_nlm1_cancel,            dissect_nlm_gen_reply },
866         { NLM_UNLOCK,           "UNLOCK",
867                 dissect_nlm1_unlock,            dissect_nlm_gen_reply },
868         { NLM_GRANTED,          "GRANTED",
869                 dissect_nlm1_granted,           dissect_nlm_gen_reply },
870         { NLM_TEST_MSG,         "TEST_MSG",
871                 dissect_nlm1_test,              NULL },
872         { NLM_LOCK_MSG,         "LOCK_MSG",
873                 dissect_nlm1_lock,              NULL },
874         { NLM_CANCEL_MSG,       "CANCEL_MSG",
875                 dissect_nlm1_cancel,            NULL },
876         { NLM_UNLOCK_MSG,       "UNLOCK_MSG",
877                 dissect_nlm1_unlock,            NULL },
878         { NLM_GRANTED_MSG,      "GRANTED_MSG",
879                 dissect_nlm1_granted,           NULL },
880         { NLM_TEST_RES,         "TEST_RES",
881                 dissect_nlm1_test_res,          NULL },
882         { NLM_LOCK_RES,         "LOCK_RES",
883                 dissect_nlm_gen_reply,          NULL },
884         { NLM_CANCEL_RES,       "CANCEL_RES",
885                 dissect_nlm_gen_reply,          NULL },
886         { NLM_UNLOCK_RES,       "UNLOCK_RES",
887                 dissect_nlm_gen_reply,          NULL },
888         { NLM_GRANTED_RES,      "GRANTED_RES",
889                 dissect_nlm_gen_reply,          NULL },
890         { 0,                    NULL,
891                 NULL,                           NULL }
892 };
893 static const value_string nlm1_proc_vals[] = {
894         { NLM_NULL,             "NULL" },
895         { NLM_TEST,             "TEST" },
896         { NLM_LOCK,             "LOCK" },
897         { NLM_CANCEL,           "CANCEL" },
898         { NLM_UNLOCK,           "UNLOCK" },
899         { NLM_GRANTED,          "GRANTED" },
900         { NLM_TEST_MSG,         "TEST_MSG" },
901         { NLM_LOCK_MSG,         "LOCK_MSG" },
902         { NLM_CANCEL_MSG,       "CANCEL_MSG" },
903         { NLM_UNLOCK_MSG,       "UNLOCK_MSG" },
904         { NLM_GRANTED_MSG,      "GRANTED_MSG" },
905         { NLM_TEST_RES,         "TEST_RES" },
906         { NLM_LOCK_RES,         "LOCK_RES" },
907         { NLM_CANCEL_RES,       "CANCEL_RES" },
908         { NLM_UNLOCK_RES,       "UNLOCK_RES" },
909         { NLM_GRANTED_RES,      "GRANTED_RES" },
910         { 0,                    NULL }
911 };
912 /* end of NLM protocol version 1 */
913
914 /* NLM protocol version 2 */
915 static const vsff nlm2_proc[] = {
916         { NLM_NULL,             "NULL",
917                 NULL,                           NULL },
918         { NLM_TEST,             "TEST",
919                 dissect_nlm1_test,              dissect_nlm1_test_res },
920         { NLM_LOCK,             "LOCK",
921                 dissect_nlm1_lock,              dissect_nlm_gen_reply },
922         { NLM_CANCEL,           "CANCEL",
923                 dissect_nlm1_cancel,            dissect_nlm_gen_reply },
924         { NLM_UNLOCK,           "UNLOCK",
925                 dissect_nlm1_unlock,            dissect_nlm_gen_reply },
926         { NLM_GRANTED,          "GRANTED",
927                 dissect_nlm1_granted,           dissect_nlm_gen_reply },
928         { NLM_TEST_MSG,         "TEST_MSG",
929                 dissect_nlm1_test,              NULL },
930         { NLM_LOCK_MSG,         "LOCK_MSG",
931                 dissect_nlm1_lock,              NULL },
932         { NLM_CANCEL_MSG,       "CANCEL_MSG",
933                 dissect_nlm1_cancel,            NULL },
934         { NLM_UNLOCK_MSG,       "UNLOCK_MSG",
935                 dissect_nlm1_unlock,            NULL },
936         { NLM_GRANTED_MSG,      "GRANTED_MSG",
937                 dissect_nlm1_granted,           NULL },
938         { NLM_TEST_RES,         "TEST_RES",
939                 dissect_nlm1_test_res,          NULL },
940         { NLM_LOCK_RES,         "LOCK_RES",
941                 dissect_nlm_gen_reply,          NULL },
942         { NLM_CANCEL_RES,       "CANCEL_RES",
943                 dissect_nlm_gen_reply,          NULL },
944         { NLM_UNLOCK_RES,       "UNLOCK_RES",
945                 dissect_nlm_gen_reply,          NULL },
946         { NLM_GRANTED_RES,      "GRANTED_RES",
947                 dissect_nlm_gen_reply,          NULL },
948         { 0,                    NULL,
949                 NULL,                           NULL }
950 };
951 static const value_string nlm2_proc_vals[] = {
952         { NLM_NULL,             "NULL" },
953         { NLM_TEST,             "TEST" },
954         { NLM_LOCK,             "LOCK" },
955         { NLM_CANCEL,           "CANCEL" },
956         { NLM_UNLOCK,           "UNLOCK" },
957         { NLM_GRANTED,          "GRANTED" },
958         { NLM_TEST_MSG,         "TEST_MSG" },
959         { NLM_LOCK_MSG,         "LOCK_MSG" },
960         { NLM_CANCEL_MSG,       "CANCEL_MSG" },
961         { NLM_UNLOCK_MSG,       "UNLOCK_MSG" },
962         { NLM_GRANTED_MSG,      "GRANTED_MSG" },
963         { NLM_TEST_RES,         "TEST_RES" },
964         { NLM_LOCK_RES,         "LOCK_RES" },
965         { NLM_CANCEL_RES,       "CANCEL_RES" },
966         { NLM_UNLOCK_RES,       "UNLOCK_RES" },
967         { NLM_GRANTED_RES,      "GRANTED_RES" },
968         { 0,                    NULL }
969 };
970 /* end of NLM protocol version 2 */
971
972 /* NLM protocol version 3 */
973 static const vsff nlm3_proc[] = {
974         { NLM_NULL,             "NULL",
975                 NULL,                           NULL },
976         { NLM_TEST,             "TEST",
977                 dissect_nlm1_test,              dissect_nlm1_test_res },
978         { NLM_LOCK,             "LOCK",
979                 dissect_nlm1_lock,              dissect_nlm_gen_reply },
980         { NLM_CANCEL,           "CANCEL",
981                 dissect_nlm1_cancel,            dissect_nlm_gen_reply },
982         { NLM_UNLOCK,           "UNLOCK",
983                 dissect_nlm1_unlock,            dissect_nlm_gen_reply },
984         { NLM_GRANTED,          "GRANTED",
985                 dissect_nlm1_granted,           dissect_nlm_gen_reply },
986         { NLM_TEST_MSG,         "TEST_MSG",
987                 dissect_nlm1_test,              NULL },
988         { NLM_LOCK_MSG,         "LOCK_MSG",
989                 dissect_nlm1_lock,              NULL },
990         { NLM_CANCEL_MSG,       "CANCEL_MSG",
991                 dissect_nlm1_cancel,            NULL },
992         { NLM_UNLOCK_MSG,       "UNLOCK_MSG",
993                 dissect_nlm1_unlock,            NULL },
994         { NLM_GRANTED_MSG,      "GRANTED_MSG",
995                 dissect_nlm1_granted,           NULL },
996         { NLM_TEST_RES,         "TEST_RES",
997                 dissect_nlm1_test_res,          NULL },
998         { NLM_LOCK_RES,         "LOCK_RES",
999                 dissect_nlm_gen_reply,          NULL },
1000         { NLM_CANCEL_RES,       "CANCEL_RES",
1001                 dissect_nlm_gen_reply,          NULL },
1002         { NLM_UNLOCK_RES,       "UNLOCK_RES",
1003                 dissect_nlm_gen_reply,          NULL },
1004         { NLM_GRANTED_RES,      "GRANTED_RES",
1005                 dissect_nlm_gen_reply,          NULL },
1006         { NLM_SHARE,            "SHARE",
1007                 dissect_nlm3_share,             dissect_nlm3_shareres },
1008         { NLM_UNSHARE,          "UNSHARE",
1009                 dissect_nlm3_share,             dissect_nlm3_shareres },
1010         { NLM_NM_LOCK,          "NM_LOCK",
1011                 dissect_nlm1_lock,              dissect_nlm_gen_reply },
1012         { NLM_FREE_ALL,         "FREE_ALL",
1013                 dissect_nlm3_freeall,           NULL },
1014         { 0,                    NULL,
1015                 NULL,                           NULL }
1016 };
1017 static const value_string nlm3_proc_vals[] = {
1018         { NLM_NULL,             "NULL" },
1019         { NLM_TEST,             "TEST" },
1020         { NLM_LOCK,             "LOCK" },
1021         { NLM_CANCEL,           "CANCEL" },
1022         { NLM_UNLOCK,           "UNLOCK" },
1023         { NLM_GRANTED,          "GRANTED" },
1024         { NLM_TEST_MSG,         "TEST_MSG" },
1025         { NLM_LOCK_MSG,         "LOCK_MSG" },
1026         { NLM_CANCEL_MSG,       "CANCEL_MSG" },
1027         { NLM_UNLOCK_MSG,       "UNLOCK_MSG" },
1028         { NLM_GRANTED_MSG,      "GRANTED_MSG" },
1029         { NLM_TEST_RES,         "TEST_RES" },
1030         { NLM_LOCK_RES,         "LOCK_RES" },
1031         { NLM_CANCEL_RES,       "CANCEL_RES" },
1032         { NLM_UNLOCK_RES,       "UNLOCK_RES" },
1033         { NLM_GRANTED_RES,      "GRANTED_RES" },
1034         { NLM_SHARE,            "SHARE" },
1035         { NLM_UNSHARE,          "UNSHARE" },
1036         { NLM_NM_LOCK,          "NM_LOCK" },
1037         { NLM_FREE_ALL,         "FREE_ALL" },
1038         { 0,                    NULL }
1039 };
1040 /* end of NLM protocol version 3 */
1041
1042
1043 /* NLM protocol version 4 */
1044 static const vsff nlm4_proc[] = {
1045         { NLM_NULL,             "NULL",
1046                 NULL,                           NULL },
1047         { NLM_TEST,             "TEST",
1048                 dissect_nlm4_test,              dissect_nlm4_test_res },
1049         { NLM_LOCK,             "LOCK",
1050                 dissect_nlm4_lock,              dissect_nlm_gen_reply },
1051         { NLM_CANCEL,           "CANCEL",
1052                 dissect_nlm4_cancel,            dissect_nlm_gen_reply },
1053         { NLM_UNLOCK,           "UNLOCK",
1054                 dissect_nlm4_unlock,            dissect_nlm_gen_reply },
1055         { NLM_GRANTED,          "GRANTED",
1056                 dissect_nlm4_granted,           dissect_nlm_gen_reply },
1057         { NLM_TEST_MSG,         "TEST_MSG",
1058                 dissect_nlm4_test,              NULL },
1059         { NLM_LOCK_MSG,         "LOCK_MSG",
1060                 dissect_nlm4_lock,              NULL },
1061         { NLM_CANCEL_MSG,       "CANCEL_MSG",
1062                 dissect_nlm4_cancel,            NULL },
1063         { NLM_UNLOCK_MSG,       "UNLOCK_MSG",
1064                 dissect_nlm4_unlock,            NULL },
1065         { NLM_GRANTED_MSG,      "GRANTED_MSG",
1066                 dissect_nlm4_granted,           NULL },
1067         { NLM_TEST_RES,         "TEST_RES",
1068                 dissect_nlm4_test_res,          NULL },
1069         { NLM_LOCK_RES,         "LOCK_RES",
1070                 dissect_nlm_gen_reply,          NULL },
1071         { NLM_CANCEL_RES,       "CANCEL_RES",
1072                 dissect_nlm_gen_reply,          NULL },
1073         { NLM_UNLOCK_RES,       "UNLOCK_RES",
1074                 dissect_nlm_gen_reply,          NULL },
1075         { NLM_GRANTED_RES,      "GRANTED_RES",
1076                 dissect_nlm_gen_reply,          NULL },
1077         { NLM_SHARE,            "SHARE",
1078                 dissect_nlm4_share,             dissect_nlm4_shareres },
1079         { NLM_UNSHARE,          "UNSHARE",
1080                 dissect_nlm4_share,             dissect_nlm4_shareres },
1081         { NLM_NM_LOCK,          "NM_LOCK",
1082                 dissect_nlm4_lock,              dissect_nlm_gen_reply },
1083         { NLM_FREE_ALL,         "FREE_ALL",
1084                 dissect_nlm4_freeall,           NULL },
1085         { 0,                    NULL,
1086                 NULL,                           NULL }
1087 };
1088 static const value_string nlm4_proc_vals[] = {
1089         { NLM_NULL,             "NULL" },
1090         { NLM_TEST,             "TEST" },
1091         { NLM_LOCK,             "LOCK" },
1092         { NLM_CANCEL,           "CANCEL" },
1093         { NLM_UNLOCK,           "UNLOCK" },
1094         { NLM_GRANTED,          "GRANTED" },
1095         { NLM_TEST_MSG,         "TEST_MSG" },
1096         { NLM_LOCK_MSG,         "LOCK_MSG" },
1097         { NLM_CANCEL_MSG,       "CANCEL_MSG" },
1098         { NLM_UNLOCK_MSG,       "UNLOCK_MSG" },
1099         { NLM_GRANTED_MSG,      "GRANTED_MSG" },
1100         { NLM_TEST_RES,         "TEST_RES" },
1101         { NLM_LOCK_RES,         "LOCK_RES" },
1102         { NLM_CANCEL_RES,       "CANCEL_RES" },
1103         { NLM_UNLOCK_RES,       "UNLOCK_RES" },
1104         { NLM_GRANTED_RES,      "GRANTED_RES" },
1105         { NLM_SHARE,            "SHARE" },
1106         { NLM_UNSHARE,          "UNSHARE" },
1107         { NLM_NM_LOCK,          "NM_LOCK" },
1108         { NLM_FREE_ALL,         "FREE_ALL" },
1109         { 0,                    NULL }
1110 };
1111 /* end of NLM protocol version 4 */
1112
1113
1114 static struct true_false_string yesno = { "Yes", "No" };
1115
1116
1117 void
1118 proto_register_nlm(void)
1119 {
1120         static hf_register_info hf[] = {
1121                 { &hf_nlm_procedure_v1, {
1122                         "V1 Procedure", "nlm.procedure_v1", FT_UINT32, BASE_DEC,
1123                         VALS(nlm1_proc_vals), 0, "V1 Procedure", HFILL }},
1124                 { &hf_nlm_procedure_v2, {
1125                         "V2 Procedure", "nlm.procedure_v2", FT_UINT32, BASE_DEC,
1126                         VALS(nlm2_proc_vals), 0, "V2 Procedure", HFILL }},
1127                 { &hf_nlm_procedure_v3, {
1128                         "V3 Procedure", "nlm.procedure_v3", FT_UINT32, BASE_DEC,
1129                         VALS(nlm3_proc_vals), 0, "V3 Procedure", HFILL }},
1130                 { &hf_nlm_procedure_v4, {
1131                         "V4 Procedure", "nlm.procedure_v4", FT_UINT32, BASE_DEC,
1132                         VALS(nlm4_proc_vals), 0, "V4 Procedure", HFILL }},
1133                 { &hf_nlm_cookie, {
1134                         "cookie", "nlm.cookie", FT_BYTES, BASE_DEC,
1135                         NULL, 0, "cookie", HFILL }},
1136                 { &hf_nlm_block, {
1137                         "block", "nlm.block", FT_BOOLEAN, BASE_NONE,
1138                         &yesno, 0, "block", HFILL }},
1139                 { &hf_nlm_exclusive, {
1140                         "exclusive", "nlm.exclusive", FT_BOOLEAN, BASE_NONE,
1141                         &yesno, 0, "exclusive", HFILL }},
1142                 { &hf_nlm_lock, {
1143                         "lock", "nlm.lock", FT_NONE, 0,
1144                         NULL, 0, "lock", HFILL }},
1145                 { &hf_nlm_lock_caller_name, {
1146                         "caller_name", "nlm.lock.caller_name", FT_STRING, BASE_NONE,
1147                         NULL, 0, "caller_name", HFILL }},
1148                 { &hf_nlm_lock_owner, {
1149                         "owner", "nlm.lock.owner", FT_BYTES, BASE_DEC,
1150                         NULL, 0, "owner", HFILL }},
1151                 { &hf_nlm_lock_svid, {
1152                         "svid", "nlm.lock.svid", FT_UINT32, BASE_DEC,
1153                         NULL, 0, "svid", HFILL }},
1154                 { &hf_nlm_lock_l_offset64, {
1155                         "l_offset", "nlm.lock.l_offset", FT_UINT64, BASE_DEC,
1156                         NULL, 0, "l_offset", HFILL }},
1157                 { &hf_nlm_lock_l_offset, {
1158                         "l_offset", "nlm.lock.l_offset", FT_UINT32, BASE_DEC,
1159                         NULL, 0, "l_offset", HFILL }},
1160                 { &hf_nlm_lock_l_len64, {
1161                         "l_len", "nlm.lock.l_len", FT_UINT64, BASE_DEC,
1162                         NULL, 0, "l_len", HFILL }},
1163                 { &hf_nlm_lock_l_len, {
1164                         "l_len", "nlm.lock.l_len", FT_UINT32, BASE_DEC,
1165                         NULL, 0, "l_len", HFILL }},
1166                 { &hf_nlm_reclaim, {
1167                         "reclaim", "nlm.reclaim", FT_BOOLEAN, BASE_NONE,
1168                         &yesno, 0, "reclaim", HFILL }},
1169                 { &hf_nlm_state, {
1170                         "state", "nlm.state", FT_UINT32, BASE_DEC,
1171                         NULL, 0, "STATD state", HFILL }},
1172                 { &hf_nlm_stat, {
1173                         "stat", "nlm.stat", FT_UINT32, BASE_DEC,
1174                         VALS(names_nlm_stats), 0, "stat", HFILL }},
1175                 { &hf_nlm_test_stat, {
1176                         "test_stat", "nlm.test_stat", FT_NONE, 0,
1177                         NULL, 0, "test_stat", HFILL }},
1178                 { &hf_nlm_test_stat_stat, {
1179                         "stat", "nlm.test_stat.stat", FT_UINT32, BASE_DEC,
1180                         VALS(names_nlm_stats), 0, "stat", HFILL }},
1181                 { &hf_nlm_holder, {
1182                         "holder", "nlm.holder", FT_NONE, 0,
1183                         NULL, 0, "holder", HFILL }},
1184                 { &hf_nlm_share, {
1185                         "share", "nlm.share", FT_NONE, 0,
1186                         NULL, 0, "share", HFILL }},
1187                 { &hf_nlm_share_mode, {
1188                         "mode", "nlm.share.mode", FT_UINT32, BASE_DEC,
1189                         VALS(names_fsh_mode), 0, "mode", HFILL }},
1190                 { &hf_nlm_share_access, {
1191                         "access", "nlm.share.access", FT_UINT32, BASE_DEC,
1192                         VALS(names_fsh_access), 0, "access", HFILL }},
1193                 { &hf_nlm_share_name, {
1194                         "name", "nlm.share.name", FT_STRING, BASE_NONE,
1195                         NULL, 0, "name", HFILL }},
1196                 { &hf_nlm_sequence, {
1197                         "sequence", "nlm.sequence", FT_INT32, BASE_DEC,
1198                         NULL, 0, "sequence", HFILL }},
1199                 { &hf_nlm_request_in, {
1200                         "Request MSG in", "nlm.msg_in", FT_UINT32, BASE_DEC,
1201                         NULL, 0, "The RES packet is a response to the MSG in this packet", HFILL }},
1202                 { &hf_nlm_reply_in, {
1203                         "Reply RES in", "nlm.res_in", FT_UINT32, BASE_DEC,
1204                         NULL, 0, "The response to this MSG packet is in this packet", HFILL }},
1205                 { &hf_nlm_time, {
1206                         "Time from request", "nlm.time", FT_RELATIVE_TIME, BASE_NONE,
1207                         NULL, 0, "Time between Request and Reply for async NLM calls", HFILL }},
1208
1209                 };
1210
1211         static gint *ett[] = {
1212                 &ett_nlm,
1213                 &ett_nlm_lock,
1214         };
1215         module_t *nlm_module;
1216
1217         proto_nlm = proto_register_protocol("Network Lock Manager Protocol",
1218             "NLM", "nlm");
1219         proto_register_field_array(proto_nlm, hf, array_length(hf));
1220         proto_register_subtree_array(ett, array_length(ett));
1221
1222         nlm_module = prefs_register_protocol(proto_nlm, NULL);
1223         prefs_register_bool_preference(nlm_module, "msg_res_matching",
1224                 "Match MSG/RES packets for async NLM",
1225                 "Whether the dissector will track and match MSG and RES calls for asynchronous NLM",
1226                 &nlm_match_msgres);
1227         register_init_routine(nlm_msg_res_match_init);
1228 }
1229
1230 void
1231 proto_reg_handoff_nlm(void)
1232 {
1233         /* Register the protocol as RPC */
1234         rpc_init_prog(proto_nlm, NLM_PROGRAM, ett_nlm);
1235         /* Register the procedure tables */
1236         rpc_init_proc_table(NLM_PROGRAM, 1, nlm1_proc, hf_nlm_procedure_v1);
1237         rpc_init_proc_table(NLM_PROGRAM, 2, nlm2_proc, hf_nlm_procedure_v2);
1238         rpc_init_proc_table(NLM_PROGRAM, 3, nlm3_proc, hf_nlm_procedure_v3);
1239         rpc_init_proc_table(NLM_PROGRAM, 4, nlm4_proc, hf_nlm_procedure_v4);
1240 }