Don't call "register_all_plugin_handoffs()" if we don't have plugin
[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  * Copyright 2000, Mike Frisch <frisch@hummingbird.com> (NFSv4 decoding)
5  *
6  * $Id: packet-nfs.c,v 1.50 2001/03/09 04:35:22 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * Copied from packet-smb.c
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37
38 #include <string.h>
39
40
41 #include "packet-rpc.h"
42 #include "packet-nfs.h"
43
44
45 static int proto_nfs = -1;
46
47 static int hf_nfs_fh_fsid_major = -1;
48 static int hf_nfs_fh_fsid_minor = -1;
49 static int hf_nfs_fh_xfsid_major = -1;
50 static int hf_nfs_fh_xfsid_minor = -1;
51 static int hf_nfs_fh_fstype = -1;
52 static int hf_nfs_fh_fn = -1;
53 static int hf_nfs_fh_fn_len = -1;
54 static int hf_nfs_fh_fn_inode = -1;
55 static int hf_nfs_fh_fn_generation = -1;
56 static int hf_nfs_fh_xfn = -1;
57 static int hf_nfs_fh_xfn_len = -1;
58 static int hf_nfs_fh_xfn_inode = -1;
59 static int hf_nfs_fh_xfn_generation = -1;
60 static int hf_nfs_fh_dentry = -1;
61 static int hf_nfs_fh_dev = -1;
62 static int hf_nfs_fh_xdev = -1;
63 static int hf_nfs_fh_dirinode = -1;
64 static int hf_nfs_fh_pinode = -1;
65 static int hf_nfs_fh_hp_len = -1;
66 static int hf_nfs_stat = -1;
67 static int hf_nfs_name = -1;
68 static int hf_nfs_readlink_data = -1;
69 static int hf_nfs_read_offset = -1;
70 static int hf_nfs_read_count = -1;
71 static int hf_nfs_read_totalcount = -1;
72 static int hf_nfs_data = -1;
73 static int hf_nfs_write_beginoffset = -1;
74 static int hf_nfs_write_offset = -1;
75 static int hf_nfs_write_totalcount = -1;
76 static int hf_nfs_symlink_to = -1;
77 static int hf_nfs_readdir_cookie = -1;
78 static int hf_nfs_readdir_count = -1;
79 static int hf_nfs_readdir_entry = -1;
80 static int hf_nfs_readdir_entry_fileid = -1;
81 static int hf_nfs_readdir_entry_name = -1;
82 static int hf_nfs_readdirplus_entry_name = -1;
83 static int hf_nfs_readdir_entry_cookie = -1;
84 static int hf_nfs_readdir_eof = -1;
85 static int hf_nfs_statfs_tsize = -1;
86 static int hf_nfs_statfs_bsize = -1;
87 static int hf_nfs_statfs_blocks = -1;
88 static int hf_nfs_statfs_bfree = -1;
89 static int hf_nfs_statfs_bavail = -1;
90 static int hf_nfs_ftype3 = -1;
91 static int hf_nfs_nfsstat3 = -1;
92 static int hf_nfs_read_eof = -1;
93 static int hf_nfs_write_stable = -1;
94 static int hf_nfs_write_committed = -1;
95 static int hf_nfs_createmode3 = -1;
96 static int hf_nfs_fsstat_invarsec = -1;
97 static int hf_nfs_fsinfo_rtmax = -1;
98 static int hf_nfs_fsinfo_rtpref = -1;
99 static int hf_nfs_fsinfo_rtmult = -1;
100 static int hf_nfs_fsinfo_wtmax = -1;
101 static int hf_nfs_fsinfo_wtpref = -1;
102 static int hf_nfs_fsinfo_wtmult = -1;
103 static int hf_nfs_fsinfo_dtpref = -1;
104 static int hf_nfs_fsinfo_properties = -1;
105 static int hf_nfs_pathconf_linkmax = -1;
106 static int hf_nfs_pathconf_name_max = -1;
107 static int hf_nfs_pathconf_no_trunc = -1;
108 static int hf_nfs_pathconf_chown_restricted = -1;
109 static int hf_nfs_pathconf_case_insensitive = -1;
110 static int hf_nfs_pathconf_case_preserving = -1;
111 static int hf_nfs_data_follows = -1;
112
113 /* NFSv4 */
114 static int hf_nfs_argop4 = -1;
115 static int hf_nfs_resop4 = -1;
116 static int hf_nfs_linktext4 = -1;
117 static int hf_nfs_tag4 = -1;
118 static int hf_nfs_component4 = -1;
119 static int hf_nfs_clientid4 = -1;
120 static int hf_nfs_ace4 = -1;
121 static int hf_nfs_recall = -1;
122 static int hf_nfs_open_claim_type4 = -1;
123 static int hf_nfs_opentype4 = -1;
124 static int hf_nfs_limit_by4 = -1;
125 static int hf_nfs_open_delegation_type4 = -1;
126 static int hf_nfs_ftype4 = -1;
127 static int hf_nfs_change_info4_atomic = -1;
128 static int hf_nfs_open4_share_access = -1;
129 static int hf_nfs_open4_share_deny = -1;
130 static int hf_nfs_seqid4 = -1;
131 static int hf_nfs_mand_attr = -1;
132 static int hf_nfs_recc_attr = -1;
133 static int hf_nfs_time_how4 = -1;
134 static int hf_nfs_attrlist4 = -1;
135 static int hf_nfs_fattr4_expire_type = -1;
136 static int hf_nfs_fattr4_link_support = -1;
137 static int hf_nfs_fattr4_symlink_support = -1;
138 static int hf_nfs_fattr4_named_attr = -1;
139 static int hf_nfs_fattr4_unique_handles = -1;
140 static int hf_nfs_fattr4_archive = -1;
141 static int hf_nfs_fattr4_cansettime = -1;
142 static int hf_nfs_fattr4_case_insensitive = -1;
143 static int hf_nfs_fattr4_case_preserving = -1;
144 static int hf_nfs_fattr4_chown_restricted = -1;
145 static int hf_nfs_fattr4_hidden = -1;
146 static int hf_nfs_fattr4_homogeneous = -1;
147 static int hf_nfs_fattr4_mimetype = -1;
148 static int hf_nfs_fattr4_no_trunc = -1;
149 static int hf_nfs_fattr4_system = -1;
150 static int hf_nfs_who = -1;
151 static int hf_nfs_server = -1;
152 static int hf_nfs_fattr4_owner = -1;
153 static int hf_nfs_fattr4_owner_group = -1;
154 static int hf_nfs_stable_how4 = -1;
155 static int hf_nfs_dirlist4_eof = -1;
156
157 static gint ett_nfs = -1;
158 static gint ett_nfs_fh_fsid = -1;
159 static gint ett_nfs_fh_xfsid = -1;
160 static gint ett_nfs_fh_fn = -1;
161 static gint ett_nfs_fh_xfn = -1;
162 static gint ett_nfs_fh_hp = -1;
163 static gint ett_nfs_fhandle = -1;
164 static gint ett_nfs_timeval = -1;
165 static gint ett_nfs_mode = -1;
166 static gint ett_nfs_fattr = -1;
167 static gint ett_nfs_sattr = -1;
168 static gint ett_nfs_diropargs = -1;
169 static gint ett_nfs_readdir_entry = -1;
170 static gint ett_nfs_mode3 = -1;
171 static gint ett_nfs_specdata3 = -1;
172 static gint ett_nfs_fh3 = -1;
173 static gint ett_nfs_nfstime3 = -1;
174 static gint ett_nfs_fattr3 = -1;
175 static gint ett_nfs_post_op_fh3 = -1;
176 static gint ett_nfs_sattr3 = -1;
177 static gint ett_nfs_diropargs3 = -1;
178 static gint ett_nfs_sattrguard3 = -1;
179 static gint ett_nfs_set_mode3 = -1;
180 static gint ett_nfs_set_uid3 = -1;
181 static gint ett_nfs_set_gid3 = -1;
182 static gint ett_nfs_set_size3 = -1;
183 static gint ett_nfs_set_atime = -1;
184 static gint ett_nfs_set_mtime = -1;
185 static gint ett_nfs_pre_op_attr = -1;
186 static gint ett_nfs_post_op_attr = -1;
187 static gint ett_nfs_wcc_attr = -1;
188 static gint ett_nfs_wcc_data = -1;
189 static gint ett_nfs_access = -1;
190 static gint ett_nfs_fsinfo_properties = -1;
191
192 /* NFSv4 */
193 static gint ett_nfs_compound_call4 = -1;
194 static gint ett_nfs_utf8string = -1;
195 static gint ett_nfs_argop4 = -1;
196 static gint ett_nfs_resop4 = -1;
197 static gint ett_nfs_access4 = -1;
198 static gint ett_nfs_close4 = -1;
199 static gint ett_nfs_commit4 = -1;
200 static gint ett_nfs_create4 = -1;
201 static gint ett_nfs_delegpurge4 = -1;
202 static gint ett_nfs_delegreturn4 = -1;
203 static gint ett_nfs_getattr4 = -1;
204 static gint ett_nfs_getfh4 = -1;
205 static gint ett_nfs_link4 = -1;
206 static gint ett_nfs_lock4 = -1;
207 static gint ett_nfs_lockt4 = -1;
208 static gint ett_nfs_locku4 = -1;
209 static gint ett_nfs_lookup4 = -1;
210 static gint ett_nfs_lookupp4 = -1;
211 static gint ett_nfs_nverify4 = -1;
212 static gint ett_nfs_open4 = -1;
213 static gint ett_nfs_openattr4 = -1;
214 static gint ett_nfs_open_confirm4 = -1;
215 static gint ett_nfs_open_downgrade4 = -1;
216 static gint ett_nfs_putfh4 = -1;
217 static gint ett_nfs_putpubfh4 = -1;
218 static gint ett_nfs_putrootfh4 = -1;
219 static gint ett_nfs_read4 = -1;
220 static gint ett_nfs_readdir4 = -1;
221 static gint ett_nfs_readlink4 = -1;
222 static gint ett_nfs_remove4 = -1;
223 static gint ett_nfs_rename4 = -1;
224 static gint ett_nfs_renew4 = -1;
225 static gint ett_nfs_restorefh4 = -1;
226 static gint ett_nfs_savefh4 = -1;
227 static gint ett_nfs_secinfo4 = -1;
228 static gint ett_nfs_setattr4 = -1;
229 static gint ett_nfs_setclientid4 = -1;
230 static gint ett_nfs_setclientid_confirm4 = -1;
231 static gint ett_nfs_verify4 = -1;
232 static gint ett_nfs_write4 = -1;
233 static gint ett_nfs_verifier4 = -1;
234 static gint ett_nfs_opaque = -1;
235 static gint ett_nfs_dirlist4 = -1;
236 static gint ett_nfs_pathname4 = -1;
237 static gint ett_nfs_change_info4 = -1;
238 static gint ett_nfs_open_delegation4 = -1;
239 static gint ett_nfs_open_claim4 = -1;
240 static gint ett_nfs_opentype4 = -1;
241 static gint ett_nfs_lockowner4 = -1;
242 static gint ett_nfs_cb_client4 = -1;
243 static gint ett_nfs_client_id4 = -1;
244 static gint ett_nfs_bitmap4 = -1;
245 static gint ett_nfs_fattr4 = -1;
246 static gint ett_nfs_fsid4 = -1;
247 static gint ett_nfs_fs_locations4 = -1;
248 static gint ett_nfs_fs_location4 = -1;
249 static gint ett_nfs_open4_result_flags = -1;
250
251 /* file handle dissection */
252
253 #define FHT_UNKNOWN     0
254 #define FHT_SVR4        1
255 #define FHT_LINUX_KNFSD_LE      2
256 #define FHT_LINUX_NFSD_LE       3
257
258 const value_string names_fhtype[] =
259 {
260         {       FHT_UNKNOWN,    "unknown"       },
261         {       FHT_SVR4,       "System V R4"   },
262         {       FHT_LINUX_KNFSD_LE,     "Linux knfsd (little-endian)"   },
263         {       FHT_LINUX_NFSD_LE,      "Linux user-land nfsd (little-endian)"  },
264         {               0,      NULL            }
265 };
266
267
268 /* SVR4: checked with ReliantUNIX (5.43, 5.44, 5.45) */
269
270 static void
271 dissect_fhandle_data_SVR4(tvbuff_t* tvb, int offset, proto_tree *tree,
272     int fhlen)
273 {
274         guint32 nof = offset;
275
276         /* file system id */
277         {
278         guint32 fsid_O;
279         guint32 fsid_L;
280         guint32 temp;
281         guint32 fsid_major;
282         guint32 fsid_minor;
283
284         fsid_O = nof;
285         fsid_L = 4;
286         temp = tvb_get_ntohl(tvb, fsid_O);
287         fsid_major = ( temp>>18 ) &  0x3fff; /* 14 bits */
288         fsid_minor = ( temp     ) & 0x3ffff; /* 18 bits */
289         if (tree) {
290                 proto_item* fsid_item = NULL;
291                 proto_tree* fsid_tree = NULL;
292         
293                 fsid_item = proto_tree_add_text(tree, tvb,
294                         fsid_O, fsid_L, 
295                         "file system ID: %d,%d", fsid_major, fsid_minor);
296                 if (fsid_item) {
297                         fsid_tree = proto_item_add_subtree(fsid_item, 
298                                         ett_nfs_fh_fsid);
299                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
300                                 tvb, fsid_O,   2, fsid_major);
301                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
302                                 tvb, fsid_O+1, 3, fsid_minor);
303                 }
304         }
305         nof = fsid_O + fsid_L;
306         }
307
308         /* file system type */
309         {
310         guint32 fstype_O;
311         guint32 fstype_L;
312         guint32 fstype;
313
314         fstype_O = nof;
315         fstype_L = 4;
316         fstype = tvb_get_ntohl(tvb, fstype_O);
317         if (tree) {
318                 proto_tree_add_uint(tree, hf_nfs_fh_fstype, tvb,
319                         fstype_O, fstype_L, fstype);
320         }
321         nof = fstype_O + fstype_L;
322         }
323
324         /* file number */
325         {
326         guint32 fn_O;
327         guint32 fn_len_O;
328         guint32 fn_len_L;
329         guint32 fn_len;
330         guint32 fn_data_O;
331         guint32 fn_data_inode_O;
332         guint32 fn_data_inode_L;
333         guint32 inode;
334         guint32 fn_data_gen_O;
335         guint32 fn_data_gen_L;
336         guint32 gen;
337         guint32 fn_L;
338         
339         fn_O = nof;
340         fn_len_O = fn_O;
341         fn_len_L = 2;
342         fn_len = tvb_get_ntohs(tvb, fn_len_O);
343         fn_data_O = fn_O + fn_len_L;
344         fn_data_inode_O = fn_data_O + 2;
345         fn_data_inode_L = 4;
346         inode = tvb_get_ntohl(tvb, fn_data_inode_O);
347         fn_data_gen_O = fn_data_inode_O + fn_data_inode_L;
348         fn_data_gen_L = 4;
349         gen = tvb_get_ntohl(tvb, fn_data_gen_O);
350         fn_L = fn_len_L + fn_len;
351         if (tree) {
352                 proto_item* fn_item = NULL;
353                 proto_tree* fn_tree = NULL;
354         
355                 fn_item = proto_tree_add_uint(tree, hf_nfs_fh_fn, tvb,
356                         fn_O, fn_L, inode);
357                 if (fn_item) {
358                         fn_tree = proto_item_add_subtree(fn_item, 
359                                         ett_nfs_fh_fn);
360                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_len,
361                                 tvb, fn_len_O, fn_len_L, fn_len);
362                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_inode,
363                                 tvb, fn_data_inode_O, fn_data_inode_L, inode);
364                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_generation,
365                                 tvb, fn_data_gen_O, fn_data_gen_L, gen);
366                 }
367         }
368         nof = fn_O + fn_len_L + fn_len;
369         }
370
371         /* exported file number */
372         {
373         guint32 xfn_O;
374         guint32 xfn_len_O;
375         guint32 xfn_len_L;
376         guint32 xfn_len;
377         guint32 xfn_data_O;
378         guint32 xfn_data_inode_O;
379         guint32 xfn_data_inode_L;
380         guint32 xinode;
381         guint32 xfn_data_gen_O;
382         guint32 xfn_data_gen_L;
383         guint32 xgen;
384         guint32 xfn_L;
385         
386         xfn_O = nof;
387         xfn_len_O = xfn_O;
388         xfn_len_L = 2;
389         xfn_len = tvb_get_ntohs(tvb, xfn_len_O);
390         xfn_data_O = xfn_O + xfn_len_L;
391         xfn_data_inode_O = xfn_data_O + 2;
392         xfn_data_inode_L = 4;
393         xinode = tvb_get_ntohl(tvb, xfn_data_inode_O);
394         xfn_data_gen_O = xfn_data_inode_O + xfn_data_inode_L;
395         xfn_data_gen_L = 4;
396         xgen = tvb_get_ntohl(tvb, xfn_data_gen_O);
397         xfn_L = xfn_len_L + xfn_len;
398         if (tree) {
399                 proto_item* xfn_item = NULL;
400                 proto_tree* xfn_tree = NULL;
401         
402                 xfn_item = proto_tree_add_uint(tree, hf_nfs_fh_xfn, tvb,
403                         xfn_O, xfn_L, xinode);
404                 if (xfn_item) {
405                         xfn_tree = proto_item_add_subtree(xfn_item, 
406                                         ett_nfs_fh_xfn);
407                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_len,
408                                 tvb, xfn_len_O, xfn_len_L, xfn_len);
409                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_inode,
410                                 tvb, xfn_data_inode_O, xfn_data_inode_L, xinode);
411                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_generation,
412                                 tvb, xfn_data_gen_O, xfn_data_gen_L, xgen);
413                 }
414         }
415         }
416 }
417
418
419 /* Checked with RedHat Linux 6.2 (kernel 2.2.14 knfsd) */
420
421 static void
422 dissect_fhandle_data_LINUX_KNFSD_LE(tvbuff_t* tvb, int offset, proto_tree *tree,
423     int fhlen)
424 {
425         guint32 dentry;
426         guint32 inode;
427         guint32 dirinode;
428         guint32 temp;
429         guint32 fsid_major;
430         guint32 fsid_minor;
431         guint32 xfsid_major;
432         guint32 xfsid_minor;
433         guint32 xinode;
434         guint32 gen;
435
436         dentry   = tvb_get_letohl(tvb, offset+0);
437         inode    = tvb_get_letohl(tvb, offset+4);
438         dirinode = tvb_get_letohl(tvb, offset+8);
439         temp     = tvb_get_letohs (tvb,offset+12);
440         fsid_major = (temp >> 8) & 0xff;
441         fsid_minor = (temp     ) & 0xff;
442         temp     = tvb_get_letohs(tvb,offset+16);
443         xfsid_major = (temp >> 8) & 0xff;
444         xfsid_minor = (temp     ) & 0xff;
445         xinode   = tvb_get_letohl(tvb,offset+20);
446         gen      = tvb_get_letohl(tvb,offset+24);
447
448         if (tree) {
449                 proto_tree_add_uint(tree, hf_nfs_fh_dentry,
450                         tvb, offset+0, 4, dentry);
451                 proto_tree_add_uint(tree, hf_nfs_fh_fn_inode,
452                         tvb, offset+4, 4, inode);
453                 proto_tree_add_uint(tree, hf_nfs_fh_dirinode,
454                         tvb, offset+8, 4, dirinode);
455
456                 /* file system id (device) */
457                 {
458                 proto_item* fsid_item = NULL;
459                 proto_tree* fsid_tree = NULL;
460
461                 fsid_item = proto_tree_add_text(tree, tvb,
462                         offset+12, 4, 
463                         "file system ID: %d,%d", fsid_major, fsid_minor);
464                 if (fsid_item) {
465                         fsid_tree = proto_item_add_subtree(fsid_item, 
466                                         ett_nfs_fh_fsid);
467                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
468                                 tvb, offset+13, 1, fsid_major);
469                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
470                                 tvb, offset+12, 1, fsid_minor);
471                 }
472                 }
473
474                 /* exported file system id (device) */
475                 {
476                 proto_item* xfsid_item = NULL;
477                 proto_tree* xfsid_tree = NULL;
478
479                 xfsid_item = proto_tree_add_text(tree, tvb,
480                         offset+16, 4, 
481                         "exported file system ID: %d,%d", xfsid_major, xfsid_minor);
482                 if (xfsid_item) {
483                         xfsid_tree = proto_item_add_subtree(xfsid_item, 
484                                         ett_nfs_fh_xfsid);
485                         proto_tree_add_uint(xfsid_tree, hf_nfs_fh_xfsid_major,
486                                 tvb, offset+17, 1, xfsid_major);
487                         proto_tree_add_uint(xfsid_tree, hf_nfs_fh_xfsid_minor,
488                                 tvb, offset+16, 1, xfsid_minor);
489                 }
490                 }
491
492                 proto_tree_add_uint(tree, hf_nfs_fh_xfn_inode,
493                         tvb, offset+20, 4, xinode);
494                 proto_tree_add_uint(tree, hf_nfs_fh_fn_generation,
495                         tvb, offset+24, 4, gen);
496         }
497 }
498
499
500 /* Checked with RedHat Linux 5.2 (nfs-server 2.2beta47 user-land nfsd) */
501
502 void
503 dissect_fhandle_data_LINUX_NFSD_LE(tvbuff_t* tvb, int offset, proto_tree *tree,
504     int fhlen)
505 {
506         /* pseudo inode */
507         {
508         guint32 pinode;
509         pinode   = tvb_get_letohl(tvb, offset+0);
510         if (tree) {
511                 proto_tree_add_uint(tree, hf_nfs_fh_pinode,
512                         tvb, offset+0, 4, pinode);
513         }
514         }
515
516         /* hash path */
517         {
518         guint32 hashlen;
519
520         hashlen  = tvb_get_guint8(tvb, offset+4);
521         if (tree) {
522                 proto_item* hash_item = NULL;
523                 proto_tree* hash_tree = NULL;
524
525                 hash_item = proto_tree_add_text(tree, tvb, offset+4,
526                                 hashlen + 1,
527                                 "hash path: %s",
528                                 tvb_bytes_to_str(tvb,offset+5,hashlen));
529                 if (hash_item) {
530                         hash_tree = proto_item_add_subtree(hash_item, 
531                                         ett_nfs_fh_hp);
532                         if (hash_tree) {
533                                 proto_tree_add_uint(hash_tree,
534                                         hf_nfs_fh_hp_len, tvb, offset+4, 1,
535                                         hashlen);
536                                 proto_tree_add_text(hash_tree, tvb, offset+5,
537                                         hashlen,
538                                         "key: %s",
539                                         tvb_bytes_to_str(tvb,offset+5,hashlen));
540                         }
541                 }
542         }
543         }
544 }
545
546
547 static void
548 dissect_fhandle_data_unknown(tvbuff_t *tvb, int offset, proto_tree *tree,
549     int fhlen)
550 {
551         int sublen;
552         int bytes_left;
553         gboolean first_line;
554
555         bytes_left = fhlen;
556         first_line = TRUE;
557         while (bytes_left != 0) {
558                 sublen = 16;
559                 if (sublen > bytes_left)
560                         sublen = bytes_left;
561                 proto_tree_add_text(tree, tvb, offset, sublen,
562                                         "%s%s",
563                                         first_line ? "data: " :
564                                                      "      ",
565                                         tvb_bytes_to_str(tvb,offset,sublen));
566                 bytes_left -= sublen;
567                 offset += sublen;
568                 first_line = FALSE;
569         }
570 }
571
572
573 static void
574 dissect_fhandle_data(tvbuff_t *tvb, int offset, packet_info *pinfo,
575     proto_tree *tree, int fhlen)
576 {
577         int fhtype = FHT_UNKNOWN;
578
579         /* filehandle too long */
580         if (fhlen>64) goto type_ready;
581         /* Not all bytes there. Any attempt to deduce the type would be
582            senseless. */
583         if (!tvb_bytes_exist(tvb,offset,fhlen)) goto type_ready;
584                 
585         /* calculate (heuristically) fhtype */
586         switch (fhlen) {
587                 case 32: {
588                         guint32 len1;
589                         guint32 len2;
590                         if (tvb_get_ntohs(tvb,offset+4) == 0) {
591                                 len1=tvb_get_ntohs(tvb,offset+8);
592                                 if (tvb_bytes_exist(tvb,offset+10+len1,2)) {
593                                         len2=tvb_get_ntohs(tvb,
594                                             offset+10+len1);
595                                         if (fhlen==12+len1+len2) {
596                                                 fhtype=FHT_SVR4;
597                                                 goto type_ready;
598                                         }
599                                 }
600                         }
601                         len1 = tvb_get_guint8(tvb,offset+4);
602                         if (len1<28 && tvb_bytes_exist(tvb,offset+5,len1)) {
603                                 int wrong=0;
604                                 for (len2=5+len1;len2<32;len2++) {
605                                         if (tvb_get_guint8(tvb,offset+len2)) {
606                                                 wrong=1;        
607                                                 break;
608                                         }
609                                 }
610                                 if (!wrong) {
611                                         fhtype=FHT_LINUX_NFSD_LE;
612                                         goto type_ready;
613                                 }
614                         }
615                         if (tvb_get_ntohl(tvb,offset+28) == 0) {
616                                 if (tvb_get_ntohs(tvb,offset+14) == 0) {
617                                         if (tvb_get_ntohs(tvb,offset+18) == 0) {
618                                                 fhtype=FHT_LINUX_KNFSD_LE;
619                                                 goto type_ready;
620                                         }
621                                 }
622                         }
623                 } break;
624         }
625
626 type_ready:
627
628         proto_tree_add_text(tree, tvb, offset, 0, 
629                 "type: %s", val_to_str(fhtype, names_fhtype, "Unknown"));
630
631         switch (fhtype) {
632                 case FHT_SVR4:
633                         dissect_fhandle_data_SVR4          (tvb, offset, tree,
634                             fhlen);
635                 break;
636                 case FHT_LINUX_KNFSD_LE:
637                         dissect_fhandle_data_LINUX_KNFSD_LE(tvb, offset, tree,
638                             fhlen);
639                 break;
640                 case FHT_LINUX_NFSD_LE:
641                         dissect_fhandle_data_LINUX_NFSD_LE (tvb, offset, tree,
642                             fhlen);
643                 break;
644                 case FHT_UNKNOWN:
645                 default:
646                         dissect_fhandle_data_unknown(tvb, offset, tree, fhlen);
647                 break;
648         }
649 }
650
651
652 /***************************/
653 /* NFS Version 2, RFC 1094 */
654 /***************************/
655
656
657 /* base 32 bit type for NFS v2 */
658 int
659 dissect_unsigned_int(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
660 char* name)
661 {
662         offset = dissect_rpc_uint32(pd,offset,fd,tree,name);
663         return offset;
664 }
665
666
667 /* RFC 1094, Page 12..14 */
668 const value_string names_nfs_stat[] =
669 {
670         {       0,      "OK" },
671         {       1,      "ERR_PERM" },
672         {       2,      "ERR_NOENT" },
673         {       5,      "ERR_IO" },
674         {       6,      "ERR_NX_IO" },
675         {       13,     "ERR_ACCES" },
676         {       17,     "ERR_EXIST" },
677         {       18,     "ERR_XDEV" },   /* not in spec, but can happen */
678         {       19,     "ERR_NODEV" },
679         {       20,     "ERR_NOTDIR" },
680         {       21,     "ERR_ISDIR" },
681         {       22,     "ERR_INVAL" },  /* not in spec, but I think it can happen */
682         {       26,     "ERR_TXTBSY" }, /* not in spec, but I think it can happen */
683         {       27,     "ERR_FBIG" },
684         {       28,     "ERR_NOSPC" },
685         {       30,     "ERR_ROFS" },
686         {       31,     "ERR_MLINK" },  /* not in spec, but can happen */
687         {       45,     "ERR_OPNOTSUPP" }, /* not in spec, but I think it can happen */
688         {       63,     "ERR_NAMETOOLONG" },
689         {       66,     "ERR_NOTEMPTY" },
690         {       69,     "ERR_DQUOT" },
691         {       70,     "ERR_STALE" },
692         {       99,     "ERR_WFLUSH" },
693         {       0,      NULL }
694 };
695
696 /* NFSv4 Draft Specification, Page 198-199 */
697 const value_string names_nfs_stat4[] = {
698         {       0,                      "NFS4_OK"                                                       },
699         {       1,                      "NFS4ERR_PERM"                                          },
700         {       2,                      "NFS4ERR_NOENT"                                 },
701         {       5,                      "NFS4ERR_IO"                                            },
702         {       6,                      "NFS4ERR_NXIO"                                          },
703         {       13,             "NFS4ERR_ACCES"                                 },
704         {       17,             "NFS4ERR_EXIST"                                 },
705         {       18,             "NFS4ERR_XDEV"                                          },
706         {       19,             "NFS4ERR_NODEV"                                 },
707         {       20,             "NFS4ERR_NOTDIR"                                        },
708         {       21,             "NFS4ERR_ISDIR"                                 },
709         {       22,             "NFS4ERR_INVAL"                                 },
710         {       27,             "NFS4ERR_FBIG"                                          },
711         {       28,             "NFS4ERR_NOSPC"                                 },
712         {       30,             "NFS4ERR_ROFS"                                          },
713         {       31,             "NFS4ERR_MLINK"                                 },
714         {       63,             "NFS4ERR_NAMETOOLONG"                   },
715         {       66,             "NFS4ERR_NOTEMPTY"                              },
716         {       69,             "NFS4ERR_DQUOT"                                 },
717         {       70,             "NFS4ERR_STALE"                                 },
718         {       10001,  "NFS4ERR_BADHANDLE"                             },
719         {       10003,  "NFS4ERR_BAD_COOKIE"                            },
720         {       10004,  "NFS4ERR_NOTSUPP"                                       },
721         {       10005,  "NFS4ERR_TOOSMALL"                              },
722         {       10006,  "NFS4ERR_SERVERFAULT"                   },
723         {       10007,  "NFS4ERR_BADTYPE"                                       },
724         {       10008,  "NFS4ERR_DELAY"                                 },
725         {       10009,  "NFS4ERR_SAME"                                          },
726         {       10010,  "NFS4ERR_DENIED"                                        },
727         {       10011,  "NFS4ERR_EXPIRED"                                       },
728         {       10012,  "NFS4ERR_LOCKED"                                        },
729         {       10013,  "NFS4ERR_GRACE"                                 },
730         {       10014,  "NFS4ERR_FHEXPIRED"                             },
731         {       10015,  "NFS4ERR_SHARE_DENIED"                  },
732         {       10016,  "NFS4ERR_WRONGSEC"                              },
733         {       10017,  "NFS4ERR_CLID_INUSE"                            },
734         {       10018,  "NFS4ERR_RESOURCE"                              },
735         {       10019,  "NFS4ERR_MOVED"                                 },
736         {       10020,  "NFS4ERR_NOFILEHANDLE"                  },
737         {       10021,  "NFS4ERR_MINOR_VERS_MISMATCH"   },
738         {       10022,  "NFS4ERR_STALE_CLIENTID"                },
739         {       10023,  "NFS4ERR_STALE_STATEID"                 },
740         {       10024,  "NFS4ERR_OLD_STATEID"                   },
741         {       10025,  "NFS4ERR_BAD_STATEID"                   },
742         {       10026,  "NFS4ERR_BAD_SEQID"                             },
743         {       10027,  "NFS4ERR_NOT_SAME"                              },
744         {       10028,  "NFS4ERR_LOCK_RANGE"                            },
745         {       10029,  "NFS4ERR_SYMLINK"                                       },
746         {       10030,  "NFS4ERR_READDIR_NOSPC"                 },
747         {       10031,  "NFS4ERR_LEASE_MOVED"                   },
748         { 0, NULL }
749 };
750
751
752 /* This function has been modified to support NFSv4 style error codes as
753  * well as being backwards compatible with NFSv2 and NFSv3.
754  */
755 int
756 dissect_stat_internal(const u_char *pd, int offset, frame_data *fd, 
757         proto_tree *tree, guint32* status, int nfsvers)
758 {
759         guint32 stat;
760
761         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
762         stat = EXTRACT_UINT(pd, offset+0);
763         
764         if (tree) {
765                 /* this gives the right NFSv2 number<->message relation */
766                 /* and makes it searchable via "nfs.status" */
767                 proto_tree_add_uint_format(tree, hf_nfs_nfsstat3, NullTVB,
768                         offset+0, 4, stat, "Status: %s (%u)", 
769                         val_to_str(stat, 
770                                 (nfsvers != 4)? names_nfs_stat: names_nfs_stat4,"%u"), stat);
771         }
772
773         offset += 4;
774         *status = stat;
775         return offset;
776 }
777
778
779 /* RFC 1094, Page 12..14 */
780 int
781 dissect_stat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
782         guint32 *status)
783 {
784         return dissect_stat_internal(pd, offset, fd, tree, status, !4);
785 }
786
787
788 /* RFC 1094, Page 12..14 */
789 int
790 dissect_nfs2_stat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
791 {
792         guint32 status;
793
794         offset = dissect_stat(pd, offset, fd, tree, &status);
795
796         return offset;
797 }
798
799
800 int
801 dissect_nfs_nfsstat4(const u_char *pd, int offset, frame_data *fd, 
802         proto_tree *tree, guint32 *status)
803 {
804         return dissect_stat_internal(pd, offset, fd, tree, status, 4);
805 }
806
807
808 /* RFC 1094, Page 15 */
809 int
810 dissect_ftype(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
811 char* name)
812 {
813         guint32 ftype;
814         char* ftype_name = NULL;
815
816         const value_string nfs2_ftype[] =
817         {
818                 {       0,      "Non-File" },
819                 {       1,      "Regular File" },
820                 {       2,      "Directory" },
821                 {       3,      "Block Special Device" },
822                 {       4,      "Character Special Device" },
823                 {       5,      "Symbolic Link" },
824                 {       0,      NULL }
825         };
826
827         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
828         ftype = EXTRACT_UINT(pd, offset+0);
829         ftype_name = val_to_str(ftype, nfs2_ftype, "%u");
830         
831         if (tree) {
832                 proto_tree_add_text(tree, NullTVB, offset, 4,
833                         "%s: %s (%u)", name, ftype_name, ftype);
834         }
835
836         offset += 4;
837         return offset;
838 }
839
840
841 /* RFC 1094, Page 15 */
842 int
843 old_dissect_fhandle(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
844 {
845         tvbuff_t *tvb = tvb_create_from_top(offset);
846
847         offset = dissect_fhandle(tvb, 0, &pi, tree, name);
848         return tvb_raw_offset(tvb) + offset;
849 }
850
851 int
852 dissect_fhandle(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,
853     char *name)
854 {
855         proto_item* fitem;
856         proto_tree* ftree = NULL;
857
858         if (tree) {
859                 fitem = proto_tree_add_text(tree, tvb, offset, FHSIZE,
860                         "%s", name);
861                 if (fitem)
862                         ftree = proto_item_add_subtree(fitem, ett_nfs_fhandle);
863         }
864
865         if (ftree)
866                 dissect_fhandle_data(tvb, offset, pinfo, ftree, FHSIZE);
867
868         offset += FHSIZE;
869         return offset;
870 }
871
872 /* RFC 1094, Page 15 */
873 int
874 dissect_nfs2_fhandle_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
875 {
876         offset = old_dissect_fhandle(pd, offset, fd, tree, "object");
877
878         return offset;
879 }
880
881
882 /* RFC 1094, Page 15 */
883 int
884 dissect_timeval(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
885 {
886         guint32 seconds;
887         guint32 mseconds;
888
889         proto_item* time_item;
890         proto_tree* time_tree = NULL;
891
892         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
893         seconds = EXTRACT_UINT(pd, offset+0);
894         mseconds = EXTRACT_UINT(pd, offset+4);
895         
896         if (tree) {
897                 time_item = proto_tree_add_text(tree, NullTVB, offset, 8,
898                         "%s: %u.%06u", name, seconds, mseconds);
899                 if (time_item)
900                         time_tree = proto_item_add_subtree(time_item, ett_nfs_timeval);
901         }
902
903         if (time_tree) {
904                 proto_tree_add_text(time_tree, NullTVB,offset+0,4,
905                                         "seconds: %u", seconds);
906                 proto_tree_add_text(time_tree, NullTVB,offset+4,4,
907                                         "micro seconds: %u", mseconds);
908         }
909         offset += 8;
910         return offset;
911 }
912
913
914 /* RFC 1094, Page 16 */
915 const value_string nfs2_mode_names[] = {
916         {       0040000,        "Directory"     },
917         {       0020000,        "Character Special Device"      },
918         {       0060000,        "Block Special Device"  },
919         {       0100000,        "Regular File"  },
920         {       0120000,        "Symbolic Link" },
921         {       0140000,        "Named Socket"  },
922         {       0000000,        NULL            },
923 };
924
925 int
926 dissect_mode(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
927 char* name)
928 {
929         guint32 mode;
930         proto_item* mode_item = NULL;
931         proto_tree* mode_tree = NULL;
932
933         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
934         mode = EXTRACT_UINT(pd, offset+0);
935         
936         if (tree) {
937                 mode_item = proto_tree_add_text(tree, NullTVB, offset, 4,
938                         "%s: 0%o", name, mode);
939                 if (mode_item)
940                         mode_tree = proto_item_add_subtree(mode_item, ett_nfs_mode);
941         }
942
943         if (mode_tree) {
944                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
945                         decode_enumerated_bitfield(mode,  0160000, 16,
946                         nfs2_mode_names, "%s"));
947                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
948                 decode_boolean_bitfield(mode,   04000, 16, "Set user id on exec", "not SUID"));
949                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
950                 decode_boolean_bitfield(mode,   02000, 16, "Set group id on exec", "not SGID"));
951                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
952                 decode_boolean_bitfield(mode,   01000, 16, "Save swapped text even after use", "not save swapped text"));
953                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
954                 decode_boolean_bitfield(mode,    0400, 16, "Read permission for owner", "no Read permission for owner"));
955                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
956                 decode_boolean_bitfield(mode,    0200, 16, "Write permission for owner", "no Write permission for owner"));
957                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
958                 decode_boolean_bitfield(mode,    0100, 16, "Execute permission for owner", "no Execute permission for owner"));
959                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
960                 decode_boolean_bitfield(mode,     040, 16, "Read permission for group", "no Read permission for group"));
961                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
962                 decode_boolean_bitfield(mode,     020, 16, "Write permission for group", "no Write permission for group"));
963                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
964                 decode_boolean_bitfield(mode,     010, 16, "Execute permission for group", "no Execute permission for group"));
965                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
966                 decode_boolean_bitfield(mode,      04, 16, "Read permission for others", "no Read permission for others"));
967                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
968                 decode_boolean_bitfield(mode,      02, 16, "Write permission for others", "no Write permission for others"));
969                 proto_tree_add_text(mode_tree, NullTVB, offset, 4, "%s",
970                 decode_boolean_bitfield(mode,      01, 16, "Execute permission for others", "no Execute permission for others"));
971         }
972
973         offset += 4;
974         return offset;
975 }
976
977
978 /* RFC 1094, Page 15 */
979 int
980 dissect_fattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
981 {
982         proto_item* fattr_item = NULL;
983         proto_tree* fattr_tree = NULL;
984         int old_offset = offset;
985
986         if (tree) {
987                 fattr_item = proto_tree_add_text(tree, NullTVB, offset,
988                         END_OF_FRAME, "%s", name);
989                 if (fattr_item)
990                         fattr_tree = proto_item_add_subtree(fattr_item, ett_nfs_fattr);
991         }
992
993         offset = dissect_ftype        (pd,offset,fd,fattr_tree,"type");
994         offset = dissect_mode         (pd,offset,fd,fattr_tree,"mode");
995         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"nlink");
996         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"uid");
997         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"gid");
998         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"size");
999         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocksize");
1000         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"rdev");
1001         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocks");
1002         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fsid");
1003         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fileid");
1004         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"atime");
1005         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"mtime");
1006         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"ctime");
1007
1008         /* now we know, that fattr is shorter */
1009         if (fattr_item) {
1010                 proto_item_set_len(fattr_item, offset - old_offset);
1011         }
1012
1013         return offset;
1014 }
1015
1016
1017 /* RFC 1094, Page 17 */
1018 int
1019 dissect_sattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1020 {
1021         proto_item* sattr_item = NULL;
1022         proto_tree* sattr_tree = NULL;
1023         int old_offset = offset;
1024
1025         if (tree) {
1026                 sattr_item = proto_tree_add_text(tree, NullTVB, offset,
1027                         END_OF_FRAME, "%s", name);
1028                 if (sattr_item)
1029                         sattr_tree = proto_item_add_subtree(sattr_item, ett_nfs_sattr);
1030         }
1031
1032         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1033         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
1034                 offset = dissect_mode         (pd,offset,fd,sattr_tree,"mode");
1035         else {
1036                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "mode: no value");
1037                 offset += 4;
1038         }
1039
1040         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1041         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
1042                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"uid");
1043         else {
1044                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "uid: no value");
1045                 offset += 4;
1046         }
1047
1048         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1049         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
1050                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"gid");
1051         else {
1052                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "gid: no value");
1053                 offset += 4;
1054         }
1055
1056         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1057         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
1058                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"size");
1059         else {
1060                 proto_tree_add_text(sattr_tree, NullTVB, offset, 4, "size: no value");
1061                 offset += 4;
1062         }
1063
1064         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1065         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
1066                 offset = dissect_timeval      (pd,offset,fd,sattr_tree,"atime");
1067         else {
1068                 proto_tree_add_text(sattr_tree, NullTVB, offset, 8, "atime: no value");
1069                 offset += 8;
1070         }
1071
1072         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1073         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
1074                 offset = dissect_timeval      (pd,offset,fd,sattr_tree,"mtime");
1075         else {
1076                 proto_tree_add_text(sattr_tree, NullTVB, offset, 8, "mtime: no value");
1077                 offset += 8;
1078         }
1079
1080         /* now we know, that sattr is shorter */
1081         if (sattr_item) {
1082                 proto_item_set_len(sattr_item, offset - old_offset);
1083         }
1084
1085         return offset;
1086 }
1087
1088
1089 /* RFC 1094, Page 17 */
1090 int
1091 dissect_filename(const u_char *pd, int offset, frame_data *fd,
1092     proto_tree *tree, int hf, char **string_ret)
1093 {
1094         offset = dissect_rpc_string(pd,offset,fd,tree,hf,string_ret);
1095         return offset;
1096 }
1097
1098
1099 /* RFC 1094, Page 17 */
1100 int
1101 dissect_path(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
1102 {
1103         offset = dissect_rpc_string(pd,offset,fd,tree,hf,NULL);
1104         return offset;
1105 }
1106
1107
1108 /* RFC 1094, Page 17,18 */
1109 int
1110 dissect_attrstat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
1111         guint32 status;
1112
1113         offset = dissect_stat(pd, offset, fd, tree, &status);
1114         switch (status) {
1115                 case 0:
1116                         offset = dissect_fattr(pd, offset, fd, tree, "attributes");
1117                 break;
1118                 default:
1119                         /* do nothing */
1120                 break;
1121         }
1122
1123         return offset;
1124 }
1125
1126
1127 /* RFC 1094, Page 17,18 */
1128 int
1129 dissect_nfs2_attrstat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1130 {
1131         offset = dissect_attrstat(pd, offset, fd, tree);
1132
1133         return offset;
1134 }
1135
1136
1137 /* RFC 1094, Page 18 */
1138 int
1139 dissect_diropargs(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1140 {
1141         proto_item* diropargs_item = NULL;
1142         proto_tree* diropargs_tree = NULL;
1143         int old_offset = offset;
1144
1145         if (tree) {
1146                 diropargs_item = proto_tree_add_text(tree, NullTVB, offset,
1147                         END_OF_FRAME, "%s", name);
1148                 if (diropargs_item)
1149                         diropargs_tree = proto_item_add_subtree(diropargs_item, ett_nfs_diropargs);
1150         }
1151
1152         offset = old_dissect_fhandle (pd,offset,fd,diropargs_tree,"dir");
1153         offset = dissect_filename(pd,offset,fd,diropargs_tree,hf_nfs_name,NULL);
1154
1155         /* now we know, that diropargs is shorter */
1156         if (diropargs_item) {
1157                 proto_item_set_len(diropargs_item, offset - old_offset);
1158         }
1159
1160         return offset;
1161 }
1162
1163
1164 /* RFC 1094, Page 18 */
1165 int
1166 dissect_nfs2_diropargs_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1167 {
1168         offset = dissect_diropargs(pd, offset, fd, tree, "where");
1169
1170         return offset;
1171 }
1172
1173
1174 /* RFC 1094, Page 18 */
1175 int
1176 dissect_diropres(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1177 {
1178         guint32 status;
1179
1180         offset = dissect_stat(pd, offset, fd, tree, &status);
1181         switch (status) {
1182                 case 0:
1183                         offset = old_dissect_fhandle(pd, offset, fd, tree, "file");
1184                         offset = dissect_fattr  (pd, offset, fd, tree, "attributes");
1185                 break;
1186                 default:
1187                         /* do nothing */
1188                 break;
1189         }
1190
1191         return offset;
1192 }
1193
1194
1195 /* nfsdata is simply a RPC string (length, data, fill bytes) */
1196 int
1197 dissect_nfsdata(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1198 int hf)
1199 {
1200         offset = dissect_rpc_data(pd,offset,fd,tree,hf);
1201
1202         return offset;
1203 }
1204
1205
1206 /* RFC 1094, Page 18 */
1207 int
1208 dissect_nfs2_diropres_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1209 {
1210         offset = dissect_diropres(pd, offset, fd, tree);
1211
1212         return offset;
1213 }
1214
1215
1216 /* RFC 1094, Page 6 */
1217 int
1218 dissect_nfs2_setattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1219 {
1220         offset = old_dissect_fhandle(pd, offset, fd, tree, "file"      );
1221         offset = dissect_sattr  (pd, offset, fd, tree, "attributes");
1222
1223         return offset;
1224 }
1225
1226
1227 /* RFC 1094, Page 6 */
1228 int
1229 dissect_nfs2_readlink_reply(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1230 {
1231         guint32 status;
1232
1233         offset = dissect_stat(pd, offset, fd, tree, &status);
1234         switch (status) {
1235                 case 0:
1236                         offset = dissect_path(pd, offset, fd, tree, hf_nfs_readlink_data);
1237                 break;
1238                 default:
1239                         /* do nothing */
1240                 break;
1241         }
1242
1243         return offset;
1244 }
1245
1246
1247 /* RFC 1094, Page 7 */
1248 int
1249 dissect_nfs2_read_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1250 {
1251         guint32 offset_value;
1252         guint32 count;
1253         guint32 totalcount;
1254
1255         offset = old_dissect_fhandle(pd, offset, fd, tree, "file"      );
1256         if (!BYTES_ARE_IN_FRAME(offset,12)) return offset;
1257         offset_value = EXTRACT_UINT(pd, offset+0);
1258         count        = EXTRACT_UINT(pd, offset+4);
1259         totalcount   = EXTRACT_UINT(pd, offset+8);
1260         if (tree) {
1261                 proto_tree_add_uint(tree, hf_nfs_read_offset, NullTVB, 
1262                 offset+0, 4, offset_value);
1263                 proto_tree_add_uint(tree, hf_nfs_read_count, NullTVB, 
1264                 offset+4, 4, count);
1265                 proto_tree_add_uint(tree, hf_nfs_read_totalcount, NullTVB, 
1266                 offset+8, 4, totalcount);
1267         }
1268         offset += 12;
1269
1270         return offset;
1271 }
1272
1273
1274 /* RFC 1094, Page 7 */
1275 int
1276 dissect_nfs2_read_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1277 {
1278         guint32 status;
1279
1280         offset = dissect_stat(pd, offset, fd, tree, &status);
1281         switch (status) {
1282                 case 0:
1283                         offset = dissect_fattr(pd, offset, fd, tree, "attributes");
1284                         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data); 
1285                 break;
1286                 default:
1287                         /* do nothing */
1288                 break;
1289         }
1290
1291         return offset;
1292 }
1293
1294
1295 /* RFC 1094, Page 8 */
1296 int
1297 dissect_nfs2_write_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1298 {
1299         guint32 beginoffset;
1300         guint32 offset_value;
1301         guint32 totalcount;
1302
1303         offset = old_dissect_fhandle(pd, offset, fd, tree, "file"      );
1304         if (!BYTES_ARE_IN_FRAME(offset,12)) return offset;
1305         beginoffset  = EXTRACT_UINT(pd, offset+0);
1306         offset_value = EXTRACT_UINT(pd, offset+4);
1307         totalcount   = EXTRACT_UINT(pd, offset+8);
1308         if (tree) {
1309                 proto_tree_add_uint(tree, hf_nfs_write_beginoffset, NullTVB, 
1310                 offset+0, 4, beginoffset);
1311                 proto_tree_add_uint(tree, hf_nfs_write_offset, NullTVB, 
1312                 offset+4, 4, offset_value);
1313                 proto_tree_add_uint(tree, hf_nfs_write_totalcount, NullTVB, 
1314                 offset+8, 4, totalcount);
1315         }
1316         offset += 12;
1317
1318         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data); 
1319
1320         return offset;
1321 }
1322
1323
1324 /* RFC 1094, Page 8 */
1325 int
1326 dissect_nfs2_createargs_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1327 {
1328         offset = dissect_diropargs(pd, offset, fd, tree, "where"     );
1329         offset = dissect_sattr    (pd, offset, fd, tree, "attributes");
1330
1331         return offset;
1332 }
1333
1334
1335 /* RFC 1094, Page 9 */
1336 int
1337 dissect_nfs2_rename_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1338 {
1339         offset = dissect_diropargs(pd, offset, fd, tree, "from");
1340         offset = dissect_diropargs(pd, offset, fd, tree, "to"  );
1341
1342         return offset;
1343 }
1344
1345
1346 /* RFC 1094, Page 9 */
1347 int
1348 dissect_nfs2_link_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1349 {
1350         offset = old_dissect_fhandle  (pd, offset, fd, tree, "from");
1351         offset = dissect_diropargs(pd, offset, fd, tree, "to"  );
1352
1353         return offset;
1354 }
1355
1356
1357 /* RFC 1094, Page 10 */
1358 int
1359 dissect_nfs2_symlink_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1360 {
1361         offset = dissect_diropargs(pd, offset, fd, tree, "from"           );
1362         offset = dissect_path     (pd, offset, fd, tree, hf_nfs_symlink_to);
1363         offset = dissect_sattr    (pd, offset, fd, tree, "attributes"     );
1364
1365         return offset;
1366 }
1367
1368
1369 /* RFC 1094, Page 11 */
1370 int
1371 dissect_nfs2_readdir_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1372 {
1373         guint32 cookie;
1374         guint32 count;
1375
1376         offset = old_dissect_fhandle (pd, offset, fd, tree, "dir");
1377         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1378         cookie  = EXTRACT_UINT(pd, offset+ 0);
1379         count = EXTRACT_UINT(pd, offset+ 4);
1380         if (tree) {
1381                 proto_tree_add_uint(tree, hf_nfs_readdir_cookie, NullTVB,
1382                         offset+ 0, 4, cookie);
1383                 proto_tree_add_uint(tree, hf_nfs_readdir_count, NullTVB,
1384                         offset+ 4, 4, count);
1385         }
1386         offset += 8;
1387
1388         return offset;
1389 }
1390
1391
1392 /* RFC 1094, Page 11 */
1393 int
1394 dissect_readdir_entry(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1395 {
1396         proto_item* entry_item = NULL;
1397         proto_tree* entry_tree = NULL;
1398         int old_offset = offset;
1399         guint32 fileid;
1400         guint32 cookie;
1401         char *name;
1402
1403         if (tree) {
1404                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, NullTVB,
1405                         offset+0, END_OF_FRAME, FALSE);
1406                 if (entry_item)
1407                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
1408         }
1409
1410         if (!BYTES_ARE_IN_FRAME(offset, 4)) {
1411                 if (entry_item)
1412                         proto_item_set_text(entry_item, "Entry: <TRUNCATED>");
1413                 return offset;
1414         }
1415         fileid = EXTRACT_UINT(pd, offset + 0);
1416         if (entry_tree)
1417                 proto_tree_add_uint(entry_tree, hf_nfs_readdir_entry_fileid, NullTVB,
1418                         offset+0, 4, fileid);
1419         offset += 4;
1420
1421         offset = dissect_filename(pd, offset, fd, entry_tree,
1422                 hf_nfs_readdir_entry_name, &name);
1423         if (entry_item)
1424                 proto_item_set_text(entry_item, "Entry: file ID %u, name %s",
1425                 fileid, name);
1426         g_free(name);
1427         
1428         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
1429         cookie = EXTRACT_UINT(pd, offset + 0);
1430         if (entry_tree)
1431                 proto_tree_add_uint(entry_tree, hf_nfs_readdir_entry_cookie, NullTVB,
1432                         offset+0, 4, cookie);
1433         offset += 4;
1434
1435         /* now we know, that a readdir entry is shorter */
1436         if (entry_item) {
1437                 proto_item_set_len(entry_item, offset - old_offset);
1438         }
1439
1440         return offset;
1441 }
1442
1443 /* RFC 1094, Page 11 */
1444 int
1445 dissect_nfs2_readdir_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1446 {
1447         guint32 status;
1448         guint32 eof_value;
1449
1450         offset = dissect_stat(pd, offset, fd, tree, &status);
1451         switch (status) {
1452                 case 0:
1453                         offset = dissect_rpc_list(pd, offset, fd, tree,
1454                                 dissect_readdir_entry);
1455                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1456                         eof_value = EXTRACT_UINT(pd, offset+0);
1457                         if (tree)
1458                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, NullTVB,
1459                                         offset+ 0, 4, eof_value);
1460                         offset += 4;
1461                 break;
1462                 default:
1463                         /* do nothing */
1464                 break;
1465         }
1466
1467         return offset;
1468 }
1469
1470
1471 /* RFC 1094, Page 12 */
1472 int
1473 dissect_nfs2_statfs_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1474 {
1475         guint32 status;
1476         guint32 tsize;
1477         guint32 bsize;
1478         guint32 blocks;
1479         guint32 bfree;
1480         guint32 bavail;
1481
1482         offset = dissect_stat(pd, offset, fd, tree, &status);
1483         switch (status) {
1484                 case 0:
1485                         if (!BYTES_ARE_IN_FRAME(offset,5 * 4)) return offset;
1486                         tsize  = EXTRACT_UINT(pd, offset+ 0);
1487                         bsize  = EXTRACT_UINT(pd, offset+ 4);
1488                         blocks = EXTRACT_UINT(pd, offset+ 8);
1489                         bfree  = EXTRACT_UINT(pd, offset+12);
1490                         bavail = EXTRACT_UINT(pd, offset+16);
1491                         if (tree) {
1492                                 proto_tree_add_uint(tree, hf_nfs_statfs_tsize, NullTVB,
1493                                         offset+ 0, 4, tsize);
1494                                 proto_tree_add_uint(tree, hf_nfs_statfs_bsize, NullTVB,
1495                                         offset+ 4, 4, bsize);
1496                                 proto_tree_add_uint(tree, hf_nfs_statfs_blocks, NullTVB,
1497                                         offset+ 8, 4, blocks);
1498                                 proto_tree_add_uint(tree, hf_nfs_statfs_bfree, NullTVB,
1499                                         offset+12, 4, bfree);
1500                                 proto_tree_add_uint(tree, hf_nfs_statfs_bavail, NullTVB,
1501                                         offset+16, 4, bavail);
1502                         }
1503                         offset += 20;
1504                 break;
1505                 default:
1506                         /* do nothing */
1507                 break;
1508         }
1509
1510         return offset;
1511 }
1512
1513
1514 /* proc number, "proc name", dissect_request, dissect_reply */
1515 /* NULL as function pointer means: type of arguments is "void". */
1516 static const old_vsff nfs2_proc[] = {
1517         { 0,    "NULL",         /* OK */
1518         NULL,                           NULL },
1519         { 1,    "GETATTR",      /* OK */
1520         dissect_nfs2_fhandle_call,      dissect_nfs2_attrstat_reply },
1521         { 2,    "SETATTR",      /* OK */
1522         dissect_nfs2_setattr_call,      dissect_nfs2_attrstat_reply },
1523         { 3,    "ROOT",         /* OK */
1524         NULL,                           NULL },
1525         { 4,    "LOOKUP",       /* OK */
1526         dissect_nfs2_diropargs_call,    dissect_nfs2_diropres_reply },
1527         { 5,    "READLINK",     /* OK */
1528         dissect_nfs2_fhandle_call,      dissect_nfs2_readlink_reply },
1529         { 6,    "READ",         /* OK */
1530         dissect_nfs2_read_call,         dissect_nfs2_read_reply },
1531         { 7,    "WRITECACHE",   /* OK */
1532         NULL,                           NULL },
1533         { 8,    "WRITE",        /* OK */
1534         dissect_nfs2_write_call,        dissect_nfs2_attrstat_reply },
1535         { 9,    "CREATE",       /* OK */
1536         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
1537         { 10,   "REMOVE",       /* OK */
1538         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
1539         { 11,   "RENAME",       /* OK */
1540         dissect_nfs2_rename_call,       dissect_nfs2_stat_reply },
1541         { 12,   "LINK",         /* OK */
1542         dissect_nfs2_link_call,         dissect_nfs2_stat_reply },
1543         { 13,   "SYMLINK",      /* OK */
1544         dissect_nfs2_symlink_call,      dissect_nfs2_stat_reply },
1545         { 14,   "MKDIR",        /* OK */
1546         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
1547         { 15,   "RMDIR",        /* OK */
1548         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
1549         { 16,   "READDIR",      /* OK */
1550         dissect_nfs2_readdir_call,      dissect_nfs2_readdir_reply },
1551         { 17,   "STATFS",       /* OK */
1552         dissect_nfs2_fhandle_call,      dissect_nfs2_statfs_reply },
1553         { 0,NULL,NULL,NULL }
1554 };
1555 /* end of NFS Version 2 */
1556
1557
1558 /***************************/
1559 /* NFS Version 3, RFC 1813 */
1560 /***************************/
1561
1562
1563 /* RFC 1813, Page 15 */
1564 int
1565 dissect_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1566 char* name)
1567 {
1568         offset = dissect_rpc_uint64(pd,offset,fd,tree,name);
1569         return offset;
1570 }
1571
1572
1573 /* RFC 1813, Page 15 */
1574 int
1575 dissect_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1576 char* name)
1577 {
1578         offset = dissect_rpc_uint32(pd,offset,fd,tree,name);
1579         return offset;
1580 }
1581
1582
1583 /* RFC 1813, Page 15 */
1584 int
1585 dissect_filename3(const u_char *pd, int offset, frame_data *fd,
1586     proto_tree *tree, int hf, char **string_ret)
1587 {
1588         offset = dissect_rpc_string(pd,offset,fd,tree,hf,string_ret);
1589         return offset;
1590 }
1591
1592
1593 /* RFC 1813, Page 15 */
1594 int
1595 dissect_nfspath3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
1596 {
1597         offset = dissect_rpc_string(pd,offset,fd,tree,hf,NULL);
1598         return offset;
1599 }
1600
1601
1602 /* RFC 1813, Page 15 */
1603 int
1604 dissect_fileid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1605 char* name)
1606 {
1607         offset = dissect_rpc_uint64(pd,offset,fd,tree,name);
1608         return offset;
1609 }
1610
1611
1612 /* RFC 1813, Page 15 */
1613 int
1614 dissect_cookie3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1615 char* name)
1616 {
1617         offset = dissect_rpc_uint64(pd,offset,fd,tree,name);
1618         return offset;
1619 }
1620
1621
1622 /* RFC 1813, Page 15 */
1623 int
1624 dissect_cookieverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1625 {
1626         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1627         proto_tree_add_text(tree, NullTVB, offset, NFS3_COOKIEVERFSIZE,
1628                 "Verifier: Opaque Data");
1629         offset += NFS3_COOKIEVERFSIZE;
1630         return offset;
1631 }
1632
1633
1634 /* RFC 1813, Page 16 */
1635 int
1636 dissect_createverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1637 {
1638         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1639         proto_tree_add_text(tree, NullTVB, offset, NFS3_CREATEVERFSIZE,
1640                 "Verifier: Opaque Data");
1641         offset += NFS3_CREATEVERFSIZE;
1642         return offset;
1643 }
1644
1645
1646 /* RFC 1813, Page 16 */
1647 int
1648 dissect_writeverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1649 {
1650         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1651         proto_tree_add_text(tree, NullTVB, offset, NFS3_WRITEVERFSIZE,
1652                 "Verifier: Opaque Data");
1653         offset += NFS3_WRITEVERFSIZE;
1654         return offset;
1655 }
1656
1657
1658 /* RFC 1813, Page 16 */
1659 int
1660 dissect_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1661 char* name)
1662 {
1663         offset = dissect_rpc_uint32(pd,offset,fd,tree,name); 
1664         return offset;
1665 }
1666
1667
1668 /* RFC 1813, Page 16 */
1669 int
1670 dissect_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1671 char* name)
1672 {
1673         offset = dissect_rpc_uint32(pd,offset,fd,tree,name); 
1674         return offset;
1675 }
1676
1677
1678 /* RFC 1813, Page 16 */
1679 int
1680 dissect_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1681 char* name)
1682 {
1683         offset = dissect_rpc_uint64(pd,offset,fd,tree,name); 
1684         return offset;
1685 }
1686
1687
1688 /* RFC 1813, Page 16 */
1689 int
1690 dissect_offset3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1691 char* name)
1692 {
1693         offset = dissect_rpc_uint64(pd,offset,fd,tree,name); 
1694         return offset;
1695 }
1696
1697
1698 /* RFC 1813, Page 16 */
1699 int
1700 dissect_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1701 char* name)
1702 {
1703         guint32 mode3;
1704         proto_item* mode3_item = NULL;
1705         proto_tree* mode3_tree = NULL;
1706
1707         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1708         mode3 = EXTRACT_UINT(pd, offset+0);
1709         
1710         if (tree) {
1711                 mode3_item = proto_tree_add_text(tree, NullTVB, offset, 4,
1712                         "%s: 0%o", name, mode3);
1713                 if (mode3_item)
1714                         mode3_tree = proto_item_add_subtree(mode3_item, ett_nfs_mode3);
1715         }
1716
1717         /* RFC 1813, Page 23 */
1718         if (mode3_tree) {
1719                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1720                 decode_boolean_bitfield(mode3,   0x800, 12, "Set user id on exec", "not SUID"));
1721                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1722                 decode_boolean_bitfield(mode3,   0x400, 12, "Set group id on exec", "not SGID"));
1723                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1724                 decode_boolean_bitfield(mode3,   0x200, 12, "Save swapped text even after use", "not save swapped text"));
1725                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1726                 decode_boolean_bitfield(mode3,   0x100, 12, "Read permission for owner", "no Read permission for owner"));
1727                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1728                 decode_boolean_bitfield(mode3,    0x80, 12, "Write permission for owner", "no Write permission for owner"));
1729                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1730                 decode_boolean_bitfield(mode3,    0x40, 12, "Execute permission for owner", "no Execute permission for owner"));
1731                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1732                 decode_boolean_bitfield(mode3,    0x20, 12, "Read permission for group", "no Read permission for group"));
1733                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1734                 decode_boolean_bitfield(mode3,    0x10, 12, "Write permission for group", "no Write permission for group"));
1735                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1736                 decode_boolean_bitfield(mode3,     0x8, 12, "Execute permission for group", "no Execute permission for group"));
1737                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1738                 decode_boolean_bitfield(mode3,     0x4, 12, "Read permission for others", "no Read permission for others"));
1739                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1740                 decode_boolean_bitfield(mode3,     0x2, 12, "Write permission for others", "no Write permission for others"));
1741                 proto_tree_add_text(mode3_tree, NullTVB, offset, 4, "%s",
1742                 decode_boolean_bitfield(mode3,     0x1, 12, "Execute permission for others", "no Execute permission for others"));
1743         }
1744
1745         offset += 4;
1746         return offset;
1747 }
1748
1749
1750 /* RFC 1813, Page 16 */
1751 int
1752 dissect_count3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1753 char* name)
1754 {
1755         offset = dissect_rpc_uint32(pd,offset,fd,tree,name);
1756         return offset;
1757 }
1758
1759
1760 /* RFC 1813, Page 16,17 */
1761 const value_string names_nfs_nfsstat3[] =
1762 {
1763         {       0,      "OK" },
1764         {       1,      "ERR_PERM" },
1765         {       2,      "ERR_NOENT" },
1766         {       5,      "ERR_IO" },
1767         {       6,      "ERR_NX_IO" },
1768         {       13,     "ERR_ACCES" },
1769         {       17,     "ERR_EXIST" },
1770         {       18,     "ERR_XDEV" },
1771         {       19,     "ERR_NODEV" },
1772         {       20,     "ERR_NOTDIR" },
1773         {       21,     "ERR_ISDIR" },
1774         {       22,     "ERR_INVAL" },
1775         {       27,     "ERR_FBIG" },
1776         {       28,     "ERR_NOSPC" },
1777         {       30,     "ERR_ROFS" },
1778         {       31,     "ERR_MLINK" },
1779         {       63,     "ERR_NAMETOOLONG" },
1780         {       66,     "ERR_NOTEMPTY" },
1781         {       69,     "ERR_DQUOT" },
1782         {       70,     "ERR_STALE" },
1783         {       71,     "ERR_REMOTE" },
1784         {       10001,  "ERR_BADHANDLE" },
1785         {       10002,  "ERR_NOT_SYNC" },
1786         {       10003,  "ERR_BAD_COOKIE" },
1787         {       10004,  "ERR_NOTSUPP" },
1788         {       10005,  "ERR_TOOSMALL" },
1789         {       10006,  "ERR_SERVERFAULT" },
1790         {       10007,  "ERR_BADTYPE" },
1791         {       10008,  "ERR_JUKEBOX" },
1792         {       0,      NULL }
1793 };
1794
1795
1796 /* RFC 1813, Page 16 */
1797 int
1798 dissect_nfsstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,guint32 *status)
1799 {
1800         guint32 nfsstat3;
1801
1802         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1803         nfsstat3 = EXTRACT_UINT(pd, offset+0);
1804         
1805         if (tree) {
1806                 proto_tree_add_uint(tree, hf_nfs_nfsstat3, NullTVB,
1807                         offset, 4, nfsstat3);
1808         }
1809
1810         offset += 4;
1811         *status = nfsstat3;
1812         return offset;
1813 }
1814
1815
1816 const value_string names_nfs_ftype3[] =
1817 {
1818         {       NF3REG, "Regular File" },
1819         {       NF3DIR, "Directory" },
1820         {       NF3BLK, "Block Special Device" },
1821         {       NF3CHR, "Character Special Device" },
1822         {       NF3LNK, "Symbolic Link" },
1823         {       NF3SOCK,"Socket" },
1824         {       NF3FIFO,"Named Pipe" },
1825         {       0,      NULL }
1826 };
1827
1828
1829 /* RFC 1813, Page 20 */
1830 int
1831 dissect_ftype3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1832 int hf, guint32* ftype3)
1833 {
1834         guint32 type;
1835
1836         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1837         type = EXTRACT_UINT(pd, offset+0);
1838         
1839         if (tree) {
1840                 proto_tree_add_uint(tree, hf, NullTVB, offset, 4, type);
1841         }
1842
1843         offset += 4;
1844         *ftype3 = type;
1845         return offset;
1846 }
1847
1848
1849 /* RFC 1813, Page 20 */
1850 int
1851 dissect_specdata3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1852 {
1853         guint32 specdata1;
1854         guint32 specdata2;
1855
1856         proto_item* specdata3_item;
1857         proto_tree* specdata3_tree = NULL;
1858
1859         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1860         specdata1 = EXTRACT_UINT(pd, offset+0);
1861         specdata2 = EXTRACT_UINT(pd, offset+4);
1862         
1863         if (tree) {
1864                 specdata3_item = proto_tree_add_text(tree, NullTVB, offset, 8,
1865                         "%s: %u,%u", name, specdata1, specdata2);
1866                 if (specdata3_item)
1867                         specdata3_tree = proto_item_add_subtree(specdata3_item,
1868                                         ett_nfs_specdata3);
1869         }
1870
1871         if (specdata3_tree) {
1872                 proto_tree_add_text(specdata3_tree, NullTVB,offset+0,4,
1873                                         "specdata1: %u", specdata1);
1874                 proto_tree_add_text(specdata3_tree, NullTVB,offset+4,4,
1875                                         "specdata2: %u", specdata2);
1876         }
1877
1878         offset += 8;
1879         return offset;
1880 }
1881
1882
1883 /* RFC 1813, Page 21 */
1884 int
1885 old_dissect_nfs_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1886 {
1887         tvbuff_t *tvb = tvb_create_from_top(offset);
1888
1889         offset = dissect_nfs_fh3(tvb, 0, &pi, tree, name);
1890         return tvb_raw_offset(tvb) + offset;
1891 }
1892
1893 int
1894 dissect_nfs_fh3(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,
1895     char *name)
1896 {
1897         guint fh3_len;
1898         guint fh3_len_full;
1899         guint fh3_fill;
1900         proto_item* fitem;
1901         proto_tree* ftree = NULL;
1902
1903         fh3_len = tvb_get_ntohl(tvb, offset+0);
1904         fh3_len_full = rpc_roundup(fh3_len);
1905         fh3_fill = fh3_len_full - fh3_len;
1906         
1907         if (tree) {
1908                 fitem = proto_tree_add_text(tree, tvb, offset, 4+fh3_len_full,
1909                         "%s", name);
1910                 if (fitem)
1911                         ftree = proto_item_add_subtree(fitem, ett_nfs_fh3);
1912         }
1913
1914         if (ftree) {
1915                 proto_tree_add_text(ftree, tvb, offset+0, 4,
1916                                         "length: %u", fh3_len);
1917                 dissect_fhandle_data(tvb, offset+4, pinfo, ftree, fh3_len);
1918         }
1919         offset += 4 + fh3_len_full;
1920         return offset;
1921 }
1922
1923
1924 /* RFC 1813, Page 21 */
1925 int
1926 dissect_nfstime3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,char* name)
1927 {
1928         guint32 seconds;
1929         guint32 nseconds;
1930
1931         proto_item* time_item;
1932         proto_tree* time_tree = NULL;
1933
1934         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1935         seconds = EXTRACT_UINT(pd, offset+0);
1936         nseconds = EXTRACT_UINT(pd, offset+4);
1937         
1938         if (tree) {
1939                 time_item = proto_tree_add_text(tree, NullTVB, offset, 8,
1940                         "%s: %u.%09u", name, seconds, nseconds);
1941                 if (time_item)
1942                         time_tree = proto_item_add_subtree(time_item, ett_nfs_nfstime3);
1943         }
1944
1945         if (time_tree) {
1946                 proto_tree_add_text(time_tree, NullTVB,offset+0,4,
1947                                         "seconds: %u", seconds);
1948                 proto_tree_add_text(time_tree, NullTVB,offset+4,4,
1949                                         "nano seconds: %u", nseconds);
1950         }
1951         offset += 8;
1952         return offset;
1953 }
1954
1955
1956 /* RFC 1813, Page 22 */
1957 int
1958 dissect_fattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1959 {
1960         proto_item* fattr3_item = NULL;
1961         proto_tree* fattr3_tree = NULL;
1962         int old_offset = offset;
1963         guint32 type;
1964
1965         if (tree) {
1966                 fattr3_item = proto_tree_add_text(tree, NullTVB, offset,
1967                         END_OF_FRAME, "%s", name);
1968                 if (fattr3_item)
1969                         fattr3_tree = proto_item_add_subtree(fattr3_item, ett_nfs_fattr3);
1970         }
1971
1972         offset = dissect_ftype3   (pd,offset,fd,fattr3_tree,hf_nfs_ftype3,&type);
1973         offset = dissect_mode3    (pd,offset,fd,fattr3_tree,"mode");
1974         offset = dissect_uint32   (pd,offset,fd,fattr3_tree,"nlink");
1975         offset = dissect_uid3     (pd,offset,fd,fattr3_tree,"uid");
1976         offset = dissect_gid3     (pd,offset,fd,fattr3_tree,"gid");
1977         offset = dissect_size3    (pd,offset,fd,fattr3_tree,"size");
1978         offset = dissect_size3    (pd,offset,fd,fattr3_tree,"used");
1979         offset = dissect_specdata3(pd,offset,fd,fattr3_tree,"rdev");
1980         offset = dissect_uint64   (pd,offset,fd,fattr3_tree,"fsid");
1981         offset = dissect_fileid3  (pd,offset,fd,fattr3_tree,"fileid");
1982         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"atime");
1983         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"mtime");
1984         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"ctime");
1985
1986         /* now we know, that fattr3 is shorter */
1987         if (fattr3_item) {
1988                 proto_item_set_len(fattr3_item, offset - old_offset);
1989         }
1990
1991         return offset;
1992 }
1993
1994
1995 const value_string value_follows[] =
1996         {
1997                 { 0, "no value" },
1998                 { 1, "value follows"},
1999                 { 0, NULL }
2000         };
2001
2002
2003 /* RFC 1813, Page 23 */
2004 int
2005 dissect_post_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2006 {
2007         proto_item* post_op_attr_item = NULL;
2008         proto_tree* post_op_attr_tree = NULL;
2009         int old_offset = offset;
2010         guint32 attributes_follow;
2011
2012         if (tree) {
2013                 post_op_attr_item = proto_tree_add_text(tree, NullTVB, offset,
2014                         END_OF_FRAME, "%s", name);
2015                 if (post_op_attr_item)
2016                         post_op_attr_tree = proto_item_add_subtree(post_op_attr_item, ett_nfs_post_op_attr);
2017         }
2018
2019         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2020         attributes_follow = EXTRACT_UINT(pd, offset+0);
2021         proto_tree_add_text(post_op_attr_tree, NullTVB, offset, 4,
2022                 "attributes_follow: %s (%u)", 
2023                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
2024         offset += 4;
2025         switch (attributes_follow) {
2026                 case TRUE:
2027                         offset = dissect_fattr3(pd, offset, fd, post_op_attr_tree,
2028                                         "attributes");
2029                 break;
2030                 case FALSE:
2031                         /* void */
2032                 break;
2033         }
2034         
2035         /* now we know, that post_op_attr_tree is shorter */
2036         if (post_op_attr_item) {
2037                 proto_item_set_len(post_op_attr_item, offset - old_offset);
2038         }
2039
2040         return offset;
2041 }
2042
2043
2044 /* RFC 1813, Page 24 */
2045 int
2046 dissect_wcc_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2047 {
2048         proto_item* wcc_attr_item = NULL;
2049         proto_tree* wcc_attr_tree = NULL;
2050         int old_offset = offset;
2051
2052         if (tree) {
2053                 wcc_attr_item = proto_tree_add_text(tree, NullTVB, offset,
2054                         END_OF_FRAME, "%s", name);
2055                 if (wcc_attr_item)
2056                         wcc_attr_tree = proto_item_add_subtree(wcc_attr_item, ett_nfs_wcc_attr);
2057         }
2058
2059         offset = dissect_size3   (pd, offset, fd, wcc_attr_tree, "size" );
2060         offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "mtime");
2061         offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "ctime");
2062         
2063         /* now we know, that wcc_attr_tree is shorter */
2064         if (wcc_attr_item) {
2065                 proto_item_set_len(wcc_attr_item, offset - old_offset);
2066         }
2067
2068         return offset;
2069 }
2070
2071
2072 /* RFC 1813, Page 24 */
2073 int
2074 dissect_pre_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2075 {
2076         proto_item* pre_op_attr_item = NULL;
2077         proto_tree* pre_op_attr_tree = NULL;
2078         int old_offset = offset;
2079         guint32 attributes_follow;
2080
2081         if (tree) {
2082                 pre_op_attr_item = proto_tree_add_text(tree, NullTVB, offset,
2083                         END_OF_FRAME, "%s", name);
2084                 if (pre_op_attr_item)
2085                         pre_op_attr_tree = proto_item_add_subtree(pre_op_attr_item, ett_nfs_pre_op_attr);
2086         }
2087
2088         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2089         attributes_follow = EXTRACT_UINT(pd, offset+0);
2090         proto_tree_add_text(pre_op_attr_tree, NullTVB, offset, 4,
2091                 "attributes_follow: %s (%u)", 
2092                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
2093         offset += 4;
2094         switch (attributes_follow) {
2095                 case TRUE:
2096                         offset = dissect_wcc_attr(pd, offset, fd, pre_op_attr_tree,
2097                                         "attributes");
2098                 break;
2099                 case FALSE:
2100                         /* void */
2101                 break;
2102         }
2103         
2104         /* now we know, that pre_op_attr_tree is shorter */
2105         if (pre_op_attr_item) {
2106                 proto_item_set_len(pre_op_attr_item, offset - old_offset);
2107         }
2108
2109         return offset;
2110 }
2111
2112
2113 /* RFC 1813, Page 24 */
2114 int
2115 dissect_wcc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2116 {
2117         proto_item* wcc_data_item = NULL;
2118         proto_tree* wcc_data_tree = NULL;
2119         int old_offset = offset;
2120
2121         if (tree) {
2122                 wcc_data_item = proto_tree_add_text(tree, NullTVB, offset,
2123                         END_OF_FRAME, "%s", name);
2124                 if (wcc_data_item)
2125                         wcc_data_tree = proto_item_add_subtree(wcc_data_item, ett_nfs_wcc_data);
2126         }
2127
2128         offset = dissect_pre_op_attr (pd, offset, fd, wcc_data_tree, "before");
2129         offset = dissect_post_op_attr(pd, offset, fd, wcc_data_tree, "after" );
2130
2131         /* now we know, that wcc_data is shorter */
2132         if (wcc_data_item) {
2133                 proto_item_set_len(wcc_data_item, offset - old_offset);
2134         }
2135
2136         return offset;
2137 }
2138
2139
2140 /* RFC 1813, Page 25 */
2141 int
2142 dissect_post_op_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2143 {
2144         proto_item* post_op_fh3_item = NULL;
2145         proto_tree* post_op_fh3_tree = NULL;
2146         int old_offset = offset;
2147         guint32 handle_follows;
2148
2149         if (tree) {
2150                 post_op_fh3_item = proto_tree_add_text(tree, NullTVB, offset,
2151                         END_OF_FRAME, "%s", name);
2152                 if (post_op_fh3_item)
2153                         post_op_fh3_tree = proto_item_add_subtree(post_op_fh3_item, ett_nfs_post_op_fh3);
2154         }
2155
2156         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2157         handle_follows = EXTRACT_UINT(pd, offset+0);
2158         proto_tree_add_text(post_op_fh3_tree, NullTVB, offset, 4,
2159                 "handle_follows: %s (%u)", 
2160                 val_to_str(handle_follows,value_follows,"Unknown"), handle_follows);
2161         offset += 4;
2162         switch (handle_follows) {
2163                 case TRUE:
2164                         offset = old_dissect_nfs_fh3(pd, offset, fd, post_op_fh3_tree,
2165                                         "handle");
2166                 break;
2167                 case FALSE:
2168                         /* void */
2169                 break;
2170         }
2171         
2172         /* now we know, that post_op_fh3_tree is shorter */
2173         if (post_op_fh3_item) {
2174                 proto_item_set_len(post_op_fh3_item, offset - old_offset);
2175         }
2176
2177         return offset;
2178 }
2179
2180
2181 /* RFC 1813, Page 25 */
2182 int
2183 dissect_set_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2184 {
2185         proto_item* set_mode3_item = NULL;
2186         proto_tree* set_mode3_tree = NULL;
2187         int old_offset = offset;
2188         guint32 set_it;
2189         char* set_it_name;
2190
2191         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2192         set_it = EXTRACT_UINT(pd, offset+0);
2193         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2194
2195         if (tree) {
2196                 set_mode3_item = proto_tree_add_text(tree, NullTVB, offset,
2197                         END_OF_FRAME, "%s: %s", name, set_it_name);
2198                 if (set_mode3_item)
2199                         set_mode3_tree = proto_item_add_subtree(set_mode3_item, ett_nfs_set_mode3);
2200         }
2201
2202         if (set_mode3_tree)
2203                 proto_tree_add_text(set_mode3_tree, NullTVB, offset, 4,
2204                         "set_it: %s (%u)", set_it_name, set_it);
2205
2206         offset += 4;
2207
2208         switch (set_it) {
2209                 case 1:
2210                         offset = dissect_mode3(pd, offset, fd, set_mode3_tree,
2211                                         "mode");
2212                 break;
2213                 default:
2214                         /* void */
2215                 break;
2216         }
2217         
2218         /* now we know, that set_mode3 is shorter */
2219         if (set_mode3_item) {
2220                 proto_item_set_len(set_mode3_item, offset - old_offset);
2221         }
2222
2223         return offset;
2224 }
2225
2226
2227 /* RFC 1813, Page 26 */
2228 int
2229 dissect_set_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2230 {
2231         proto_item* set_uid3_item = NULL;
2232         proto_tree* set_uid3_tree = NULL;
2233         int old_offset = offset;
2234         guint32 set_it;
2235         char* set_it_name;
2236
2237         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2238         set_it = EXTRACT_UINT(pd, offset+0);
2239         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2240
2241         if (tree) {
2242                 set_uid3_item = proto_tree_add_text(tree, NullTVB, offset,
2243                         END_OF_FRAME, "%s: %s", name, set_it_name);
2244                 if (set_uid3_item)
2245                         set_uid3_tree = proto_item_add_subtree(set_uid3_item, ett_nfs_set_uid3);
2246         }
2247
2248         if (set_uid3_tree)
2249                 proto_tree_add_text(set_uid3_tree, NullTVB, offset, 4,
2250                         "set_it: %s (%u)", set_it_name, set_it);
2251
2252         offset += 4;
2253
2254         switch (set_it) {
2255                 case 1:
2256                         offset = dissect_uid3(pd, offset, fd, set_uid3_tree,
2257                                         "uid");
2258                 break;
2259                 default:
2260                         /* void */
2261                 break;
2262         }
2263
2264         /* now we know, that set_uid3 is shorter */
2265         if (set_uid3_item) {
2266                 proto_item_set_len(set_uid3_item, offset - old_offset);
2267         }
2268
2269         return offset;
2270 }
2271
2272
2273 /* RFC 1813, Page 26 */
2274 int
2275 dissect_set_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2276 {
2277         proto_item* set_gid3_item = NULL;
2278         proto_tree* set_gid3_tree = NULL;
2279         int old_offset = offset;
2280         guint32 set_it;
2281         char* set_it_name;
2282
2283         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2284         set_it = EXTRACT_UINT(pd, offset+0);
2285         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2286
2287         if (tree) {
2288                 set_gid3_item = proto_tree_add_text(tree, NullTVB, offset,
2289                         END_OF_FRAME, "%s: %s", name, set_it_name);
2290                 if (set_gid3_item)
2291                         set_gid3_tree = proto_item_add_subtree(set_gid3_item, ett_nfs_set_gid3);
2292         }
2293
2294         if (set_gid3_tree)
2295                 proto_tree_add_text(set_gid3_tree, NullTVB, offset, 4,
2296                         "set_it: %s (%u)", set_it_name, set_it);
2297
2298         offset += 4;
2299
2300         switch (set_it) {
2301                 case 1:
2302                         offset = dissect_gid3(pd, offset, fd, set_gid3_tree,
2303                                         "gid");
2304                 break;
2305                 default:
2306                         /* void */
2307                 break;
2308         }
2309
2310         /* now we know, that set_gid3 is shorter */
2311         if (set_gid3_item) {
2312                 proto_item_set_len(set_gid3_item, offset - old_offset);
2313         }
2314
2315         return offset;
2316 }
2317
2318
2319 /* RFC 1813, Page 26 */
2320 int
2321 dissect_set_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2322 {
2323         proto_item* set_size3_item = NULL;
2324         proto_tree* set_size3_tree = NULL;
2325         int old_offset = offset;
2326         guint32 set_it;
2327         char* set_it_name;
2328
2329         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2330         set_it = EXTRACT_UINT(pd, offset+0);
2331         set_it_name = val_to_str(set_it,value_follows,"Unknown");
2332
2333         if (tree) {
2334                 set_size3_item = proto_tree_add_text(tree, NullTVB, offset,
2335                         END_OF_FRAME, "%s: %s", name, set_it_name);
2336                 if (set_size3_item)
2337                         set_size3_tree = proto_item_add_subtree(set_size3_item, ett_nfs_set_size3);
2338         }
2339
2340         if (set_size3_tree)
2341                 proto_tree_add_text(set_size3_tree, NullTVB, offset, 4,
2342                         "set_it: %s (%u)", set_it_name, set_it);
2343
2344         offset += 4;
2345
2346         switch (set_it) {
2347                 case 1:
2348                         offset = dissect_size3(pd, offset, fd, set_size3_tree,
2349                                         "size");
2350                 break;
2351                 default:
2352                         /* void */
2353                 break;
2354         }
2355
2356         /* now we know, that set_size3 is shorter */
2357         if (set_size3_item) {
2358                 proto_item_set_len(set_size3_item, offset - old_offset);
2359         }
2360
2361         return offset;
2362 }
2363
2364
2365 /* RFC 1813, Page 25 */
2366 #define DONT_CHANGE 0
2367 #define SET_TO_SERVER_TIME 1
2368 #define SET_TO_CLIENT_TIME 2
2369
2370 const value_string time_how[] =
2371         {
2372                 { DONT_CHANGE,  "don't change" },
2373                 { SET_TO_SERVER_TIME, "set to server time" },
2374                 { SET_TO_CLIENT_TIME, "set to client time" },
2375                 { 0, NULL }
2376         };
2377
2378
2379 /* RFC 1813, Page 26 */
2380 int
2381 dissect_set_atime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2382 {
2383         proto_item* set_atime_item = NULL;
2384         proto_tree* set_atime_tree = NULL;
2385         int old_offset = offset;
2386         guint32 set_it;
2387         char* set_it_name;
2388
2389         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2390         set_it = EXTRACT_UINT(pd, offset+0);
2391         set_it_name = val_to_str(set_it,time_how,"Unknown");
2392
2393         if (tree) {
2394                 set_atime_item = proto_tree_add_text(tree, NullTVB, offset,
2395                         END_OF_FRAME, "%s: %s",
2396                         name, set_it_name);
2397                 if (set_atime_item)
2398                         set_atime_tree = proto_item_add_subtree(set_atime_item, ett_nfs_set_atime);
2399         }
2400
2401         if (set_atime_tree)
2402                 proto_tree_add_text(set_atime_tree, NullTVB, offset, 4,
2403                         "set_it: %s (%u)", set_it_name, set_it);
2404
2405         offset += 4;
2406
2407         switch (set_it) {
2408                 case SET_TO_CLIENT_TIME:
2409                         if (set_atime_item)
2410                         offset = dissect_nfstime3(pd, offset, fd, set_atime_tree,
2411                                         "atime");
2412                 break;
2413                 default:
2414                         /* void */
2415                 break;
2416         }
2417
2418         /* now we know, that set_atime is shorter */
2419         if (set_atime_item) {
2420                 proto_item_set_len(set_atime_item, offset - old_offset);
2421         }
2422
2423         return offset;
2424 }
2425
2426
2427 /* RFC 1813, Page 26 */
2428 int
2429 dissect_set_mtime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2430 {
2431         proto_item* set_mtime_item = NULL;
2432         proto_tree* set_mtime_tree = NULL;
2433         int old_offset = offset;
2434         guint32 set_it;
2435         char* set_it_name;
2436
2437         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2438         set_it = EXTRACT_UINT(pd, offset+0);
2439         set_it_name = val_to_str(set_it,time_how,"Unknown");
2440
2441         if (tree) {
2442                 set_mtime_item = proto_tree_add_text(tree, NullTVB, offset,
2443                         END_OF_FRAME, "%s: %s",
2444                         name, set_it_name);
2445                 if (set_mtime_item)
2446                         set_mtime_tree = proto_item_add_subtree(set_mtime_item, ett_nfs_set_mtime);
2447         }
2448
2449         if (set_mtime_tree)
2450                 proto_tree_add_text(set_mtime_tree, NullTVB, offset, 4,
2451                                 "set_it: %s (%u)", set_it_name, set_it);
2452
2453         offset += 4;
2454
2455         switch (set_it) {
2456                 case SET_TO_CLIENT_TIME:
2457                         if (set_mtime_item)
2458                         offset = dissect_nfstime3(pd, offset, fd, set_mtime_tree,
2459                                         "atime");
2460                 break;
2461                 default:
2462                         /* void */
2463                 break;
2464         }
2465
2466         /* now we know, that set_mtime is shorter */
2467         if (set_mtime_item) {
2468                 proto_item_set_len(set_mtime_item, offset - old_offset);
2469         }
2470
2471         return offset;
2472 }
2473
2474
2475 /* RFC 1813, Page 25..27 */
2476 int
2477 dissect_sattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2478 {
2479         proto_item* sattr3_item = NULL;
2480         proto_tree* sattr3_tree = NULL;
2481         int old_offset = offset;
2482
2483         if (tree) {
2484                 sattr3_item = proto_tree_add_text(tree, NullTVB, offset,
2485                         END_OF_FRAME, "%s", name);
2486                 if (sattr3_item)
2487                         sattr3_tree = proto_item_add_subtree(sattr3_item, ett_nfs_sattr3);
2488         }
2489
2490         offset = dissect_set_mode3(pd, offset, fd, sattr3_tree, "mode");
2491         offset = dissect_set_uid3 (pd, offset, fd, sattr3_tree, "uid");
2492         offset = dissect_set_gid3 (pd, offset, fd, sattr3_tree, "gid");
2493         offset = dissect_set_size3(pd, offset, fd, sattr3_tree, "size");
2494         offset = dissect_set_atime(pd, offset, fd, sattr3_tree, "atime");
2495         offset = dissect_set_mtime(pd, offset, fd, sattr3_tree, "mtime");
2496
2497         /* now we know, that sattr3 is shorter */
2498         if (sattr3_item) {
2499                 proto_item_set_len(sattr3_item, offset - old_offset);
2500         }
2501
2502         return offset;
2503 }
2504
2505
2506 /* RFC 1813, Page 27 */
2507 int
2508 dissect_diropargs3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2509 {
2510         proto_item* diropargs3_item = NULL;
2511         proto_tree* diropargs3_tree = NULL;
2512         int old_offset = offset;
2513
2514         if (tree) {
2515                 diropargs3_item = proto_tree_add_text(tree, NullTVB, offset,
2516                         END_OF_FRAME, "%s", name);
2517                 if (diropargs3_item)
2518                         diropargs3_tree = proto_item_add_subtree(diropargs3_item, ett_nfs_diropargs3);
2519         }
2520
2521         offset = old_dissect_nfs_fh3  (pd, offset, fd, diropargs3_tree, "dir");
2522         offset = dissect_filename3(pd, offset, fd, diropargs3_tree, hf_nfs_name,NULL);
2523
2524         /* now we know, that diropargs3 is shorter */
2525         if (diropargs3_item) {
2526                 proto_item_set_len(diropargs3_item, offset - old_offset);
2527         }
2528
2529         return offset;
2530 }
2531
2532
2533 /* RFC 1813, Page 27 */
2534 int
2535 dissect_nfs3_diropargs3_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
2536 {
2537         offset = dissect_diropargs3(pd, offset, fd, tree, "object");
2538
2539         return offset;
2540 }
2541
2542
2543 /* RFC 1813, Page 40 */
2544 int
2545 dissect_access(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
2546 {
2547         guint32 access;
2548         proto_item* access_item = NULL;
2549         proto_tree* access_tree = NULL;
2550
2551         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2552         access = EXTRACT_UINT(pd, offset+0);
2553         
2554         if (tree) {
2555                 access_item = proto_tree_add_text(tree, NullTVB, offset, 4,
2556                         "%s: 0x%02x", name, access);
2557                 if (access_item)
2558                         access_tree = proto_item_add_subtree(access_item, ett_nfs_access);
2559         }
2560
2561         if (access_tree) {
2562                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s READ",
2563                 decode_boolean_bitfield(access,  0x001, 6, "allow", "not allow"));
2564                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s LOOKUP",
2565                 decode_boolean_bitfield(access,  0x002, 6, "allow", "not allow"));
2566                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s MODIFY",
2567                 decode_boolean_bitfield(access,  0x004, 6, "allow", "not allow"));
2568                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s EXTEND",
2569                 decode_boolean_bitfield(access,  0x008, 6, "allow", "not allow"));
2570                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s DELETE",
2571                 decode_boolean_bitfield(access,  0x010, 6, "allow", "not allow"));
2572                 proto_tree_add_text(access_tree, NullTVB, offset, 4, "%s EXECUTE",
2573                 decode_boolean_bitfield(access,  0x020, 6, "allow", "not allow"));
2574         }
2575
2576         offset += 4;
2577         return offset;
2578 }
2579
2580
2581 /* NFS3 file handle dissector */
2582 int
2583 dissect_nfs3_nfs_fh3_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2584 {
2585         offset = old_dissect_nfs_fh3(pd, offset, fd, tree, "object");
2586         return offset;
2587 }
2588
2589
2590 /* generic NFS3 reply dissector */
2591 int
2592 dissect_nfs3_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2593 {
2594         guint32 status;
2595
2596         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2597
2598         return offset;
2599
2600 }
2601
2602
2603 /* RFC 1813, Page 32,33 */
2604 int
2605 dissect_nfs3_getattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2606 {
2607         offset = old_dissect_nfs_fh3(pd, offset, fd, tree, "object");
2608         return offset;
2609 }
2610
2611
2612 /* RFC 1813, Page 32,33 */
2613 int
2614 dissect_nfs3_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2615 {
2616         guint32 status;
2617
2618         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2619         switch (status) {
2620                 case 0:
2621                         offset = dissect_fattr3(pd, offset, fd, tree, "obj_attributes");
2622                 break;
2623                 default:
2624                         /* void */
2625                 break;
2626         }
2627                 
2628         return offset;
2629 }
2630
2631
2632 /* RFC 1813, Page 33 */
2633 int
2634 dissect_sattrguard3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, char *name)
2635 {
2636         proto_item* sattrguard3_item = NULL;
2637         proto_tree* sattrguard3_tree = NULL;
2638         int old_offset = offset;
2639         guint32 check;
2640         char* check_name;
2641
2642         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2643         check = EXTRACT_UINT(pd, offset+0);
2644         check_name = val_to_str(check,value_follows,"Unknown");
2645
2646         if (tree) {
2647                 sattrguard3_item = proto_tree_add_text(tree, NullTVB, offset,
2648                         END_OF_FRAME, "%s: %s", name, check_name);
2649                 if (sattrguard3_item)
2650                         sattrguard3_tree = proto_item_add_subtree(sattrguard3_item, ett_nfs_sattrguard3);
2651         }
2652
2653         if (sattrguard3_tree)
2654                 proto_tree_add_text(sattrguard3_tree, NullTVB, offset, 4,
2655                         "check: %s (%u)", check_name, check);
2656
2657         offset += 4;
2658
2659         switch (check) {
2660                 case TRUE:
2661                         offset = dissect_nfstime3(pd, offset, fd, sattrguard3_tree,
2662                                         "obj_ctime");
2663                 break;
2664                 case FALSE:
2665                         /* void */
2666                 break;
2667         }
2668
2669         /* now we know, that sattrguard3 is shorter */
2670         if (sattrguard3_item) {
2671                 proto_item_set_len(sattrguard3_item, offset - old_offset);
2672         }
2673
2674         return offset;
2675 }
2676
2677
2678 /* RFC 1813, Page 33..36 */
2679 int
2680 dissect_nfs3_setattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2681 {
2682         offset = old_dissect_nfs_fh3    (pd, offset, fd, tree, "object");
2683         offset = dissect_sattr3     (pd, offset, fd, tree, "new_attributes");
2684         offset = dissect_sattrguard3(pd, offset, fd, tree, "guard");
2685         return offset;
2686 }
2687
2688
2689 /* RFC 1813, Page 33..36 */
2690 int
2691 dissect_nfs3_setattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2692 {
2693         guint32 status;
2694
2695         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2696         switch (status) {
2697                 case 0:
2698                         offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
2699                 break;
2700                 default:
2701                         offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
2702                 break;
2703         }
2704                 
2705         return offset;
2706 }
2707
2708
2709 /* RFC 1813, Page 37..39 */
2710 int
2711 dissect_nfs3_lookup_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2712 {
2713         offset = dissect_diropargs3 (pd, offset, fd, tree, "what");
2714         return offset;
2715 }
2716
2717
2718 /* RFC 1813, Page 37..39 */
2719 int
2720 dissect_nfs3_lookup_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2721 {
2722         guint32 status;
2723
2724         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2725         switch (status) {
2726                 case 0:
2727                         offset = old_dissect_nfs_fh3     (pd, offset, fd, tree, "object");
2728                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2729                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2730                 break;
2731                 default:
2732                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2733                 break;
2734         }
2735                 
2736         return offset;
2737 }
2738
2739
2740 /* RFC 1813, Page 40..43 */
2741 int
2742 dissect_nfs3_access_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2743 {
2744         offset = old_dissect_nfs_fh3(pd, offset, fd, tree, "object");
2745         offset = dissect_access (pd, offset, fd, tree, "access");
2746
2747         return offset;
2748 }
2749
2750
2751 /* RFC 1813, Page 40..43 */
2752 int
2753 dissect_nfs3_access_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2754 {
2755         guint32 status;
2756
2757         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2758         switch (status) {
2759                 case 0:
2760                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2761                         offset = dissect_access      (pd, offset, fd, tree, "access");
2762                 break;
2763                 default:
2764                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2765                 break;
2766         }
2767                 
2768         return offset;
2769 }
2770
2771
2772 /* RFC 1813, Page 44,45 */
2773 int
2774 dissect_nfs3_readlink_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2775 {
2776         guint32 status;
2777
2778         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2779         switch (status) {
2780                 case 0:
2781                         offset = dissect_post_op_attr(pd, offset, fd, tree, "symlink_attributes");
2782                         offset = dissect_nfspath3    (pd, offset, fd, tree, hf_nfs_readlink_data);
2783                 break;
2784                 default:
2785                         offset = dissect_post_op_attr(pd, offset, fd, tree, "symlink_attributes");
2786                 break;
2787         }
2788                 
2789         return offset;
2790 }
2791
2792
2793 /* RFC 1813, Page 46..48 */
2794 int
2795 dissect_nfs3_read_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2796 {
2797         offset = old_dissect_nfs_fh3(pd, offset, fd, tree, "file");
2798         offset = dissect_offset3(pd, offset, fd, tree, "offset");
2799         offset = dissect_count3 (pd, offset, fd, tree, "count");
2800
2801         return offset;
2802 }
2803
2804
2805 /* RFC 1813, Page 46..48 */
2806 int
2807 dissect_nfs3_read_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2808 {
2809         guint32 status;
2810
2811         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2812         switch (status) {
2813                 case 0:
2814                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2815                         offset = dissect_count3      (pd, offset, fd, tree, "count");
2816                         offset = dissect_rpc_bool    (pd, offset, fd, tree, hf_nfs_read_eof);
2817                         offset = dissect_nfsdata     (pd, offset, fd, tree, hf_nfs_data);
2818                 break;
2819                 default:
2820                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2821                 break;
2822         }
2823                 
2824         return offset;
2825 }
2826
2827
2828 /* RFC 1813, Page 49 */
2829 static const value_string names_stable_how[] = {
2830         {       UNSTABLE,  "UNSTABLE"  },
2831         {       DATA_SYNC, "DATA_SYNC" },
2832         {       FILE_SYNC, "FILE_SYNC" },
2833         { 0, NULL }
2834 };
2835
2836
2837 /* RFC 1813, Page 49 */
2838 int
2839 dissect_stable_how(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, int hfindex)
2840 {
2841         guint32 stable_how;
2842
2843         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2844         stable_how = EXTRACT_UINT(pd,offset+0);
2845         if (tree) {
2846                 proto_tree_add_uint(tree, hfindex, NullTVB,
2847                         offset, 4, stable_how); 
2848         }
2849         offset += 4;
2850
2851         return offset;
2852 }
2853
2854
2855 /* RFC 1813, Page 49..54 */
2856 int
2857 dissect_nfs3_write_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2858 {
2859         offset = old_dissect_nfs_fh3   (pd, offset, fd, tree, "file");
2860         offset = dissect_offset3   (pd, offset, fd, tree, "offset");
2861         offset = dissect_count3    (pd, offset, fd, tree, "count");
2862         offset = dissect_stable_how(pd, offset, fd, tree, hf_nfs_write_stable);
2863         offset = dissect_nfsdata   (pd, offset, fd, tree, hf_nfs_data);
2864
2865         return offset;
2866 }
2867
2868
2869 /* RFC 1813, Page 49..54 */
2870 int
2871 dissect_nfs3_write_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2872 {
2873         guint32 status;
2874
2875         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2876         switch (status) {
2877                 case 0:
2878                         offset = dissect_wcc_data  (pd, offset, fd, tree, "file_wcc");
2879                         offset = dissect_count3    (pd, offset, fd, tree, "count");
2880                         offset = dissect_stable_how(pd, offset, fd, tree, hf_nfs_write_committed);
2881                         offset = dissect_writeverf3(pd, offset, fd, tree);
2882                 break;
2883                 default:
2884                         offset = dissect_wcc_data(pd, offset, fd, tree, "file_wcc");
2885                 break;
2886         }
2887                 
2888         return offset;
2889 }
2890
2891
2892 /* RFC 1813, Page 54 */
2893 static const value_string names_createmode3[] = {
2894         {       UNCHECKED, "UNCHECKED" },
2895         {       GUARDED,   "GUARDED" },
2896         {       EXCLUSIVE, "EXCLUSIVE" },
2897         { 0, NULL }
2898 };
2899
2900
2901 /* RFC 1813, Page 54 */
2902 int
2903 dissect_createmode3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, guint32* mode)
2904 {
2905         guint32 mode_value;
2906         
2907         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
2908         mode_value = EXTRACT_UINT(pd, offset + 0);
2909         if (tree) {
2910                 proto_tree_add_uint(tree, hf_nfs_createmode3, NullTVB,
2911                 offset+0, 4, mode_value);
2912         }
2913         offset += 4;
2914
2915         *mode = mode_value;
2916         return offset;
2917 }
2918
2919
2920 /* RFC 1813, Page 54..58 */
2921 int
2922 dissect_nfs3_create_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2923 {
2924         guint32 mode;
2925
2926         offset = dissect_diropargs3 (pd, offset, fd, tree, "where");
2927         offset = dissect_createmode3(pd, offset, fd, tree, &mode);
2928         switch (mode) {
2929                 case UNCHECKED:
2930                 case GUARDED:
2931                         offset = dissect_sattr3     (pd, offset, fd, tree, "obj_attributes");
2932                 break;
2933                 case EXCLUSIVE:
2934                         offset = dissect_createverf3(pd, offset, fd, tree);
2935                 break;
2936         }
2937         
2938         return offset;
2939 }
2940
2941
2942 /* RFC 1813, Page 54..58 */
2943 int
2944 dissect_nfs3_create_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2945 {
2946         guint32 status;
2947
2948         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2949         switch (status) {
2950                 case 0:
2951                         offset = dissect_post_op_fh3 (pd, offset, fd, tree, "obj");
2952                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2953                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2954                 break;
2955                 default:
2956                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2957                 break;
2958         }
2959                 
2960         return offset;
2961 }
2962
2963
2964 /* RFC 1813, Page 58..60 */
2965 int
2966 dissect_nfs3_mkdir_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2967 {
2968         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2969         offset = dissect_sattr3    (pd, offset, fd, tree, "attributes");
2970         
2971         return offset;
2972 }
2973
2974
2975 /* RFC 1813, Page 61..63 */
2976 int
2977 dissect_nfs3_symlink_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2978 {
2979         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2980         offset = dissect_sattr3    (pd, offset, fd, tree, "symlink_attributes");
2981         offset = dissect_nfspath3  (pd, offset, fd, tree, hf_nfs_symlink_to);
2982         
2983         return offset;
2984 }
2985
2986
2987 /* RFC 1813, Page 63..66 */
2988 int
2989 dissect_nfs3_mknod_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2990 {
2991         guint32 type;
2992
2993         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2994         offset = dissect_ftype3(pd, offset, fd, tree, hf_nfs_ftype3, &type);
2995         switch (type) {
2996                 case NF3CHR:
2997                 case NF3BLK:
2998                         offset = dissect_sattr3(pd, offset, fd, tree, "dev_attributes");
2999                         offset = dissect_specdata3(pd, offset, fd, tree, "spec");
3000                 break;
3001                 case NF3SOCK:
3002                 case NF3FIFO:
3003                         offset = dissect_sattr3(pd, offset, fd, tree, "pipe_attributes");
3004                 break;
3005                 default:
3006                         /* nothing to do */
3007                 break;
3008         }
3009         
3010         return offset;
3011 }
3012
3013
3014 /* RFC 1813, Page 67..69 */
3015 int
3016 dissect_nfs3_remove_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3017 {
3018         guint32 status;
3019
3020         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3021         switch (status) {
3022                 case 0:
3023                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
3024                 break;
3025                 default:
3026                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
3027                 break;
3028         }
3029                 
3030         return offset;
3031 }
3032
3033
3034 /* RFC 1813, Page 71..74 */
3035 int
3036 dissect_nfs3_rename_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3037 {
3038         offset = dissect_diropargs3(pd, offset, fd, tree, "from");
3039         offset = dissect_diropargs3(pd, offset, fd, tree, "to");
3040         
3041         return offset;
3042 }
3043
3044
3045 /* RFC 1813, Page 71..74 */
3046 int
3047 dissect_nfs3_rename_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3048 {
3049         guint32 status;
3050
3051         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3052         switch (status) {
3053                 case 0:
3054                         offset = dissect_wcc_data(pd, offset, fd, tree, "fromdir_wcc");
3055                         offset = dissect_wcc_data(pd, offset, fd, tree, "todir_wcc");
3056                 break;
3057                 default:
3058                         offset = dissect_wcc_data(pd, offset, fd, tree, "fromdir_wcc");
3059                         offset = dissect_wcc_data(pd, offset, fd, tree, "todir_wcc");
3060                 break;
3061         }
3062                 
3063         return offset;
3064 }
3065
3066
3067 /* RFC 1813, Page 74..76 */
3068 int
3069 dissect_nfs3_link_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3070 {
3071         offset = old_dissect_nfs_fh3   (pd, offset, fd, tree, "file");
3072         offset = dissect_diropargs3(pd, offset, fd, tree, "link");
3073         
3074         return offset;
3075 }
3076
3077
3078 /* RFC 1813, Page 74..76 */
3079 int
3080 dissect_nfs3_link_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3081 {
3082         guint32 status;
3083
3084         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3085         switch (status) {
3086                 case 0:
3087                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
3088                         offset = dissect_wcc_data    (pd, offset, fd, tree, "linkdir_wcc");
3089                 break;
3090                 default:
3091                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
3092                         offset = dissect_wcc_data    (pd, offset, fd, tree, "linkdir_wcc");
3093                 break;
3094         }
3095                 
3096         return offset;
3097 }
3098
3099
3100 /* RFC 1813, Page 76..80 */
3101 int
3102 dissect_nfs3_readdir_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3103 {
3104         offset = old_dissect_nfs_fh3    (pd, offset, fd, tree, "dir");
3105         offset = dissect_cookie3    (pd, offset, fd, tree, "cookie");
3106         offset = dissect_cookieverf3(pd, offset, fd, tree);
3107         offset = dissect_count3     (pd, offset, fd, tree, "count");
3108         
3109         return offset;
3110 }
3111
3112
3113 /* RFC 1813, Page 76..80 */
3114 int
3115 dissect_entry3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3116 {
3117         proto_item* entry_item = NULL;
3118         proto_tree* entry_tree = NULL;
3119         int old_offset = offset;
3120         char *name;
3121
3122         if (tree) {
3123                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, NullTVB,
3124                         offset+0, END_OF_FRAME, FALSE);
3125                 if (entry_item)
3126                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
3127         }
3128
3129         offset = dissect_fileid3(pd, offset, fd, entry_tree, "fileid");
3130
3131         offset = dissect_filename3(pd, offset, fd, entry_tree,
3132                 hf_nfs_readdir_entry_name, &name);
3133         if (entry_item)
3134                 proto_item_set_text(entry_item, "Entry: name %s", name);
3135         g_free(name);
3136
3137         offset = dissect_cookie3(pd, offset, fd, entry_tree, "cookie");
3138
3139         /* now we know, that a readdir entry is shorter */
3140         if (entry_item) {
3141                 proto_item_set_len(entry_item, offset - old_offset);
3142         }
3143
3144         return offset;
3145 }
3146
3147
3148 /* RFC 1813, Page 76..80 */
3149 int
3150 dissect_nfs3_readdir_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3151 {
3152         guint32 status;
3153         guint32 eof_value;
3154
3155         offset = dissect_stat(pd, offset, fd, tree, &status);
3156         switch (status) {
3157                 case 0:
3158                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
3159                         offset = dissect_cookieverf3(pd, offset, fd, tree);
3160                         offset = dissect_rpc_list(pd, offset, fd, tree,
3161                                 dissect_entry3);
3162                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3163                         eof_value = EXTRACT_UINT(pd, offset+0);
3164                         if (tree)
3165                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, NullTVB,
3166                                         offset+ 0, 4, eof_value);
3167                         offset += 4;
3168                 break;
3169                 default:
3170                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
3171                 break;
3172         }
3173
3174         return offset;
3175 }
3176
3177
3178 /* RFC 1813, Page 80..83 */
3179 int
3180 dissect_nfs3_readdirplus_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3181 {
3182         offset = old_dissect_nfs_fh3    (pd, offset, fd, tree, "dir");
3183         offset = dissect_cookie3    (pd, offset, fd, tree, "cookie");
3184         offset = dissect_cookieverf3(pd, offset, fd, tree);
3185         offset = dissect_count3     (pd, offset, fd, tree, "dircount");
3186         offset = dissect_count3     (pd, offset, fd, tree, "maxcount");
3187         
3188         return offset;
3189 }
3190
3191
3192 /* RFC 1813, Page 80..83 */
3193 int
3194 dissect_entryplus3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3195 {
3196         proto_item* entry_item = NULL;
3197         proto_tree* entry_tree = NULL;
3198         int old_offset = offset;
3199         char *name;
3200
3201         if (tree) {
3202                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, NullTVB,
3203                         offset+0, END_OF_FRAME, FALSE);
3204                 if (entry_item)
3205                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
3206         }
3207
3208         offset = dissect_fileid3(pd, offset, fd, entry_tree, "fileid");
3209
3210         offset = dissect_filename3(pd, offset, fd, entry_tree,
3211                 hf_nfs_readdirplus_entry_name, &name);
3212         if (entry_item)
3213                 proto_item_set_text(entry_item, "Entry: name %s", name);
3214         g_free(name);
3215
3216         offset = dissect_cookie3(pd, offset, fd, entry_tree, "cookie");
3217
3218         offset = dissect_post_op_attr(pd, offset, fd, entry_tree, "name_attributes");
3219         offset = dissect_post_op_fh3(pd, offset, fd, entry_tree, "name_handle");
3220
3221         /* now we know, that a readdirplus entry is shorter */
3222         if (entry_item) {
3223                 proto_item_set_len(entry_item, offset - old_offset);
3224         }
3225
3226         return offset;
3227 }
3228
3229
3230 /* RFC 1813, Page 80..83 */
3231 int
3232 dissect_nfs3_readdirplus_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3233 {
3234         guint32 status;
3235         guint32 eof_value;
3236
3237         offset = dissect_stat(pd, offset, fd, tree, &status);
3238         switch (status) {
3239                 case 0:
3240                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
3241                         offset = dissect_cookieverf3(pd, offset, fd, tree);
3242                         offset = dissect_rpc_list(pd, offset, fd, tree,
3243                                 dissect_entryplus3);
3244                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3245                         eof_value = EXTRACT_UINT(pd, offset+0);
3246                         if (tree)
3247                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, NullTVB,
3248                                         offset+ 0, 4, eof_value);
3249                         offset += 4;
3250                 break;
3251                 default:
3252                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
3253                 break;
3254         }
3255
3256         return offset;
3257 }
3258
3259
3260 /* RFC 1813, Page 84..86 */
3261 int
3262 dissect_nfs3_fsstat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3263 {
3264         guint32 status;
3265         guint32 invarsec;
3266
3267         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3268         switch (status) {
3269                 case 0:
3270                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3271                         offset = dissect_size3 (pd, offset, fd, tree, "tbytes");
3272                         offset = dissect_size3 (pd, offset, fd, tree, "fbytes");
3273                         offset = dissect_size3 (pd, offset, fd, tree, "abytes");
3274                         offset = dissect_size3 (pd, offset, fd, tree, "tfiles");
3275                         offset = dissect_size3 (pd, offset, fd, tree, "ffiles");
3276                         offset = dissect_size3 (pd, offset, fd, tree, "afiles");
3277                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3278                         invarsec = EXTRACT_UINT(pd, offset + 0);
3279                         if (tree)
3280                                 proto_tree_add_uint(tree, hf_nfs_fsstat_invarsec, NullTVB,
3281                                 offset+0, 4, invarsec);
3282                         offset += 4;
3283                 break;
3284                 default:
3285                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3286                 break;
3287         }
3288
3289         return offset;
3290 }
3291
3292
3293 #define FSF3_LINK        0x0001
3294 #define FSF3_SYMLINK     0x0002
3295 #define FSF3_HOMOGENEOUS 0x0008
3296 #define FSF3_CANSETTIME  0x0010
3297
3298
3299 /* RFC 1813, Page 86..90 */
3300 int
3301 dissect_nfs3_fsinfo_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3302 {
3303         guint32 status;
3304         guint32 rtmax;
3305         guint32 rtpref;
3306         guint32 rtmult;
3307         guint32 wtmax;
3308         guint32 wtpref;
3309         guint32 wtmult;
3310         guint32 dtpref;
3311         guint32 properties;
3312         proto_item*     properties_item = NULL;
3313         proto_tree*     properties_tree = NULL;
3314
3315         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3316         switch (status) {
3317                 case 0:
3318                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3319                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3320                         rtmax = EXTRACT_UINT(pd, offset+0);
3321                         if (tree)
3322                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtmax, NullTVB,
3323                                 offset+0, 4, rtmax);
3324                         offset += 4;
3325                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3326                         rtpref = EXTRACT_UINT(pd, offset+0);
3327                         if (tree)
3328                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtpref, NullTVB,
3329                                 offset+0, 4, rtpref);
3330                         offset += 4;
3331                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3332                         rtmult = EXTRACT_UINT(pd, offset+0);
3333                         if (tree)
3334                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtmult, NullTVB,
3335                                 offset+0, 4, rtmult);
3336                         offset += 4;
3337                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3338                         wtmax = EXTRACT_UINT(pd, offset+0);
3339                         if (tree)
3340                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtmax, NullTVB,
3341                                 offset+0, 4, wtmax);
3342                         offset += 4;
3343                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3344                         wtpref = EXTRACT_UINT(pd, offset+0);
3345                         if (tree)
3346                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtpref, NullTVB,
3347                                 offset+0, 4, wtpref);
3348                         offset += 4;
3349                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3350                         wtmult = EXTRACT_UINT(pd, offset+0);
3351                         if (tree)
3352                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtmult, NullTVB,
3353                                 offset+0, 4, wtmult);
3354                         offset += 4;
3355                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3356                         dtpref = EXTRACT_UINT(pd, offset+0);
3357                         if (tree)
3358                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_dtpref, NullTVB,
3359                                 offset+0, 4, dtpref);
3360                         offset += 4;
3361
3362                         offset = dissect_size3   (pd, offset, fd, tree, "maxfilesize");
3363                         offset = dissect_nfstime3(pd, offset, fd, tree, "time_delta");
3364                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
3365                         properties = EXTRACT_UINT(pd, offset+0);
3366                         if (tree) {
3367                                 properties_item = proto_tree_add_uint(tree,
3368                                 hf_nfs_fsinfo_properties,
3369                                 NullTVB, offset+0, 4, properties);
3370                                 if (properties_item) 
3371                                         properties_tree = proto_item_add_subtree(properties_item, ett_nfs_fsinfo_properties);
3372                                 if (properties_tree) {
3373                                         proto_tree_add_text(properties_tree, NullTVB,
3374                                         offset, 4, "%s",
3375                                         decode_boolean_bitfield(properties,
3376                                         FSF3_CANSETTIME,5,
3377                                         "SETATTR can set time on server",
3378                                         "SETATTR can't set time on server"));
3379
3380                                         proto_tree_add_text(properties_tree, NullTVB,
3381                                         offset, 4, "%s",
3382                                         decode_boolean_bitfield(properties,
3383                                         FSF3_HOMOGENEOUS,5,
3384                                         "PATHCONF is valid for all files",
3385                                         "PATHCONF should be get for every single file"));
3386
3387                                         proto_tree_add_text(properties_tree, NullTVB,
3388                                         offset, 4, "%s",
3389                                         decode_boolean_bitfield(properties,
3390                                         FSF3_SYMLINK,5,
3391                                         "File System supports symbolic links",
3392                                         "File System does not symbolic hard links"));
3393
3394                                         proto_tree_add_text(properties_tree, NullTVB,
3395                                         offset, 4, "%s",
3396                                         decode_boolean_bitfield(properties,
3397                                         FSF3_LINK,5,
3398                                         "File System supports hard links",
3399                                         "File System does not support hard links"));
3400                                 }
3401                         }
3402                         offset += 4;
3403                 break;
3404                 default:
3405                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3406                 break;
3407         }
3408
3409         return offset;
3410 }
3411
3412
3413 /* RFC 1813, Page 90..92 */
3414 int
3415 dissect_nfs3_pathconf_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3416 {
3417         guint32 status;
3418         guint32 linkmax;
3419         guint32 name_max;
3420
3421         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3422         switch (status) {
3423                 case 0:
3424                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3425                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3426                         linkmax = EXTRACT_UINT(pd, offset + 0);
3427                         if (tree)
3428                                 proto_tree_add_uint(tree, hf_nfs_pathconf_linkmax, NullTVB,
3429                                 offset+0, 4, linkmax);
3430                         offset += 4;
3431                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3432                         name_max = EXTRACT_UINT(pd, offset + 0);
3433                         if (tree)
3434                                 proto_tree_add_uint(tree, hf_nfs_pathconf_name_max, NullTVB,
3435                                 offset+0, 4, name_max);
3436                         offset += 4;
3437                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_no_trunc);
3438                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_chown_restricted);
3439                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_case_insensitive);
3440                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_case_preserving);
3441                 break;
3442                 default:
3443                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
3444                 break;
3445         }
3446
3447         return offset;
3448 }
3449
3450
3451 /* RFC 1813, Page 92..95 */
3452 int
3453 dissect_nfs3_commit_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3454 {
3455         offset = old_dissect_nfs_fh3(pd, offset, fd, tree, "file");
3456         offset = dissect_offset3(pd, offset, fd, tree, "offset");
3457         offset = dissect_count3 (pd, offset, fd, tree, "count");
3458         
3459         return offset;
3460 }
3461
3462
3463 /* RFC 1813, Page 92..95 */
3464 int
3465 dissect_nfs3_commit_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
3466 {
3467         guint32 status;
3468
3469         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
3470         switch (status) {
3471                 case 0:
3472                         offset = dissect_wcc_data  (pd, offset, fd, tree, "file_wcc");
3473                         offset = dissect_writeverf3(pd, offset, fd, tree);
3474                 break;
3475                 default:
3476                         offset = dissect_wcc_data(pd, offset, fd, tree, "file_wcc");
3477                 break;
3478         }
3479                 
3480         return offset;
3481 }
3482
3483 /* 1 missing functions */
3484
3485 /* NFS Version 4 Protocol Draft Specification 07 */
3486
3487 int
3488 dissect_nfs_utf8string(const u_char *pd, int offset, frame_data *fd,
3489         proto_tree *tree, int hf, char **string_ret)
3490 {
3491         /* TODO: this needs to be fixed */
3492         return dissect_rpc_string(pd, offset, fd, tree, hf, string_ret);
3493 }
3494
3495 int
3496 dissect_nfs_seqid4(const u_char *pd, int offset, frame_data *fd, 
3497         proto_tree *tree)
3498 {
3499         guint seqid;
3500
3501         seqid = EXTRACT_UINT(pd, offset);
3502         proto_tree_add_uint(tree, hf_nfs_seqid4, NullTVB, offset, 4, seqid);
3503         offset += 4;
3504
3505         return offset;
3506 }
3507
3508 int
3509 dissect_nfs_stateid4(const u_char *pd, int offset, frame_data *fd,
3510         proto_tree *tree, char *name)
3511 {
3512         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3513 }
3514
3515 int
3516 dissect_nfs_offset4(const u_char *pd, int offset, frame_data *fd,
3517         proto_tree *tree, char *name)
3518 {
3519         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3520 }
3521
3522 int
3523 dissect_nfs_count4(const u_char *pd, int offset, frame_data *fd,
3524         proto_tree *tree, char *name)
3525 {
3526         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3527 }
3528
3529 int
3530 dissect_nfs_type4(const u_char *pd, int offset, frame_data *fd,
3531         proto_tree *tree, char *name)
3532 {
3533         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3534 }
3535
3536 int
3537 dissect_nfs_linktext4(const u_char *pd, int offset, frame_data *fd,
3538         proto_tree *tree, char *name)
3539 {
3540         return dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_linktext4, NULL);
3541 }
3542
3543 int
3544 dissect_nfs_specdata4(const u_char *pd, int offset, frame_data *fd,
3545         proto_tree *tree, char *name)
3546 {
3547         offset = dissect_rpc_uint32(pd, offset, fd, tree, "specdata1");
3548         offset = dissect_rpc_uint32(pd, offset, fd, tree, "specdata2");
3549
3550         return offset;
3551 }
3552
3553 int
3554 dissect_nfs_clientid4(const u_char *pd, int offset, frame_data *fd,
3555         proto_tree *tree, char *name)
3556 {
3557         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3558 }
3559
3560 int
3561 dissect_nfs_client_id4(const u_char *pd, int offset, frame_data *fd,
3562         proto_tree *tree, char *name)
3563 {
3564         offset = dissect_nfs_clientid4(pd, offset, fd, tree, "Verifier");
3565         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data);
3566
3567         return offset;
3568 }
3569
3570 static const value_string names_ftype4[] = {
3571         {       NF4REG, "NF4REG"        },
3572         {       NF4DIR, "NF4DIR"        },
3573         {       NF4BLK, "NF4BLK"  },
3574         {       NF4CHR, "NF4CHR"  },
3575         {       NF4LNK,  "NF4LNK"  },
3576         {       NF4SOCK,        "NF4SOCK"  },
3577         {       NF4FIFO,        "NF4FIFO"  },
3578         {       NF4ATTRDIR,     "NF4ATTRDIR"    },
3579         {       NF4NAMEDATTR,   "NF4NAMEDATTR"  },
3580         { 0, NULL }
3581 };
3582
3583 int
3584 dissect_nfs_ftype4(const u_char *pd, int offset, frame_data *fd,
3585         proto_tree *tree, char *name)
3586 {
3587         guint ftype4;
3588
3589         ftype4 = EXTRACT_UINT(pd, offset);
3590         proto_tree_add_uint(tree, hf_nfs_ftype4, NullTVB, offset, 4, ftype4);
3591         offset += 4;
3592
3593         return offset;
3594 }
3595
3596 int
3597 dissect_nfs_component4(const u_char *pd, int offset, frame_data *fd,
3598         proto_tree *tree, char *name)
3599 {
3600         return dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_component4, 
3601                 NULL);
3602 }
3603
3604 int
3605 dissect_nfs_lock_type4(const u_char *pd, int offset, frame_data *fd,
3606         proto_tree *tree, char *name)
3607 {
3608         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3609 }
3610
3611 int
3612 dissect_nfs_reclaim4(const u_char *pd, int offset, frame_data *fd,
3613         proto_tree *tree, char *name)
3614 {
3615         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3616 }
3617
3618 int
3619 dissect_nfs_length4(const u_char *pd, int offset, frame_data *fd,
3620         proto_tree *tree, char *name)
3621 {
3622         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3623 }
3624
3625 int
3626 dissect_nfs_opaque4(const u_char *pd, int offset, frame_data *fd,
3627         proto_tree *tree, char *name);
3628
3629 int
3630 dissect_nfs_lockowner4(const u_char *pd, int offset, frame_data *fd,
3631         proto_tree *tree, char *name)
3632 {
3633         proto_tree *newftree = NULL;
3634         proto_item *fitem = NULL;
3635
3636         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, "Owner");
3637
3638         if (fitem) {
3639                 newftree = proto_item_add_subtree(fitem, ett_nfs_lockowner4);
3640
3641                 if (newftree) {
3642                         offset = dissect_rpc_uint64(pd, offset, fd, newftree, "Client ID");
3643                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "Owner");
3644                 }
3645         }
3646
3647         return offset;
3648 }
3649
3650 int
3651 dissect_nfs_pathname4(const u_char *pd, int offset, frame_data *fd,
3652         proto_tree *tree, char *name)
3653 {
3654         guint comp_count, i;
3655         proto_item *fitem = NULL;
3656         proto_tree *newftree = NULL;
3657
3658         comp_count=EXTRACT_UINT(pd, offset);
3659         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, 
3660                 "pathname components (%d)", comp_count);
3661         offset += 4;
3662
3663         if (fitem) {
3664                 newftree = proto_item_add_subtree(fitem, ett_nfs_pathname4);
3665
3666                 if (newftree) {
3667                         for (i=0; i<comp_count; i++)
3668                                 offset=dissect_nfs_component4(pd, offset, fd, newftree, "comp");
3669                 }
3670         }
3671
3672         return offset;
3673 }
3674
3675 int
3676 dissect_nfs_changeid4(const u_char *pd, int offset, frame_data *fd,
3677         proto_tree *tree, char *name)
3678 {
3679         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3680 }
3681
3682 int
3683 dissect_nfs_nfstime4(const u_char *pd, int offset, frame_data *fd,
3684         proto_tree *tree, char *name)
3685 {
3686         offset = dissect_rpc_uint64(pd, offset, fd, tree, "seconds");
3687         offset = dissect_rpc_uint32(pd, offset, fd, tree, "nseconds");
3688         return offset;
3689 }
3690
3691 static const value_string names_time_how4[] = {
3692 #define SET_TO_SERVER_TIME4 0
3693         {       SET_TO_SERVER_TIME4,    "SET_TO_SERVER_TIME4"   },
3694 #define SET_TO_CLIENT_TIME4 1
3695         {       SET_TO_CLIENT_TIME4,    "SET_TO_CLIENT_TIME4"   },
3696         {       0,      NULL    },
3697 };
3698
3699 int
3700 dissect_nfs_settime4(const u_char *pd, int offset, frame_data *fd,
3701         proto_tree *tree, char *name)
3702 {
3703         guint32 set_it;
3704
3705         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3706
3707         set_it = EXTRACT_UINT(pd, offset);
3708         proto_tree_add_uint(tree, hf_nfs_time_how4, NullTVB, offset+0, 
3709                 4, set_it);
3710         offset += 4;
3711
3712         if (set_it == SET_TO_CLIENT_TIME4)
3713                 offset = dissect_nfs_nfstime4(pd, offset, fd, tree, NULL);
3714         
3715         return offset;
3716 }
3717
3718 static const value_string names_fattr4_expire_type[] = {
3719 #define FH4_PERSISTENT 0x00000000
3720         {       FH4_PERSISTENT, "FH4_PERSISTENT"        },
3721 #define FH4_NOEXPIRE_WITH_OPEN 0x00000001
3722         {       FH4_NOEXPIRE_WITH_OPEN, "FH4_NOEXPIRE_WITH_OPEN"        },
3723 #define FH4_VOLATILE_ANY 0x00000002
3724         {       FH4_NOEXPIRE_WITH_OPEN, "FH4_NOEXPIRE_WITH_OPEN"        },
3725 #define FH4_VOL_MIGRATION 0x00000004
3726         {       FH4_VOL_MIGRATION,      "FH4_VOL_MIGRATION"     },
3727 #define FH4_VOL_RENAME 0x00000008
3728         {       FH4_VOL_RENAME, "FH4_VOL_RENAME"        },
3729         {       0,      NULL    }
3730 };
3731
3732 int
3733 dissect_nfs_fh_expire_type(const u_char *pd, int offset, frame_data *fd,
3734         proto_tree *tree)
3735 {
3736         guint32 fattr4_fh_expire_type;
3737
3738         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3739
3740         fattr4_fh_expire_type = EXTRACT_UINT(pd, offset);
3741         proto_tree_add_uint(tree, hf_nfs_fattr4_expire_type, NullTVB, offset+0, 
3742                 4, fattr4_fh_expire_type);
3743         offset += 4;
3744
3745         return offset;
3746 }
3747
3748 int
3749 dissect_nfs_fsid4(const u_char *pd, int offset, frame_data *fd, 
3750         proto_tree *tree, char *name)
3751 {
3752         proto_tree *newftree = NULL;
3753         proto_item *fitem = NULL;
3754
3755         if (!BYTES_ARE_IN_FRAME(offset, 8)) return offset;
3756
3757         fitem = proto_tree_add_text(tree, NullTVB, offset, 0, "%s", name);
3758
3759         if (fitem == NULL) return offset;
3760
3761         newftree = proto_item_add_subtree(fitem, ett_nfs_fsid4);
3762
3763         if (newftree == NULL) return offset;
3764
3765         offset = dissect_rpc_uint64(pd, offset, fd, newftree, "major");
3766         offset = dissect_rpc_uint64(pd, offset, fd, newftree, "minor");
3767
3768         return offset;
3769 }
3770
3771 int
3772 dissect_nfs_acetype4(const u_char *pd, int offset, frame_data *fd,
3773         proto_tree *tree, char *name)
3774 {
3775         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3776 }
3777
3778 int
3779 dissect_nfs_aceflag4(const u_char *pd, int offset, frame_data *fd,
3780         proto_tree *tree, char *name)
3781 {
3782         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3783 }
3784
3785 int
3786 dissect_nfs_acemask4(const u_char *pd, int offset, frame_data *fd,
3787         proto_tree *tree, char *name)
3788 {
3789         return dissect_rpc_uint32(pd, offset, fd, tree, name);
3790 }
3791
3792 int
3793 dissect_nfs_nfsace4(const u_char *pd, int offset, frame_data *fd, 
3794         proto_tree *tree, char *name)
3795 {
3796         proto_tree *newftree = NULL;
3797         proto_item *fitem = NULL;
3798         int nextentry;
3799
3800         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3801
3802         fitem = proto_tree_add_text(tree, NullTVB, offset, 0, "%s", name);
3803
3804         if (fitem == NULL) return offset;
3805
3806         newftree = proto_item_add_subtree(fitem, ett_nfs_fsid4);
3807
3808         if (newftree == NULL) return offset;
3809
3810         nextentry = EXTRACT_UINT(pd, offset);
3811         offset = dissect_rpc_bool(pd, offset, fd, newftree, hf_nfs_data_follows);
3812
3813         while (nextentry)
3814         {
3815                 offset = dissect_nfs_acetype4(pd, offset, fd, newftree, "type");
3816                 offset = dissect_nfs_aceflag4(pd, offset, fd, newftree, "flag");
3817                 offset = dissect_nfs_acemask4(pd, offset, fd, newftree, "access_mask");
3818                 offset = dissect_nfs_utf8string(pd, offset, fd, newftree, 
3819                         hf_nfs_who, NULL);
3820                 nextentry = EXTRACT_UINT(pd, offset);
3821                 offset += 4;
3822         }
3823
3824         return offset;
3825 }
3826
3827 int
3828 dissect_nfs_fh4(const u_char *pd, int offset, frame_data *fd,
3829         proto_tree *tree, char *name)
3830 {
3831         return old_dissect_nfs_fh3(pd, offset, fd, tree, name);
3832 }
3833
3834 int
3835 dissect_nfs_fs_location4(const u_char *pd, int offset, frame_data *fd,
3836         proto_tree *tree, char *name)
3837 {
3838         proto_tree *newftree = NULL;
3839         proto_item *fitem = NULL;
3840
3841         fitem = proto_tree_add_text(tree, NullTVB, offset, 0, "%s", name);
3842
3843         if (fitem == NULL) return offset;
3844
3845         newftree = proto_item_add_subtree(fitem, ett_nfs_fs_location4);
3846
3847         if (newftree == NULL) return offset;
3848
3849         offset = dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_server, NULL);
3850
3851         return offset;
3852 }
3853
3854 int
3855 dissect_nfs_fs_locations4(const u_char *pd, int offset, frame_data *fd,
3856         proto_tree *tree, char *name)
3857 {
3858         proto_tree *newftree = NULL;
3859         proto_item *fitem = NULL;
3860         int nextentry;
3861
3862         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
3863
3864         fitem = proto_tree_add_text(tree, NullTVB, offset, 0, "%s", name);
3865
3866         if (fitem == NULL) return offset;
3867
3868         newftree = proto_item_add_subtree(fitem, ett_nfs_fs_locations4);
3869
3870         if (newftree == NULL) return offset;
3871
3872         offset = dissect_nfs_pathname4(pd, offset, fd, newftree, "fs_root");
3873
3874         nextentry = EXTRACT_UINT(pd, offset);
3875         offset = dissect_rpc_bool(pd, offset, fd, newftree, hf_nfs_data_follows);
3876
3877         while (nextentry)
3878         {
3879                 offset = dissect_nfs_fs_location4(pd, offset, fd, newftree, "locations");
3880                 nextentry = EXTRACT_UINT(pd, offset);
3881                 offset += 4;
3882         }
3883
3884         return offset;
3885 }
3886
3887 int
3888 dissect_nfs_mode4(const u_char *pd, int offset, frame_data *fd,
3889         proto_tree *tree, char *name)
3890 {
3891         return dissect_mode(pd, offset, fd, tree, name);
3892 }
3893
3894 static const value_string names_fattr4[] = {
3895 #define FATTR4_SUPPORTED_ATTRS     0
3896         {       FATTR4_SUPPORTED_ATTRS, "FATTR4_SUPPORTED_ATTRS"        },
3897 #define FATTR4_TYPE                1
3898         {       FATTR4_TYPE,    "FATTR4_TYPE"   },
3899 #define FATTR4_FH_EXPIRE_TYPE      2
3900         {       FATTR4_FH_EXPIRE_TYPE,  "FATTR4_FH_EXPIRE_TYPE" },
3901 #define FATTR4_CHANGE              3
3902         {       FATTR4_CHANGE,  "FATTR4_CHANGE" },
3903 #define FATTR4_SIZE                4
3904         {       FATTR4_SIZE,    "FATTR4_SIZE"   },
3905 #define FATTR4_LINK_SUPPORT        5
3906         {       FATTR4_LINK_SUPPORT,    "FATTR4_LINK_SUPPORT"   },
3907 #define FATTR4_SYMLINK_SUPPORT     6
3908         {       FATTR4_SYMLINK_SUPPORT, "FATTR4_SYMLINK_SUPPORT"        },
3909 #define FATTR4_NAMED_ATTR          7
3910         {       FATTR4_NAMED_ATTR,      "FATTR4_NAMED_ATTR"     },
3911 #define FATTR4_FSID                8
3912         {       FATTR4_FSID,    "FATTR4_FSID"   },
3913 #define FATTR4_UNIQUE_HANDLES      9
3914         {       FATTR4_UNIQUE_HANDLES,  "FATTR4_UNIQUE_HANDLES" },
3915 #define FATTR4_LEASE_TIME          10
3916         {       FATTR4_LEASE_TIME,      "FATTR4_LEASE_TIME"     },
3917 #define FATTR4_RDATTR_ERROR        11
3918         {       FATTR4_RDATTR_ERROR,    "FATTR4_RDATTR_ERROR"   },
3919 #define FATTR4_ACL                 12
3920         {       FATTR4_ACL,     "FATTR4_ACL"    },
3921 #define FATTR4_ACLSUPPORT          13
3922         {       FATTR4_ACLSUPPORT,      "FATTR4_ACLSUPPORT"     },
3923 #define FATTR4_ARCHIVE             14
3924         {       FATTR4_ARCHIVE, "FATTR4_ARCHIVE"        },
3925 #define FATTR4_CANSETTIME          15
3926         {       FATTR4_CANSETTIME, "FATTR4_CANSETTIME"  },
3927 #define FATTR4_CASE_INSENSITIVE    16
3928         {       FATTR4_CASE_INSENSITIVE, "FATTR4_CASE_INSENSITIVE"      },
3929 #define FATTR4_CASE_PRESERVING     17
3930         {       FATTR4_CASE_PRESERVING, "FATTR4_CASE_PRESERVING"        },
3931 #define FATTR4_CHOWN_RESTRICTED    18
3932         {       FATTR4_CHOWN_RESTRICTED, "FATTR4_CHOWN_RESTRICTED"      },
3933 #define FATTR4_FILEHANDLE          19
3934         {       FATTR4_FILEHANDLE, "FATTR4_FILEHANDLE"  },
3935 #define FATTR4_FILEID              20
3936         {       FATTR4_FILEID, "FATTR4_FILEID"  },
3937 #define FATTR4_FILES_AVAIL         21
3938         {       FATTR4_FILES_AVAIL, "FATTR4_FILES_AVAIL"        },
3939 #define FATTR4_FILES_FREE          22
3940         {       FATTR4_FILES_FREE, "FATTR4_FILES_FREE"  },
3941 #define FATTR4_FILES_TOTAL         23
3942         {       FATTR4_FILES_TOTAL, "FATTR4_FILES_TOTAL"        },
3943 #define FATTR4_FS_LOCATIONS        24
3944         {       FATTR4_FS_LOCATIONS, "FATTR4_FS_LOCATIONS"      },
3945 #define FATTR4_HIDDEN              25
3946         {       FATTR4_HIDDEN, "FATTR4_HIDDEN"  },
3947 #define FATTR4_HOMOGENEOUS         26
3948         {       FATTR4_HOMOGENEOUS, "FATTR4_HOMOGENEOUS"        },
3949 #define FATTR4_MAXFILESIZE         27
3950         {       FATTR4_MAXFILESIZE, "FATTR4_MAXFILESIZE"        },
3951 #define FATTR4_MAXLINK             28
3952         {       FATTR4_MAXLINK, "FATTR4_MAXLINK"        },
3953 #define FATTR4_MAXNAME             29
3954         {       FATTR4_MAXNAME, "FATTR4_MAXNAME"        },
3955 #define FATTR4_MAXREAD             30
3956         {       FATTR4_MAXREAD, "FATTR4_MAXREAD"        },
3957 #define FATTR4_MAXWRITE            31
3958         {       FATTR4_MAXWRITE, "FATTR4_MAXWRITE"      },
3959 #define FATTR4_MIMETYPE            32
3960         {       FATTR4_MIMETYPE, "FATTR4_MIMETYPE"      },
3961 #define FATTR4_MODE                33
3962         {       FATTR4_MODE, "FATTR4_MODE"      },
3963 #define FATTR4_NO_TRUNC            34
3964         {       FATTR4_NO_TRUNC, "FATTR4_NO_TRUNC"      },
3965 #define FATTR4_NUMLINKS            35
3966         {       FATTR4_NUMLINKS, "FATTR4_NUMLINKS"      },
3967 #define FATTR4_OWNER               36
3968         {       FATTR4_OWNER, "FATTR4_OWNER"    },
3969 #define FATTR4_OWNER_GROUP         37
3970         {       FATTR4_OWNER_GROUP, "FATTR4_OWNER_GROUP"        },
3971 #define FATTR4_QUOTA_AVAIL_HARD    38
3972         {       FATTR4_QUOTA_AVAIL_HARD, "FATTR4_QUOTA_AVAIL_HARD"      },
3973 #define FATTR4_QUOTA_AVAIL_SOFT    39
3974         {       FATTR4_QUOTA_AVAIL_SOFT, "FATTR4_QUOTA_AVAIL_SOFT"      },
3975 #define FATTR4_QUOTA_USED          40
3976         {       FATTR4_QUOTA_USED, "FATTR4_QUOTA_USED"  },
3977 #define FATTR4_RAWDEV              41
3978         {       FATTR4_RAWDEV, "FATTR4_RAWDEV"  },
3979 #define FATTR4_SPACE_AVAIL         42
3980         {       FATTR4_SPACE_AVAIL, "FATTR4_SPACE_AVAIL"        },
3981 #define FATTR4_SPACE_FREE          43
3982         {       FATTR4_SPACE_FREE, "FATTR4_SPACE_FREE"  },
3983 #define FATTR4_SPACE_TOTAL         44
3984         {       FATTR4_SPACE_TOTAL, "FATTR4_SPACE_TOTAL"        },
3985 #define FATTR4_SPACE_USED          45
3986         {       FATTR4_SPACE_USED, "FATTR4_SPACE_USED"  },
3987 #define FATTR4_SYSTEM              46
3988         {       FATTR4_SYSTEM, "FATTR4_SYSTEM"  },
3989 #define FATTR4_TIME_ACCESS         47
3990         {       FATTR4_TIME_ACCESS, "FATTR4_TIME_ACCESS"        },
3991 #define FATTR4_TIME_ACCESS_SET     48
3992         {       FATTR4_TIME_ACCESS_SET, "FATTR4_TIME_ACCESS_SET"        },
3993 #define FATTR4_TIME_BACKUP         49
3994         {       FATTR4_TIME_BACKUP, "FATTR4_TIME_BACKUP"        },
3995 #define FATTR4_TIME_CREATE         50
3996         {       FATTR4_TIME_CREATE, "FATTR4_TIME_CREATE"        },
3997 #define FATTR4_TIME_DELTA          51
3998         {       FATTR4_TIME_DELTA, "FATTR4_TIME_DELTA"  },
3999 #define FATTR4_TIME_METADATA       52
4000         {       FATTR4_TIME_METADATA, "FATTR4_TIME_METADATA"    },
4001 #define FATTR4_TIME_MODIFY         53
4002         {       FATTR4_TIME_MODIFY, "FATTR4_TIME_MODIFY"        },
4003 #define FATTR4_TIME_MODIFY_SET     54
4004         {       FATTR4_TIME_MODIFY_SET, "FATTR4_TIME_MODIFY_SET"        },
4005         {       0,      NULL    }
4006 };
4007
4008
4009 int
4010 dissect_nfs_attributes(const u_char *pd, int offset, frame_data *fd,
4011         proto_tree *tree, char *name, int type)
4012 {
4013         guint32 bitmap_len;
4014         proto_item *fitem = NULL;
4015         proto_tree *newftree = NULL;
4016         proto_item *attr_fitem = NULL;
4017         proto_tree *attr_newftree = NULL;
4018         int i, j, fattr;
4019         guint32 *bitmap;
4020         guint32 sl;
4021         int attr_vals_offset;
4022
4023         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4024
4025         bitmap_len = EXTRACT_UINT(pd, offset);
4026         fitem = proto_tree_add_text(tree, NullTVB, offset, 4 + bitmap_len * 4,
4027                 "%s", "attrmask");
4028         offset += 4;
4029
4030         if (fitem == NULL) return offset;
4031
4032         newftree = proto_item_add_subtree(fitem, ett_nfs_bitmap4);
4033
4034         if (newftree == NULL) return offset;
4035
4036         attr_vals_offset = offset + 4 + bitmap_len * 4;
4037
4038         bitmap = g_malloc(bitmap_len * sizeof(guint32));        
4039         if (bitmap == NULL) return offset;
4040
4041         for (i = 0; i < bitmap_len; i++)
4042         {
4043                 if (!BYTES_ARE_IN_FRAME(offset, 4))
4044                 {
4045                         g_free(bitmap);
4046                         return offset;
4047                 }
4048
4049                 bitmap[i] = EXTRACT_UINT(pd, offset);
4050
4051                 sl = 0x00000001;
4052
4053                 for (j = 0; j < 32; j++)
4054                 {
4055                         fattr = 32 * i + j;
4056
4057                         if (bitmap[i] & sl)
4058                         {
4059                                 /* switch label if attribute is recommended vs. mandatory */
4060                                 attr_fitem = proto_tree_add_uint(newftree, 
4061                                         (fattr < FATTR4_ACL)? hf_nfs_mand_attr: hf_nfs_recc_attr, 
4062                                         NullTVB, offset, 4, fattr);
4063
4064                                 if (attr_fitem == NULL)
4065                                         continue;
4066
4067                                 attr_newftree = proto_item_add_subtree(attr_fitem, ett_nfs_bitmap4);
4068
4069                                 if (attr_newftree == NULL)
4070                                         continue;
4071
4072                                 if (type == 1)
4073                                 {
4074                                         /* do a full decode of the arguments for the set flag */
4075                                         switch(fattr)
4076                                         {
4077                                         case FATTR4_SUPPORTED_ATTRS:
4078                                                 attr_vals_offset = dissect_nfs_attributes(pd, 
4079                                                         attr_vals_offset, fd, attr_newftree, 
4080                                                         "fattr4_supported_attrs", 0);
4081                                                 break;
4082                                                 
4083                                         case FATTR4_TYPE:
4084                                                 attr_vals_offset = dissect_nfs_ftype4(pd, attr_vals_offset,
4085                                                         fd, attr_newftree, "fattr4_type");
4086                                                 break;
4087
4088                                         case FATTR4_FH_EXPIRE_TYPE:
4089                                                 attr_vals_offset = dissect_nfs_fh_expire_type(pd,
4090                                                         attr_vals_offset, fd, attr_newftree);
4091                                                 break;
4092
4093                                         case FATTR4_CHANGE:
4094                                                 attr_vals_offset = dissect_nfs_changeid4(pd, attr_vals_offset,
4095                                                         fd, attr_newftree, "fattr4_change");
4096                                                 break;
4097
4098                                         case FATTR4_SIZE:
4099                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4100                                                         fd, attr_newftree, "size");
4101                                                 break;
4102
4103                                         case FATTR4_LINK_SUPPORT:
4104                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset, 
4105                                                         fd, attr_newftree, hf_nfs_fattr4_link_support);
4106                                                 break;
4107
4108                                         case FATTR4_SYMLINK_SUPPORT:
4109                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset, 
4110                                                         fd, attr_newftree, hf_nfs_fattr4_symlink_support);
4111                                                 break;
4112
4113                                         case FATTR4_NAMED_ATTR:
4114                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset, 
4115                                                         fd, attr_newftree, hf_nfs_fattr4_named_attr);
4116                                                 break;
4117
4118                                         case FATTR4_FSID:
4119                                                 attr_vals_offset = dissect_nfs_fsid4(pd, attr_vals_offset,
4120                                                         fd, attr_newftree, "fattr4_fsid");
4121                                                 break;
4122
4123                                         case FATTR4_UNIQUE_HANDLES:
4124                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4125                                                         fd, attr_newftree, hf_nfs_fattr4_unique_handles);
4126                                                 break;
4127
4128                                         case FATTR4_LEASE_TIME:
4129                                                 attr_vals_offset = dissect_rpc_uint32(pd, attr_vals_offset,
4130                                                         fd, attr_newftree, "fattr4_lease_time");
4131                                                 break;
4132
4133                                         case FATTR4_RDATTR_ERROR:
4134                                                 attr_vals_offset = dissect_nfs_nfsstat4(pd, attr_vals_offset,
4135                                                         fd, attr_newftree, NULL);
4136                                                 break;
4137
4138                                         case FATTR4_ACL:
4139                                                 attr_vals_offset = dissect_nfs_nfsace4(pd, attr_vals_offset,
4140                                                         fd, attr_newftree, "fattr4_acl");
4141                                                 break;
4142
4143                                         case FATTR4_ACLSUPPORT:
4144                                                 attr_vals_offset = dissect_rpc_uint32(pd, attr_vals_offset,
4145                                                         fd, attr_newftree, "fattr4_aclsupport");
4146                                                 break;
4147
4148                                         case FATTR4_ARCHIVE:
4149                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4150                                                         fd, attr_newftree, hf_nfs_fattr4_archive);
4151                                                 break;
4152
4153                                         case FATTR4_CANSETTIME:
4154                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4155                                                         fd, attr_newftree, hf_nfs_fattr4_cansettime);
4156                                                 break;
4157
4158                                         case FATTR4_CASE_INSENSITIVE:
4159                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4160                                                         fd, attr_newftree, hf_nfs_fattr4_case_insensitive);
4161                                                 break;
4162
4163                                         case FATTR4_CASE_PRESERVING:
4164                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4165                                                         fd, attr_newftree, hf_nfs_fattr4_case_preserving);
4166                                                 break;
4167
4168                                         case FATTR4_CHOWN_RESTRICTED:
4169                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4170                                                         fd, attr_newftree, hf_nfs_fattr4_chown_restricted);
4171                                                 break;
4172
4173                                         case FATTR4_FILEID:
4174                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4175                                                         fd, attr_newftree, "fattr4_fileid");
4176                                                 break;
4177
4178                                         case FATTR4_FILES_AVAIL:
4179                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4180                                                         fd, attr_newftree, "fattr4_files_avail");
4181                                                 break;
4182
4183                                         case FATTR4_FILEHANDLE:
4184                                                 attr_vals_offset = dissect_nfs_fh4(pd, attr_vals_offset,
4185                                                         fd, attr_newftree, "fattr4_filehandle");
4186                                                 break;
4187
4188                                         case FATTR4_FILES_FREE:
4189                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4190                                                         fd, attr_newftree, "fattr4_files_free");
4191                                                 break;
4192
4193                                         case FATTR4_FILES_TOTAL:
4194                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4195                                                         fd, attr_newftree, "fattr4_files_total");
4196                                                 break;
4197
4198                                         case FATTR4_FS_LOCATIONS:
4199                                                 attr_vals_offset = dissect_nfs_fs_locations4(pd, 
4200                                                         attr_vals_offset, fd, attr_newftree, 
4201                                                         "fattr4_fs_locations");
4202                                                 break;
4203
4204                                         case FATTR4_HIDDEN:
4205                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4206                                                         fd, attr_newftree, hf_nfs_fattr4_hidden);
4207                                                 break;
4208
4209                                         case FATTR4_HOMOGENEOUS:
4210                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4211                                                         fd, attr_newftree, hf_nfs_fattr4_homogeneous);
4212                                                 break;
4213
4214                                         case FATTR4_MAXFILESIZE:
4215                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4216                                                         fd, attr_newftree, "fattr4_maxfilesize");
4217                                                 break;
4218
4219                                         case FATTR4_MAXLINK:
4220                                                 attr_vals_offset = dissect_rpc_uint32(pd, attr_vals_offset,
4221                                                         fd, attr_newftree, "fattr4_maxlink");
4222                                                 break;
4223
4224                                         case FATTR4_MAXNAME:
4225                                                 attr_vals_offset = dissect_rpc_uint32(pd, attr_vals_offset,
4226                                                         fd, attr_newftree, "fattr4_maxname");
4227                                                 break;
4228
4229                                         case FATTR4_MAXREAD:
4230                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4231                                                         fd, attr_newftree, "fattr4_maxread");
4232                                                 break;
4233
4234                                         case FATTR4_MAXWRITE:
4235                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4236                                                         fd, attr_newftree, "fattr4_maxwrite");
4237                                                 break;
4238
4239                                         case FATTR4_MIMETYPE:
4240                                                 attr_vals_offset = dissect_nfs_utf8string(pd, 
4241                                                         attr_vals_offset, fd, attr_newftree, 
4242                                                         hf_nfs_fattr4_mimetype, NULL);
4243                                                 break;
4244                                         
4245                                         case FATTR4_MODE:
4246                                                 attr_vals_offset = dissect_nfs_mode4(pd,
4247                                                         attr_vals_offset, fd, attr_newftree, "fattr4_mode");
4248                                                 break;
4249
4250                                         case FATTR4_NO_TRUNC:
4251                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4252                                                         fd, attr_newftree, hf_nfs_fattr4_no_trunc);
4253                                                 break;
4254
4255                                         case FATTR4_NUMLINKS:
4256                                                 attr_vals_offset = dissect_rpc_uint32(pd, attr_vals_offset,
4257                                                         fd, attr_newftree, "fattr4_numlinks");
4258                                                 break;
4259
4260                                         case FATTR4_OWNER:
4261                                                 attr_vals_offset = dissect_nfs_utf8string(pd, 
4262                                                         attr_vals_offset, fd, attr_newftree, hf_nfs_fattr4_owner,
4263                                                         NULL);
4264                                                 break;
4265
4266                                         case FATTR4_OWNER_GROUP:
4267                                                 attr_vals_offset = dissect_nfs_utf8string(pd, 
4268                                                         attr_vals_offset, fd, attr_newftree, 
4269                                                         hf_nfs_fattr4_owner_group, NULL);
4270                                                 break;
4271
4272                                         case FATTR4_QUOTA_AVAIL_HARD:
4273                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4274                                                         fd, attr_newftree, "fattr4_quota_hard");
4275                                                 break;
4276
4277                                         case FATTR4_QUOTA_AVAIL_SOFT:
4278                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4279                                                         fd, attr_newftree, "fattr4_quota_soft");
4280                                                 break;
4281
4282                                         case FATTR4_QUOTA_USED:
4283                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4284                                                         fd, attr_newftree, "fattr4_quota_used");
4285                                                 break;
4286
4287                                         case FATTR4_RAWDEV:
4288                                                 attr_vals_offset = dissect_nfs_specdata4(pd, attr_vals_offset,
4289                                                         fd, attr_newftree, "fattr4_rawdev");
4290                                                 break;
4291
4292                                         case FATTR4_SPACE_AVAIL:
4293                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4294                                                         fd, attr_newftree, "fattr4_space_avail");
4295                                                 break;
4296
4297                                         case FATTR4_SPACE_FREE:
4298                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4299                                                         fd, attr_newftree, "fattr4_space_free");
4300                                                 break;
4301
4302                                         case FATTR4_SPACE_TOTAL:
4303                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4304                                                         fd, attr_newftree, "fattr4_space_total");
4305                                                 break;
4306
4307                                         case FATTR4_SPACE_USED:
4308                                                 attr_vals_offset = dissect_rpc_uint64(pd, attr_vals_offset,
4309                                                         fd, attr_newftree, "fattr4_space_used");
4310                                                 break;
4311                                         
4312                                         case FATTR4_SYSTEM:
4313                                                 attr_vals_offset = dissect_rpc_bool(pd, attr_vals_offset,
4314                                                         fd, attr_newftree, hf_nfs_fattr4_system);
4315                                                 break;
4316
4317                                         case FATTR4_TIME_ACCESS:
4318                                         case FATTR4_TIME_BACKUP:
4319                                         case FATTR4_TIME_CREATE:
4320                                         case FATTR4_TIME_DELTA:
4321                                         case FATTR4_TIME_METADATA:
4322                                         case FATTR4_TIME_MODIFY:
4323                                                 attr_vals_offset = dissect_nfs_nfstime4(pd, attr_vals_offset,
4324                                                         fd, attr_newftree, "nfstime4");
4325                                                 break;
4326
4327                                         case FATTR4_TIME_ACCESS_SET:
4328                                         case FATTR4_TIME_MODIFY_SET:
4329                                                 attr_vals_offset = dissect_nfs_settime4(pd, attr_vals_offset, 
4330                                                         fd, attr_newftree, "settime4");
4331                                                 break;
4332
4333                                         default:
4334                                                 break;
4335                                         }
4336                                 }
4337                         }
4338
4339                         sl <<= 1;
4340                 }
4341
4342                 offset += 4;
4343         }
4344
4345         g_free(bitmap);
4346
4347         return offset;
4348 }
4349
4350 int
4351 dissect_nfs_attrlist4(const u_char *pd, int offset, frame_data *fd,
4352         proto_tree *tree)
4353 {
4354         return dissect_nfsdata(pd, offset, fd, tree, hf_nfs_attrlist4);
4355 }
4356
4357 int
4358 dissect_nfs_fattr4(const u_char *pd, int offset, frame_data *fd,
4359         proto_tree *tree, char *name)
4360 {
4361         proto_tree *newftree = NULL;
4362         proto_item *fitem = NULL;
4363
4364         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, "obj_attributes");
4365
4366         if (fitem == NULL) return offset;
4367
4368         newftree = proto_item_add_subtree(fitem, ett_nfs_fattr4);
4369
4370         if (newftree == NULL) return offset;
4371
4372         offset = dissect_nfs_attributes(pd, offset, fd, newftree, name, 1);
4373         offset = dissect_nfs_attrlist4(pd, offset, fd, newftree);
4374
4375         return offset;
4376 }
4377
4378 static const value_string names_open4_share_access[] = {
4379 #define OPEN4_SHARE_ACCESS_READ 0x00000001
4380         { OPEN4_SHARE_ACCESS_READ, "OPEN4_SHARE_ACCESS_READ" }, 
4381 #define OPEN4_SHARE_ACCESS_WRITE 0x00000002
4382         { OPEN4_SHARE_ACCESS_WRITE, "OPEN4_SHARE_ACCESS_WRITE" },
4383 #define OPEN4_SHARE_ACCESS_BOTH 0x00000003
4384         { OPEN4_SHARE_ACCESS_BOTH, "OPEN4_SHARE_ACCESS_BOTH" },
4385         { 0, NULL }
4386 };
4387
4388 int
4389 dissect_nfs_open4_share_access(const u_char *pd, int offset, frame_data *fd,
4390         proto_tree *tree)
4391 {
4392         guint share_access;
4393
4394         share_access = EXTRACT_UINT(pd, offset);
4395         proto_tree_add_uint(tree, hf_nfs_open4_share_access, NullTVB, offset, 4, 
4396                 share_access);
4397         offset += 4;
4398
4399         return offset;
4400 }
4401
4402 static const value_string names_open4_share_deny[] = {
4403 #define OPEN4_SHARE_DENY_NONE 0x00000000
4404         { OPEN4_SHARE_DENY_NONE, "OPEN4_SHARE_DENY_NONE" },
4405 #define OPEN4_SHARE_DENY_READ 0x00000001
4406         { OPEN4_SHARE_DENY_READ, "OPEN4_SHARE_DENY_READ" },
4407 #define OPEN4_SHARE_DENY_WRITE 0x00000002
4408         { OPEN4_SHARE_DENY_WRITE, "OPEN4_SHARE_DENY_WRITE" },
4409 #define OPEN4_SHARE_DENY_BOTH 0x00000003
4410         { OPEN4_SHARE_DENY_BOTH, "OPEN4_SHARE_DENY_BOTH" },
4411         { 0, NULL }
4412 };
4413
4414 int
4415 dissect_nfs_open4_share_deny(const u_char *pd, int offset, frame_data *fd,
4416         proto_tree *tree)
4417 {
4418         guint deny_access;
4419
4420         deny_access = EXTRACT_UINT(pd, offset);
4421         proto_tree_add_uint(tree, hf_nfs_open4_share_deny, NullTVB, offset, 4,
4422                 deny_access);
4423         offset += 4;
4424
4425         return offset;
4426 }
4427
4428 int
4429 dissect_nfs_open_claim_delegate_cur4(const u_char *pd, int offset,
4430         frame_data *fd, proto_tree *tree, char *name)
4431 {
4432         offset = dissect_nfs_pathname4(pd, offset, fd, tree, "file");
4433         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "delegate_stateid");
4434         return offset;
4435 }
4436
4437 #define CLAIM_NULL                      0
4438 #define CLAIM_PREVIOUS                  1
4439 #define CLAIM_DELEGATE_CUR              2
4440 #define CLAIM_DELEGATE_PREV             3
4441
4442 static const value_string names_claim_type4[] = {
4443         {       CLAIM_NULL,             "CLAIM_NULL"  },
4444         {       CLAIM_PREVIOUS,         "CLAIM_PREVIOUS" },
4445         {       CLAIM_DELEGATE_CUR,     "CLAIM_DELEGATE_CUR" },
4446         {       CLAIM_DELEGATE_PREV,    "CLAIM_DELEGATE_PREV" },
4447         { 0, NULL }
4448 };
4449
4450 int
4451 dissect_nfs_open_claim4(const u_char *pd, int offset, frame_data *fd,
4452         proto_tree *tree, char *name)
4453 {
4454         guint open_claim_type4;
4455         proto_item *fitem = NULL;
4456         proto_tree *newftree = NULL;
4457
4458         open_claim_type4 = EXTRACT_UINT(pd, offset);
4459         fitem = proto_tree_add_uint(tree, hf_nfs_open_claim_type4, NullTVB,
4460                 offset+0, 4, open_claim_type4);
4461         offset += 4;
4462
4463         if (fitem) {
4464                 newftree = proto_item_add_subtree(fitem, ett_nfs_open_claim4);
4465
4466                 if (newftree) {
4467
4468                         switch(open_claim_type4)
4469                         {
4470                         case CLAIM_NULL:
4471                                 offset = dissect_nfs_pathname4(pd, offset, fd, newftree, "file");
4472                                 break;
4473
4474                         case CLAIM_PREVIOUS:
4475                                 offset = dissect_rpc_uint32(pd, offset, fd, newftree, 
4476                                         "delegate_type");
4477                                 break;
4478
4479                         case CLAIM_DELEGATE_CUR:
4480                                 offset = dissect_nfs_open_claim_delegate_cur4(pd, offset, fd, 
4481                                         newftree, "delegate_cur_info");
4482                                 break;
4483
4484                         case CLAIM_DELEGATE_PREV:
4485                                 offset = dissect_nfs_pathname4(pd, offset, fd, newftree, 
4486                                         "file_delegate_prev");
4487                                 break;
4488
4489                         default:
4490                                 break;
4491                         }
4492                 }
4493         }
4494
4495         return offset;
4496 }
4497
4498 int
4499 dissect_nfs_verifier4(const u_char *pd, int offset, frame_data *fd,
4500         proto_tree *tree, char *name);
4501
4502 int
4503 dissect_nfs_createhow4(const u_char *pd, int offset, frame_data *fd,
4504         proto_tree *tree, char *name)
4505 {
4506         guint mode;
4507
4508         /* This is intentional; we're using the same flags as NFSv3 */
4509         mode = EXTRACT_UINT(pd, offset);
4510         proto_tree_add_uint(tree, hf_nfs_createmode3, NullTVB, offset, 4, mode);
4511         offset += 4;
4512         
4513         switch(mode)
4514         {
4515         case UNCHECKED:         /* UNCHECKED4 */
4516         case GUARDED:           /* GUARDED4 */
4517                 offset = dissect_nfs_fattr4(pd, offset, fd, tree, "createattrs");
4518                 break;
4519
4520         case EXCLUSIVE:         /* EXCLUSIVE4 */
4521                 offset = dissect_nfs_verifier4(pd, offset, fd, tree, "createverf");
4522                 break;
4523         
4524         default:
4525                 break;
4526         }
4527
4528         return offset;
4529 }
4530
4531 #define OPEN4_NOCREATE                          0
4532 #define OPEN4_CREATE                                    1
4533 static const value_string names_opentype4[] = {
4534         {       OPEN4_NOCREATE,  "OPEN4_NOCREATE"  },
4535         {       OPEN4_CREATE, "OPEN4_CREATE" },
4536         { 0, NULL }
4537 };
4538
4539 int
4540 dissect_nfs_openflag4(const u_char *pd, int offset, frame_data *fd,
4541         proto_tree *tree)
4542 {
4543         guint opentype4;
4544         proto_item *fitem = NULL;
4545         proto_tree *newftree = NULL;
4546
4547         opentype4 = EXTRACT_UINT(pd, offset);
4548         fitem = proto_tree_add_uint(tree, hf_nfs_opentype4, NullTVB,
4549                 offset+0, 4, opentype4);
4550         offset += 4;
4551
4552         if (fitem) {
4553                 newftree = proto_item_add_subtree(fitem, ett_nfs_opentype4);
4554
4555                 if (newftree) {
4556
4557                         switch(opentype4)
4558                         {
4559                         case OPEN4_CREATE:
4560                                 offset = dissect_nfs_createhow4(pd, offset, fd, newftree, "how");
4561                                 break;
4562
4563                         default:
4564                                 break;
4565                         }
4566                 }
4567         }
4568
4569         return offset;
4570 }
4571
4572 int
4573 dissect_nfs_verifier4(const u_char *pd, int offset, frame_data *fd,
4574         proto_tree *tree, char *name)
4575 {
4576         return dissect_rpc_uint64(pd, offset, fd, tree, name);
4577 }
4578
4579
4580 int
4581 dissect_nfs_cookie4(const u_char *pd, int offset, frame_data *fd,
4582         proto_tree *tree, char *name)
4583 {
4584         return dissect_rpc_uint64(pd, offset, fd, tree, name);
4585 }
4586
4587 int
4588 dissect_nfs_cookieverf4(const u_char *pd, int offset, frame_data *fd,
4589         proto_tree *tree, char *name)
4590 {
4591         return dissect_rpc_uint64(pd, offset, fd, tree, name);
4592 }
4593
4594
4595 int
4596 dissect_nfs_clientaddr4(const u_char *pd, int offset, frame_data *fd,
4597         proto_tree *tree, char *name)
4598 {
4599         offset = dissect_nfs_opaque4(pd, offset, fd, tree, "network id");
4600         offset = dissect_nfs_opaque4(pd, offset, fd, tree, "universal address");
4601
4602         return offset;
4603 }
4604         
4605
4606 int
4607 dissect_nfs_cb_client4(const u_char *pd, int offset, frame_data *fd,
4608         proto_tree *tree, char *name)
4609 {
4610         offset = dissect_rpc_uint32(pd, offset, fd, tree, "cb_program");
4611         offset = dissect_nfs_clientaddr4(pd, offset, fd, tree, "cb_location");
4612
4613         return offset;
4614 }
4615
4616 static const value_string names_stable_how4[] = {
4617 #define UNSTABLE4 0
4618         {       UNSTABLE4,      "UNSTABLE4"     },
4619 #define DATA_SYNC4 1
4620         {       DATA_SYNC4,     "DATA_SYNC4"    },
4621 #define FILE_SYNC4 2
4622         {       FILE_SYNC4,     "FILE_SYNC4"    },
4623         {       0,      NULL    }
4624 };
4625
4626 int
4627 dissect_nfs_stable_how4(const u_char *pd, int offset, frame_data *fd,
4628         proto_tree *tree, char *name)
4629 {
4630         guint stable_how4;
4631
4632         stable_how4 = EXTRACT_UINT(pd, offset);
4633         proto_tree_add_uint_format(tree, hf_nfs_stable_how4, NullTVB,
4634                         offset+0, 4, stable_how4, "%s: %s (%u)", name,
4635                         val_to_str(stable_how4, names_stable_how4, "%u"), stable_how4);
4636         offset += 4;
4637
4638         return offset;
4639 }
4640
4641 int
4642 dissect_nfs_opaque4(const u_char *pd, int offset, frame_data *fd,
4643         proto_tree *tree, char *name)
4644 {
4645         return dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data);
4646 }
4647
4648 /* There is probably a better (built-in?) way to do this, but this works
4649  * for now.
4650  */
4651
4652 static const value_string names_nfsv4_operation[] = {
4653         {       NFS4_OP_ACCESS,                                 "ACCESS"        },
4654         {       NFS4_OP_CLOSE,                                          "CLOSE" },
4655         {       NFS4_OP_COMMIT,                                 "COMMIT"        },
4656         {       NFS4_OP_CREATE,                                 "CREATE"        },
4657         {       NFS4_OP_DELEGPURGE,                             "DELEGPURGE"    },
4658         {       NFS4_OP_DELEGRETURN,                            "DELEGRETURN"   },
4659         {       NFS4_OP_GETATTR,                                        "GETATTR"       },
4660         {       NFS4_OP_GETFH,                                          "GETFH" },
4661         {       NFS4_OP_LINK,                                           "LINK"  },
4662         {       NFS4_OP_LOCK,                                           "LOCK"  },
4663         {       NFS4_OP_LOCKT,                                          "LOCKT" },
4664         {       NFS4_OP_LOCKU,                                          "LOCKU" },
4665         {       NFS4_OP_LOOKUP,                                 "LOOKUP"        },
4666         {       NFS4_OP_NVERIFY,                                        "NVERIFY"       },
4667         {       NFS4_OP_OPEN,                                           "OPEN"  },
4668         {       NFS4_OP_OPENATTR,                                       "OPENATTR"      },
4669         {       NFS4_OP_OPEN_CONFIRM,                   "OPEN_CONFIRM"  },
4670         {       NFS4_OP_OPEN_DOWNGRADE,                 "OPEN_DOWNGRADE"        },
4671         {       NFS4_OP_PUTFH,                                          "PUTFH" },
4672         {       NFS4_OP_PUTPUBFH,                                       "PUTPUBFH"      },
4673         {       NFS4_OP_PUTROOTFH,                              "PUTROOTFH"     },
4674         {       NFS4_OP_READ,                                           "READ"  },
4675         {       NFS4_OP_READDIR,                                        "READDIR"       },
4676         {       NFS4_OP_READLINK,                                       "READLINK"      },
4677         {       NFS4_OP_REMOVE,                                 "REMOVE"        },
4678         {       NFS4_OP_RENAME,                                 "RENAME"        },
4679         {       NFS4_OP_RENEW,                                          "RENEW" },
4680         {       NFS4_OP_RESTOREFH,                              "RESTOREFH"     },
4681         {       NFS4_OP_SAVEFH,                                 "SAVEFH"        },
4682         {       NFS4_OP_SECINFO,                                        "SECINFO"       },
4683         {       NFS4_OP_SETATTR,                                        "SETATTR"       },
4684         {       NFS4_OP_SETCLIENTID,                            "SETCLIENTID"   },
4685         {       NFS4_OP_SETCLIENTID_CONFIRM,    "SETCLIENTID_CONFIRM"   },
4686         {       NFS4_OP_VERIFY,                                 "VERIFY"        },
4687         {       NFS4_OP_WRITE,                                          "WRITE" },
4688         { 0, NULL }
4689 };
4690
4691 gint *nfsv4_operation_ett[] =
4692 {
4693          &ett_nfs_access4 ,
4694          &ett_nfs_close4 ,
4695          &ett_nfs_commit4 ,
4696          &ett_nfs_create4 ,
4697          &ett_nfs_delegpurge4 ,
4698          &ett_nfs_delegreturn4 ,
4699          &ett_nfs_getattr4 ,
4700          &ett_nfs_getfh4 ,
4701          &ett_nfs_link4 ,
4702          &ett_nfs_lock4 ,
4703          &ett_nfs_lockt4 ,
4704          &ett_nfs_locku4 ,
4705          &ett_nfs_lookup4 ,
4706          &ett_nfs_lookupp4 ,
4707          &ett_nfs_nverify4 ,
4708          &ett_nfs_open4 ,
4709          &ett_nfs_openattr4 ,
4710          &ett_nfs_open_confirm4 ,
4711          &ett_nfs_open_downgrade4 ,
4712          &ett_nfs_putfh4 ,
4713          &ett_nfs_putpubfh4 ,
4714          &ett_nfs_putrootfh4 ,
4715          &ett_nfs_read4 ,
4716          &ett_nfs_readdir4 ,
4717          &ett_nfs_readlink4 ,
4718          &ett_nfs_remove4 ,
4719          &ett_nfs_rename4 ,
4720          &ett_nfs_renew4 ,
4721          &ett_nfs_restorefh4 ,
4722          &ett_nfs_savefh4 ,
4723          &ett_nfs_secinfo4 ,
4724          &ett_nfs_setattr4 ,
4725          &ett_nfs_setclientid4 ,
4726          &ett_nfs_setclientid_confirm4 ,
4727          &ett_nfs_verify4 ,
4728          &ett_nfs_write4 
4729 };
4730
4731 int
4732 dissect_nfs_dirlist4(const u_char *pd, int offset, frame_data *fd,
4733         proto_tree *tree, char *name)
4734 {
4735         proto_tree *newftree = NULL;
4736         guint nextentry;
4737
4738         newftree = proto_item_add_subtree(tree, ett_nfs_dirlist4);
4739         if (newftree==NULL) return offset;
4740
4741         nextentry = EXTRACT_UINT(pd, offset);
4742
4743         offset = dissect_rpc_bool(pd, offset, fd, newftree, hf_nfs_data_follows);
4744         
4745         while (nextentry)
4746         {
4747                 offset = dissect_nfs_cookie4(pd, offset, fd, newftree, "cookie");
4748                 offset = dissect_nfs_component4(pd, offset, fd, newftree, "name");
4749                 offset = dissect_nfs_fattr4(pd, offset, fd, newftree, "attrs");
4750                 nextentry = EXTRACT_UINT(pd, offset);
4751                 offset += 4;
4752         }
4753
4754         offset = dissect_rpc_bool(pd, offset, fd, newftree, hf_nfs_dirlist4_eof);
4755
4756         return offset;
4757 }
4758
4759 int
4760 dissect_nfs_change_info4(const u_char *pd, int offset, frame_data *fd,
4761         proto_tree *tree, char *name)
4762 {
4763         proto_tree *newftree = NULL;
4764         proto_tree *fitem = NULL;
4765
4766         fitem = proto_tree_add_text(tree, NullTVB, offset, 0, "%s", name);
4767
4768         if (fitem) {
4769                 newftree=proto_item_add_subtree(fitem, ett_nfs_change_info4);
4770
4771                 if (newftree) {
4772                         offset = dissect_rpc_bool(pd, offset, fd, newftree, 
4773                                 hf_nfs_change_info4_atomic);
4774                         offset = dissect_nfs_changeid4(pd, offset, fd, newftree, "before");
4775                         offset = dissect_nfs_changeid4(pd, offset, fd, newftree, "after");
4776                 }
4777         }
4778
4779         return offset;
4780 }
4781
4782 int
4783 dissect_nfs_lock4denied(const u_char *pd, int offset, frame_data *fd,
4784         proto_tree *tree, char *name)
4785 {
4786         offset = dissect_nfs_lockowner4(pd, offset, fd, tree, "owner");
4787         offset = dissect_nfs_offset4(pd, offset, fd, tree, "offset");
4788         return dissect_nfs_length4(pd, offset, fd, tree, "length");
4789 }
4790
4791
4792 int
4793 dissect_nfs_ace4(const u_char *pd, int offset, frame_data *fd, 
4794         proto_tree *tree, char *name)
4795 {
4796         offset = dissect_nfs_acetype4(pd, offset, fd, tree, "type");
4797         offset = dissect_nfs_aceflag4(pd, offset, fd, tree, "flag");
4798         offset = dissect_nfs_acemask4(pd, offset, fd, tree, "access_mask");
4799         return dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_ace4, NULL);
4800 }
4801
4802 static const value_string names_open4_result_flags[] = {
4803 #define OPEN4_RESULT_MLOCK 0x00000001
4804         { OPEN4_RESULT_MLOCK, "OPEN4_RESULT_MLOCK" }, 
4805 #define OPEN4_RESULT_CONFIRM 0x00000002
4806         { OPEN4_RESULT_CONFIRM, "OPEN4_RESULT_CONFIRM" },
4807         { 0, NULL }
4808 };
4809
4810 int 
4811 dissect_nfs_open4_rflags(const u_char *pd, int offset, frame_data *fd, 
4812         proto_tree *tree, char *name)
4813 {
4814         guint rflags;
4815         proto_item *rflags_item = NULL;
4816         proto_item *rflags_tree = NULL;
4817
4818         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4819         rflags = EXTRACT_UINT(pd, offset);
4820
4821         if (tree)
4822         {
4823                 rflags_item = proto_tree_add_text(tree, NullTVB, offset, 4,
4824                         "%s: 0x%08x", name, rflags);
4825
4826                 if (rflags_item)
4827                         rflags_tree = proto_item_add_subtree(rflags_item, 
4828                                 ett_nfs_open4_result_flags);
4829         }
4830
4831         if (rflags_tree)
4832         {
4833                 proto_tree_add_text(rflags_tree, NullTVB, offset, 4, "%s",
4834                         decode_enumerated_bitfield(rflags, OPEN4_RESULT_MLOCK, 2,
4835                         names_open4_result_flags, "%s"));
4836
4837                 proto_tree_add_text(rflags_tree, NullTVB, offset, 4, "%s",
4838                         decode_enumerated_bitfield(rflags, OPEN4_RESULT_CONFIRM, 2,
4839                         names_open4_result_flags, "%s"));
4840         }
4841         
4842         offset += 4;
4843
4844         return offset;
4845 }
4846
4847 int
4848 dissect_nfs_open_read_delegation4(const u_char *pd, int offset, frame_data *fd,
4849         proto_tree *tree)
4850 {
4851         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "stateid");
4852         offset = dissect_rpc_uint32(pd, offset, fd, tree, "recall?");
4853         return dissect_nfs_ace4(pd, offset, fd, tree, "permissions");
4854 }
4855
4856 int
4857 dissect_nfs_modified_limit4(const u_char *pd, int offset, frame_data *fd,
4858         proto_tree *tree, char *name)
4859 {
4860         offset = dissect_rpc_uint32(pd, offset, fd, tree, "num_blocks");
4861         return dissect_rpc_uint32(pd, offset, fd, tree, "bytes_per_block");
4862 }
4863
4864 #define NFS_LIMIT_SIZE                                          1
4865 #define NFS_LIMIT_BLOCKS                                        2
4866 static const value_string names_limit_by4[] = {
4867         {       NFS_LIMIT_SIZE,  "NFS_LIMIT_SIZE"  },
4868         {       NFS_LIMIT_BLOCKS, "NFS_LIMIT_BLOCKS" },
4869         { 0, NULL }
4870 };
4871
4872 int
4873 dissect_nfs_space_limit4(const u_char *pd, int offset, frame_data *fd,
4874         proto_tree *tree, char *name)
4875 {
4876         guint limitby;
4877
4878         limitby = EXTRACT_UINT(pd, offset);
4879         proto_tree_add_uint(tree, hf_nfs_limit_by4, NullTVB, offset+0, 4, limitby);
4880         offset += 4;
4881
4882         switch(limitby)
4883         {
4884         case NFS_LIMIT_SIZE:
4885                 offset = dissect_rpc_uint64(pd, offset, fd, tree, "filesize");
4886                 break;
4887
4888         case NFS_LIMIT_BLOCKS:
4889                 offset = dissect_nfs_modified_limit4(pd, offset, fd, tree, "mod_blocks");
4890                 break;
4891
4892         default:
4893                 break;
4894         }
4895
4896         return offset;
4897 }
4898
4899 int
4900 dissect_nfs_open_write_delegation4(const u_char *pd, int offset, 
4901         frame_data *fd, proto_tree *tree)
4902 {
4903         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "stateid");
4904         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_recall);
4905         offset = dissect_nfs_space_limit4(pd, offset, fd, tree, "space_limit");
4906         return dissect_nfs_ace4(pd, offset, fd, tree, "permissions");
4907 }
4908
4909 #define OPEN_DELEGATE_NONE 0
4910 #define OPEN_DELEGATE_READ 1
4911 #define OPEN_DELEGATE_WRITE 2
4912 static const value_string names_open_delegation_type4[] = {
4913         {       OPEN_DELEGATE_NONE,  "OPEN_DELEGATE_NONE"  },
4914         {       OPEN_DELEGATE_READ,     "OPEN_DELEGATE_READ" },
4915         {       OPEN_DELEGATE_WRITE,    "OPEN_DELEGATE_WRITE" },
4916         { 0, NULL }
4917 };
4918
4919 int
4920 dissect_nfs_open_delegation4(const u_char *pd, int offset, frame_data *fd,
4921         proto_tree *tree, char *name)
4922 {
4923         guint delegation_type;
4924         proto_tree *newftree = NULL;
4925         proto_item *fitem = NULL;
4926
4927         delegation_type = EXTRACT_UINT(pd, offset);
4928         proto_tree_add_uint(tree, hf_nfs_open_delegation_type4, NullTVB, offset+0, 
4929                 4, delegation_type);
4930         offset += 4;
4931
4932         if (fitem) {
4933                 newftree = proto_item_add_subtree(fitem, ett_nfs_open_delegation4);
4934
4935                 switch(delegation_type)
4936                 {
4937                 case OPEN_DELEGATE_NONE:
4938                         break;
4939
4940                 case OPEN_DELEGATE_READ:
4941                         offset = dissect_nfs_open_read_delegation4(pd, offset, fd, newftree);
4942                         break;
4943
4944                 case OPEN_DELEGATE_WRITE:
4945                         offset = dissect_nfs_open_write_delegation4(pd, offset, fd, newftree);
4946                         break;
4947
4948                 default:
4949                         break;
4950                 }
4951         }
4952
4953         return offset;
4954 }
4955
4956
4957 int
4958 dissect_nfs_argop4(const u_char *pd, int offset, frame_data *fd, 
4959         proto_tree *tree, char *name)
4960 {
4961         guint ops, ops_counter;
4962         guint opcode;
4963         proto_item *fitem;
4964         proto_tree *ftree = NULL;
4965         proto_tree *newftree = NULL;
4966
4967         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4968
4969         ops = EXTRACT_UINT(pd, offset+0);
4970
4971         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, 
4972                 "Operations (count: %d)", ops);
4973         offset += 4;
4974
4975         if (fitem == NULL) return offset;
4976
4977         ftree = proto_item_add_subtree(fitem, ett_nfs_argop4);
4978
4979         if (ftree == NULL) return offset;
4980
4981         for (ops_counter=0; ops_counter<ops; ops_counter++)
4982         {
4983                 if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4984
4985                 opcode = EXTRACT_UINT(pd, offset);
4986                 fitem = proto_tree_add_uint(ftree, hf_nfs_argop4, NullTVB, offset, 4, 
4987                         opcode);
4988                 offset += 4;
4989
4990                 if (opcode < NFS4_OP_ACCESS || opcode >NFS4_OP_WRITE)
4991                         break;
4992
4993                 if (fitem == NULL)      break;
4994
4995                 newftree = proto_item_add_subtree(fitem, *nfsv4_operation_ett[opcode-3]);
4996
4997                 if (newftree == NULL)   break;
4998
4999
5000                 switch(opcode)
5001                 {
5002                 case NFS4_OP_ACCESS:
5003                         offset = dissect_access(pd, offset, fd, newftree, "access");
5004                         break;
5005
5006                 case NFS4_OP_CLOSE:
5007                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree);
5008                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5009                         break;
5010
5011                 case NFS4_OP_COMMIT:
5012                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
5013                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "count");
5014                         break;
5015
5016                 case NFS4_OP_CREATE:
5017                         {
5018                                 guint create_type;
5019
5020                                 offset = dissect_nfs_component4(pd, offset, fd, newftree, 
5021                                         "objname");
5022
5023                                 create_type = EXTRACT_UINT(pd, offset);
5024                                 offset = dissect_nfs_ftype4(pd, offset, fd, newftree, "type");
5025
5026                                 switch(create_type)
5027                                 {
5028                                 case NF4LNK:
5029                                         offset = dissect_nfs_linktext4(pd, offset, fd, newftree, 
5030                                                 "linkdata");
5031                                         break;
5032                                 
5033                                 case NF4BLK:
5034                                 case NF4CHR:
5035                                         offset = dissect_nfs_specdata4(pd, offset, fd, 
5036                                                 newftree, "devdata");
5037                                         break;
5038
5039                                 case NF4SOCK:
5040                                 case NF4FIFO:
5041                                 case NF4DIR:
5042                                         break;
5043
5044                                 default:
5045                                         break;
5046                                 }
5047                         }
5048                         break;
5049
5050                 case NFS4_OP_DELEGPURGE:
5051                         offset = dissect_nfs_clientid4(pd, offset, fd, newftree, "Client ID");
5052                         break;
5053
5054                 case NFS4_OP_DELEGRETURN:
5055                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5056                         break;
5057
5058                 case NFS4_OP_GETATTR:
5059                         offset = dissect_nfs_attributes(pd, offset, fd, newftree, "attr_request", 0);
5060                         break;
5061
5062                 case NFS4_OP_GETFH:
5063                         break;
5064
5065                 case NFS4_OP_LINK:
5066                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "newname");
5067                         break;
5068
5069                 case NFS4_OP_LOCK:
5070                         offset = dissect_nfs_lock_type4(pd, offset, fd, newftree, "locktype");
5071                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree);
5072                         offset = dissect_nfs_reclaim4(pd, offset, fd, newftree, "reclaim");
5073                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5074                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
5075                         offset = dissect_nfs_length4(pd, offset, fd, newftree, "length");
5076                         break;
5077
5078                 case NFS4_OP_LOCKT:
5079                         offset = dissect_nfs_lock_type4(pd, offset, fd, newftree, "locktype");
5080                         offset = dissect_nfs_lockowner4(pd, offset, fd, newftree, "owner");
5081                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
5082                         offset = dissect_nfs_length4(pd, offset, fd, newftree, "length");
5083                         break;
5084
5085                 case NFS4_OP_LOCKU:
5086                         offset = dissect_nfs_lock_type4(pd, offset, fd, newftree, "type");
5087                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree);
5088                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5089                         offset =        dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
5090                         offset = dissect_nfs_length4(pd, offset, fd, newftree, "length");
5091                         break;
5092
5093                 case NFS4_OP_LOOKUP:
5094                         offset = dissect_nfs_pathname4(pd, offset, fd, newftree, "path");
5095                         break;
5096
5097                 case NFS4_OP_LOOKUPP:
5098                         break;
5099
5100                 case NFS4_OP_NVERIFY:
5101                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
5102                                 "obj_attributes");
5103                         break;
5104
5105                 case NFS4_OP_OPEN:
5106                         offset = dissect_nfs_open_claim4(pd, offset, fd, newftree, "claim");
5107                         offset = dissect_nfs_openflag4(pd, offset, fd, newftree);
5108                         offset = dissect_nfs_lockowner4(pd, offset, fd, newftree, "Owner");
5109                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree);
5110                         offset = dissect_nfs_open4_share_access(pd, offset, fd, newftree);
5111                         offset = dissect_nfs_open4_share_deny(pd, offset, fd, newftree);
5112                         break;
5113
5114                 case NFS4_OP_OPENATTR:
5115                         break;
5116
5117                 case NFS4_OP_OPEN_CONFIRM:
5118                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree);
5119                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, 
5120                                 "verifier");
5121                         break;
5122
5123                 case NFS4_OP_OPEN_DOWNGRADE:
5124                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5125                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree);
5126                         offset = dissect_nfs_open4_share_access(pd, offset, fd, newftree);
5127                         offset = dissect_nfs_open4_share_deny(pd, offset, fd, newftree);
5128                         break;
5129
5130                 case NFS4_OP_PUTFH:
5131                         offset = dissect_nfs_fh4(pd, offset, fd, newftree, "filehandle");
5132                         break;
5133
5134                 case NFS4_OP_PUTPUBFH:
5135                 case NFS4_OP_PUTROOTFH:
5136                         break;
5137
5138                 case NFS4_OP_READ:
5139                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5140                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
5141                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "count");
5142                         break;
5143
5144                 case NFS4_OP_READDIR:
5145                         offset = dissect_nfs_cookie4(pd, offset, fd, newftree, "cookie");
5146                         offset = dissect_nfs_cookieverf4(pd, offset, fd, newftree, 
5147                                 "cookieverf");
5148                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "dircount");
5149                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "maxcount");
5150                         offset = dissect_nfs_attributes(pd, offset, fd, newftree, "attr", 0);
5151                         break;
5152
5153                 case NFS4_OP_READLINK:
5154                         break;
5155
5156                 case NFS4_OP_REMOVE:
5157                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "target");
5158                         break;
5159
5160                 case NFS4_OP_RENAME:
5161                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "oldname");
5162                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "newname");
5163                         break;
5164
5165                 case NFS4_OP_RENEW:
5166                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5167                         break;
5168         
5169                 case NFS4_OP_RESTOREFH:
5170                 case NFS4_OP_SAVEFH:
5171                         break;
5172
5173                 case NFS4_OP_SECINFO:
5174                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "name");
5175                         break;
5176
5177                 case NFS4_OP_SETATTR:
5178                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5179                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
5180                                 "obj_attributes");
5181                         break;
5182
5183                 case NFS4_OP_SETCLIENTID:
5184                         {
5185                                 proto_tree *client_tree = NULL;
5186
5187                                 fitem = proto_tree_add_text(newftree, NullTVB, offset, 0, "Client");
5188
5189                                 if (fitem) {
5190                                         client_tree = proto_item_add_subtree(fitem, 
5191                                                 ett_nfs_client_id4);
5192
5193                                         if (newftree)
5194                                                 offset = dissect_nfs_client_id4(pd, offset, fd, 
5195                                                         client_tree, "client");
5196                                 }
5197
5198                                 fitem = proto_tree_add_text(newftree, NullTVB, offset, 0,
5199                                         "Callback");
5200                                 if (fitem) {
5201                                         newftree = proto_item_add_subtree(fitem, ett_nfs_cb_client4);
5202                                         if (newftree)
5203                                                 offset = dissect_nfs_cb_client4(pd, offset, fd, newftree, 
5204                                                         "callback");
5205                                 }
5206                         }
5207                         break;
5208
5209                 case NFS4_OP_SETCLIENTID_CONFIRM:
5210                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree,
5211                                                 "setclientid_confirm");
5212                         break;
5213                 
5214                 case NFS4_OP_VERIFY:
5215                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
5216                                                 "obj_attributes");
5217                         break;
5218
5219                 case NFS4_OP_WRITE:
5220                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5221                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
5222                         offset = dissect_nfs_stable_how4(pd, offset, fd, newftree, "stable");
5223                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "data");
5224                         break;
5225                 
5226                 default:
5227                         break;
5228                 }
5229         }
5230
5231         return offset;
5232 }
5233
5234 int
5235 dissect_nfs4_compound_call(const u_char* pd, int offset, frame_data* fd, 
5236         proto_tree* tree)
5237 {
5238         offset = dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_tag4, NULL);
5239         offset = dissect_rpc_uint32(pd, offset, fd, tree, "minorversion");
5240         offset = dissect_nfs_argop4(pd, offset, fd, tree, "arguments");
5241
5242         return offset;
5243 }
5244
5245 int
5246 dissect_nfs_resop4(const u_char *pd, int offset, frame_data *fd, 
5247         proto_tree *tree, char *name)
5248 {
5249         guint ops, ops_counter;
5250         guint opcode;
5251         proto_item *fitem;
5252         proto_tree *ftree = NULL;
5253         proto_tree *newftree = NULL;
5254         guint32 status;
5255
5256         ops = EXTRACT_UINT(pd, offset+0);
5257
5258         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, 
5259                 "Operations (count: %d)", ops);
5260         offset += 4;
5261
5262         if (fitem == NULL)      return offset;
5263
5264         ftree = proto_item_add_subtree(fitem, ett_nfs_resop4);
5265
5266         if (ftree == NULL)      return offset;          /* error adding new subtree */
5267
5268         for (ops_counter = 0; ops_counter < ops; ops_counter++)
5269         {
5270                 if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
5271
5272                 opcode = EXTRACT_UINT(pd, offset);
5273
5274                 if (opcode < NFS4_OP_ACCESS || opcode > NFS4_OP_WRITE)  break;
5275
5276                 if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
5277
5278                 fitem = proto_tree_add_uint(ftree, hf_nfs_resop4, NullTVB, offset, 4, 
5279                         opcode);
5280                 offset += 4;
5281
5282                 if (fitem == NULL)      break;          /* error adding new item to tree */
5283
5284                 newftree = proto_item_add_subtree(fitem, *nfsv4_operation_ett[opcode-3]);
5285
5286                 if (newftree == NULL)
5287                         break;          /* error adding new subtree to operation item */
5288
5289                 offset = dissect_nfs_nfsstat4(pd, offset, fd, newftree, &status);
5290
5291                 /*
5292                  * With the exception of NFS4_OP_LOCK, NFS4_OP_LOCKT, and 
5293                  * NFS4_OP_SETATTR, all other ops do *not* return data with the
5294                  * failed status code.
5295                  */
5296                 if ((status != NFS4_OK) &&
5297                         ((opcode != NFS4_OP_LOCK) && (opcode != NFS4_OP_LOCKT) &&
5298                         (opcode != NFS4_OP_SETATTR)))
5299                         continue;
5300
5301                 /* These parsing routines are only executed if the status is NFS4_OK */
5302                 switch(opcode)
5303                 {
5304                 case NFS4_OP_ACCESS:
5305                         offset = dissect_access(pd, offset, fd, newftree, "Supported");
5306                         offset = dissect_access(pd, offset, fd, newftree, "Access");
5307                         break;
5308
5309                 case NFS4_OP_CLOSE:
5310                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5311                         break;
5312
5313                 case NFS4_OP_COMMIT:
5314                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, "writeverf");
5315                         break;
5316
5317                 case NFS4_OP_CREATE:
5318                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, 
5319                                 "change_info");
5320                         break;
5321
5322                 case NFS4_OP_DELEGPURGE:
5323                         /* void */
5324                         break;
5325
5326                 case NFS4_OP_DELEGRETURN:
5327                         /* void */
5328                         break;
5329
5330                 case NFS4_OP_GETATTR:
5331                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
5332                                 "obj_attributes");
5333                         break;
5334
5335                 case NFS4_OP_GETFH:
5336                         offset = dissect_nfs_fh4(pd, offset, fd, newftree, "Filehandle");
5337                         break;
5338
5339                 case NFS4_OP_LINK:
5340                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, 
5341                                 "change_info");
5342                         break;
5343
5344                 case NFS4_OP_LOCK:
5345                 case NFS4_OP_LOCKT:
5346                         if (status==NFS4_OK)
5347                                 offset = dissect_nfs_stateid4(pd, offset, fd, newftree, 
5348                                         "stateid");
5349                         else
5350                         if (status==NFS4ERR_DENIED)
5351                                 offset = dissect_nfs_lock4denied(pd, offset, fd, newftree, 
5352                                         "denied");
5353                         break;
5354
5355                 case NFS4_OP_LOCKU:
5356                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5357                         break;
5358
5359                 case NFS4_OP_LOOKUP:
5360                         /* void */
5361                         break;
5362
5363                 case NFS4_OP_LOOKUPP:
5364                         /* void */
5365                         break;
5366
5367                 case NFS4_OP_NVERIFY:
5368                         /* void */
5369                         break;
5370
5371                 case NFS4_OP_OPEN:
5372                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5373                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, 
5374                                 "change_info");
5375                         offset = dissect_nfs_open4_rflags(pd, offset, fd, newftree, 
5376                                 "result_flags");
5377                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, 
5378                                 "verifier");
5379                         offset = dissect_nfs_open_delegation4(pd, offset, fd, newftree, 
5380                                 "delegation");
5381                         break;
5382
5383                 case NFS4_OP_OPENATTR:
5384                         /* void */
5385                         break;
5386
5387                 case NFS4_OP_OPEN_CONFIRM:
5388                 case NFS4_OP_OPEN_DOWNGRADE:
5389                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "stateid");
5390                         break;
5391
5392                 case NFS4_OP_PUTFH:
5393                         /* void */
5394                         break;
5395
5396                 case NFS4_OP_PUTPUBFH:
5397                         /* void */
5398                         break;
5399                 
5400                 case NFS4_OP_PUTROOTFH:
5401                         /* void */
5402                         break;
5403
5404                 case NFS4_OP_READ:
5405                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "eof?");
5406                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "data");
5407                         break;
5408
5409                 case NFS4_OP_READDIR:
5410                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, 
5411                                 "cookieverf");
5412                         offset = dissect_nfs_dirlist4(pd, offset, fd, newftree, "reply");
5413                         break;
5414
5415                 case NFS4_OP_READLINK:
5416                         offset = dissect_nfs_linktext4(pd, offset, fd, newftree, "link");       
5417                         break;
5418
5419                 case NFS4_OP_REMOVE:
5420                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, 
5421                                 "change_info");
5422                         break;
5423
5424                 case NFS4_OP_RENAME:
5425                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, 
5426                                 "source_cinfo");
5427                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree,
5428                                 "target_cinfo");
5429                         break;
5430
5431                 case NFS4_OP_RENEW:
5432                         /* void */
5433                         break;
5434
5435                 case NFS4_OP_RESTOREFH:
5436                         /* void */
5437                         break;
5438
5439                 case NFS4_OP_SAVEFH:
5440                         /* void */
5441                         break;
5442
5443                 case NFS4_OP_SECINFO:
5444                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "flavor");
5445                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "flavor_info");
5446                         break;
5447
5448                 case NFS4_OP_SETATTR:
5449                         offset = dissect_nfs_attributes(pd, offset, fd, newftree, "attrsset",
5450                                 0);
5451                         break;
5452
5453                 case NFS4_OP_SETCLIENTID:
5454                         if (status == NFS4_OK)
5455                         {
5456                                 offset = dissect_nfs_clientid4(pd, offset, fd, newftree, 
5457                                         "Client ID");
5458                                 offset = dissect_nfs_verifier4(pd, offset, fd, newftree,
5459                                         "setclientid_confirm");
5460                         }
5461                         else
5462                         if (status == NFS4ERR_CLID_INUSE)
5463                         {
5464                                 offset = dissect_nfs_clientaddr4(pd, offset, fd, newftree,
5465                                         "client_using");
5466                         }
5467                         break;
5468
5469                 case NFS4_OP_SETCLIENTID_CONFIRM:
5470                         /* void */
5471                         break;
5472
5473                 case NFS4_OP_VERIFY:
5474                         /* void */
5475                         break;
5476
5477                 case NFS4_OP_WRITE:
5478                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "count");
5479                         offset = dissect_nfs_stable_how4(pd, offset, fd, newftree, 
5480                                 "committed");
5481                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree,
5482                                 "writeverf");
5483                         break;
5484
5485                 default:
5486                         break;
5487                 }
5488         }
5489
5490         return offset;
5491 }
5492
5493 int
5494 dissect_nfs4_compound_reply(const u_char* pd, int offset, frame_data* fd, 
5495         proto_tree* tree)
5496 {
5497         guint32 status;
5498
5499         offset = dissect_nfs_nfsstat4(pd, offset, fd, tree, &status);
5500         offset = dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_tag4, NULL);
5501         offset = dissect_nfs_resop4(pd, offset, fd, tree, "arguments");
5502
5503         return offset;
5504 }
5505
5506
5507 /* proc number, "proc name", dissect_request, dissect_reply */
5508 /* NULL as function pointer means: type of arguments is "void". */
5509 static const old_vsff nfs3_proc[] = {
5510         { 0,    "NULL",         /* OK */
5511         NULL,                           NULL },
5512         { 1,    "GETATTR",      /* OK */
5513         dissect_nfs3_getattr_call,      dissect_nfs3_getattr_reply },
5514         { 2,    "SETATTR",      /* OK */
5515         dissect_nfs3_setattr_call,      dissect_nfs3_setattr_reply },
5516         { 3,    "LOOKUP",       /* OK */
5517         dissect_nfs3_lookup_call,       dissect_nfs3_lookup_reply },
5518         { 4,    "ACCESS",       /* OK */
5519         dissect_nfs3_access_call,       dissect_nfs3_access_reply },
5520         { 5,    "READLINK",     /* OK */
5521         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_readlink_reply },
5522         { 6,    "READ",         /* OK */
5523         dissect_nfs3_read_call,         dissect_nfs3_read_reply },
5524         { 7,    "WRITE",        /* OK */
5525         dissect_nfs3_write_call,        dissect_nfs3_write_reply },
5526         { 8,    "CREATE",       /* OK */
5527         dissect_nfs3_create_call,       dissect_nfs3_create_reply },
5528         { 9,    "MKDIR",        /* OK */
5529         dissect_nfs3_mkdir_call,        dissect_nfs3_create_reply },
5530         { 10,   "SYMLINK",      /* OK */
5531         dissect_nfs3_symlink_call,      dissect_nfs3_create_reply },
5532         { 11,   "MKNOD",        /* OK */
5533         dissect_nfs3_mknod_call,        dissect_nfs3_create_reply },
5534         { 12,   "REMOVE",       /* OK */
5535         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
5536         { 13,   "RMDIR",        /* OK */
5537         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
5538         { 14,   "RENAME",       /* OK */
5539         dissect_nfs3_rename_call,       dissect_nfs3_rename_reply },
5540         { 15,   "LINK",         /* OK */
5541         dissect_nfs3_link_call,         dissect_nfs3_link_reply },
5542         { 16,   "READDIR",      /* OK */
5543         dissect_nfs3_readdir_call,      dissect_nfs3_readdir_reply },
5544         { 17,   "READDIRPLUS",  /* OK */
5545         dissect_nfs3_readdirplus_call,  dissect_nfs3_readdirplus_reply },
5546         { 18,   "FSSTAT",       /* OK */
5547         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsstat_reply },
5548         { 19,   "FSINFO",       /* OK */
5549         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsinfo_reply },
5550         { 20,   "PATHCONF",     /* OK */
5551         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_pathconf_reply },
5552         { 21,   "COMMIT",       /* OK */
5553         dissect_nfs3_commit_call,       dissect_nfs3_commit_reply },
5554         { 0,NULL,NULL,NULL }
5555 };
5556 /* end of NFS Version 3 */
5557
5558 static const old_vsff nfs4_proc[] = {
5559         { 0, "NULL",
5560         NULL, NULL },
5561         { 1, "COMPOUND",
5562         dissect_nfs4_compound_call, dissect_nfs4_compound_reply },
5563         { 0, NULL, NULL, NULL }
5564 };
5565
5566
5567 static struct true_false_string yesno = { "Yes", "No" };
5568
5569
5570 void
5571 proto_register_nfs(void)
5572 {
5573         static hf_register_info hf[] = {
5574                 { &hf_nfs_fh_fsid_major, {
5575                         "major", "nfs.fh.fsid.major", FT_UINT32, BASE_DEC,
5576                         NULL, 0, "major file system ID" }},
5577                 { &hf_nfs_fh_fsid_minor, {
5578                         "minor", "nfs.fh.fsid.minor", FT_UINT32, BASE_DEC,
5579                         NULL, 0, "minor file system ID" }},
5580                 { &hf_nfs_fh_xfsid_major, {
5581                         "exported major", "nfs.fh.xfsid.major", FT_UINT32, BASE_DEC,
5582                         NULL, 0, "exported major file system ID" }},
5583                 { &hf_nfs_fh_xfsid_minor, {
5584                         "exported minor", "nfs.fh.xfsid.minor", FT_UINT32, BASE_DEC,
5585                         NULL, 0, "exported minor file system ID" }},
5586                 { &hf_nfs_fh_fstype, {
5587                         "file system type", "nfs.fh.fstype", FT_UINT32, BASE_DEC,
5588                         NULL, 0, "file system type" }},
5589                 { &hf_nfs_fh_fn, {
5590                         "file number", "nfs.fh.fn", FT_UINT32, BASE_DEC,
5591                         NULL, 0, "file number" }},
5592                 { &hf_nfs_fh_fn_len, {
5593                         "length", "nfs.fh.fn.len", FT_UINT32, BASE_DEC,
5594                         NULL, 0, "file number length" }},
5595                 { &hf_nfs_fh_fn_inode, {
5596                         "inode", "nfs.fh.fn.inode", FT_UINT32, BASE_DEC,
5597                         NULL, 0, "file number inode" }},
5598                 { &hf_nfs_fh_fn_generation, {
5599                         "generation", "nfs.fh.fn.generation", FT_UINT32, BASE_DEC,
5600                         NULL, 0, "file number generation" }},
5601                 { &hf_nfs_fh_xfn, {
5602                         "exported file number", "nfs.fh.xfn", FT_UINT32, BASE_DEC,
5603                         NULL, 0, "exported file number" }},
5604                 { &hf_nfs_fh_xfn_len, {
5605                         "length", "nfs.fh.xfn.len", FT_UINT32, BASE_DEC,
5606                         NULL, 0, "exported file number length" }},
5607                 { &hf_nfs_fh_xfn_inode, {
5608                         "exported inode", "nfs.fh.xfn.inode", FT_UINT32, BASE_DEC,
5609                         NULL, 0, "exported file number inode" }},
5610                 { &hf_nfs_fh_xfn_generation, {
5611                         "generation", "nfs.fh.xfn.generation", FT_UINT32, BASE_DEC,
5612                         NULL, 0, "exported file number generation" }},
5613                 { &hf_nfs_fh_dentry, {
5614                         "dentry", "nfs.fh.dentry", FT_UINT32, BASE_HEX,
5615                         NULL, 0, "dentry (cookie)" }},
5616                 { &hf_nfs_fh_dev, {
5617                         "device", "nfs.fh.dev", FT_UINT32, BASE_DEC,
5618                         NULL, 0, "device" }},
5619                 { &hf_nfs_fh_xdev, {
5620                         "exported device", "nfs.fh.xdev", FT_UINT32, BASE_DEC,
5621                         NULL, 0, "exported device" }},
5622                 { &hf_nfs_fh_dirinode, {
5623                         "directory inode", "nfs.fh.dirinode", FT_UINT32, BASE_DEC,
5624                         NULL, 0, "directory inode" }},
5625                 { &hf_nfs_fh_pinode, {
5626                         "pseudo inode", "nfs.fh.pinode", FT_UINT32, BASE_HEX,
5627                         NULL, 0, "pseudo inode" }},
5628                 { &hf_nfs_fh_hp_len, {
5629                         "length", "nfs.fh.hp.len", FT_UINT32, BASE_DEC,
5630                         NULL, 0, "hash path length" }},
5631                 { &hf_nfs_stat, {
5632                         "Status", "nfs.status2", FT_UINT32, BASE_DEC,
5633                         VALS(names_nfs_stat), 0, "Reply status" }},
5634                 { &hf_nfs_name, {
5635                         "Name", "nfs.name", FT_STRING, BASE_DEC,
5636                         NULL, 0, "Name" }},
5637                 { &hf_nfs_readlink_data, {
5638                         "Data", "nfs.readlink.data", FT_STRING, BASE_DEC,
5639                         NULL, 0, "Symbolic Link Data" }},
5640                 { &hf_nfs_read_offset, {
5641                         "Offset", "nfs.read.offset", FT_UINT32, BASE_DEC,
5642                         NULL, 0, "Read Offset" }},
5643                 { &hf_nfs_read_count, {
5644                         "Count", "nfs.read.count", FT_UINT32, BASE_DEC,
5645                         NULL, 0, "Read Count" }},
5646                 { &hf_nfs_read_totalcount, {
5647                         "Total Count", "nfs.read.totalcount", FT_UINT32, BASE_DEC,
5648                         NULL, 0, "Total Count (obsolete)" }},
5649                 { &hf_nfs_data, {
5650                         "Data", "nfs.data", FT_STRING, BASE_DEC,
5651                         NULL, 0, "Data" }},
5652                 { &hf_nfs_write_beginoffset, {
5653                         "Begin Offset", "nfs.write.beginoffset", FT_UINT32, BASE_DEC,
5654                         NULL, 0, "Begin offset (obsolete)" }},
5655                 { &hf_nfs_write_offset, {
5656                         "Offset", "nfs.write.offset", FT_UINT32, BASE_DEC,
5657                         NULL, 0, "Offset" }},
5658                 { &hf_nfs_write_totalcount, {
5659                         "Total Count", "nfs.write.totalcount", FT_UINT32, BASE_DEC,
5660                         NULL, 0, "Total Count (obsolete)" }},
5661                 { &hf_nfs_symlink_to, {
5662                         "To", "nfs.symlink.to", FT_STRING, BASE_DEC,
5663                         NULL, 0, "Symbolic link destination name" }},
5664                 { &hf_nfs_readdir_cookie, {
5665                         "Cookie", "nfs.readdir.cookie", FT_UINT32, BASE_DEC,
5666                         NULL, 0, "Directory Cookie" }},
5667                 { &hf_nfs_readdir_count, {
5668                         "Count", "nfs.readdir.count", FT_UINT32, BASE_DEC,
5669                         NULL, 0, "Directory Count" }},
5670                 { &hf_nfs_readdir_entry, {
5671                         "Entry", "nfs.readdir.entry", FT_NONE, 0,
5672                         NULL, 0, "Directory Entry" }},
5673                 { &hf_nfs_readdir_entry_fileid, {
5674                         "File ID", "nfs.readdir.entry.fileid", FT_UINT32, BASE_DEC,
5675                         NULL, 0, "File ID" }},
5676                 { &hf_nfs_readdir_entry_name, {
5677                         "Name", "nfs.readdir.entry.name", FT_STRING, BASE_DEC,
5678                         NULL, 0, "Name" }},
5679                 { &hf_nfs_readdirplus_entry_name, {
5680                         "Name", "nfs.readdirplus.entry.name", FT_STRING, BASE_DEC,
5681                         NULL, 0, "Name" }},
5682                 { &hf_nfs_readdir_entry_cookie, {
5683                         "Cookie", "nfs.readdir.entry.cookie", FT_UINT32, BASE_DEC,
5684                         NULL, 0, "Directory Cookie" }},
5685                 { &hf_nfs_readdir_eof, {
5686                         "EOF", "nfs.readdir.eof", FT_UINT32, BASE_DEC,
5687                         NULL, 0, "EOF" }},
5688                 { &hf_nfs_statfs_tsize, {
5689                         "Transfer Size", "nfs.statfs.tsize", FT_UINT32, BASE_DEC,
5690                         NULL, 0, "Transfer Size" }},
5691                 { &hf_nfs_statfs_bsize, {
5692                         "Block Size", "nfs.statfs.bsize", FT_UINT32, BASE_DEC,
5693                         NULL, 0, "Block Size" }},
5694                 { &hf_nfs_statfs_blocks, {
5695                         "Total Blocks", "nfs.statfs.blocks", FT_UINT32, BASE_DEC,
5696                         NULL, 0, "Total Blocks" }},
5697                 { &hf_nfs_statfs_bfree, {
5698                         "Free Blocks", "nfs.statfs.bfree", FT_UINT32, BASE_DEC,
5699                         NULL, 0, "Free Blocks" }},
5700                 { &hf_nfs_statfs_bavail, {
5701                         "Available Blocks", "nfs.statfs.bavail", FT_UINT32, BASE_DEC,
5702                         NULL, 0, "Available Blocks" }},
5703                 { &hf_nfs_ftype3, {
5704                         "Type", "nfs.type", FT_UINT32, BASE_DEC,
5705                         VALS(names_nfs_ftype3), 0, "File Type" }},
5706                 { &hf_nfs_nfsstat3, {
5707                         "Status", "nfs.status", FT_UINT32, BASE_DEC,
5708                         VALS(names_nfs_nfsstat3), 0, "Reply status" }},
5709                 { &hf_nfs_read_eof, {
5710                         "EOF", "nfs.read.eof", FT_BOOLEAN, BASE_NONE,
5711                         &yesno, 0, "EOF" }},
5712                 { &hf_nfs_write_stable, {
5713                         "Stable", "nfs.write.stable", FT_UINT32, BASE_DEC,
5714                         VALS(names_stable_how), 0, "Stable" }},
5715                 { &hf_nfs_write_committed, {
5716                         "Committed", "nfs.write.committed", FT_UINT32, BASE_DEC,
5717                         VALS(names_stable_how), 0, "Committed" }},
5718                 { &hf_nfs_createmode3, {
5719                         "Create Mode", "nfs.createmode", FT_UINT32, BASE_DEC,
5720                         VALS(names_createmode3), 0, "Create Mode" }},
5721                 { &hf_nfs_fsstat_invarsec, {
5722                         "invarsec", "nfs.fsstat.invarsec", FT_UINT32, BASE_DEC,
5723                         NULL, 0, "probable number of seconds of file system invariance" }},
5724                 { &hf_nfs_fsinfo_rtmax, {
5725                         "rtmax", "nfs.fsinfo.rtmax", FT_UINT32, BASE_DEC,
5726                         NULL, 0, "maximum READ request" }},
5727                 { &hf_nfs_fsinfo_rtpref, {
5728                         "rtpref", "nfs.fsinfo.rtpref", FT_UINT32, BASE_DEC,
5729                         NULL, 0, "preferred READ request" }},
5730                 { &hf_nfs_fsinfo_rtmult, {
5731                         "rtmult", "nfs.fsinfo.rtmult", FT_UINT32, BASE_DEC,
5732                         NULL, 0, "suggested READ multiple" }},
5733                 { &hf_nfs_fsinfo_wtmax, {
5734                         "wtmax", "nfs.fsinfo.wtmax", FT_UINT32, BASE_DEC,
5735                         NULL, 0, "maximum WRITE request" }},
5736                 { &hf_nfs_fsinfo_wtpref, {
5737                         "wtpref", "nfs.fsinfo.wtpref", FT_UINT32, BASE_DEC,
5738                         NULL, 0, "preferred WRITE request" }},
5739                 { &hf_nfs_fsinfo_wtmult, {
5740                         "wtmult", "nfs.fsinfo.wtmult", FT_UINT32, BASE_DEC,
5741                         NULL, 0, "suggested WRITE multiple" }},
5742                 { &hf_nfs_fsinfo_dtpref, {
5743                         "dtpref", "nfs.fsinfo.dtpref", FT_UINT32, BASE_DEC,
5744                         NULL, 0, "preferred READDIR request" }},
5745                 { &hf_nfs_fsinfo_properties, {
5746                         "Properties", "nfs.fsinfo.propeties", FT_UINT32, BASE_HEX,
5747                         NULL, 0, "File System Properties" }},
5748                 { &hf_nfs_pathconf_linkmax, {
5749                         "linkmax", "nfs.pathconf.linkmax", FT_UINT32, BASE_DEC,
5750                         NULL, 0, "Maximum number of hard links" }},
5751                 { &hf_nfs_pathconf_name_max, {
5752                         "name_max", "nfs.pathconf.name_max", FT_UINT32, BASE_DEC,
5753                         NULL, 0, "Maximum file name length" }},
5754                 { &hf_nfs_pathconf_no_trunc, {
5755                         "no_trunc", "nfs.pathconf.no_trunc", FT_BOOLEAN, BASE_NONE,
5756                         &yesno, 0, "No long file name truncation" }},
5757                 { &hf_nfs_pathconf_chown_restricted, {
5758                         "chown_restricted", "nfs.pathconf.chown_restricted", FT_BOOLEAN, BASE_NONE,
5759                         &yesno, 0, "chown is restricted to root" }},
5760                 { &hf_nfs_pathconf_case_insensitive, {
5761                         "case_insensitive", "nfs.pathconf.case_insensitive", FT_BOOLEAN, BASE_NONE,
5762                         &yesno, 0, "file names are treated case insensitive" }},
5763                 { &hf_nfs_pathconf_case_preserving, {
5764                         "case_preserving", "nfs.pathconf.case_preserving", FT_BOOLEAN, BASE_NONE,
5765                         &yesno, 0, "file name cases are preserved" }},
5766
5767                 /* NFSv4 */
5768
5769                 { &hf_nfs_argop4, {
5770                         "Opcode", "nfs.call.operation", FT_UINT32, BASE_DEC,
5771                         VALS(names_nfsv4_operation), 0, "Opcode" }},
5772
5773                 { &hf_nfs_resop4,       {
5774                         "Opcode", "nfs.reply.operation", FT_UINT32, BASE_DEC,
5775                         VALS(names_nfsv4_operation), 0, "Opcode" }},
5776
5777                 { &hf_nfs_linktext4, {
5778                         "Name", "nfs.symlink.linktext", FT_STRING, BASE_DEC,
5779                         NULL, 0, "Symbolic link contents" }},
5780
5781                 { &hf_nfs_component4, {
5782                         "Filename", "nfs.pathname.component", FT_STRING, BASE_DEC,
5783                         NULL, 0, "Pathname component" }},
5784
5785                 { &hf_nfs_tag4, {
5786                         "Tag", "nfs.tag", FT_STRING, BASE_DEC,
5787                         NULL, 0, "Tag" }},
5788
5789                 { &hf_nfs_clientid4, {
5790                         "Client ID", "nfs.clientid", FT_STRING, BASE_DEC,
5791                         NULL, 0, "Name" }},
5792
5793                 { &hf_nfs_ace4, {
5794                         "ace", "nfs.ace", FT_STRING, BASE_DEC,
5795                         NULL, 0, "Access Control Entry" }},
5796
5797                 { &hf_nfs_recall, {
5798                         "EOF", "nfs.recall", FT_BOOLEAN, BASE_NONE,
5799                         &yesno, 0, "Recall" }},
5800
5801                 { &hf_nfs_open_claim_type4, {
5802                         "Claim Type", "nfs.open.claim_type", FT_UINT32, BASE_DEC,
5803                         VALS(names_claim_type4), 0, "Claim Type" }},
5804
5805                 { &hf_nfs_opentype4, {
5806                         "Open Type", "nfs.open.opentype", FT_UINT32, BASE_DEC,
5807                         VALS(names_opentype4), 0, "Open Type" }},
5808
5809                 { &hf_nfs_limit_by4, {
5810                         "Space Limit", "nfs.open.limit_by", FT_UINT32, BASE_DEC,
5811                         VALS(names_limit_by4), 0, "Limit By" }},
5812
5813                 { &hf_nfs_open_delegation_type4, {
5814                         "Delegation Type", "nfs.open.delegation_type", FT_UINT32, BASE_DEC,
5815                         VALS(names_open_delegation_type4), 0, "Delegation Type" }},
5816
5817                 { &hf_nfs_ftype4, {
5818                         "nfs_ftype4", "nfs.nfs_ftype4", FT_UINT32, BASE_DEC,
5819                         VALS(names_ftype4), 0, "nfs.nfs_ftype4" }},
5820
5821                 { &hf_nfs_change_info4_atomic, {
5822                         "Atomic", "nfs.change_info.atomic", FT_BOOLEAN, BASE_NONE,
5823                         &yesno, 0, "Atomic" }},
5824
5825                 { &hf_nfs_open4_share_access, {
5826                         "share_access", "nfs.open4.share_access", FT_UINT32, BASE_DEC,
5827                         VALS(names_open4_share_access), 0, "Share Access" }},
5828
5829                 { &hf_nfs_open4_share_deny, {
5830                         "share_deny", "nfs.open4.share_deny", FT_UINT32, BASE_DEC,
5831                         VALS(names_open4_share_deny), 0, "Share Deny" }},
5832
5833 #if 0
5834                 { &hf_nfs_open4_result_flags, {
5835                         "result_flags", "nfs.open4.rflags", FT_UINT32, BASE_HEX,
5836                         VALS(names_open4_result_flags), 0, "Result Flags" }},
5837 #endif
5838
5839                 { &hf_nfs_seqid4, {
5840                         "seqid", "nfs.seqid", FT_UINT32, BASE_HEX,
5841                         NULL, 0, "Sequence ID" }},
5842
5843                 { &hf_nfs_mand_attr, {
5844                         "mand_attr",    "nfs.attr", FT_UINT32, BASE_DEC,
5845                         VALS(names_fattr4), 0, "Mandatory Attribute" }},
5846
5847                 { &hf_nfs_recc_attr, {
5848                         "recc_attr",    "nfs.attr", FT_UINT32, BASE_DEC,
5849                         VALS(names_fattr4), 0, "Recommended Attribute" }},
5850
5851                 { &hf_nfs_time_how4,    {
5852                         "set_it", "nfs.set_it", FT_UINT32, BASE_DEC,
5853                         VALS(names_time_how4), 0, "How To Set Time" }},
5854
5855                 { &hf_nfs_attrlist4, {
5856                         "attr_vals", "nfs.fattr4.attr_vals", FT_STRING, BASE_DEC,
5857                         NULL, 0, "attr_vals" }},
5858
5859                 { &hf_nfs_fattr4_expire_type, {
5860                         "fattr4_expire_type", "nfs.fattr4_expire_type", FT_UINT32, BASE_DEC,
5861                         VALS(names_fattr4_expire_type), 0, "fattr4_expire_type" }},
5862
5863                 { &hf_nfs_fattr4_link_support, {
5864                         "fattr4_link_support", "nfs.fattr4_link_support", FT_BOOLEAN, 
5865                         BASE_NONE, &yesno, 0, "nfs.fattr4_link_support" }},
5866
5867                 { &hf_nfs_fattr4_symlink_support, {
5868                         "fattr4_symlink_support", "nfs.fattr4_symlink_support", FT_BOOLEAN, 
5869                         BASE_NONE, &yesno, 0, "nfs.fattr4_symlink_support" }},
5870
5871                 { &hf_nfs_fattr4_named_attr, {
5872                         "fattr4_named_attr", "nfs.fattr4_named_attr", FT_BOOLEAN, BASE_NONE,
5873                         &yesno, 0, "nfs.fattr4_named_attr" }},
5874
5875                 { &hf_nfs_fattr4_unique_handles, {
5876                         "fattr4_unique_handles", "nfs.fattr4_unique_handles", FT_BOOLEAN, 
5877                         BASE_NONE, &yesno, 0, "nfs.fattr4_unique_handles" }},
5878
5879                 { &hf_nfs_fattr4_archive, {
5880                         "fattr4_archive", "nfs.fattr4_archive", FT_BOOLEAN, 
5881                         BASE_NONE, &yesno, 0, "nfs.fattr4_archive" }},
5882
5883                 { &hf_nfs_fattr4_cansettime, {
5884                         "fattr4_cansettime", "nfs.fattr4_cansettime", FT_BOOLEAN, 
5885                         BASE_NONE, &yesno, 0, "nfs.fattr4_cansettime" }},
5886
5887                 { &hf_nfs_fattr4_case_insensitive, {
5888                         "fattr4_case_insensitive", "nfs.fattr4_case_insensitive", FT_BOOLEAN, 
5889                         BASE_NONE, &yesno, 0, "nfs.fattr4_case_insensitive" }},
5890
5891                 { &hf_nfs_fattr4_case_preserving, {
5892                         "fattr4_case_preserving", "nfs.fattr4_case_preserving", FT_BOOLEAN, 
5893                         BASE_NONE, &yesno, 0, "nfs.fattr4_case_preserving" }},
5894
5895                 { &hf_nfs_fattr4_chown_restricted, {
5896                         "fattr4_chown_restricted", "nfs.fattr4_chown_restricted", FT_BOOLEAN, 
5897                         BASE_NONE, &yesno, 0, "nfs.fattr4_chown_restricted" }},
5898
5899                 { &hf_nfs_fattr4_hidden, {
5900                         "fattr4_hidden", "nfs.fattr4_hidden", FT_BOOLEAN, 
5901                         BASE_NONE, &yesno, 0, "nfs.fattr4_hidden" }},
5902
5903                 { &hf_nfs_fattr4_homogeneous, {
5904                         "fattr4_homogeneous", "nfs.fattr4_homogeneous", FT_BOOLEAN, 
5905                         BASE_NONE, &yesno, 0, "nfs.fattr4_homogeneous" }},
5906
5907                 { &hf_nfs_fattr4_mimetype, {
5908                         "fattr4_mimetype", "nfs.fattr4_mimetype", FT_STRING, BASE_DEC,
5909                         NULL, 0, "nfs.fattr4_mimetype" }},
5910
5911                 { &hf_nfs_fattr4_no_trunc, {
5912                         "fattr4_no_trunc", "nfs.fattr4_no_trunc", FT_BOOLEAN, 
5913                         BASE_NONE, &yesno, 0, "nfs.fattr4_no_trunc" }},
5914
5915                 { &hf_nfs_fattr4_system, {
5916                         "fattr4_system", "nfs.fattr4_system", FT_BOOLEAN, 
5917                         BASE_NONE, &yesno, 0, "nfs.fattr4_system" }},
5918
5919                 { &hf_nfs_who, {
5920                         "who", "nfs.who", FT_STRING, BASE_DEC,
5921                         NULL, 0, "nfs.who" }},
5922
5923                 { &hf_nfs_server, {
5924                         "server", "nfs.server", FT_STRING, BASE_DEC,
5925                         NULL, 0, "nfs.server" }},
5926
5927                 { &hf_nfs_fattr4_owner, {
5928                         "fattr4_owner", "nfs.fattr4_owner", FT_STRING, BASE_DEC,
5929                         NULL, 0, "nfs.fattr4_owner" }},
5930
5931                 { &hf_nfs_fattr4_owner_group, {
5932                         "fattr4_owner_group", "nfs.fattr4_owner_group", FT_STRING, BASE_DEC,
5933                         NULL, 0, "nfs.fattr4_owner_group" }},
5934
5935                 { &hf_nfs_stable_how4, {
5936                         "stable_how4", "nfs.stable_how4", FT_UINT32, BASE_DEC,
5937                         VALS(names_stable_how4), 0, "nfs.stable_how4" }},
5938
5939                 { &hf_nfs_dirlist4_eof, {
5940                         "eof", "nfs.dirlist4.eof", FT_BOOLEAN,
5941                         BASE_NONE, &yesno, 0, "nfs.dirlist4.eof" }},
5942
5943                 { &hf_nfs_data_follows, {
5944                         "data_follows", "nfs.data_follows", FT_BOOLEAN,
5945                         BASE_NONE, &yesno, 0, "nfs.data_follows" }},
5946         };
5947
5948         static gint *ett[] = {
5949                 &ett_nfs,
5950                 &ett_nfs_fh_fsid,
5951                 &ett_nfs_fh_xfsid,
5952                 &ett_nfs_fh_fn,
5953                 &ett_nfs_fh_xfn,
5954                 &ett_nfs_fh_hp,
5955                 &ett_nfs_fhandle,
5956                 &ett_nfs_timeval,
5957                 &ett_nfs_mode,
5958                 &ett_nfs_fattr,
5959                 &ett_nfs_sattr,
5960                 &ett_nfs_diropargs,
5961                 &ett_nfs_readdir_entry,
5962                 &ett_nfs_mode3,
5963                 &ett_nfs_specdata3,
5964                 &ett_nfs_fh3,
5965                 &ett_nfs_nfstime3,
5966                 &ett_nfs_fattr3,
5967                 &ett_nfs_post_op_fh3,
5968                 &ett_nfs_sattr3,
5969                 &ett_nfs_diropargs3,
5970                 &ett_nfs_sattrguard3,
5971                 &ett_nfs_set_mode3,
5972                 &ett_nfs_set_uid3,
5973                 &ett_nfs_set_gid3,
5974                 &ett_nfs_set_size3,
5975                 &ett_nfs_set_atime,
5976                 &ett_nfs_set_mtime,
5977                 &ett_nfs_pre_op_attr,
5978                 &ett_nfs_post_op_attr,
5979                 &ett_nfs_wcc_attr,
5980                 &ett_nfs_wcc_data,
5981                 &ett_nfs_access,
5982                 &ett_nfs_fsinfo_properties,
5983                 &ett_nfs_compound_call4,
5984                 &ett_nfs_utf8string,
5985                 &ett_nfs_argop4,
5986                 &ett_nfs_resop4,
5987                 &ett_nfs_access4,
5988                 &ett_nfs_close4,
5989                 &ett_nfs_commit4,
5990                 &ett_nfs_create4,
5991                 &ett_nfs_delegpurge4,
5992                 &ett_nfs_delegreturn4,
5993                 &ett_nfs_getattr4,
5994                 &ett_nfs_getfh4,
5995                 &ett_nfs_link4,
5996                 &ett_nfs_lock4,
5997                 &ett_nfs_lockt4,
5998                 &ett_nfs_locku4,
5999                 &ett_nfs_lookup4,
6000                 &ett_nfs_lookupp4,
6001                 &ett_nfs_nverify4,
6002                 &ett_nfs_open4,
6003                 &ett_nfs_openattr4,
6004                 &ett_nfs_open_confirm4,
6005                 &ett_nfs_open_downgrade4,
6006                 &ett_nfs_putfh4,
6007                 &ett_nfs_putpubfh4,
6008                 &ett_nfs_putrootfh4,
6009                 &ett_nfs_read4,
6010                 &ett_nfs_readdir4,
6011                 &ett_nfs_readlink4,
6012                 &ett_nfs_remove4,
6013                 &ett_nfs_rename4,
6014                 &ett_nfs_renew4,
6015                 &ett_nfs_restorefh4,
6016                 &ett_nfs_savefh4,
6017                 &ett_nfs_secinfo4,
6018                 &ett_nfs_setattr4,
6019                 &ett_nfs_setclientid4,
6020                 &ett_nfs_setclientid_confirm4,
6021                 &ett_nfs_verify4,
6022                 &ett_nfs_write4,
6023                 &ett_nfs_verifier4,
6024                 &ett_nfs_opaque,
6025                 &ett_nfs_dirlist4,
6026                 &ett_nfs_pathname4,
6027                 &ett_nfs_change_info4,
6028                 &ett_nfs_open_delegation4,
6029                 &ett_nfs_open_claim4,
6030                 &ett_nfs_opentype4,
6031                 &ett_nfs_lockowner4,
6032                 &ett_nfs_cb_client4,
6033                 &ett_nfs_client_id4,
6034                 &ett_nfs_bitmap4,
6035                 &ett_nfs_fattr4,
6036                 &ett_nfs_fsid4,
6037                 &ett_nfs_fs_locations4,
6038                 &ett_nfs_fs_location4,
6039                 &ett_nfs_open4_result_flags
6040         };
6041         proto_nfs = proto_register_protocol("Network File System", "NFS", "nfs");
6042         proto_register_field_array(proto_nfs, hf, array_length(hf));
6043         proto_register_subtree_array(ett, array_length(ett));
6044 }
6045
6046 void
6047 proto_reg_handoff_nfs(void)
6048 {
6049         /* Register the protocol as RPC */
6050         rpc_init_prog(proto_nfs, NFS_PROGRAM, ett_nfs);
6051         /* Register the procedure tables */
6052         old_rpc_init_proc_table(NFS_PROGRAM, 2, nfs2_proc);
6053         old_rpc_init_proc_table(NFS_PROGRAM, 3, nfs3_proc);
6054         old_rpc_init_proc_table(NFS_PROGRAM, 4, nfs4_proc);
6055 }