7a6c93fa02cc4f9abc5560d29d0fae0a817f1bb0
[obnox/wireshark/wip.git] / packet-nfs.c
1 /* packet-nfs.c
2  * Routines for nfs dissection
3  * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
4  *
5  * $Id: packet-nfs.c,v 1.37 2000/08/27 02:03:31 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-smb.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36
37
38 #include "packet-rpc.h"
39 #include "packet-nfs.h"
40
41
42 static int proto_nfs = -1;
43
44 static int hf_nfs_fh_fsid_major = -1;
45 static int hf_nfs_fh_fsid_minor = -1;
46 static int hf_nfs_fh_xfsid_major = -1;
47 static int hf_nfs_fh_xfsid_minor = -1;
48 static int hf_nfs_fh_fstype = -1;
49 static int hf_nfs_fh_fn = -1;
50 static int hf_nfs_fh_fn_len = -1;
51 static int hf_nfs_fh_fn_inode = -1;
52 static int hf_nfs_fh_fn_generation = -1;
53 static int hf_nfs_fh_xfn = -1;
54 static int hf_nfs_fh_xfn_len = -1;
55 static int hf_nfs_fh_xfn_inode = -1;
56 static int hf_nfs_fh_xfn_generation = -1;
57 static int hf_nfs_fh_dentry = -1;
58 static int hf_nfs_fh_dev = -1;
59 static int hf_nfs_fh_xdev = -1;
60 static int hf_nfs_fh_dirinode = -1;
61 static int hf_nfs_fh_pinode = -1;
62 static int hf_nfs_fh_hp_len = -1;
63 static int hf_nfs_stat = -1;
64 static int hf_nfs_name = -1;
65 static int hf_nfs_readlink_data = -1;
66 static int hf_nfs_read_offset = -1;
67 static int hf_nfs_read_count = -1;
68 static int hf_nfs_read_totalcount = -1;
69 static int hf_nfs_data = -1;
70 static int hf_nfs_write_beginoffset = -1;
71 static int hf_nfs_write_offset = -1;
72 static int hf_nfs_write_totalcount = -1;
73 static int hf_nfs_symlink_to = -1;
74 static int hf_nfs_readdir_cookie = -1;
75 static int hf_nfs_readdir_count = -1;
76 static int hf_nfs_readdir_entry = -1;
77 static int hf_nfs_readdir_entry_fileid = -1;
78 static int hf_nfs_readdir_entry_name = -1;
79 static int hf_nfs_readdirplus_entry_name = -1;
80 static int hf_nfs_readdir_entry_cookie = -1;
81 static int hf_nfs_readdir_eof = -1;
82 static int hf_nfs_statfs_tsize = -1;
83 static int hf_nfs_statfs_bsize = -1;
84 static int hf_nfs_statfs_blocks = -1;
85 static int hf_nfs_statfs_bfree = -1;
86 static int hf_nfs_statfs_bavail = -1;
87 static int hf_nfs_ftype3 = -1;
88 static int hf_nfs_nfsstat3 = -1;
89 static int hf_nfs_read_eof = -1;
90 static int hf_nfs_write_stable = -1;
91 static int hf_nfs_write_committed = -1;
92 static int hf_nfs_createmode3 = -1;
93 static int hf_nfs_fsstat_invarsec = -1;
94 static int hf_nfs_fsinfo_rtmax = -1;
95 static int hf_nfs_fsinfo_rtpref = -1;
96 static int hf_nfs_fsinfo_rtmult = -1;
97 static int hf_nfs_fsinfo_wtmax = -1;
98 static int hf_nfs_fsinfo_wtpref = -1;
99 static int hf_nfs_fsinfo_wtmult = -1;
100 static int hf_nfs_fsinfo_dtpref = -1;
101 static int hf_nfs_fsinfo_properties = -1;
102 static int hf_nfs_pathconf_linkmax = -1;
103 static int hf_nfs_pathconf_name_max = -1;
104 static int hf_nfs_pathconf_no_trunc = -1;
105 static int hf_nfs_pathconf_chown_restricted = -1;
106 static int hf_nfs_pathconf_case_insensitive = -1;
107 static int hf_nfs_pathconf_case_preserving = -1;
108
109
110 static gint ett_nfs = -1;
111 static gint ett_nfs_fh_fsid = -1;
112 static gint ett_nfs_fh_xfsid = -1;
113 static gint ett_nfs_fh_fn = -1;
114 static gint ett_nfs_fh_xfn = -1;
115 static gint ett_nfs_fh_hp = -1;
116 static gint ett_nfs_fhandle = -1;
117 static gint ett_nfs_timeval = -1;
118 static gint ett_nfs_mode = -1;
119 static gint ett_nfs_fattr = -1;
120 static gint ett_nfs_sattr = -1;
121 static gint ett_nfs_diropargs = -1;
122 static gint ett_nfs_readdir_entry = -1;
123 static gint ett_nfs_mode3 = -1;
124 static gint ett_nfs_specdata3 = -1;
125 static gint ett_nfs_fh3 = -1;
126 static gint ett_nfs_nfstime3 = -1;
127 static gint ett_nfs_fattr3 = -1;
128 static gint ett_nfs_post_op_fh3 = -1;
129 static gint ett_nfs_sattr3 = -1;
130 static gint ett_nfs_diropargs3 = -1;
131 static gint ett_nfs_sattrguard3 = -1;
132 static gint ett_nfs_set_mode3 = -1;
133 static gint ett_nfs_set_uid3 = -1;
134 static gint ett_nfs_set_gid3 = -1;
135 static gint ett_nfs_set_size3 = -1;
136 static gint ett_nfs_set_atime = -1;
137 static gint ett_nfs_set_mtime = -1;
138 static gint ett_nfs_pre_op_attr = -1;
139 static gint ett_nfs_post_op_attr = -1;
140 static gint ett_nfs_wcc_attr = -1;
141 static gint ett_nfs_wcc_data = -1;
142 static gint ett_nfs_access = -1;
143 static gint ett_nfs_fsinfo_properties = -1;
144
145
146 /* file handle dissection */
147
148
149 const value_string names_fhtype[] =
150 {
151 #define FHT_UNKNOWN     0
152         {       FHT_UNKNOWN,    "unknown"       },
153 #define FHT_SVR4        1
154         {       FHT_SVR4,       "System V R4"   },
155 #define FHT_LINUX_KNFSD_LE      2
156         {       FHT_LINUX_KNFSD_LE,     "Linux knfsd (little-endian)"   },
157 #define FHT_LINUX_NFSD_LE       3
158         {       FHT_LINUX_NFSD_LE,      "Linux user-land nfsd (little-endian)"  },
159         {               0,      NULL            }
160 };
161
162
163 /* SVR4: checked with ReliantUNIX (5.43, 5.44, 5.45) */
164
165 void
166 dissect_fhandle_data_SVR4(tvbuff_t* tvb, proto_tree *tree, int fhlen)
167 {
168         guint32 nof = 0;
169
170         /* file system id */
171         {
172         guint32 fsid_O;
173         guint32 fsid_L;
174         guint32 temp;
175         guint32 fsid_major;
176         guint32 fsid_minor;
177
178         fsid_O = nof;
179         fsid_L = 4;
180         temp = tvb_get_ntohl(tvb, fsid_O);
181         fsid_major = ( temp>>18 ) &  0x3fff; /* 14 bits */
182         fsid_minor = ( temp     ) & 0x3ffff; /* 18 bits */
183         if (tree) {
184                 proto_item* fsid_item = NULL;
185                 proto_tree* fsid_tree = NULL;
186         
187                 fsid_item = proto_tree_add_text(tree, tvb,
188                         fsid_O, fsid_L, 
189                         "file system ID: %d,%d", fsid_major, fsid_minor);
190                 if (fsid_item) {
191                         fsid_tree = proto_item_add_subtree(fsid_item, 
192                                         ett_nfs_fh_fsid);
193                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
194                                 tvb, fsid_O,   2, fsid_major);
195                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
196                                 tvb, fsid_O+1, 3, fsid_minor);
197                 }
198         }
199         nof = fsid_O + fsid_L;
200         }
201
202         /* file system type */
203         {
204         guint32 fstype_O;
205         guint32 fstype_L;
206         guint32 fstype;
207
208         fstype_O = nof;
209         fstype_L = 4;
210         fstype = tvb_get_ntohl(tvb, fstype_O);
211         if (tree) {
212                 proto_tree_add_uint(tree, hf_nfs_fh_fstype, tvb,
213                         fstype_O, fstype_L, fstype);
214         }
215         nof = fstype_O + fstype_L;
216         }
217
218         /* file number */
219         {
220         guint32 fn_O;
221         guint32 fn_len_O;
222         guint32 fn_len_L;
223         guint32 fn_len;
224         guint32 fn_data_O;
225         guint32 fn_data_inode_O;
226         guint32 fn_data_inode_L;
227         guint32 inode;
228         guint32 fn_data_gen_O;
229         guint32 fn_data_gen_L;
230         guint32 gen;
231         guint32 fn_L;
232         
233         fn_O = nof;
234         fn_len_O = fn_O;
235         fn_len_L = 2;
236         fn_len = tvb_get_ntohs(tvb, fn_len_O);
237         fn_data_O = fn_O + fn_len_L;
238         fn_data_inode_O = fn_data_O + 2;
239         fn_data_inode_L = 4;
240         inode = tvb_get_ntohl(tvb, fn_data_inode_O);
241         fn_data_gen_O = fn_data_inode_O + fn_data_inode_L;
242         fn_data_gen_L = 4;
243         gen = tvb_get_ntohl(tvb, fn_data_gen_O);
244         fn_L = fn_len_L + fn_len;
245         if (tree) {
246                 proto_item* fn_item = NULL;
247                 proto_tree* fn_tree = NULL;
248         
249                 fn_item = proto_tree_add_uint(tree, hf_nfs_fh_fn, tvb,
250                         fn_O, fn_L, inode);
251                 if (fn_item) {
252                         fn_tree = proto_item_add_subtree(fn_item, 
253                                         ett_nfs_fh_fn);
254                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_len,
255                                 tvb, fn_len_O, fn_len_L, fn_len);
256                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_inode,
257                                 tvb, fn_data_inode_O, fn_data_inode_L, inode);
258                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_generation,
259                                 tvb, fn_data_gen_O, fn_data_gen_L, gen);
260                 }
261         }
262         nof = fn_O + fn_len_L + fn_len;
263         }
264
265         /* exported file number */
266         {
267         guint32 xfn_O;
268         guint32 xfn_len_O;
269         guint32 xfn_len_L;
270         guint32 xfn_len;
271         guint32 xfn_data_O;
272         guint32 xfn_data_inode_O;
273         guint32 xfn_data_inode_L;
274         guint32 xinode;
275         guint32 xfn_data_gen_O;
276         guint32 xfn_data_gen_L;
277         guint32 xgen;
278         guint32 xfn_L;
279         
280         xfn_O = nof;
281         xfn_len_O = xfn_O;
282         xfn_len_L = 2;
283         xfn_len = tvb_get_ntohs(tvb, xfn_len_O);
284         xfn_data_O = xfn_O + xfn_len_L;
285         xfn_data_inode_O = xfn_data_O + 2;
286         xfn_data_inode_L = 4;
287         xinode = tvb_get_ntohl(tvb, xfn_data_inode_O);
288         xfn_data_gen_O = xfn_data_inode_O + xfn_data_inode_L;
289         xfn_data_gen_L = 4;
290         xgen = tvb_get_ntohl(tvb, xfn_data_gen_O);
291         xfn_L = xfn_len_L + xfn_len;
292         if (tree) {
293                 proto_item* xfn_item = NULL;
294                 proto_tree* xfn_tree = NULL;
295         
296                 xfn_item = proto_tree_add_uint(tree, hf_nfs_fh_xfn, tvb,
297                         xfn_O, xfn_L, xinode);
298                 if (xfn_item) {
299                         xfn_tree = proto_item_add_subtree(xfn_item, 
300                                         ett_nfs_fh_xfn);
301                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_len,
302                                 tvb, xfn_len_O, xfn_len_L, xfn_len);
303                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_inode,
304                                 tvb, xfn_data_inode_O, xfn_data_inode_L, xinode);
305                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_generation,
306                                 tvb, xfn_data_gen_O, xfn_data_gen_L, xgen);
307                 }
308         }
309         }
310 }
311
312
313 /* Checked with RedHat Linux 6.2 (kernel 2.2.14 knfsd) */
314
315 void
316 dissect_fhandle_data_LINUX_KNFSD_LE(tvbuff_t* tvb, proto_tree *tree, int fhlen)
317 {
318         guint32 dentry;
319         guint32 inode;
320         guint32 dirinode;
321         guint32 temp;
322         guint32 fsid_major;
323         guint32 fsid_minor;
324         guint32 xfsid_major;
325         guint32 xfsid_minor;
326         guint32 xinode;
327         guint32 gen;
328
329         dentry   = tvb_get_letohl(tvb, 0);
330         inode    = tvb_get_letohl(tvb, 4);
331         dirinode = tvb_get_letohl(tvb, 8);
332         temp     = tvb_get_letohs (tvb,12);
333         fsid_major = (temp >> 8) & 0xff;
334         fsid_minor = (temp     ) & 0xff;
335         temp     = tvb_get_letohs(tvb,16);
336         xfsid_major = (temp >> 8) & 0xff;
337         xfsid_minor = (temp     ) & 0xff;
338         xinode   = tvb_get_letohl(tvb,20);
339         gen      = tvb_get_letohl(tvb,24);
340
341         if (tree) {
342                 proto_tree_add_uint(tree, hf_nfs_fh_dentry,
343                         tvb, 0, 4, dentry);
344                 proto_tree_add_uint(tree, hf_nfs_fh_fn_inode,
345                         tvb, 4, 4, inode);
346                 proto_tree_add_uint(tree, hf_nfs_fh_dirinode,
347                         tvb, 8, 4, dirinode);
348
349                 /* file system id (device) */
350                 {
351                 proto_item* fsid_item = NULL;
352                 proto_tree* fsid_tree = NULL;
353
354                 fsid_item = proto_tree_add_text(tree, tvb,
355                         12, 4, 
356                         "file system ID: %d,%d", fsid_major, fsid_minor);
357                 if (fsid_item) {
358                         fsid_tree = proto_item_add_subtree(fsid_item, 
359                                         ett_nfs_fh_fsid);
360                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
361                                 tvb, 13, 1, fsid_major);
362                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
363                                 tvb, 12, 1, fsid_minor);
364                 }
365                 }
366
367                 /* exported file system id (device) */
368                 {
369                 proto_item* xfsid_item = NULL;
370                 proto_tree* xfsid_tree = NULL;
371
372                 xfsid_item = proto_tree_add_text(tree, tvb,
373                         16, 4, 
374                         "exported file system ID: %d,%d", xfsid_major, xfsid_minor);
375                 if (xfsid_item) {
376                         xfsid_tree = proto_item_add_subtree(xfsid_item, 
377                                         ett_nfs_fh_xfsid);
378                         proto_tree_add_uint(xfsid_tree, hf_nfs_fh_xfsid_major,
379                                 tvb, 17, 1, xfsid_major);
380                         proto_tree_add_uint(xfsid_tree, hf_nfs_fh_xfsid_minor,
381                                 tvb, 16, 1, xfsid_minor);
382                 }
383                 }
384
385                 proto_tree_add_uint(tree, hf_nfs_fh_xfn_inode,
386                         tvb, 20, 4, xinode);
387                 proto_tree_add_uint(tree, hf_nfs_fh_fn_generation,
388                         tvb, 24, 4, gen);
389         }
390 }
391
392
393 /* Checked with RedHat Linux 5.2 (nfs-server 2.2beta47 user-land nfsd) */
394
395 void
396 dissect_fhandle_data_LINUX_NFSD_LE(tvbuff_t* tvb, proto_tree *tree, int fhlen)
397 {
398         /* pseudo inode */
399         {
400         guint32 pinode;
401         pinode   = tvb_get_letohl(tvb, 0);
402         if (tree) {
403                 proto_tree_add_uint(tree, hf_nfs_fh_pinode,
404                         tvb, 0, 4, pinode);
405         }
406         }
407
408         /* hash path */
409         {
410         guint32 hashlen;
411
412         hashlen  = tvb_get_guint8(tvb, 4);
413         if (tree) {
414                 proto_item* hash_item = NULL;
415                 proto_tree* hash_tree = NULL;
416
417                 hash_item = proto_tree_add_text(tree, tvb, 4, hashlen + 1,
418                                 "hash path: %s",
419                                 bytes_to_str(tvb_get_ptr(tvb,5,hashlen),hashlen));
420                 if (hash_item) {
421                         hash_tree = proto_item_add_subtree(hash_item, 
422                                         ett_nfs_fh_hp);
423                         if (hash_tree) {
424                                 proto_tree_add_uint(hash_tree,
425                                         hf_nfs_fh_hp_len, tvb, 4, 1, hashlen);
426                                 proto_tree_add_text(hash_tree, tvb, 5, hashlen,
427                                         "key: %s",
428                                         bytes_to_str(tvb_get_ptr(tvb,5,hashlen),hashlen));
429                         }
430                 }
431         }
432         }
433 }
434
435
436 static void
437 dissect_fhandle_data_unknown(tvbuff_t *tvb, proto_tree *tree, int fhlen)
438 {
439         int offset;
440
441         int sublen;
442         int bytes_left;
443         gboolean first_line;
444
445         offset = 0;
446
447         bytes_left = fhlen;
448         first_line = TRUE;
449         while (bytes_left != 0) {
450                 sublen = 16;
451                 if (sublen > bytes_left)
452                         sublen = bytes_left;
453                 proto_tree_add_text(tree, tvb, offset, sublen,
454                                         "%s%s",
455                                         first_line ? "data: " :
456                                                      "      ",
457                                         bytes_to_str(tvb_get_ptr(tvb,offset,sublen),sublen));
458                 bytes_left -= sublen;
459                 offset += sublen;
460                 first_line = FALSE;
461         }
462 }
463
464
465 static void
466 dissect_fhandle_data(const u_char *pd, int offset, frame_data* fd, proto_tree *tree, int fhlen)
467 {
468         tvbuff_t *tvb = tvb_create_from_top(offset);
469         int fhtype = FHT_UNKNOWN;
470
471         /* filehandle too long */
472         if (fhlen>64) goto type_ready;
473         /* Not all bytes there. Any attempt to deduce the type would be
474            senseless. */
475         if (!tvb_bytes_exist(tvb,0,fhlen)) goto type_ready;
476                 
477         /* calculate (heuristically) fhtype */
478         switch (fhlen) {
479                 case 32: {
480                         guint32 len1;
481                         guint32 len2;
482                         if (tvb_get_ntohs(tvb,4) == 0) {
483                                 len1= tvb_get_ntohs(tvb,8);
484                                 if (tvb_bytes_exist(tvb,10+len1,2)) {
485                                                 len2 = tvb_get_ntohs(tvb,10+len1);
486                                                 if (fhlen==12+len1+len2) {
487                                                         fhtype=FHT_SVR4;
488                                                         goto type_ready;
489                                                 }
490                                 }
491                         }
492                         len1 = tvb_get_guint8(tvb,4);
493                         if (len1<28 && tvb_bytes_exist(tvb,5,len1)) {
494                                 int wrong=0;
495                                 for (len2=5+len1;len2<32;len2++) {
496                                         if (tvb_get_guint8(tvb,len2)) {
497                                                 wrong=1;        
498                                                 break;
499                                         }
500                                 }
501                                 if (!wrong) {
502                                         fhtype=FHT_LINUX_NFSD_LE;
503                                         goto type_ready;
504                                 }
505                         }
506                         if (tvb_get_ntohl(tvb,28) == 0) {
507                                 if (tvb_get_ntohs(tvb,14) == 0) {
508                                         if (tvb_get_ntohs(tvb,18) == 0) {
509                                                 fhtype=FHT_LINUX_KNFSD_LE;
510                                                 goto type_ready;
511                                         }
512                                 }
513                         }
514                 } break;
515         }
516
517 type_ready:
518
519         proto_tree_add_text(tree, tvb, 0, 0, 
520                 "type: %s", val_to_str(fhtype, names_fhtype, "Unknown"));
521
522         switch (fhtype) {
523                 case FHT_SVR4:
524                         dissect_fhandle_data_SVR4          (tvb, tree, fhlen);
525                 break;
526                 case FHT_LINUX_KNFSD_LE:
527                         dissect_fhandle_data_LINUX_KNFSD_LE(tvb, tree, fhlen);
528                 break;
529                 case FHT_LINUX_NFSD_LE:
530                         dissect_fhandle_data_LINUX_NFSD_LE (tvb, tree, fhlen);
531                 break;
532                 case FHT_UNKNOWN:
533                 default:
534                         dissect_fhandle_data_unknown(tvb, tree, fhlen);
535                 break;
536         }
537 }
538
539
540 /***************************/
541 /* NFS Version 2, RFC 1094 */
542 /***************************/
543
544
545 /* base 32 bit type for NFS v2 */
546 int
547 dissect_unsigned_int(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
548 char* name)
549 {
550         offset = dissect_rpc_uint32(pd,offset,fd,tree,name);
551         return offset;
552 }
553
554
555 /* RFC 1094, Page 12..14 */
556 const value_string names_nfs_stat[] =
557 {
558         {       0,      "OK" },
559         {       1,      "ERR_PERM" },
560         {       2,      "ERR_NOENT" },
561         {       5,      "ERR_IO" },
562         {       6,      "ERR_NX_IO" },
563         {       13,     "ERR_ACCES" },
564         {       17,     "ERR_EXIST" },
565         {       18,     "ERR_XDEV" },   /* not in spec, but can happen */
566         {       19,     "ERR_NODEV" },
567         {       20,     "ERR_NOTDIR" },
568         {       21,     "ERR_ISDIR" },
569         {       22,     "ERR_INVAL" },  /* not in spec, but I think it can happen */
570         {       26,     "ERR_TXTBSY" }, /* not in spec, but I think it can happen */
571         {       27,     "ERR_FBIG" },
572         {       28,     "ERR_NOSPC" },
573         {       30,     "ERR_ROFS" },
574         {       31,     "ERR_MLINK" },  /* not in spec, but can happen */
575         {       45,     "ERR_OPNOTSUPP" }, /* not in spec, but I think it can happen */
576         {       63,     "ERR_NAMETOOLONG" },
577         {       66,     "ERR_NOTEMPTY" },
578         {       69,     "ERR_DQUOT" },
579         {       70,     "ERR_STALE" },
580         {       99,     "ERR_WFLUSH" },
581         {       0,      NULL }
582 };
583
584
585 /* RFC 1094, Page 12..14 */
586 int
587 dissect_stat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
588 guint32* status)
589 {
590         guint32 stat;
591
592         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
593         stat = EXTRACT_UINT(pd, offset+0);
594         
595         if (tree) {
596                 /* this gives the right NFSv2 number<->message relation */
597                 /* and makes it searchable via "nfs.status" */
598                 proto_tree_add_uint_format(tree, hf_nfs_nfsstat3, NullTVB,
599                         offset+0, 4, stat, "Status: %s (%u)", 
600                         val_to_str(stat,names_nfs_stat,"%u"), stat);
601         }
602
603         offset += 4;
604         *status = stat;
605         return offset;
606 }
607
608
609 /* RFC 1094, Page 12..14 */
610 int
611 dissect_nfs2_stat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
612 {
613         guint32 status;
614
615         offset = dissect_stat(pd, offset, fd, tree, &status);
616
617         return offset;
618 }
619
620
621 /* RFC 1094, Page 15 */
622 int
623 dissect_ftype(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
624 char* name)
625 {
626         guint32 ftype;
627         char* ftype_name = NULL;
628
629         const value_string nfs2_ftype[] =
630         {
631                 {       0,      "Non-File" },
632                 {       1,      "Regular File" },
633                 {       2,      "Directory" },
634                 {       3,      "Block Special Device" },
635                 {       4,      "Character Special Device" },
636                 {       5,      "Symbolic Link" },
637                 {       0,      NULL }
638         };
639
640         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
641         ftype = EXTRACT_UINT(pd, offset+0);
642         ftype_name = val_to_str(ftype, nfs2_ftype, "%u");
643         
644         if (tree) {
645                 proto_tree_add_text(tree, NullTVB, offset, 4,
646                         "%s: %s (%u)", name, ftype_name, ftype);
647         }
648
649         offset += 4;
650         return offset;
651 }
652
653
654 /* RFC 1094, Page 15 */
655 int
656 dissect_fhandle(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
657 {
658         proto_item* fitem;
659         proto_tree* ftree = NULL;
660
661         if (tree) {
662                 fitem = proto_tree_add_text(tree, NullTVB, offset, FHSIZE,
663                         "%s", name);
664                 if (fitem)
665                         ftree = proto_item_add_subtree(fitem, ett_nfs_fhandle);
666         }
667
668         if (ftree)
669                 dissect_fhandle_data(pd, offset, fd, ftree, FHSIZE);
670
671         offset += FHSIZE;
672         return offset;
673 }
674
675 /* RFC 1094, Page 15 */
676 int
677 dissect_nfs2_fhandle_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
678 {
679         offset = dissect_fhandle(pd, offset, fd, tree, "object");
680
681         return offset;
682 }
683
684
685 /* RFC 1094, Page 15 */
686 int
687 dissect_timeval(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
688 {
689         guint32 seconds;
690         guint32 mseconds;
691
692         proto_item* time_item;
693         proto_tree* time_tree = NULL;
694
695         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
696         seconds = EXTRACT_UINT(pd, offset+0);
697         mseconds = EXTRACT_UINT(pd, offset+4);
698         
699         if (tree) {
700                 time_item = proto_tree_add_text(tree, NullTVB, offset, 8,
701                         "%s: %u.%06u", name, seconds, mseconds);
702                 if (time_item)
703                         time_tree = proto_item_add_subtree(time_item, ett_nfs_timeval);
704         }
705
706         if (time_tree) {
707                 proto_tree_add_text(time_tree, NullTVB,offset+0,4,
708                                         "seconds: %u", seconds);
709                 proto_tree_add_text(time_tree, NullTVB,offset+4,4,
710                                         "micro seconds: %u", mseconds);
711         }
712         offset += 8;
713         return offset;
714 }
715
716
717 /* RFC 1094, Page 16 */
718 const value_string nfs2_mode_names[] = {
719         {       0040000,        "Directory"     },
720         {       0020000,        "Character Special Device"      },
721         {       0060000,        "Block Special Device"  },
722         {       0100000,        "Regular File"  },
723         {       0120000,        "Symbolic Link" },
724         {       0140000,        "Named Socket"  },
725         {       0000000,        NULL            },
726 };
727
728 int
729 dissect_mode(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
730 char* name)
731 {
732         guint32 mode;
733         proto_item* mode_item = NULL;
734         proto_tree* mode_tree = NULL;
735
736         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
737         mode = EXTRACT_UINT(pd, offset+0);
738         
739         if (tree) {
740                 mode_item = proto_tree_add_text(tree, NullTVB, offset, 4,
741                         "%s: 0%o", name, mode);
742                 if (mode_item)
743                         mode_tree = proto_item_add_subtree(mode_item, ett_nfs_mode);
744         }
745
746         if (mode_tree) {
747                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
748                         decode_enumerated_bitfield(mode,  0160000, 16,
749                         nfs2_mode_names, "%s"));
750                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
751                 decode_boolean_bitfield(mode,   04000, 16, "Set user id on exec", "not SUID"));
752                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
753                 decode_boolean_bitfield(mode,   02000, 16, "Set group id on exec", "not SGID"));
754                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
755                 decode_boolean_bitfield(mode,   01000, 16, "Save swapped text even after use", "not save swapped text"));
756                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
757                 decode_boolean_bitfield(mode,    0400, 16, "Read permission for owner", "no Read permission for owner"));
758                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
759                 decode_boolean_bitfield(mode,    0200, 16, "Write permission for owner", "no Write permission for owner"));
760                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
761                 decode_boolean_bitfield(mode,    0100, 16, "Execute permission for owner", "no Execute permission for owner"));
762                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
763                 decode_boolean_bitfield(mode,     040, 16, "Read permission for group", "no Read permission for group"));
764                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
765                 decode_boolean_bitfield(mode,     020, 16, "Write permission for group", "no Write permission for group"));
766                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
767                 decode_boolean_bitfield(mode,     010, 16, "Execute permission for group", "no Execute permission for group"));
768                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
769                 decode_boolean_bitfield(mode,      04, 16, "Read permission for others", "no Read permission for others"));
770                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
771                 decode_boolean_bitfield(mode,      02, 16, "Write permission for others", "no Write permission for others"));
772                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
773                 decode_boolean_bitfield(mode,      01, 16, "Execute permission for others", "no Execute permission for others"));
774         }
775
776         offset += 4;
777         return offset;
778 }
779
780
781 /* RFC 1094, Page 15 */
782 int
783 dissect_fattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
784 {
785         proto_item* fattr_item = NULL;
786         proto_tree* fattr_tree = NULL;
787         int old_offset = offset;
788
789         if (tree) {
790                 fattr_item = proto_tree_add_text(tree, NullTVB, offset,
791                         END_OF_FRAME, "%s", name);
792                 if (fattr_item)
793                         fattr_tree = proto_item_add_subtree(fattr_item, ett_nfs_fattr);
794         }
795
796         offset = dissect_ftype        (pd,offset,fd,fattr_tree,"type");
797         offset = dissect_mode         (pd,offset,fd,fattr_tree,"mode");
798         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"nlink");
799         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"uid");
800         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"gid");
801         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"size");
802         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocksize");
803         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"rdev");
804         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocks");
805         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fsid");
806         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fileid");
807         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"atime");
808         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"mtime");
809         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"ctime");
810
811         /* now we know, that fattr is shorter */
812         if (fattr_item) {
813                 proto_item_set_len(fattr_item, offset - old_offset);
814         }
815
816         return offset;
817 }
818
819
820 /* RFC 1094, Page 17 */
821 int
822 dissect_sattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
823 {
824         proto_item* sattr_item = NULL;
825         proto_tree* sattr_tree = NULL;
826         int old_offset = offset;
827
828         if (tree) {
829                 sattr_item = proto_tree_add_text(tree, NullTVB, offset,
830                         END_OF_FRAME, "%s", name);
831                 if (sattr_item)
832                         sattr_tree = proto_item_add_subtree(sattr_item, ett_nfs_sattr);
833         }
834
835         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
836         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
837                 offset = dissect_mode         (pd,offset,fd,sattr_tree,"mode");
838         else {
839                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "mode: no value");
840                 offset += 4;
841         }
842
843         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
844         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
845                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"uid");
846         else {
847                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "uid: no value");
848                 offset += 4;
849         }
850
851         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
852         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
853                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"gid");
854         else {
855                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "gid: no value");
856                 offset += 4;
857         }
858
859         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
860         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
861                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"size");
862         else {
863                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "size: no value");
864                 offset += 4;
865         }
866
867         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
868         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
869                 offset = dissect_timeval      (pd,offset,fd,sattr_tree,"atime");
870         else {
871                 proto_tree_add_text(sattr_tree, NullTVB, offset, 8, "atime: no value");
872                 offset += 8;
873         }
874
875         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
876         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
877                 offset = dissect_timeval      (pd,offset,fd,sattr_tree,"mtime");
878         else {
879                 proto_tree_add_text(sattr_tree, NullTVB, offset, 8, "mtime: no value");
880                 offset += 8;
881         }
882
883         /* now we know, that sattr is shorter */
884         if (sattr_item) {
885                 proto_item_set_len(sattr_item, offset - old_offset);
886         }
887
888         return offset;
889 }
890
891
892 /* RFC 1094, Page 17 */
893 int
894 dissect_filename(const u_char *pd, int offset, frame_data *fd,
895     proto_tree *tree, int hf, char **string_ret)
896 {
897         offset = dissect_rpc_string(pd,offset,fd,tree,hf,string_ret);
898         return offset;
899 }
900
901
902 /* RFC 1094, Page 17 */
903 int
904 dissect_path(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
905 {
906         offset = dissect_rpc_string(pd,offset,fd,tree,hf,NULL);
907         return offset;
908 }
909
910
911 /* RFC 1094, Page 17,18 */
912 int
913 dissect_attrstat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
914         guint32 status;
915
916         offset = dissect_stat(pd, offset, fd, tree, &status);
917         switch (status) {
918                 case 0:
919                         offset = dissect_fattr(pd, offset, fd, tree, "attributes");
920                 break;
921                 default:
922                         /* do nothing */
923                 break;
924         }
925
926         return offset;
927 }
928
929
930 /* RFC 1094, Page 17,18 */
931 int
932 dissect_nfs2_attrstat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
933 {
934         offset = dissect_attrstat(pd, offset, fd, tree);
935
936         return offset;
937 }
938
939
940 /* RFC 1094, Page 18 */
941 int
942 dissect_diropargs(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
943 {
944         proto_item* diropargs_item = NULL;
945         proto_tree* diropargs_tree = NULL;
946         int old_offset = offset;
947
948         if (tree) {
949                 diropargs_item = proto_tree_add_text(tree, NullTVB, offset,
950                         END_OF_FRAME, "%s", name);
951                 if (diropargs_item)
952                         diropargs_tree = proto_item_add_subtree(diropargs_item, ett_nfs_diropargs);
953         }
954
955         offset = dissect_fhandle (pd,offset,fd,diropargs_tree,"dir");
956         offset = dissect_filename(pd,offset,fd,diropargs_tree,hf_nfs_name,NULL);
957
958         /* now we know, that diropargs is shorter */
959         if (diropargs_item) {
960                 proto_item_set_len(diropargs_item, offset - old_offset);
961         }
962
963         return offset;
964 }
965
966
967 /* RFC 1094, Page 18 */
968 int
969 dissect_nfs2_diropargs_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
970 {
971         offset = dissect_diropargs(pd, offset, fd, tree, "where");
972
973         return offset;
974 }
975
976
977 /* RFC 1094, Page 18 */
978 int
979 dissect_diropres(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
980 {
981         guint32 status;
982
983         offset = dissect_stat(pd, offset, fd, tree, &status);
984         switch (status) {
985                 case 0:
986                         offset = dissect_fhandle(pd, offset, fd, tree, "file");
987                         offset = dissect_fattr  (pd, offset, fd, tree, "attributes");
988                 break;
989                 default:
990                         /* do nothing */
991                 break;
992         }
993
994         return offset;
995 }
996
997
998 /* nfsdata is simply a RPC string (length, data, fill bytes) */
999 int
1000 dissect_nfsdata(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1001 int hf)
1002 {
1003         offset = dissect_rpc_data(pd,offset,fd,tree,hf);
1004
1005         return offset;
1006 }
1007
1008
1009 /* RFC 1094, Page 18 */
1010 int
1011 dissect_nfs2_diropres_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1012 {
1013         offset = dissect_diropres(pd, offset, fd, tree);
1014
1015         return offset;
1016 }
1017
1018
1019 /* RFC 1094, Page 6 */
1020 int
1021 dissect_nfs2_setattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1022 {
1023         offset = dissect_fhandle(pd, offset, fd, tree, "file"      );
1024         offset = dissect_sattr  (pd, offset, fd, tree, "attributes");
1025
1026         return offset;
1027 }
1028
1029
1030 /* RFC 1094, Page 6 */
1031 int
1032 dissect_nfs2_readlink_reply(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1033 {
1034         guint32 status;
1035
1036         offset = dissect_stat(pd, offset, fd, tree, &status);
1037         switch (status) {
1038                 case 0:
1039                         offset = dissect_path(pd, offset, fd, tree, hf_nfs_readlink_data);
1040                 break;
1041                 default:
1042                         /* do nothing */
1043                 break;
1044         }
1045
1046         return offset;
1047 }
1048
1049
1050 /* RFC 1094, Page 7 */
1051 int
1052 dissect_nfs2_read_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1053 {
1054         guint32 offset_value;
1055         guint32 count;
1056         guint32 totalcount;
1057
1058         offset = dissect_fhandle(pd, offset, fd, tree, "file"      );
1059         if (!BYTES_ARE_IN_FRAME(offset,12)) return offset;
1060         offset_value = EXTRACT_UINT(pd, offset+0);
1061         count        = EXTRACT_UINT(pd, offset+4);
1062         totalcount   = EXTRACT_UINT(pd, offset+8);
1063         if (tree) {
1064                 proto_tree_add_uint(tree, hf_nfs_read_offset, NullTVB, 
1065                 offset+0, 4, offset_value);
1066                 proto_tree_add_uint(tree, hf_nfs_read_count, NullTVB, 
1067                 offset+4, 4, count);
1068                 proto_tree_add_uint(tree, hf_nfs_read_totalcount, NullTVB, 
1069                 offset+8, 4, totalcount);
1070         }
1071         offset += 12;
1072
1073         return offset;
1074 }
1075
1076
1077 /* RFC 1094, Page 7 */
1078 int
1079 dissect_nfs2_read_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1080 {
1081         guint32 status;
1082
1083         offset = dissect_stat(pd, offset, fd, tree, &status);
1084         switch (status) {
1085                 case 0:
1086                         offset = dissect_fattr(pd, offset, fd, tree, "attributes");
1087                         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data); 
1088                 break;
1089                 default:
1090                         /* do nothing */
1091                 break;
1092         }
1093
1094         return offset;
1095 }
1096
1097
1098 /* RFC 1094, Page 8 */
1099 int
1100 dissect_nfs2_write_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1101 {
1102         guint32 beginoffset;
1103         guint32 offset_value;
1104         guint32 totalcount;
1105
1106         offset = dissect_fhandle(pd, offset, fd, tree, "file"      );
1107         if (!BYTES_ARE_IN_FRAME(offset,12)) return offset;
1108         beginoffset  = EXTRACT_UINT(pd, offset+0);
1109         offset_value = EXTRACT_UINT(pd, offset+4);
1110         totalcount   = EXTRACT_UINT(pd, offset+8);
1111         if (tree) {
1112                 proto_tree_add_uint(tree, hf_nfs_write_beginoffset, NullTVB, 
1113                 offset+0, 4, beginoffset);
1114                 proto_tree_add_uint(tree, hf_nfs_write_offset, NullTVB, 
1115                 offset+4, 4, offset_value);
1116                 proto_tree_add_uint(tree, hf_nfs_write_totalcount, NullTVB, 
1117                 offset+8, 4, totalcount);
1118         }
1119         offset += 12;
1120
1121         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data); 
1122
1123         return offset;
1124 }
1125
1126
1127 /* RFC 1094, Page 8 */
1128 int
1129 dissect_nfs2_createargs_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1130 {
1131         offset = dissect_diropargs(pd, offset, fd, tree, "where"     );
1132         offset = dissect_sattr    (pd, offset, fd, tree, "attributes");
1133
1134         return offset;
1135 }
1136
1137
1138 /* RFC 1094, Page 9 */
1139 int
1140 dissect_nfs2_rename_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1141 {
1142         offset = dissect_diropargs(pd, offset, fd, tree, "from");
1143         offset = dissect_diropargs(pd, offset, fd, tree, "to"  );
1144
1145         return offset;
1146 }
1147
1148
1149 /* RFC 1094, Page 9 */
1150 int
1151 dissect_nfs2_link_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1152 {
1153         offset = dissect_fhandle  (pd, offset, fd, tree, "from");
1154         offset = dissect_diropargs(pd, offset, fd, tree, "to"  );
1155
1156         return offset;
1157 }
1158
1159
1160 /* RFC 1094, Page 10 */
1161 int
1162 dissect_nfs2_symlink_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1163 {
1164         offset = dissect_diropargs(pd, offset, fd, tree, "from"           );
1165         offset = dissect_path     (pd, offset, fd, tree, hf_nfs_symlink_to);
1166         offset = dissect_sattr    (pd, offset, fd, tree, "attributes"     );
1167
1168         return offset;
1169 }
1170
1171
1172 /* RFC 1094, Page 11 */
1173 int
1174 dissect_nfs2_readdir_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1175 {
1176         guint32 cookie;
1177         guint32 count;
1178
1179         offset = dissect_fhandle (pd, offset, fd, tree, "dir");
1180         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1181         cookie  = EXTRACT_UINT(pd, offset+ 0);
1182         count = EXTRACT_UINT(pd, offset+ 4);
1183         if (tree) {
1184                 proto_tree_add_uint(tree, hf_nfs_readdir_cookie, NullTVB,
1185                         offset+ 0, 4, cookie);
1186                 proto_tree_add_uint(tree, hf_nfs_readdir_count, NullTVB,
1187                         offset+ 4, 4, count);
1188         }
1189         offset += 8;
1190
1191         return offset;
1192 }
1193
1194
1195 /* RFC 1094, Page 11 */
1196 int
1197 dissect_readdir_entry(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1198 {
1199         proto_item* entry_item = NULL;
1200         proto_tree* entry_tree = NULL;
1201         int old_offset = offset;
1202         guint32 fileid;
1203         guint32 cookie;
1204         char *name;
1205
1206         if (tree) {
1207                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, NullTVB,
1208                         offset+0, END_OF_FRAME, FALSE);
1209                 if (entry_item)
1210                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
1211         }
1212
1213         if (!BYTES_ARE_IN_FRAME(offset, 4)) {
1214                 if (entry_item)
1215                         proto_item_set_text(entry_item, "Entry: <TRUNCATED>");
1216                 return offset;
1217         }
1218         fileid = EXTRACT_UINT(pd, offset + 0);
1219         if (entry_tree)
1220                 proto_tree_add_uint(entry_tree, hf_nfs_readdir_entry_fileid, NullTVB,
1221                         offset+0, 4, fileid);
1222         offset += 4;
1223
1224         offset = dissect_filename(pd, offset, fd, entry_tree,
1225                 hf_nfs_readdir_entry_name, &name);
1226         if (entry_item)
1227                 proto_item_set_text(entry_item, "Entry: file ID %u, name %s",
1228                 fileid, name);
1229         g_free(name);
1230         
1231         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
1232         cookie = EXTRACT_UINT(pd, offset + 0);
1233         if (entry_tree)
1234                 proto_tree_add_uint(entry_tree, hf_nfs_readdir_entry_cookie, NullTVB,
1235                         offset+0, 4, cookie);
1236         offset += 4;
1237
1238         /* now we know, that a readdir entry is shorter */
1239         if (entry_item) {
1240                 proto_item_set_len(entry_item, offset - old_offset);
1241         }
1242
1243         return offset;
1244 }
1245
1246 /* RFC 1094, Page 11 */
1247 int
1248 dissect_nfs2_readdir_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1249 {
1250         guint32 status;
1251         guint32 eof_value;
1252
1253         offset = dissect_stat(pd, offset, fd, tree, &status);
1254         switch (status) {
1255                 case 0:
1256                         offset = dissect_rpc_list(pd, offset, fd, tree,
1257                                 dissect_readdir_entry);
1258                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1259                         eof_value = EXTRACT_UINT(pd, offset+0);
1260                         if (tree)
1261                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, NullTVB,
1262                                         offset+ 0, 4, eof_value);
1263                         offset += 4;
1264                 break;
1265                 default:
1266                         /* do nothing */
1267                 break;
1268         }
1269
1270         return offset;
1271 }
1272
1273
1274 /* RFC 1094, Page 12 */
1275 int
1276 dissect_nfs2_statfs_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1277 {
1278         guint32 status;
1279         guint32 tsize;
1280         guint32 bsize;
1281         guint32 blocks;
1282         guint32 bfree;
1283         guint32 bavail;
1284
1285         offset = dissect_stat(pd, offset, fd, tree, &status);
1286         switch (status) {
1287                 case 0:
1288                         if (!BYTES_ARE_IN_FRAME(offset,5 * 4)) return offset;
1289                         tsize  = EXTRACT_UINT(pd, offset+ 0);
1290                         bsize  = EXTRACT_UINT(pd, offset+ 4);
1291                         blocks = EXTRACT_UINT(pd, offset+ 8);
1292                         bfree  = EXTRACT_UINT(pd, offset+12);
1293                         bavail = EXTRACT_UINT(pd, offset+16);
1294                         if (tree) {
1295                                 proto_tree_add_uint(tree, hf_nfs_statfs_tsize, NullTVB,
1296                                         offset+ 0, 4, tsize);
1297                                 proto_tree_add_uint(tree, hf_nfs_statfs_bsize, NullTVB,
1298                                         offset+ 4, 4, bsize);
1299                                 proto_tree_add_uint(tree, hf_nfs_statfs_blocks, NullTVB,
1300                                         offset+ 8, 4, blocks);
1301                                 proto_tree_add_uint(tree, hf_nfs_statfs_bfree, NullTVB,
1302                                         offset+12, 4, bfree);
1303                                 proto_tree_add_uint(tree, hf_nfs_statfs_bavail, NullTVB,
1304                                         offset+16, 4, bavail);
1305                         }
1306                         offset += 20;
1307                 break;
1308                 default:
1309                         /* do nothing */
1310                 break;
1311         }
1312
1313         return offset;
1314 }
1315
1316
1317 /* proc number, "proc name", dissect_request, dissect_reply */
1318 /* NULL as function pointer means: take the generic one. */
1319 const vsff nfs2_proc[] = {
1320         { 0,    "NULL",         /* OK */
1321         NULL,                           NULL },
1322         { 1,    "GETATTR",      /* OK */
1323         dissect_nfs2_fhandle_call,      dissect_nfs2_attrstat_reply },
1324         { 2,    "SETATTR",      /* OK */
1325         dissect_nfs2_setattr_call,      dissect_nfs2_attrstat_reply },
1326         { 3,    "ROOT",         /* OK */
1327         NULL,                           NULL },
1328         { 4,    "LOOKUP",       /* OK */
1329         dissect_nfs2_diropargs_call,    dissect_nfs2_diropres_reply },
1330         { 5,    "READLINK",     /* OK */
1331         dissect_nfs2_fhandle_call,      dissect_nfs2_readlink_reply },
1332         { 6,    "READ",         /* OK */
1333         dissect_nfs2_read_call,         dissect_nfs2_read_reply },
1334         { 7,    "WRITECACHE",   /* OK */
1335         NULL,                           NULL },
1336         { 8,    "WRITE",        /* OK */
1337         dissect_nfs2_write_call,        dissect_nfs2_attrstat_reply },
1338         { 9,    "CREATE",       /* OK */
1339         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
1340         { 10,   "REMOVE",       /* OK */
1341         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
1342         { 11,   "RENAME",       /* OK */
1343         dissect_nfs2_rename_call,       dissect_nfs2_stat_reply },
1344         { 12,   "LINK",         /* OK */
1345         dissect_nfs2_link_call,         dissect_nfs2_stat_reply },
1346         { 13,   "SYMLINK",      /* OK */
1347         dissect_nfs2_symlink_call,      dissect_nfs2_stat_reply },
1348         { 14,   "MKDIR",        /* OK */
1349         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
1350         { 15,   "RMDIR",        /* OK */
1351         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
1352         { 16,   "READDIR",      /* OK */
1353         dissect_nfs2_readdir_call,      dissect_nfs2_readdir_reply },
1354         { 17,   "STATFS",       /* OK */
1355         dissect_nfs2_fhandle_call,      dissect_nfs2_statfs_reply },
1356         { 0,NULL,NULL,NULL }
1357 };
1358 /* end of NFS Version 2 */
1359
1360
1361 /***************************/
1362 /* NFS Version 3, RFC 1813 */
1363 /***************************/
1364
1365
1366 /* RFC 1813, Page 15 */
1367 int
1368 dissect_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1369 char* name)
1370 {
1371         offset = dissect_rpc_uint64(pd,offset,fd,tree,name);
1372         return offset;
1373 }
1374
1375
1376 /* RFC 1813, Page 15 */
1377 int
1378 dissect_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1379 char* name)
1380 {
1381         offset = dissect_rpc_uint32(pd,offset,fd,tree,name);
1382         return offset;
1383 }
1384
1385
1386 /* RFC 1813, Page 15 */
1387 int
1388 dissect_filename3(const u_char *pd, int offset, frame_data *fd,
1389     proto_tree *tree, int hf, char **string_ret)
1390 {
1391         offset = dissect_rpc_string(pd,offset,fd,tree,hf,string_ret);
1392         return offset;
1393 }
1394
1395
1396 /* RFC 1813, Page 15 */
1397 int
1398 dissect_nfspath3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
1399 {
1400         offset = dissect_rpc_string(pd,offset,fd,tree,hf,NULL);
1401         return offset;
1402 }
1403
1404
1405 /* RFC 1813, Page 15 */
1406 int
1407 dissect_fileid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1408 char* name)
1409 {
1410         offset = dissect_rpc_uint64(pd,offset,fd,tree,name);
1411         return offset;
1412 }
1413
1414
1415 /* RFC 1813, Page 15 */
1416 int
1417 dissect_cookie3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1418 char* name)
1419 {
1420         offset = dissect_rpc_uint64(pd,offset,fd,tree,name);
1421         return offset;
1422 }
1423
1424
1425 /* RFC 1813, Page 15 */
1426 int
1427 dissect_cookieverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1428 {
1429         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1430         proto_tree_add_text(tree, NullTVB, offset, NFS3_COOKIEVERFSIZE,
1431                 "Verifier: Opaque Data");
1432         offset += NFS3_COOKIEVERFSIZE;
1433         return offset;
1434 }
1435
1436
1437 /* RFC 1813, Page 16 */
1438 int
1439 dissect_createverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1440 {
1441         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1442         proto_tree_add_text(tree, NullTVB, offset, NFS3_CREATEVERFSIZE,
1443                 "Verifier: Opaque Data");
1444         offset += NFS3_CREATEVERFSIZE;
1445         return offset;
1446 }
1447
1448
1449 /* RFC 1813, Page 16 */
1450 int
1451 dissect_writeverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1452 {
1453         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1454         proto_tree_add_text(tree, NullTVB, offset, NFS3_WRITEVERFSIZE,
1455                 "Verifier: Opaque Data");
1456         offset += NFS3_WRITEVERFSIZE;
1457         return offset;
1458 }
1459
1460
1461 /* RFC 1813, Page 16 */
1462 int
1463 dissect_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1464 char* name)
1465 {
1466         offset = dissect_rpc_uint32(pd,offset,fd,tree,name); 
1467         return offset;
1468 }
1469
1470
1471 /* RFC 1813, Page 16 */
1472 int
1473 dissect_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1474 char* name)
1475 {
1476         offset = dissect_rpc_uint32(pd,offset,fd,tree,name); 
1477         return offset;
1478 }
1479
1480
1481 /* RFC 1813, Page 16 */
1482 int
1483 dissect_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1484 char* name)
1485 {
1486         offset = dissect_rpc_uint64(pd,offset,fd,tree,name); 
1487         return offset;
1488 }
1489
1490
1491 /* RFC 1813, Page 16 */
1492 int
1493 dissect_offset3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1494 char* name)
1495 {
1496         offset = dissect_rpc_uint64(pd,offset,fd,tree,name); 
1497         return offset;
1498 }
1499
1500
1501 /* RFC 1813, Page 16 */
1502 int
1503 dissect_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1504 char* name)
1505 {
1506         guint32 mode3;
1507         proto_item* mode3_item = NULL;
1508         proto_tree* mode3_tree = NULL;
1509
1510         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1511         mode3 = EXTRACT_UINT(pd, offset+0);
1512         
1513         if (tree) {
1514                 mode3_item = proto_tree_add_text(tree, NullTVB, offset, 4,
1515                         "%s: 0%o", name, mode3);
1516                 if (mode3_item)
1517                         mode3_tree = proto_item_add_subtree(mode3_item, ett_nfs_mode3);
1518         }
1519
1520         /* RFC 1813, Page 23 */
1521         if (mode3_tree) {
1522                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1523                 decode_boolean_bitfield(mode3,   0x800, 12, "Set user id on exec", "not SUID"));
1524                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1525                 decode_boolean_bitfield(mode3,   0x400, 12, "Set group id on exec", "not SGID"));
1526                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1527                 decode_boolean_bitfield(mode3,   0x200, 12, "Save swapped text even after use", "not save swapped text"));
1528                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1529                 decode_boolean_bitfield(mode3,   0x100, 12, "Read permission for owner", "no Read permission for owner"));
1530                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1531                 decode_boolean_bitfield(mode3,    0x80, 12, "Write permission for owner", "no Write permission for owner"));
1532                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1533                 decode_boolean_bitfield(mode3,    0x40, 12, "Execute permission for owner", "no Execute permission for owner"));
1534                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1535                 decode_boolean_bitfield(mode3,    0x20, 12, "Read permission for group", "no Read permission for group"));
1536                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1537                 decode_boolean_bitfield(mode3,    0x10, 12, "Write permission for group", "no Write permission for group"));
1538                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1539                 decode_boolean_bitfield(mode3,     0x8, 12, "Execute permission for group", "no Execute permission for group"));
1540                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1541                 decode_boolean_bitfield(mode3,     0x4, 12, "Read permission for others", "no Read permission for others"));
1542                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1543                 decode_boolean_bitfield(mode3,     0x2, 12, "Write permission for others", "no Write permission for others"));
1544                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1545                 decode_boolean_bitfield(mode3,     0x1, 12, "Execute permission for others", "no Execute permission for others"));
1546         }
1547
1548         offset += 4;
1549         return offset;
1550 }
1551
1552
1553 /* RFC 1813, Page 16 */
1554 int
1555 dissect_count3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1556 char* name)
1557 {
1558         offset = dissect_rpc_uint32(pd,offset,fd,tree,name);
1559         return offset;
1560 }
1561
1562
1563 /* RFC 1813, Page 16,17 */
1564 const value_string names_nfs_nfsstat3[] =
1565 {
1566         {       0,      "OK" },
1567         {       1,      "ERR_PERM" },
1568         {       2,      "ERR_NOENT" },
1569         {       5,      "ERR_IO" },
1570         {       6,      "ERR_NX_IO" },
1571         {       13,     "ERR_ACCES" },
1572         {       17,     "ERR_EXIST" },
1573         {       18,     "ERR_XDEV" },
1574         {       19,     "ERR_NODEV" },
1575         {       20,     "ERR_NOTDIR" },
1576         {       21,     "ERR_ISDIR" },
1577         {       22,     "ERR_INVAL" },
1578         {       27,     "ERR_FBIG" },
1579         {       28,     "ERR_NOSPC" },
1580         {       30,     "ERR_ROFS" },
1581         {       31,     "ERR_MLINK" },
1582         {       63,     "ERR_NAMETOOLONG" },
1583         {       66,     "ERR_NOTEMPTY" },
1584         {       69,     "ERR_DQUOT" },
1585         {       70,     "ERR_STALE" },
1586         {       71,     "ERR_REMOTE" },
1587         {       10001,  "ERR_BADHANDLE" },
1588         {       10002,  "ERR_NOT_SYNC" },
1589         {       10003,  "ERR_BAD_COOKIE" },
1590         {       10004,  "ERR_NOTSUPP" },
1591         {       10005,  "ERR_TOOSMALL" },
1592         {       10006,  "ERR_SERVERFAULT" },
1593         {       10007,  "ERR_BADTYPE" },
1594         {       10008,  "ERR_JUKEBOX" },
1595         {       0,      NULL }
1596 };
1597
1598
1599 /* RFC 1813, Page 16 */
1600 int
1601 dissect_nfsstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,guint32 *status)
1602 {
1603         guint32 nfsstat3;
1604
1605         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1606         nfsstat3 = EXTRACT_UINT(pd, offset+0);
1607         
1608         if (tree) {
1609                 proto_tree_add_uint(tree, hf_nfs_nfsstat3, NullTVB,
1610                         offset, 4, nfsstat3);
1611         }
1612
1613         offset += 4;
1614         *status = nfsstat3;
1615         return offset;
1616 }
1617
1618
1619 const value_string names_nfs_ftype3[] =
1620 {
1621         {       NF3REG, "Regular File" },
1622         {       NF3DIR, "Directory" },
1623         {       NF3BLK, "Block Special Device" },
1624         {       NF3CHR, "Character Special Device" },
1625         {       NF3LNK, "Symbolic Link" },
1626         {       NF3SOCK,"Socket" },
1627         {       NF3FIFO,"Named Pipe" },
1628         {       0,      NULL }
1629 };
1630
1631
1632 /* RFC 1813, Page 20 */
1633 int
1634 dissect_ftype3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1635 int hf, guint32* ftype3)
1636 {
1637         guint32 type;
1638
1639         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1640         type = EXTRACT_UINT(pd, offset+0);
1641         
1642         if (tree) {
1643                 proto_tree_add_uint(tree, hf, NullTVB, offset, 4, type);
1644         }
1645
1646         offset += 4;
1647         *ftype3 = type;
1648         return offset;
1649 }
1650
1651
1652 /* RFC 1813, Page 20 */
1653 int
1654 dissect_specdata3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1655 {
1656         guint32 specdata1;
1657         guint32 specdata2;
1658
1659         proto_item* specdata3_item;
1660         proto_tree* specdata3_tree = NULL;
1661
1662         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1663         specdata1 = EXTRACT_UINT(pd, offset+0);
1664         specdata2 = EXTRACT_UINT(pd, offset+4);
1665         
1666         if (tree) {
1667                 specdata3_item = proto_tree_add_text(tree, NullTVB, offset, 8,
1668                         "%s: %u,%u", name, specdata1, specdata2);
1669                 if (specdata3_item)
1670                         specdata3_tree = proto_item_add_subtree(specdata3_item,
1671                                         ett_nfs_specdata3);
1672         }
1673
1674         if (specdata3_tree) {
1675                 proto_tree_add_text(specdata3_tree, NullTVB,offset+0,4,
1676                                         "specdata1: %u", specdata1);
1677                 proto_tree_add_text(specdata3_tree, NullTVB,offset+4,4,
1678                                         "specdata2: %u", specdata2);
1679         }
1680
1681         offset += 8;
1682         return offset;
1683 }
1684
1685
1686 /* RFC 1813, Page 21 */
1687 int
1688 dissect_nfs_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1689 {
1690         guint fh3_len;
1691         guint fh3_len_full;
1692         guint fh3_fill;
1693         proto_item* fitem;
1694         proto_tree* ftree = NULL;
1695
1696         fh3_len = EXTRACT_UINT(pd, offset+0);
1697         fh3_len_full = rpc_roundup(fh3_len);
1698         fh3_fill = fh3_len_full - fh3_len;
1699         
1700         if (tree) {
1701                 fitem = proto_tree_add_text(tree, NullTVB, offset, 4+fh3_len_full,
1702                         "%s", name);
1703                 if (fitem)
1704                         ftree = proto_item_add_subtree(fitem, ett_nfs_fh3);
1705         }
1706
1707         if (ftree) {
1708                 proto_tree_add_text(ftree, NullTVB,offset+0,4,
1709                                         "length: %u", fh3_len);
1710                 dissect_fhandle_data(pd, offset+4, fd, ftree, fh3_len);
1711         }
1712         offset += 4 + fh3_len_full;
1713         return offset;
1714 }
1715
1716
1717 /* RFC 1813, Page 21 */
1718 int
1719 dissect_nfstime3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,char* name)
1720 {
1721         guint32 seconds;
1722         guint32 nseconds;
1723
1724         proto_item* time_item;
1725         proto_tree* time_tree = NULL;
1726
1727         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1728         seconds = EXTRACT_UINT(pd, offset+0);
1729         nseconds = EXTRACT_UINT(pd, offset+4);
1730         
1731         if (tree) {
1732                 time_item = proto_tree_add_text(tree, NullTVB, offset, 8,
1733                         "%s: %u.%09u", name, seconds, nseconds);
1734                 if (time_item)
1735                         time_tree = proto_item_add_subtree(time_item, ett_nfs_nfstime3);
1736         }
1737
1738         if (time_tree) {
1739                 proto_tree_add_text(time_tree, NullTVB,offset+0,4,
1740                                         "seconds: %u", seconds);
1741                 proto_tree_add_text(time_tree, NullTVB,offset+4,4,
1742                                         "nano seconds: %u", nseconds);
1743         }
1744         offset += 8;
1745         return offset;
1746 }
1747
1748
1749 /* RFC 1813, Page 22 */
1750 int
1751 dissect_fattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1752 {
1753         proto_item* fattr3_item = NULL;
1754         proto_tree* fattr3_tree = NULL;
1755         int old_offset = offset;
1756         guint32 type;
1757
1758         if (tree) {
1759                 fattr3_item = proto_tree_add_text(tree, NullTVB, offset,
1760                         END_OF_FRAME, "%s", name);
1761                 if (fattr3_item)
1762                         fattr3_tree = proto_item_add_subtree(fattr3_item, ett_nfs_fattr3);
1763         }
1764
1765         offset = dissect_ftype3   (pd,offset,fd,fattr3_tree,hf_nfs_ftype3,&type);
1766         offset = dissect_mode3    (pd,offset,fd,fattr3_tree,"mode");
1767         offset = dissect_uint32   (pd,offset,fd,fattr3_tree,"nlink");
1768         offset = dissect_uid3     (pd,offset,fd,fattr3_tree,"uid");
1769         offset = dissect_gid3     (pd,offset,fd,fattr3_tree,"gid");
1770         offset = dissect_size3    (pd,offset,fd,fattr3_tree,"size");
1771         offset = dissect_size3    (pd,offset,fd,fattr3_tree,"used");
1772         offset = dissect_specdata3(pd,offset,fd,fattr3_tree,"rdev");
1773         offset = dissect_uint64   (pd,offset,fd,fattr3_tree,"fsid");
1774         offset = dissect_fileid3  (pd,offset,fd,fattr3_tree,"fileid");
1775         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"atime");
1776         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"mtime");
1777         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"ctime");
1778
1779         /* now we know, that fattr3 is shorter */
1780         if (fattr3_item) {
1781                 proto_item_set_len(fattr3_item, offset - old_offset);
1782         }
1783
1784         return offset;
1785 }
1786
1787
1788 const value_string value_follows[] =
1789         {
1790                 { 0, "no value" },
1791                 { 1, "value follows"},
1792                 { 0, NULL }
1793         };
1794
1795
1796 /* RFC 1813, Page 23 */
1797 int
1798 dissect_post_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1799 {
1800         proto_item* post_op_attr_item = NULL;
1801         proto_tree* post_op_attr_tree = NULL;
1802         int old_offset = offset;
1803         guint32 attributes_follow;
1804
1805         if (tree) {
1806                 post_op_attr_item = proto_tree_add_text(tree, NullTVB, offset,
1807                         END_OF_FRAME, "%s", name);
1808                 if (post_op_attr_item)
1809                         post_op_attr_tree = proto_item_add_subtree(post_op_attr_item, ett_nfs_post_op_attr);
1810         }
1811
1812         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1813         attributes_follow = EXTRACT_UINT(pd, offset+0);
1814         proto_tree_add_text(post_op_attr_tree, NullTVB, offset, 4,
1815                 "attributes_follow: %s (%u)", 
1816                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
1817         offset += 4;
1818         switch (attributes_follow) {
1819                 case TRUE:
1820                         offset = dissect_fattr3(pd, offset, fd, post_op_attr_tree,
1821                                         "attributes");
1822                 break;
1823                 case FALSE:
1824                         /* void */
1825                 break;
1826         }
1827         
1828         /* now we know, that post_op_attr_tree is shorter */
1829         if (post_op_attr_item) {
1830                 proto_item_set_len(post_op_attr_item, offset - old_offset);
1831         }
1832
1833         return offset;
1834 }
1835
1836
1837 /* RFC 1813, Page 24 */
1838 int
1839 dissect_wcc_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1840 {
1841         proto_item* wcc_attr_item = NULL;
1842         proto_tree* wcc_attr_tree = NULL;
1843         int old_offset = offset;
1844
1845         if (tree) {
1846                 wcc_attr_item = proto_tree_add_text(tree, NullTVB, offset,
1847                         END_OF_FRAME, "%s", name);
1848                 if (wcc_attr_item)
1849                         wcc_attr_tree = proto_item_add_subtree(wcc_attr_item, ett_nfs_wcc_attr);
1850         }
1851
1852         offset = dissect_size3   (pd, offset, fd, wcc_attr_tree, "size" );
1853         offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "mtime");
1854         offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "ctime");
1855         
1856         /* now we know, that wcc_attr_tree is shorter */
1857         if (wcc_attr_item) {
1858                 proto_item_set_len(wcc_attr_item, offset - old_offset);
1859         }
1860
1861         return offset;
1862 }
1863
1864
1865 /* RFC 1813, Page 24 */
1866 int
1867 dissect_pre_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1868 {
1869         proto_item* pre_op_attr_item = NULL;
1870         proto_tree* pre_op_attr_tree = NULL;
1871         int old_offset = offset;
1872         guint32 attributes_follow;
1873
1874         if (tree) {
1875                 pre_op_attr_item = proto_tree_add_text(tree, NullTVB, offset,
1876                         END_OF_FRAME, "%s", name);
1877                 if (pre_op_attr_item)
1878                         pre_op_attr_tree = proto_item_add_subtree(pre_op_attr_item, ett_nfs_pre_op_attr);
1879         }
1880
1881         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1882         attributes_follow = EXTRACT_UINT(pd, offset+0);
1883         proto_tree_add_text(pre_op_attr_tree, NullTVB, offset, 4,
1884                 "attributes_follow: %s (%u)", 
1885                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
1886         offset += 4;
1887         switch (attributes_follow) {
1888                 case TRUE:
1889                         offset = dissect_wcc_attr(pd, offset, fd, pre_op_attr_tree,
1890                                         "attributes");
1891                 break;
1892                 case FALSE:
1893                         /* void */
1894                 break;
1895         }
1896         
1897         /* now we know, that pre_op_attr_tree is shorter */
1898         if (pre_op_attr_item) {
1899                 proto_item_set_len(pre_op_attr_item, offset - old_offset);
1900         }
1901
1902         return offset;
1903 }
1904
1905
1906 /* RFC 1813, Page 24 */
1907 int
1908 dissect_wcc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1909 {
1910         proto_item* wcc_data_item = NULL;
1911         proto_tree* wcc_data_tree = NULL;
1912         int old_offset = offset;
1913
1914         if (tree) {
1915                 wcc_data_item = proto_tree_add_text(tree, NullTVB, offset,
1916                         END_OF_FRAME, "%s", name);
1917                 if (wcc_data_item)
1918                         wcc_data_tree = proto_item_add_subtree(wcc_data_item, ett_nfs_wcc_data);
1919         }
1920
1921         offset = dissect_pre_op_attr (pd, offset, fd, wcc_data_tree, "before");
1922         offset = dissect_post_op_attr(pd, offset, fd, wcc_data_tree, "after" );
1923
1924         /* now we know, that wcc_data is shorter */
1925         if (wcc_data_item) {
1926                 proto_item_set_len(wcc_data_item, offset - old_offset);
1927         }
1928
1929         return offset;
1930 }
1931
1932
1933 /* RFC 1813, Page 25 */
1934 int
1935 dissect_post_op_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1936 {
1937         proto_item* post_op_fh3_item = NULL;
1938         proto_tree* post_op_fh3_tree = NULL;
1939         int old_offset = offset;
1940         guint32 handle_follows;
1941
1942         if (tree) {
1943                 post_op_fh3_item = proto_tree_add_text(tree, NullTVB, offset,
1944                         END_OF_FRAME, "%s", name);
1945                 if (post_op_fh3_item)
1946                         post_op_fh3_tree = proto_item_add_subtree(post_op_fh3_item, ett_nfs_post_op_fh3);
1947         }
1948
1949         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1950         handle_follows = EXTRACT_UINT(pd, offset+0);
1951         proto_tree_add_text(post_op_fh3_tree, NullTVB, offset, 4,
1952                 "handle_follows: %s (%u)", 
1953                 val_to_str(handle_follows,value_follows,"Unknown"), handle_follows);
1954         offset += 4;
1955         switch (handle_follows) {
1956                 case TRUE:
1957                         offset = dissect_nfs_fh3(pd, offset, fd, post_op_fh3_tree,
1958                                         "handle");
1959                 break;
1960                 case FALSE:
1961                         /* void */
1962                 break;
1963         }
1964         
1965         /* now we know, that post_op_fh3_tree is shorter */
1966         if (post_op_fh3_item) {
1967                 proto_item_set_len(post_op_fh3_item, offset - old_offset);
1968         }
1969
1970         return offset;
1971 }
1972
1973
1974 /* RFC 1813, Page 25 */
1975 int
1976 dissect_set_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1977 {
1978         proto_item* set_mode3_item = NULL;
1979         proto_tree* set_mode3_tree = NULL;
1980         int old_offset = offset;
1981         guint32 set_it;
1982         char* set_it_name;
1983
1984         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1985         set_it = EXTRACT_UINT(pd, offset+0);
1986         set_it_name = val_to_str(set_it,value_follows,"Unknown");
1987
1988         if (tree) {
1989                 set_mode3_item = proto_tree_add_text(tree, NullTVB, offset,
1990                         END_OF_FRAME, "%s: %s", name, set_it_name);
1991                 if (set_mode3_item)
1992                         set_mode3_tree = proto_item_add_subtree(set_mode3_item, ett_nfs_set_mode3);
1993         }
1994
1995         if (set_mode3_tree)
1996                 proto_tree_add_text(set_mode3_tree, NullTVB, offset, 4,
1997                         "set_it: %s (%u)", set_it_name, set_it);
1998
1999         offset += 4;
2000
2001         switch (set_it) {
2002                 case 1:
2003                         offset = dissect_mode3(pd, offset, fd, set_mode3_tree,
2004                                         "mode");
2005                 break;
2006                 default:
2007                         /* void */
2008                 break;
2009         }
2010         
2011         /* now we know, that set_mode3 is shorter */
2012         if (set_mode3_item) {
2013                 proto_item_set_len(set_mode3_item, offset - old_offset);
2014         }
2015
2016         return offset;
2017 }
2018
2019
2020 /* RFC 1813, Page 26 */
2021 int
2022 dissect_set_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2023 {
2024         proto_item* set_uid3_item = NULL;
2025         proto_tree* set_uid3_tree = NULL;
2026         int old_offset = offset;
2027         guint32 set_it;
2028         char* set_it_name;
2029
2030         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2031         set_it = EXTRACT_UINT(pd, offset+0);
2032         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2033
2034         if (tree) {
2035                 set_uid3_item = proto_tree_add_text(tree, NullTVB, offset,
2036                         END_OF_FRAME, "%s: %s", name, set_it_name);
2037                 if (set_uid3_item)
2038                         set_uid3_tree = proto_item_add_subtree(set_uid3_item, ett_nfs_set_uid3);
2039         }
2040
2041         if (set_uid3_tree)
2042                 proto_tree_add_text(set_uid3_tree, NullTVB, offset, 4,
2043                         "set_it: %s (%u)", set_it_name, set_it);
2044
2045         offset += 4;
2046
2047         switch (set_it) {
2048                 case 1:
2049                         offset = dissect_uid3(pd, offset, fd, set_uid3_tree,
2050                                         "uid");
2051                 break;
2052                 default:
2053                         /* void */
2054                 break;
2055         }
2056
2057         /* now we know, that set_uid3 is shorter */
2058         if (set_uid3_item) {
2059                 proto_item_set_len(set_uid3_item, offset - old_offset);
2060         }
2061
2062         return offset;
2063 }
2064
2065
2066 /* RFC 1813, Page 26 */
2067 int
2068 dissect_set_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2069 {
2070         proto_item* set_gid3_item = NULL;
2071         proto_tree* set_gid3_tree = NULL;
2072         int old_offset = offset;
2073         guint32 set_it;
2074         char* set_it_name;
2075
2076         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2077         set_it = EXTRACT_UINT(pd, offset+0);
2078         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2079
2080         if (tree) {
2081                 set_gid3_item = proto_tree_add_text(tree, NullTVB, offset,
2082                         END_OF_FRAME, "%s: %s", name, set_it_name);
2083                 if (set_gid3_item)
2084                         set_gid3_tree = proto_item_add_subtree(set_gid3_item, ett_nfs_set_gid3);
2085         }
2086
2087         if (set_gid3_tree)
2088                 proto_tree_add_text(set_gid3_tree, NullTVB, offset, 4,
2089                         "set_it: %s (%u)", set_it_name, set_it);
2090
2091         offset += 4;
2092
2093         switch (set_it) {
2094                 case 1:
2095                         offset = dissect_gid3(pd, offset, fd, set_gid3_tree,
2096                                         "gid");
2097                 break;
2098                 default:
2099                         /* void */
2100                 break;
2101         }
2102
2103         /* now we know, that set_gid3 is shorter */
2104         if (set_gid3_item) {
2105                 proto_item_set_len(set_gid3_item, offset - old_offset);
2106         }
2107
2108         return offset;
2109 }
2110
2111
2112 /* RFC 1813, Page 26 */
2113 int
2114 dissect_set_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2115 {
2116         proto_item* set_size3_item = NULL;
2117         proto_tree* set_size3_tree = NULL;
2118         int old_offset = offset;
2119         guint32 set_it;
2120         char* set_it_name;
2121
2122         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2123         set_it = EXTRACT_UINT(pd, offset+0);
2124         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2125
2126         if (tree) {
2127                 set_size3_item = proto_tree_add_text(tree, NullTVB, offset,
2128                         END_OF_FRAME, "%s: %s", name, set_it_name);
2129                 if (set_size3_item)
2130                         set_size3_tree = proto_item_add_subtree(set_size3_item, ett_nfs_set_size3);
2131         }
2132
2133         if (set_size3_tree)
2134                 proto_tree_add_text(set_size3_tree, NullTVB, offset, 4,
2135                         "set_it: %s (%u)", set_it_name, set_it);
2136
2137         offset += 4;
2138
2139         switch (set_it) {
2140                 case 1:
2141                         offset = dissect_size3(pd, offset, fd, set_size3_tree,
2142                                         "size");
2143                 break;
2144                 default:
2145                         /* void */
2146                 break;
2147         }
2148
2149         /* now we know, that set_size3 is shorter */
2150         if (set_size3_item) {
2151                 proto_item_set_len(set_size3_item, offset - old_offset);
2152         }
2153
2154         return offset;
2155 }
2156
2157
2158 /* RFC 1813, Page 25 */
2159 #define DONT_CHANGE 0
2160 #define SET_TO_SERVER_TIME 1
2161 #define SET_TO_CLIENT_TIME 2
2162
2163 const value_string time_how[] =
2164         {
2165                 { DONT_CHANGE,  "don't change" },
2166                 { SET_TO_SERVER_TIME, "set to server time" },
2167                 { SET_TO_CLIENT_TIME, "set to client time" },
2168                 { 0, NULL }
2169         };
2170
2171
2172 /* RFC 1813, Page 26 */
2173 int
2174 dissect_set_atime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2175 {
2176         proto_item* set_atime_item = NULL;
2177         proto_tree* set_atime_tree = NULL;
2178         int old_offset = offset;
2179         guint32 set_it;
2180         char* set_it_name;
2181
2182         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2183         set_it = EXTRACT_UINT(pd, offset+0);
2184         set_it_name = val_to_str(set_it,time_how,"Unknown");
2185
2186         if (tree) {
2187                 set_atime_item = proto_tree_add_text(tree, NullTVB, offset,
2188                         END_OF_FRAME, "%s: %s",
2189                         name, set_it_name);
2190                 if (set_atime_item)
2191                         set_atime_tree = proto_item_add_subtree(set_atime_item, ett_nfs_set_atime);
2192         }
2193
2194         if (set_atime_tree)
2195                 proto_tree_add_text(set_atime_tree, NullTVB, offset, 4,
2196                         "set_it: %s (%u)", set_it_name, set_it);
2197
2198         offset += 4;
2199
2200         switch (set_it) {
2201                 case SET_TO_CLIENT_TIME:
2202                         if (set_atime_item)
2203                         offset = dissect_nfstime3(pd, offset, fd, set_atime_tree,
2204                                         "atime");
2205                 break;
2206                 default:
2207                         /* void */
2208                 break;
2209         }
2210
2211         /* now we know, that set_atime is shorter */
2212         if (set_atime_item) {
2213                 proto_item_set_len(set_atime_item, offset - old_offset);
2214         }
2215
2216         return offset;
2217 }
2218
2219
2220 /* RFC 1813, Page 26 */
2221 int
2222 dissect_set_mtime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2223 {
2224         proto_item* set_mtime_item = NULL;
2225         proto_tree* set_mtime_tree = NULL;
2226         int old_offset = offset;
2227         guint32 set_it;
2228         char* set_it_name;
2229
2230         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2231         set_it = EXTRACT_UINT(pd, offset+0);
2232         set_it_name = val_to_str(set_it,time_how,"Unknown");
2233
2234         if (tree) {
2235                 set_mtime_item = proto_tree_add_text(tree, NullTVB, offset,
2236                         END_OF_FRAME, "%s: %s",
2237                         name, set_it_name);
2238                 if (set_mtime_item)
2239                         set_mtime_tree = proto_item_add_subtree(set_mtime_item, ett_nfs_set_mtime);
2240         }
2241
2242         if (set_mtime_tree)
2243                 proto_tree_add_text(set_mtime_tree, NullTVB, offset, 4,
2244                                 "set_it: %s (%u)", set_it_name, set_it);
2245
2246         offset += 4;
2247
2248         switch (set_it) {
2249                 case SET_TO_CLIENT_TIME:
2250                         if (set_mtime_item)
2251                         offset = dissect_nfstime3(pd, offset, fd, set_mtime_tree,
2252                                         "atime");
2253                 break;
2254                 default:
2255                         /* void */
2256                 break;
2257         }
2258
2259         /* now we know, that set_mtime is shorter */
2260         if (set_mtime_item) {
2261                 proto_item_set_len(set_mtime_item, offset - old_offset);
2262         }
2263
2264         return offset;
2265 }
2266
2267
2268 /* RFC 1813, Page 25..27 */
2269 int
2270 dissect_sattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2271 {
2272         proto_item* sattr3_item = NULL;
2273         proto_tree* sattr3_tree = NULL;
2274         int old_offset = offset;
2275
2276         if (tree) {
2277                 sattr3_item = proto_tree_add_text(tree, NullTVB, offset,
2278                         END_OF_FRAME, "%s", name);
2279                 if (sattr3_item)
2280                         sattr3_tree = proto_item_add_subtree(sattr3_item, ett_nfs_sattr3);
2281         }
2282
2283         offset = dissect_set_mode3(pd, offset, fd, sattr3_tree, "mode");
2284         offset = dissect_set_uid3 (pd, offset, fd, sattr3_tree, "uid");
2285         offset = dissect_set_gid3 (pd, offset, fd, sattr3_tree, "gid");
2286         offset = dissect_set_size3(pd, offset, fd, sattr3_tree, "size");
2287         offset = dissect_set_atime(pd, offset, fd, sattr3_tree, "atime");
2288         offset = dissect_set_mtime(pd, offset, fd, sattr3_tree, "mtime");
2289
2290         /* now we know, that sattr3 is shorter */
2291         if (sattr3_item) {
2292                 proto_item_set_len(sattr3_item, offset - old_offset);
2293         }
2294
2295         return offset;
2296 }
2297
2298
2299 /* RFC 1813, Page 27 */
2300 int
2301 dissect_diropargs3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2302 {
2303         proto_item* diropargs3_item = NULL;
2304         proto_tree* diropargs3_tree = NULL;
2305         int old_offset = offset;
2306
2307         if (tree) {
2308                 diropargs3_item = proto_tree_add_text(tree, NullTVB, offset,
2309                         END_OF_FRAME, "%s", name);
2310                 if (diropargs3_item)
2311                         diropargs3_tree = proto_item_add_subtree(diropargs3_item, ett_nfs_diropargs3);
2312         }
2313
2314         offset = dissect_nfs_fh3  (pd, offset, fd, diropargs3_tree, "dir");
2315         offset = dissect_filename3(pd, offset, fd, diropargs3_tree, hf_nfs_name,NULL);
2316
2317         /* now we know, that diropargs3 is shorter */
2318         if (diropargs3_item) {
2319                 proto_item_set_len(diropargs3_item, offset - old_offset);
2320         }
2321
2322         return offset;
2323 }
2324
2325
2326 /* RFC 1813, Page 27 */
2327 int
2328 dissect_nfs3_diropargs3_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
2329 {
2330         offset = dissect_diropargs3(pd, offset, fd, tree, "object");
2331
2332         return offset;
2333 }
2334
2335
2336 /* RFC 1813, Page 40 */
2337 int
2338 dissect_access(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2339 {
2340         guint32 access;
2341         proto_item* access_item = NULL;
2342         proto_tree* access_tree = NULL;
2343
2344         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2345         access = EXTRACT_UINT(pd, offset+0);
2346         
2347         if (tree) {
2348                 access_item = proto_tree_add_text(tree, NullTVB, offset, 4,
2349                         "%s: 0x%02x", name, access);
2350                 if (access_item)
2351                         access_tree = proto_item_add_subtree(access_item, ett_nfs_access);
2352         }
2353
2354         if (access_tree) {
2355                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s READ",
2356                 decode_boolean_bitfield(access,  0x001, 6, "allow", "not allow"));
2357                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s LOOKUP",
2358                 decode_boolean_bitfield(access,  0x002, 6, "allow", "not allow"));
2359                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s MODIFY",
2360                 decode_boolean_bitfield(access,  0x004, 6, "allowed", "not allow"));
2361                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s EXTEND",
2362                 decode_boolean_bitfield(access,  0x008, 6, "allow", "not allow"));
2363                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s DELETE",
2364                 decode_boolean_bitfield(access,  0x010, 6, "allow", "not allow"));
2365                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s EXECUTE",
2366                 decode_boolean_bitfield(access,  0x020, 6, "allow", "not allow"));
2367         }
2368
2369         offset += 4;
2370         return offset;
2371 }
2372
2373
2374 /* NFS3 file handle dissector */
2375 int
2376 dissect_nfs3_nfs_fh3_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2377 {
2378         offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
2379         return offset;
2380 }
2381
2382
2383 /* generic NFS3 reply dissector */
2384 int
2385 dissect_nfs3_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2386 {
2387         guint32 status;
2388
2389         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2390
2391         return offset;
2392
2393 }
2394
2395
2396 /* RFC 1813, Page 32,33 */
2397 int
2398 dissect_nfs3_getattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2399 {
2400         offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
2401         return offset;
2402 }
2403
2404
2405 /* RFC 1813, Page 32,33 */
2406 int
2407 dissect_nfs3_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2408 {
2409         guint32 status;
2410
2411         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2412         switch (status) {
2413                 case 0:
2414                         offset = dissect_fattr3(pd, offset, fd, tree, "obj_attributes");
2415                 break;
2416                 default:
2417                         /* void */
2418                 break;
2419         }
2420                 
2421         return offset;
2422 }
2423
2424
2425 /* RFC 1813, Page 33 */
2426 int
2427 dissect_sattrguard3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, char *name)
2428 {
2429         proto_item* sattrguard3_item = NULL;
2430         proto_tree* sattrguard3_tree = NULL;
2431         int old_offset = offset;
2432         guint32 check;
2433         char* check_name;
2434
2435         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2436         check = EXTRACT_UINT(pd, offset+0);
2437         check_name = val_to_str(check,value_follows,"Unknown");
2438
2439         if (tree) {
2440                 sattrguard3_item = proto_tree_add_text(tree, NullTVB, offset,
2441                         END_OF_FRAME, "%s: %s", name, check_name);
2442                 if (sattrguard3_item)
2443                         sattrguard3_tree = proto_item_add_subtree(sattrguard3_item, ett_nfs_sattrguard3);
2444         }
2445
2446         if (sattrguard3_tree)
2447                 proto_tree_add_text(sattrguard3_tree, NullTVB, offset, 4,
2448                         "check: %s (%u)", check_name, check);
2449
2450         offset += 4;
2451
2452         switch (check) {
2453                 case TRUE:
2454                         offset = dissect_nfstime3(pd, offset, fd, sattrguard3_tree,
2455                                         "obj_ctime");
2456                 break;
2457                 case FALSE:
2458                         /* void */
2459                 break;
2460         }
2461
2462         /* now we know, that sattrguard3 is shorter */
2463         if (sattrguard3_item) {
2464                 proto_item_set_len(sattrguard3_item, offset - old_offset);
2465         }
2466
2467         return offset;
2468 }
2469
2470
2471 /* RFC 1813, Page 33..36 */
2472 int
2473 dissect_nfs3_setattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2474 {
2475         offset = dissect_nfs_fh3    (pd, offset, fd, tree, "object");
2476         offset = dissect_sattr3     (pd, offset, fd, tree, "new_attributes");
2477         offset = dissect_sattrguard3(pd, offset, fd, tree, "guard");
2478         return offset;
2479 }
2480
2481
2482 /* RFC 1813, Page 33..36 */
2483 int
2484 dissect_nfs3_setattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2485 {
2486         guint32 status;
2487
2488         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2489         switch (status) {
2490                 case 0:
2491                         offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
2492                 break;
2493                 default:
2494                         offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
2495                 break;
2496         }
2497                 
2498         return offset;
2499 }
2500
2501
2502 /* RFC 1813, Page 37..39 */
2503 int
2504 dissect_nfs3_lookup_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2505 {
2506         offset = dissect_diropargs3 (pd, offset, fd, tree, "what");
2507         return offset;
2508 }
2509
2510
2511 /* RFC 1813, Page 37..39 */
2512 int
2513 dissect_nfs3_lookup_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2514 {
2515         guint32 status;
2516
2517         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2518         switch (status) {
2519                 case 0:
2520                         offset = dissect_nfs_fh3     (pd, offset, fd, tree, "object");
2521                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2522                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2523                 break;
2524                 default:
2525                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2526                 break;
2527         }
2528                 
2529         return offset;
2530 }
2531
2532
2533 /* RFC 1813, Page 40..43 */
2534 int
2535 dissect_nfs3_access_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2536 {
2537         offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
2538         offset = dissect_access (pd, offset, fd, tree, "access");
2539
2540         return offset;
2541 }
2542
2543
2544 /* RFC 1813, Page 40..43 */
2545 int
2546 dissect_nfs3_access_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2547 {
2548         guint32 status;
2549
2550         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2551         switch (status) {
2552                 case 0:
2553                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2554                         offset = dissect_access      (pd, offset, fd, tree, "access");
2555                 break;
2556                 default:
2557                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2558                 break;
2559         }
2560                 
2561         return offset;
2562 }
2563
2564
2565 /* RFC 1813, Page 44,45 */
2566 int
2567 dissect_nfs3_readlink_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2568 {
2569         guint32 status;
2570
2571         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2572         switch (status) {
2573                 case 0:
2574                         offset = dissect_post_op_attr(pd, offset, fd, tree, "symlink_attributes");
2575                         offset = dissect_nfspath3    (pd, offset, fd, tree, hf_nfs_readlink_data);
2576                 break;
2577                 default:
2578                         offset = dissect_post_op_attr(pd, offset, fd, tree, "symlink_attributes");
2579                 break;
2580         }
2581                 
2582         return offset;
2583 }
2584
2585
2586 /* RFC 1813, Page 46..48 */
2587 int
2588 dissect_nfs3_read_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2589 {
2590         offset = dissect_nfs_fh3(pd, offset, fd, tree, "file");
2591         offset = dissect_offset3(pd, offset, fd, tree, "offset");
2592         offset = dissect_count3 (pd, offset, fd, tree, "count");
2593
2594         return offset;
2595 }
2596
2597
2598 /* RFC 1813, Page 46..48 */
2599 int
2600 dissect_nfs3_read_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2601 {
2602         guint32 status;
2603
2604         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2605         switch (status) {
2606                 case 0:
2607                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2608                         offset = dissect_count3      (pd, offset, fd, tree, "count");
2609                         offset = dissect_rpc_bool    (pd, offset, fd, tree, hf_nfs_read_eof);
2610                         offset = dissect_nfsdata     (pd, offset, fd, tree, hf_nfs_data);
2611                 break;
2612                 default:
2613                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2614                 break;
2615         }
2616                 
2617         return offset;
2618 }
2619
2620
2621 /* RFC 1813, Page 49 */
2622 static const value_string names_stable_how[] = {
2623         {       UNSTABLE,  "UNSTABLE"  },
2624         {       DATA_SYNC, "DATA_SYNC" },
2625         {       FILE_SYNC, "FILE_SYNC" },
2626         { 0, NULL }
2627 };
2628
2629
2630 /* RFC 1813, Page 49 */
2631 int
2632 dissect_stable_how(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, int hfindex)
2633 {
2634         guint32 stable_how;
2635
2636         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2637         stable_how = EXTRACT_UINT(pd,offset+0);
2638         if (tree) {
2639                 proto_tree_add_uint(tree, hfindex, NullTVB,
2640                         offset, 4, stable_how); 
2641         }
2642         offset += 4;
2643
2644         return offset;
2645 }
2646
2647
2648 /* RFC 1813, Page 49..54 */
2649 int
2650 dissect_nfs3_write_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2651 {
2652         offset = dissect_nfs_fh3   (pd, offset, fd, tree, "file");
2653         offset = dissect_offset3   (pd, offset, fd, tree, "offset");
2654         offset = dissect_count3    (pd, offset, fd, tree, "count");
2655         offset = dissect_stable_how(pd, offset, fd, tree, hf_nfs_write_stable);
2656         offset = dissect_nfsdata   (pd, offset, fd, tree, hf_nfs_data);
2657
2658         return offset;
2659 }
2660
2661
2662 /* RFC 1813, Page 49..54 */
2663 int
2664 dissect_nfs3_write_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2665 {
2666         guint32 status;
2667
2668         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2669         switch (status) {
2670                 case 0:
2671                         offset = dissect_wcc_data  (pd, offset, fd, tree, "file_wcc");
2672                         offset = dissect_count3    (pd, offset, fd, tree, "count");
2673                         offset = dissect_stable_how(pd, offset, fd, tree, hf_nfs_write_committed);
2674                         offset = dissect_writeverf3(pd, offset, fd, tree);
2675                 break;
2676                 default:
2677                         offset = dissect_wcc_data(pd, offset, fd, tree, "file_wcc");
2678                 break;
2679         }
2680                 
2681         return offset;
2682 }
2683
2684
2685 /* RFC 1813, Page 54 */
2686 static const value_string names_createmode3[] = {
2687         {       UNCHECKED, "UNCHECKED" },
2688         {       GUARDED,   "GUARDED" },
2689         {       EXCLUSIVE, "EXCLUSIVE" },
2690         { 0, NULL }
2691 };
2692
2693
2694 /* RFC 1813, Page 54 */
2695 int
2696 dissect_createmode3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, guint32* mode)
2697 {
2698         guint32 mode_value;
2699         
2700         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
2701         mode_value = EXTRACT_UINT(pd, offset + 0);
2702         if (tree) {
2703                 proto_tree_add_uint(tree, hf_nfs_createmode3, NullTVB,
2704                 offset+0, 4, mode_value);
2705         }
2706         offset += 4;
2707
2708         *mode = mode_value;
2709         return offset;
2710 }
2711
2712
2713 /* RFC 1813, Page 54..58 */
2714 int
2715 dissect_nfs3_create_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2716 {
2717         guint32 mode;
2718
2719         offset = dissect_diropargs3 (pd, offset, fd, tree, "where");
2720         offset = dissect_createmode3(pd, offset, fd, tree, &mode);
2721         switch (mode) {
2722                 case UNCHECKED:
2723                 case GUARDED:
2724                         offset = dissect_sattr3     (pd, offset, fd, tree, "obj_attributes");
2725                 break;
2726                 case EXCLUSIVE:
2727                         offset = dissect_createverf3(pd, offset, fd, tree);
2728                 break;
2729         }
2730         
2731         return offset;
2732 }
2733
2734
2735 /* RFC 1813, Page 54..58 */
2736 int
2737 dissect_nfs3_create_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2738 {
2739         guint32 status;
2740
2741         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2742         switch (status) {
2743                 case 0:
2744                         offset = dissect_post_op_fh3 (pd, offset, fd, tree, "obj");
2745                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2746                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2747                 break;
2748                 default:
2749                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2750                 break;
2751         }
2752                 
2753         return offset;
2754 }
2755
2756
2757 /* RFC 1813, Page 58..60 */
2758 int
2759 dissect_nfs3_mkdir_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2760 {
2761         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2762         offset = dissect_sattr3    (pd, offset, fd, tree, "attributes");
2763         
2764         return offset;
2765 }
2766
2767
2768 /* RFC 1813, Page 61..63 */
2769 int
2770 dissect_nfs3_symlink_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2771 {
2772         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2773         offset = dissect_sattr3    (pd, offset, fd, tree, "symlink_attributes");
2774         offset = dissect_nfspath3  (pd, offset, fd, tree, hf_nfs_symlink_to);
2775         
2776         return offset;
2777 }
2778
2779
2780 /* RFC 1813, Page 63..66 */
2781 int
2782 dissect_nfs3_mknod_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2783 {
2784         guint32 type;
2785
2786         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2787         offset = dissect_ftype3(pd, offset, fd, tree, hf_nfs_ftype3, &type);
2788         switch (type) {
2789                 case NF3CHR:
2790                 case NF3BLK:
2791                         offset = dissect_sattr3(pd, offset, fd, tree, "dev_attributes");
2792                         offset = dissect_specdata3(pd, offset, fd, tree, "spec");
2793                 break;
2794                 case NF3SOCK:
2795                 case NF3FIFO:
2796                         offset = dissect_sattr3(pd, offset, fd, tree, "pipe_attributes");
2797                 break;
2798                 default:
2799                         /* nothing to do */
2800                 break;
2801         }
2802         
2803         return offset;
2804 }
2805
2806
2807 /* RFC 1813, Page 67..69 */
2808 int
2809 dissect_nfs3_remove_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2810 {
2811         guint32 status;
2812
2813         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2814         switch (status) {
2815                 case 0:
2816                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2817                 break;
2818                 default:
2819                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2820                 break;
2821         }
2822                 
2823         return offset;
2824 }
2825
2826
2827 /* RFC 1813, Page 71..74 */
2828 int
2829 dissect_nfs3_rename_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2830 {
2831         offset = dissect_diropargs3(pd, offset, fd, tree, "from");
2832         offset = dissect_diropargs3(pd, offset, fd, tree, "to");
2833         
2834         return offset;
2835 }
2836
2837
2838 /* RFC 1813, Page 71..74 */
2839 int
2840 dissect_nfs3_rename_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2841 {
2842         guint32 status;
2843
2844         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2845         switch (status) {
2846                 case 0:
2847                         offset = dissect_wcc_data(pd, offset, fd, tree, "fromdir_wcc");
2848                         offset = dissect_wcc_data(pd, offset, fd, tree, "todir_wcc");
2849                 break;
2850                 default:
2851                         offset = dissect_wcc_data(pd, offset, fd, tree, "fromdir_wcc");
2852                         offset = dissect_wcc_data(pd, offset, fd, tree, "todir_wcc");
2853                 break;
2854         }
2855                 
2856         return offset;
2857 }
2858
2859
2860 /* RFC 1813, Page 74..76 */
2861 int
2862 dissect_nfs3_link_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2863 {
2864         offset = dissect_nfs_fh3   (pd, offset, fd, tree, "file");
2865         offset = dissect_diropargs3(pd, offset, fd, tree, "link");
2866         
2867         return offset;
2868 }
2869
2870
2871 /* RFC 1813, Page 74..76 */
2872 int
2873 dissect_nfs3_link_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2874 {
2875         guint32 status;
2876
2877         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2878         switch (status) {
2879                 case 0:
2880                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2881                         offset = dissect_wcc_data    (pd, offset, fd, tree, "linkdir_wcc");
2882                 break;
2883                 default:
2884                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2885                         offset = dissect_wcc_data    (pd, offset, fd, tree, "linkdir_wcc");
2886                 break;
2887         }
2888                 
2889         return offset;
2890 }
2891
2892
2893 /* RFC 1813, Page 76..80 */
2894 int
2895 dissect_nfs3_readdir_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2896 {
2897         offset = dissect_nfs_fh3    (pd, offset, fd, tree, "dir");
2898         offset = dissect_cookie3    (pd, offset, fd, tree, "cookie");
2899         offset = dissect_cookieverf3(pd, offset, fd, tree);
2900         offset = dissect_count3     (pd, offset, fd, tree, "count");
2901         
2902         return offset;
2903 }
2904
2905
2906 /* RFC 1813, Page 76..80 */
2907 int
2908 dissect_entry3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2909 {
2910         proto_item* entry_item = NULL;
2911         proto_tree* entry_tree = NULL;
2912         int old_offset = offset;
2913         char *name;
2914
2915         if (tree) {
2916                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, NullTVB,
2917                         offset+0, END_OF_FRAME, FALSE);
2918                 if (entry_item)
2919                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
2920         }
2921
2922         offset = dissect_fileid3(pd, offset, fd, entry_tree, "fileid");
2923
2924         offset = dissect_filename3(pd, offset, fd, entry_tree,
2925                 hf_nfs_readdir_entry_name, &name);
2926         if (entry_item)
2927                 proto_item_set_text(entry_item, "Entry: name %s", name);
2928         g_free(name);
2929
2930         offset = dissect_cookie3(pd, offset, fd, entry_tree, "cookie");
2931
2932         /* now we know, that a readdir entry is shorter */
2933         if (entry_item) {
2934                 proto_item_set_len(entry_item, offset - old_offset);
2935         }
2936
2937         return offset;
2938 }
2939
2940
2941 /* RFC 1813, Page 76..80 */
2942 int
2943 dissect_nfs3_readdir_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2944 {
2945         guint32 status;
2946         guint32 eof_value;
2947
2948         offset = dissect_stat(pd, offset, fd, tree, &status);
2949         switch (status) {
2950                 case 0:
2951                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2952                         offset = dissect_cookieverf3(pd, offset, fd, tree);
2953                         offset = dissect_rpc_list(pd, offset, fd, tree,
2954                                 dissect_entry3);
2955                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2956                         eof_value = EXTRACT_UINT(pd, offset+0);
2957                         if (tree)
2958                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, NullTVB,
2959                                         offset+ 0, 4, eof_value);
2960                         offset += 4;
2961                 break;
2962                 default:
2963                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2964                 break;
2965         }
2966
2967         return offset;
2968 }
2969
2970
2971 /* RFC 1813, Page 80..83 */
2972 int
2973 dissect_nfs3_readdirplus_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2974 {
2975         offset = dissect_nfs_fh3    (pd, offset, fd, tree, "dir");
2976         offset = dissect_cookie3    (pd, offset, fd, tree, "cookie");
2977         offset = dissect_cookieverf3(pd, offset, fd, tree);
2978         offset = dissect_count3     (pd, offset, fd, tree, "dircount");
2979         offset = dissect_count3     (pd, offset, fd, tree, "maxcount");
2980         
2981         return offset;
2982 }
2983
2984
2985 /* RFC 1813, Page 80..83 */
2986 int
2987 dissect_entryplus3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2988 {
2989         proto_item* entry_item = NULL;
2990         proto_tree* entry_tree = NULL;
2991         int old_offset = offset;
2992         char *name;
2993
2994         if (tree) {
2995                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, NullTVB,
2996                         offset+0, END_OF_FRAME, FALSE);
2997                 if (entry_item)
2998                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
2999         }
3000
3001         offset = dissect_fileid3(pd, offset, fd, entry_tree, "fileid");
3002
3003         offset = dissect_filename3(pd, offset, fd, entry_tree,
3004                 hf_nfs_readdirplus_entry_name, &name);
3005         if (entry_item)
3006                 proto_item_set_text(entry_item, "Entry: name %s", name);
3007         g_free(name);
3008
3009         offset = dissect_cookie3(pd, offset, fd, entry_tree, "cookie");
3010
3011         offset = dissect_post_op_attr(pd, offset, fd, entry_tree, "name_attributes");
3012         offset = dissect_post_op_fh3(pd, offset, fd, entry_tree, "name_handle");
3013
3014         /* now we know, that a readdirplus entry is shorter */
3015         if (entry_item) {
3016                 proto_item_set_len(entry_item, offset - old_offset);
3017         }
3018
3019         return offset;
3020 }
3021
3022
3023 /* RFC 1813, Page 80..83 */
3024 int
3025 dissect_nfs3_readdirplus_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3026 {
3027         guint32 status;
3028         guint32 eof_value;
3029
3030         offset = dissect_stat(pd, offset, fd, tree, &status);
3031         switch (status) {
3032                 case 0:
3033                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
3034                         offset = dissect_cookieverf3(pd, offset, fd, tree);
3035                         offset = dissect_rpc_list(pd, offset, fd, tree,
3036                                 dissect_entryplus3);
3037                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3038                         eof_value = EXTRACT_UINT(pd, offset+0);
3039                         if (tree)
3040                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, NullTVB,
3041                                         offset+ 0, 4, eof_value);
3042                         offset += 4;
3043                 break;
3044                 default:
3045                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
3046                 break;
3047         }
3048
3049         return offset;
3050 }
3051
3052
3053 /* RFC 1813, Page 84..86 */
3054 int
3055 dissect_nfs3_fsstat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3056 {
3057         guint32 status;
3058         guint32 invarsec;
3059
3060         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3061         switch (status) {
3062                 case 0:
3063                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3064                         offset = dissect_size3 (pd, offset, fd, tree, "tbytes");
3065                         offset = dissect_size3 (pd, offset, fd, tree, "fbytes");
3066                         offset = dissect_size3 (pd, offset, fd, tree, "abytes");
3067                         offset = dissect_size3 (pd, offset, fd, tree, "tfiles");
3068                         offset = dissect_size3 (pd, offset, fd, tree, "ffiles");
3069                         offset = dissect_size3 (pd, offset, fd, tree, "afiles");
3070                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3071                         invarsec = EXTRACT_UINT(pd, offset + 0);
3072                         if (tree)
3073                                 proto_tree_add_uint(tree, hf_nfs_fsstat_invarsec, NullTVB,
3074                                 offset+0, 4, invarsec);
3075                         offset += 4;
3076                 break;
3077                 default:
3078                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3079                 break;
3080         }
3081
3082         return offset;
3083 }
3084
3085
3086 #define FSF3_LINK        0x0001
3087 #define FSF3_SYMLINK     0x0002
3088 #define FSF3_HOMOGENEOUS 0x0008
3089 #define FSF3_CANSETTIME  0x0010
3090
3091
3092 /* RFC 1813, Page 86..90 */
3093 int
3094 dissect_nfs3_fsinfo_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3095 {
3096         guint32 status;
3097         guint32 rtmax;
3098         guint32 rtpref;
3099         guint32 rtmult;
3100         guint32 wtmax;
3101         guint32 wtpref;
3102         guint32 wtmult;
3103         guint32 dtpref;
3104         guint32 properties;
3105         proto_item*     properties_item = NULL;
3106         proto_tree*     properties_tree = NULL;
3107
3108         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3109         switch (status) {
3110                 case 0:
3111                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3112                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3113                         rtmax = EXTRACT_UINT(pd, offset+0);
3114                         if (tree)
3115                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtmax, NullTVB,
3116                                 offset+0, 4, rtmax);
3117                         offset += 4;
3118                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3119                         rtpref = EXTRACT_UINT(pd, offset+0);
3120                         if (tree)
3121                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtpref, NullTVB,
3122                                 offset+0, 4, rtpref);
3123                         offset += 4;
3124                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3125                         rtmult = EXTRACT_UINT(pd, offset+0);
3126                         if (tree)
3127                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtmult, NullTVB,
3128                                 offset+0, 4, rtmult);
3129                         offset += 4;
3130                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3131                         wtmax = EXTRACT_UINT(pd, offset+0);
3132                         if (tree)
3133                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtmax, NullTVB,
3134                                 offset+0, 4, wtmax);
3135                         offset += 4;
3136                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3137                         wtpref = EXTRACT_UINT(pd, offset+0);
3138                         if (tree)
3139                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtpref, NullTVB,
3140                                 offset+0, 4, wtpref);
3141                         offset += 4;
3142                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3143                         wtmult = EXTRACT_UINT(pd, offset+0);
3144                         if (tree)
3145                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtmult, NullTVB,
3146                                 offset+0, 4, wtmult);
3147                         offset += 4;
3148                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3149                         dtpref = EXTRACT_UINT(pd, offset+0);
3150                         if (tree)
3151                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_dtpref, NullTVB,
3152                                 offset+0, 4, dtpref);
3153                         offset += 4;
3154
3155                         offset = dissect_size3   (pd, offset, fd, tree, "maxfilesize");
3156                         offset = dissect_nfstime3(pd, offset, fd, tree, "time_delta");
3157                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3158                         properties = EXTRACT_UINT(pd, offset+0);
3159                         if (tree) {
3160                                 properties_item = proto_tree_add_uint(tree,
3161                                 hf_nfs_fsinfo_properties,
3162                                 NullTVB, offset+0, 4, properties);
3163                                 if (properties_item) 
3164                                         properties_tree = proto_item_add_subtree(properties_item, ett_nfs_fsinfo_properties);
3165                                 if (properties_tree) {
3166                                         proto_tree_add_text(properties_tree, NullTVB,
3167                                         offset, 4, "%s",
3168                                         decode_boolean_bitfield(properties,
3169                                         FSF3_CANSETTIME,5,
3170                                         "SETATTR can set time on server",
3171                                         "SETATTR can't set time on server"));
3172
3173                                         proto_tree_add_text(properties_tree, NullTVB,
3174                                         offset, 4, "%s",
3175                                         decode_boolean_bitfield(properties,
3176                                         FSF3_HOMOGENEOUS,5,
3177                                         "PATHCONF is valid for all files",
3178                                         "PATHCONF should be get for every single file"));
3179
3180                                         proto_tree_add_text(properties_tree, NullTVB,
3181                                         offset, 4, "%s",
3182                                         decode_boolean_bitfield(properties,
3183                                         FSF3_SYMLINK,5,
3184                                         "File System supports symbolic links",
3185                                         "File System does not symbolic hard links"));
3186
3187                                         proto_tree_add_text(properties_tree, NullTVB,
3188                                         offset, 4, "%s",
3189                                         decode_boolean_bitfield(properties,
3190                                         FSF3_LINK,5,
3191                                         "File System supports hard links",
3192                                         "File System does not support hard links"));
3193                                 }
3194                         }
3195                         offset += 4;
3196                 break;
3197                 default:
3198                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3199                 break;
3200         }
3201
3202         return offset;
3203 }
3204
3205
3206 /* RFC 1813, Page 90..92 */
3207 int
3208 dissect_nfs3_pathconf_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3209 {
3210         guint32 status;
3211         guint32 linkmax;
3212         guint32 name_max;
3213
3214         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3215         switch (status) {
3216                 case 0:
3217                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3218                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3219                         linkmax = EXTRACT_UINT(pd, offset + 0);
3220                         if (tree)
3221                                 proto_tree_add_uint(tree, hf_nfs_pathconf_linkmax, NullTVB,
3222                                 offset+0, 4, linkmax);
3223                         offset += 4;
3224                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3225                         name_max = EXTRACT_UINT(pd, offset + 0);
3226                         if (tree)
3227                                 proto_tree_add_uint(tree, hf_nfs_pathconf_name_max, NullTVB,
3228                                 offset+0, 4, name_max);
3229                         offset += 4;
3230                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_no_trunc);
3231                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_chown_restricted);
3232                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_case_insensitive);
3233                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_case_preserving);
3234                 break;
3235                 default:
3236                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3237                 break;
3238         }
3239
3240         return offset;
3241 }
3242
3243
3244 /* RFC 1813, Page 92..95 */
3245 int
3246 dissect_nfs3_commit_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3247 {
3248         offset = dissect_nfs_fh3(pd, offset, fd, tree, "file");
3249         offset = dissect_offset3(pd, offset, fd, tree, "offset");
3250         offset = dissect_count3 (pd, offset, fd, tree, "count");
3251         
3252         return offset;
3253 }
3254
3255
3256 /* RFC 1813, Page 92..95 */
3257 int
3258 dissect_nfs3_commit_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3259 {
3260         guint32 status;
3261
3262         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3263         switch (status) {
3264                 case 0:
3265                         offset = dissect_wcc_data  (pd, offset, fd, tree, "file_wcc");
3266                         offset = dissect_writeverf3(pd, offset, fd, tree);
3267                 break;
3268                 default:
3269                         offset = dissect_wcc_data(pd, offset, fd, tree, "file_wcc");
3270                 break;
3271         }
3272                 
3273         return offset;
3274 }
3275
3276
3277 /* 1 missing functions */
3278
3279
3280 /* proc number, "proc name", dissect_request, dissect_reply */
3281 /* NULL as function pointer means: take the generic one. */
3282 const vsff nfs3_proc[] = {
3283         { 0,    "NULL",         /* OK */
3284         NULL,                           NULL },
3285         { 1,    "GETATTR",      /* OK */
3286         dissect_nfs3_getattr_call,      dissect_nfs3_getattr_reply },
3287         { 2,    "SETATTR",      /* OK */
3288         dissect_nfs3_setattr_call,      dissect_nfs3_setattr_reply },
3289         { 3,    "LOOKUP",       /* OK */
3290         dissect_nfs3_lookup_call,       dissect_nfs3_lookup_reply },
3291         { 4,    "ACCESS",       /* OK */
3292         dissect_nfs3_access_call,       dissect_nfs3_access_reply },
3293         { 5,    "READLINK",     /* OK */
3294         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_readlink_reply },
3295         { 6,    "READ",         /* OK */
3296         dissect_nfs3_read_call,         dissect_nfs3_read_reply },
3297         { 7,    "WRITE",        /* OK */
3298         dissect_nfs3_write_call,        dissect_nfs3_write_reply },
3299         { 8,    "CREATE",       /* OK */
3300         dissect_nfs3_create_call,       dissect_nfs3_create_reply },
3301         { 9,    "MKDIR",        /* OK */
3302         dissect_nfs3_mkdir_call,        dissect_nfs3_create_reply },
3303         { 10,   "SYMLINK",      /* OK */
3304         dissect_nfs3_symlink_call,      dissect_nfs3_create_reply },
3305         { 11,   "MKNOD",        /* OK */
3306         dissect_nfs3_mknod_call,        dissect_nfs3_create_reply },
3307         { 12,   "REMOVE",       /* OK */
3308         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
3309         { 13,   "RMDIR",        /* OK */
3310         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
3311         { 14,   "RENAME",       /* OK */
3312         dissect_nfs3_rename_call,       dissect_nfs3_rename_reply },
3313         { 15,   "LINK",         /* OK */
3314         dissect_nfs3_link_call,         dissect_nfs3_link_reply },
3315         { 16,   "READDIR",      /* OK */
3316         dissect_nfs3_readdir_call,      dissect_nfs3_readdir_reply },
3317         { 17,   "READDIRPLUS",  /* OK */
3318         dissect_nfs3_readdirplus_call,  dissect_nfs3_readdirplus_reply },
3319         { 18,   "FSSTAT",       /* OK */
3320         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsstat_reply },
3321         { 19,   "FSINFO",       /* OK */
3322         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsinfo_reply },
3323         { 20,   "PATHCONF",     /* OK */
3324         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_pathconf_reply },
3325         { 21,   "COMMIT",       /* OK */
3326         dissect_nfs3_commit_call,       dissect_nfs3_commit_reply },
3327         { 0,NULL,NULL,NULL }
3328 };
3329 /* end of NFS Version 3 */
3330
3331
3332 static struct true_false_string yesno = { "Yes", "No" };
3333
3334
3335 void
3336 proto_register_nfs(void)
3337 {
3338         static hf_register_info hf[] = {
3339                 { &hf_nfs_fh_fsid_major, {
3340                         "major", "nfs.fh.fsid.major", FT_UINT32, BASE_DEC,
3341                         NULL, 0, "major file system ID" }},
3342                 { &hf_nfs_fh_fsid_minor, {
3343                         "minor", "nfs.fh.fsid.minor", FT_UINT32, BASE_DEC,
3344                         NULL, 0, "minor file system ID" }},
3345                 { &hf_nfs_fh_xfsid_major, {
3346                         "exported major", "nfs.fh.xfsid.major", FT_UINT32, BASE_DEC,
3347                         NULL, 0, "exported major file system ID" }},
3348                 { &hf_nfs_fh_xfsid_minor, {
3349                         "exported minor", "nfs.fh.xfsid.minor", FT_UINT32, BASE_DEC,
3350                         NULL, 0, "exported minor file system ID" }},
3351                 { &hf_nfs_fh_fstype, {
3352                         "file system type", "nfs.fh.fstype", FT_UINT32, BASE_DEC,
3353                         NULL, 0, "file system type" }},
3354                 { &hf_nfs_fh_fn, {
3355                         "file number", "nfs.fh.fn", FT_UINT32, BASE_DEC,
3356                         NULL, 0, "file number" }},
3357                 { &hf_nfs_fh_fn_len, {
3358                         "length", "nfs.fh.fn.len", FT_UINT32, BASE_DEC,
3359                         NULL, 0, "file number length" }},
3360                 { &hf_nfs_fh_fn_inode, {
3361                         "inode", "nfs.fh.fn.inode", FT_UINT32, BASE_DEC,
3362                         NULL, 0, "file number inode" }},
3363                 { &hf_nfs_fh_fn_generation, {
3364                         "generation", "nfs.fh.fn.generation", FT_UINT32, BASE_DEC,
3365                         NULL, 0, "file number generation" }},
3366                 { &hf_nfs_fh_xfn, {
3367                         "exported file number", "nfs.fh.xfn", FT_UINT32, BASE_DEC,
3368                         NULL, 0, "exported file number" }},
3369                 { &hf_nfs_fh_xfn_len, {
3370                         "length", "nfs.fh.xfn.len", FT_UINT32, BASE_DEC,
3371                         NULL, 0, "exported file number length" }},
3372                 { &hf_nfs_fh_xfn_inode, {
3373                         "exported inode", "nfs.fh.xfn.inode", FT_UINT32, BASE_DEC,
3374                         NULL, 0, "exported file number inode" }},
3375                 { &hf_nfs_fh_xfn_generation, {
3376                         "generation", "nfs.fh.xfn.generation", FT_UINT32, BASE_DEC,
3377                         NULL, 0, "exported file number generation" }},
3378                 { &hf_nfs_fh_dentry, {
3379                         "dentry", "nfs.fh.dentry", FT_UINT32, BASE_HEX,
3380                         NULL, 0, "dentry (cookie)" }},
3381                 { &hf_nfs_fh_dev, {
3382                         "device", "nfs.fh.dev", FT_UINT32, BASE_DEC,
3383                         NULL, 0, "device" }},
3384                 { &hf_nfs_fh_xdev, {
3385                         "exported device", "nfs.fh.xdev", FT_UINT32, BASE_DEC,
3386                         NULL, 0, "exported device" }},
3387                 { &hf_nfs_fh_dirinode, {
3388                         "directory inode", "nfs.fh.dirinode", FT_UINT32, BASE_DEC,
3389                         NULL, 0, "directory inode" }},
3390                 { &hf_nfs_fh_pinode, {
3391                         "pseudo inode", "nfs.fh.pinode", FT_UINT32, BASE_HEX,
3392                         NULL, 0, "pseudo inode" }},
3393                 { &hf_nfs_fh_hp_len, {
3394                         "length", "nfs.fh.hp.len", FT_UINT32, BASE_DEC,
3395                         NULL, 0, "hash path length" }},
3396                 { &hf_nfs_stat, {
3397                         "Status", "nfs.status2", FT_UINT32, BASE_DEC,
3398                         VALS(names_nfs_stat), 0, "Reply status" }},
3399                 { &hf_nfs_name, {
3400                         "Name", "nfs.name", FT_STRING, BASE_DEC,
3401                         NULL, 0, "Name" }},
3402                 { &hf_nfs_readlink_data, {
3403                         "Data", "nfs.readlink.data", FT_STRING, BASE_DEC,
3404                         NULL, 0, "Symbolic Link Data" }},
3405                 { &hf_nfs_read_offset, {
3406                         "Offset", "nfs.read.offset", FT_UINT32, BASE_DEC,
3407                         NULL, 0, "Read Offset" }},
3408                 { &hf_nfs_read_count, {
3409                         "Count", "nfs.read.count", FT_UINT32, BASE_DEC,
3410                         NULL, 0, "Read Count" }},
3411                 { &hf_nfs_read_totalcount, {
3412                         "Total Count", "nfs.read.totalcount", FT_UINT32, BASE_DEC,
3413                         NULL, 0, "Total Count (obsolete)" }},
3414                 { &hf_nfs_data, {
3415                         "Data", "nfs.data", FT_STRING, BASE_DEC,
3416                         NULL, 0, "Data" }},
3417                 { &hf_nfs_write_beginoffset, {
3418                         "Begin Offset", "nfs.write.beginoffset", FT_UINT32, BASE_DEC,
3419                         NULL, 0, "Begin offset (obsolete)" }},
3420                 { &hf_nfs_write_offset, {
3421                         "Offset", "nfs.write.offset", FT_UINT32, BASE_DEC,
3422                         NULL, 0, "Offset" }},
3423                 { &hf_nfs_write_totalcount, {
3424                         "Total Count", "nfs.write.totalcount", FT_UINT32, BASE_DEC,
3425                         NULL, 0, "Total Count (obsolete)" }},
3426                 { &hf_nfs_symlink_to, {
3427                         "To", "nfs.symlink.to", FT_STRING, BASE_DEC,
3428                         NULL, 0, "Symbolic link destination name" }},
3429                 { &hf_nfs_readdir_cookie, {
3430                         "Cookie", "nfs.readdir.cookie", FT_UINT32, BASE_DEC,
3431                         NULL, 0, "Directory Cookie" }},
3432                 { &hf_nfs_readdir_count, {
3433                         "Count", "nfs.readdir.count", FT_UINT32, BASE_DEC,
3434                         NULL, 0, "Directory Count" }},
3435                 { &hf_nfs_readdir_entry, {
3436                         "Entry", "nfs.readdir.entry", FT_NONE, 0,
3437                         NULL, 0, "Directory Entry" }},
3438                 { &hf_nfs_readdir_entry_fileid, {
3439                         "File ID", "nfs.readdir.entry.fileid", FT_UINT32, BASE_DEC,
3440                         NULL, 0, "File ID" }},
3441                 { &hf_nfs_readdir_entry_name, {
3442                         "Name", "nfs.readdir.entry.name", FT_STRING, BASE_DEC,
3443                         NULL, 0, "Name" }},
3444                 { &hf_nfs_readdirplus_entry_name, {
3445                         "Name", "nfs.readdirplus.entry.name", FT_STRING, BASE_DEC,
3446                         NULL, 0, "Name" }},
3447                 { &hf_nfs_readdir_entry_cookie, {
3448                         "Cookie", "nfs.readdir.entry.cookie", FT_UINT32, BASE_DEC,
3449                         NULL, 0, "Directory Cookie" }},
3450                 { &hf_nfs_readdir_eof, {
3451                         "EOF", "nfs.readdir.eof", FT_UINT32, BASE_DEC,
3452                         NULL, 0, "EOF" }},
3453                 { &hf_nfs_statfs_tsize, {
3454                         "Transfer Size", "nfs.statfs.tsize", FT_UINT32, BASE_DEC,
3455                         NULL, 0, "Transfer Size" }},
3456                 { &hf_nfs_statfs_bsize, {
3457                         "Block Size", "nfs.statfs.bsize", FT_UINT32, BASE_DEC,
3458                         NULL, 0, "Block Size" }},
3459                 { &hf_nfs_statfs_blocks, {
3460                         "Total Blocks", "nfs.statfs.blocks", FT_UINT32, BASE_DEC,
3461                         NULL, 0, "Total Blocks" }},
3462                 { &hf_nfs_statfs_bfree, {
3463                         "Free Blocks", "nfs.statfs.bfree", FT_UINT32, BASE_DEC,
3464                         NULL, 0, "Free Blocks" }},
3465                 { &hf_nfs_statfs_bavail, {
3466                         "Available Blocks", "nfs.statfs.bavail", FT_UINT32, BASE_DEC,
3467                         NULL, 0, "Available Blocks" }},
3468                 { &hf_nfs_ftype3, {
3469                         "Type", "nfs.type", FT_UINT32, BASE_DEC,
3470                         VALS(names_nfs_ftype3), 0, "File Type" }},
3471                 { &hf_nfs_nfsstat3, {
3472                         "Status", "nfs.status", FT_UINT32, BASE_DEC,
3473                         VALS(names_nfs_nfsstat3), 0, "Reply status" }},
3474                 { &hf_nfs_read_eof, {
3475                         "EOF", "nfs.read.eof", FT_BOOLEAN, BASE_NONE,
3476                         &yesno, 0, "EOF" }},
3477                 { &hf_nfs_write_stable, {
3478                         "Stable", "nfs.write.stable", FT_UINT32, BASE_DEC,
3479                         VALS(names_stable_how), 0, "Stable" }},
3480                 { &hf_nfs_write_committed, {
3481                         "Committed", "nfs.write.committed", FT_UINT32, BASE_DEC,
3482                         VALS(names_stable_how), 0, "Committed" }},
3483                 { &hf_nfs_createmode3, {
3484                         "Create Mode", "nfs.createmode", FT_UINT32, BASE_DEC,
3485                         VALS(names_createmode3), 0, "Create Mode" }},
3486                 { &hf_nfs_fsstat_invarsec, {
3487                         "invarsec", "nfs.fsstat.invarsec", FT_UINT32, BASE_DEC,
3488                         NULL, 0, "probable number of seconds of file system invariance" }},
3489                 { &hf_nfs_fsinfo_rtmax, {
3490                         "rtmax", "nfs.fsinfo.rtmax", FT_UINT32, BASE_DEC,
3491                         NULL, 0, "maximum READ request" }},
3492                 { &hf_nfs_fsinfo_rtpref, {
3493                         "rtpref", "nfs.fsinfo.rtpref", FT_UINT32, BASE_DEC,
3494                         NULL, 0, "preferred READ request" }},
3495                 { &hf_nfs_fsinfo_rtmult, {
3496                         "rtmult", "nfs.fsinfo.rtmult", FT_UINT32, BASE_DEC,
3497                         NULL, 0, "suggested READ multiple" }},
3498                 { &hf_nfs_fsinfo_wtmax, {
3499                         "wtmax", "nfs.fsinfo.wtmax", FT_UINT32, BASE_DEC,
3500                         NULL, 0, "maximum WRITE request" }},
3501                 { &hf_nfs_fsinfo_wtpref, {
3502                         "wtpref", "nfs.fsinfo.wtpref", FT_UINT32, BASE_DEC,
3503                         NULL, 0, "preferred WRITE request" }},
3504                 { &hf_nfs_fsinfo_wtmult, {
3505                         "wtmult", "nfs.fsinfo.wtmult", FT_UINT32, BASE_DEC,
3506                         NULL, 0, "suggested WRITE multiple" }},
3507                 { &hf_nfs_fsinfo_dtpref, {
3508                         "dtpref", "nfs.fsinfo.dtpref", FT_UINT32, BASE_DEC,
3509                         NULL, 0, "preferred READDIR request" }},
3510                 { &hf_nfs_fsinfo_properties, {
3511                         "Properties", "nfs.fsinfo.propeties", FT_UINT32, BASE_HEX,
3512                         NULL, 0, "File System Properties" }},
3513                 { &hf_nfs_pathconf_linkmax, {
3514                         "linkmax", "nfs.pathconf.linkmax", FT_UINT32, BASE_DEC,
3515                         NULL, 0, "Maximum number of hard links" }},
3516                 { &hf_nfs_pathconf_name_max, {
3517                         "name_max", "nfs.pathconf.name_max", FT_UINT32, BASE_DEC,
3518                         NULL, 0, "Maximum file name length" }},
3519                 { &hf_nfs_pathconf_no_trunc, {
3520                         "no_trunc", "nfs.pathconf.no_trunc", FT_BOOLEAN, BASE_NONE,
3521                         &yesno, 0, "No long file name truncation" }},
3522                 { &hf_nfs_pathconf_chown_restricted, {
3523                         "chown_restricted", "nfs.pathconf.chown_restricted", FT_BOOLEAN, BASE_NONE,
3524                         &yesno, 0, "chown is restricted to root" }},
3525                 { &hf_nfs_pathconf_case_insensitive, {
3526                         "case_insensitive", "nfs.pathconf.case_insensitive", FT_BOOLEAN, BASE_NONE,
3527                         &yesno, 0, "file names are treated case insensitive" }},
3528                 { &hf_nfs_pathconf_case_preserving, {
3529                         "case_preserving", "nfs.pathconf.case_preserving", FT_BOOLEAN, BASE_NONE,
3530                         &yesno, 0, "file name cases are preserved" }}
3531         };
3532
3533         static gint *ett[] = {
3534                 &ett_nfs,
3535                 &ett_nfs_fh_fsid,
3536                 &ett_nfs_fh_xfsid,
3537                 &ett_nfs_fh_fn,
3538                 &ett_nfs_fh_xfn,
3539                 &ett_nfs_fh_hp,
3540                 &ett_nfs_fhandle,
3541                 &ett_nfs_timeval,
3542                 &ett_nfs_mode,
3543                 &ett_nfs_fattr,
3544                 &ett_nfs_sattr,
3545                 &ett_nfs_diropargs,
3546                 &ett_nfs_readdir_entry,
3547                 &ett_nfs_mode3,
3548                 &ett_nfs_specdata3,
3549                 &ett_nfs_fh3,
3550                 &ett_nfs_nfstime3,
3551                 &ett_nfs_fattr3,
3552                 &ett_nfs_post_op_fh3,
3553                 &ett_nfs_sattr3,
3554                 &ett_nfs_diropargs3,
3555                 &ett_nfs_sattrguard3,
3556                 &ett_nfs_set_mode3,
3557                 &ett_nfs_set_uid3,
3558                 &ett_nfs_set_gid3,
3559                 &ett_nfs_set_size3,
3560                 &ett_nfs_set_atime,
3561                 &ett_nfs_set_mtime,
3562                 &ett_nfs_pre_op_attr,
3563                 &ett_nfs_post_op_attr,
3564                 &ett_nfs_wcc_attr,
3565                 &ett_nfs_wcc_data,
3566                 &ett_nfs_access,
3567                 &ett_nfs_fsinfo_properties
3568         };
3569         proto_nfs = proto_register_protocol("Network File System", "nfs");
3570         proto_register_field_array(proto_nfs, hf, array_length(hf));
3571         proto_register_subtree_array(ett, array_length(ett));
3572 }
3573
3574 void
3575 proto_reg_handoff_nfs(void)
3576 {
3577         /* Register the protocol as RPC */
3578         rpc_init_prog(proto_nfs, NFS_PROGRAM, ett_nfs);
3579         /* Register the procedure tables */
3580         rpc_init_proc_table(NFS_PROGRAM, 2, nfs2_proc);
3581         rpc_init_proc_table(NFS_PROGRAM, 3, nfs3_proc);
3582 }