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