From Mike Frisch: add the FATTR4_MOUNTED_ON_FILEID attribute.
[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-2002, Mike Frisch <frisch@hummingbird.com> (NFSv4 decoding)
5  * $Id: packet-nfs.c,v 1.79 2002/08/08 22:15:07 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-smb.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32
33 #include <string.h>
34
35
36 #include "packet-rpc.h"
37 #include "packet-nfs.h"
38 #include "prefs.h"
39
40
41 static int proto_nfs = -1;
42
43 static int hf_nfs_fh_length = -1;
44 static int hf_nfs_fh_hash = -1;
45 static int hf_nfs_fh_fsid_major = -1;
46 static int hf_nfs_fh_fsid_minor = -1;
47 static int hf_nfs_fh_fsid_inode = -1;
48 static int hf_nfs_fh_xfsid_major = -1;
49 static int hf_nfs_fh_xfsid_minor = -1;
50 static int hf_nfs_fh_fstype = -1;
51 static int hf_nfs_fh_fn = -1;
52 static int hf_nfs_fh_fn_len = -1;
53 static int hf_nfs_fh_fn_inode = -1;
54 static int hf_nfs_fh_fn_generation = -1;
55 static int hf_nfs_fh_xfn = -1;
56 static int hf_nfs_fh_xfn_len = -1;
57 static int hf_nfs_fh_xfn_inode = -1;
58 static int hf_nfs_fh_xfn_generation = -1;
59 static int hf_nfs_fh_dentry = -1;
60 static int hf_nfs_fh_dev = -1;
61 static int hf_nfs_fh_xdev = -1;
62 static int hf_nfs_fh_dirinode = -1;
63 static int hf_nfs_fh_pinode = -1;
64 static int hf_nfs_fh_hp_len = -1;
65 static int hf_nfs_fh_version = -1;
66 static int hf_nfs_fh_auth_type = -1;
67 static int hf_nfs_fh_fsid_type = -1;
68 static int hf_nfs_fh_fileid_type = -1;
69 static int hf_nfs_stat = -1;
70 static int hf_nfs_name = -1;
71 static int hf_nfs_full_name = -1;
72 static int hf_nfs_readlink_data = -1;
73 static int hf_nfs_read_offset = -1;
74 static int hf_nfs_read_count = -1;
75 static int hf_nfs_read_totalcount = -1;
76 static int hf_nfs_data = -1;
77 static int hf_nfs_write_beginoffset = -1;
78 static int hf_nfs_write_offset = -1;
79 static int hf_nfs_write_totalcount = -1;
80 static int hf_nfs_symlink_to = -1;
81 static int hf_nfs_readdir_cookie = -1;
82 static int hf_nfs_readdir_count = -1;
83 static int hf_nfs_readdir_entry = -1;
84 static int hf_nfs_readdir_entry_fileid = -1;
85 static int hf_nfs_readdir_entry_name = -1;
86 static int hf_nfs_readdir_entry_cookie = -1;
87 static int hf_nfs_readdir_entry3_fileid = -1;
88 static int hf_nfs_readdir_entry3_name = -1;
89 static int hf_nfs_readdir_entry3_cookie = -1;
90 static int hf_nfs_readdirplus_entry_fileid = -1;
91 static int hf_nfs_readdirplus_entry_name = -1;
92 static int hf_nfs_readdirplus_entry_cookie = -1;
93 static int hf_nfs_readdir_eof = -1;
94 static int hf_nfs_statfs_tsize = -1;
95 static int hf_nfs_statfs_bsize = -1;
96 static int hf_nfs_statfs_blocks = -1;
97 static int hf_nfs_statfs_bfree = -1;
98 static int hf_nfs_statfs_bavail = -1;
99 static int hf_nfs_ftype3 = -1;
100 static int hf_nfs_nfsstat3 = -1;
101 static int hf_nfs_read_eof = -1;
102 static int hf_nfs_write_stable = -1;
103 static int hf_nfs_write_committed = -1;
104 static int hf_nfs_createmode3 = -1;
105 static int hf_nfs_fsstat_invarsec = -1;
106 static int hf_nfs_fsinfo_rtmax = -1;
107 static int hf_nfs_fsinfo_rtpref = -1;
108 static int hf_nfs_fsinfo_rtmult = -1;
109 static int hf_nfs_fsinfo_wtmax = -1;
110 static int hf_nfs_fsinfo_wtpref = -1;
111 static int hf_nfs_fsinfo_wtmult = -1;
112 static int hf_nfs_fsinfo_dtpref = -1;
113 static int hf_nfs_fsinfo_maxfilesize = -1;
114 static int hf_nfs_fsinfo_properties = -1;
115 static int hf_nfs_pathconf_linkmax = -1;
116 static int hf_nfs_pathconf_name_max = -1;
117 static int hf_nfs_pathconf_no_trunc = -1;
118 static int hf_nfs_pathconf_chown_restricted = -1;
119 static int hf_nfs_pathconf_case_insensitive = -1;
120 static int hf_nfs_pathconf_case_preserving = -1;
121
122 static int hf_nfs_atime = -1;
123 static int hf_nfs_atime_sec = -1;
124 static int hf_nfs_atime_nsec = -1;
125 static int hf_nfs_atime_usec = -1;
126 static int hf_nfs_mtime = -1;
127 static int hf_nfs_mtime_sec = -1;
128 static int hf_nfs_mtime_nsec = -1;
129 static int hf_nfs_mtime_usec = -1;
130 static int hf_nfs_ctime = -1;
131 static int hf_nfs_ctime_sec = -1;
132 static int hf_nfs_ctime_nsec = -1;
133 static int hf_nfs_ctime_usec = -1;
134 static int hf_nfs_dtime = -1;
135 static int hf_nfs_dtime_sec = -1;
136 static int hf_nfs_dtime_nsec = -1;
137
138 static int hf_nfs_fattr_type = -1;
139 static int hf_nfs_fattr_nlink = -1;
140 static int hf_nfs_fattr_uid = -1;
141 static int hf_nfs_fattr_gid = -1;
142 static int hf_nfs_fattr_size = -1;
143 static int hf_nfs_fattr_blocksize = -1;
144 static int hf_nfs_fattr_rdev = -1;
145 static int hf_nfs_fattr_blocks = -1;
146 static int hf_nfs_fattr_fsid = -1;
147 static int hf_nfs_fattr_fileid = -1;
148 static int hf_nfs_fattr3_type = -1;
149 static int hf_nfs_fattr3_nlink = -1;
150 static int hf_nfs_fattr3_uid = -1;
151 static int hf_nfs_fattr3_gid = -1;
152 static int hf_nfs_fattr3_size = -1;
153 static int hf_nfs_fattr3_used = -1;
154 static int hf_nfs_fattr3_rdev = -1;
155 static int hf_nfs_fattr3_fsid = -1;
156 static int hf_nfs_fattr3_fileid = -1;
157 static int hf_nfs_wcc_attr_size = -1;
158 static int hf_nfs_set_size3_size = -1;
159 static int hf_nfs_cookie3 = -1;
160 static int hf_nfs_fsstat3_resok_tbytes = -1;
161 static int hf_nfs_fsstat3_resok_fbytes = -1;
162 static int hf_nfs_fsstat3_resok_abytes = -1;
163 static int hf_nfs_fsstat3_resok_tfiles = -1;
164 static int hf_nfs_fsstat3_resok_ffiles = -1;
165 static int hf_nfs_fsstat3_resok_afiles = -1;
166 static int hf_nfs_uid3 = -1;
167 static int hf_nfs_gid3 = -1;
168 static int hf_nfs_offset3 = -1;
169 static int hf_nfs_count3 = -1;
170 static int hf_nfs_count3_maxcount = -1;
171 static int hf_nfs_count3_dircount= -1;
172
173 /* NFSv4 */
174 static int hf_nfs_argop4 = -1;
175 static int hf_nfs_resop4 = -1;
176 static int hf_nfs_linktext4 = -1;
177 static int hf_nfs_tag4 = -1;
178 static int hf_nfs_component4 = -1;
179 static int hf_nfs_clientid4 = -1;
180 static int hf_nfs_ace4 = -1;
181 static int hf_nfs_recall = -1;
182 static int hf_nfs_open_claim_type4 = -1;
183 static int hf_nfs_opentype4 = -1;
184 static int hf_nfs_limit_by4 = -1;
185 static int hf_nfs_open_delegation_type4 = -1;
186 static int hf_nfs_ftype4 = -1;
187 static int hf_nfs_change_info4_atomic = -1;
188 static int hf_nfs_open4_share_access = -1;
189 static int hf_nfs_open4_share_deny = -1;
190 static int hf_nfs_seqid4 = -1;
191 static int hf_nfs_lock_seqid4 = -1;
192 static int hf_nfs_mand_attr = -1;
193 static int hf_nfs_recc_attr = -1;
194 static int hf_nfs_time_how4 = -1;
195 static int hf_nfs_attrlist4 = -1;
196 static int hf_nfs_fattr4_link_support = -1;
197 static int hf_nfs_fattr4_symlink_support = -1;
198 static int hf_nfs_fattr4_named_attr = -1;
199 static int hf_nfs_fattr4_unique_handles = -1;
200 static int hf_nfs_fattr4_archive = -1;
201 static int hf_nfs_fattr4_cansettime = -1;
202 static int hf_nfs_fattr4_case_insensitive = -1;
203 static int hf_nfs_fattr4_case_preserving = -1;
204 static int hf_nfs_fattr4_chown_restricted = -1;
205 static int hf_nfs_fattr4_hidden = -1;
206 static int hf_nfs_fattr4_homogeneous = -1;
207 static int hf_nfs_fattr4_mimetype = -1;
208 static int hf_nfs_fattr4_no_trunc = -1;
209 static int hf_nfs_fattr4_system = -1;
210 static int hf_nfs_fattr4_owner = -1;
211 static int hf_nfs_fattr4_owner_group = -1;
212 static int hf_nfs_fattr4_size = -1;
213 static int hf_nfs_fattr4_aclsupport = -1;
214 static int hf_nfs_fattr4_lease_time = -1;
215 static int hf_nfs_fattr4_fileid = -1;
216 static int hf_nfs_fattr4_files_avail = -1;
217 static int hf_nfs_fattr4_files_free = -1;
218 static int hf_nfs_fattr4_files_total = -1;
219 static int hf_nfs_fattr4_maxfilesize = -1;
220 static int hf_nfs_fattr4_maxlink = -1;
221 static int hf_nfs_fattr4_maxname = -1;
222 static int hf_nfs_fattr4_numlinks = -1;
223 static int hf_nfs_fattr4_maxread = -1;
224 static int hf_nfs_fattr4_maxwrite = -1;
225 static int hf_nfs_fattr4_quota_hard = -1;
226 static int hf_nfs_fattr4_quota_soft = -1;
227 static int hf_nfs_fattr4_quota_used = -1;
228 static int hf_nfs_fattr4_space_avail = -1;
229 static int hf_nfs_fattr4_space_free = -1;
230 static int hf_nfs_fattr4_space_total = -1;
231 static int hf_nfs_fattr4_space_used = -1;
232 static int hf_nfs_who = -1;
233 static int hf_nfs_server = -1;
234 static int hf_nfs_stable_how4 = -1;
235 static int hf_nfs_dirlist4_eof = -1;
236 static int hf_nfs_stateid4 = -1;
237 static int hf_nfs_offset4 = -1;
238 static int hf_nfs_specdata1 = -1;
239 static int hf_nfs_specdata2 = -1;
240 static int hf_nfs_lock_type4 = -1;
241 static int hf_nfs_reclaim4 = -1;
242 static int hf_nfs_length4 = -1;
243 static int hf_nfs_changeid4 = -1;
244 static int hf_nfs_changeid4_before = -1;
245 static int hf_nfs_changeid4_after = -1;
246 static int hf_nfs_nfstime4_seconds = -1;
247 static int hf_nfs_nfstime4_nseconds = -1;
248 static int hf_nfs_fsid4_major = -1;
249 static int hf_nfs_fsid4_minor = -1;
250 static int hf_nfs_acetype4 = -1;
251 static int hf_nfs_aceflag4 = -1;
252 static int hf_nfs_acemask4 = -1;
253 static int hf_nfs_delegate_type = -1;
254 static int hf_nfs_secinfo_flavor = -1;
255 static int hf_nfs_num_blocks = -1;
256 static int hf_nfs_bytes_per_block = -1;
257 static int hf_nfs_eof = -1;
258 static int hf_nfs_stateid4_delegate_stateid = -1;
259 static int hf_nfs_verifier4 = -1;
260 static int hf_nfs_cookie4 = -1;
261 static int hf_nfs_cookieverf4 = -1;
262 static int hf_nfs_cb_program = -1;
263 static int hf_nfs_cb_location = -1;
264 static int hf_nfs_recall4 = -1;
265 static int hf_nfs_filesize = -1;
266 static int hf_nfs_count4 = -1;
267 static int hf_nfs_count4_dircount = -1;
268 static int hf_nfs_count4_maxcount = -1;
269 static int hf_nfs_minorversion = -1;
270 static int hf_nfs_open_owner4 = -1;
271 static int hf_nfs_lock_owner4 = -1;
272 static int hf_nfs_new_lock_owner = -1;
273 static int hf_nfs_sec_oid4 = -1;
274 static int hf_nfs_qop4 = -1;
275 static int hf_nfs_secinfo_rpcsec_gss_info_service = -1;
276 static int hf_nfs_attrdircreate = -1;
277 static int hf_nfs_client_id4_id = -1;
278 static int hf_nfs_stateid4_other = -1;
279 static int hf_nfs_lock4_reclaim = -1;
280 static int hf_nfs_acl4 = -1;
281 static int hf_nfs_callback_ident = -1;
282 static int hf_nfs_r_netid = -1;
283 static int hf_nfs_r_addr = -1;
284
285 static gint ett_nfs = -1;
286 static gint ett_nfs_fh_encoding = -1;
287 static gint ett_nfs_fh_fsid = -1;
288 static gint ett_nfs_fh_xfsid = -1;
289 static gint ett_nfs_fh_fn = -1;
290 static gint ett_nfs_fh_xfn = -1;
291 static gint ett_nfs_fh_hp = -1;
292 static gint ett_nfs_fh_auth = -1;
293 static gint ett_nfs_fhandle = -1;
294 static gint ett_nfs_timeval = -1;
295 static gint ett_nfs_mode = -1;
296 static gint ett_nfs_fattr = -1;
297 static gint ett_nfs_sattr = -1;
298 static gint ett_nfs_diropargs = -1;
299 static gint ett_nfs_readdir_entry = -1;
300 static gint ett_nfs_mode3 = -1;
301 static gint ett_nfs_specdata3 = -1;
302 static gint ett_nfs_fh3 = -1;
303 static gint ett_nfs_nfstime3 = -1;
304 static gint ett_nfs_fattr3 = -1;
305 static gint ett_nfs_post_op_fh3 = -1;
306 static gint ett_nfs_sattr3 = -1;
307 static gint ett_nfs_diropargs3 = -1;
308 static gint ett_nfs_sattrguard3 = -1;
309 static gint ett_nfs_set_mode3 = -1;
310 static gint ett_nfs_set_uid3 = -1;
311 static gint ett_nfs_set_gid3 = -1;
312 static gint ett_nfs_set_size3 = -1;
313 static gint ett_nfs_set_atime = -1;
314 static gint ett_nfs_set_mtime = -1;
315 static gint ett_nfs_pre_op_attr = -1;
316 static gint ett_nfs_post_op_attr = -1;
317 static gint ett_nfs_wcc_attr = -1;
318 static gint ett_nfs_wcc_data = -1;
319 static gint ett_nfs_access = -1;
320 static gint ett_nfs_fsinfo_properties = -1;
321
322 /* NFSv4 */
323 static gint ett_nfs_compound_call4 = -1;
324 static gint ett_nfs_utf8string = -1;
325 static gint ett_nfs_argop4 = -1;
326 static gint ett_nfs_resop4 = -1;
327 static gint ett_nfs_access4 = -1;
328 static gint ett_nfs_close4 = -1;
329 static gint ett_nfs_commit4 = -1;
330 static gint ett_nfs_create4 = -1;
331 static gint ett_nfs_delegpurge4 = -1;
332 static gint ett_nfs_delegreturn4 = -1;
333 static gint ett_nfs_getattr4 = -1;
334 static gint ett_nfs_getfh4 = -1;
335 static gint ett_nfs_link4 = -1;
336 static gint ett_nfs_lock4 = -1;
337 static gint ett_nfs_lockt4 = -1;
338 static gint ett_nfs_locku4 = -1;
339 static gint ett_nfs_lookup4 = -1;
340 static gint ett_nfs_lookupp4 = -1;
341 static gint ett_nfs_nverify4 = -1;
342 static gint ett_nfs_open4 = -1;
343 static gint ett_nfs_openattr4 = -1;
344 static gint ett_nfs_open_confirm4 = -1;
345 static gint ett_nfs_open_downgrade4 = -1;
346 static gint ett_nfs_putfh4 = -1;
347 static gint ett_nfs_putpubfh4 = -1;
348 static gint ett_nfs_putrootfh4 = -1;
349 static gint ett_nfs_read4 = -1;
350 static gint ett_nfs_readdir4 = -1;
351 static gint ett_nfs_readlink4 = -1;
352 static gint ett_nfs_remove4 = -1;
353 static gint ett_nfs_rename4 = -1;
354 static gint ett_nfs_renew4 = -1;
355 static gint ett_nfs_restorefh4 = -1;
356 static gint ett_nfs_savefh4 = -1;
357 static gint ett_nfs_secinfo4 = -1;
358 static gint ett_nfs_setattr4 = -1;
359 static gint ett_nfs_setclientid4 = -1;
360 static gint ett_nfs_setclientid_confirm4 = -1;
361 static gint ett_nfs_verify4 = -1;
362 static gint ett_nfs_write4 = -1;
363 static gint ett_nfs_verifier4 = -1;
364 static gint ett_nfs_opaque = -1;
365 static gint ett_nfs_dirlist4 = -1;
366 static gint ett_nfs_pathname4 = -1;
367 static gint ett_nfs_change_info4 = -1;
368 static gint ett_nfs_open_delegation4 = -1;
369 static gint ett_nfs_open_claim4 = -1;
370 static gint ett_nfs_opentype4 = -1;
371 static gint ett_nfs_lock_owner4 = -1;
372 static gint ett_nfs_cb_client4 = -1;
373 static gint ett_nfs_client_id4 = -1;
374 static gint ett_nfs_bitmap4 = -1;
375 static gint ett_nfs_fattr4 = -1;
376 static gint ett_nfs_fsid4 = -1;
377 static gint ett_nfs_fs_locations4 = -1;
378 static gint ett_nfs_fs_location4 = -1;
379 static gint ett_nfs_open4_result_flags = -1;
380 static gint ett_nfs_secinfo4_flavor_info = -1;
381 static gint ett_nfs_stateid4 = -1;
382 static gint ett_nfs_fattr4_fh_expire_type = -1;
383 static gint ett_nfs_ace4 = -1;
384 static gint ett_nfs_clientaddr4 = -1;
385 static gint ett_nfs_aceflag4 = -1;
386 static gint ett_nfs_acemask4 = -1;
387
388
389 /* fhandle displayfilters to match also corresponding request/response
390    packet in addition to the one containing the actual filehandle */
391 gboolean nfs_fhandle_reqrep_matching = FALSE;
392 static GMemChunk *nfs_fhandle_data_chunk = NULL;
393 static int nfs_fhandle_data_init_count = 100;
394 static GHashTable *nfs_fhandle_data_table = NULL;
395 GHashTable *nfs_fhandle_frame_table = NULL;
396
397 static gint
398 nfs_fhandle_data_equal(gconstpointer k1, gconstpointer k2)
399 {
400         nfs_fhandle_data_t *key1 = (nfs_fhandle_data_t *)k1;
401         nfs_fhandle_data_t *key2 = (nfs_fhandle_data_t *)k2;
402
403         return (key1->len==key2->len)
404              &&(!memcmp(key1->fh, key2->fh, key1->len));
405 }
406 static guint
407 nfs_fhandle_data_hash(gconstpointer k)
408 {
409         nfs_fhandle_data_t *key = (nfs_fhandle_data_t *)k;
410         int i;
411         int hash;
412
413         hash=0;
414         for(i=0;i<key->len;i++)
415                 hash ^= key->fh[i];
416
417         return hash;
418 }
419 static gboolean
420 nfs_fhandle_data_free_all(gpointer key_arg _U_, gpointer value, gpointer user_data _U_)
421 {
422         nfs_fhandle_data_t *nns = (nfs_fhandle_data_t *)value;
423
424         if(nns->fh){
425                 tvb_free(nns->tvb);
426                 nns->tvb=NULL;          
427                 g_free((gpointer)nns->fh);
428                 nns->fh=NULL;
429                 nns->len=0;
430         }
431
432         return TRUE;
433 }
434 static gint
435 nfs_fhandle_frame_equal(gconstpointer k1, gconstpointer k2)
436 {
437         guint32 key1 = (guint32)k1;
438         guint32 key2 = (guint32)k2;
439
440         return key1==key2;
441 }
442 static guint
443 nfs_fhandle_frame_hash(gconstpointer k)
444 {
445         guint32 key = (guint32)k;
446
447         return key;
448 }
449 static gboolean
450 nfs_fhandle_frame_free_all(gpointer key_arg _U_, gpointer value _U_, gpointer user_data _U_)
451 {
452         return TRUE;
453 }
454 static void
455 nfs_fhandle_reqrep_matching_init(void)
456 {
457         if (nfs_fhandle_frame_table != NULL) {
458                 g_hash_table_foreach_remove(nfs_fhandle_frame_table,
459                                 nfs_fhandle_frame_free_all, NULL);
460         } else {
461                 nfs_fhandle_frame_table=g_hash_table_new(nfs_fhandle_frame_hash,
462                         nfs_fhandle_frame_equal);
463         }
464
465
466         if (nfs_fhandle_data_table != NULL) {
467                 g_hash_table_foreach_remove(nfs_fhandle_data_table,
468                                 nfs_fhandle_data_free_all, NULL);
469         } else {
470                 nfs_fhandle_data_table=g_hash_table_new(nfs_fhandle_data_hash,
471                         nfs_fhandle_data_equal);
472         }
473
474         if(nfs_fhandle_data_chunk){
475                 g_mem_chunk_destroy(nfs_fhandle_data_chunk);
476                 nfs_fhandle_data_chunk = NULL;
477         }
478
479         if(nfs_fhandle_reqrep_matching){
480                 nfs_fhandle_data_chunk = g_mem_chunk_new("nfs_fhandle_data_chunk",
481                         sizeof(nfs_fhandle_data_t),
482                         nfs_fhandle_data_init_count * sizeof(nfs_fhandle_data_t),
483                         G_ALLOC_ONLY);
484         }
485                 
486 }
487
488
489 /* file name snooping */
490 gboolean nfs_file_name_snooping = FALSE;
491 gboolean nfs_file_name_full_snooping = FALSE;
492 typedef struct nfs_name_snoop {
493         int fh_length;
494         unsigned char *fh;
495         int name_len;
496         unsigned char *name;
497         int parent_len;
498         unsigned char *parent;
499         int full_name_len;
500         unsigned char *full_name;
501 } nfs_name_snoop_t;
502
503 typedef struct nfs_name_snoop_key {
504         int key;
505         int fh_length;
506         unsigned char *fh;
507 } nfs_name_snoop_key_t;
508
509 static GMemChunk *nfs_name_snoop_chunk = NULL;
510 static int nfs_name_snoop_init_count = 100;
511 static GHashTable *nfs_name_snoop_unmatched = NULL;
512
513 static GMemChunk *nfs_name_snoop_key_chunk = NULL;
514 static int nfs_name_snoop_key_init_count = 100;
515 static GHashTable *nfs_name_snoop_matched = NULL;
516
517 static GHashTable *nfs_name_snoop_known = NULL;
518
519 static gint
520 nfs_name_snoop_matched_equal(gconstpointer k1, gconstpointer k2)
521 {
522         nfs_name_snoop_key_t *key1 = (nfs_name_snoop_key_t *)k1;
523         nfs_name_snoop_key_t *key2 = (nfs_name_snoop_key_t *)k2;
524
525         return (key1->key==key2->key)
526              &&(key1->fh_length==key2->fh_length)
527              &&(!memcmp(key1->fh, key2->fh, key1->fh_length));
528 }
529 static guint
530 nfs_name_snoop_matched_hash(gconstpointer k)
531 {
532         nfs_name_snoop_key_t *key = (nfs_name_snoop_key_t *)k;
533         int i;
534         guint hash;
535
536         hash=key->key;
537         for(i=0;i<key->fh_length;i++)
538                 hash ^= key->fh[i];
539
540         return hash;
541 }
542 static gint
543 nfs_name_snoop_unmatched_equal(gconstpointer k1, gconstpointer k2)
544 {
545         guint32 key1 = (guint32)k1;
546         guint32 key2 = (guint32)k2;
547
548         return key1==key2;
549 }
550 static guint
551 nfs_name_snoop_unmatched_hash(gconstpointer k)
552 {
553         guint32 key = (guint32)k;
554
555         return key;
556 }
557 static gboolean
558 nfs_name_snoop_unmatched_free_all(gpointer key_arg _U_, gpointer value, gpointer user_data _U_)
559 {
560         nfs_name_snoop_t *nns = (nfs_name_snoop_t *)value;
561
562         if(nns->name){
563                 g_free((gpointer)nns->name);
564                 nns->name=NULL;
565                 nns->name_len=0;
566         }
567         if(nns->full_name){
568                 g_free((gpointer)nns->full_name);
569                 nns->full_name=NULL;
570                 nns->full_name_len=0;
571         }
572         if(nns->parent){
573                 g_free((gpointer)nns->parent);
574                 nns->parent=NULL;
575                 nns->parent_len=0;
576         }
577         if(nns->fh){
578                 g_free((gpointer)nns->fh);
579                 nns->fh=NULL;
580                 nns->fh_length=0;
581         }
582         return TRUE;
583 }
584
585 static void
586 nfs_name_snoop_init(void)
587 {
588         if (nfs_name_snoop_unmatched != NULL) {
589                 g_hash_table_foreach_remove(nfs_name_snoop_unmatched,
590                                 nfs_name_snoop_unmatched_free_all, NULL);
591         } else {
592                 /* The fragment table does not exist. Create it */
593                 nfs_name_snoop_unmatched=g_hash_table_new(nfs_name_snoop_unmatched_hash,
594                         nfs_name_snoop_unmatched_equal);
595         }
596         if (nfs_name_snoop_matched != NULL) {
597                 g_hash_table_foreach_remove(nfs_name_snoop_matched,
598                                 nfs_name_snoop_unmatched_free_all, NULL);
599         } else {
600                 /* The fragment table does not exist. Create it */
601                 nfs_name_snoop_matched=g_hash_table_new(nfs_name_snoop_matched_hash,
602                         nfs_name_snoop_matched_equal);
603         }
604         if (nfs_name_snoop_known != NULL) {
605                 g_hash_table_foreach_remove(nfs_name_snoop_known,
606                                 nfs_name_snoop_unmatched_free_all, NULL);
607         } else {
608                 /* The fragment table does not exist. Create it */
609                 nfs_name_snoop_known=g_hash_table_new(nfs_name_snoop_matched_hash,
610                         nfs_name_snoop_matched_equal);
611         }
612
613         if(nfs_name_snoop_chunk){
614                 g_mem_chunk_destroy(nfs_name_snoop_chunk);
615                 nfs_name_snoop_chunk = NULL;
616         }
617         if(nfs_name_snoop_key_chunk){
618                 g_mem_chunk_destroy(nfs_name_snoop_key_chunk);
619                 nfs_name_snoop_key_chunk = NULL;
620         }
621
622         if(nfs_file_name_snooping){
623                 nfs_name_snoop_chunk = g_mem_chunk_new("nfs_name_snoop_chunk",
624                         sizeof(nfs_name_snoop_t),
625                         nfs_name_snoop_init_count * sizeof(nfs_name_snoop_t),
626                         G_ALLOC_ONLY);
627                 nfs_name_snoop_key_chunk = g_mem_chunk_new("nfs_name_snoop_key_chunk",
628                         sizeof(nfs_name_snoop_key_t),
629                         nfs_name_snoop_key_init_count * sizeof(nfs_name_snoop_key_t),
630                         G_ALLOC_ONLY);
631         }
632                 
633 }
634
635 void
636 nfs_name_snoop_add_name(int xid, tvbuff_t *tvb, int name_offset, int name_len, int parent_offset, int parent_len, unsigned char *name)
637 {
638         nfs_name_snoop_t *nns, *old_nns;
639         unsigned char *ptr=NULL;
640
641         /* filter out all '.' and '..' names */
642         if(!name){
643                 ptr=(unsigned char *)tvb_get_ptr(tvb, name_offset, name_len);
644                 if(ptr[0]=='.'){
645                         if(ptr[1]==0){
646                                 return;
647                         }
648                         if(ptr[1]=='.'){
649                                 if(ptr[2]==0){
650                                         return;
651                                 }
652                         }
653                 }
654         }
655
656         nns=g_mem_chunk_alloc(nfs_name_snoop_chunk);
657
658         nns->fh_length=0;
659         nns->fh=NULL;
660
661         if(parent_len){
662                 nns->parent_len=parent_len;
663                 nns->parent=g_malloc(parent_len);
664                 memcpy(nns->parent, tvb_get_ptr(tvb, parent_offset, parent_len), parent_len);
665         } else {
666                 nns->parent_len=0;
667                 nns->parent=NULL;
668         }
669
670         nns->name_len=name_len;
671         if(name){
672                 nns->name=name;
673         } else {
674                 nns->name=g_malloc(name_len+1);
675                 memcpy(nns->name, ptr, name_len);
676         }
677         nns->name[name_len]=0;
678
679         nns->full_name_len=0;
680         nns->full_name=NULL;
681
682         /* remove any old entry for this */
683         old_nns=g_hash_table_lookup(nfs_name_snoop_unmatched, (gconstpointer)xid);
684         if(old_nns){
685                 /* if we haven't seen the reply yet, then there are no
686                    matched entries for it, thus we can dealloc the arrays*/
687                 if(!old_nns->fh){
688                         g_free(old_nns->name);
689                         old_nns->name=NULL;
690                         old_nns->name_len=0;
691
692                         g_free(old_nns->parent);
693                         old_nns->parent=NULL;
694                         old_nns->parent_len=0;
695
696                         g_mem_chunk_free(nfs_name_snoop_chunk, old_nns);
697                 }
698                 g_hash_table_remove(nfs_name_snoop_unmatched, (gconstpointer)xid);
699         }
700
701         g_hash_table_insert(nfs_name_snoop_unmatched, (gpointer)xid, nns);
702 }
703
704 static void
705 nfs_name_snoop_add_fh(int xid, tvbuff_t *tvb, int fh_offset, int fh_length)
706 {
707         nfs_name_snoop_t *nns, *old_nns;
708         nfs_name_snoop_key_t *key;
709
710         /* find which request we correspond to */
711         nns=g_hash_table_lookup(nfs_name_snoop_unmatched, (gconstpointer)xid);
712         if(!nns){
713                 /* oops couldnt find matching request, bail out */
714                 return;
715         }
716
717         /* if we have already seen this response earlier */
718         if(nns->fh){
719                 return;
720         }
721
722         /* oki, we have a new entry */
723         nns->fh=g_malloc(fh_length);
724         memcpy(nns->fh, tvb_get_ptr(tvb, fh_offset, fh_length), fh_length);
725         nns->fh_length=fh_length;
726         
727         key=g_mem_chunk_alloc(nfs_name_snoop_key_chunk);
728         key->key=0;
729         key->fh_length=nns->fh_length;
730         key->fh    =nns->fh;
731
732         /* already have something matched for this fh, remove it from
733            the table */
734         old_nns=g_hash_table_lookup(nfs_name_snoop_matched, key);
735         if(old_nns){
736                 g_hash_table_remove(nfs_name_snoop_matched, key);
737         }
738
739         g_hash_table_remove(nfs_name_snoop_unmatched, (gconstpointer)xid);
740         g_hash_table_insert(nfs_name_snoop_matched, key, nns);
741 }
742
743 static void
744 nfs_full_name_snoop(nfs_name_snoop_t *nns, int *len, unsigned char **name, unsigned char **pos)
745 {
746         nfs_name_snoop_t *parent_nns = NULL;
747         nfs_name_snoop_key_t key;
748
749         /* check if the nns component ends with a '/' else we just allocate
750            an extra byte to len to accommodate for it later */
751         if(nns->name[nns->name_len-1]!='/'){
752                 (*len)++;
753         }
754
755         (*len) += nns->name_len;
756
757         if(nns->parent==NULL){
758                 *name = g_malloc((*len)+1);
759                 *pos = *name;
760
761                 strcpy(*pos, nns->name);
762                 *pos += nns->name_len;
763                 return;
764         }
765
766         key.key=0;
767         key.fh_length=nns->parent_len;
768         key.fh=nns->parent;
769
770         parent_nns=g_hash_table_lookup(nfs_name_snoop_matched, &key);
771
772         if(parent_nns){
773                 nfs_full_name_snoop(parent_nns, len, name, pos);
774                 if(*name){
775                         /* make sure components are '/' separated */
776                         if( (*pos)[-1] != '/'){
777                                 **pos='/';
778                                 (*pos)++;
779                                 **pos=0;
780                         }
781                         strcpy(*pos, nns->name);
782                         *pos += nns->name_len;
783                 }
784                 return;
785         }
786
787         return;
788 }
789
790 static void
791 nfs_name_snoop_fh(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int fh_offset, int fh_length, gboolean hidden)
792 {
793         nfs_name_snoop_key_t key;
794         nfs_name_snoop_t *nns = NULL;
795
796         /* if this is a new packet, see if we can register the mapping */
797         if(!pinfo->fd->flags.visited){
798                 key.key=0;
799                 key.fh_length=fh_length;
800                 key.fh=(unsigned char *)tvb_get_ptr(tvb, fh_offset, fh_length);
801
802                 nns=g_hash_table_lookup(nfs_name_snoop_matched, &key);
803                 if(nns){
804                         nfs_name_snoop_key_t *k;
805                         k=g_mem_chunk_alloc(nfs_name_snoop_key_chunk);
806                         k->key=pinfo->fd->num;
807                         k->fh_length=nns->fh_length;
808                         k->fh=nns->fh;
809                         g_hash_table_insert(nfs_name_snoop_known, k, nns);
810
811                         if(nfs_file_name_full_snooping){
812                                 unsigned char *name=NULL, *pos=NULL;
813                                 int len=0;
814
815                                 nfs_full_name_snoop(nns, &len, &name, &pos);
816                                 if(name){
817                                         nns->full_name=name;
818                                         nns->full_name_len=len;
819                                 }
820                         }
821                 }
822         }
823
824         /* see if we know this mapping */
825         if(!nns){
826                 key.key=pinfo->fd->num;
827                 key.fh_length=fh_length;
828                 key.fh=(unsigned char *)tvb_get_ptr(tvb, fh_offset, fh_length);
829
830                 nns=g_hash_table_lookup(nfs_name_snoop_known, &key);
831         }
832
833         /* if we know the mapping, print the filename */
834         if(nns){
835                 if(hidden){
836                         proto_tree_add_string_hidden(tree, hf_nfs_name, tvb, 
837                                 fh_offset, 0, nns->name);
838                 }else {
839                         proto_tree_add_string_format(tree, hf_nfs_name, tvb, 
840                                 fh_offset, 0, nns->name, "Name: %s", nns->name);
841                 }
842                 if(nns->full_name){
843                         if(hidden){
844                                 proto_tree_add_string_hidden(tree, hf_nfs_full_name, tvb, 
845                                         fh_offset, 0, nns->name);
846                         } else {
847                                 proto_tree_add_string_format(tree, hf_nfs_full_name, tvb, 
848                                         fh_offset, 0, nns->name, "Full Name: %s", nns->full_name);
849                         }
850                 }
851         }
852 }
853
854 /* file handle dissection */
855
856 #define FHT_UNKNOWN             0
857 #define FHT_SVR4                1
858 #define FHT_LINUX_KNFSD_LE      2
859 #define FHT_LINUX_NFSD_LE       3
860 #define FHT_LINUX_KNFSD_NEW     4
861
862 static const value_string names_fhtype[] =
863 {
864         {       FHT_UNKNOWN,            "unknown"                               },
865         {       FHT_SVR4,               "System V R4"                           },
866         {       FHT_LINUX_KNFSD_LE,     "Linux knfsd (little-endian)"           },
867         {       FHT_LINUX_NFSD_LE,      "Linux user-land nfsd (little-endian)"  },
868         {       FHT_LINUX_KNFSD_NEW,    "Linux knfsd (new)"                     },
869         {       0,      NULL    }
870 };
871
872
873 /* SVR4: checked with ReliantUNIX (5.43, 5.44, 5.45) */
874
875 static void
876 dissect_fhandle_data_SVR4(tvbuff_t* tvb, int offset, proto_tree *tree,
877     int fhlen _U_)
878 {
879         guint32 nof = offset;
880
881         /* file system id */
882         {
883         guint32 fsid_O;
884         guint32 fsid_L;
885         guint32 temp;
886         guint32 fsid_major;
887         guint32 fsid_minor;
888
889         fsid_O = nof;
890         fsid_L = 4;
891         temp = tvb_get_ntohl(tvb, fsid_O);
892         fsid_major = ( temp>>18 ) &  0x3fff; /* 14 bits */
893         fsid_minor = ( temp     ) & 0x3ffff; /* 18 bits */
894         if (tree) {
895                 proto_item* fsid_item = NULL;
896                 proto_tree* fsid_tree = NULL;
897         
898                 fsid_item = proto_tree_add_text(tree, tvb,
899                         fsid_O, fsid_L, 
900                         "file system ID: %d,%d", fsid_major, fsid_minor);
901                 if (fsid_item) {
902                         fsid_tree = proto_item_add_subtree(fsid_item, 
903                                         ett_nfs_fh_fsid);
904                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
905                                 tvb, fsid_O,   2, fsid_major);
906                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
907                                 tvb, fsid_O+1, 3, fsid_minor);
908                 }
909         }
910         nof = fsid_O + fsid_L;
911         }
912
913         /* file system type */
914         {
915         guint32 fstype_O;
916         guint32 fstype_L;
917         guint32 fstype;
918
919         fstype_O = nof;
920         fstype_L = 4;
921         fstype = tvb_get_ntohl(tvb, fstype_O);
922         if (tree) {
923                 proto_tree_add_uint(tree, hf_nfs_fh_fstype, tvb,
924                         fstype_O, fstype_L, fstype);
925         }
926         nof = fstype_O + fstype_L;
927         }
928
929         /* file number */
930         {
931         guint32 fn_O;
932         guint32 fn_len_O;
933         guint32 fn_len_L;
934         guint32 fn_len;
935         guint32 fn_data_O;
936         guint32 fn_data_inode_O;
937         guint32 fn_data_inode_L;
938         guint32 inode;
939         guint32 fn_data_gen_O;
940         guint32 fn_data_gen_L;
941         guint32 gen;
942         guint32 fn_L;
943         
944         fn_O = nof;
945         fn_len_O = fn_O;
946         fn_len_L = 2;
947         fn_len = tvb_get_ntohs(tvb, fn_len_O);
948         fn_data_O = fn_O + fn_len_L;
949         fn_data_inode_O = fn_data_O + 2;
950         fn_data_inode_L = 4;
951         inode = tvb_get_ntohl(tvb, fn_data_inode_O);
952         fn_data_gen_O = fn_data_inode_O + fn_data_inode_L;
953         fn_data_gen_L = 4;
954         gen = tvb_get_ntohl(tvb, fn_data_gen_O);
955         fn_L = fn_len_L + fn_len;
956         if (tree) {
957                 proto_item* fn_item = NULL;
958                 proto_tree* fn_tree = NULL;
959         
960                 fn_item = proto_tree_add_uint(tree, hf_nfs_fh_fn, tvb,
961                         fn_O, fn_L, inode);
962                 if (fn_item) {
963                         fn_tree = proto_item_add_subtree(fn_item, 
964                                         ett_nfs_fh_fn);
965                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_len,
966                                 tvb, fn_len_O, fn_len_L, fn_len);
967                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_inode,
968                                 tvb, fn_data_inode_O, fn_data_inode_L, inode);
969                         proto_tree_add_uint(fn_tree, hf_nfs_fh_fn_generation,
970                                 tvb, fn_data_gen_O, fn_data_gen_L, gen);
971                 }
972         }
973         nof = fn_O + fn_len_L + fn_len;
974         }
975
976         /* exported file number */
977         {
978         guint32 xfn_O;
979         guint32 xfn_len_O;
980         guint32 xfn_len_L;
981         guint32 xfn_len;
982         guint32 xfn_data_O;
983         guint32 xfn_data_inode_O;
984         guint32 xfn_data_inode_L;
985         guint32 xinode;
986         guint32 xfn_data_gen_O;
987         guint32 xfn_data_gen_L;
988         guint32 xgen;
989         guint32 xfn_L;
990         
991         xfn_O = nof;
992         xfn_len_O = xfn_O;
993         xfn_len_L = 2;
994         xfn_len = tvb_get_ntohs(tvb, xfn_len_O);
995         xfn_data_O = xfn_O + xfn_len_L;
996         xfn_data_inode_O = xfn_data_O + 2;
997         xfn_data_inode_L = 4;
998         xinode = tvb_get_ntohl(tvb, xfn_data_inode_O);
999         xfn_data_gen_O = xfn_data_inode_O + xfn_data_inode_L;
1000         xfn_data_gen_L = 4;
1001         xgen = tvb_get_ntohl(tvb, xfn_data_gen_O);
1002         xfn_L = xfn_len_L + xfn_len;
1003         if (tree) {
1004                 proto_item* xfn_item = NULL;
1005                 proto_tree* xfn_tree = NULL;
1006         
1007                 xfn_item = proto_tree_add_uint(tree, hf_nfs_fh_xfn, tvb,
1008                         xfn_O, xfn_L, xinode);
1009                 if (xfn_item) {
1010                         xfn_tree = proto_item_add_subtree(xfn_item, 
1011                                         ett_nfs_fh_xfn);
1012                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_len,
1013                                 tvb, xfn_len_O, xfn_len_L, xfn_len);
1014                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_inode,
1015                                 tvb, xfn_data_inode_O, xfn_data_inode_L, xinode);
1016                         proto_tree_add_uint(xfn_tree, hf_nfs_fh_xfn_generation,
1017                                 tvb, xfn_data_gen_O, xfn_data_gen_L, xgen);
1018                 }
1019         }
1020         }
1021 }
1022
1023
1024 /* Checked with RedHat Linux 6.2 (kernel 2.2.14 knfsd) */
1025
1026 static void
1027 dissect_fhandle_data_LINUX_KNFSD_LE(tvbuff_t* tvb, int offset, proto_tree *tree,
1028     int fhlen _U_)
1029 {
1030         guint32 dentry;
1031         guint32 inode;
1032         guint32 dirinode;
1033         guint32 temp;
1034         guint32 fsid_major;
1035         guint32 fsid_minor;
1036         guint32 xfsid_major;
1037         guint32 xfsid_minor;
1038         guint32 xinode;
1039         guint32 gen;
1040
1041         dentry   = tvb_get_letohl(tvb, offset+0);
1042         inode    = tvb_get_letohl(tvb, offset+4);
1043         dirinode = tvb_get_letohl(tvb, offset+8);
1044         temp     = tvb_get_letohs (tvb,offset+12);
1045         fsid_major = (temp >> 8) & 0xff;
1046         fsid_minor = (temp     ) & 0xff;
1047         temp     = tvb_get_letohs(tvb,offset+16);
1048         xfsid_major = (temp >> 8) & 0xff;
1049         xfsid_minor = (temp     ) & 0xff;
1050         xinode   = tvb_get_letohl(tvb,offset+20);
1051         gen      = tvb_get_letohl(tvb,offset+24);
1052
1053         if (tree) {
1054                 proto_tree_add_uint(tree, hf_nfs_fh_dentry,
1055                         tvb, offset+0, 4, dentry);
1056                 proto_tree_add_uint(tree, hf_nfs_fh_fn_inode,
1057                         tvb, offset+4, 4, inode);
1058                 proto_tree_add_uint(tree, hf_nfs_fh_dirinode,
1059                         tvb, offset+8, 4, dirinode);
1060
1061                 /* file system id (device) */
1062                 {
1063                 proto_item* fsid_item = NULL;
1064                 proto_tree* fsid_tree = NULL;
1065
1066                 fsid_item = proto_tree_add_text(tree, tvb,
1067                         offset+12, 4, 
1068                         "file system ID: %d,%d", fsid_major, fsid_minor);
1069                 if (fsid_item) {
1070                         fsid_tree = proto_item_add_subtree(fsid_item, 
1071                                         ett_nfs_fh_fsid);
1072                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
1073                                 tvb, offset+13, 1, fsid_major);
1074                         proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
1075                                 tvb, offset+12, 1, fsid_minor);
1076                 }
1077                 }
1078
1079                 /* exported file system id (device) */
1080                 {
1081                 proto_item* xfsid_item = NULL;
1082                 proto_tree* xfsid_tree = NULL;
1083
1084                 xfsid_item = proto_tree_add_text(tree, tvb,
1085                         offset+16, 4, 
1086                         "exported file system ID: %d,%d", xfsid_major, xfsid_minor);
1087                 if (xfsid_item) {
1088                         xfsid_tree = proto_item_add_subtree(xfsid_item, 
1089                                         ett_nfs_fh_xfsid);
1090                         proto_tree_add_uint(xfsid_tree, hf_nfs_fh_xfsid_major,
1091                                 tvb, offset+17, 1, xfsid_major);
1092                         proto_tree_add_uint(xfsid_tree, hf_nfs_fh_xfsid_minor,
1093                                 tvb, offset+16, 1, xfsid_minor);
1094                 }
1095                 }
1096
1097                 proto_tree_add_uint(tree, hf_nfs_fh_xfn_inode,
1098                         tvb, offset+20, 4, xinode);
1099                 proto_tree_add_uint(tree, hf_nfs_fh_fn_generation,
1100                         tvb, offset+24, 4, gen);
1101         }
1102 }
1103
1104
1105 /* Checked with RedHat Linux 5.2 (nfs-server 2.2beta47 user-land nfsd) */
1106
1107 static void
1108 dissect_fhandle_data_LINUX_NFSD_LE(tvbuff_t* tvb, int offset, proto_tree *tree,
1109     int fhlen _U_)
1110 {
1111         /* pseudo inode */
1112         {
1113         guint32 pinode;
1114         pinode   = tvb_get_letohl(tvb, offset+0);
1115         if (tree) {
1116                 proto_tree_add_uint(tree, hf_nfs_fh_pinode,
1117                         tvb, offset+0, 4, pinode);
1118         }
1119         }
1120
1121         /* hash path */
1122         {
1123         guint32 hashlen;
1124
1125         hashlen  = tvb_get_guint8(tvb, offset+4);
1126         if (tree) {
1127                 proto_item* hash_item = NULL;
1128                 proto_tree* hash_tree = NULL;
1129
1130                 hash_item = proto_tree_add_text(tree, tvb, offset+4,
1131                                 hashlen + 1,
1132                                 "hash path: %s",
1133                                 tvb_bytes_to_str(tvb,offset+5,hashlen));
1134                 if (hash_item) {
1135                         hash_tree = proto_item_add_subtree(hash_item, 
1136                                         ett_nfs_fh_hp);
1137                         if (hash_tree) {
1138                                 proto_tree_add_uint(hash_tree,
1139                                         hf_nfs_fh_hp_len, tvb, offset+4, 1,
1140                                         hashlen);
1141                                 proto_tree_add_text(hash_tree, tvb, offset+5,
1142                                         hashlen,
1143                                         "key: %s",
1144                                         tvb_bytes_to_str(tvb,offset+5,hashlen));
1145                         }
1146                 }
1147         }
1148         }
1149 }
1150
1151
1152 /* Checked with SuSE 7.1 (kernel 2.4.0 knfsd) */
1153 /* read linux-2.4.5/include/linux/nfsd/nfsfh.h for more details */
1154
1155 #define AUTH_TYPE_NONE 0
1156 static const value_string auth_type_names[] = {
1157         {       AUTH_TYPE_NONE,                         "no authentication"             },
1158         {0,NULL}
1159 };
1160
1161 #define FSID_TYPE_MAJOR_MINOR_INODE 0
1162 static const value_string fsid_type_names[] = {
1163         {       FSID_TYPE_MAJOR_MINOR_INODE,            "major/minor/inode"             },
1164         {0,NULL}
1165 };
1166
1167 #define FILEID_TYPE_ROOT                        0
1168 #define FILEID_TYPE_INODE_GENERATION            1
1169 #define FILEID_TYPE_INODE_GENERATION_PARENT     2
1170 static const value_string fileid_type_names[] = {
1171         {       FILEID_TYPE_ROOT,                       "root"                          },
1172         {       FILEID_TYPE_INODE_GENERATION,           "inode/generation"              },
1173         {       FILEID_TYPE_INODE_GENERATION_PARENT,    "inode/generation/parent"       },
1174         {0,NULL}
1175 };
1176
1177 static void
1178 dissect_fhandle_data_LINUX_KNFSD_NEW(tvbuff_t* tvb, int offset, proto_tree *tree,
1179     int fhlen _U_)
1180 {
1181         guint8 version;
1182         guint8 auth_type;
1183         guint8 fsid_type;
1184         guint8 fileid_type;
1185
1186         version     = tvb_get_guint8(tvb, offset + 0);
1187         if (tree) {
1188                 proto_tree_add_uint(tree, hf_nfs_fh_version,
1189                         tvb, offset+0, 1, version);
1190         }
1191
1192         switch (version) {
1193                 case 1: {
1194                         auth_type   = tvb_get_guint8(tvb, offset + 1);
1195                         fsid_type   = tvb_get_guint8(tvb, offset + 2);
1196                         fileid_type = tvb_get_guint8(tvb, offset + 3);
1197                         if (tree) {
1198                                 proto_item* encoding_item = proto_tree_add_text(tree, tvb,
1199                                         offset + 1, 3,
1200                                         "encoding: %u %u %u",
1201                                         auth_type, fsid_type, fileid_type);
1202                                 if (encoding_item) {
1203                                         proto_tree* encoding_tree = proto_item_add_subtree(encoding_item,
1204                                                 ett_nfs_fh_encoding);
1205                                         if (encoding_tree) {
1206                                                 proto_tree_add_uint(encoding_tree, hf_nfs_fh_auth_type,
1207                                                         tvb, offset+1, 1, auth_type);
1208                                                 proto_tree_add_uint(encoding_tree, hf_nfs_fh_fsid_type,
1209                                                         tvb, offset+2, 1, fsid_type);
1210                                                 proto_tree_add_uint(encoding_tree, hf_nfs_fh_fileid_type,
1211                                                         tvb, offset+3, 1, fileid_type);
1212                                         }
1213                                 }
1214                         }
1215                         offset += 4;
1216                 } break;
1217                 default: {
1218                         /* unknown version */
1219                         goto out;
1220                 }
1221         }
1222                 
1223         switch (auth_type) {
1224                 case 0: {
1225                         /* no authentication */
1226                         if (tree) {
1227                                 proto_tree_add_text(tree, tvb,
1228                                         offset + 0, 0,
1229                                         "authentication: none");
1230                         }
1231                 } break;
1232                 default: {
1233                         /* unknown authentication type */
1234                         goto out;
1235                 }
1236         }
1237
1238         switch (fsid_type) {
1239                 case 0: {
1240                         guint16 fsid_major;
1241                         guint16 fsid_minor;
1242                         guint32 fsid_inode;
1243
1244                         fsid_major = tvb_get_ntohs(tvb, offset + 0);
1245                         fsid_minor = tvb_get_ntohs(tvb, offset + 2);
1246                         fsid_inode = tvb_get_letohl(tvb, offset + 4);
1247                         if (tree) {
1248                                 proto_item* fsid_item = proto_tree_add_text(tree, tvb,
1249                                         offset+0, 8, 
1250                                         "file system ID: %u,%u (inode %u)",
1251                                         fsid_major, fsid_minor, fsid_inode);
1252                                 if (fsid_item) {
1253                                         proto_tree* fsid_tree = proto_item_add_subtree(fsid_item, 
1254                                                 ett_nfs_fh_fsid);
1255                                         if (fsid_tree) {
1256                                                 proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_major,
1257                                                         tvb, offset+0, 2, fsid_major);
1258                                                 proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_minor,
1259                                                         tvb, offset+2, 2, fsid_minor);
1260                                                 proto_tree_add_uint(fsid_tree, hf_nfs_fh_fsid_inode,
1261                                                         tvb, offset+4, 4, fsid_inode);
1262                                         }
1263                                 }
1264                         }
1265                         offset += 8;
1266                 } break;
1267                 default: {
1268                         /* unknown fsid type */
1269                         goto out;
1270                 }
1271         }
1272
1273         switch (fileid_type) {
1274                 case 0: {
1275                         if (tree) {
1276                                 proto_tree_add_text(tree, tvb,
1277                                         offset+0, 0,
1278                                         "file ID: root inode");
1279                         }
1280                 } break;
1281                 case 1: {
1282                         guint32 inode;
1283                         guint32 generation;
1284
1285                         inode = tvb_get_letohl(tvb, offset + 0);
1286                         generation = tvb_get_letohl(tvb, offset + 4);
1287
1288                         if (tree) {
1289                                 proto_item* fileid_item = proto_tree_add_text(tree, tvb,
1290                                         offset+0, 8,
1291                                         "file ID: %u (%u)",
1292                                         inode, generation);
1293                                 if (fileid_item) {
1294                                         proto_tree* fileid_tree = proto_item_add_subtree(
1295                                                 fileid_item, ett_nfs_fh_fn);
1296                                         if (fileid_tree) {
1297                                                 proto_tree_add_uint(fileid_tree, hf_nfs_fh_fn_inode,
1298                                                 tvb, offset+0, 4, inode);
1299                                                 proto_tree_add_uint(fileid_tree, hf_nfs_fh_fn_generation,
1300                                                 tvb, offset+4, 4, generation);
1301                                         }
1302                                 }
1303                         }
1304
1305                         offset += 8;
1306                 } break;
1307                 case 2: {
1308                         guint32 inode;
1309                         guint32 generation;
1310                         guint32 parent_inode;
1311
1312                         inode = tvb_get_letohl(tvb, offset + 0);
1313                         generation = tvb_get_letohl(tvb, offset + 4);
1314                         parent_inode = tvb_get_letohl(tvb, offset + 8);
1315
1316                         if (tree) {
1317                                  proto_item* fileid_item = proto_tree_add_text(tree, tvb,
1318                                         offset+0, 8,
1319                                         "file ID: %u (%u)",
1320                                         inode, generation);
1321                                 if (fileid_item) {
1322                                         proto_tree* fileid_tree = proto_item_add_subtree(
1323                                                 fileid_item, ett_nfs_fh_fn);
1324                                         if (fileid_tree) {
1325                                                 proto_tree_add_uint(fileid_tree, hf_nfs_fh_fn_inode,
1326                                                 tvb, offset+0, 4, inode);
1327                                                 proto_tree_add_uint(fileid_tree, hf_nfs_fh_fn_generation,
1328                                                 tvb, offset+4, 4, generation);
1329                                                 proto_tree_add_uint(fileid_tree, hf_nfs_fh_dirinode,
1330                                                 tvb, offset+8, 4, parent_inode);
1331                                         }
1332                                 }
1333                         }
1334
1335                         offset += 12;
1336                 } break;
1337                 default: {
1338                         /* unknown fileid type */
1339                         goto out;
1340                 }
1341         }
1342
1343 out:
1344         ;
1345 }
1346
1347
1348 static void
1349 dissect_fhandle_data_unknown(tvbuff_t *tvb, int offset, proto_tree *tree,
1350     int fhlen)
1351 {
1352         int sublen;
1353         int bytes_left;
1354         gboolean first_line;
1355
1356         bytes_left = fhlen;
1357         first_line = TRUE;
1358         while (bytes_left != 0) {
1359                 sublen = 16;
1360                 if (sublen > bytes_left)
1361                         sublen = bytes_left;
1362                 proto_tree_add_text(tree, tvb, offset, sublen,
1363                                         "%s%s",
1364                                         first_line ? "data: " :
1365                                                      "      ",
1366                                         tvb_bytes_to_str(tvb,offset,sublen));
1367                 bytes_left -= sublen;
1368                 offset += sublen;
1369                 first_line = FALSE;
1370         }
1371 }
1372
1373
1374 static void
1375 dissect_fhandle_data(tvbuff_t *tvb, int offset, packet_info *pinfo,
1376     proto_tree *tree, unsigned int fhlen, gboolean hidden)
1377 {
1378         unsigned int fhtype = FHT_UNKNOWN;
1379
1380         /* filehandle too long */
1381         if (fhlen>64) goto type_ready;
1382         /* Not all bytes there. Any attempt to deduce the type would be
1383            senseless. */
1384         if (!tvb_bytes_exist(tvb,offset,fhlen)) goto type_ready;
1385
1386         /* this is to set up fhandle display filters to find both packets
1387            of an RPC call */
1388         if(nfs_fhandle_reqrep_matching && (!hidden) ){
1389                 nfs_fhandle_data_t *old_fhd=NULL;
1390
1391                 if( !pinfo->fd->flags.visited ){
1392                         nfs_fhandle_data_t fhd;
1393
1394                         /* first check if we have seen this fhandle before */
1395                         fhd.len=fhlen;
1396                         fhd.fh=(unsigned char *)tvb_get_ptr(tvb, offset, fhlen);
1397                         old_fhd=g_hash_table_lookup(nfs_fhandle_data_table, 
1398                                 (gconstpointer)&fhd);
1399                         if(!old_fhd){
1400                                 /* oh, a new fhandle, alloc struct and store it in the table*/
1401                                 old_fhd=g_mem_chunk_alloc(nfs_fhandle_data_chunk);
1402                                 old_fhd->len=fhlen;
1403                                 old_fhd->fh=g_malloc(fhlen);
1404                                 memcpy(old_fhd->fh, fhd.fh, fhlen);
1405                                 old_fhd->tvb=tvb_new_real_data(old_fhd->fh, old_fhd->len, old_fhd->len);
1406                                 g_hash_table_insert(nfs_fhandle_data_table, 
1407                                         (gpointer)old_fhd, (gpointer)old_fhd);
1408                         }
1409         
1410                         /* XXX here we should really check that we havent stored
1411                            this fhandle for this frame number already.
1412                            We should also make sure we can handle when we have multiple 
1413                            fhandles seen for the same frame, which WILL happen for certain
1414                            nfs calls. For now, we dont handle this and those calls will
1415                            not work properly with this feature 
1416                         */
1417                         g_hash_table_insert(nfs_fhandle_frame_table,
1418                                         (gpointer)pinfo->fd->num,
1419                                         (gpointer)old_fhd);
1420                 }
1421         }
1422
1423         /* create a semiunique hash value for the filehandle */
1424         {
1425                 guint32 fhhash;
1426                 guint32 i;
1427
1428                 for(fhhash=0,i=0;i<(fhlen-3);i+=4){
1429                         guint32 val;
1430                         val = tvb_get_ntohl(tvb, offset+i);
1431                         fhhash ^= val;
1432                         fhhash += val;
1433                 }
1434                 if(hidden){
1435                         proto_tree_add_uint_hidden(tree, hf_nfs_fh_hash, tvb, offset, 
1436                                 fhlen, fhhash);
1437                 } else {
1438                         proto_tree_add_uint(tree, hf_nfs_fh_hash, tvb, offset, 
1439                                 fhlen, fhhash);
1440                 }
1441         }
1442         if(nfs_file_name_snooping){
1443                 nfs_name_snoop_fh(pinfo, tree, tvb, offset, fhlen, hidden);
1444         }
1445
1446         if(!hidden){            
1447                 /* calculate (heuristically) fhtype */
1448                 switch (fhlen) {
1449                 case 12:
1450                         if (tvb_get_ntohl(tvb,offset) == 0x01000000) {
1451                                         fhtype=FHT_LINUX_KNFSD_NEW;
1452                                 }
1453                         break;
1454                 case 20:
1455                         if (tvb_get_ntohl(tvb,offset) == 0x01000001) {
1456                                 fhtype=FHT_LINUX_KNFSD_NEW;
1457                         }
1458                         break;
1459                 case 24:
1460                         if (tvb_get_ntohl(tvb,offset) == 0x01000002) {
1461                                 fhtype=FHT_LINUX_KNFSD_NEW;
1462                         }
1463                         break;
1464                 case 32: {
1465                         guint32 len1;
1466                         guint32 len2;
1467                         if (tvb_get_ntohs(tvb,offset+4) == 0) {
1468                                 len1=tvb_get_ntohs(tvb,offset+8);
1469                                 if (tvb_bytes_exist(tvb,offset+10+len1,2)) {
1470                                         len2=tvb_get_ntohs(tvb,
1471                                             offset+10+len1);
1472                                         if (fhlen==12+len1+len2) {
1473                                                 fhtype=FHT_SVR4;
1474                                                 goto type_ready;
1475                                         }
1476                                 }
1477                         }
1478                         len1 = tvb_get_guint8(tvb,offset+4);
1479                         if (len1<28 && tvb_bytes_exist(tvb,offset+5,len1)) {
1480                                 int wrong=0;
1481                                 for (len2=5+len1;len2<32;len2++) {
1482                                         if (tvb_get_guint8(tvb,offset+len2)) {
1483                                                 wrong=1;        
1484                                                 break;
1485                                         }
1486                                 }
1487                                 if (!wrong) {
1488                                         fhtype=FHT_LINUX_NFSD_LE;
1489                                         goto type_ready;
1490                                 }
1491                         }
1492                         if (tvb_get_ntohl(tvb,offset+28) == 0) {
1493                                 if (tvb_get_ntohs(tvb,offset+14) == 0) {
1494                                         if (tvb_get_ntohs(tvb,offset+18) == 0) {
1495                                                 fhtype=FHT_LINUX_KNFSD_LE;
1496                                                 goto type_ready;
1497                                         }
1498                                 }
1499                         }
1500                         } break;
1501                 }
1502         }
1503
1504 type_ready:
1505
1506         if(!hidden){
1507                 proto_tree_add_text(tree, tvb, offset, 0, 
1508                         "type: %s", val_to_str(fhtype, names_fhtype, "Unknown"));
1509         
1510
1511                 switch (fhtype) {
1512                 case FHT_SVR4:
1513                         dissect_fhandle_data_SVR4          (tvb, offset, tree,
1514                             fhlen);
1515                 break;
1516                 case FHT_LINUX_KNFSD_LE:
1517                         dissect_fhandle_data_LINUX_KNFSD_LE(tvb, offset, tree,
1518                             fhlen);
1519                 break;
1520                 case FHT_LINUX_NFSD_LE:
1521                         dissect_fhandle_data_LINUX_NFSD_LE (tvb, offset, tree,
1522                             fhlen);
1523                 break;
1524                 case FHT_LINUX_KNFSD_NEW:
1525                         dissect_fhandle_data_LINUX_KNFSD_NEW (tvb, offset, tree,
1526                             fhlen);
1527                 break;
1528                 case FHT_UNKNOWN:
1529                 default:
1530                         dissect_fhandle_data_unknown(tvb, offset, tree, fhlen);
1531                 break;
1532                 }
1533         }
1534 }
1535
1536 void
1537 dissect_fhandle_hidden(packet_info *pinfo, proto_tree *tree, nfs_fhandle_data_t *nfd)
1538 {
1539         if(nfd && nfd->len){
1540                 dissect_fhandle_data(nfd->tvb, 0, pinfo, tree, nfd->len, TRUE);
1541         }
1542 }
1543
1544
1545 /***************************/
1546 /* NFS Version 2, RFC 1094 */
1547 /***************************/
1548
1549
1550 /* RFC 1094, Page 12..14 */
1551 static const value_string names_nfs_stat[] =
1552 {
1553         {       0,      "OK" },
1554         {       1,      "ERR_PERM" },
1555         {       2,      "ERR_NOENT" },
1556         {       5,      "ERR_IO" },
1557         {       6,      "ERR_NX_IO" },
1558         {       13,     "ERR_ACCES" },
1559         {       17,     "ERR_EXIST" },
1560         {       18,     "ERR_XDEV" },   /* not in spec, but can happen */
1561         {       19,     "ERR_NODEV" },
1562         {       20,     "ERR_NOTDIR" },
1563         {       21,     "ERR_ISDIR" },
1564         {       22,     "ERR_INVAL" },  /* not in spec, but I think it can happen */
1565         {       26,     "ERR_TXTBSY" }, /* not in spec, but I think it can happen */
1566         {       27,     "ERR_FBIG" },
1567         {       28,     "ERR_NOSPC" },
1568         {       30,     "ERR_ROFS" },
1569         {       31,     "ERR_MLINK" },  /* not in spec, but can happen */
1570         {       45,     "ERR_OPNOTSUPP" }, /* not in spec, but I think it can happen */
1571         {       63,     "ERR_NAMETOOLONG" },
1572         {       66,     "ERR_NOTEMPTY" },
1573         {       69,     "ERR_DQUOT" },
1574         {       70,     "ERR_STALE" },
1575         {       99,     "ERR_WFLUSH" },
1576         {       0,      NULL }
1577 };
1578
1579 /* NFSv4 Draft Specification, Page 198-199 */
1580 static const value_string names_nfs_stat4[] = {
1581         {       0,      "NFS4_OK"                                       },
1582         {       1,      "NFS4ERR_PERM"                                  },
1583         {       2,      "NFS4ERR_NOENT"                                 },
1584         {       5,      "NFS4ERR_IO"                                    },
1585         {       6,      "NFS4ERR_NXIO"                                  },
1586         {       13,     "NFS4ERR_ACCES"                                 },
1587         {       17,     "NFS4ERR_EXIST"                                 },
1588         {       18,     "NFS4ERR_XDEV"                                  },
1589         {       19,     "NFS4ERR_NODEV"                                 },
1590         {       20,     "NFS4ERR_NOTDIR"                                },
1591         {       21,     "NFS4ERR_ISDIR"                                 },
1592         {       22,     "NFS4ERR_INVAL"                                 },
1593         {       27,     "NFS4ERR_FBIG"                                  },
1594         {       28,     "NFS4ERR_NOSPC"                                 },
1595         {       30,     "NFS4ERR_ROFS"                                  },
1596         {       31,     "NFS4ERR_MLINK"                                 },
1597         {       63,     "NFS4ERR_NAMETOOLONG"                           },
1598         {       66,     "NFS4ERR_NOTEMPTY"                              },
1599         {       69,     "NFS4ERR_DQUOT"                                 },
1600         {       70,     "NFS4ERR_STALE"                                 },
1601         {       10001,  "NFS4ERR_BADHANDLE"                             },
1602         {       10003,  "NFS4ERR_BAD_COOKIE"                            },
1603         {       10004,  "NFS4ERR_NOTSUPP"                               },
1604         {       10005,  "NFS4ERR_TOOSMALL"                              },
1605         {       10006,  "NFS4ERR_SERVERFAULT"                           },
1606         {       10007,  "NFS4ERR_BADTYPE"                               },
1607         {       10008,  "NFS4ERR_DELAY"                                 },
1608         {       10009,  "NFS4ERR_SAME"                                  },
1609         {       10010,  "NFS4ERR_DENIED"                                },
1610         {       10011,  "NFS4ERR_EXPIRED"                               },
1611         {       10012,  "NFS4ERR_LOCKED"                                },
1612         {       10013,  "NFS4ERR_GRACE"                                 },
1613         {       10014,  "NFS4ERR_FHEXPIRED"                             },
1614         {       10015,  "NFS4ERR_SHARE_DENIED"                          },
1615         {       10016,  "NFS4ERR_WRONGSEC"                              },
1616         {       10017,  "NFS4ERR_CLID_INUSE"                            },
1617         {       10018,  "NFS4ERR_RESOURCE"                              },
1618         {       10019,  "NFS4ERR_MOVED"                                 },
1619         {       10020,  "NFS4ERR_NOFILEHANDLE"                          },
1620         {       10021,  "NFS4ERR_MINOR_VERS_MISMATCH"                   },
1621         {       10022,  "NFS4ERR_STALE_CLIENTID"                        },
1622         {       10023,  "NFS4ERR_STALE_STATEID"                         },
1623         {       10024,  "NFS4ERR_OLD_STATEID"                           },
1624         {       10025,  "NFS4ERR_BAD_STATEID"                           },
1625         {       10026,  "NFS4ERR_BAD_SEQID"                             },
1626         {       10027,  "NFS4ERR_NOT_SAME"                              },
1627         {       10028,  "NFS4ERR_LOCK_RANGE"                            },
1628         {       10029,  "NFS4ERR_SYMLINK"                               },
1629         {       10030,  "NFS4ERR_READDIR_NOSPC"                         },
1630         {       10031,  "NFS4ERR_LEASE_MOVED"                           },
1631         {       10032,  "NFS4ERR_ATTRNOTSUPP"                           },
1632         {       10033,  "NFS4ERR_NO_GRACE"                              },
1633         {       10034,  "NFS4ERR_RECLAIM_BAD"                           },
1634         {       10035,  "NFS4ERR_RECLAIM_CONFLICT"                      },
1635         {       10036,  "NFS4ERR_BADXDR"                                },
1636         {       10037,  "NFS4ERR_LOCKS_HELD"                            },
1637         {       10038,  "NFS4ERR_OPENMODE"      },
1638         {       10039,  "NFS4ERR_BADOWNER"      },
1639         { 0, NULL }
1640 };
1641
1642
1643 /* This function has been modified to support NFSv4 style error codes as
1644  * well as being backwards compatible with NFSv2 and NFSv3.
1645  */
1646 static int
1647 dissect_stat_internal(tvbuff_t *tvb, int offset,
1648         proto_tree *tree, guint32* status, int nfsvers)
1649 {
1650         guint32 stat;
1651
1652         stat = tvb_get_ntohl(tvb, offset+0);
1653         
1654         if (tree) {
1655                 /* this gives the right NFSv2 number<->message relation */
1656                 /* and makes it searchable via "nfs.status" */
1657                 proto_tree_add_uint_format(tree, hf_nfs_nfsstat3, tvb,
1658                         offset+0, 4, stat, "Status: %s (%u)", 
1659                         val_to_str(stat, 
1660                                 (nfsvers != 4)? names_nfs_stat: names_nfs_stat4,"%u"), stat);
1661         }
1662
1663         offset += 4;
1664
1665         if (status) *status = stat;
1666
1667         return offset;
1668 }
1669
1670
1671 /* RFC 1094, Page 12..14 */
1672 static int
1673 dissect_stat(tvbuff_t *tvb, int offset, proto_tree *tree,
1674         guint32 *status)
1675 {
1676         return dissect_stat_internal(tvb, offset, tree, status, !4);
1677 }
1678
1679
1680 /* RFC 1094, Page 12..14 */
1681 static int
1682 dissect_nfs2_stat_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree* tree)
1683 {
1684         guint32 status;
1685
1686         offset = dissect_stat(tvb, offset, tree, &status);
1687
1688         return offset;
1689 }
1690
1691
1692 static int
1693 dissect_nfs_nfsstat4(tvbuff_t *tvb, int offset,
1694         proto_tree *tree, guint32 *status)
1695 {
1696         return dissect_stat_internal(tvb, offset, tree, status, 4);
1697 }
1698
1699
1700 /* RFC 1094, Page 15 */
1701 static int
1702 dissect_ftype(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
1703 {
1704         guint32 ftype;
1705         char* ftype_name = NULL;
1706
1707         const value_string nfs2_ftype[] =
1708         {
1709                 {       0,      "Non-File" },
1710                 {       1,      "Regular File" },
1711                 {       2,      "Directory" },
1712                 {       3,      "Block Special Device" },
1713                 {       4,      "Character Special Device" },
1714                 {       5,      "Symbolic Link" },
1715                 {       0,      NULL }
1716         };
1717
1718         ftype = tvb_get_ntohl(tvb, offset+0);
1719         ftype_name = val_to_str(ftype, nfs2_ftype, "%u");
1720         
1721         if (tree) {
1722                 proto_tree_add_text(tree, tvb, offset, 4,
1723                         "%s: %s (%u)", name, ftype_name, ftype);
1724         }
1725
1726         offset += 4;
1727         return offset;
1728 }
1729
1730
1731 /* RFC 1094, Page 15 */
1732 int
1733 dissect_fhandle(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,
1734     char *name)
1735 {
1736         proto_item* fitem;
1737         proto_tree* ftree = NULL;
1738
1739         if (tree) {
1740                 fitem = proto_tree_add_text(tree, tvb, offset, FHSIZE,
1741                         "%s", name);
1742                 if (fitem)
1743                         ftree = proto_item_add_subtree(fitem, ett_nfs_fhandle);
1744         }
1745
1746         /* are we snooping fh to filenames ?*/
1747         if((!pinfo->fd->flags.visited) && nfs_file_name_snooping){
1748                 rpc_call_info_value *civ=pinfo->private_data;
1749
1750                 /* NFS v2 LOOKUP, CREATE, MKDIR calls might give us a mapping*/
1751                 if( (civ->prog==100003)
1752                   &&(civ->vers==2)
1753                   &&(!civ->request)
1754                   &&((civ->proc==4)||(civ->proc==9)||(civ->proc==14))
1755                 ) {
1756                         nfs_name_snoop_add_fh(civ->xid, tvb, 
1757                                 offset, 32);
1758                 }
1759
1760                 /* MOUNT v1,v2 MNT replies might give us a filehandle*/
1761                 if( (civ->prog==100005)
1762                   &&(civ->proc==1)
1763                   &&((civ->vers==1)||(civ->vers==2))
1764                   &&(!civ->request)
1765                 ) {
1766                         nfs_name_snoop_add_fh(civ->xid, tvb, 
1767                                 offset, 32);
1768                 }
1769         }
1770
1771         dissect_fhandle_data(tvb, offset, pinfo, ftree, FHSIZE, FALSE);
1772
1773         offset += FHSIZE;
1774         return offset;
1775 }
1776
1777 /* RFC 1094, Page 15 */
1778 static int
1779 dissect_nfs2_fhandle_call(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
1780 {
1781         offset = dissect_fhandle(tvb, offset, pinfo, tree, "object");
1782
1783         return offset;
1784 }
1785
1786
1787 /* RFC 1094, Page 15 */
1788 static int
1789 dissect_timeval(tvbuff_t *tvb, int offset, proto_tree *tree, int hf_time, int hf_time_sec, int hf_time_usec)
1790 {
1791         guint32 seconds;
1792         guint32 useconds;
1793         nstime_t ts;
1794
1795         proto_item* time_item;
1796         proto_tree* time_tree = NULL;
1797
1798         seconds = tvb_get_ntohl(tvb, offset+0);
1799         useconds = tvb_get_ntohl(tvb, offset+4);
1800         ts.secs = seconds;
1801         ts.nsecs = useconds*1000;
1802
1803         if (tree) {
1804                 time_item = proto_tree_add_time(tree, hf_time, tvb, offset, 8,
1805                                 &ts);
1806                 if (time_item)
1807                         time_tree = proto_item_add_subtree(time_item, ett_nfs_timeval);
1808         }
1809
1810         if (time_tree) {
1811                 proto_tree_add_uint(time_tree, hf_time_sec, tvb, offset, 4,
1812                                         seconds);
1813                 proto_tree_add_uint(time_tree, hf_time_usec, tvb, offset+4, 4,
1814                                         useconds);
1815         }
1816         offset += 8;
1817         return offset;
1818 }
1819
1820
1821 /* RFC 1094, Page 16 */
1822 static const value_string nfs2_mode_names[] = {
1823         {       0040000,        "Directory"     },
1824         {       0020000,        "Character Special Device"      },
1825         {       0060000,        "Block Special Device"  },
1826         {       0100000,        "Regular File"  },
1827         {       0120000,        "Symbolic Link" },
1828         {       0140000,        "Named Socket"  },
1829         {       0000000,        NULL            },
1830 };
1831
1832 static int
1833 dissect_mode(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
1834 {
1835         guint32 mode;
1836         proto_item* mode_item = NULL;
1837         proto_tree* mode_tree = NULL;
1838
1839         mode = tvb_get_ntohl(tvb, offset+0);
1840         
1841         if (tree) {
1842                 mode_item = proto_tree_add_text(tree, tvb, offset, 4,
1843                         "%s: 0%o", name, mode);
1844                 if (mode_item)
1845                         mode_tree = proto_item_add_subtree(mode_item, ett_nfs_mode);
1846         }
1847
1848         if (mode_tree) {
1849                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1850                         decode_enumerated_bitfield(mode,  0160000, 16,
1851                         nfs2_mode_names, "%s"));
1852                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1853                 decode_boolean_bitfield(mode,   04000, 16, "Set user id on exec", "not SUID"));
1854                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1855                 decode_boolean_bitfield(mode,   02000, 16, "Set group id on exec", "not SGID"));
1856                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1857                 decode_boolean_bitfield(mode,   01000, 16, "Save swapped text even after use", "not save swapped text"));
1858                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1859                 decode_boolean_bitfield(mode,    0400, 16, "Read permission for owner", "no Read permission for owner"));
1860                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1861                 decode_boolean_bitfield(mode,    0200, 16, "Write permission for owner", "no Write permission for owner"));
1862                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1863                 decode_boolean_bitfield(mode,    0100, 16, "Execute permission for owner", "no Execute permission for owner"));
1864                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1865                 decode_boolean_bitfield(mode,     040, 16, "Read permission for group", "no Read permission for group"));
1866                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1867                 decode_boolean_bitfield(mode,     020, 16, "Write permission for group", "no Write permission for group"));
1868                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1869                 decode_boolean_bitfield(mode,     010, 16, "Execute permission for group", "no Execute permission for group"));
1870                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1871                 decode_boolean_bitfield(mode,      04, 16, "Read permission for others", "no Read permission for others"));
1872                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1873                 decode_boolean_bitfield(mode,      02, 16, "Write permission for others", "no Write permission for others"));
1874                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
1875                 decode_boolean_bitfield(mode,      01, 16, "Execute permission for others", "no Execute permission for others"));
1876         }
1877
1878         offset += 4;
1879         return offset;
1880 }
1881
1882
1883 /* RFC 1094, Page 15 */
1884 static int
1885 dissect_fattr(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
1886 {
1887         proto_item* fattr_item = NULL;
1888         proto_tree* fattr_tree = NULL;
1889         int old_offset = offset;
1890
1891         if (tree) {
1892                 fattr_item = proto_tree_add_text(tree, tvb, offset, -1,
1893                         "%s", name);
1894                 fattr_tree = proto_item_add_subtree(fattr_item, ett_nfs_fattr);
1895         }
1896
1897         offset = dissect_ftype(tvb, offset, fattr_tree, "type");
1898         offset = dissect_mode(tvb, offset, fattr_tree, "mode");
1899         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_nlink, offset);
1900         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_uid, offset);
1901         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_gid, offset);
1902         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_size, offset);
1903         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_blocksize, offset);
1904         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_rdev, offset);
1905         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_blocks, offset);
1906         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_fsid, offset);
1907         offset = dissect_rpc_uint32(tvb, fattr_tree, hf_nfs_fattr_fileid, offset);
1908
1909         offset = dissect_timeval(tvb, offset, fattr_tree, hf_nfs_atime, hf_nfs_atime_sec, hf_nfs_atime_usec);
1910         offset = dissect_timeval(tvb, offset, fattr_tree, hf_nfs_mtime, hf_nfs_mtime_sec, hf_nfs_mtime_usec);
1911         offset = dissect_timeval(tvb, offset, fattr_tree, hf_nfs_ctime, hf_nfs_ctime_sec, hf_nfs_ctime_usec);
1912
1913         /* now we know, that fattr is shorter */
1914         if (fattr_item) {
1915                 proto_item_set_len(fattr_item, offset - old_offset);
1916         }
1917
1918         return offset;
1919 }
1920
1921
1922 /* RFC 1094, Page 17 */
1923 static int
1924 dissect_sattr(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
1925 {
1926         proto_item* sattr_item = NULL;
1927         proto_tree* sattr_tree = NULL;
1928         int old_offset = offset;
1929
1930         if (tree) {
1931                 sattr_item = proto_tree_add_text(tree, tvb, offset, -1,
1932                         "%s", name);
1933                 sattr_tree = proto_item_add_subtree(sattr_item, ett_nfs_sattr);
1934         }
1935
1936         if (tvb_get_ntohl(tvb, offset+0) != 0xffffffff)
1937                 offset = dissect_mode(tvb, offset, sattr_tree, "mode");
1938         else {
1939                 proto_tree_add_text(sattr_tree, tvb, offset, 4, "mode: no value");
1940                 offset += 4;
1941         }
1942
1943         if (tvb_get_ntohl(tvb, offset+0) != 0xffffffff)
1944                 offset = dissect_rpc_uint32(tvb, sattr_tree, hf_nfs_fattr_uid,
1945                         offset);
1946         else {
1947                 proto_tree_add_text(sattr_tree, tvb, offset, 4, "uid: no value");
1948                 offset += 4;
1949         }
1950
1951         if (tvb_get_ntohl(tvb, offset+0) != 0xffffffff)
1952                 offset = dissect_rpc_uint32(tvb, sattr_tree, hf_nfs_fattr_gid,
1953                         offset);
1954         else {
1955                 proto_tree_add_text(sattr_tree, tvb, offset, 4, "gid: no value");
1956                 offset += 4;
1957         }
1958
1959         if (tvb_get_ntohl(tvb, offset+0) != 0xffffffff)
1960                 offset = dissect_rpc_uint32(tvb, sattr_tree, hf_nfs_fattr_size,
1961                         offset);
1962         else {
1963                 proto_tree_add_text(sattr_tree, tvb, offset, 4, "size: no value");
1964                 offset += 4;
1965         }
1966
1967         if (tvb_get_ntohl(tvb, offset+0) != 0xffffffff) {
1968                 offset = dissect_timeval(tvb, offset, sattr_tree, hf_nfs_atime, hf_nfs_atime_sec, hf_nfs_atime_usec);
1969         } else {
1970                 proto_tree_add_text(sattr_tree, tvb, offset, 8, "atime: no value");
1971                 offset += 8;
1972         }
1973
1974         if (tvb_get_ntohl(tvb, offset+0) != 0xffffffff) {
1975                 offset = dissect_timeval(tvb, offset, sattr_tree, hf_nfs_mtime, hf_nfs_mtime_sec, hf_nfs_mtime_usec);
1976         } else {
1977                 proto_tree_add_text(sattr_tree, tvb, offset, 8, "mtime: no value");
1978                 offset += 8;
1979         }
1980
1981         /* now we know, that sattr is shorter */
1982         if (sattr_item) {
1983                 proto_item_set_len(sattr_item, offset - old_offset);
1984         }
1985
1986         return offset;
1987 }
1988
1989
1990 /* RFC 1094, Page 17 */
1991 static int
1992 dissect_filename(tvbuff_t *tvb, int offset,
1993     proto_tree *tree, int hf, char **string_ret)
1994 {
1995         offset = dissect_rpc_string(tvb, tree, hf, offset, string_ret);
1996         return offset;
1997 }
1998
1999
2000 /* RFC 1094, Page 17 */
2001 static int
2002 dissect_path(tvbuff_t *tvb, int offset, proto_tree *tree, int hf)
2003 {
2004         offset = dissect_rpc_string(tvb, tree, hf, offset, NULL);
2005         return offset;
2006 }
2007
2008
2009 /* RFC 1094, Page 17,18 */
2010 static int
2011 dissect_attrstat(tvbuff_t *tvb, int offset, proto_tree *tree)
2012 {
2013         guint32 status;
2014
2015         offset = dissect_stat(tvb, offset, tree, &status);
2016         switch (status) {
2017                 case 0:
2018                         offset = dissect_fattr(tvb, offset, tree, "attributes");
2019                 break;
2020                 default:
2021                         /* do nothing */
2022                 break;
2023         }
2024
2025         return offset;
2026 }
2027
2028
2029 /* RFC 1094, Page 17,18 */
2030 static int
2031 dissect_nfs2_attrstat_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree* tree)
2032 {
2033         offset = dissect_attrstat(tvb, offset, tree);
2034
2035         return offset;
2036 }
2037
2038
2039 /* RFC 1094, Page 18 */
2040 static int
2041 dissect_diropargs(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char* name)
2042 {
2043         proto_item* diropargs_item = NULL;
2044         proto_tree* diropargs_tree = NULL;
2045         int old_offset = offset;
2046
2047         if (tree) {
2048                 diropargs_item = proto_tree_add_text(tree, tvb, offset, -1,
2049                         "%s", name);
2050                 diropargs_tree = proto_item_add_subtree(diropargs_item, ett_nfs_diropargs);
2051         }
2052
2053         /* are we snooping fh to filenames ?*/
2054         if((!pinfo->fd->flags.visited) && nfs_file_name_snooping){
2055                 /* v2 LOOKUP, CREATE, MKDIR calls might give us a mapping*/
2056                 rpc_call_info_value *civ=pinfo->private_data;
2057
2058                 if( (civ->prog==100003)
2059                   &&(civ->vers==2)
2060                   &&(civ->request)
2061                   &&((civ->proc==4)||(civ->proc==9)||(civ->proc==14))
2062                 ) {
2063                         nfs_name_snoop_add_name(civ->xid, tvb, 
2064                                 offset+36, tvb_get_ntohl(tvb, offset+32),
2065                                 offset, 32, NULL);
2066                 }
2067         }
2068
2069         offset = dissect_fhandle (tvb,offset,pinfo,diropargs_tree,"dir");
2070         offset = dissect_filename(tvb,offset,      diropargs_tree,hf_nfs_name,NULL);
2071
2072         /* now we know, that diropargs is shorter */
2073         if (diropargs_item) {
2074                 proto_item_set_len(diropargs_item, offset - old_offset);
2075         }
2076
2077         return offset;
2078 }
2079
2080
2081 /* RFC 1094, Page 18 */
2082 static int
2083 dissect_nfs2_diropargs_call(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
2084 {
2085         offset = dissect_diropargs(tvb, offset, pinfo, tree, "where");
2086
2087         return offset;
2088 }
2089
2090
2091 /* RFC 1094, Page 18 */
2092 static int
2093 dissect_diropres(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
2094 {
2095         guint32 status;
2096
2097         offset = dissect_stat(tvb, offset, tree, &status);
2098         switch (status) {
2099                 case 0:
2100                         offset = dissect_fhandle(tvb, offset, pinfo, tree, "file");
2101                         offset = dissect_fattr  (tvb, offset, tree, "attributes");
2102                 break;
2103                 default:
2104                         /* do nothing */
2105                 break;
2106         }
2107
2108         return offset;
2109 }
2110
2111
2112 /* nfsdata is simply a chunk of RPC opaque data (length, data, fill bytes) */
2113 static int
2114 dissect_nfsdata(tvbuff_t *tvb, int offset, proto_tree *tree, int hf)
2115 {
2116         offset = dissect_rpc_data(tvb, tree, hf, offset);
2117         return offset;
2118 }
2119
2120
2121 /* RFC 1094, Page 18 */
2122 static int
2123 dissect_nfs2_diropres_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2124         proto_tree* tree)
2125 {
2126         offset = dissect_diropres(tvb, offset, pinfo, tree);
2127         return offset;
2128 }
2129
2130
2131 /* RFC 1094, Page 6 */
2132 static int
2133 dissect_nfs2_setattr_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2134         proto_tree *tree)
2135 {
2136         offset = dissect_fhandle(tvb, offset, pinfo, tree, "file"      );
2137         offset = dissect_sattr  (tvb, offset,        tree, "attributes");
2138
2139         return offset;
2140 }
2141
2142
2143 /* RFC 1094, Page 6 */
2144 static int
2145 dissect_nfs2_readlink_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, 
2146         proto_tree *tree)
2147 {
2148         guint32 status;
2149
2150         offset = dissect_stat(tvb, offset, tree, &status);
2151         switch (status) {
2152                 case 0:
2153                         offset = dissect_path(tvb, offset, tree, hf_nfs_readlink_data);
2154                 break;
2155                 default:
2156                         /* do nothing */
2157                 break;
2158         }
2159
2160         return offset;
2161 }
2162
2163
2164 /* RFC 1094, Page 7 */
2165 static int
2166 dissect_nfs2_read_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2167         proto_tree *tree)
2168 {
2169         guint32 offset_value;
2170         guint32 count;
2171         guint32 totalcount;
2172
2173         offset = dissect_fhandle(tvb, offset, pinfo, tree, "file"      );
2174         offset_value = tvb_get_ntohl(tvb, offset+0);
2175         count        = tvb_get_ntohl(tvb, offset+4);
2176         totalcount   = tvb_get_ntohl(tvb, offset+8);
2177         if (tree) {
2178                 proto_tree_add_uint(tree, hf_nfs_read_offset, tvb, 
2179                 offset+0, 4, offset_value);
2180                 proto_tree_add_uint(tree, hf_nfs_read_count, tvb, 
2181                 offset+4, 4, count);
2182                 proto_tree_add_uint(tree, hf_nfs_read_totalcount, tvb, 
2183                 offset+8, 4, totalcount);
2184         }
2185         offset += 12;
2186
2187         return offset;
2188 }
2189
2190
2191 /* RFC 1094, Page 7 */
2192 static int
2193 dissect_nfs2_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, 
2194         proto_tree* tree)
2195 {
2196         guint32 status;
2197
2198         offset = dissect_stat(tvb, offset, tree, &status);
2199         switch (status) {
2200                 case 0:
2201                         offset = dissect_fattr(tvb, offset, tree, "attributes");
2202                         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_data); 
2203                 break;
2204                 default:
2205                         /* do nothing */
2206                 break;
2207         }
2208
2209         return offset;
2210 }
2211
2212
2213 /* RFC 1094, Page 8 */
2214 static int
2215 dissect_nfs2_write_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2216         proto_tree *tree)
2217 {
2218         guint32 beginoffset;
2219         guint32 offset_value;
2220         guint32 totalcount;
2221
2222         offset = dissect_fhandle(tvb, offset, pinfo, tree, "file"      );
2223         beginoffset  = tvb_get_ntohl(tvb, offset+0);
2224         offset_value = tvb_get_ntohl(tvb, offset+4);
2225         totalcount   = tvb_get_ntohl(tvb, offset+8);
2226         if (tree) {
2227                 proto_tree_add_uint(tree, hf_nfs_write_beginoffset, tvb, 
2228                 offset+0, 4, beginoffset);
2229                 proto_tree_add_uint(tree, hf_nfs_write_offset, tvb, 
2230                 offset+4, 4, offset_value);
2231                 proto_tree_add_uint(tree, hf_nfs_write_totalcount, tvb, 
2232                 offset+8, 4, totalcount);
2233         }
2234         offset += 12;
2235
2236         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_data); 
2237
2238         return offset;
2239 }
2240
2241
2242 /* RFC 1094, Page 8 */
2243 static int
2244 dissect_nfs2_createargs_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2245         proto_tree *tree)
2246 {
2247         offset = dissect_diropargs(tvb, offset, pinfo, tree, "where"     );
2248         offset = dissect_sattr    (tvb, offset,        tree, "attributes");
2249
2250         return offset;
2251 }
2252
2253
2254 /* RFC 1094, Page 9 */
2255 static int
2256 dissect_nfs2_rename_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2257         proto_tree *tree)
2258 {
2259         offset = dissect_diropargs(tvb, offset, pinfo, tree, "from");
2260         offset = dissect_diropargs(tvb, offset, pinfo, tree, "to"  );
2261
2262         return offset;
2263 }
2264
2265
2266 /* RFC 1094, Page 9 */
2267 static int
2268 dissect_nfs2_link_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2269         proto_tree *tree)
2270 {
2271         offset = dissect_fhandle  (tvb, offset, pinfo, tree, "from");
2272         offset = dissect_diropargs(tvb, offset, pinfo, tree, "to"  );
2273
2274         return offset;
2275 }
2276
2277
2278 /* RFC 1094, Page 10 */
2279 static int
2280 dissect_nfs2_symlink_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2281         proto_tree *tree)
2282 {
2283         offset = dissect_diropargs(tvb, offset, pinfo, tree, "from"           );
2284         offset = dissect_path     (tvb, offset,        tree, hf_nfs_symlink_to);
2285         offset = dissect_sattr    (tvb, offset,        tree, "attributes"     );
2286
2287         return offset;
2288 }
2289
2290
2291 /* RFC 1094, Page 11 */
2292 static int
2293 dissect_nfs2_readdir_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2294         proto_tree *tree)
2295 {
2296         guint32 cookie;
2297         guint32 count;
2298
2299         offset = dissect_fhandle (tvb, offset, pinfo, tree, "dir");
2300         cookie  = tvb_get_ntohl(tvb, offset+ 0);
2301         count = tvb_get_ntohl(tvb, offset+ 4);
2302         if (tree) {
2303                 proto_tree_add_uint(tree, hf_nfs_readdir_cookie, tvb,
2304                         offset+ 0, 4, cookie);
2305                 proto_tree_add_uint(tree, hf_nfs_readdir_count, tvb,
2306                         offset+ 4, 4, count);
2307         }
2308         offset += 8;
2309
2310         return offset;
2311 }
2312
2313
2314 /* RFC 1094, Page 11 */
2315 static int
2316 dissect_readdir_entry(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, 
2317         proto_tree* tree)
2318 {
2319         proto_item* entry_item = NULL;
2320         proto_tree* entry_tree = NULL;
2321         int old_offset = offset;
2322         guint32 fileid;
2323         guint32 cookie;
2324         char *name;
2325
2326         if (tree) {
2327                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, tvb,
2328                         offset+0, -1, FALSE);
2329                 entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
2330         }
2331
2332         fileid = tvb_get_ntohl(tvb, offset + 0);
2333         if (entry_tree)
2334                 proto_tree_add_uint(entry_tree, hf_nfs_readdir_entry_fileid, tvb,
2335                         offset+0, 4, fileid);
2336         offset += 4;
2337
2338         offset = dissect_filename(tvb, offset, entry_tree,
2339                 hf_nfs_readdir_entry_name, &name);
2340         if (entry_item)
2341                 proto_item_set_text(entry_item, "Entry: file ID %u, name %s",
2342                 fileid, name);
2343         g_free(name);
2344         
2345         cookie = tvb_get_ntohl(tvb, offset + 0);
2346         if (entry_tree)
2347                 proto_tree_add_uint(entry_tree, hf_nfs_readdir_entry_cookie, tvb,
2348                         offset+0, 4, cookie);
2349         offset += 4;
2350
2351         /* now we know, that a readdir entry is shorter */
2352         if (entry_item) {
2353                 proto_item_set_len(entry_item, offset - old_offset);
2354         }
2355
2356         return offset;
2357 }
2358
2359 /* RFC 1094, Page 11 */
2360 static int
2361 dissect_nfs2_readdir_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2362         proto_tree* tree)
2363 {
2364         guint32 status;
2365         guint32 eof_value;
2366
2367         offset = dissect_stat(tvb, offset, tree, &status);
2368         switch (status) {
2369                 case 0:
2370                         offset = dissect_rpc_list(tvb, pinfo, tree, offset, 
2371                                 dissect_readdir_entry);
2372                         eof_value = tvb_get_ntohl(tvb, offset+0);
2373                         if (tree)
2374                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, tvb,
2375                                         offset+ 0, 4, eof_value);
2376                         offset += 4;
2377                 break;
2378                 default:
2379                         /* do nothing */
2380                 break;
2381         }
2382
2383         return offset;
2384 }
2385
2386
2387 /* RFC 1094, Page 12 */
2388 static int
2389 dissect_nfs2_statfs_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2390         proto_tree* tree)
2391 {
2392         guint32 status;
2393         guint32 tsize;
2394         guint32 bsize;
2395         guint32 blocks;
2396         guint32 bfree;
2397         guint32 bavail;
2398
2399         offset = dissect_stat(tvb, offset, tree, &status);
2400         switch (status) {
2401                 case 0:
2402                         tsize  = tvb_get_ntohl(tvb, offset+ 0);
2403                         bsize  = tvb_get_ntohl(tvb, offset+ 4);
2404                         blocks = tvb_get_ntohl(tvb, offset+ 8);
2405                         bfree  = tvb_get_ntohl(tvb, offset+12);
2406                         bavail = tvb_get_ntohl(tvb, offset+16);
2407                         if (tree) {
2408                                 proto_tree_add_uint(tree, hf_nfs_statfs_tsize, tvb,
2409                                         offset+ 0, 4, tsize);
2410                                 proto_tree_add_uint(tree, hf_nfs_statfs_bsize, tvb,
2411                                         offset+ 4, 4, bsize);
2412                                 proto_tree_add_uint(tree, hf_nfs_statfs_blocks, tvb,
2413                                         offset+ 8, 4, blocks);
2414                                 proto_tree_add_uint(tree, hf_nfs_statfs_bfree, tvb,
2415                                         offset+12, 4, bfree);
2416                                 proto_tree_add_uint(tree, hf_nfs_statfs_bavail, tvb,
2417                                         offset+16, 4, bavail);
2418                         }
2419                         offset += 20;
2420                 break;
2421                 default:
2422                         /* do nothing */
2423                 break;
2424         }
2425
2426         return offset;
2427 }
2428
2429
2430 /* proc number, "proc name", dissect_request, dissect_reply */
2431 /* NULL as function pointer means: type of arguments is "void". */
2432 static const vsff nfs2_proc[] = {
2433         { 0,    "NULL",         /* OK */
2434         NULL,                           NULL },
2435         { 1,    "GETATTR",      /* OK */
2436         dissect_nfs2_fhandle_call,      dissect_nfs2_attrstat_reply },
2437         { 2,    "SETATTR",      /* OK */
2438         dissect_nfs2_setattr_call,      dissect_nfs2_attrstat_reply },
2439         { 3,    "ROOT",         /* OK */
2440         NULL,                           NULL },
2441         { 4,    "LOOKUP",       /* OK */
2442         dissect_nfs2_diropargs_call,    dissect_nfs2_diropres_reply },
2443         { 5,    "READLINK",     /* OK */
2444         dissect_nfs2_fhandle_call,      dissect_nfs2_readlink_reply },
2445         { 6,    "READ",         /* OK */
2446         dissect_nfs2_read_call,         dissect_nfs2_read_reply },
2447         { 7,    "WRITECACHE",   /* OK */
2448         NULL,                           NULL },
2449         { 8,    "WRITE",        /* OK */
2450         dissect_nfs2_write_call,        dissect_nfs2_attrstat_reply },
2451         { 9,    "CREATE",       /* OK */
2452         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
2453         { 10,   "REMOVE",       /* OK */
2454         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
2455         { 11,   "RENAME",       /* OK */
2456         dissect_nfs2_rename_call,       dissect_nfs2_stat_reply },
2457         { 12,   "LINK",         /* OK */
2458         dissect_nfs2_link_call,         dissect_nfs2_stat_reply },
2459         { 13,   "SYMLINK",      /* OK */
2460         dissect_nfs2_symlink_call,      dissect_nfs2_stat_reply },
2461         { 14,   "MKDIR",        /* OK */
2462         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
2463         { 15,   "RMDIR",        /* OK */
2464         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
2465         { 16,   "READDIR",      /* OK */
2466         dissect_nfs2_readdir_call,      dissect_nfs2_readdir_reply },
2467         { 17,   "STATFS",       /* OK */
2468         dissect_nfs2_fhandle_call,      dissect_nfs2_statfs_reply },
2469         { 0,NULL,NULL,NULL }
2470 };
2471 /* end of NFS Version 2 */
2472
2473
2474 /***************************/
2475 /* NFS Version 3, RFC 1813 */
2476 /***************************/
2477
2478
2479 /* RFC 1813, Page 15 */
2480 static int
2481 dissect_filename3(tvbuff_t *tvb, int offset,
2482     proto_tree *tree, int hf, char **string_ret)
2483 {
2484         offset = dissect_rpc_string(tvb, tree, hf, offset, string_ret);
2485         return offset;
2486 }
2487
2488
2489 /* RFC 1813, Page 15 */
2490 static int
2491 dissect_nfspath3(tvbuff_t *tvb, int offset, proto_tree *tree, int hf)
2492 {
2493         offset = dissect_rpc_string(tvb, tree, hf, offset, NULL);
2494         return offset;
2495 }
2496
2497 /* RFC 1813, Page 15 */
2498 static int
2499 dissect_cookieverf3(tvbuff_t *tvb, int offset, proto_tree *tree)
2500 {
2501         proto_tree_add_text(tree, tvb, offset, NFS3_COOKIEVERFSIZE,
2502                 "Verifier: Opaque Data");
2503         offset += NFS3_COOKIEVERFSIZE;
2504         return offset;
2505 }
2506
2507
2508 /* RFC 1813, Page 16 */
2509 static int
2510 dissect_createverf3(tvbuff_t *tvb, int offset, proto_tree *tree)
2511 {
2512         proto_tree_add_text(tree, tvb, offset, NFS3_CREATEVERFSIZE,
2513                 "Verifier: Opaque Data");
2514         offset += NFS3_CREATEVERFSIZE;
2515         return offset;
2516 }
2517
2518
2519 /* RFC 1813, Page 16 */
2520 static int
2521 dissect_writeverf3(tvbuff_t *tvb, int offset, proto_tree *tree)
2522 {
2523         proto_tree_add_text(tree, tvb, offset, NFS3_WRITEVERFSIZE,
2524                 "Verifier: Opaque Data");
2525         offset += NFS3_WRITEVERFSIZE;
2526         return offset;
2527 }
2528
2529 /* RFC 1813, Page 16 */
2530 static int
2531 dissect_mode3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2532 {
2533         guint32 mode3;
2534         proto_item* mode3_item = NULL;
2535         proto_tree* mode3_tree = NULL;
2536
2537         mode3 = tvb_get_ntohl(tvb, offset+0);
2538         
2539         if (tree) {
2540                 mode3_item = proto_tree_add_text(tree, tvb, offset, 4,
2541                         "%s: 0%o", name, mode3);
2542                 if (mode3_item)
2543                         mode3_tree = proto_item_add_subtree(mode3_item, ett_nfs_mode3);
2544         }
2545
2546         /* RFC 1813, Page 23 */
2547         if (mode3_tree) {
2548                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2549                 decode_boolean_bitfield(mode3,   0x800, 12, "Set user id on exec", "not SUID"));
2550                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2551                 decode_boolean_bitfield(mode3,   0x400, 12, "Set group id on exec", "not SGID"));
2552                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2553                 decode_boolean_bitfield(mode3,   0x200, 12, "Save swapped text even after use", "not save swapped text"));
2554                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2555                 decode_boolean_bitfield(mode3,   0x100, 12, "Read permission for owner", "no Read permission for owner"));
2556                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2557                 decode_boolean_bitfield(mode3,    0x80, 12, "Write permission for owner", "no Write permission for owner"));
2558                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2559                 decode_boolean_bitfield(mode3,    0x40, 12, "Execute permission for owner", "no Execute permission for owner"));
2560                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2561                 decode_boolean_bitfield(mode3,    0x20, 12, "Read permission for group", "no Read permission for group"));
2562                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2563                 decode_boolean_bitfield(mode3,    0x10, 12, "Write permission for group", "no Write permission for group"));
2564                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2565                 decode_boolean_bitfield(mode3,     0x8, 12, "Execute permission for group", "no Execute permission for group"));
2566                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2567                 decode_boolean_bitfield(mode3,     0x4, 12, "Read permission for others", "no Read permission for others"));
2568                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2569                 decode_boolean_bitfield(mode3,     0x2, 12, "Write permission for others", "no Write permission for others"));
2570                 proto_tree_add_text(mode3_tree, tvb, offset, 4, "%s",
2571                 decode_boolean_bitfield(mode3,     0x1, 12, "Execute permission for others", "no Execute permission for others"));
2572         }
2573
2574         offset += 4;
2575         return offset;
2576 }
2577
2578 /* RFC 1813, Page 16,17 */
2579 static const value_string names_nfs_nfsstat3[] =
2580 {
2581         {       0,      "OK" },
2582         {       1,      "ERR_PERM" },
2583         {       2,      "ERR_NOENT" },
2584         {       5,      "ERR_IO" },
2585         {       6,      "ERR_NX_IO" },
2586         {       13,     "ERR_ACCES" },
2587         {       17,     "ERR_EXIST" },
2588         {       18,     "ERR_XDEV" },
2589         {       19,     "ERR_NODEV" },
2590         {       20,     "ERR_NOTDIR" },
2591         {       21,     "ERR_ISDIR" },
2592         {       22,     "ERR_INVAL" },
2593         {       27,     "ERR_FBIG" },
2594         {       28,     "ERR_NOSPC" },
2595         {       30,     "ERR_ROFS" },
2596         {       31,     "ERR_MLINK" },
2597         {       63,     "ERR_NAMETOOLONG" },
2598         {       66,     "ERR_NOTEMPTY" },
2599         {       69,     "ERR_DQUOT" },
2600         {       70,     "ERR_STALE" },
2601         {       71,     "ERR_REMOTE" },
2602         {       10001,  "ERR_BADHANDLE" },
2603         {       10002,  "ERR_NOT_SYNC" },
2604         {       10003,  "ERR_BAD_COOKIE" },
2605         {       10004,  "ERR_NOTSUPP" },
2606         {       10005,  "ERR_TOOSMALL" },
2607         {       10006,  "ERR_SERVERFAULT" },
2608         {       10007,  "ERR_BADTYPE" },
2609         {       10008,  "ERR_JUKEBOX" },
2610         {       0,      NULL }
2611 };
2612
2613
2614 /* RFC 1813, Page 16 */
2615 static int
2616 dissect_nfsstat3(tvbuff_t *tvb, int offset,
2617         proto_tree *tree,guint32 *status)
2618 {
2619         guint32 nfsstat3;
2620
2621         nfsstat3 = tvb_get_ntohl(tvb, offset+0);
2622         
2623         if (tree) {
2624                 proto_tree_add_uint(tree, hf_nfs_nfsstat3, tvb,
2625                         offset, 4, nfsstat3);
2626         }
2627
2628         offset += 4;
2629         *status = nfsstat3;
2630         return offset;
2631 }
2632
2633
2634 static const value_string names_nfs_ftype3[] =
2635 {
2636         {       NF3REG, "Regular File" },
2637         {       NF3DIR, "Directory" },
2638         {       NF3BLK, "Block Special Device" },
2639         {       NF3CHR, "Character Special Device" },
2640         {       NF3LNK, "Symbolic Link" },
2641         {       NF3SOCK,"Socket" },
2642         {       NF3FIFO,"Named Pipe" },
2643         {       0,      NULL }
2644 };
2645
2646
2647 /* RFC 1813, Page 20 */
2648 static int
2649 dissect_ftype3(tvbuff_t *tvb, int offset, proto_tree *tree,
2650         int hf, guint32* ftype3)
2651 {
2652         guint32 type;
2653
2654         type = tvb_get_ntohl(tvb, offset+0);
2655         
2656         if (tree) {
2657                 proto_tree_add_uint(tree, hf, tvb, offset, 4, type);
2658         }
2659
2660         offset += 4;
2661         *ftype3 = type;
2662         return offset;
2663 }
2664
2665
2666 /* RFC 1813, Page 20 */
2667 static int
2668 dissect_specdata3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2669 {
2670         guint32 specdata1;
2671         guint32 specdata2;
2672
2673         proto_item* specdata3_item;
2674         proto_tree* specdata3_tree = NULL;
2675
2676         specdata1 = tvb_get_ntohl(tvb, offset+0);
2677         specdata2 = tvb_get_ntohl(tvb, offset+4);
2678         
2679         if (tree) {
2680                 specdata3_item = proto_tree_add_text(tree, tvb, offset, 8,
2681                         "%s: %u,%u", name, specdata1, specdata2);
2682                 if (specdata3_item)
2683                         specdata3_tree = proto_item_add_subtree(specdata3_item,
2684                                         ett_nfs_specdata3);
2685         }
2686
2687         if (specdata3_tree) {
2688                 proto_tree_add_text(specdata3_tree, tvb,offset+0,4,
2689                                         "specdata1: %u", specdata1);
2690                 proto_tree_add_text(specdata3_tree, tvb,offset+4,4,
2691                                         "specdata2: %u", specdata2);
2692         }
2693
2694         offset += 8;
2695         return offset;
2696 }
2697
2698
2699 /* RFC 1813, Page 21 */
2700 int
2701 dissect_nfs_fh3(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2702         proto_tree *tree, char *name)
2703 {
2704         guint fh3_len;
2705         guint fh3_len_full;
2706         guint fh3_fill;
2707         proto_item* fitem = NULL;
2708         proto_tree* ftree = NULL;
2709         int fh_offset,fh_length;
2710
2711         fh3_len = tvb_get_ntohl(tvb, offset+0);
2712         fh3_len_full = rpc_roundup(fh3_len);
2713         fh3_fill = fh3_len_full - fh3_len;
2714         
2715         if (tree) {
2716                 fitem = proto_tree_add_text(tree, tvb, offset, 4+fh3_len_full,
2717                         "%s", name);
2718                 if (fitem)
2719                         ftree = proto_item_add_subtree(fitem, ett_nfs_fh3);
2720         }
2721
2722         /* are we snooping fh to filenames ?*/
2723         if((!pinfo->fd->flags.visited) && nfs_file_name_snooping){
2724                 rpc_call_info_value *civ=pinfo->private_data;
2725
2726                 /* NFS v3 LOOKUP, CREATE, MKDIR calls might give us a mapping*/
2727                 if( (civ->prog==100003)
2728                   &&(civ->vers==3)
2729                   &&(!civ->request)
2730                   &&((civ->proc==3)||(civ->proc==8)||(civ->proc==9))
2731                 ) {
2732                         fh_length=tvb_get_ntohl(tvb, offset);
2733                         fh_offset=offset+4;
2734                         nfs_name_snoop_add_fh(civ->xid, tvb, 
2735                                 fh_offset, fh_length);
2736                 }
2737
2738                 /* MOUNT v3 MNT replies might give us a filehandle */
2739                 if( (civ->prog==100005)
2740                   &&(civ->vers==3)
2741                   &&(!civ->request)
2742                   &&(civ->proc==1)
2743                 ) {
2744                         fh_length=tvb_get_ntohl(tvb, offset);
2745                         fh_offset=offset+4;
2746                         nfs_name_snoop_add_fh(civ->xid, tvb, 
2747                                 fh_offset, fh_length);
2748                 }
2749         }
2750
2751         proto_tree_add_uint(ftree, hf_nfs_fh_length, tvb, offset+0, 4,
2752                         fh3_len);
2753         dissect_fhandle_data(tvb, offset+4, pinfo, ftree, fh3_len, FALSE);
2754
2755         offset += 4 + fh3_len_full;
2756         return offset;
2757 }
2758
2759
2760 /* RFC 1813, Page 21 */
2761 static int
2762 dissect_nfstime3(tvbuff_t *tvb, int offset,
2763         proto_tree *tree, int hf_time, int hf_time_sec, int hf_time_nsec)
2764 {
2765         guint32 seconds;
2766         guint32 nseconds;
2767         nstime_t ts;
2768
2769         proto_item* time_item;
2770         proto_tree* time_tree = NULL;
2771
2772         seconds = tvb_get_ntohl(tvb, offset+0);
2773         nseconds = tvb_get_ntohl(tvb, offset+4);
2774         ts.secs = seconds;
2775         ts.nsecs = nseconds;
2776         
2777         if (tree) {
2778                 time_item = proto_tree_add_time(tree, hf_time, tvb, offset, 8,
2779                                 &ts);
2780                 if (time_item)
2781                         time_tree = proto_item_add_subtree(time_item, ett_nfs_nfstime3);
2782         }
2783
2784         if (time_tree) {
2785                 proto_tree_add_uint(time_tree, hf_time_sec, tvb, offset, 4,
2786                                         seconds);
2787                 proto_tree_add_uint(time_tree, hf_time_nsec, tvb, offset+4, 4,
2788                                         nseconds);
2789         }
2790         offset += 8;
2791         return offset;
2792 }
2793
2794
2795 /* RFC 1813, Page 22 */
2796 static int
2797 dissect_fattr3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2798 {
2799         proto_item* fattr3_item = NULL;
2800         proto_tree* fattr3_tree = NULL;
2801         int old_offset = offset;
2802         guint32 type;
2803
2804         if (tree) {
2805                 fattr3_item = proto_tree_add_text(tree, tvb, offset, -1,
2806                         "%s", name);
2807                 fattr3_tree = proto_item_add_subtree(fattr3_item, ett_nfs_fattr3);
2808         }
2809
2810         offset = dissect_ftype3(tvb,offset,fattr3_tree,hf_nfs_fattr3_type,&type);
2811         offset = dissect_mode3(tvb,offset,fattr3_tree,"mode");
2812         offset = dissect_rpc_uint32(tvb, fattr3_tree, hf_nfs_fattr3_nlink,
2813                 offset);
2814         offset = dissect_rpc_uint32(tvb, fattr3_tree, hf_nfs_fattr3_uid,
2815                 offset);
2816         offset = dissect_rpc_uint32(tvb, fattr3_tree, hf_nfs_fattr3_gid,
2817                 offset);
2818         offset = dissect_rpc_uint64(tvb, fattr3_tree, hf_nfs_fattr3_size, 
2819                 offset);
2820         offset = dissect_rpc_uint64(tvb, fattr3_tree, hf_nfs_fattr3_used,
2821                 offset);
2822         offset = dissect_specdata3(tvb,offset,fattr3_tree,"rdev");
2823         offset = dissect_rpc_uint64(tvb, fattr3_tree, hf_nfs_fattr3_fsid,
2824                 offset);
2825         offset = dissect_rpc_uint64(tvb, fattr3_tree, hf_nfs_fattr3_fileid,
2826                 offset);
2827         offset = dissect_nfstime3 (tvb,offset,fattr3_tree,hf_nfs_atime,hf_nfs_atime_sec,hf_nfs_atime_nsec);
2828         offset = dissect_nfstime3 (tvb,offset,fattr3_tree,hf_nfs_mtime,hf_nfs_mtime_sec,hf_nfs_mtime_nsec);
2829         offset = dissect_nfstime3 (tvb,offset,fattr3_tree,hf_nfs_ctime,hf_nfs_ctime_sec,hf_nfs_ctime_nsec);
2830
2831         /* now we know, that fattr3 is shorter */
2832         if (fattr3_item) {
2833                 proto_item_set_len(fattr3_item, offset - old_offset);
2834         }
2835
2836         return offset;
2837 }
2838
2839
2840 static const value_string value_follows[] =
2841         {
2842                 { 0, "no value" },
2843                 { 1, "value follows"},
2844                 { 0, NULL }
2845         };
2846
2847
2848 /* RFC 1813, Page 23 */
2849 static int
2850 dissect_post_op_attr(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2851 {
2852         proto_item* post_op_attr_item = NULL;
2853         proto_tree* post_op_attr_tree = NULL;
2854         int old_offset = offset;
2855         guint32 attributes_follow;
2856
2857         if (tree) {
2858                 post_op_attr_item = proto_tree_add_text(tree, tvb, offset, -1,
2859                         "%s", name);
2860                 post_op_attr_tree = proto_item_add_subtree(post_op_attr_item, 
2861                         ett_nfs_post_op_attr);
2862         }
2863
2864         attributes_follow = tvb_get_ntohl(tvb, offset+0);
2865         proto_tree_add_text(post_op_attr_tree, tvb, offset, 4,
2866                 "attributes_follow: %s (%u)", 
2867                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
2868         offset += 4;
2869         switch (attributes_follow) {
2870                 case TRUE:
2871                         offset = dissect_fattr3(tvb, offset, post_op_attr_tree,
2872                                         "attributes");
2873                 break;
2874                 case FALSE:
2875                         /* void */
2876                 break;
2877         }
2878         
2879         /* now we know, that post_op_attr_tree is shorter */
2880         if (post_op_attr_item) {
2881                 proto_item_set_len(post_op_attr_item, offset - old_offset);
2882         }
2883
2884         return offset;
2885 }
2886
2887
2888 /* RFC 1813, Page 24 */
2889 static int
2890 dissect_wcc_attr(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2891 {
2892         proto_item* wcc_attr_item = NULL;
2893         proto_tree* wcc_attr_tree = NULL;
2894         int old_offset = offset;
2895
2896         if (tree) {
2897                 wcc_attr_item = proto_tree_add_text(tree, tvb, offset, -1,
2898                         "%s", name);
2899                 wcc_attr_tree = proto_item_add_subtree(wcc_attr_item, 
2900                         ett_nfs_wcc_attr);
2901         }
2902
2903         offset = dissect_rpc_uint64(tvb, wcc_attr_tree, hf_nfs_wcc_attr_size, 
2904                 offset);
2905         offset = dissect_nfstime3(tvb, offset, wcc_attr_tree, hf_nfs_mtime, hf_nfs_mtime_sec, hf_nfs_mtime_nsec);
2906         offset = dissect_nfstime3(tvb, offset, wcc_attr_tree, hf_nfs_ctime, hf_nfs_ctime_sec, hf_nfs_ctime_nsec);
2907         /* now we know, that wcc_attr_tree is shorter */
2908         if (wcc_attr_item) {
2909                 proto_item_set_len(wcc_attr_item, offset - old_offset);
2910         }
2911
2912         return offset;
2913 }
2914
2915
2916 /* RFC 1813, Page 24 */
2917 static int
2918 dissect_pre_op_attr(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2919 {
2920         proto_item* pre_op_attr_item = NULL;
2921         proto_tree* pre_op_attr_tree = NULL;
2922         int old_offset = offset;
2923         guint32 attributes_follow;
2924
2925         if (tree) {
2926                 pre_op_attr_item = proto_tree_add_text(tree, tvb, offset, -1,
2927                         "%s", name);
2928                 pre_op_attr_tree = proto_item_add_subtree(pre_op_attr_item, 
2929                         ett_nfs_pre_op_attr);
2930         }
2931
2932         attributes_follow = tvb_get_ntohl(tvb, offset+0);
2933         proto_tree_add_text(pre_op_attr_tree, tvb, offset, 4,
2934                 "attributes_follow: %s (%u)", 
2935                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
2936         offset += 4;
2937         switch (attributes_follow) {
2938                 case TRUE:
2939                         offset = dissect_wcc_attr(tvb, offset, pre_op_attr_tree,
2940                                         "attributes");
2941                 break;
2942                 case FALSE:
2943                         /* void */
2944                 break;
2945         }
2946         
2947         /* now we know, that pre_op_attr_tree is shorter */
2948         if (pre_op_attr_item) {
2949                 proto_item_set_len(pre_op_attr_item, offset - old_offset);
2950         }
2951
2952         return offset;
2953 }
2954
2955
2956 /* RFC 1813, Page 24 */
2957 static int
2958 dissect_wcc_data(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
2959 {
2960         proto_item* wcc_data_item = NULL;
2961         proto_tree* wcc_data_tree = NULL;
2962         int old_offset = offset;
2963
2964         if (tree) {
2965                 wcc_data_item = proto_tree_add_text(tree, tvb, offset, -1,
2966                         "%s", name);
2967                 wcc_data_tree = proto_item_add_subtree(wcc_data_item, 
2968                         ett_nfs_wcc_data);
2969         }
2970
2971         offset = dissect_pre_op_attr (tvb, offset, wcc_data_tree, "before");
2972         offset = dissect_post_op_attr(tvb, offset, wcc_data_tree, "after" );
2973
2974         /* now we know, that wcc_data is shorter */
2975         if (wcc_data_item) {
2976                 proto_item_set_len(wcc_data_item, offset - old_offset);
2977         }
2978
2979         return offset;
2980 }
2981
2982
2983 /* RFC 1813, Page 25 */
2984 static int
2985 dissect_post_op_fh3(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2986         proto_tree *tree, char* name)
2987 {
2988         proto_item* post_op_fh3_item = NULL;
2989         proto_tree* post_op_fh3_tree = NULL;
2990         int old_offset = offset;
2991         guint32 handle_follows;
2992
2993         if (tree) {
2994                 post_op_fh3_item = proto_tree_add_text(tree, tvb, offset, -1,
2995                         "%s", name);
2996                 post_op_fh3_tree = proto_item_add_subtree(post_op_fh3_item, 
2997                         ett_nfs_post_op_fh3);
2998         }
2999
3000         handle_follows = tvb_get_ntohl(tvb, offset+0);
3001         proto_tree_add_text(post_op_fh3_tree, tvb, offset, 4,
3002                 "handle_follows: %s (%u)", 
3003                 val_to_str(handle_follows,value_follows,"Unknown"), handle_follows);
3004         offset += 4;
3005         switch (handle_follows) {
3006                 case TRUE:
3007                         offset = dissect_nfs_fh3(tvb, offset, pinfo, post_op_fh3_tree,
3008                                         "handle");
3009                 break;
3010                 case FALSE:
3011                         /* void */
3012                 break;
3013         }
3014         
3015         /* now we know, that post_op_fh3_tree is shorter */
3016         if (post_op_fh3_item) {
3017                 proto_item_set_len(post_op_fh3_item, offset - old_offset);
3018         }
3019
3020         return offset;
3021 }
3022
3023
3024 /* RFC 1813, Page 25 */
3025 static int
3026 dissect_set_mode3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3027 {
3028         proto_item* set_mode3_item = NULL;
3029         proto_tree* set_mode3_tree = NULL;
3030         int old_offset = offset;
3031         guint32 set_it;
3032         char* set_it_name;
3033
3034         set_it = tvb_get_ntohl(tvb, offset+0);
3035         set_it_name = val_to_str(set_it,value_follows,"Unknown");
3036
3037         if (tree) {
3038                 set_mode3_item = proto_tree_add_text(tree, tvb, offset, -1,
3039                         "%s: %s", name, set_it_name);
3040                 set_mode3_tree = proto_item_add_subtree(set_mode3_item, 
3041                         ett_nfs_set_mode3);
3042         }
3043
3044         if (set_mode3_tree)
3045                 proto_tree_add_text(set_mode3_tree, tvb, offset, 4,
3046                         "set_it: %s (%u)", set_it_name, set_it);
3047
3048         offset += 4;
3049
3050         switch (set_it) {
3051                 case 1:
3052                         offset = dissect_mode3(tvb, offset, set_mode3_tree,
3053                                         "mode");
3054                 break;
3055                 default:
3056                         /* void */
3057                 break;
3058         }
3059         
3060         /* now we know, that set_mode3 is shorter */
3061         if (set_mode3_item) {
3062                 proto_item_set_len(set_mode3_item, offset - old_offset);
3063         }
3064
3065         return offset;
3066 }
3067
3068
3069 /* RFC 1813, Page 26 */
3070 static int
3071 dissect_set_uid3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3072 {
3073         proto_item* set_uid3_item = NULL;
3074         proto_tree* set_uid3_tree = NULL;
3075         int old_offset = offset;
3076         guint32 set_it;
3077         char* set_it_name;
3078
3079         set_it = tvb_get_ntohl(tvb, offset+0);
3080         set_it_name = val_to_str(set_it,value_follows,"Unknown");
3081
3082         if (tree) {
3083                 set_uid3_item = proto_tree_add_text(tree, tvb, offset, -1,
3084                         "%s: %s", name, set_it_name);
3085                 set_uid3_tree = proto_item_add_subtree(set_uid3_item, 
3086                         ett_nfs_set_uid3);
3087         }
3088
3089         if (set_uid3_tree)
3090                 proto_tree_add_text(set_uid3_tree, tvb, offset, 4,
3091                         "set_it: %s (%u)", set_it_name, set_it);
3092
3093         offset += 4;
3094
3095         switch (set_it) {
3096                 case 1:
3097                         offset = dissect_rpc_uint32(tvb, set_uid3_tree,
3098                                                                  hf_nfs_uid3, offset);
3099                 break;
3100                 default:
3101                         /* void */
3102                 break;
3103         }
3104
3105         /* now we know, that set_uid3 is shorter */
3106         if (set_uid3_item) {
3107                 proto_item_set_len(set_uid3_item, offset - old_offset);
3108         }
3109
3110         return offset;
3111 }
3112
3113
3114 /* RFC 1813, Page 26 */
3115 static int
3116 dissect_set_gid3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3117 {
3118         proto_item* set_gid3_item = NULL;
3119         proto_tree* set_gid3_tree = NULL;
3120         int old_offset = offset;
3121         guint32 set_it;
3122         char* set_it_name;
3123
3124         set_it = tvb_get_ntohl(tvb, offset+0);
3125         set_it_name = val_to_str(set_it,value_follows,"Unknown");
3126
3127         if (tree) {
3128                 set_gid3_item = proto_tree_add_text(tree, tvb, offset, -1,
3129                         "%s: %s", name, set_it_name);
3130                 set_gid3_tree = proto_item_add_subtree(set_gid3_item, 
3131                         ett_nfs_set_gid3);
3132         }
3133
3134         if (set_gid3_tree)
3135                 proto_tree_add_text(set_gid3_tree, tvb, offset, 4,
3136                         "set_it: %s (%u)", set_it_name, set_it);
3137
3138         offset += 4;
3139
3140         switch (set_it) {
3141                 case 1:
3142                         offset = dissect_rpc_uint32(tvb, set_gid3_tree, 
3143                                 hf_nfs_gid3, offset);
3144                 break;
3145                 default:
3146                         /* void */
3147                 break;
3148         }
3149
3150         /* now we know, that set_gid3 is shorter */
3151         if (set_gid3_item) {
3152                 proto_item_set_len(set_gid3_item, offset - old_offset);
3153         }
3154
3155         return offset;
3156 }
3157
3158
3159 /* RFC 1813, Page 26 */
3160 static int
3161 dissect_set_size3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3162 {
3163         proto_item* set_size3_item = NULL;
3164         proto_tree* set_size3_tree = NULL;
3165         int old_offset = offset;
3166         guint32 set_it;
3167         char* set_it_name;
3168
3169         set_it = tvb_get_ntohl(tvb, offset+0);
3170         set_it_name = val_to_str(set_it,value_follows,"Unknown");
3171
3172         if (tree) {
3173                 set_size3_item = proto_tree_add_text(tree, tvb, offset, -1,
3174                         "%s: %s", name, set_it_name);
3175                 set_size3_tree = proto_item_add_subtree(set_size3_item, 
3176                         ett_nfs_set_size3);
3177         }
3178
3179         if (set_size3_tree)
3180                 proto_tree_add_text(set_size3_tree, tvb, offset, 4,
3181                         "set_it: %s (%u)", set_it_name, set_it);
3182
3183         offset += 4;
3184
3185         switch (set_it) {
3186                 case 1:
3187                         offset = dissect_rpc_uint64(tvb, set_size3_tree,
3188                                 hf_nfs_set_size3_size, offset);
3189                 break;
3190                 default:
3191                         /* void */
3192                 break;
3193         }
3194
3195         /* now we know, that set_size3 is shorter */
3196         if (set_size3_item) {
3197                 proto_item_set_len(set_size3_item, offset - old_offset);
3198         }
3199
3200         return offset;
3201 }
3202
3203
3204 /* RFC 1813, Page 25 */
3205 #define DONT_CHANGE 0
3206 #define SET_TO_SERVER_TIME 1
3207 #define SET_TO_CLIENT_TIME 2
3208
3209 static const value_string time_how[] =
3210         {
3211                 { DONT_CHANGE,  "don't change" },
3212                 { SET_TO_SERVER_TIME, "set to server time" },
3213                 { SET_TO_CLIENT_TIME, "set to client time" },
3214                 { 0, NULL }
3215         };
3216
3217
3218 /* RFC 1813, Page 26 */
3219 static int
3220 dissect_set_atime(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3221 {
3222         proto_item* set_atime_item = NULL;
3223         proto_tree* set_atime_tree = NULL;
3224         int old_offset = offset;
3225         guint32 set_it;
3226         char* set_it_name;
3227
3228         set_it = tvb_get_ntohl(tvb, offset+0);
3229         set_it_name = val_to_str(set_it,time_how,"Unknown");
3230
3231         if (tree) {
3232                 set_atime_item = proto_tree_add_text(tree, tvb, offset, -1,
3233                         "%s: %s", name, set_it_name);
3234                 set_atime_tree = proto_item_add_subtree(set_atime_item, 
3235                         ett_nfs_set_atime);
3236         }
3237
3238         if (set_atime_tree)
3239                 proto_tree_add_text(set_atime_tree, tvb, offset, 4,
3240                         "set_it: %s (%u)", set_it_name, set_it);
3241
3242         offset += 4;
3243
3244         switch (set_it) {
3245                 case SET_TO_CLIENT_TIME:
3246                         if (set_atime_item) {
3247                                 offset = dissect_nfstime3(tvb, offset, set_atime_tree,
3248                                         hf_nfs_atime, hf_nfs_atime_sec, hf_nfs_atime_nsec);
3249                         }
3250                 break;
3251                 default:
3252                         /* void */
3253                 break;
3254         }
3255
3256         /* now we know, that set_atime is shorter */
3257         if (set_atime_item) {
3258                 proto_item_set_len(set_atime_item, offset - old_offset);
3259         }
3260
3261         return offset;
3262 }
3263
3264
3265 /* RFC 1813, Page 26 */
3266 static int
3267 dissect_set_mtime(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3268 {
3269         proto_item* set_mtime_item = NULL;
3270         proto_tree* set_mtime_tree = NULL;
3271         int old_offset = offset;
3272         guint32 set_it;
3273         char* set_it_name;
3274
3275         set_it = tvb_get_ntohl(tvb, offset+0);
3276         set_it_name = val_to_str(set_it,time_how,"Unknown");
3277
3278         if (tree) {
3279                 set_mtime_item = proto_tree_add_text(tree, tvb, offset, -1,
3280                         "%s: %s", name, set_it_name);
3281                 set_mtime_tree = proto_item_add_subtree(set_mtime_item, 
3282                         ett_nfs_set_mtime);
3283         }
3284
3285         if (set_mtime_tree)
3286                 proto_tree_add_text(set_mtime_tree, tvb, offset, 4,
3287                                 "set_it: %s (%u)", set_it_name, set_it);
3288
3289         offset += 4;
3290
3291         switch (set_it) {
3292                 case SET_TO_CLIENT_TIME:
3293                         if (set_mtime_item) {
3294                                 offset = dissect_nfstime3(tvb, offset, set_mtime_tree,
3295                                         hf_nfs_atime, hf_nfs_atime_sec, hf_nfs_atime_nsec);
3296                         }
3297                 break;
3298                 default:
3299                         /* void */
3300                 break;
3301         }
3302
3303         /* now we know, that set_mtime is shorter */
3304         if (set_mtime_item) {
3305                 proto_item_set_len(set_mtime_item, offset - old_offset);
3306         }
3307
3308         return offset;
3309 }
3310
3311
3312 /* RFC 1813, Page 25..27 */
3313 static int
3314 dissect_sattr3(tvbuff_t *tvb, int offset, proto_tree *tree, char* name)
3315 {
3316         proto_item* sattr3_item = NULL;
3317         proto_tree* sattr3_tree = NULL;
3318         int old_offset = offset;
3319
3320         if (tree) {
3321                 sattr3_item = proto_tree_add_text(tree, tvb, offset, -1,
3322                         "%s", name);
3323                 sattr3_tree = proto_item_add_subtree(sattr3_item, ett_nfs_sattr3);
3324         }
3325
3326         offset = dissect_set_mode3(tvb, offset, sattr3_tree, "mode");
3327         offset = dissect_set_uid3 (tvb, offset, sattr3_tree, "uid");
3328         offset = dissect_set_gid3 (tvb, offset, sattr3_tree, "gid");
3329         offset = dissect_set_size3(tvb, offset, sattr3_tree, "size");
3330         offset = dissect_set_atime(tvb, offset, sattr3_tree, "atime");
3331         offset = dissect_set_mtime(tvb, offset, sattr3_tree, "mtime");
3332
3333         /* now we know, that sattr3 is shorter */
3334         if (sattr3_item) {
3335                 proto_item_set_len(sattr3_item, offset - old_offset);
3336         }
3337
3338         return offset;
3339 }
3340
3341
3342 /* RFC 1813, Page 27 */
3343 static int
3344 dissect_diropargs3(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3345         proto_tree *tree, char* name)
3346 {
3347         proto_item* diropargs3_item = NULL;
3348         proto_tree* diropargs3_tree = NULL;
3349         int old_offset = offset;
3350         int parent_offset, parent_len;
3351         int name_offset, name_len;
3352
3353         if (tree) {
3354                 diropargs3_item = proto_tree_add_text(tree, tvb, offset, -1,
3355                         "%s", name);
3356                 diropargs3_tree = proto_item_add_subtree(diropargs3_item, 
3357                         ett_nfs_diropargs3);
3358         }
3359
3360         parent_offset=offset+4;
3361         parent_len=tvb_get_ntohl(tvb, offset);
3362         offset = dissect_nfs_fh3(tvb, offset, pinfo, diropargs3_tree, "dir");
3363         name_offset=offset+4;
3364         name_len=tvb_get_ntohl(tvb, offset);
3365         offset = dissect_filename3(tvb, offset, diropargs3_tree, 
3366                 hf_nfs_name, NULL);
3367
3368         /* are we snooping fh to filenames ?*/
3369         if((!pinfo->fd->flags.visited) && nfs_file_name_snooping){
3370                 /* v3 LOOKUP, CREATE, MKDIR calls might give us a mapping*/
3371                 rpc_call_info_value *civ=pinfo->private_data;
3372
3373                 if( (civ->prog==100003)
3374                   &&(civ->vers==3)
3375                   &&(civ->request)
3376                   &&((civ->proc==3)||(civ->proc==8)||(civ->proc==9))
3377                 ) {
3378                         nfs_name_snoop_add_name(civ->xid, tvb, 
3379                                 name_offset, name_len,
3380                                 parent_offset, parent_len, NULL);
3381                 }
3382         }
3383
3384
3385         /* now we know, that diropargs3 is shorter */
3386         if (diropargs3_item) {
3387                 proto_item_set_len(diropargs3_item, offset - old_offset);
3388         }
3389
3390         return offset;
3391 }
3392
3393
3394 /* RFC 1813, Page 27 */
3395 static int
3396 dissect_nfs3_diropargs3_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3397         proto_tree *tree)
3398 {
3399         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "object");
3400
3401         return offset;
3402 }
3403
3404
3405 /* RFC 1813, Page 40 */
3406 static int
3407 dissect_access(tvbuff_t *tvb, int offset, proto_tree *tree,
3408         char* name)
3409 {
3410         guint32 access;
3411         proto_item* access_item = NULL;
3412         proto_tree* access_tree = NULL;
3413
3414         access = tvb_get_ntohl(tvb, offset+0);
3415         
3416         if (tree) {
3417                 access_item = proto_tree_add_text(tree, tvb, offset, 4,
3418                         "%s: 0x%02x", name, access);
3419                 if (access_item)
3420                         access_tree = proto_item_add_subtree(access_item, ett_nfs_access);
3421         }
3422
3423         if (access_tree) {
3424                 proto_tree_add_text(access_tree, tvb, offset, 4, "%s READ",
3425                 decode_boolean_bitfield(access,  0x001, 6, "allow", "not allow"));
3426                 proto_tree_add_text(access_tree, tvb, offset, 4, "%s LOOKUP",
3427                 decode_boolean_bitfield(access,  0x002, 6, "allow", "not allow"));
3428                 proto_tree_add_text(access_tree, tvb, offset, 4, "%s MODIFY",
3429                 decode_boolean_bitfield(access,  0x004, 6, "allow", "not allow"));
3430                 proto_tree_add_text(access_tree, tvb, offset, 4, "%s EXTEND",
3431                 decode_boolean_bitfield(access,  0x008, 6, "allow", "not allow"));
3432                 proto_tree_add_text(access_tree, tvb, offset, 4, "%s DELETE",
3433                 decode_boolean_bitfield(access,  0x010, 6, "allow", "not allow"));
3434                 proto_tree_add_text(access_tree, tvb, offset, 4, "%s EXECUTE",
3435                 decode_boolean_bitfield(access,  0x020, 6, "allow", "not allow"));
3436         }
3437
3438         offset += 4;
3439         return offset;
3440 }
3441
3442
3443 /* NFS3 file handle dissector */
3444 static int
3445 dissect_nfs3_nfs_fh3_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3446         proto_tree* tree)
3447 {
3448         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "object");
3449         return offset;
3450 }
3451
3452
3453 /* RFC 1813, Page 32,33 */
3454 static int
3455 dissect_nfs3_getattr_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3456         proto_tree* tree)
3457 {
3458         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "object");
3459         return offset;
3460 }
3461
3462
3463 /* RFC 1813, Page 32,33 */
3464 static int
3465 dissect_nfs3_getattr_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, 
3466         proto_tree* tree)
3467 {
3468         guint32 status;
3469
3470         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3471         switch (status) {
3472                 case 0:
3473                         offset = dissect_fattr3(tvb, offset, tree, "obj_attributes");
3474                 break;
3475                 default:
3476                         /* void */
3477                 break;
3478         }
3479                 
3480         return offset;
3481 }
3482
3483
3484 /* RFC 1813, Page 33 */
3485 static int
3486 dissect_sattrguard3(tvbuff_t *tvb, int offset, proto_tree* tree, char *name)
3487 {
3488         proto_item* sattrguard3_item = NULL;
3489         proto_tree* sattrguard3_tree = NULL;
3490         int old_offset = offset;
3491         guint32 check;
3492         char* check_name;
3493
3494         check = tvb_get_ntohl(tvb, offset+0);
3495         check_name = val_to_str(check,value_follows,"Unknown");
3496
3497         if (tree) {
3498                 sattrguard3_item = proto_tree_add_text(tree, tvb, offset, -1,
3499                         "%s: %s", name, check_name);
3500                 sattrguard3_tree = proto_item_add_subtree(sattrguard3_item, 
3501                         ett_nfs_sattrguard3);
3502         }
3503
3504         if (sattrguard3_tree)
3505                 proto_tree_add_text(sattrguard3_tree, tvb, offset, 4,
3506                         "check: %s (%u)", check_name, check);
3507
3508         offset += 4;
3509
3510         switch (check) {
3511                 case TRUE:
3512                         offset = dissect_nfstime3(tvb, offset, sattrguard3_tree,
3513                                         hf_nfs_ctime, hf_nfs_ctime_sec, hf_nfs_ctime_nsec);
3514                 break;
3515                 case FALSE:
3516                         /* void */
3517                 break;
3518         }
3519
3520         /* now we know, that sattrguard3 is shorter */
3521         if (sattrguard3_item) {
3522                 proto_item_set_len(sattrguard3_item, offset - old_offset);
3523         }
3524
3525         return offset;
3526 }
3527
3528
3529 /* RFC 1813, Page 33..36 */
3530 static int
3531 dissect_nfs3_setattr_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3532         proto_tree* tree)
3533 {
3534         offset = dissect_nfs_fh3    (tvb, offset, pinfo, tree, "object");
3535         offset = dissect_sattr3     (tvb, offset,        tree, "new_attributes");
3536         offset = dissect_sattrguard3(tvb, offset,        tree, "guard");
3537         return offset;
3538 }
3539
3540
3541 /* RFC 1813, Page 33..36 */
3542 static int
3543 dissect_nfs3_setattr_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3544         proto_tree* tree)
3545 {
3546         guint32 status;
3547
3548         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3549         switch (status) {
3550                 case 0:
3551                         offset = dissect_wcc_data(tvb, offset, tree, "obj_wcc");
3552                 break;
3553                 default:
3554                         offset = dissect_wcc_data(tvb, offset, tree, "obj_wcc");
3555                 break;
3556         }
3557                 
3558         return offset;
3559 }
3560
3561
3562 /* RFC 1813, Page 37..39 */
3563 static int
3564 dissect_nfs3_lookup_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3565         proto_tree* tree)
3566 {
3567         offset = dissect_diropargs3 (tvb, offset, pinfo, tree, "what");
3568         return offset;
3569 }
3570
3571
3572 /* RFC 1813, Page 37..39 */
3573 static int
3574 dissect_nfs3_lookup_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3575         proto_tree* tree)
3576 {
3577         guint32 status;
3578
3579         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3580         switch (status) {
3581                 case 0:
3582                         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "object");
3583                         offset = dissect_post_op_attr(tvb, offset, tree, 
3584                                 "obj_attributes");
3585                         offset = dissect_post_op_attr(tvb, offset, tree, 
3586                                 "dir_attributes");
3587                 break;
3588                 default:
3589                         offset = dissect_post_op_attr(tvb, offset, tree, 
3590                                 "dir_attributes");
3591                 break;
3592         }
3593                 
3594         return offset;
3595 }
3596
3597
3598 /* RFC 1813, Page 40..43 */
3599 static int
3600 dissect_nfs3_access_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3601         proto_tree* tree)
3602 {
3603         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "object");
3604         offset = dissect_access (tvb, offset,        tree, "access");
3605
3606         return offset;
3607 }
3608
3609
3610 /* RFC 1813, Page 40..43 */
3611 static int
3612 dissect_nfs3_access_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3613         proto_tree* tree)
3614 {
3615         guint32 status;
3616
3617         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3618         switch (status) {
3619                 case 0:
3620                         offset = dissect_post_op_attr(tvb, offset, tree, 
3621                                 "obj_attributes");
3622                         offset = dissect_access(tvb, offset, tree, "access");
3623                 break;
3624                 default:
3625                         offset = dissect_post_op_attr(tvb, offset, tree, 
3626                                 "obj_attributes");
3627                 break;
3628         }
3629                 
3630         return offset;
3631 }
3632
3633
3634 /* RFC 1813, Page 44,45 */
3635 static int
3636 dissect_nfs3_readlink_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3637         proto_tree* tree)
3638 {
3639         guint32 status;
3640
3641         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3642         switch (status) {
3643                 case 0:
3644                         offset = dissect_post_op_attr(tvb, offset, tree, 
3645                                 "symlink_attributes");
3646                         offset = dissect_nfspath3(tvb, offset, tree, 
3647                                 hf_nfs_readlink_data);
3648                 break;
3649                 default:
3650                         offset = dissect_post_op_attr(tvb, offset, tree, 
3651                                 "symlink_attributes");
3652                 break;
3653         }
3654                 
3655         return offset;
3656 }
3657
3658
3659 /* RFC 1813, Page 46..48 */
3660 static int
3661 dissect_nfs3_read_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3662         proto_tree* tree)
3663 {
3664         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "file");
3665         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_offset3, offset);
3666         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3, offset);
3667
3668         return offset;
3669 }
3670
3671
3672 /* RFC 1813, Page 46..48 */
3673 static int
3674 dissect_nfs3_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3675         proto_tree* tree)
3676 {
3677         guint32 status;
3678
3679         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3680         switch (status) {
3681                 case 0:
3682                         offset = dissect_post_op_attr(tvb, offset, tree, 
3683                                 "file_attributes");
3684                         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3, 
3685                                 offset);
3686                         offset = dissect_rpc_bool(tvb, tree, hf_nfs_read_eof, 
3687                                 offset);
3688                         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_data);
3689                 break;
3690                 default:
3691                         offset = dissect_post_op_attr(tvb, offset, tree, 
3692                                 "file_attributes");
3693                 break;
3694         }
3695                 
3696         return offset;
3697 }
3698
3699
3700 /* RFC 1813, Page 49 */
3701 static const value_string names_stable_how[] = {
3702         {       UNSTABLE,  "UNSTABLE"  },
3703         {       DATA_SYNC, "DATA_SYNC" },
3704         {       FILE_SYNC, "FILE_SYNC" },
3705         { 0, NULL }
3706 };
3707
3708
3709 /* RFC 1813, Page 49 */
3710 static int
3711 dissect_stable_how(tvbuff_t *tvb, int offset, proto_tree* tree, int hfindex)
3712 {
3713         guint32 stable_how;
3714
3715         stable_how = tvb_get_ntohl(tvb,offset+0);
3716         if (tree) {
3717                 proto_tree_add_uint(tree, hfindex, tvb,
3718                         offset, 4, stable_how); 
3719         }
3720         offset += 4;
3721
3722         return offset;
3723 }
3724
3725
3726 /* RFC 1813, Page 49..54 */
3727 static int
3728 dissect_nfs3_write_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3729         proto_tree* tree)
3730 {
3731         offset = dissect_nfs_fh3   (tvb, offset, pinfo, tree, "file");
3732         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_offset3, offset);
3733         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3, offset);
3734         offset = dissect_stable_how(tvb, offset, tree, hf_nfs_write_stable);
3735         offset = dissect_nfsdata   (tvb, offset, tree, hf_nfs_data);
3736
3737         return offset;
3738 }
3739
3740
3741 /* RFC 1813, Page 49..54 */
3742 static int
3743 dissect_nfs3_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3744         proto_tree* tree)
3745 {
3746         guint32 status;
3747
3748         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3749         switch (status) {
3750                 case 0:
3751                         offset = dissect_wcc_data  (tvb, offset, tree, "file_wcc");
3752                         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3, 
3753                                 offset);
3754                         offset = dissect_stable_how(tvb, offset, tree,
3755                                 hf_nfs_write_committed);
3756                         offset = dissect_writeverf3(tvb, offset, tree);
3757                 break;
3758                 default:
3759                         offset = dissect_wcc_data(tvb, offset, tree, "file_wcc");
3760                 break;
3761         }
3762                 
3763         return offset;
3764 }
3765
3766
3767 /* RFC 1813, Page 54 */
3768 static const value_string names_createmode3[] = {
3769         {       UNCHECKED, "UNCHECKED" },
3770         {       GUARDED,   "GUARDED" },
3771         {       EXCLUSIVE, "EXCLUSIVE" },
3772         { 0, NULL }
3773 };
3774
3775
3776 /* RFC 1813, Page 54 */
3777 static int
3778 dissect_createmode3(tvbuff_t *tvb, int offset, proto_tree* tree, guint32* mode)
3779 {
3780         guint32 mode_value;
3781         
3782         mode_value = tvb_get_ntohl(tvb, offset + 0);
3783         if (tree) {
3784                 proto_tree_add_uint(tree, hf_nfs_createmode3, tvb,
3785                 offset+0, 4, mode_value);
3786         }
3787         offset += 4;
3788
3789         *mode = mode_value;
3790         return offset;
3791 }
3792
3793
3794 /* RFC 1813, Page 54..58 */
3795 static int
3796 dissect_nfs3_create_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3797         proto_tree* tree)
3798 {
3799         guint32 mode;
3800
3801         offset = dissect_diropargs3 (tvb, offset, pinfo, tree, "where");
3802         offset = dissect_createmode3(tvb, offset, tree, &mode);
3803         switch (mode) {
3804                 case UNCHECKED:
3805                 case GUARDED:
3806                         offset = dissect_sattr3(tvb, offset, tree, "obj_attributes");
3807                 break;
3808                 case EXCLUSIVE:
3809                         offset = dissect_createverf3(tvb, offset, tree);
3810                 break;
3811         }
3812         
3813         return offset;
3814 }
3815
3816
3817 /* RFC 1813, Page 54..58 */
3818 static int
3819 dissect_nfs3_create_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3820         proto_tree* tree)
3821 {
3822         guint32 status;
3823
3824         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3825         switch (status) {
3826                 case 0:
3827                         offset = dissect_post_op_fh3 (tvb, offset, pinfo, tree, "obj");
3828                         offset = dissect_post_op_attr(tvb, offset, tree, 
3829                                 "obj_attributes");
3830                         offset = dissect_wcc_data(tvb, offset, tree, "dir_wcc");
3831                 break;
3832                 default:
3833                         offset = dissect_wcc_data(tvb, offset, tree, "dir_wcc");
3834                 break;
3835         }
3836                 
3837         return offset;
3838 }
3839
3840
3841 /* RFC 1813, Page 58..60 */
3842 static int
3843 dissect_nfs3_mkdir_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3844         proto_tree* tree)
3845 {
3846         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "where");
3847         offset = dissect_sattr3    (tvb, offset, tree, "attributes");
3848         
3849         return offset;
3850 }
3851
3852
3853 /* RFC 1813, Page 61..63 */
3854 static int
3855 dissect_nfs3_symlink_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3856         proto_tree* tree)
3857 {
3858         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "where");
3859         offset = dissect_sattr3    (tvb, offset,        tree, "symlink_attributes");
3860         offset = dissect_nfspath3  (tvb, offset,        tree, hf_nfs_symlink_to);
3861         
3862         return offset;
3863 }
3864
3865
3866 /* RFC 1813, Page 63..66 */
3867 static int
3868 dissect_nfs3_mknod_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3869         proto_tree* tree)
3870 {
3871         guint32 type;
3872
3873         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "where");
3874         offset = dissect_ftype3(tvb, offset, tree, hf_nfs_ftype3, &type);
3875         switch (type) {
3876                 case NF3CHR:
3877                 case NF3BLK:
3878                         offset = dissect_sattr3(tvb, offset, tree, "dev_attributes");
3879                         offset = dissect_specdata3(tvb, offset, tree, "spec");
3880                 break;
3881                 case NF3SOCK:
3882                 case NF3FIFO:
3883                         offset = dissect_sattr3(tvb, offset, tree, "pipe_attributes");
3884                 break;
3885                 default:
3886                         /* nothing to do */
3887                 break;
3888         }
3889         
3890         return offset;
3891 }
3892
3893
3894 /* RFC 1813, Page 67..69 */
3895 static int
3896 dissect_nfs3_remove_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3897         proto_tree* tree)
3898 {
3899         guint32 status;
3900
3901         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3902         switch (status) {
3903                 case 0:
3904                         offset = dissect_wcc_data(tvb, offset, tree, "dir_wcc");
3905                 break;
3906                 default:
3907                         offset = dissect_wcc_data(tvb, offset, tree, "dir_wcc");
3908                 break;
3909         }
3910                 
3911         return offset;
3912 }
3913
3914
3915 /* RFC 1813, Page 71..74 */
3916 static int
3917 dissect_nfs3_rename_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3918         proto_tree* tree)
3919 {
3920         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "from");
3921         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "to");
3922         
3923         return offset;
3924 }
3925
3926
3927 /* RFC 1813, Page 71..74 */
3928 static int
3929 dissect_nfs3_rename_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3930         proto_tree* tree)
3931 {
3932         guint32 status;
3933
3934         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3935         switch (status) {
3936                 case 0:
3937                         offset = dissect_wcc_data(tvb, offset, tree, "fromdir_wcc");
3938                         offset = dissect_wcc_data(tvb, offset, tree, "todir_wcc");
3939                 break;
3940                 default:
3941                         offset = dissect_wcc_data(tvb, offset, tree, "fromdir_wcc");
3942                         offset = dissect_wcc_data(tvb, offset, tree, "todir_wcc");
3943                 break;
3944         }
3945                 
3946         return offset;
3947 }
3948
3949
3950 /* RFC 1813, Page 74..76 */
3951 static int
3952 dissect_nfs3_link_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3953         proto_tree* tree)
3954 {
3955         offset = dissect_nfs_fh3   (tvb, offset, pinfo, tree, "file");
3956         offset = dissect_diropargs3(tvb, offset, pinfo, tree, "link");
3957         
3958         return offset;
3959 }
3960
3961
3962 /* RFC 1813, Page 74..76 */
3963 static int
3964 dissect_nfs3_link_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
3965         proto_tree* tree)
3966 {
3967         guint32 status;
3968
3969         offset = dissect_nfsstat3(tvb, offset, tree, &status);
3970         switch (status) {
3971                 case 0:
3972                         offset = dissect_post_op_attr(tvb, offset, tree, 
3973                                 "file_attributes");
3974                         offset = dissect_wcc_data(tvb, offset, tree, "linkdir_wcc");
3975                 break;
3976                 default:
3977                         offset = dissect_post_op_attr(tvb, offset, tree, 
3978                                 "file_attributes");
3979                         offset = dissect_wcc_data(tvb, offset, tree, "linkdir_wcc");
3980                 break;
3981         }
3982                 
3983         return offset;
3984 }
3985
3986
3987 /* RFC 1813, Page 76..80 */
3988 static int
3989 dissect_nfs3_readdir_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
3990         proto_tree* tree)
3991 {
3992         offset = dissect_nfs_fh3    (tvb, offset, pinfo, tree, "dir");
3993         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_cookie3, offset);
3994         offset = dissect_cookieverf3(tvb, offset, tree);
3995         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3, offset);
3996         
3997         return offset;
3998 }
3999
4000
4001 /* RFC 1813, Page 76..80 */
4002 static int
4003 dissect_entry3(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
4004         proto_tree* tree)
4005 {
4006         proto_item* entry_item = NULL;
4007         proto_tree* entry_tree = NULL;
4008         int old_offset = offset;
4009         char *name;
4010
4011         if (tree) {
4012                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, tvb,
4013                         offset+0, -1, FALSE);
4014                 entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
4015         }
4016
4017         offset = dissect_rpc_uint64(tvb, entry_tree, hf_nfs_readdir_entry3_fileid,
4018                 offset);
4019
4020         offset = dissect_filename3(tvb, offset, entry_tree,
4021                 hf_nfs_readdir_entry3_name, &name);
4022         if (entry_item)
4023                 proto_item_set_text(entry_item, "Entry: name %s", name);
4024         g_free(name);
4025
4026         offset = dissect_rpc_uint64(tvb, entry_tree, hf_nfs_readdir_entry3_cookie, 
4027                 offset);
4028
4029         /* now we know, that a readdir entry is shorter */
4030         if (entry_item) {
4031                 proto_item_set_len(entry_item, offset - old_offset);
4032         }
4033
4034         return offset;
4035 }
4036
4037
4038 /* RFC 1813, Page 76..80 */
4039 static int
4040 dissect_nfs3_readdir_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
4041         proto_tree* tree)
4042 {
4043         guint32 status;
4044         guint32 eof_value;
4045
4046         offset = dissect_stat(tvb, offset, tree, &status);
4047         switch (status) {
4048                 case 0:
4049                         offset = dissect_post_op_attr(tvb, offset, tree, 
4050                                 "dir_attributes");
4051                         offset = dissect_cookieverf3(tvb, offset, tree);
4052                         offset = dissect_rpc_list(tvb, pinfo, tree, offset, 
4053                                 dissect_entry3);
4054                         eof_value = tvb_get_ntohl(tvb, offset+0);
4055                         if (tree)
4056                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, tvb,
4057                                         offset+ 0, 4, eof_value);
4058                         offset += 4;
4059                 break;
4060                 default:
4061                         offset = dissect_post_op_attr(tvb, offset, tree, 
4062                                 "dir_attributes");
4063                 break;
4064         }
4065
4066         return offset;
4067 }
4068
4069
4070 /* RFC 1813, Page 80..83 */
4071 static int
4072 dissect_nfs3_readdirplus_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
4073         proto_tree* tree)
4074 {
4075         offset = dissect_nfs_fh3    (tvb, offset, pinfo, tree, "dir");
4076         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_cookie3, offset);
4077         offset = dissect_cookieverf3(tvb, offset, tree);
4078         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3_dircount,
4079                 offset);
4080         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3_maxcount,
4081                 offset);
4082         
4083         return offset;
4084 }
4085
4086
4087 /* RFC 1813, Page 80..83 */
4088 static int
4089 dissect_entryplus3(tvbuff_t *tvb, int offset, packet_info *pinfo, 
4090         proto_tree* tree)
4091 {
4092         proto_item* entry_item = NULL;
4093         proto_tree* entry_tree = NULL;
4094         int old_offset = offset;
4095         char *name;
4096
4097         if (tree) {
4098                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry, tvb,
4099                         offset+0, -1, FALSE);
4100                 entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
4101         }
4102
4103         offset = dissect_rpc_uint64(tvb, entry_tree,
4104                 hf_nfs_readdirplus_entry_fileid, offset);
4105
4106         offset = dissect_filename3(tvb, offset, entry_tree,
4107                 hf_nfs_readdirplus_entry_name, &name);
4108         if (entry_item)
4109                 proto_item_set_text(entry_item, "Entry: name %s", name);
4110         g_free(name);
4111
4112         offset = dissect_rpc_uint64(tvb, entry_tree, hf_nfs_readdirplus_entry_cookie,
4113                 offset);
4114
4115         offset = dissect_post_op_attr(tvb, offset, entry_tree, 
4116                 "name_attributes");
4117         offset = dissect_post_op_fh3(tvb, offset, pinfo, entry_tree, "name_handle");
4118
4119         /* now we know, that a readdirplus entry is shorter */
4120         if (entry_item) {
4121                 proto_item_set_len(entry_item, offset - old_offset);
4122         }
4123
4124         return offset;
4125 }
4126
4127
4128 /* RFC 1813, Page 80..83 */
4129 static int
4130 dissect_nfs3_readdirplus_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
4131         proto_tree* tree)
4132 {
4133         guint32 status;
4134         guint32 eof_value;
4135
4136         offset = dissect_stat(tvb, offset, tree, &status);
4137         switch (status) {
4138                 case 0:
4139                         offset = dissect_post_op_attr(tvb, offset, tree, 
4140                                 "dir_attributes");
4141                         offset = dissect_cookieverf3(tvb, offset, tree);
4142                         offset = dissect_rpc_list(tvb, pinfo, tree, offset, 
4143                                 dissect_entryplus3);
4144                         eof_value = tvb_get_ntohl(tvb, offset+0);
4145                         if (tree)
4146                                 proto_tree_add_uint(tree, hf_nfs_readdir_eof, tvb,
4147                                         offset+ 0, 4, eof_value);
4148                         offset += 4;
4149                 break;
4150                 default:
4151                         offset = dissect_post_op_attr(tvb, offset, tree, 
4152                                 "dir_attributes");
4153                 break;
4154         }
4155
4156         return offset;
4157 }
4158
4159
4160 /* RFC 1813, Page 84..86 */
4161 static int
4162 dissect_nfs3_fsstat_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
4163         proto_tree* tree)
4164 {
4165         guint32 status;
4166         guint32 invarsec;
4167
4168         offset = dissect_nfsstat3(tvb, offset, tree, &status);
4169         switch (status) {
4170                 case 0:
4171                         offset = dissect_post_op_attr(tvb, offset, tree, 
4172                                 "obj_attributes");
4173                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_fsstat3_resok_tbytes,
4174                                 offset);
4175                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_fsstat3_resok_fbytes,
4176                                 offset);
4177                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_fsstat3_resok_abytes,
4178                                 offset);
4179                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_fsstat3_resok_tfiles,
4180                                 offset);
4181                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_fsstat3_resok_ffiles,
4182                                 offset);
4183                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_fsstat3_resok_afiles,
4184                                 offset);
4185                         invarsec = tvb_get_ntohl(tvb, offset + 0);
4186                         if (tree)
4187                                 proto_tree_add_uint(tree, hf_nfs_fsstat_invarsec, tvb,
4188                                 offset+0, 4, invarsec);
4189                         offset += 4;
4190                 break;
4191                 default:
4192                         offset = dissect_post_op_attr(tvb, offset, tree, 
4193                                 "obj_attributes");
4194                 break;
4195         }
4196
4197         return offset;
4198 }
4199
4200
4201 #define FSF3_LINK        0x0001
4202 #define FSF3_SYMLINK     0x0002
4203 #define FSF3_HOMOGENEOUS 0x0008
4204 #define FSF3_CANSETTIME  0x0010
4205
4206
4207 /* RFC 1813, Page 86..90 */
4208 static int
4209 dissect_nfs3_fsinfo_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
4210         proto_tree* tree)
4211 {
4212         guint32 status;
4213         guint32 rtmax;
4214         guint32 rtpref;
4215         guint32 rtmult;
4216         guint32 wtmax;
4217         guint32 wtpref;
4218         guint32 wtmult;
4219         guint32 dtpref;
4220         guint32 properties;
4221         proto_item*     properties_item = NULL;
4222         proto_tree*     properties_tree = NULL;
4223
4224         offset = dissect_nfsstat3(tvb, offset, tree, &status);
4225         switch (status) {
4226                 case 0:
4227                         offset = dissect_post_op_attr(tvb, offset, tree, 
4228                                 "obj_attributes");
4229                         rtmax = tvb_get_ntohl(tvb, offset+0);
4230                         if (tree)
4231                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtmax, tvb,
4232                                 offset+0, 4, rtmax);
4233                         offset += 4;
4234                         rtpref = tvb_get_ntohl(tvb, offset+0);
4235                         if (tree)
4236                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtpref, tvb,
4237                                 offset+0, 4, rtpref);
4238                         offset += 4;
4239                         rtmult = tvb_get_ntohl(tvb, offset+0);
4240                         if (tree)
4241                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_rtmult, tvb,
4242                                 offset+0, 4, rtmult);
4243                         offset += 4;
4244                         wtmax = tvb_get_ntohl(tvb, offset+0);
4245                         if (tree)
4246                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtmax, tvb,
4247                                 offset+0, 4, wtmax);
4248                         offset += 4;
4249                         wtpref = tvb_get_ntohl(tvb, offset+0);
4250                         if (tree)
4251                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtpref, tvb,
4252                                 offset+0, 4, wtpref);
4253                         offset += 4;
4254                         wtmult = tvb_get_ntohl(tvb, offset+0);
4255                         if (tree)
4256                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_wtmult, tvb,
4257                                 offset+0, 4, wtmult);
4258                         offset += 4;
4259                         dtpref = tvb_get_ntohl(tvb, offset+0);
4260                         if (tree)
4261                                 proto_tree_add_uint(tree, hf_nfs_fsinfo_dtpref, tvb,
4262                                 offset+0, 4, dtpref);
4263                         offset += 4;
4264
4265                         offset = dissect_rpc_uint64(tvb, tree, 
4266                                 hf_nfs_fsinfo_maxfilesize, offset);
4267                         offset = dissect_nfstime3(tvb, offset, tree, hf_nfs_dtime, hf_nfs_dtime_sec, hf_nfs_dtime_nsec);
4268                         properties = tvb_get_ntohl(tvb, offset+0);
4269                         if (tree) {
4270                                 properties_item = proto_tree_add_uint(tree,
4271                                 hf_nfs_fsinfo_properties,
4272                                 tvb, offset+0, 4, properties);
4273                                 if (properties_item) 
4274                                         properties_tree = proto_item_add_subtree(properties_item, 
4275                                                 ett_nfs_fsinfo_properties);
4276                                 if (properties_tree) {
4277                                         proto_tree_add_text(properties_tree, tvb,
4278                                         offset, 4, "%s",
4279                                         decode_boolean_bitfield(properties,
4280                                         FSF3_CANSETTIME,5,
4281                                         "SETATTR can set time on server",
4282                                         "SETATTR can't set time on server"));
4283
4284                                         proto_tree_add_text(properties_tree, tvb,
4285                                         offset, 4, "%s",
4286                                         decode_boolean_bitfield(properties,
4287                                         FSF3_HOMOGENEOUS,5,
4288                                         "PATHCONF is valid for all files",
4289                                         "PATHCONF should be get for every single file"));
4290
4291                                         proto_tree_add_text(properties_tree, tvb,
4292                                         offset, 4, "%s",
4293                                         decode_boolean_bitfield(properties,
4294                                         FSF3_SYMLINK,5,
4295                                         "File System supports symbolic links",
4296                                         "File System does not symbolic hard links"));
4297
4298                                         proto_tree_add_text(properties_tree, tvb,
4299                                         offset, 4, "%s",
4300                                         decode_boolean_bitfield(properties,
4301                                         FSF3_LINK,5,
4302                                         "File System supports hard links",
4303                                         "File System does not support hard links"));
4304                                 }
4305                         }
4306                         offset += 4;
4307                 break;
4308                 default:
4309                         offset = dissect_post_op_attr(tvb, offset, tree, 
4310                                 "obj_attributes");
4311                 break;
4312         }
4313
4314         return offset;
4315 }
4316
4317
4318 /* RFC 1813, Page 90..92 */
4319 static int
4320 dissect_nfs3_pathconf_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
4321         proto_tree* tree)
4322 {
4323         guint32 status;
4324         guint32 linkmax;
4325         guint32 name_max;
4326
4327         offset = dissect_nfsstat3(tvb, offset, tree, &status);
4328         switch (status) {
4329                 case 0:
4330                         offset = dissect_post_op_attr(tvb, offset, tree, 
4331                                 "obj_attributes");
4332                         linkmax = tvb_get_ntohl(tvb, offset + 0);
4333                         if (tree)
4334                                 proto_tree_add_uint(tree, hf_nfs_pathconf_linkmax, tvb,
4335                                 offset+0, 4, linkmax);
4336                         offset += 4;
4337                         name_max = tvb_get_ntohl(tvb, offset + 0);
4338                         if (tree)
4339                                 proto_tree_add_uint(tree, hf_nfs_pathconf_name_max, tvb,
4340                                 offset+0, 4, name_max);
4341                         offset += 4;
4342                         offset = dissect_rpc_bool(tvb, tree, 
4343                                 hf_nfs_pathconf_no_trunc, offset);
4344                         offset = dissect_rpc_bool(tvb, tree, 
4345                                 hf_nfs_pathconf_chown_restricted, offset);
4346                         offset = dissect_rpc_bool(tvb, tree, 
4347                                 hf_nfs_pathconf_case_insensitive, offset);
4348                         offset = dissect_rpc_bool(tvb, tree, 
4349                                 hf_nfs_pathconf_case_preserving, offset);
4350                 break;
4351                 default:
4352                         offset = dissect_post_op_attr(tvb, offset, tree, 
4353                                 "obj_attributes");
4354                 break;
4355         }
4356
4357         return offset;
4358 }
4359
4360
4361 /* RFC 1813, Page 92..95 */
4362 static int
4363 dissect_nfs3_commit_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
4364         proto_tree* tree)
4365 {
4366         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "file");
4367         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_offset3, offset);
4368         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_count3, offset);
4369         return offset;
4370 }
4371
4372
4373 /* RFC 1813, Page 92..95 */
4374 static int
4375 dissect_nfs3_commit_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
4376         proto_tree* tree)
4377 {
4378         guint32 status;
4379
4380         offset = dissect_nfsstat3(tvb, offset, tree, &status);
4381         switch (status) {
4382                 case 0:
4383                         offset = dissect_wcc_data  (tvb, offset, tree, "file_wcc");
4384                         offset = dissect_writeverf3(tvb, offset, tree);
4385                 break;
4386                 default:
4387                         offset = dissect_wcc_data(tvb, offset, tree, "file_wcc");
4388                 break;
4389         }
4390                 
4391         return offset;
4392 }
4393
4394 /**********************************************************/
4395 /* NFS Version 4, RFC 3010 with nfs4_prot.x 1.103 changes */
4396 /**********************************************************/
4397
4398 static int
4399 dissect_nfs_utf8string(tvbuff_t *tvb, int offset,
4400         proto_tree *tree, int hf, char **string_ret)
4401 {
4402         /* TODO: this dissector is subject to change; do not remove */
4403         return dissect_rpc_string(tvb, tree, hf, offset, string_ret);
4404 }
4405
4406 static int
4407 dissect_nfs_specdata4(tvbuff_t *tvb, int offset, proto_tree *tree)
4408 {
4409         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_specdata1, offset);
4410         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_specdata2, offset);
4411
4412         return offset;
4413 }
4414
4415 static const value_string names_ftype4[] = {
4416         {       NF4REG, "NF4REG"        },
4417         {       NF4DIR, "NF4DIR"        },
4418         {       NF4BLK, "NF4BLK"  },
4419         {       NF4CHR, "NF4CHR"  },
4420         {       NF4LNK,  "NF4LNK"  },
4421         {       NF4SOCK,        "NF4SOCK"  },
4422         {       NF4FIFO,        "NF4FIFO"  },
4423         {       NF4ATTRDIR,     "NF4ATTRDIR"    },
4424         {       NF4NAMEDATTR,   "NF4NAMEDATTR"  },
4425         { 0, NULL }
4426 };
4427
4428 static int
4429 dissect_nfs_lock_owner4(tvbuff_t *tvb, int offset, proto_tree *tree)
4430 {
4431         proto_tree *newftree = NULL;
4432         proto_item *fitem = NULL;
4433
4434         fitem = proto_tree_add_text(tree, tvb, offset, 4, "Owner");
4435
4436         if (fitem) 
4437         {
4438                 newftree = proto_item_add_subtree(fitem, ett_nfs_lock_owner4);
4439
4440                 if (newftree) 
4441                 {
4442                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_clientid4, offset);
4443                         offset = dissect_nfsdata(tvb, offset, newftree, hf_nfs_data);
4444                 }
4445         }
4446
4447         return offset;
4448 }
4449
4450 static int
4451 dissect_nfs_pathname4(tvbuff_t *tvb, int offset, proto_tree *tree)
4452 {
4453         guint32 comp_count, i;
4454         proto_item *fitem = NULL;
4455         proto_tree *newftree = NULL;
4456
4457         comp_count=tvb_get_ntohl(tvb, offset);
4458         fitem = proto_tree_add_text(tree, tvb, offset, 4, 
4459                 "pathname components (%u)", comp_count);
4460         offset += 4;
4461
4462         if (fitem) 
4463         {
4464                 newftree = proto_item_add_subtree(fitem, ett_nfs_pathname4);
4465
4466                 if (newftree) 
4467                 {
4468                         for (i = 0; i < comp_count; i++)
4469                                 offset = dissect_nfs_utf8string(tvb, offset, newftree, 
4470                                         hf_nfs_component4, NULL);
4471                 }
4472         }
4473
4474         return offset;
4475 }
4476
4477 static int
4478 dissect_nfs_nfstime4(tvbuff_t *tvb, int offset, proto_tree *tree)
4479 {
4480         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_nfstime4_seconds, offset);
4481         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_nfstime4_nseconds, offset);
4482
4483         return offset;
4484 }
4485
4486 static const value_string names_time_how4[] = {
4487 #define SET_TO_SERVER_TIME4 0
4488         {       SET_TO_SERVER_TIME4,    "SET_TO_SERVER_TIME4"   },
4489 #define SET_TO_CLIENT_TIME4 1
4490         {       SET_TO_CLIENT_TIME4,    "SET_TO_CLIENT_TIME4"   },
4491         {       0,      NULL    },
4492 };
4493
4494 static int
4495 dissect_nfs_settime4(tvbuff_t *tvb, int offset,
4496         proto_tree *tree, char *name _U_)
4497 {
4498         guint32 set_it;
4499
4500         set_it = tvb_get_ntohl(tvb, offset);
4501         proto_tree_add_uint(tree, hf_nfs_time_how4, tvb, offset+0, 
4502                 4, set_it);
4503         offset += 4;
4504
4505         if (set_it == SET_TO_CLIENT_TIME4)
4506                 offset = dissect_nfs_nfstime4(tvb, offset, tree);
4507         
4508         return offset;
4509 }
4510
4511 static int
4512 dissect_nfs_fsid4(tvbuff_t *tvb, int offset, proto_tree *tree, char *name)
4513 {
4514         proto_tree *newftree = NULL;
4515         proto_item *fitem = NULL;
4516
4517         fitem = proto_tree_add_text(tree, tvb, offset, 0, "%s", name);
4518
4519         if (fitem == NULL) return offset;
4520
4521         newftree = proto_item_add_subtree(fitem, ett_nfs_fsid4);
4522
4523         if (newftree == NULL) return offset;
4524
4525         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_fsid4_major,
4526                 offset);
4527         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_fsid4_minor,
4528                 offset);
4529
4530         return offset;
4531 }
4532
4533 static const value_string names_acetype4[] = {
4534 #define ACE4_ACCESS_ALLOWED_ACE_TYPE    0x00000000
4535         {       ACE4_ACCESS_ALLOWED_ACE_TYPE, "ACE4_ACCESS_ALLOWED_ACE_TYPE"  },
4536 #define ACE4_ACCESS_DENIED_ACE_TYPE             0x00000001
4537         {       ACE4_ACCESS_DENIED_ACE_TYPE, "ACE4_ACCESS_DENIED_ACE_TYPE" },
4538 #define ACE4_SYSTEM_AUDIT_ACE_TYPE              0x00000002
4539         {       ACE4_SYSTEM_AUDIT_ACE_TYPE, "ACE4_SYSTEM_AUDIT_ACE_TYPE" },
4540 #define ACE4_SYSTEM_ALARM_ACE_TYPE              0x00000003
4541         {       ACE4_SYSTEM_ALARM_ACE_TYPE, "ACE4_SYSTEM_ALARM_ACE_TYPE"        },
4542         { 0, NULL }
4543 };
4544
4545 /* ACE mask values */
4546 #define ACE4_READ_DATA                          0x00000001
4547 #define ACE4_LIST_DIRECTORY             0x00000001
4548 #define ACE4_WRITE_DATA                         0x00000002
4549 #define ACE4_ADD_FILE                           0x00000002
4550 #define ACE4_APPEND_DATA                        0x00000004
4551 #define ACE4_ADD_SUBDIRECTORY           0x00000004
4552 #define ACE4_READ_NAMED_ATTRS           0x00000008
4553 #define ACE4_WRITE_NAMED_ATTRS  0x00000010
4554 #define ACE4_EXECUTE                                    0x00000020
4555 #define ACE4_DELETE_CHILD                       0x00000040
4556 #define ACE4_READ_ATTRIBUTES            0x00000080
4557 #define ACE4_WRITE_ATTRIBUTES           0x00000100
4558 #define ACE4_DELETE                                     0x00010000
4559 #define ACE4_READ_ACL                           0x00020000
4560 #define ACE4_WRITE_ACL                          0x00040000
4561 #define ACE4_WRITE_OWNER                        0x00080000
4562 #define ACE4_SYNCHRONIZE                        0x00100000
4563
4564 static int
4565 dissect_nfs_acemask4(tvbuff_t *tvb, int offset, proto_tree *tree)
4566 {
4567         guint32 acemask;
4568         proto_item *acemask_item = NULL;
4569         proto_tree *acemask_tree = NULL;
4570
4571         acemask = tvb_get_ntohl(tvb, offset);
4572
4573         acemask_item = proto_tree_add_text(tree, tvb, offset, 4, 
4574                 "acemask: 0x%08x", acemask);
4575
4576         if (acemask_item)
4577                 acemask_tree = proto_item_add_subtree(acemask_item, ett_nfs_acemask4);
4578
4579         if (acemask_tree)
4580         {
4581                 if (acemask & ACE4_READ_DATA)
4582                         proto_tree_add_text(acemask_tree, tvb, offset, 4, 
4583                                 "ACE4_READ_DATA/ACE4_LIST_DIRECTORY (0x%08x)",
4584                                 ACE4_READ_DATA);
4585
4586                 if (acemask & ACE4_WRITE_DATA)
4587                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4588                                 "ACE4_WRITE_DATA/ACE4_ADD_FILE (0x%08x)",
4589                                 ACE4_WRITE_DATA);
4590
4591                 if (acemask & ACE4_APPEND_DATA)
4592                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4593                                 "ACE4_ADD_FILE/ACE4_ADD_SUBDIRECTORY (0x%08x)",
4594                                 ACE4_APPEND_DATA);
4595
4596                 if (acemask & ACE4_READ_NAMED_ATTRS)
4597                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4598                                 "ACE4_READ_NAMED_ATTRS (0x%08x)",
4599                                 ACE4_READ_NAMED_ATTRS);
4600
4601                 if (acemask & ACE4_WRITE_NAMED_ATTRS)
4602                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4603                                 "ACE4_WRITE_NAMED_ATTRS (0x%08x)",
4604                                 ACE4_WRITE_NAMED_ATTRS);
4605
4606                 if (acemask & ACE4_EXECUTE)
4607                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4608                                 "ACE4_EXECUTE (0x%08x)",
4609                                 ACE4_EXECUTE);
4610
4611                 if (acemask & ACE4_DELETE_CHILD)
4612                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4613                                 "ACE4_DELETE_CHILD (0x%08x)",
4614                                 ACE4_DELETE_CHILD);
4615                                         
4616                 if (acemask & ACE4_READ_ATTRIBUTES)
4617                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4618                                 "ACE4_READ_ATTRIBUTES (0x%08x)",
4619                                 ACE4_READ_ATTRIBUTES);
4620
4621                 if (acemask & ACE4_WRITE_ATTRIBUTES)
4622                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4623                                 "ACE4_WRITE_ATTRIBUTES (0x%08x)",
4624                                 ACE4_WRITE_ATTRIBUTES);
4625
4626                 if (acemask & ACE4_DELETE)
4627                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4628                                 "ACE4_DELETE (0x%08x)",
4629                                 ACE4_DELETE);
4630
4631                 if (acemask & ACE4_READ_ACL)
4632                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4633                                 "ACE4_READ_ACL (0x%08x)",
4634                                 ACE4_READ_ACL);
4635
4636                 if (acemask & ACE4_WRITE_ACL)
4637                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4638                                 "ACE4_WRITE_ACL (0x%08x)",
4639                                 ACE4_WRITE_ACL);
4640
4641                 if (acemask & ACE4_WRITE_OWNER)
4642                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4643                                 "ACE4_WRITE_OWNER (0x%08x)",
4644                                 ACE4_WRITE_OWNER);
4645
4646                 if (acemask & ACE4_SYNCHRONIZE)
4647                         proto_tree_add_text(acemask_tree, tvb, offset, 4,
4648                                 "ACE4_SYNCHRONIZE (0x%08x)",
4649                                 ACE4_SYNCHRONIZE);
4650         }
4651
4652         offset += 4;
4653
4654         return offset;
4655 }
4656
4657 /* ACE flag values */
4658 #define ACE4_FILE_INHERIT_ACE                                   0x00000001
4659 #define ACE4_DIRECTORY_INHERIT_ACE                      0x00000002
4660 #define ACE4_NO_PROPAGATE_INHERIT_ACE           0x00000004
4661 #define ACE4_INHERIT_ONLY_ACE                                   0x00000008
4662 #define ACE4_SUCCESSFUL_ACCESS_ACE_FLAG 0x00000010
4663 #define ACE4_FAILED_ACCESS_ACE_FLAG                     0x00000020
4664 #define ACE4_IDENTIFIER_GROUP                                   0x00000040
4665
4666
4667 static int
4668 dissect_nfs_ace4(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, 
4669         proto_tree *tree)
4670 {
4671         proto_item* ace_item = NULL;
4672         proto_tree* ace_tree = NULL;
4673         proto_item *aceflag_item = NULL;
4674         proto_tree *aceflag_tree = NULL;
4675         guint32 aceflag4;
4676
4677         if (tree) {
4678                 ace_item = proto_tree_add_text(tree, tvb, offset, 4, 
4679                         "ACE");
4680
4681                 if (ace_item)
4682                         ace_tree = proto_item_add_subtree(ace_item, ett_nfs_ace4);
4683         }
4684
4685         if (ace_tree) {
4686                 offset = dissect_rpc_uint32(tvb, ace_tree, hf_nfs_acetype4, offset);
4687
4688                 aceflag4 = tvb_get_ntohl(tvb, offset);
4689
4690                 aceflag_item = proto_tree_add_text(ace_tree, tvb, offset, 4, 
4691                         "aceflag: 0x%08x", aceflag4);
4692
4693                 if (aceflag_item)
4694                 {
4695                         aceflag_tree = proto_item_add_subtree(aceflag_item, ett_nfs_aceflag4);
4696
4697                         if (aceflag_tree)
4698                         {
4699                                 if (aceflag4 & ACE4_FILE_INHERIT_ACE)
4700                                         proto_tree_add_text(aceflag_tree, tvb, offset, 4, 
4701                                                 "ACE4_FILE_INHERIT_ACE (0x%08x)", ACE4_FILE_INHERIT_ACE);
4702
4703                                 if (aceflag4 & ACE4_DIRECTORY_INHERIT_ACE)
4704                                         proto_tree_add_text(aceflag_tree, tvb, offset, 4,
4705                                                 "ACE4_DIRECTORY_INHERIT_ACE (0x%08x)",
4706                                                  ACE4_DIRECTORY_INHERIT_ACE);
4707
4708                                 if (aceflag4 & ACE4_INHERIT_ONLY_ACE)
4709                                         proto_tree_add_text(aceflag_tree, tvb, offset, 4, 
4710                                                 "ACE4_INHERIT_ONLY_ACE (0x%08x)", 
4711                                                 ACE4_INHERIT_ONLY_ACE);
4712
4713                                 if (aceflag4 & ACE4_SUCCESSFUL_ACCESS_ACE_FLAG)
4714                                         proto_tree_add_text(aceflag_tree, tvb, offset, 4,
4715                                                 "ACE4_SUCCESSFUL_ACCESS_ACE_FLAG (0x%08x)",
4716                                                 ACE4_SUCCESSFUL_ACCESS_ACE_FLAG);
4717
4718                                 if (aceflag4 & ACE4_FAILED_ACCESS_ACE_FLAG)
4719                                         proto_tree_add_text(aceflag_tree, tvb, offset, 4,
4720                                                 "ACE4_FAILED_ACCESS_ACE_FLAG (0x%08x)",
4721                                                 ACE4_FAILED_ACCESS_ACE_FLAG);
4722
4723                                 if (aceflag4 & ACE4_IDENTIFIER_GROUP)
4724                                         proto_tree_add_text(aceflag_tree, tvb, offset, 4,
4725                                                 "ACE4_IDENTIFIER_GROUP (0x%08x)",
4726                                                 ACE4_IDENTIFIER_GROUP);
4727                         }
4728                 }
4729
4730                 offset += 4;
4731
4732                 offset = dissect_nfs_acemask4(tvb, offset, ace_tree);
4733                 
4734                 offset = dissect_nfs_utf8string(tvb, offset, ace_tree, hf_nfs_who, NULL);
4735         }
4736
4737         return offset;
4738 }
4739
4740 static int
4741 dissect_nfs_fattr4_acl(tvbuff_t *tvb, int offset, packet_info *pinfo,
4742         proto_tree *tree)
4743 {
4744         return dissect_rpc_array(tvb, pinfo, tree, offset, dissect_nfs_ace4,
4745                 hf_nfs_acl4);
4746 }
4747
4748 static int
4749 dissect_nfs_fh4(tvbuff_t *tvb, int offset, packet_info *pinfo,
4750         proto_tree *tree, char *name)
4751 {
4752         return dissect_nfs_fh3(tvb, offset, pinfo, tree, name);
4753 }
4754
4755 static int
4756 dissect_nfs_fs_location4(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
4757         proto_tree *tree)
4758 {
4759         proto_tree *newftree = NULL;
4760         proto_item *fitem = NULL;
4761
4762         fitem = proto_tree_add_text(tree, tvb, offset, 0, "rootpath");
4763
4764         if (fitem == NULL) return offset;
4765
4766         newftree = proto_item_add_subtree(fitem, ett_nfs_fs_location4);
4767
4768         if (newftree == NULL) return offset;
4769
4770         offset = dissect_nfs_utf8string(tvb, offset, tree, hf_nfs_server, NULL);
4771
4772         return offset;
4773 }
4774
4775 static int
4776 dissect_nfs_fs_locations4(tvbuff_t *tvb, packet_info *pinfo, int offset,
4777         proto_tree *tree, char *name)
4778 {
4779         proto_tree *newftree = NULL;
4780         proto_item *fitem = NULL;
4781
4782         fitem = proto_tree_add_text(tree, tvb, offset, 0, "%s", name);
4783
4784         if (fitem == NULL) return offset;
4785
4786         newftree = proto_item_add_subtree(fitem, ett_nfs_fs_locations4);
4787
4788         if (newftree == NULL) return offset;
4789
4790         offset = dissect_nfs_pathname4(tvb, offset, newftree);
4791
4792         offset = dissect_rpc_list(tvb, pinfo, tree, offset, 
4793                 dissect_nfs_fs_location4);
4794
4795         return offset;
4796 }
4797
4798 static int
4799 dissect_nfs_mode4(tvbuff_t *tvb, int offset,
4800         proto_tree *tree, char *name)
4801 {
4802         return dissect_mode(tvb, offset, tree, name);
4803 }
4804
4805 static const value_string nfs4_fattr4_fh_expire_type_names[] = {
4806 #define FH4_PERSISTENT 0x00000000
4807         {       FH4_PERSISTENT, "FH4_PERSISTENT"        },
4808 #define FH4_NOEXPIRE_WITH_OPEN 0x00000001
4809         {       FH4_NOEXPIRE_WITH_OPEN, "FH4_NOEXPIRE_WITH_OPEN"        },
4810 #define FH4_VOLATILE_ANY 0x00000002
4811         {       FH4_VOLATILE_ANY,       "FH4_VOLATILE_ANY"      },
4812 #define FH4_VOL_MIGRATION 0x00000004
4813         {       FH4_VOL_MIGRATION,      "FH4_VOL_MIGRATION"     },
4814 #define FH4_VOL_RENAME 0x00000008
4815         {       FH4_VOL_RENAME, "FH4_VOL_RENAME"        },
4816         {       0,      NULL    }
4817 };
4818
4819
4820 static int
4821 dissect_nfs_fattr4_fh_expire_type(tvbuff_t *tvb, int offset, proto_tree *tree)
4822 {
4823         guint32 expire_type;
4824         proto_item *expire_type_item = NULL;
4825         proto_tree *expire_type_tree = NULL;
4826
4827         expire_type = tvb_get_ntohl(tvb, offset + 0);
4828
4829         if (tree)
4830         {
4831                 expire_type_item = proto_tree_add_text(tree, tvb, offset, 4,
4832                         "fattr4_fh_expire_type: 0x%08x", expire_type);
4833                 if (expire_type_item)
4834                         expire_type_tree = proto_item_add_subtree(expire_type_item, 
4835                                 ett_nfs_fattr4_fh_expire_type);
4836         }
4837
4838         if (expire_type_tree)
4839         {
4840                 if (expire_type == FH4_PERSISTENT)
4841                 {
4842                         proto_tree_add_text(expire_type_tree, tvb, offset, 4, "%s",
4843                                 decode_enumerated_bitfield(expire_type, FH4_PERSISTENT, 8, 
4844                                 nfs4_fattr4_fh_expire_type_names, "%s"));
4845                 }
4846                 else
4847                 {
4848                         if (expire_type & FH4_NOEXPIRE_WITH_OPEN)
4849                                 proto_tree_add_text(expire_type_tree, tvb, offset, 4,
4850                                                 "FH4_NOEXPIRE_WITH_OPEN (0x%08x)", FH4_NOEXPIRE_WITH_OPEN);
4851
4852                         if (expire_type & FH4_VOLATILE_ANY)
4853                                 proto_tree_add_text(expire_type_tree, tvb, offset, 4,
4854                                                 "FH4_VOLATILE_ANY (0x%08x)", FH4_VOLATILE_ANY);
4855
4856                         if (expire_type & FH4_VOL_MIGRATION)
4857                                 proto_tree_add_text(expire_type_tree, tvb, offset, 4,
4858                                                 "FH4_VOL_MIGRATION (0x%08x)", FH4_VOL_MIGRATION);
4859
4860                         if (expire_type & FH4_VOL_RENAME)
4861                                 proto_tree_add_text(expire_type_tree, tvb, offset, 4,
4862                                                 "FH4_VOL_RENAME (0x%08x)", FH4_VOL_RENAME);
4863                 }
4864         }
4865
4866         offset += 4;
4867
4868         return offset;
4869 }
4870
4871 static const value_string names_fattr4[] = {
4872 #define FATTR4_SUPPORTED_ATTRS     0
4873         {       FATTR4_SUPPORTED_ATTRS, "FATTR4_SUPPORTED_ATTRS"        },
4874 #define FATTR4_TYPE                1
4875         {       FATTR4_TYPE,    "FATTR4_TYPE"   },
4876 #define FATTR4_FH_EXPIRE_TYPE      2
4877         {       FATTR4_FH_EXPIRE_TYPE,  "FATTR4_FH_EXPIRE_TYPE" },
4878 #define FATTR4_CHANGE              3
4879         {       FATTR4_CHANGE,  "FATTR4_CHANGE" },
4880 #define FATTR4_SIZE                4
4881         {       FATTR4_SIZE,    "FATTR4_SIZE"   },
4882 #define FATTR4_LINK_SUPPORT        5
4883         {       FATTR4_LINK_SUPPORT,    "FATTR4_LINK_SUPPORT"   },
4884 #define FATTR4_SYMLINK_SUPPORT     6
4885         {       FATTR4_SYMLINK_SUPPORT, "FATTR4_SYMLINK_SUPPORT"        },
4886 #define FATTR4_NAMED_ATTR          7
4887         {       FATTR4_NAMED_ATTR,      "FATTR4_NAMED_ATTR"     },
4888 #define FATTR4_FSID                8
4889         {       FATTR4_FSID,    "FATTR4_FSID"   },
4890 #define FATTR4_UNIQUE_HANDLES      9
4891         {       FATTR4_UNIQUE_HANDLES,  "FATTR4_UNIQUE_HANDLES" },
4892 #define FATTR4_LEASE_TIME          10
4893         {       FATTR4_LEASE_TIME,      "FATTR4_LEASE_TIME"     },
4894 #define FATTR4_RDATTR_ERROR        11
4895         {       FATTR4_RDATTR_ERROR,    "FATTR4_RDATTR_ERROR"   },
4896 #define FATTR4_ACL                 12
4897         {       FATTR4_ACL,     "FATTR4_ACL"    },
4898 #define FATTR4_ACLSUPPORT          13
4899         {       FATTR4_ACLSUPPORT,      "FATTR4_ACLSUPPORT"     },
4900 #define FATTR4_ARCHIVE             14
4901         {       FATTR4_ARCHIVE, "FATTR4_ARCHIVE"        },
4902 #define FATTR4_CANSETTIME          15
4903         {       FATTR4_CANSETTIME, "FATTR4_CANSETTIME"  },
4904 #define FATTR4_CASE_INSENSITIVE    16
4905         {       FATTR4_CASE_INSENSITIVE, "FATTR4_CASE_INSENSITIVE"      },
4906 #define FATTR4_CASE_PRESERVING     17
4907         {       FATTR4_CASE_PRESERVING, "FATTR4_CASE_PRESERVING"        },
4908 #define FATTR4_CHOWN_RESTRICTED    18
4909         {       FATTR4_CHOWN_RESTRICTED, "FATTR4_CHOWN_RESTRICTED"      },
4910 #define FATTR4_FILEHANDLE          19
4911         {       FATTR4_FILEHANDLE, "FATTR4_FILEHANDLE"  },
4912 #define FATTR4_FILEID              20
4913         {       FATTR4_FILEID, "FATTR4_FILEID"  },
4914 #define FATTR4_FILES_AVAIL         21
4915         {       FATTR4_FILES_AVAIL, "FATTR4_FILES_AVAIL"        },
4916 #define FATTR4_FILES_FREE          22
4917         {       FATTR4_FILES_FREE, "FATTR4_FILES_FREE"  },
4918 #define FATTR4_FILES_TOTAL         23
4919         {       FATTR4_FILES_TOTAL, "FATTR4_FILES_TOTAL"        },
4920 #define FATTR4_FS_LOCATIONS        24
4921         {       FATTR4_FS_LOCATIONS, "FATTR4_FS_LOCATIONS"      },
4922 #define FATTR4_HIDDEN              25
4923         {       FATTR4_HIDDEN, "FATTR4_HIDDEN"  },
4924 #define FATTR4_HOMOGENEOUS         26
4925         {       FATTR4_HOMOGENEOUS, "FATTR4_HOMOGENEOUS"        },
4926 #define FATTR4_MAXFILESIZE         27
4927         {       FATTR4_MAXFILESIZE, "FATTR4_MAXFILESIZE"        },
4928 #define FATTR4_MAXLINK             28
4929         {       FATTR4_MAXLINK, "FATTR4_MAXLINK"        },
4930 #define FATTR4_MAXNAME             29
4931         {       FATTR4_MAXNAME, "FATTR4_MAXNAME"        },
4932 #define FATTR4_MAXREAD             30
4933         {       FATTR4_MAXREAD, "FATTR4_MAXREAD"        },
4934 #define FATTR4_MAXWRITE            31
4935         {       FATTR4_MAXWRITE, "FATTR4_MAXWRITE"      },
4936 #define FATTR4_MIMETYPE            32
4937         {       FATTR4_MIMETYPE, "FATTR4_MIMETYPE"      },
4938 #define FATTR4_MODE                33
4939         {       FATTR4_MODE, "FATTR4_MODE"      },
4940 #define FATTR4_NO_TRUNC            34
4941         {       FATTR4_NO_TRUNC, "FATTR4_NO_TRUNC"      },
4942 #define FATTR4_NUMLINKS            35
4943         {       FATTR4_NUMLINKS, "FATTR4_NUMLINKS"      },
4944 #define FATTR4_OWNER               36
4945         {       FATTR4_OWNER, "FATTR4_OWNER"    },
4946 #define FATTR4_OWNER_GROUP         37
4947         {       FATTR4_OWNER_GROUP, "FATTR4_OWNER_GROUP"        },
4948 #define FATTR4_QUOTA_AVAIL_HARD    38
4949         {       FATTR4_QUOTA_AVAIL_HARD, "FATTR4_QUOTA_AVAIL_HARD"      },
4950 #define FATTR4_QUOTA_AVAIL_SOFT    39
4951         {       FATTR4_QUOTA_AVAIL_SOFT, "FATTR4_QUOTA_AVAIL_SOFT"      },
4952 #define FATTR4_QUOTA_USED          40
4953         {       FATTR4_QUOTA_USED, "FATTR4_QUOTA_USED"  },
4954 #define FATTR4_RAWDEV              41
4955         {       FATTR4_RAWDEV, "FATTR4_RAWDEV"  },
4956 #define FATTR4_SPACE_AVAIL         42
4957         {       FATTR4_SPACE_AVAIL, "FATTR4_SPACE_AVAIL"        },
4958 #define FATTR4_SPACE_FREE          43
4959         {       FATTR4_SPACE_FREE, "FATTR4_SPACE_FREE"  },
4960 #define FATTR4_SPACE_TOTAL         44
4961         {       FATTR4_SPACE_TOTAL, "FATTR4_SPACE_TOTAL"        },
4962 #define FATTR4_SPACE_USED          45
4963         {       FATTR4_SPACE_USED, "FATTR4_SPACE_USED"  },
4964 #define FATTR4_SYSTEM              46
4965         {       FATTR4_SYSTEM, "FATTR4_SYSTEM"  },
4966 #define FATTR4_TIME_ACCESS         47
4967         {       FATTR4_TIME_ACCESS, "FATTR4_TIME_ACCESS"        },
4968 #define FATTR4_TIME_ACCESS_SET     48
4969         {       FATTR4_TIME_ACCESS_SET, "FATTR4_TIME_ACCESS_SET"        },
4970 #define FATTR4_TIME_BACKUP         49
4971         {       FATTR4_TIME_BACKUP, "FATTR4_TIME_BACKUP"        },
4972 #define FATTR4_TIME_CREATE         50
4973         {       FATTR4_TIME_CREATE, "FATTR4_TIME_CREATE"        },
4974 #define FATTR4_TIME_DELTA          51
4975         {       FATTR4_TIME_DELTA, "FATTR4_TIME_DELTA"  },
4976 #define FATTR4_TIME_METADATA       52
4977         {       FATTR4_TIME_METADATA, "FATTR4_TIME_METADATA"    },
4978 #define FATTR4_TIME_MODIFY         53
4979         {       FATTR4_TIME_MODIFY, "FATTR4_TIME_MODIFY"        },
4980 #define FATTR4_TIME_MODIFY_SET     54
4981         {       FATTR4_TIME_MODIFY_SET, "FATTR4_TIME_MODIFY_SET"        },
4982 #define FATTR4_MOUNTED_ON_FILEID   55
4983         {       FATTR4_MOUNTED_ON_FILEID, "FATTR4_MOUNTED_ON_FILEID"    },
4984         {       0,      NULL    }
4985 };
4986
4987 #define FATTR4_BITMAP_ONLY 0
4988 #define FATTR4_FULL_DISSECT 1
4989
4990 static int
4991 dissect_nfs_attributes(tvbuff_t *tvb, int offset, packet_info *pinfo,
4992         proto_tree *tree, int type)
4993 {
4994         guint32 bitmap_len;
4995         proto_item *fitem = NULL;
4996         proto_tree *newftree = NULL;
4997         proto_item *attr_fitem = NULL;
4998         proto_tree *attr_newftree = NULL;
4999         guint32 i;
5000         gint j;
5001         guint32 fattr;
5002         guint32 *bitmap;
5003         guint32 sl;
5004         int attr_vals_offset;
5005
5006         bitmap_len = tvb_get_ntohl(tvb, offset);
5007         fitem = proto_tree_add_text(tree, tvb, offset, 4 + bitmap_len * 4,
5008                 "%s", "attrmask");
5009         offset += 4;
5010
5011         if (fitem == NULL) return offset;
5012
5013         newftree = proto_item_add_subtree(fitem, ett_nfs_bitmap4);
5014
5015         if (newftree == NULL) return offset;
5016
5017         attr_vals_offset = offset + 4 + bitmap_len * 4;
5018
5019         bitmap = g_malloc(bitmap_len * sizeof(guint32));        
5020         if (bitmap == NULL) return offset;
5021
5022         for (i = 0; i < bitmap_len; i++)
5023         {
5024                 if (!tvb_bytes_exist(tvb, offset,  4))
5025                 {
5026                         g_free(bitmap);
5027                         return offset;
5028                 }
5029
5030                 bitmap[i] = tvb_get_ntohl(tvb, offset);
5031
5032                 sl = 0x00000001;
5033
5034                 for (j = 0; j < 32; j++)
5035                 {
5036                         fattr = 32 * i + j;
5037
5038                         if (bitmap[i] & sl)
5039                         {
5040                                 /* switch label if attribute is recommended vs. mandatory */
5041                                 attr_fitem = proto_tree_add_uint(newftree, 
5042                                         (fattr < FATTR4_ACL)? hf_nfs_mand_attr: hf_nfs_recc_attr, 
5043                                         tvb, offset, 4, fattr);
5044
5045                                 if (attr_fitem == NULL) break;
5046
5047                                 attr_newftree = proto_item_add_subtree(attr_fitem, ett_nfs_bitmap4);
5048
5049                                 if (attr_newftree == NULL) break;
5050
5051                                 if (type == FATTR4_FULL_DISSECT)
5052                                 {
5053                                         /* do a full decode of the arguments for the set flag */
5054                                         switch(fattr)
5055                                         {
5056                                         case FATTR4_SUPPORTED_ATTRS:
5057                                                 attr_vals_offset = dissect_nfs_attributes(tvb, 
5058                                                         attr_vals_offset, pinfo, attr_newftree, 
5059                                                         FATTR4_BITMAP_ONLY);
5060                                                 break;
5061                                                 
5062                                         case FATTR4_TYPE:
5063                                                 attr_vals_offset = dissect_rpc_uint32(tvb,
5064                                                         attr_newftree, hf_nfs_ftype4, attr_vals_offset);
5065                                                 break;
5066
5067                                         case FATTR4_FH_EXPIRE_TYPE:
5068                                                 attr_vals_offset = dissect_nfs_fattr4_fh_expire_type(tvb,
5069                                                         attr_vals_offset, attr_newftree);
5070                                                 break;
5071
5072                                         case FATTR4_CHANGE:
5073                                                 attr_vals_offset = dissect_rpc_uint64(tvb, attr_newftree, 
5074                                                         hf_nfs_changeid4, attr_vals_offset);
5075                                                 break;
5076
5077                                         case FATTR4_SIZE:
5078                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5079                                                         attr_newftree, hf_nfs_fattr4_size, attr_vals_offset);
5080                                                 break;
5081
5082                                         case FATTR4_LINK_SUPPORT:
5083                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5084                                                         attr_newftree, hf_nfs_fattr4_link_support, 
5085                                                         attr_vals_offset);
5086                                                 break;
5087
5088                                         case FATTR4_SYMLINK_SUPPORT:
5089                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5090                                                         attr_newftree, hf_nfs_fattr4_symlink_support, 
5091                                                         attr_vals_offset);
5092                                                 break;
5093
5094                                         case FATTR4_NAMED_ATTR:
5095                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5096                                                         attr_newftree, hf_nfs_fattr4_named_attr, attr_vals_offset);
5097                                                 break;
5098
5099                                         case FATTR4_FSID:
5100                                                 attr_vals_offset = dissect_nfs_fsid4(tvb, attr_vals_offset,
5101                                                         attr_newftree, "fattr4_fsid");
5102                                                 break;
5103
5104                                         case FATTR4_UNIQUE_HANDLES:
5105                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5106                                                         attr_newftree, hf_nfs_fattr4_unique_handles, 
5107                                                         attr_vals_offset);
5108                                                 break;
5109
5110                                         case FATTR4_LEASE_TIME:
5111                                                 attr_vals_offset = dissect_rpc_uint32(tvb,
5112                                                         attr_newftree, hf_nfs_fattr4_lease_time, 
5113                                                         attr_vals_offset);
5114                                                 break;
5115
5116                                         case FATTR4_RDATTR_ERROR:
5117                                                 attr_vals_offset = dissect_nfs_nfsstat4(tvb, 
5118                                                         attr_vals_offset, attr_newftree, NULL);
5119                                                 break;
5120
5121                                         case FATTR4_ACL:
5122                                                 attr_vals_offset = dissect_nfs_fattr4_acl(tvb, 
5123                                                         attr_vals_offset, pinfo, attr_newftree);
5124                                                 break;
5125
5126                                         case FATTR4_ACLSUPPORT:
5127                                                 attr_vals_offset = dissect_rpc_uint32(tvb,
5128                                                         attr_newftree, hf_nfs_fattr4_aclsupport, 
5129                                                         attr_vals_offset);
5130                                                 break;
5131
5132                                         case FATTR4_ARCHIVE:
5133                                                 attr_vals_offset = dissect_rpc_bool(tvb, 
5134                                                         attr_newftree, hf_nfs_fattr4_archive, 
5135                                                         attr_vals_offset);
5136                                                 break;
5137
5138                                         case FATTR4_CANSETTIME:
5139                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5140                                                         attr_newftree, hf_nfs_fattr4_cansettime, attr_vals_offset);
5141                                                 break;
5142
5143                                         case FATTR4_CASE_INSENSITIVE:
5144                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5145                                                         attr_newftree, hf_nfs_fattr4_case_insensitive, 
5146                                                         attr_vals_offset);
5147                                                 break;
5148
5149                                         case FATTR4_CASE_PRESERVING:
5150                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5151                                                         attr_newftree, hf_nfs_fattr4_case_preserving, 
5152                                                         attr_vals_offset);
5153                                                 break;
5154
5155                                         case FATTR4_CHOWN_RESTRICTED:
5156                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5157                                                         attr_newftree, hf_nfs_fattr4_chown_restricted, 
5158                                                         attr_vals_offset);
5159                                                 break;
5160
5161                                         case FATTR4_FILEID:
5162                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5163                                                         attr_newftree, hf_nfs_fattr4_fileid, attr_vals_offset);
5164                                                 break;
5165
5166                                         case FATTR4_FILES_AVAIL:
5167                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5168                                                         attr_newftree, hf_nfs_fattr4_files_avail, 
5169                                                         attr_vals_offset);
5170                                                 break;
5171
5172                                         case FATTR4_FILEHANDLE:
5173                                                 attr_vals_offset = dissect_nfs_fh4(tvb, attr_vals_offset,
5174                                                         pinfo, attr_newftree, "fattr4_filehandle");
5175                                                 break;
5176
5177                                         case FATTR4_FILES_FREE:
5178                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5179                                                         attr_newftree, hf_nfs_fattr4_files_free, attr_vals_offset);
5180                                                 break;
5181
5182                                         case FATTR4_FILES_TOTAL:
5183                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5184                                                         attr_newftree, hf_nfs_fattr4_files_total, 
5185                                                         attr_vals_offset);
5186                                                 break;
5187
5188                                         case FATTR4_FS_LOCATIONS:
5189                                                 attr_vals_offset = dissect_nfs_fs_locations4(tvb, pinfo,
5190                                                         attr_vals_offset, attr_newftree, 
5191                                                         "fattr4_fs_locations");
5192                                                 break;
5193
5194                                         case FATTR4_HIDDEN:
5195                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5196                                                         attr_newftree, hf_nfs_fattr4_hidden, attr_vals_offset);
5197                                                 break;
5198
5199                                         case FATTR4_HOMOGENEOUS:
5200                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5201                                                         attr_newftree, hf_nfs_fattr4_homogeneous, 
5202                                                         attr_vals_offset);
5203                                                 break;
5204
5205                                         case FATTR4_MAXFILESIZE:
5206                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5207                                                         attr_newftree, hf_nfs_fattr4_maxfilesize, 
5208                                                         attr_vals_offset);
5209                                                 break;
5210
5211                                         case FATTR4_MAXLINK:
5212                                                 attr_vals_offset = dissect_rpc_uint32(tvb,
5213                                                         attr_newftree, hf_nfs_fattr4_maxlink, attr_vals_offset);
5214                                                 break;
5215
5216                                         case FATTR4_MAXNAME:
5217                                                 attr_vals_offset = dissect_rpc_uint32(tvb,
5218                                                         attr_newftree, hf_nfs_fattr4_maxname, attr_vals_offset);
5219                                                 break;
5220
5221                                         case FATTR4_MAXREAD:
5222                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5223                                                         attr_newftree, hf_nfs_fattr4_maxread, attr_vals_offset);
5224                                                 break;
5225
5226                                         case FATTR4_MAXWRITE:
5227                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5228                                                         attr_newftree, hf_nfs_fattr4_maxwrite, attr_vals_offset);
5229                                                 break;
5230
5231                                         case FATTR4_MIMETYPE:
5232                                                 attr_vals_offset = dissect_nfs_utf8string(tvb, 
5233                                                         attr_vals_offset, attr_newftree, 
5234                                                         hf_nfs_fattr4_mimetype, NULL);
5235                                                 break;
5236                                         
5237                                         case FATTR4_MODE:
5238                                                 attr_vals_offset = dissect_nfs_mode4(tvb,
5239                                                         attr_vals_offset, attr_newftree, "fattr4_mode");
5240                                                 break;
5241
5242                                         case FATTR4_NO_TRUNC:
5243                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5244                                                         attr_newftree, hf_nfs_fattr4_no_trunc, attr_vals_offset);
5245                                                 break;
5246
5247                                         case FATTR4_NUMLINKS:
5248                                                 attr_vals_offset = dissect_rpc_uint32(tvb,
5249                                                         attr_newftree, hf_nfs_fattr4_numlinks, attr_vals_offset);
5250                                                 break;
5251
5252                                         case FATTR4_OWNER:
5253                                                 attr_vals_offset = dissect_nfs_utf8string(tvb, 
5254                                                         attr_vals_offset, attr_newftree, 
5255                                                         hf_nfs_fattr4_owner,
5256                                                         NULL);
5257                                                 break;
5258
5259                                         case FATTR4_OWNER_GROUP:
5260                                                 attr_vals_offset = dissect_nfs_utf8string(tvb, 
5261                                                         attr_vals_offset, attr_newftree, 
5262                                                         hf_nfs_fattr4_owner_group, NULL);
5263                                                 break;
5264
5265                                         case FATTR4_QUOTA_AVAIL_HARD:
5266                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5267                                                         attr_newftree, hf_nfs_fattr4_quota_hard, attr_vals_offset);
5268                                                 break;
5269
5270                                         case FATTR4_QUOTA_AVAIL_SOFT:
5271                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5272                                                         attr_newftree, hf_nfs_fattr4_quota_soft, attr_vals_offset);
5273                                                 break;
5274
5275                                         case FATTR4_QUOTA_USED:
5276                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5277                                                         attr_newftree, hf_nfs_fattr4_quota_used, attr_vals_offset);
5278                                                 break;
5279
5280                                         case FATTR4_RAWDEV:
5281                                                 attr_vals_offset = dissect_nfs_specdata4(tvb, 
5282                                                         attr_vals_offset, attr_newftree);
5283                                                 break;
5284
5285                                         case FATTR4_SPACE_AVAIL:
5286                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5287                                                         attr_newftree, hf_nfs_fattr4_space_avail, 
5288                                                         attr_vals_offset);
5289                                                 break;
5290
5291                                         case FATTR4_SPACE_FREE:
5292                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5293                                                         attr_newftree, hf_nfs_fattr4_space_free, attr_vals_offset);
5294                                                 break;
5295
5296                                         case FATTR4_SPACE_TOTAL:
5297                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5298                                                         attr_newftree, hf_nfs_fattr4_space_total, 
5299                                                         attr_vals_offset);
5300                                                 break;
5301
5302                                         case FATTR4_SPACE_USED:
5303                                                 attr_vals_offset = dissect_rpc_uint64(tvb,
5304                                                         attr_newftree, hf_nfs_fattr4_space_used, attr_vals_offset);
5305                                                 break;
5306                                         
5307                                         case FATTR4_SYSTEM:
5308                                                 attr_vals_offset = dissect_rpc_bool(tvb,
5309                                                         attr_newftree, hf_nfs_fattr4_system, attr_vals_offset);
5310                                                 break;
5311
5312                                         case FATTR4_TIME_ACCESS:
5313                                         case FATTR4_TIME_BACKUP:
5314                                         case FATTR4_TIME_CREATE:
5315                                         case FATTR4_TIME_DELTA:
5316                                         case FATTR4_TIME_METADATA:
5317                                         case FATTR4_TIME_MODIFY:
5318                                                 attr_vals_offset = dissect_nfs_nfstime4(tvb, attr_vals_offset,
5319                                                         attr_newftree);
5320                                                 break;
5321
5322                                         case FATTR4_TIME_ACCESS_SET:
5323                                         case FATTR4_TIME_MODIFY_SET:
5324                                                 attr_vals_offset = dissect_nfs_settime4(tvb, 
5325                                                         attr_vals_offset, attr_newftree, "settime4");
5326                                                 break;
5327
5328                                         default:
5329                                                 break;
5330                                         }
5331                                 }
5332                         }
5333
5334                         sl <<= 1;
5335                 }
5336
5337                 offset += 4;
5338         }
5339
5340         g_free(bitmap);
5341
5342         return offset;
5343 }
5344
5345 static int
5346 dissect_nfs_fattr4(tvbuff_t *tvb, int offset, packet_info *pinfo,
5347         proto_tree *tree)
5348 {
5349         proto_tree *newftree = NULL;
5350         proto_item *fitem = NULL;
5351
5352         fitem = proto_tree_add_text(tree, tvb, offset, 4, "obj_attributes");
5353
5354         if (fitem == NULL) return offset;
5355
5356         newftree = proto_item_add_subtree(fitem, ett_nfs_fattr4);
5357
5358         if (newftree == NULL) return offset;
5359
5360         offset = dissect_nfs_attributes(tvb, offset, pinfo, newftree, 
5361                 FATTR4_FULL_DISSECT);
5362
5363         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_attrlist4);
5364
5365         return offset;
5366 }
5367
5368 static const value_string names_open4_share_access[] = {
5369 #define OPEN4_SHARE_ACCESS_READ 0x00000001
5370         { OPEN4_SHARE_ACCESS_READ, "OPEN4_SHARE_ACCESS_READ" }, 
5371 #define OPEN4_SHARE_ACCESS_WRITE 0x00000002
5372         { OPEN4_SHARE_ACCESS_WRITE, "OPEN4_SHARE_ACCESS_WRITE" },
5373 #define OPEN4_SHARE_ACCESS_BOTH 0x00000003
5374         { OPEN4_SHARE_ACCESS_BOTH, "OPEN4_SHARE_ACCESS_BOTH" },
5375         { 0, NULL }
5376 };
5377
5378 static int
5379 dissect_nfs_open4_share_access(tvbuff_t *tvb, int offset,
5380         proto_tree *tree)
5381 {
5382         guint share_access;
5383
5384         share_access = tvb_get_ntohl(tvb, offset);
5385         proto_tree_add_uint(tree, hf_nfs_open4_share_access, tvb, offset, 4, 
5386                 share_access);
5387         offset += 4;
5388
5389         return offset;
5390 }
5391
5392 static const value_string names_open4_share_deny[] = {
5393 #define OPEN4_SHARE_DENY_NONE 0x00000000
5394         { OPEN4_SHARE_DENY_NONE, "OPEN4_SHARE_DENY_NONE" },
5395 #define OPEN4_SHARE_DENY_READ 0x00000001
5396         { OPEN4_SHARE_DENY_READ, "OPEN4_SHARE_DENY_READ" },
5397 #define OPEN4_SHARE_DENY_WRITE 0x00000002
5398         { OPEN4_SHARE_DENY_WRITE, "OPEN4_SHARE_DENY_WRITE" },
5399 #define OPEN4_SHARE_DENY_BOTH 0x00000003
5400         { OPEN4_SHARE_DENY_BOTH, "OPEN4_SHARE_DENY_BOTH" },
5401         { 0, NULL }
5402 };
5403
5404 static int
5405 dissect_nfs_open4_share_deny(tvbuff_t *tvb, int offset,
5406         proto_tree *tree)
5407 {
5408         guint deny_access;
5409
5410         deny_access = tvb_get_ntohl(tvb, offset);
5411         proto_tree_add_uint(tree, hf_nfs_open4_share_deny, tvb, offset, 4,
5412                 deny_access);
5413         offset += 4;
5414
5415         return offset;
5416 }
5417
5418 static int
5419 dissect_nfs_open_owner4(tvbuff_t *tvb, int offset, proto_tree *tree)
5420 {
5421         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_clientid4, offset);
5422         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_open_owner4);
5423
5424         return offset;
5425 }
5426
5427 static int
5428 dissect_nfs_open_claim_delegate_cur4(tvbuff_t *tvb, int offset,
5429         proto_tree *tree)
5430 {
5431         offset = dissect_rpc_uint64(tvb, tree, 
5432                 hf_nfs_stateid4_delegate_stateid, offset);
5433         offset = dissect_nfs_utf8string(tvb, offset, tree, hf_nfs_component4, NULL);
5434
5435         return offset;
5436 }
5437
5438 #define CLAIM_NULL                              0
5439 #define CLAIM_PREVIOUS                  1
5440 #define CLAIM_DELEGATE_CUR              2
5441 #define CLAIM_DELEGATE_PREV     3
5442
5443 static const value_string names_claim_type4[] = {
5444         {       CLAIM_NULL,             "CLAIM_NULL"  },
5445         {       CLAIM_PREVIOUS,         "CLAIM_PREVIOUS" },
5446         {       CLAIM_DELEGATE_CUR,     "CLAIM_DELEGATE_CUR" },
5447         {       CLAIM_DELEGATE_PREV,    "CLAIM_DELEGATE_PREV" },
5448         {       0, NULL }
5449 };
5450
5451 static int
5452 dissect_nfs_open_claim4(tvbuff_t *tvb, int offset,
5453         proto_tree *tree)
5454 {
5455         guint open_claim_type4;
5456         proto_item *fitem = NULL;
5457         proto_tree *newftree = NULL;
5458
5459         open_claim_type4 = tvb_get_ntohl(tvb, offset);
5460         fitem = proto_tree_add_uint(tree, hf_nfs_open_claim_type4, tvb,
5461                 offset+0, 4, open_claim_type4);
5462         offset += 4;
5463
5464         if (fitem) {
5465                 newftree = proto_item_add_subtree(fitem, ett_nfs_open_claim4);
5466
5467                 if (newftree) {
5468
5469                         switch(open_claim_type4)
5470                         {
5471                         case CLAIM_NULL:
5472                                 offset = dissect_nfs_utf8string(tvb, offset, newftree, hf_nfs_component4, NULL);
5473                                 break;
5474
5475                         case CLAIM_PREVIOUS:
5476                                 offset = dissect_rpc_uint32(tvb, newftree, 
5477                                         hf_nfs_delegate_type, offset);
5478                                 break;
5479
5480                         case CLAIM_DELEGATE_CUR:
5481                                 offset = dissect_nfs_open_claim_delegate_cur4(tvb, offset,
5482                                         newftree);
5483                                 break;
5484
5485                         case CLAIM_DELEGATE_PREV:
5486                                 offset = dissect_nfs_utf8string(tvb, offset, newftree, hf_nfs_component4, NULL);
5487                                 break;
5488
5489                         default:
5490                                 break;
5491                         }
5492                 }
5493         }
5494
5495         return offset;
5496 }
5497
5498 static int
5499 dissect_nfs_createhow4(tvbuff_t *tvb, int offset, packet_info *pinfo,
5500         proto_tree *tree)
5501 {
5502         guint mode;
5503
5504         /* This is intentional; we're using the same flags as NFSv3 */
5505         mode = tvb_get_ntohl(tvb, offset);
5506         proto_tree_add_uint(tree, hf_nfs_createmode3, tvb, offset, 4, mode);
5507         offset += 4;
5508         
5509         switch(mode)
5510         {
5511         case UNCHECKED:         /* UNCHECKED4 */
5512         case GUARDED:           /* GUARDED4 */
5513                 offset = dissect_nfs_fattr4(tvb, offset, pinfo, tree);
5514                 break;
5515
5516         case EXCLUSIVE:         /* EXCLUSIVE4 */
5517                 offset = dissect_rpc_uint64(tvb, tree, hf_nfs_verifier4, offset);
5518                 break;
5519         
5520         default:
5521                 break;
5522         }
5523
5524         return offset;
5525 }
5526
5527 #define OPEN4_NOCREATE                          0
5528 #define OPEN4_CREATE                                    1
5529 static const value_string names_opentype4[] = {
5530         {       OPEN4_NOCREATE,  "OPEN4_NOCREATE"  },
5531         {       OPEN4_CREATE, "OPEN4_CREATE" },
5532         { 0, NULL }
5533 };
5534
5535 static int
5536 dissect_nfs_openflag4(tvbuff_t *tvb, int offset, packet_info *pinfo,
5537         proto_tree *tree)
5538 {
5539         guint opentype4;
5540         proto_item *fitem = NULL;
5541         proto_tree *newftree = NULL;
5542
5543         opentype4 = tvb_get_ntohl(tvb, offset);
5544         fitem = proto_tree_add_uint(tree, hf_nfs_opentype4, tvb,
5545                 offset+0, 4, opentype4);
5546         offset += 4;
5547
5548         if (fitem) {
5549                 newftree = proto_item_add_subtree(fitem, ett_nfs_opentype4);
5550
5551                 if (newftree) {
5552
5553                         switch(opentype4)
5554                         {
5555                         case OPEN4_CREATE:
5556                                 offset = dissect_nfs_createhow4(tvb, offset, pinfo, newftree);
5557                                 break;
5558
5559                         default:
5560                                 break;
5561                         }
5562                 }
5563         }
5564
5565         return offset;
5566 }
5567
5568 static int
5569 dissect_nfs_clientaddr4(tvbuff_t *tvb, int offset, proto_tree *tree)
5570 {
5571         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_r_netid);
5572         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_r_addr);
5573
5574         return offset;
5575 }
5576         
5577
5578 static int
5579 dissect_nfs_cb_client4(tvbuff_t *tvb, int offset, proto_tree *tree)
5580 {
5581         proto_tree *cb_location = NULL;
5582         proto_item *fitem = NULL;
5583
5584         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_cb_program, offset);
5585
5586         fitem = proto_tree_add_text(tree, tvb, offset, 0, "cb_location");
5587
5588         if (fitem) 
5589         {
5590                 cb_location = proto_item_add_subtree(fitem, ett_nfs_clientaddr4);
5591         
5592                 offset = dissect_nfs_clientaddr4(tvb, offset, cb_location);
5593         }
5594
5595         return offset;
5596 }
5597
5598 static const value_string names_stable_how4[] = {
5599 #define UNSTABLE4 0
5600         {       UNSTABLE4,      "UNSTABLE4"     },
5601 #define DATA_SYNC4 1
5602         {       DATA_SYNC4,     "DATA_SYNC4"    },
5603 #define FILE_SYNC4 2
5604         {       FILE_SYNC4,     "FILE_SYNC4"    },
5605         {       0,      NULL    }
5606 };
5607
5608 static int
5609 dissect_nfs_stable_how4(tvbuff_t *tvb, int offset,
5610         proto_tree *tree, char *name)
5611 {
5612         guint stable_how4;
5613
5614         stable_how4 = tvb_get_ntohl(tvb, offset);
5615         proto_tree_add_uint_format(tree, hf_nfs_stable_how4, tvb,
5616                         offset+0, 4, stable_how4, "%s: %s (%u)", name,
5617                         val_to_str(stable_how4, names_stable_how4, "%u"), stable_how4);
5618         offset += 4;
5619
5620         return offset;
5621 }
5622
5623 static const value_string names_nfsv4_operation[] = {
5624         {       NFS4_OP_ACCESS,                                 "ACCESS"        },
5625         {       NFS4_OP_CLOSE,                                          "CLOSE" },
5626         {       NFS4_OP_COMMIT,                                 "COMMIT"        },
5627         {       NFS4_OP_CREATE,                                 "CREATE"        },
5628         {       NFS4_OP_DELEGPURGE,                             "DELEGPURGE"    },
5629         {       NFS4_OP_DELEGRETURN,                            "DELEGRETURN"   },
5630         {       NFS4_OP_GETATTR,                                        "GETATTR"       },
5631         {       NFS4_OP_GETFH,                                          "GETFH" },
5632         {       NFS4_OP_LINK,                                           "LINK"  },
5633         {       NFS4_OP_LOCK,                                           "LOCK"  },
5634         {       NFS4_OP_LOCKT,                                          "LOCKT" },
5635         {       NFS4_OP_LOCKU,                                          "LOCKU" },
5636         {       NFS4_OP_LOOKUP,                                 "LOOKUP"        },
5637         {       NFS4_OP_LOOKUPP,                                        "LOOKUPP" },
5638         {       NFS4_OP_NVERIFY,                                        "NVERIFY"       },
5639         {       NFS4_OP_OPEN,                                           "OPEN"  },
5640         {       NFS4_OP_OPENATTR,                                       "OPENATTR"      },
5641         {       NFS4_OP_OPEN_CONFIRM,                   "OPEN_CONFIRM"  },
5642         {       NFS4_OP_OPEN_DOWNGRADE,                 "OPEN_DOWNGRADE"        },
5643         {       NFS4_OP_PUTFH,                                          "PUTFH" },
5644         {       NFS4_OP_PUTPUBFH,                                       "PUTPUBFH"      },
5645         {       NFS4_OP_PUTROOTFH,                              "PUTROOTFH"     },
5646         {       NFS4_OP_READ,                                           "READ"  },
5647         {       NFS4_OP_READDIR,                                        "READDIR"       },
5648         {       NFS4_OP_READLINK,                                       "READLINK"      },
5649         {       NFS4_OP_REMOVE,                                 "REMOVE"        },
5650         {       NFS4_OP_RENAME,                                 "RENAME"        },
5651         {       NFS4_OP_RENEW,                                          "RENEW" },
5652         {       NFS4_OP_RESTOREFH,                              "RESTOREFH"     },
5653         {       NFS4_OP_SAVEFH,                                 "SAVEFH"        },
5654         {       NFS4_OP_SECINFO,                                        "SECINFO"       },
5655         {       NFS4_OP_SETATTR,                                        "SETATTR"       },
5656         {       NFS4_OP_SETCLIENTID,                            "SETCLIENTID"   },
5657         {       NFS4_OP_SETCLIENTID_CONFIRM,    "SETCLIENTID_CONFIRM"   },
5658         {       NFS4_OP_VERIFY,                                 "VERIFY"        },
5659         {       NFS4_OP_WRITE,                                          "WRITE" },
5660         { 0, NULL }
5661 };
5662
5663 gint *nfsv4_operation_ett[] =
5664 {
5665          &ett_nfs_access4 ,
5666          &ett_nfs_close4 ,
5667          &ett_nfs_commit4 ,
5668          &ett_nfs_create4 ,
5669          &ett_nfs_delegpurge4 ,
5670          &ett_nfs_delegreturn4 ,
5671          &ett_nfs_getattr4 ,
5672          &ett_nfs_getfh4 ,
5673          &ett_nfs_link4 ,
5674          &ett_nfs_lock4 ,
5675          &ett_nfs_lockt4 ,
5676          &ett_nfs_locku4 ,
5677          &ett_nfs_lookup4 ,
5678          &ett_nfs_lookupp4 ,
5679          &ett_nfs_nverify4 ,
5680          &ett_nfs_open4 ,
5681          &ett_nfs_openattr4 ,
5682          &ett_nfs_open_confirm4 ,
5683          &ett_nfs_open_downgrade4 ,
5684          &ett_nfs_putfh4 ,
5685          &ett_nfs_putpubfh4 ,
5686          &ett_nfs_putrootfh4 ,
5687          &ett_nfs_read4 ,
5688          &ett_nfs_readdir4 ,
5689          &ett_nfs_readlink4 ,
5690          &ett_nfs_remove4 ,
5691          &ett_nfs_rename4 ,
5692          &ett_nfs_renew4 ,
5693          &ett_nfs_restorefh4 ,
5694          &ett_nfs_savefh4 ,
5695          &ett_nfs_secinfo4 ,
5696          &ett_nfs_setattr4 ,
5697          &ett_nfs_setclientid4 ,
5698          &ett_nfs_setclientid_confirm4 ,
5699          &ett_nfs_verify4 ,
5700          &ett_nfs_write4 
5701 };
5702
5703 static int
5704 dissect_nfs_entry4(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
5705         proto_tree *tree)
5706 {
5707         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_cookie4, offset);
5708         offset = dissect_nfs_utf8string(tvb, offset, tree, hf_nfs_component4, NULL);
5709         offset = dissect_nfs_fattr4(tvb, offset, pinfo, tree);
5710
5711         return offset;
5712 }
5713
5714 static int
5715 dissect_nfs_dirlist4(tvbuff_t *tvb, int offset, packet_info *pinfo,
5716         proto_tree *tree)
5717 {
5718         proto_tree *newftree = NULL;
5719
5720         newftree = proto_item_add_subtree(tree, ett_nfs_dirlist4);
5721         if (newftree==NULL) return offset;
5722
5723         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_nfs_entry4);
5724         offset = dissect_rpc_bool(tvb, newftree, hf_nfs_dirlist4_eof, offset);
5725
5726         return offset;
5727 }
5728
5729 static int
5730 dissect_nfs_change_info4(tvbuff_t *tvb, int offset,
5731         proto_tree *tree, char *name)
5732 {
5733         proto_tree *newftree = NULL;
5734         proto_tree *fitem = NULL;
5735
5736         fitem = proto_tree_add_text(tree, tvb, offset, 0, "%s", name);
5737
5738         if (fitem) {
5739                 newftree = proto_item_add_subtree(fitem, ett_nfs_change_info4);
5740
5741                 if (newftree) {
5742                         offset = dissect_rpc_bool(tvb, newftree, 
5743                                 hf_nfs_change_info4_atomic, offset);
5744                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_changeid4_before, 
5745                                 offset);
5746                         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_changeid4_after, 
5747                                 offset);
5748                 }
5749         }
5750
5751         return offset;
5752 }
5753
5754 static const value_string names_nfs_lock_type4[] =
5755 {
5756 #define READ_LT 1
5757         {       READ_LT,                "READ_LT"                               },
5758 #define WRITE_LT 2
5759         {       WRITE_LT,               "WRITE_LT"                              },
5760 #define READW_LT 3
5761         {       READW_LT,       "READW_LT"      },
5762 #define WRITEW_LT 4
5763         {       WRITEW_LT,      "WRITEW_LT"     },
5764 #define RELEASE_STATE 5
5765         {       RELEASE_STATE,  "RELEASE_STATE" },
5766         {       0,      NULL    }
5767 };
5768
5769 static int
5770 dissect_nfs_lock4denied(tvbuff_t *tvb, int offset, proto_tree *tree)
5771 {
5772         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_offset4, offset);
5773         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_length4, offset);
5774         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_lock_type4, offset);
5775         offset = dissect_nfs_lock_owner4(tvb, offset, tree);
5776
5777         return offset;
5778 }
5779
5780
5781 static const value_string names_open4_result_flags[] = {
5782 #define OPEN4_RESULT_MLOCK 0x00000001
5783         { OPEN4_RESULT_MLOCK, "OPEN4_RESULT_MLOCK" }, 
5784 #define OPEN4_RESULT_CONFIRM 0x00000002
5785         { OPEN4_RESULT_CONFIRM, "OPEN4_RESULT_CONFIRM" },
5786         { 0, NULL }
5787 };
5788
5789 static int 
5790 dissect_nfs_open4_rflags(tvbuff_t *tvb, int offset,
5791         proto_tree *tree, char *name)
5792 {
5793         guint rflags;
5794         proto_item *rflags_item = NULL;
5795         proto_item *rflags_tree = NULL;
5796
5797         rflags = tvb_get_ntohl(tvb, offset);
5798
5799         if (tree)
5800         {
5801                 rflags_item = proto_tree_add_text(tree, tvb, offset, 4,
5802                         "%s: 0x%08x", name, rflags);
5803
5804                 if (rflags_item)
5805                 {
5806                         rflags_tree = proto_item_add_subtree(rflags_item, 
5807                                 ett_nfs_open4_result_flags);
5808
5809                         if (rflags_tree)
5810                         {
5811                                 proto_tree_add_text(rflags_tree, tvb, offset, 4, "%s",
5812                                         decode_enumerated_bitfield(rflags, OPEN4_RESULT_MLOCK, 2,
5813                                         names_open4_result_flags, "%s"));
5814
5815                                 proto_tree_add_text(rflags_tree, tvb, offset, 4, "%s",
5816                                         decode_enumerated_bitfield(rflags, OPEN4_RESULT_CONFIRM, 2,
5817                                         names_open4_result_flags, "%s"));
5818                         }
5819                 }
5820         }
5821         
5822         offset += 4;
5823
5824         return offset;
5825 }
5826
5827 static int
5828 dissect_nfs_stateid4(tvbuff_t *tvb, int offset,
5829                 proto_tree *tree)
5830 {
5831         proto_item *fitem = NULL;
5832         proto_tree *newftree = NULL;
5833         int sublen;
5834         int bytes_left;
5835         gboolean first_line;
5836
5837         fitem = proto_tree_add_text(tree, tvb, offset, 4, "stateid");
5838
5839         if (fitem) {
5840                 newftree = proto_item_add_subtree(fitem, ett_nfs_stateid4);
5841                 if (newftree) {
5842                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_seqid4, 
5843                                 offset);
5844
5845                         bytes_left = 12;
5846                         first_line = TRUE;
5847
5848                         while (bytes_left != 0)
5849                         {
5850                                 sublen = 12;
5851                                 if (sublen > bytes_left)
5852                                         sublen = bytes_left;
5853
5854                                 proto_tree_add_text(newftree, tvb, offset, sublen, "%s%s",
5855                                         first_line ? "other: " : "      ",
5856                                         tvb_bytes_to_str(tvb, offset, sublen));
5857
5858                                 bytes_left -= sublen;
5859                                 offset += sublen;
5860                                 first_line = FALSE;
5861                         }
5862                 }
5863         }
5864
5865         return offset;
5866 }
5867
5868 static int
5869 dissect_nfs_open_read_delegation4(tvbuff_t *tvb, int offset, 
5870         packet_info *pinfo, proto_tree *tree)
5871 {
5872         offset = dissect_nfs_stateid4(tvb, offset, tree);
5873         offset = dissect_rpc_bool(tvb, tree, hf_nfs_recall4, offset);
5874         offset = dissect_nfs_ace4(tvb, offset, pinfo, tree);
5875
5876         return offset;
5877 }
5878
5879 static int
5880 dissect_nfs_modified_limit4(tvbuff_t *tvb, int offset, proto_tree *tree)
5881 {
5882         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_num_blocks, offset);
5883         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_bytes_per_block, offset);
5884
5885         return offset;
5886 }
5887
5888 #define NFS_LIMIT_SIZE                                          1
5889 #define NFS_LIMIT_BLOCKS                                        2
5890 static const value_string names_limit_by4[] = {
5891         {       NFS_LIMIT_SIZE,  "NFS_LIMIT_SIZE"  },
5892         {       NFS_LIMIT_BLOCKS, "NFS_LIMIT_BLOCKS" },
5893         { 0, NULL }
5894 };
5895
5896 static int
5897 dissect_nfs_space_limit4(tvbuff_t *tvb, int offset,
5898         proto_tree *tree)
5899 {
5900         guint limitby;
5901
5902         limitby = tvb_get_ntohl(tvb, offset);
5903         proto_tree_add_uint(tree, hf_nfs_limit_by4, tvb, offset+0, 4, limitby);
5904         offset += 4;
5905
5906         switch(limitby)
5907         {
5908         case NFS_LIMIT_SIZE:
5909                 offset = dissect_rpc_uint64(tvb, tree, hf_nfs_filesize, 
5910                         offset);
5911                 break;
5912
5913         case NFS_LIMIT_BLOCKS:
5914                 offset = dissect_nfs_modified_limit4(tvb, offset, tree);
5915                 break;
5916
5917         default:
5918                 break;
5919         }
5920
5921         return offset;
5922 }
5923
5924 static int
5925 dissect_nfs_open_write_delegation4(tvbuff_t *tvb, int offset, 
5926         packet_info *pinfo, proto_tree *tree)
5927 {
5928         offset = dissect_nfs_stateid4(tvb, offset, tree);
5929         offset = dissect_rpc_bool(tvb, tree, hf_nfs_recall, offset);
5930         offset = dissect_nfs_space_limit4(tvb, offset, tree);
5931         offset = dissect_nfs_ace4(tvb, offset, pinfo, tree);
5932
5933         return offset;
5934 }
5935
5936 #define OPEN_DELEGATE_NONE 0
5937 #define OPEN_DELEGATE_READ 1
5938 #define OPEN_DELEGATE_WRITE 2
5939 static const value_string names_open_delegation_type4[] = {
5940         {       OPEN_DELEGATE_NONE,  "OPEN_DELEGATE_NONE"  },
5941         {       OPEN_DELEGATE_READ,     "OPEN_DELEGATE_READ" },
5942         {       OPEN_DELEGATE_WRITE,    "OPEN_DELEGATE_WRITE" },
5943         { 0, NULL }
5944 };
5945
5946 static int
5947 dissect_nfs_open_delegation4(tvbuff_t *tvb, int offset, packet_info *pinfo,
5948         proto_tree *tree)
5949 {
5950         guint delegation_type;
5951         proto_tree *newftree = NULL;
5952         proto_item *fitem = NULL;
5953
5954         delegation_type = tvb_get_ntohl(tvb, offset);
5955         proto_tree_add_uint(tree, hf_nfs_open_delegation_type4, tvb, offset+0, 
5956                 4, delegation_type);
5957         offset += 4;
5958
5959         if (fitem) {
5960                 newftree = proto_item_add_subtree(fitem, ett_nfs_open_delegation4);
5961
5962                 switch(delegation_type)
5963                 {
5964                 case OPEN_DELEGATE_NONE:
5965                         break;
5966
5967                 case OPEN_DELEGATE_READ:
5968                         offset = dissect_nfs_open_read_delegation4(tvb, offset, pinfo,
5969                                 newftree);
5970                         break;
5971
5972                 case OPEN_DELEGATE_WRITE:
5973                         offset = dissect_nfs_open_write_delegation4(tvb, offset, pinfo,
5974                                 newftree);
5975                         break;
5976
5977                 default:
5978                         break;
5979                 }
5980         }
5981
5982         return offset;
5983 }
5984
5985 static int
5986 dissect_nfs_rpcsec_gss_info(tvbuff_t *tvb, int offset, proto_tree *tree)
5987 {
5988         offset = dissect_nfsdata(tvb, offset, tree, hf_nfs_sec_oid4); 
5989         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_qop4, offset);
5990         offset = dissect_rpc_uint32(tvb, tree, 
5991                 hf_nfs_secinfo_rpcsec_gss_info_service, offset);
5992
5993         return offset;
5994 }
5995
5996 static int
5997 dissect_nfs_open_to_lock_owner4(tvbuff_t *tvb, int offset, proto_tree *tree)
5998 {
5999         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_seqid4, offset);
6000         offset = dissect_nfs_stateid4(tvb, offset, tree);
6001         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_lock_seqid4, offset);
6002         offset = dissect_nfs_lock_owner4(tvb, offset, tree);
6003
6004         return offset;
6005 }
6006
6007 static int
6008 dissect_nfs_exist_lock_owner4(tvbuff_t *tvb, int offset, proto_tree *tree)
6009 {
6010         offset = dissect_nfs_stateid4(tvb, offset, tree);
6011         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_lock_seqid4, offset);
6012
6013         return offset;
6014 }
6015
6016 static int
6017 dissect_nfs_locker4(tvbuff_t *tvb, int offset, proto_tree *tree)
6018 {
6019         guint new_lock_owner;
6020
6021         new_lock_owner = tvb_get_ntohl(tvb, offset);
6022         offset = dissect_rpc_bool(tvb, tree, hf_nfs_new_lock_owner, offset);
6023         
6024         if (new_lock_owner)
6025                 offset = dissect_nfs_open_to_lock_owner4(tvb, offset, tree);
6026         else
6027                 offset = dissect_nfs_exist_lock_owner4(tvb, offset, tree);
6028
6029         return offset;
6030 }
6031
6032 static int
6033 dissect_nfs_client_id4(tvbuff_t *tvb, int offset, proto_tree *tree)
6034 {
6035         offset = dissect_rpc_uint64(tvb, tree, hf_nfs_verifier4, offset);
6036         offset = dissect_rpc_data(tvb, tree, hf_nfs_client_id4_id, offset);
6037
6038         return offset;
6039 }
6040
6041 static int
6042 dissect_nfs_argop4(tvbuff_t *tvb, int offset, packet_info *pinfo, 
6043         proto_tree *tree)
6044 {
6045         guint32 ops, ops_counter;
6046         guint opcode;
6047         proto_item *fitem;
6048         proto_tree *ftree = NULL;
6049         proto_tree *newftree = NULL;
6050
6051         ops = tvb_get_ntohl(tvb, offset+0);
6052
6053         fitem = proto_tree_add_text(tree, tvb, offset, 4, 
6054                 "Operations (count: %u)", ops);
6055         offset += 4;
6056
6057         if (fitem == NULL) return offset;
6058
6059         ftree = proto_item_add_subtree(fitem, ett_nfs_argop4);
6060
6061         if (ftree == NULL) return offset;
6062
6063         for (ops_counter=0; ops_counter<ops; ops_counter++)
6064         {
6065                 opcode = tvb_get_ntohl(tvb, offset);
6066
6067                 fitem = proto_tree_add_uint(ftree, hf_nfs_argop4, tvb, offset, 4, 
6068                         opcode);
6069                 offset += 4;
6070
6071                 if (opcode < NFS4_OP_ACCESS || opcode > NFS4_OP_WRITE)
6072                         break;
6073
6074                 if (fitem == NULL)      break;
6075
6076                 newftree = proto_item_add_subtree(fitem, *nfsv4_operation_ett[opcode-3]);
6077                 if (newftree == NULL)   break;
6078
6079                 switch(opcode)
6080                 {
6081                 case NFS4_OP_ACCESS:
6082                         offset = dissect_access(tvb, offset, newftree, "access");
6083                         break;
6084
6085                 case NFS4_OP_CLOSE:
6086                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_seqid4,
6087                                 offset);
6088                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6089                         break;
6090
6091                 case NFS4_OP_COMMIT:
6092                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_offset4,
6093                                 offset);
6094                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_count4,
6095                                 offset);
6096                         break;
6097
6098                 case NFS4_OP_CREATE:
6099                         {
6100                                 guint create_type;
6101
6102                                 create_type = tvb_get_ntohl(tvb, offset);
6103                                 offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_ftype4, 
6104                                         offset);
6105
6106                                 switch(create_type)
6107                                 {
6108                                 case NF4LNK:
6109                                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6110                                                 hf_nfs_linktext4, NULL);
6111                                         break;
6112                                 
6113                                 case NF4BLK:
6114                                 case NF4CHR:
6115                                         offset = dissect_nfs_specdata4(tvb, offset, newftree);
6116                                         break;
6117
6118                                 case NF4SOCK:
6119                                 case NF4FIFO:
6120                                 case NF4DIR:
6121                                         break;
6122
6123                                 default:
6124                                         break;
6125                                 }
6126
6127                                 offset = dissect_nfs_utf8string(tvb, offset, newftree, hf_nfs_component4, NULL);
6128
6129                                 offset = dissect_nfs_fattr4(tvb, offset, pinfo, newftree);
6130                         }
6131                         break;
6132
6133                 case NFS4_OP_DELEGPURGE:
6134                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_clientid4, offset);
6135                         break;
6136
6137                 case NFS4_OP_DELEGRETURN:
6138                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6139                         break;
6140
6141                 case NFS4_OP_GETATTR:
6142                         offset = dissect_nfs_attributes(tvb, offset, pinfo, newftree, 
6143                                 FATTR4_BITMAP_ONLY);
6144                         break;
6145
6146                 case NFS4_OP_GETFH:
6147                         break;
6148
6149                 case NFS4_OP_LINK:
6150                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6151                                 hf_nfs_component4, NULL);
6152                         break;
6153
6154                 case NFS4_OP_LOCK:
6155                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_lock_type4, offset);
6156                         offset = dissect_rpc_bool(tvb, newftree, hf_nfs_lock4_reclaim, offset);
6157                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_offset4, offset);
6158                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_length4, offset);
6159                         offset = dissect_nfs_locker4(tvb, offset, newftree);
6160                         break;
6161
6162                 case NFS4_OP_LOCKT:
6163                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_lock_type4, offset);
6164                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_offset4, offset);
6165                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_length4, offset);
6166                         offset = dissect_nfs_lock_owner4(tvb, offset, newftree);
6167                         break;
6168
6169                 case NFS4_OP_LOCKU:
6170                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_lock_type4, offset);
6171                         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_seqid4, offset);
6172                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6173                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_offset4, offset);
6174                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_length4, offset);
6175                         break;
6176
6177                 case NFS4_OP_LOOKUP:
6178                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6179                                 hf_nfs_component4, NULL);
6180                         break;
6181
6182                 case NFS4_OP_LOOKUPP:
6183                         break;
6184
6185                 case NFS4_OP_NVERIFY:
6186                         offset = dissect_nfs_fattr4(tvb, offset, pinfo, newftree);
6187                         break;
6188
6189                 case NFS4_OP_OPEN:
6190                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_seqid4, 
6191                                 offset);
6192                         offset = dissect_nfs_open4_share_access(tvb, offset, newftree);
6193                         offset = dissect_nfs_open4_share_deny(tvb, offset, newftree);
6194                         offset = dissect_nfs_open_owner4(tvb, offset, newftree);
6195                         offset = dissect_nfs_openflag4(tvb, offset, pinfo, newftree);
6196                         offset = dissect_nfs_open_claim4(tvb, offset, newftree);
6197                         break;
6198
6199                 case NFS4_OP_OPENATTR:
6200                         offset = dissect_rpc_bool(tvb, newftree, hf_nfs_attrdircreate,
6201                                 offset);
6202                         break;
6203
6204                 case NFS4_OP_OPEN_CONFIRM:
6205                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6206                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_seqid4, 
6207                                 offset);
6208                         break;
6209
6210                 case NFS4_OP_OPEN_DOWNGRADE:
6211                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6212                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_seqid4, 
6213                                 offset);
6214                         offset = dissect_nfs_open4_share_access(tvb, offset, newftree);
6215                         offset = dissect_nfs_open4_share_deny(tvb, offset, newftree);
6216                         break;
6217
6218                 case NFS4_OP_PUTFH:
6219                         offset = dissect_nfs_fh4(tvb, offset, pinfo, newftree, "filehandle");
6220                         break;
6221
6222                 case NFS4_OP_PUTPUBFH:
6223                 case NFS4_OP_PUTROOTFH:
6224                         break;
6225
6226                 case NFS4_OP_READ:
6227                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6228                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_offset4,
6229                                 offset);
6230                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_count4,
6231                                 offset);
6232                         break;
6233
6234                 case NFS4_OP_READDIR:
6235                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_cookie4,
6236                                 offset);
6237                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_cookieverf4,
6238                                 offset);
6239                         offset = dissect_rpc_uint32(tvb, newftree, 
6240                                 hf_nfs_count4_dircount, offset);
6241                         offset = dissect_rpc_uint32(tvb, newftree,
6242                                 hf_nfs_count4_maxcount, offset);
6243                         offset = dissect_nfs_attributes(tvb, offset, pinfo, newftree, 
6244                                 FATTR4_BITMAP_ONLY);
6245                         break;
6246
6247                 case NFS4_OP_READLINK:
6248                         break;
6249
6250                 case NFS4_OP_REMOVE:
6251                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6252                                 hf_nfs_component4, NULL);
6253                         break;
6254
6255                 case NFS4_OP_RENAME:
6256                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6257                                 hf_nfs_component4, NULL);
6258                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6259                                 hf_nfs_component4, NULL);
6260                         break;
6261
6262                 case NFS4_OP_RENEW:
6263                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_clientid4, offset);
6264                         break;
6265         
6266                 case NFS4_OP_RESTOREFH:
6267                 case NFS4_OP_SAVEFH:
6268                         break;
6269
6270                 case NFS4_OP_SECINFO:
6271                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6272                                 hf_nfs_component4, NULL);
6273                         break;
6274
6275                 case NFS4_OP_SETATTR:
6276                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6277                         offset = dissect_nfs_fattr4(tvb, offset, pinfo, newftree);
6278                         break;
6279
6280                 case NFS4_OP_SETCLIENTID:
6281                         {
6282                                 proto_tree *client_tree = NULL;
6283                                 proto_tree *callback_tree = NULL;
6284
6285                                 fitem = proto_tree_add_text(newftree, tvb, offset, 0, "client");
6286                                 if (fitem)
6287                                 {
6288                                         client_tree = proto_item_add_subtree(fitem, ett_nfs_client_id4);
6289
6290                                         if (client_tree)
6291                                                 offset = dissect_nfs_client_id4(tvb, offset, client_tree);
6292                                 }
6293
6294                                 fitem = proto_tree_add_text(newftree, tvb, offset, 0, "callback");
6295                                 if (fitem) 
6296                                 {
6297                                         callback_tree = proto_item_add_subtree(fitem, 
6298                                                 ett_nfs_cb_client4);
6299
6300                                         if (callback_tree)
6301                                                 offset = dissect_nfs_cb_client4(tvb, offset, callback_tree);
6302                                 }
6303
6304                                 offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_callback_ident, 
6305                                         offset);
6306                         }
6307                         break;
6308
6309                 case NFS4_OP_SETCLIENTID_CONFIRM:
6310                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_clientid4, offset);
6311                         break;
6312                 
6313                 case NFS4_OP_VERIFY:
6314                         offset = dissect_nfs_fattr4(tvb, offset, pinfo, newftree);
6315                         break;
6316
6317                 case NFS4_OP_WRITE:
6318                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6319                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_offset4, offset);
6320                         offset = dissect_nfs_stable_how4(tvb, offset, newftree, "stable");
6321                         offset = dissect_nfsdata(tvb, offset, newftree, hf_nfs_data);
6322                         break;
6323                 
6324                 default:
6325                         break;
6326                 }
6327         }
6328
6329         return offset;
6330 }
6331
6332 static int
6333 dissect_nfs4_compound_call(tvbuff_t *tvb, int offset, packet_info *pinfo, 
6334         proto_tree* tree)
6335 {
6336         offset = dissect_nfs_utf8string(tvb, offset, tree, hf_nfs_tag4, NULL);
6337         offset = dissect_rpc_uint32(tvb, tree, hf_nfs_minorversion, offset);
6338         offset = dissect_nfs_argop4(tvb, offset, pinfo, tree);
6339
6340         return offset;
6341 }
6342
6343 static int
6344 dissect_nfs_secinfo4_res(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
6345         proto_tree *tree)
6346 {
6347         guint flavor;
6348         proto_item *fitem;
6349         proto_tree *secftree;
6350                                 
6351         flavor = tvb_get_ntohl(tvb, offset);
6352         fitem = proto_tree_add_uint(tree, hf_nfs_secinfo_flavor, tvb, offset, 4, 
6353                 flavor);
6354         offset += 4;
6355
6356         if (fitem) 
6357         {
6358                 switch(flavor)
6359                 {
6360                 case RPCSEC_GSS:
6361                         secftree = proto_item_add_subtree(fitem, ett_nfs_secinfo4_flavor_info);
6362                         if (secftree)
6363                                 offset = dissect_nfs_rpcsec_gss_info(tvb, offset, secftree);
6364                         break;
6365
6366                 default:
6367                         break;
6368                 }
6369         }
6370
6371         return offset;
6372 }
6373
6374 static int
6375 dissect_nfs_resop4(tvbuff_t *tvb, int offset, packet_info *pinfo, 
6376         proto_tree *tree)
6377 {
6378         guint32 ops, ops_counter;
6379         guint32 opcode;
6380         proto_item *fitem;
6381         proto_tree *ftree = NULL;
6382         proto_tree *newftree = NULL;
6383         guint32 status;
6384
6385         ops = tvb_get_ntohl(tvb, offset+0);
6386
6387         fitem = proto_tree_add_text(tree, tvb, offset, 4, 
6388                 "Operations (count: %u)", ops);
6389         offset += 4;
6390
6391         if (fitem == NULL)      return offset;
6392
6393         ftree = proto_item_add_subtree(fitem, ett_nfs_resop4);
6394
6395         if (ftree == NULL)      return offset;          /* error adding new subtree */
6396
6397         for (ops_counter = 0; ops_counter < ops; ops_counter++)
6398         {
6399                 opcode = tvb_get_ntohl(tvb, offset);
6400
6401                 /* sanity check for bogus packets */
6402                 if (opcode < NFS4_OP_ACCESS || opcode > NFS4_OP_WRITE)  break;
6403
6404                 fitem = proto_tree_add_uint(ftree, hf_nfs_resop4, tvb, offset, 4, 
6405                         opcode);
6406                 offset += 4;
6407
6408                 if (fitem == NULL)      break;          /* error adding new item to tree */
6409
6410                 newftree = proto_item_add_subtree(fitem, *nfsv4_operation_ett[opcode-3]);
6411
6412                 if (newftree == NULL)
6413                         break;          /* error adding new subtree to operation item */
6414
6415                 offset = dissect_nfs_nfsstat4(tvb, offset, newftree, &status);
6416
6417                 /*
6418                  * With the exception of NFS4_OP_LOCK, NFS4_OP_LOCKT, and 
6419                  * NFS4_OP_SETATTR, all other ops do *not* return data with the
6420                  * failed status code.
6421                  */
6422                 if ((status != NFS4_OK) &&
6423                         ((opcode != NFS4_OP_LOCK) && (opcode != NFS4_OP_LOCKT) &&
6424                         (opcode != NFS4_OP_SETATTR)))
6425                         continue;
6426
6427                 /* These parsing routines are only executed if the status is NFS4_OK */
6428                 switch(opcode)
6429                 {
6430                 case NFS4_OP_ACCESS:
6431                         offset = dissect_access(tvb, offset, newftree, "Supported");
6432                         offset = dissect_access(tvb, offset, newftree, "Access");
6433                         break;
6434
6435                 case NFS4_OP_CLOSE:
6436                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6437                         break;
6438
6439                 case NFS4_OP_COMMIT:
6440                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_verifier4, 
6441                                 offset);
6442                         break;
6443
6444                 case NFS4_OP_CREATE:
6445                         offset = dissect_nfs_change_info4(tvb, offset, newftree, 
6446                                 "change_info");
6447                         offset = dissect_nfs_attributes(tvb, offset, pinfo, newftree,
6448                                 FATTR4_BITMAP_ONLY);
6449                         break;
6450
6451                 case NFS4_OP_GETATTR:
6452                         offset = dissect_nfs_fattr4(tvb, offset, pinfo, newftree);
6453                         break;
6454
6455                 case NFS4_OP_GETFH:
6456                         offset = dissect_nfs_fh4(tvb, offset, pinfo, newftree, "Filehandle");
6457                         break;
6458
6459                 case NFS4_OP_LINK:
6460                         offset = dissect_nfs_change_info4(tvb, offset, newftree, 
6461                                 "change_info");
6462                         break;
6463
6464                 case NFS4_OP_LOCK:
6465                 case NFS4_OP_LOCKT:
6466                         if (status == NFS4_OK)
6467                         {
6468                                 if (opcode == NFS4_OP_LOCK)
6469                                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6470                         }
6471                         else
6472                         if (status == NFS4ERR_DENIED)
6473                                 offset = dissect_nfs_lock4denied(tvb, offset, newftree);
6474                         break;
6475
6476                 case NFS4_OP_LOCKU:
6477                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6478                         break;
6479
6480                 case NFS4_OP_OPEN:
6481                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6482                         offset = dissect_nfs_change_info4(tvb, offset, newftree, 
6483                                 "change_info");
6484                         offset = dissect_nfs_open4_rflags(tvb, offset, newftree, 
6485                                 "result_flags");
6486                         offset = dissect_nfs_attributes(tvb, offset, pinfo, newftree, 
6487                                 FATTR4_BITMAP_ONLY);
6488                         offset = dissect_nfs_open_delegation4(tvb, offset, pinfo, newftree);
6489                         break;
6490
6491                 case NFS4_OP_OPEN_CONFIRM:
6492                 case NFS4_OP_OPEN_DOWNGRADE:
6493                         offset = dissect_nfs_stateid4(tvb, offset, newftree);
6494                         break;
6495
6496                 case NFS4_OP_READ:
6497                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_eof, offset);
6498                         offset = dissect_nfsdata(tvb, offset, newftree, hf_nfs_data);
6499                         break;
6500
6501                 case NFS4_OP_READDIR:
6502                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_verifier4, offset);
6503                         offset = dissect_nfs_dirlist4(tvb, offset, pinfo, newftree);
6504                         break;
6505
6506                 case NFS4_OP_READLINK:
6507                         offset = dissect_nfs_utf8string(tvb, offset, newftree, 
6508                                 hf_nfs_linktext4, NULL);
6509                         break;
6510
6511                 case NFS4_OP_REMOVE:
6512                         offset = dissect_nfs_change_info4(tvb, offset, newftree, 
6513                                 "change_info");
6514                         break;
6515
6516                 case NFS4_OP_RENAME:
6517                         offset = dissect_nfs_change_info4(tvb, offset, newftree, 
6518                                 "source_cinfo");
6519                         offset = dissect_nfs_change_info4(tvb, offset, newftree,
6520                                 "target_cinfo");
6521                         break;
6522
6523                 case NFS4_OP_SECINFO:
6524                         offset = dissect_rpc_list(tvb, pinfo, tree, offset, 
6525                                 dissect_nfs_secinfo4_res);
6526                         break;
6527
6528                 case NFS4_OP_SETATTR:
6529                         offset = dissect_nfs_attributes(tvb, offset, pinfo, newftree, 
6530                                 FATTR4_BITMAP_ONLY);
6531                         break;
6532
6533                 case NFS4_OP_SETCLIENTID:
6534                         if (status == NFS4_OK)
6535                                 offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_clientid4, 
6536                                         offset);
6537                         else
6538                         if (status == NFS4ERR_CLID_INUSE)
6539                                 offset = dissect_nfs_clientaddr4(tvb, offset, newftree);
6540                         break;
6541
6542                 case NFS4_OP_WRITE:
6543                         offset = dissect_rpc_uint32(tvb, newftree, hf_nfs_count4,
6544                                 offset);
6545                         offset = dissect_nfs_stable_how4(tvb, offset, newftree, 
6546                                 "committed");
6547                         offset = dissect_rpc_uint64(tvb, newftree, hf_nfs_verifier4, 
6548                                 offset);
6549                         break;
6550
6551                 default:
6552                         break;
6553                 }
6554         }
6555
6556         return offset;
6557 }
6558
6559 static int
6560 dissect_nfs4_compound_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
6561         proto_tree* tree)
6562 {
6563         guint32 status;
6564
6565         offset = dissect_nfs_nfsstat4(tvb, offset, tree, &status);
6566         offset = dissect_nfs_utf8string(tvb, offset, tree, hf_nfs_tag4, NULL);
6567         offset = dissect_nfs_resop4(tvb, offset, pinfo, tree);
6568
6569         return offset;
6570 }
6571
6572
6573 /* proc number, "proc name", dissect_request, dissect_reply */
6574 /* NULL as function pointer means: type of arguments is "void". */
6575 static const vsff nfs3_proc[] = {
6576         { 0,    "NULL",         /* OK */
6577         NULL,                           NULL },
6578         { 1,    "GETATTR",      /* OK */
6579         dissect_nfs3_getattr_call,      dissect_nfs3_getattr_reply },
6580         { 2,    "SETATTR",      /* OK */
6581         dissect_nfs3_setattr_call,      dissect_nfs3_setattr_reply },
6582         { 3,    "LOOKUP",       /* OK */
6583         dissect_nfs3_lookup_call,       dissect_nfs3_lookup_reply },
6584         { 4,    "ACCESS",       /* OK */
6585         dissect_nfs3_access_call,       dissect_nfs3_access_reply },
6586         { 5,    "READLINK",     /* OK */
6587         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_readlink_reply },
6588         { 6,    "READ",         /* OK */
6589         dissect_nfs3_read_call,         dissect_nfs3_read_reply },
6590         { 7,    "WRITE",        /* OK */
6591         dissect_nfs3_write_call,        dissect_nfs3_write_reply },
6592         { 8,    "CREATE",       /* OK */
6593         dissect_nfs3_create_call,       dissect_nfs3_create_reply },
6594         { 9,    "MKDIR",        /* OK */
6595         dissect_nfs3_mkdir_call,        dissect_nfs3_create_reply },
6596         { 10,   "SYMLINK",      /* OK */
6597         dissect_nfs3_symlink_call,      dissect_nfs3_create_reply },
6598         { 11,   "MKNOD",        /* OK */
6599         dissect_nfs3_mknod_call,        dissect_nfs3_create_reply },
6600         { 12,   "REMOVE",       /* OK */
6601         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
6602         { 13,   "RMDIR",        /* OK */
6603         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
6604         { 14,   "RENAME",       /* OK */
6605         dissect_nfs3_rename_call,       dissect_nfs3_rename_reply },
6606         { 15,   "LINK",         /* OK */
6607         dissect_nfs3_link_call,         dissect_nfs3_link_reply },
6608         { 16,   "READDIR",      /* OK */
6609         dissect_nfs3_readdir_call,      dissect_nfs3_readdir_reply },
6610         { 17,   "READDIRPLUS",  /* OK */
6611         dissect_nfs3_readdirplus_call,  dissect_nfs3_readdirplus_reply },
6612         { 18,   "FSSTAT",       /* OK */
6613         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsstat_reply },
6614         { 19,   "FSINFO",       /* OK */
6615         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsinfo_reply },
6616         { 20,   "PATHCONF",     /* OK */
6617         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_pathconf_reply },
6618         { 21,   "COMMIT",       /* OK */
6619         dissect_nfs3_commit_call,       dissect_nfs3_commit_reply },
6620         { 0,NULL,NULL,NULL }
6621 };
6622 /* end of NFS Version 3 */
6623
6624 static const vsff nfs4_proc[] = {
6625         { 0, "NULL",
6626         NULL, NULL },
6627         { 1, "COMPOUND",
6628         dissect_nfs4_compound_call, dissect_nfs4_compound_reply },
6629         { 0, NULL, NULL, NULL }
6630 };
6631
6632
6633 static struct true_false_string yesno = { "Yes", "No" };
6634
6635
6636 void
6637 proto_register_nfs(void)
6638 {
6639         static hf_register_info hf[] = {
6640                 { &hf_nfs_fh_length, {
6641                         "length", "nfs.fh.length", FT_UINT32, BASE_DEC,
6642                         NULL, 0, "file handle length", HFILL }},
6643                 { &hf_nfs_fh_hash, {
6644                         "hash", "nfs.fh.hash", FT_UINT32, BASE_HEX,
6645                         NULL, 0, "file handle hash", HFILL }},
6646                 { &hf_nfs_fh_fsid_major, {
6647                         "major", "nfs.fh.fsid.major", FT_UINT32, BASE_DEC,
6648                         NULL, 0, "major file system ID", HFILL }},
6649                 { &hf_nfs_fh_fsid_minor, {
6650                         "minor", "nfs.fh.fsid.minor", FT_UINT32, BASE_DEC,
6651                         NULL, 0, "minor file system ID", HFILL }},
6652                 { &hf_nfs_fh_fsid_inode, {
6653                         "inode", "nfs.fh.fsid.inode", FT_UINT32, BASE_DEC,
6654                         NULL, 0, "file system inode", HFILL }},
6655                 { &hf_nfs_fh_xfsid_major, {
6656                         "exported major", "nfs.fh.xfsid.major", FT_UINT32, BASE_DEC,
6657                         NULL, 0, "exported major file system ID", HFILL }},
6658                 { &hf_nfs_fh_xfsid_minor, {
6659                         "exported minor", "nfs.fh.xfsid.minor", FT_UINT32, BASE_DEC,
6660                         NULL, 0, "exported minor file system ID", HFILL }},
6661                 { &hf_nfs_fh_fstype, {
6662                         "file system type", "nfs.fh.fstype", FT_UINT32, BASE_DEC,
6663                         NULL, 0, "file system type", HFILL }},
6664                 { &hf_nfs_fh_fn, {
6665                         "file number", "nfs.fh.fn", FT_UINT32, BASE_DEC,
6666                         NULL, 0, "file number", HFILL }},
6667                 { &hf_nfs_fh_fn_len, {
6668                         "length", "nfs.fh.fn.len", FT_UINT32, BASE_DEC,
6669                         NULL, 0, "file number length", HFILL }},
6670                 { &hf_nfs_fh_fn_inode, {
6671                         "inode", "nfs.fh.fn.inode", FT_UINT32, BASE_DEC,
6672                         NULL, 0, "file number inode", HFILL }},
6673                 { &hf_nfs_fh_fn_generation, {
6674                         "generation", "nfs.fh.fn.generation", FT_UINT32, BASE_DEC,
6675                         NULL, 0, "file number generation", HFILL }},
6676                 { &hf_nfs_fh_xfn, {
6677                         "exported file number", "nfs.fh.xfn", FT_UINT32, BASE_DEC,
6678                         NULL, 0, "exported file number", HFILL }},
6679                 { &hf_nfs_fh_xfn_len, {
6680                         "length", "nfs.fh.xfn.len", FT_UINT32, BASE_DEC,
6681                         NULL, 0, "exported file number length", HFILL }},
6682                 { &hf_nfs_fh_xfn_inode, {
6683                         "exported inode", "nfs.fh.xfn.inode", FT_UINT32, BASE_DEC,
6684                         NULL, 0, "exported file number inode", HFILL }},
6685                 { &hf_nfs_fh_xfn_generation, {
6686                         "generation", "nfs.fh.xfn.generation", FT_UINT32, BASE_DEC,
6687                         NULL, 0, "exported file number generation", HFILL }},
6688                 { &hf_nfs_fh_dentry, {
6689                         "dentry", "nfs.fh.dentry", FT_UINT32, BASE_HEX,
6690                         NULL, 0, "dentry (cookie)", HFILL }},
6691                 { &hf_nfs_fh_dev, {
6692                         "device", "nfs.fh.dev", FT_UINT32, BASE_DEC,
6693                         NULL, 0, "device", HFILL }},
6694                 { &hf_nfs_fh_xdev, {
6695                         "exported device", "nfs.fh.xdev", FT_UINT32, BASE_DEC,
6696                         NULL, 0, "exported device", HFILL }},
6697                 { &hf_nfs_fh_dirinode, {
6698                         "directory inode", "nfs.fh.dirinode", FT_UINT32, BASE_DEC,
6699                         NULL, 0, "directory inode", HFILL }},
6700                 { &hf_nfs_fh_pinode, {
6701                         "pseudo inode", "nfs.fh.pinode", FT_UINT32, BASE_HEX,
6702                         NULL, 0, "pseudo inode", HFILL }},
6703                 { &hf_nfs_fh_hp_len, {
6704                         "length", "nfs.fh.hp.len", FT_UINT32, BASE_DEC,
6705                         NULL, 0, "hash path length", HFILL }},
6706                 { &hf_nfs_fh_version, {
6707                         "version", "nfs.fh.version", FT_UINT8, BASE_DEC,
6708                         NULL, 0, "file handle layout version", HFILL }},
6709                 { &hf_nfs_fh_auth_type, {
6710                         "auth_type", "nfs.fh.auth_type", FT_UINT8, BASE_DEC,
6711                         VALS(auth_type_names), 0, "authentication type", HFILL }},
6712                 { &hf_nfs_fh_fsid_type, {
6713                         "fsid_type", "nfs.fh.fsid_type", FT_UINT8, BASE_DEC,
6714                         VALS(fsid_type_names), 0, "file system ID type", HFILL }},
6715                 { &hf_nfs_fh_fileid_type, {
6716                         "fileid_type", "nfs.fh.fileid_type", FT_UINT8, BASE_DEC,
6717                         VALS(fileid_type_names), 0, "file ID type", HFILL }},
6718                 { &hf_nfs_stat, {
6719                         "Status", "nfs.status2", FT_UINT32, BASE_DEC,
6720                         VALS(names_nfs_stat), 0, "Reply status", HFILL }},
6721                 { &hf_nfs_full_name, {
6722                         "Full Name", "nfs.full_name", FT_STRING, BASE_DEC,
6723                         NULL, 0, "Full Name", HFILL }},
6724                 { &hf_nfs_name, {
6725                         "Name", "nfs.name", FT_STRING, BASE_DEC,
6726                         NULL, 0, "Name", HFILL }},
6727                 { &hf_nfs_readlink_data, {
6728                         "Data", "nfs.readlink.data", FT_STRING, BASE_DEC,
6729                         NULL, 0, "Symbolic Link Data", HFILL }},
6730                 { &hf_nfs_read_offset, {
6731                         "Offset", "nfs.read.offset", FT_UINT32, BASE_DEC,
6732                         NULL, 0, "Read Offset", HFILL }},
6733                 { &hf_nfs_read_count, {
6734                         "Count", "nfs.read.count", FT_UINT32, BASE_DEC,
6735                         NULL, 0, "Read Count", HFILL }},
6736                 { &hf_nfs_read_totalcount, {
6737                         "Total Count", "nfs.read.totalcount", FT_UINT32, BASE_DEC,
6738                         NULL, 0, "Total Count (obsolete)", HFILL }},
6739                 { &hf_nfs_data, {
6740                         "Data", "nfs.data", FT_BYTES, BASE_DEC,
6741                         NULL, 0, "Data", HFILL }},
6742                 { &hf_nfs_write_beginoffset, {
6743                         "Begin Offset", "nfs.write.beginoffset", FT_UINT32, BASE_DEC,
6744                         NULL, 0, "Begin offset (obsolete)", HFILL }},
6745                 { &hf_nfs_write_offset, {
6746                         "Offset", "nfs.write.offset", FT_UINT32, BASE_DEC,
6747                         NULL, 0, "Offset", HFILL }},
6748                 { &hf_nfs_write_totalcount, {
6749                         "Total Count", "nfs.write.totalcount", FT_UINT32, BASE_DEC,
6750                         NULL, 0, "Total Count (obsolete)", HFILL }},
6751                 { &hf_nfs_symlink_to, {
6752                         "To", "nfs.symlink.to", FT_STRING, BASE_DEC,
6753                         NULL, 0, "Symbolic link destination name", HFILL }},
6754                 { &hf_nfs_readdir_cookie, {
6755                         "Cookie", "nfs.readdir.cookie", FT_UINT32, BASE_DEC,
6756                         NULL, 0, "Directory Cookie", HFILL }},
6757                 { &hf_nfs_readdir_count, {
6758                         "Count", "nfs.readdir.count", FT_UINT32, BASE_DEC,
6759                         NULL, 0, "Directory Count", HFILL }},
6760
6761                 { &hf_nfs_readdir_entry, {
6762                         "Entry", "nfs.readdir.entry", FT_NONE, 0,
6763                         NULL, 0, "Directory Entry", HFILL }},
6764
6765                 { &hf_nfs_readdir_entry_fileid, {
6766                         "File ID", "nfs.readdir.entry.fileid", FT_UINT32, BASE_DEC,
6767                         NULL, 0, "File ID", HFILL }},
6768
6769                 { &hf_nfs_readdir_entry_name, {
6770                         "Name", "nfs.readdir.entry.name", FT_STRING, BASE_DEC,
6771                         NULL, 0, "Name", HFILL }},
6772
6773                 { &hf_nfs_readdir_entry_cookie, {
6774                         "Cookie", "nfs.readdir.entry.cookie", FT_UINT32, BASE_DEC,
6775                         NULL, 0, "Directory Cookie", HFILL }},
6776
6777                 { &hf_nfs_readdir_entry3_fileid, {
6778                         "File ID", "nfs.readdir.entry3.fileid", FT_UINT64, BASE_DEC,
6779                         NULL, 0, "File ID", HFILL }},
6780
6781                 { &hf_nfs_readdir_entry3_name, {
6782                         "Name", "nfs.readdir.entry3.name", FT_STRING, BASE_DEC,
6783                         NULL, 0, "Name", HFILL }},
6784
6785                 { &hf_nfs_readdir_entry3_cookie, {
6786                         "Cookie", "nfs.readdir.entry3.cookie", FT_UINT64, BASE_DEC,
6787                         NULL, 0, "Directory Cookie", HFILL }},
6788
6789                 { &hf_nfs_readdirplus_entry_fileid, {
6790                         "File ID", "nfs.readdirplus.entry.fileid", FT_UINT64, BASE_DEC,
6791                         NULL, 0, "Name", HFILL }},
6792
6793                 { &hf_nfs_readdirplus_entry_name, {
6794                         "Name", "nfs.readdirplus.entry.name", FT_STRING, BASE_DEC,
6795                         NULL, 0, "Name", HFILL }},
6796
6797                 { &hf_nfs_readdirplus_entry_cookie, {
6798                         "Cookie", "nfs.readdirplus.entry.cookie", FT_UINT64, BASE_DEC,
6799                         NULL, 0, "Directory Cookie", HFILL }},
6800
6801                 { &hf_nfs_readdir_eof, {
6802                         "EOF", "nfs.readdir.eof", FT_UINT32, BASE_DEC,
6803                         NULL, 0, "EOF", HFILL }},
6804
6805                 { &hf_nfs_statfs_tsize, {
6806                         "Transfer Size", "nfs.statfs.tsize", FT_UINT32, BASE_DEC,
6807                         NULL, 0, "Transfer Size", HFILL }},
6808                 { &hf_nfs_statfs_bsize, {
6809                         "Block Size", "nfs.statfs.bsize", FT_UINT32, BASE_DEC,
6810                         NULL, 0, "Block Size", HFILL }},
6811                 { &hf_nfs_statfs_blocks, {
6812                         "Total Blocks", "nfs.statfs.blocks", FT_UINT32, BASE_DEC,
6813                         NULL, 0, "Total Blocks", HFILL }},
6814                 { &hf_nfs_statfs_bfree, {
6815                         "Free Blocks", "nfs.statfs.bfree", FT_UINT32, BASE_DEC,
6816                         NULL, 0, "Free Blocks", HFILL }},
6817                 { &hf_nfs_statfs_bavail, {
6818                         "Available Blocks", "nfs.statfs.bavail", FT_UINT32, BASE_DEC,
6819                         NULL, 0, "Available Blocks", HFILL }},
6820                 { &hf_nfs_ftype3, {
6821                         "Type", "nfs.type", FT_UINT32, BASE_DEC,
6822                         VALS(names_nfs_ftype3), 0, "File Type", HFILL }},
6823                 { &hf_nfs_nfsstat3, {
6824                         "Status", "nfs.status", FT_UINT32, BASE_DEC,
6825                         VALS(names_nfs_nfsstat3), 0, "Reply status", HFILL }},
6826                 { &hf_nfs_read_eof, {
6827                         "EOF", "nfs.read.eof", FT_BOOLEAN, BASE_NONE,
6828                         &yesno, 0, "EOF", HFILL }},
6829                 { &hf_nfs_write_stable, {
6830                         "Stable", "nfs.write.stable", FT_UINT32, BASE_DEC,
6831                         VALS(names_stable_how), 0, "Stable", HFILL }},
6832                 { &hf_nfs_write_committed, {
6833                         "Committed", "nfs.write.committed", FT_UINT32, BASE_DEC,
6834                         VALS(names_stable_how), 0, "Committed", HFILL }},
6835                 { &hf_nfs_createmode3, {
6836                         "Create Mode", "nfs.createmode", FT_UINT32, BASE_DEC,
6837                         VALS(names_createmode3), 0, "Create Mode", HFILL }},
6838                 { &hf_nfs_fsstat_invarsec, {
6839                         "invarsec", "nfs.fsstat.invarsec", FT_UINT32, BASE_DEC,
6840                         NULL, 0, "probable number of seconds of file system invariance", HFILL }},
6841                 { &hf_nfs_fsinfo_rtmax, {
6842                         "rtmax", "nfs.fsinfo.rtmax", FT_UINT32, BASE_DEC,
6843                         NULL, 0, "maximum READ request", HFILL }},
6844                 { &hf_nfs_fsinfo_rtpref, {
6845                         "rtpref", "nfs.fsinfo.rtpref", FT_UINT32, BASE_DEC,
6846                         NULL, 0, "Preferred READ request size", HFILL }},
6847                 { &hf_nfs_fsinfo_rtmult, {
6848                         "rtmult", "nfs.fsinfo.rtmult", FT_UINT32, BASE_DEC,
6849                         NULL, 0, "Suggested READ multiple", HFILL }},
6850                 { &hf_nfs_fsinfo_wtmax, {
6851                         "wtmax", "nfs.fsinfo.wtmax", FT_UINT32, BASE_DEC,
6852                         NULL, 0, "Maximum WRITE request size", HFILL }},
6853                 { &hf_nfs_fsinfo_wtpref, {
6854                         "wtpref", "nfs.fsinfo.wtpref", FT_UINT32, BASE_DEC,
6855                         NULL, 0, "Preferred WRITE request size", HFILL }},
6856                 { &hf_nfs_fsinfo_wtmult, {
6857                         "wtmult", "nfs.fsinfo.wtmult", FT_UINT32, BASE_DEC,
6858                         NULL, 0, "Suggested WRITE multiple", HFILL }},
6859                 { &hf_nfs_fsinfo_dtpref, {
6860                         "dtpref", "nfs.fsinfo.dtpref", FT_UINT32, BASE_DEC,
6861                         NULL, 0, "Preferred READDIR request", HFILL }},
6862                 { &hf_nfs_fsinfo_maxfilesize, {
6863                         "maxfilesize", "nfs.fsinfo.maxfilesize", FT_UINT64, BASE_DEC,
6864                         NULL, 0, "Maximum file size", HFILL }},
6865                 { &hf_nfs_fsinfo_properties, {
6866                         "Properties", "nfs.fsinfo.propeties", FT_UINT32, BASE_HEX,
6867                         NULL, 0, "File System Properties", HFILL }},
6868                 { &hf_nfs_pathconf_linkmax, {
6869                         "linkmax", "nfs.pathconf.linkmax", FT_UINT32, BASE_DEC,
6870                         NULL, 0, "Maximum number of hard links", HFILL }},
6871                 { &hf_nfs_pathconf_name_max, {
6872                         "name_max", "nfs.pathconf.name_max", FT_UINT32, BASE_DEC,
6873                         NULL, 0, "Maximum file name length", HFILL }},
6874                 { &hf_nfs_pathconf_no_trunc, {
6875                         "no_trunc", "nfs.pathconf.no_trunc", FT_BOOLEAN, BASE_NONE,
6876                         &yesno, 0, "No long file name truncation", HFILL }},
6877                 { &hf_nfs_pathconf_chown_restricted, {
6878                         "chown_restricted", "nfs.pathconf.chown_restricted", FT_BOOLEAN, 
6879                         BASE_NONE, &yesno, 0, "chown is restricted to root", HFILL }},
6880                 { &hf_nfs_pathconf_case_insensitive, {
6881                         "case_insensitive", "nfs.pathconf.case_insensitive", FT_BOOLEAN, 
6882                         BASE_NONE, &yesno, 0, "file names are treated case insensitive", HFILL }},
6883                 { &hf_nfs_pathconf_case_preserving, {
6884                         "case_preserving", "nfs.pathconf.case_preserving", FT_BOOLEAN, 
6885                         BASE_NONE, &yesno, 0, "file name cases are preserved", HFILL }},
6886
6887                 { &hf_nfs_fattr_type, {
6888                         "type", "nfs.fattr.type", FT_UINT32, BASE_DEC,
6889                         NULL, 0, "nfs.fattr.type", HFILL }},
6890
6891                 { &hf_nfs_fattr_nlink, {
6892                         "nlink", "nfs.fattr.nlink", FT_UINT32, BASE_DEC,
6893                         NULL, 0, "nfs.fattr.nlink", HFILL }},
6894
6895                 { &hf_nfs_fattr_uid, {
6896                         "uid", "nfs.fattr.uid", FT_UINT32, BASE_DEC,
6897                         NULL, 0, "nfs.fattr.uid", HFILL }},
6898
6899                 { &hf_nfs_fattr_gid, {
6900                         "gid", "nfs.fattr.gid", FT_UINT32, BASE_DEC,
6901                         NULL, 0, "nfs.fattr.gid", HFILL }},
6902
6903                 { &hf_nfs_fattr_size, {
6904                         "size", "nfs.fattr.size", FT_UINT32, BASE_DEC,
6905                         NULL, 0, "nfs.fattr.size", HFILL }},
6906
6907                 { &hf_nfs_fattr_blocksize, {
6908                         "blocksize", "nfs.fattr.blocksize", FT_UINT32, BASE_DEC,
6909                         NULL, 0, "nfs.fattr.blocksize", HFILL }},
6910
6911                 { &hf_nfs_fattr_rdev, {
6912                         "rdev", "nfs.fattr.rdev", FT_UINT32, BASE_DEC,
6913                         NULL, 0, "nfs.fattr.rdev", HFILL }},
6914
6915                 { &hf_nfs_fattr_blocks, {
6916                         "blocks", "nfs.fattr.blocks", FT_UINT32, BASE_DEC,
6917                         NULL, 0, "nfs.fattr.blocks", HFILL }},
6918
6919                 { &hf_nfs_fattr_fsid, {
6920                         "fsid", "nfs.fattr.fsid", FT_UINT32, BASE_DEC,
6921                         NULL, 0, "nfs.fattr.fsid", HFILL }},
6922
6923                 { &hf_nfs_fattr_fileid, {
6924                         "fileid", "nfs.fattr.fileid", FT_UINT32, BASE_DEC,
6925                         NULL, 0, "nfs.fattr.fileid", HFILL }},
6926
6927                 { &hf_nfs_fattr3_type, {
6928                         "Type", "nfs.fattr3.type", FT_UINT32, BASE_DEC,
6929                         VALS(names_nfs_ftype3), 0, "nfs.fattr3.type", HFILL }},
6930
6931                 { &hf_nfs_fattr3_nlink, {
6932                         "nlink", "nfs.fattr3.nlink", FT_UINT32, BASE_DEC,
6933                         NULL, 0, "nfs.fattr3.nlink", HFILL }},
6934
6935                 { &hf_nfs_fattr3_uid, {
6936                         "uid", "nfs.fattr3.uid", FT_UINT32, BASE_DEC,
6937                         NULL, 0, "nfs.fattr3.uid", HFILL }},
6938
6939                 { &hf_nfs_fattr3_gid, {
6940                         "gid", "nfs.fattr3.gid", FT_UINT32, BASE_DEC,
6941                         NULL, 0, "nfs.fattr3.gid", HFILL }},
6942
6943                 { &hf_nfs_fattr3_size, {
6944                         "size", "nfs.fattr3.size", FT_UINT64, BASE_DEC,
6945                         NULL, 0, "nfs.fattr3.size", HFILL }},
6946
6947                 { &hf_nfs_fattr3_used, {
6948                         "used", "nfs.fattr3.used", FT_UINT64, BASE_DEC,
6949                         NULL, 0, "nfs.fattr3.used", HFILL }},
6950
6951                 { &hf_nfs_fattr3_rdev, {
6952                         "rdev", "nfs.fattr3.rdev", FT_UINT32, BASE_DEC,
6953                         NULL, 0, "nfs.fattr3.rdev", HFILL }},
6954
6955                 { &hf_nfs_fattr3_fsid, {
6956                         "fsid", "nfs.fattr3.fsid", FT_UINT64, BASE_DEC,
6957                         NULL, 0, "nfs.fattr3.fsid", HFILL }},
6958
6959                 { &hf_nfs_fattr3_fileid, {
6960                         "fileid", "nfs.fattr3.fileid", FT_UINT64, BASE_DEC,
6961                         NULL, 0, "nfs.fattr3.fileid", HFILL }},
6962
6963                 { &hf_nfs_wcc_attr_size, {
6964                         "size", "nfs.wcc_attr.size", FT_UINT64, BASE_DEC,
6965                         NULL, 0, "nfs.wcc_attr.size", HFILL }},
6966
6967                 { &hf_nfs_set_size3_size, {
6968                         "size", "nfs.set_size3.size", FT_UINT64, BASE_DEC,
6969                         NULL, 0, "nfs.set_size3.size", HFILL }},
6970
6971                 { &hf_nfs_uid3, {
6972                         "uid", "nfs.uid3", FT_UINT32, BASE_DEC,
6973                         NULL, 0, "nfs.uid3", HFILL }},
6974
6975                 { &hf_nfs_gid3, {
6976                         "gid", "nfs.gid3", FT_UINT32, BASE_DEC,
6977                         NULL, 0, "nfs.gid3", HFILL }},
6978
6979                 { &hf_nfs_cookie3, {
6980                         "cookie", "nfs.cookie3", FT_UINT64, BASE_DEC,
6981                         NULL, 0, "nfs.cookie3", HFILL }},
6982
6983                 { &hf_nfs_offset3, {
6984                         "offset", "nfs.offset3", FT_UINT64, BASE_DEC,
6985                         NULL, 0, "nfs.offset3", HFILL }},
6986
6987                 { &hf_nfs_count3, {
6988                         "count", "nfs.count3", FT_UINT32, BASE_DEC,
6989                         NULL, 0, "nfs.count3", HFILL }},
6990
6991                 { &hf_nfs_count3_maxcount, {
6992                         "maxcount", "nfs.count3_maxcount", FT_UINT32, BASE_DEC,
6993                         NULL, 0, "nfs.count3_maxcount", HFILL }},
6994
6995                 { &hf_nfs_count3_dircount, {
6996                         "dircount", "nfs.count3_dircount", FT_UINT32, BASE_DEC,
6997                         NULL, 0, "nfs.count3_dircount", HFILL }},
6998
6999                 { &hf_nfs_fsstat3_resok_tbytes, {
7000                         "Total bytes", "nfs.fsstat3_resok.tbytes", FT_UINT64, BASE_DEC,
7001                         NULL, 0, "Total bytes", HFILL }},
7002
7003                 { &hf_nfs_fsstat3_resok_fbytes, {
7004                         "Free bytes", "nfs.fsstat3_resok.fbytes", FT_UINT64, BASE_DEC,
7005                         NULL, 0, "Free bytes", HFILL }},
7006
7007                 { &hf_nfs_fsstat3_resok_abytes, {
7008                         "Available free bytes", "nfs.fsstat3_resok.abytes", FT_UINT64, BASE_DEC,
7009                         NULL, 0, "Available free bytes", HFILL }},
7010
7011                 { &hf_nfs_fsstat3_resok_tfiles, {
7012                         "Total file slots", "nfs.fsstat3_resok.tfiles", FT_UINT64, BASE_DEC,
7013                         NULL, 0, "Total file slots", HFILL }},
7014
7015                 { &hf_nfs_fsstat3_resok_ffiles, {
7016                         "Free file slots", "nfs.fsstat3_resok.ffiles", FT_UINT64, BASE_DEC,
7017                         NULL, 0, "Free file slots", HFILL }},
7018
7019                 { &hf_nfs_fsstat3_resok_afiles, {
7020                         "Available free file slots", "nfs.fsstat3_resok.afiles", FT_UINT64, BASE_DEC,
7021                         NULL, 0, "Available free file slots", HFILL }},
7022
7023                 /* NFSv4 */
7024
7025                 { &hf_nfs_argop4, {
7026                         "Opcode", "nfs.call.operation", FT_UINT32, BASE_DEC,
7027                         VALS(names_nfsv4_operation), 0, "Opcode", HFILL }},
7028
7029                 { &hf_nfs_resop4,       {
7030                         "Opcode", "nfs.reply.operation", FT_UINT32, BASE_DEC,
7031                         VALS(names_nfsv4_operation), 0, "Opcode", HFILL }},
7032
7033                 { &hf_nfs_linktext4, {
7034                         "Name", "nfs.symlink.linktext", FT_STRING, BASE_DEC,
7035                         NULL, 0, "Symbolic link contents", HFILL }},
7036
7037                 { &hf_nfs_component4, {
7038                         "Filename", "nfs.pathname.component", FT_STRING, BASE_DEC,
7039                         NULL, 0, "Pathname component", HFILL }},
7040
7041                 { &hf_nfs_tag4, {
7042                         "Tag", "nfs.tag", FT_STRING, BASE_DEC,
7043                         NULL, 0, "Tag", HFILL }},
7044
7045                 { &hf_nfs_clientid4, {
7046                         "clientid", "nfs.clientid", FT_UINT64, BASE_HEX,
7047                         NULL, 0, "Client ID", HFILL }},
7048
7049                 { &hf_nfs_ace4, {
7050                         "ace", "nfs.ace", FT_STRING, BASE_DEC,
7051                         NULL, 0, "Access Control Entry", HFILL }},
7052
7053                 { &hf_nfs_recall, {
7054                         "EOF", "nfs.recall", FT_BOOLEAN, BASE_NONE,
7055                         &yesno, 0, "Recall", HFILL }},
7056
7057                 { &hf_nfs_open_claim_type4, {
7058                         "Claim Type", "nfs.open.claim_type", FT_UINT32, BASE_DEC,
7059                         VALS(names_claim_type4), 0, "Claim Type", HFILL }},
7060
7061                 { &hf_nfs_opentype4, {
7062                         "Open Type", "nfs.open.opentype", FT_UINT32, BASE_DEC,
7063                         VALS(names_opentype4), 0, "Open Type", HFILL }},
7064
7065                 { &hf_nfs_limit_by4, {
7066                         "Space Limit", "nfs.open.limit_by", FT_UINT32, BASE_DEC,
7067                         VALS(names_limit_by4), 0, "Limit By", HFILL }},
7068
7069                 { &hf_nfs_open_delegation_type4, {
7070                         "Delegation Type", "nfs.open.delegation_type", FT_UINT32, BASE_DEC,
7071                         VALS(names_open_delegation_type4), 0, "Delegation Type", HFILL }},
7072
7073                 { &hf_nfs_ftype4, {
7074                         "nfs_ftype4", "nfs.nfs_ftype4", FT_UINT32, BASE_DEC,
7075                         VALS(names_ftype4), 0, "nfs.nfs_ftype4", HFILL }},
7076
7077                 { &hf_nfs_change_info4_atomic, {
7078                         "Atomic", "nfs.change_info.atomic", FT_BOOLEAN, BASE_NONE,
7079                         &yesno, 0, "Atomic", HFILL }},
7080
7081                 { &hf_nfs_open4_share_access, {
7082                         "share_access", "nfs.open4.share_access", FT_UINT32, BASE_DEC,
7083                         VALS(names_open4_share_access), 0, "Share Access", HFILL }},
7084
7085                 { &hf_nfs_open4_share_deny, {
7086                         "share_deny", "nfs.open4.share_deny", FT_UINT32, BASE_DEC,
7087                         VALS(names_open4_share_deny), 0, "Share Deny", HFILL }},
7088
7089                 { &hf_nfs_seqid4, {
7090                         "seqid", "nfs.seqid", FT_UINT32, BASE_HEX,
7091                         NULL, 0, "Sequence ID", HFILL }},
7092
7093                 { &hf_nfs_lock_seqid4, {
7094                         "lock_seqid", "nfs.lock_seqid", FT_UINT32, BASE_HEX,
7095                         NULL, 0, "Lock Sequence ID", HFILL }},
7096
7097                 { &hf_nfs_mand_attr, {
7098                         "mand_attr",    "nfs.attr", FT_UINT32, BASE_DEC,
7099                         VALS(names_fattr4), 0, "Mandatory Attribute", HFILL }},
7100
7101                 { &hf_nfs_recc_attr, {
7102                         "recc_attr",    "nfs.attr", FT_UINT32, BASE_DEC,
7103                         VALS(names_fattr4), 0, "Recommended Attribute", HFILL }},
7104
7105                 { &hf_nfs_time_how4,    {
7106                         "set_it", "nfs.set_it", FT_UINT32, BASE_DEC,
7107                         VALS(names_time_how4), 0, "How To Set Time", HFILL }},
7108
7109                 { &hf_nfs_attrlist4, {
7110                         "attr_vals", "nfs.fattr4.attr_vals", FT_BYTES, BASE_DEC,
7111                         NULL, 0, "attr_vals", HFILL }},
7112
7113                 { &hf_nfs_fattr4_link_support, {
7114                         "fattr4_link_support", "nfs.fattr4_link_support", FT_BOOLEAN, 
7115                         BASE_NONE, &yesno, 0, "nfs.fattr4_link_support", HFILL }},
7116
7117                 { &hf_nfs_fattr4_symlink_support, {
7118                         "fattr4_symlink_support", "nfs.fattr4_symlink_support", FT_BOOLEAN, 
7119                         BASE_NONE, &yesno, 0, "nfs.fattr4_symlink_support", HFILL }},
7120
7121                 { &hf_nfs_fattr4_named_attr, {
7122                         "fattr4_named_attr", "nfs.fattr4_named_attr", FT_BOOLEAN, BASE_NONE,
7123                         &yesno, 0, "nfs.fattr4_named_attr", HFILL }},
7124
7125                 { &hf_nfs_fattr4_unique_handles, {
7126                         "fattr4_unique_handles", "nfs.fattr4_unique_handles", FT_BOOLEAN, 
7127                         BASE_NONE, &yesno, 0, "nfs.fattr4_unique_handles", HFILL }},
7128
7129                 { &hf_nfs_fattr4_archive, {
7130                         "fattr4_archive", "nfs.fattr4_archive", FT_BOOLEAN, 
7131                         BASE_NONE, &yesno, 0, "nfs.fattr4_archive", HFILL }},
7132
7133                 { &hf_nfs_fattr4_cansettime, {
7134                         "fattr4_cansettime", "nfs.fattr4_cansettime", FT_BOOLEAN, 
7135                         BASE_NONE, &yesno, 0, "nfs.fattr4_cansettime", HFILL }},
7136
7137                 { &hf_nfs_fattr4_case_insensitive, {
7138                         "fattr4_case_insensitive", "nfs.fattr4_case_insensitive", FT_BOOLEAN, 
7139                         BASE_NONE, &yesno, 0, "nfs.fattr4_case_insensitive", HFILL }},
7140
7141                 { &hf_nfs_fattr4_case_preserving, {
7142                         "fattr4_case_preserving", "nfs.fattr4_case_preserving", FT_BOOLEAN, 
7143                         BASE_NONE, &yesno, 0, "nfs.fattr4_case_preserving", HFILL }},
7144
7145                 { &hf_nfs_fattr4_chown_restricted, {
7146                         "fattr4_chown_restricted", "nfs.fattr4_chown_restricted", FT_BOOLEAN, 
7147                         BASE_NONE, &yesno, 0, "nfs.fattr4_chown_restricted", HFILL }},
7148
7149                 { &hf_nfs_fattr4_hidden, {
7150                         "fattr4_hidden", "nfs.fattr4_hidden", FT_BOOLEAN, 
7151                         BASE_NONE, &yesno, 0, "nfs.fattr4_hidden", HFILL }},
7152
7153                 { &hf_nfs_fattr4_homogeneous, {
7154                         "fattr4_homogeneous", "nfs.fattr4_homogeneous", FT_BOOLEAN, 
7155                         BASE_NONE, &yesno, 0, "nfs.fattr4_homogeneous", HFILL }},
7156
7157                 { &hf_nfs_fattr4_mimetype, {
7158                         "fattr4_mimetype", "nfs.fattr4_mimetype", FT_STRING, BASE_DEC,
7159                         NULL, 0, "nfs.fattr4_mimetype", HFILL }},
7160
7161                 { &hf_nfs_fattr4_no_trunc, {
7162                         "fattr4_no_trunc", "nfs.fattr4_no_trunc", FT_BOOLEAN, 
7163                         BASE_NONE, &yesno, 0, "nfs.fattr4_no_trunc", HFILL }},
7164
7165                 { &hf_nfs_fattr4_system, {
7166                         "fattr4_system", "nfs.fattr4_system", FT_BOOLEAN, 
7167                         BASE_NONE, &yesno, 0, "nfs.fattr4_system", HFILL }},
7168
7169                 { &hf_nfs_who, {
7170                         "who", "nfs.who", FT_STRING, BASE_DEC,
7171                         NULL, 0, "nfs.who", HFILL }},
7172
7173                 { &hf_nfs_server, {
7174                         "server", "nfs.server", FT_STRING, BASE_DEC,
7175                         NULL, 0, "nfs.server", HFILL }},
7176
7177                 { &hf_nfs_fattr4_owner, {
7178                         "fattr4_owner", "nfs.fattr4_owner", FT_STRING, BASE_DEC,
7179                         NULL, 0, "nfs.fattr4_owner", HFILL }},
7180
7181                 { &hf_nfs_fattr4_owner_group, {
7182                         "fattr4_owner_group", "nfs.fattr4_owner_group", FT_STRING, BASE_DEC,
7183                         NULL, 0, "nfs.fattr4_owner_group", HFILL }},
7184
7185                 { &hf_nfs_stable_how4, {
7186                         "stable_how4", "nfs.stable_how4", FT_UINT32, BASE_DEC,
7187                         VALS(names_stable_how4), 0, "nfs.stable_how4", HFILL }},
7188
7189                 { &hf_nfs_dirlist4_eof, {
7190                         "eof", "nfs.dirlist4.eof", FT_BOOLEAN,
7191                         BASE_NONE, &yesno, 0, "nfs.dirlist4.eof", HFILL }},
7192
7193                 { &hf_nfs_stateid4, {
7194                         "stateid", "nfs.stateid4", FT_UINT64, BASE_DEC,
7195                         NULL, 0, "nfs.stateid4", HFILL }},
7196
7197                 { &hf_nfs_offset4, {
7198                         "offset", "nfs.offset4", FT_UINT64, BASE_DEC,
7199                         NULL, 0, "nfs.offset4", HFILL }},
7200
7201                 { &hf_nfs_specdata1, {
7202                         "specdata1", "nfs.specdata1", FT_UINT32, BASE_DEC,
7203                         NULL, 0, "nfs.specdata1", HFILL }},
7204
7205                 { &hf_nfs_specdata2, {
7206                         "specdata2", "nfs.specdata2", FT_UINT32, BASE_DEC,
7207                         NULL, 0, "nfs.specdata2", HFILL }},
7208
7209                 { &hf_nfs_lock_type4, {
7210                         "locktype", "nfs.locktype4", FT_UINT32, BASE_DEC,
7211                         VALS(names_nfs_lock_type4), 0, "nfs.locktype4", HFILL }},
7212
7213                 { &hf_nfs_reclaim4, {
7214                         "reclaim", "nfs.reclaim4", FT_BOOLEAN, 
7215                         BASE_NONE, &yesno, 0, "Reclaim", HFILL }},
7216
7217                 { &hf_nfs_length4, {
7218                         "length", "nfs.length4", FT_UINT64, BASE_DEC,
7219                         NULL, 0, "nfs.length4", HFILL }},
7220
7221                 { &hf_nfs_changeid4, {
7222                         "changeid", "nfs.changeid4", FT_UINT64, BASE_DEC,
7223                         NULL, 0, "nfs.changeid4", HFILL }},
7224
7225                 { &hf_nfs_changeid4_before, {
7226                         "changeid", "nfs.changeid4.before", FT_UINT64, BASE_DEC,
7227                         NULL, 0, "nfs.changeid4.before", HFILL }},
7228
7229                 { &hf_nfs_changeid4_after, {
7230                         "changeid", "nfs.changeid4.after", FT_UINT64, BASE_DEC,
7231                         NULL, 0, "nfs.changeid4.after", HFILL }},
7232
7233                 { &hf_nfs_nfstime4_seconds, {
7234                         "seconds", "nfs.nfstime4.seconds", FT_UINT64, BASE_DEC,
7235                         NULL, 0, "nfs.nfstime4.seconds", HFILL }},
7236
7237                 { &hf_nfs_nfstime4_nseconds, {
7238                         "nseconds", "nfs.nfstime4.nseconds", FT_UINT32, BASE_DEC,
7239                         NULL, 0, "nfs.nfstime4.nseconds", HFILL }},
7240
7241                 { &hf_nfs_fsid4_major, {
7242                         "fsid4.major", "nfs.fsid4.major", FT_UINT64, BASE_DEC,
7243                         NULL, 0, "nfs.nfstime4.fsid4.major", HFILL }},
7244
7245                 { &hf_nfs_fsid4_minor, {
7246                         "fsid4.minor", "nfs.fsid4.minor", FT_UINT64, BASE_DEC,
7247                         NULL, 0, "nfs.fsid4.minor", HFILL }},
7248
7249                 { &hf_nfs_acetype4, {
7250                         "acetype", "nfs.acetype4", FT_UINT32, BASE_DEC,
7251                         VALS(names_acetype4), 0, "nfs.acetype4", HFILL }},
7252
7253                 { &hf_nfs_aceflag4, {
7254                         "aceflag", "nfs.aceflag4", FT_UINT32, BASE_DEC,
7255                         NULL, 0, "nfs.aceflag4", HFILL }},
7256
7257                 { &hf_nfs_acemask4, {
7258                         "acemask", "nfs.acemask4", FT_UINT32, BASE_DEC,
7259                         NULL, 0, "nfs.acemask4", HFILL }},
7260
7261                 { &hf_nfs_fattr4_size, {
7262                         "size", "nfs.fattr4.size", FT_UINT64, BASE_DEC,
7263                         NULL, 0, "nfs.fattr4.size", HFILL }},
7264
7265                 { &hf_nfs_fattr4_lease_time, {
7266                         "lease_time", "nfs.fattr4.lease_time", FT_UINT32, BASE_DEC,
7267                         NULL, 0, "nfs.fattr4.lease_time", HFILL }},
7268
7269                 { &hf_nfs_fattr4_aclsupport, {
7270                         "aclsupport", "nfs.fattr4.aclsupport", FT_UINT32, BASE_DEC,
7271                         NULL, 0, "nfs.fattr4.aclsupport", HFILL }},
7272
7273                 { &hf_nfs_fattr4_fileid, {
7274                         "fileid", "nfs.fattr4.fileid", FT_UINT64, BASE_DEC,
7275                         NULL, 0, "nfs.fattr4.fileid", HFILL }},
7276
7277                 { &hf_nfs_fattr4_files_avail, {
7278                         "files_avail", "nfs.fattr4.files_avail", FT_UINT64, BASE_DEC,
7279                         NULL, 0, "nfs.fattr4.files_avail", HFILL }},
7280
7281                 { &hf_nfs_fattr4_files_free, {
7282                         "files_free", "nfs.fattr4.files_free", FT_UINT64, BASE_DEC,
7283                         NULL, 0, "nfs.fattr4.files_free", HFILL }},
7284
7285                 { &hf_nfs_fattr4_files_total, {
7286                         "files_total", "nfs.fattr4.files_total", FT_UINT64, BASE_DEC,
7287                         NULL, 0, "nfs.fattr4.files_total", HFILL }},
7288
7289                 { &hf_nfs_fattr4_maxfilesize, {
7290                         "maxfilesize", "nfs.fattr4.maxfilesize", FT_UINT64, BASE_DEC,
7291                         NULL, 0, "nfs.fattr4.maxfilesize", HFILL }},
7292
7293                 { &hf_nfs_fattr4_maxlink, {
7294                         "maxlink", "nfs.fattr4.maxlink", FT_UINT32, BASE_DEC,
7295                         NULL, 0, "nfs.fattr4.maxlink", HFILL }},
7296
7297                 { &hf_nfs_fattr4_maxname, {
7298                         "maxname", "nfs.fattr4.maxname", FT_UINT32, BASE_DEC,
7299                         NULL, 0, "nfs.fattr4.maxname", HFILL }},
7300
7301                 { &hf_nfs_fattr4_numlinks, {
7302                         "numlinks", "nfs.fattr4.numlinks", FT_UINT32, BASE_DEC,
7303                         NULL, 0, "nfs.fattr4.numlinks", HFILL }},
7304
7305                 { &hf_nfs_delegate_type, {
7306                         "delegate_type", "nfs.delegate_type", FT_UINT32, BASE_DEC,
7307                         NULL, 0, "nfs.delegate_type", HFILL }},
7308
7309                 { &hf_nfs_secinfo_flavor, {
7310                         "flavor", "nfs.secinfo.flavor", FT_UINT32, BASE_DEC,
7311                         VALS(rpc_auth_flavor), 0, "nfs.secinfo.flavor", HFILL }},
7312
7313                 { &hf_nfs_num_blocks, {
7314                         "num_blocks", "nfs.num_blocks", FT_UINT32, BASE_DEC,
7315                         NULL, 0, "nfs.num_blocks", HFILL }},
7316
7317                 { &hf_nfs_bytes_per_block, {
7318                         "bytes_per_block", "nfs.bytes_per_block", FT_UINT32, BASE_DEC,
7319                         NULL, 0, "nfs.bytes_per_block", HFILL }},
7320
7321                 { &hf_nfs_eof, {
7322                         "eof", "nfs.eof", FT_UINT32, BASE_DEC,
7323                         NULL, 0, "nfs.eof", HFILL }},
7324
7325                 { &hf_nfs_fattr4_maxread, {
7326                         "maxread", "nfs.fattr4.maxread", FT_UINT64, BASE_DEC,
7327                         NULL, 0, "nfs.fattr4.maxread", HFILL }},
7328
7329                 { &hf_nfs_fattr4_maxwrite, {
7330                         "maxwrite", "nfs.fattr4.maxwrite", FT_UINT64, BASE_DEC,
7331                         NULL, 0, "nfs.fattr4.maxwrite", HFILL }},
7332
7333                 { &hf_nfs_fattr4_quota_hard, {
7334                         "quota_hard", "nfs.fattr4.quota_hard", FT_UINT64, BASE_DEC,
7335                         NULL, 0, "nfs.fattr4.quota_hard", HFILL }},
7336
7337                 { &hf_nfs_fattr4_quota_soft, {
7338                         "quota_soft", "nfs.fattr4.quota_soft", FT_UINT64, BASE_DEC,
7339                         NULL, 0, "nfs.fattr4.quota_soft", HFILL }},
7340
7341                 { &hf_nfs_fattr4_quota_used, {
7342                         "quota_used", "nfs.fattr4.quota_used", FT_UINT64, BASE_DEC,
7343                         NULL, 0, "nfs.fattr4.quota_used", HFILL }},
7344
7345                 { &hf_nfs_fattr4_space_avail, {
7346                         "space_avail", "nfs.fattr4.space_avail", FT_UINT64, BASE_DEC,
7347                         NULL, 0, "nfs.fattr4.space_avail", HFILL }},
7348
7349                 { &hf_nfs_fattr4_space_free, {
7350                         "space_free", "nfs.fattr4.space_free", FT_UINT64, BASE_DEC,
7351                         NULL, 0, "nfs.fattr4.space_free", HFILL }},
7352
7353                 { &hf_nfs_fattr4_space_total, {
7354                         "space_total", "nfs.fattr4.space_total", FT_UINT64, BASE_DEC,
7355                         NULL, 0, "nfs.fattr4.space_total", HFILL }},
7356
7357                 { &hf_nfs_fattr4_space_used, {
7358                         "space_used", "nfs.fattr4.space_used", FT_UINT64, BASE_DEC,
7359                         NULL, 0, "nfs.fattr4.space_used", HFILL }},
7360
7361                 { &hf_nfs_stateid4_delegate_stateid, {
7362                         "delegate_stateid", "nfs.delegate_stateid", FT_UINT64, BASE_DEC,
7363                         NULL, 0, "nfs.delegate_stateid", HFILL }},
7364
7365                 { &hf_nfs_verifier4, {
7366                         "verifier", "nfs.verifier4", FT_UINT64, BASE_HEX,
7367                         NULL, 0, "nfs.verifier4", HFILL }},
7368
7369                 { &hf_nfs_cookie4, {
7370                         "cookie", "nfs.cookie4", FT_UINT64, BASE_DEC,
7371                         NULL, 0, "nfs.cookie4", HFILL }},
7372
7373                 { &hf_nfs_cookieverf4, {
7374                         "cookieverf", "nfs.cookieverf4", FT_UINT64, BASE_DEC,
7375                         NULL, 0, "nfs.cookieverf4", HFILL }},
7376
7377                 { &hf_nfs_cb_location, {
7378                         "cb_location", "nfs.cb_location", FT_UINT32, BASE_DEC,
7379                         NULL, 0, "nfs.cb_location", HFILL }},
7380
7381                 { &hf_nfs_cb_program, {
7382                         "cb_program", "nfs.cb_program", FT_UINT32, BASE_DEC,
7383                         NULL, 0, "nfs.cb_program", HFILL }},
7384
7385                 { &hf_nfs_recall4, {
7386                         "recall", "nfs.recall4", FT_BOOLEAN, 
7387                         BASE_NONE, &yesno, 0, "nfs.recall4", HFILL }},
7388
7389                 { &hf_nfs_filesize, {
7390                         "filesize", "nfs.filesize", FT_UINT64, BASE_DEC,
7391                         NULL, 0, "nfs.filesize", HFILL }},
7392
7393                 { &hf_nfs_count4, {
7394                         "count", "nfs.count4", FT_UINT32, BASE_DEC,
7395                         NULL, 0, "nfs.count4", HFILL }},
7396
7397                 { &hf_nfs_count4_dircount, {
7398                         "dircount", "nfs.dircount", FT_UINT32, BASE_DEC,
7399                         NULL, 0, "nfs.dircount", HFILL }},
7400
7401                 { &hf_nfs_count4_maxcount, {
7402                         "maxcount", "nfs.maxcount", FT_UINT32, BASE_DEC,
7403                         NULL, 0, "nfs.maxcount", HFILL }},
7404
7405                 { &hf_nfs_minorversion, {
7406                         "minorversion", "nfs.minorversion", FT_UINT32, BASE_DEC,
7407                         NULL, 0, "nfs.minorversion", HFILL }},
7408
7409                 { &hf_nfs_atime, {
7410                         "atime", "nfs.atime", FT_ABSOLUTE_TIME, BASE_NONE,
7411                         NULL, 0, "Access Time", HFILL }},
7412
7413                 { &hf_nfs_atime_sec, {
7414                         "seconds", "nfs.atime.sec", FT_UINT32, BASE_DEC,
7415                         NULL, 0, "Access Time, Seconds", HFILL }},
7416
7417                 { &hf_nfs_atime_nsec, {
7418                         "nano seconds", "nfs.atime.nsec", FT_UINT32, BASE_DEC,
7419                         NULL, 0, "Access Time, Nano-seconds", HFILL }},
7420
7421                 { &hf_nfs_atime_usec, {
7422                         "micro seconds", "nfs.atime.usec", FT_UINT32, BASE_DEC,
7423                         NULL, 0, "Access Time, Micro-seconds", HFILL }},
7424
7425                 { &hf_nfs_mtime, {
7426                         "mtime", "nfs.mtime", FT_ABSOLUTE_TIME, BASE_NONE,
7427                         NULL, 0, "Modify Time", HFILL }},
7428
7429                 { &hf_nfs_mtime_sec, {
7430                         "seconds", "nfs.mtime.sec", FT_UINT32, BASE_DEC,
7431                         NULL, 0, "Modify Seconds", HFILL }},
7432
7433                 { &hf_nfs_mtime_nsec, {
7434                         "nano seconds", "nfs.mtime.nsec", FT_UINT32, BASE_DEC,
7435                         NULL, 0, "Modify Time, Nano-seconds", HFILL }},
7436
7437                 { &hf_nfs_mtime_usec, {
7438                         "micro seconds", "nfs.mtime.usec", FT_UINT32, BASE_DEC,
7439                         NULL, 0, "Modify Time, Micro-seconds", HFILL }},
7440
7441                 { &hf_nfs_ctime, {
7442                         "ctime", "nfs.ctime", FT_ABSOLUTE_TIME, BASE_NONE,
7443                         NULL, 0, "Creation Time", HFILL }},
7444
7445                 { &hf_nfs_ctime_sec, {
7446                         "seconds", "nfs.ctime.sec", FT_UINT32, BASE_DEC,
7447                         NULL, 0, "Creation Time, Seconds", HFILL }},
7448
7449                 { &hf_nfs_ctime_nsec, {
7450                         "nano seconds", "nfs.ctime.nsec", FT_UINT32, BASE_DEC,
7451                         NULL, 0, "Creation Time, Nano-seconds", HFILL }},
7452
7453                 { &hf_nfs_ctime_usec, {
7454                         "micro seconds", "nfs.ctime.usec", FT_UINT32, BASE_DEC,
7455                         NULL, 0, "Creation Time, Micro-seconds", HFILL }},
7456
7457                 { &hf_nfs_dtime, {
7458                         "time delta", "nfs.dtime", FT_RELATIVE_TIME, BASE_NONE,
7459                         NULL, 0, "Time Delta", HFILL }},
7460
7461                 { &hf_nfs_dtime_sec, {
7462                         "seconds", "nfs.dtime.sec", FT_UINT32, BASE_DEC,
7463                         NULL, 0, "Time Delta, Seconds", HFILL }},
7464
7465                 { &hf_nfs_dtime_nsec, {
7466                         "nano seconds", "nfs.dtime.nsec", FT_UINT32, BASE_DEC,
7467                         NULL, 0, "Time Delta, Nano-seconds", HFILL }},
7468
7469                 { &hf_nfs_open_owner4, {
7470                         "owner", "nfs.open_owner4", FT_BYTES, BASE_DEC,
7471                         NULL, 0, "owner", HFILL }},
7472
7473                 { &hf_nfs_lock_owner4, {
7474                         "owner", "nfs.lock_owner4", FT_BYTES, BASE_DEC,
7475                         NULL, 0, "owner", HFILL }},
7476
7477                 { &hf_nfs_secinfo_rpcsec_gss_info_service, {
7478                         "service", "nfs.secinfo.rpcsec_gss_info.service", FT_UINT32,
7479                         BASE_DEC, VALS(rpc_authgss_svc), 0, "service", HFILL }},
7480
7481                 { &hf_nfs_attrdircreate, {
7482                         "attribute dir create", "nfs.openattr4.createdir", FT_BOOLEAN, 
7483                         BASE_NONE, &yesno, 0, "nfs.openattr4.createdir", HFILL }},
7484
7485                 { &hf_nfs_new_lock_owner, {
7486                         "new lock owner?", "nfs.lock.locker.new_lock_owner", FT_BOOLEAN, 
7487                         BASE_NONE, &yesno, 0, "nfs.lock.locker.new_lock_owner", HFILL }},
7488
7489                 { &hf_nfs_lock4_reclaim, {
7490                         "reclaim?", "nfs.lock.reclaim", FT_BOOLEAN, 
7491                         BASE_NONE, &yesno, 0, "nfs.lock.reclaim", HFILL }},
7492
7493                 { &hf_nfs_sec_oid4, {
7494                         "oid", "nfs.secinfo.flavor_info.rpcsec_gss_info.oid", FT_BYTES,
7495                         BASE_DEC, NULL, 0, "oid", HFILL }},
7496
7497                 { &hf_nfs_qop4, {
7498                         "qop", "nfs.secinfo.flavor_info.rpcsec_gss_info.qop", FT_UINT32, 
7499                         BASE_DEC, NULL, 0, "qop", HFILL }},
7500
7501                 { &hf_nfs_client_id4_id, {
7502                         "id", "nfs.nfs_client_id4.id", FT_BYTES, BASE_DEC,
7503                         NULL, 0, "nfs.nfs_client_id4.id", HFILL }},
7504
7505                 { &hf_nfs_stateid4_other, {
7506                         "Data", "nfs.stateid4.other", FT_BYTES, BASE_DEC,
7507                         NULL, 0, "Data", HFILL }},
7508
7509                 { &hf_nfs_acl4, {
7510                         "ACL", "nfs.acl", FT_NONE, BASE_NONE,
7511                         NULL, 0, "Access Control List", HFILL }},
7512
7513                 { &hf_nfs_callback_ident, {
7514                         "callback_ident", "nfs.callback.ident", FT_UINT32, BASE_HEX,
7515                         NULL, 0, "Callback Identifier", HFILL }},
7516
7517                 { &hf_nfs_r_netid, {
7518                         "r_netid", "nfs.r_netid", FT_BYTES, BASE_DEC, NULL, 0, 
7519                         "r_netid", HFILL }},
7520
7521                 { &hf_nfs_r_addr, {
7522                         "r_addr", "nfs.r_addr", FT_BYTES, BASE_DEC, NULL, 0,
7523                         "r_addr", HFILL }},
7524         };
7525
7526         static gint *ett[] = {
7527                 &ett_nfs,
7528                 &ett_nfs_fh_encoding,
7529                 &ett_nfs_fh_fsid,
7530                 &ett_nfs_fh_xfsid,
7531                 &ett_nfs_fh_fn,
7532                 &ett_nfs_fh_xfn,
7533                 &ett_nfs_fh_hp,
7534                 &ett_nfs_fh_auth,
7535                 &ett_nfs_fhandle,
7536                 &ett_nfs_timeval,
7537                 &ett_nfs_mode,
7538                 &ett_nfs_fattr,
7539                 &ett_nfs_sattr,
7540                 &ett_nfs_diropargs,
7541                 &ett_nfs_readdir_entry,
7542                 &ett_nfs_mode3,
7543                 &ett_nfs_specdata3,
7544                 &ett_nfs_fh3,
7545                 &ett_nfs_nfstime3,
7546                 &ett_nfs_fattr3,
7547                 &ett_nfs_post_op_fh3,
7548                 &ett_nfs_sattr3,
7549                 &ett_nfs_diropargs3,
7550                 &ett_nfs_sattrguard3,
7551                 &ett_nfs_set_mode3,
7552                 &ett_nfs_set_uid3,
7553                 &ett_nfs_set_gid3,
7554                 &ett_nfs_set_size3,
7555                 &ett_nfs_set_atime,
7556                 &ett_nfs_set_mtime,
7557                 &ett_nfs_pre_op_attr,
7558                 &ett_nfs_post_op_attr,
7559                 &ett_nfs_wcc_attr,
7560                 &ett_nfs_wcc_data,
7561                 &ett_nfs_access,
7562                 &ett_nfs_fsinfo_properties,
7563                 &ett_nfs_compound_call4,
7564                 &ett_nfs_utf8string,
7565                 &ett_nfs_argop4,
7566                 &ett_nfs_resop4,
7567                 &ett_nfs_access4,
7568                 &ett_nfs_close4,
7569                 &ett_nfs_commit4,
7570                 &ett_nfs_create4,
7571                 &ett_nfs_delegpurge4,
7572                 &ett_nfs_delegreturn4,
7573                 &ett_nfs_getattr4,
7574                 &ett_nfs_getfh4,
7575                 &ett_nfs_link4,
7576                 &ett_nfs_lock4,
7577                 &ett_nfs_lockt4,
7578                 &ett_nfs_locku4,
7579                 &ett_nfs_lookup4,
7580                 &ett_nfs_lookupp4,
7581                 &ett_nfs_nverify4,
7582                 &ett_nfs_open4,
7583                 &ett_nfs_openattr4,
7584                 &ett_nfs_open_confirm4,
7585                 &ett_nfs_open_downgrade4,
7586                 &ett_nfs_putfh4,
7587                 &ett_nfs_putpubfh4,
7588                 &ett_nfs_putrootfh4,
7589                 &ett_nfs_read4,
7590                 &ett_nfs_readdir4,
7591                 &ett_nfs_readlink4,
7592                 &ett_nfs_remove4,
7593                 &ett_nfs_rename4,
7594                 &ett_nfs_renew4,
7595                 &ett_nfs_restorefh4,
7596                 &ett_nfs_savefh4,
7597                 &ett_nfs_setattr4,
7598                 &ett_nfs_setclientid4,
7599                 &ett_nfs_setclientid_confirm4,
7600                 &ett_nfs_verify4,
7601                 &ett_nfs_write4,
7602                 &ett_nfs_verifier4,
7603                 &ett_nfs_opaque,
7604                 &ett_nfs_dirlist4,
7605                 &ett_nfs_pathname4,
7606                 &ett_nfs_change_info4,
7607                 &ett_nfs_open_delegation4,
7608                 &ett_nfs_open_claim4,
7609                 &ett_nfs_opentype4,
7610                 &ett_nfs_lock_owner4,
7611                 &ett_nfs_cb_client4,
7612                 &ett_nfs_client_id4,
7613                 &ett_nfs_bitmap4,
7614                 &ett_nfs_fattr4,
7615                 &ett_nfs_fsid4,
7616                 &ett_nfs_fs_locations4,
7617                 &ett_nfs_fs_location4,
7618                 &ett_nfs_open4_result_flags,
7619                 &ett_nfs_secinfo4,
7620                 &ett_nfs_secinfo4_flavor_info,
7621                 &ett_nfs_stateid4,
7622                 &ett_nfs_fattr4_fh_expire_type,
7623                 &ett_nfs_ace4,
7624                 &ett_nfs_clientaddr4,
7625                 &ett_nfs_aceflag4,
7626                 &ett_nfs_acemask4,
7627         };
7628         module_t *nfs_module;
7629
7630         proto_nfs = proto_register_protocol("Network File System", "NFS", "nfs");
7631         proto_register_field_array(proto_nfs, hf, array_length(hf));
7632         proto_register_subtree_array(ett, array_length(ett));
7633
7634         nfs_module=prefs_register_protocol(proto_nfs, NULL);
7635         prefs_register_bool_preference(nfs_module, "file_name_snooping",
7636                                        "Snoop FH to filename mappings",
7637                                        "Whether the dissector should snoop the FH to filename mappings by looking inside certain packets",
7638                                        &nfs_file_name_snooping);
7639         prefs_register_bool_preference(nfs_module, "file_full_name_snooping",
7640                                        "Snoop full path to filenames",
7641                                        "Whether the dissector should snoop the full pathname for files for matching FH's",
7642                                        &nfs_file_name_full_snooping);
7643         prefs_register_bool_preference(nfs_module, "fhandle_find_both_reqrep",
7644                                        "Fhandle filters finds both request/response",
7645                                        "With this option display filters for nfs fhandles (nfs.fh.{name|full_name|hash}) will find both the request and response packets for a RPC call, even if the actual fhandle is only present in one of the packets",
7646                                         &nfs_fhandle_reqrep_matching);
7647         register_init_routine(nfs_name_snoop_init);
7648         register_init_routine(nfs_fhandle_reqrep_matching_init);
7649 }
7650
7651 void
7652 proto_reg_handoff_nfs(void)
7653 {
7654         /* Register the protocol as RPC */
7655         rpc_init_prog(proto_nfs, NFS_PROGRAM, ett_nfs);
7656         /* Register the procedure tables */
7657         rpc_init_proc_table(NFS_PROGRAM, 2, nfs2_proc);
7658         rpc_init_proc_table(NFS_PROGRAM, 3, nfs3_proc);
7659         rpc_init_proc_table(NFS_PROGRAM, 4, nfs4_proc);
7660 }