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