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