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