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