Update from Paul Ionescu to set the reported length of the tvbuff for
[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.41 2001/01/03 16:41:06 gram 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 #define FHT_UNKNOWN     0
220 #define FHT_SVR4        1
221 #define FHT_LINUX_KNFSD_LE      2
222 #define FHT_LINUX_NFSD_LE       3
223
224 const value_string names_fhtype[] =
225 {
226         {       FHT_UNKNOWN,    "unknown"       },
227         {       FHT_SVR4,       "System V R4"   },
228         {       FHT_LINUX_KNFSD_LE,     "Linux knfsd (little-endian)"   },
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 #define CLAIM_NULL                      0
3554 #define CLAIM_PREVIOUS                  1
3555 #define CLAIM_DELEGATE_CUR              2
3556 #define CLAIM_DELEGATE_PREV             3
3557
3558 static const value_string names_claim_type4[] = {
3559         {       CLAIM_NULL,             "CLAIM_NULL"  },
3560         {       CLAIM_PREVIOUS,         "CLAIM_PREVIOUS" },
3561         {       CLAIM_DELEGATE_CUR,     "CLAIM_DELEGATE_CUR" },
3562         {       CLAIM_DELEGATE_PREV,    "CLAIM_DELEGATE_PREV" },
3563         { 0, NULL }
3564 };
3565
3566 int
3567 dissect_nfs_open_claim4(const u_char *pd, int offset, frame_data *fd,
3568         proto_tree *tree, char *name)
3569 {
3570         guint open_claim_type4;
3571         proto_item *fitem = NULL;
3572         proto_tree *newftree = NULL;
3573
3574         open_claim_type4 = EXTRACT_UINT(pd, offset);
3575         fitem = proto_tree_add_uint(tree, hf_nfs_open_claim_type4, NullTVB,
3576                 offset+0, 4, open_claim_type4);
3577         offset += 4;
3578
3579         if (fitem) {
3580                 newftree = proto_item_add_subtree(fitem, ett_nfs_open_claim4);
3581
3582                 if (newftree) {
3583
3584                         switch(open_claim_type4)
3585                         {
3586                         case CLAIM_NULL:
3587                                 offset = dissect_nfs_pathname4(pd, offset, fd, newftree, "file");
3588                                 break;
3589
3590                         case CLAIM_PREVIOUS:
3591                                 offset = dissect_rpc_uint32(pd, offset, fd, newftree, 
3592                                         "delegate_type");
3593                                 break;
3594
3595                         case CLAIM_DELEGATE_CUR:
3596                                 offset = dissect_nfs_open_claim_delegate_cur4(pd, offset, fd, 
3597                                         newftree, "delegate_cur_info");
3598                                 break;
3599
3600                         case CLAIM_DELEGATE_PREV:
3601                                 offset = dissect_nfs_pathname4(pd, offset, fd, newftree, 
3602                                         "file_delegate_prev");
3603                                 break;
3604
3605                         default:
3606                                 break;
3607                         }
3608                 }
3609         }
3610
3611         return offset;
3612 }
3613
3614 int
3615 dissect_nfs_verifier4(const u_char *pd, int offset, frame_data *fd,
3616         proto_tree *tree, char *name);
3617
3618 int
3619 dissect_nfs_createhow4(const u_char *pd, int offset, frame_data *fd,
3620         proto_tree *tree, char *name)
3621 {
3622         guint mode;
3623
3624         /* This is intentional; we're using the same flags as NFSv3 */
3625         mode = EXTRACT_UINT(pd, offset);
3626         proto_tree_add_uint(tree, hf_nfs_createmode3, NullTVB, offset, 4, mode);
3627         offset += 4;
3628         
3629         switch(mode)
3630         {
3631         case UNCHECKED:         /* UNCHECKED4 */
3632         case GUARDED:           /* GUARDED4 */
3633                 offset = dissect_nfs_fattr4(pd, offset, fd, tree, "createattrs");
3634                 break;
3635
3636         case EXCLUSIVE:         /* EXCLUSIVE4 */
3637                 offset = dissect_nfs_verifier4(pd, offset, fd, tree, "createverf");
3638                 break;
3639         
3640         default:
3641                 break;
3642         }
3643
3644         return offset;
3645 }
3646
3647 #define OPEN4_NOCREATE                          0
3648 #define OPEN4_CREATE                                    1
3649 static const value_string names_opentype4[] = {
3650         {       OPEN4_NOCREATE,  "OPEN4_NOCREATE"  },
3651         {       OPEN4_CREATE, "OPEN4_CREATE" },
3652         { 0, NULL }
3653 };
3654
3655 int
3656 dissect_nfs_openflag4(const u_char *pd, int offset, frame_data *fd,
3657         proto_tree *tree)
3658 {
3659         guint opentype4;
3660         proto_item *fitem = NULL;
3661         proto_tree *newftree = NULL;
3662
3663         opentype4 = EXTRACT_UINT(pd, offset);
3664         fitem = proto_tree_add_uint(tree, hf_nfs_opentype4, NullTVB,
3665                 offset+0, 4, opentype4);
3666         offset += 4;
3667
3668         if (fitem) {
3669                 newftree = proto_item_add_subtree(fitem, ett_nfs_opentype4);
3670
3671                 if (newftree) {
3672
3673                         switch(opentype4)
3674                         {
3675                         case OPEN4_CREATE:
3676                                 offset = dissect_nfs_createhow4(pd, offset, fd, newftree, "how");
3677                                 break;
3678
3679                         default:
3680                                 break;
3681                         }
3682                 }
3683         }
3684
3685         return offset;
3686 }
3687
3688 int
3689 dissect_nfs_verifier4(const u_char *pd, int offset, frame_data *fd,
3690         proto_tree *tree, char *name)
3691 {
3692         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3693 }
3694
3695 int
3696 dissect_nfs_fh4(const u_char *pd, int offset, frame_data *fd,
3697         proto_tree *tree, char *name)
3698 {
3699         return dissect_nfs_fh3(pd, offset, fd, tree, name);
3700 }
3701
3702 int
3703 dissect_nfs_cookie4(const u_char *pd, int offset, frame_data *fd,
3704         proto_tree *tree, char *name)
3705 {
3706         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3707 }
3708
3709 int
3710 dissect_nfs_cookieverf4(const u_char *pd, int offset, frame_data *fd,
3711         proto_tree *tree, char *name)
3712 {
3713         return dissect_rpc_uint64(pd, offset, fd, tree, name);
3714 }
3715
3716 /* this function is terribly ugly */
3717 int
3718 dissect_nfs_bitmap4(const u_char *pd, int offset, frame_data *fd,
3719         proto_tree *tree, char *name)
3720 {
3721         guint bitmap_len, bitmap;
3722         char flagtxt[256];
3723         proto_item *fitem = NULL;
3724         proto_tree *newftree = NULL;
3725
3726         bitmap_len = EXTRACT_UINT(pd, offset);
3727
3728         fitem = proto_tree_add_text(tree, NullTVB, offset, 4 + bitmap_len*4,
3729                 "%s", name);
3730
3731         offset += 4;
3732
3733         if (fitem == NULL) return offset;
3734
3735         newftree = proto_item_add_subtree(fitem, ett_nfs_bitmap4);
3736
3737         if (newftree == NULL) return offset;
3738
3739         bitmap = EXTRACT_UINT(pd, offset);
3740         offset += 4;
3741
3742         flagtxt[0]='\0';
3743
3744         if (bitmap & (1 << 0))
3745                 strcat(flagtxt, "supp_attr ");
3746         
3747         if (bitmap & (1 << 1))
3748                 strcat(flagtxt, "type ");
3749
3750         if (bitmap & (1 << 2))
3751                 strcat(flagtxt, "fh_expire_type ");
3752
3753         if (bitmap & (1 << 3))
3754                 strcat(flagtxt, "change ");
3755
3756         if (flagtxt[0] == '\0')
3757                 strcpy(flagtxt, "<none>");
3758         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 0-3: %s", flagtxt);
3759         flagtxt[0]='\0';
3760         
3761         if (bitmap & (1 << 4))
3762                 strcat(flagtxt, "size ");
3763
3764         if (bitmap & (1 << 5))
3765                 strcat(flagtxt, "link_support ");
3766
3767         if (bitmap & (1 << 6))
3768                 strcat(flagtxt, "symlink_support ");
3769
3770         if (bitmap & (1 << 7))
3771                 strcat(flagtxt, "named_attr ");
3772
3773         if (flagtxt[0] == '\0')
3774                 strcpy(flagtxt, "<none>");
3775         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 4-7: %s", flagtxt);
3776         
3777         flagtxt[0]='\0';
3778         
3779         if (bitmap & (1 << 8))
3780                 strcat(flagtxt, "fsid ");
3781
3782         if (bitmap & (1 << 9))
3783                 strcat(flagtxt, "unique_handles ");
3784
3785         if (bitmap & (1 << 10))
3786                 strcat(flagtxt, "lease_time ");
3787
3788         if (bitmap & (1 << 11))
3789                 strcat(flagtxt, "rdattr_error ");
3790
3791         if (flagtxt[0] == '\0')
3792                 strcpy(flagtxt, "<none>");
3793         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 8-11: %s", flagtxt);
3794         flagtxt[0]='\0';
3795         
3796         if (bitmap & (1 << 12))
3797                 strcat(flagtxt, "ACL ");
3798         
3799         if (bitmap & (1 << 13))
3800                 strcat(flagtxt, "aclsupport ");
3801
3802         if (bitmap & (1 << 14))
3803                 strcat(flagtxt, "archive ");
3804
3805         if (bitmap & (1 << 15))
3806                 strcat(flagtxt, "cansettime ");
3807
3808         if (flagtxt[0] == '\0')
3809                 strcpy(flagtxt, "<none>");
3810         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 12-15: %s", flagtxt);
3811         flagtxt[0]='\0';
3812
3813         if (bitmap & (1 << 16))
3814                 strcat(flagtxt, "case_insensitive ");
3815
3816         if (bitmap & (1 << 17))
3817                 strcat(flagtxt, "case_preserving ");
3818
3819         if (bitmap & (1 << 18))
3820                 strcat(flagtxt, "chown_restricted ");
3821
3822         if (bitmap & (1 << 19))
3823                 strcat(flagtxt, "filehandle ");
3824
3825         if (flagtxt[0] == '\0')
3826                 strcpy(flagtxt, "<none>");
3827         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 16-19: %s", flagtxt);
3828         flagtxt[0]='\0';
3829         
3830         if (bitmap & (1 << 20))
3831                 strcat(flagtxt, "fileid ");
3832
3833         if (bitmap & (1 << 21))
3834                 strcat(flagtxt, "files_avail ");
3835
3836         if (bitmap & (1 << 22))
3837                 strcat(flagtxt, "files_free ");
3838
3839         if (bitmap & (1 << 23))
3840                 strcat(flagtxt, "files_total ");
3841
3842         if (flagtxt[0] == '\0')
3843                 strcpy(flagtxt, "<none>");
3844         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 20-23: %s", flagtxt);
3845         flagtxt[0]='\0';
3846
3847         if (bitmap & (1 << 24))
3848                 strcat(flagtxt, "fs_locations ");
3849
3850         if (bitmap & (1 << 25))
3851                 strcat(flagtxt, "hidden ");
3852
3853         if (bitmap & (1 << 26))
3854                 strcat(flagtxt, "homegeneous ");
3855
3856         if (bitmap & (1 << 27))
3857                 strcat(flagtxt, "maxfilesize ");
3858
3859         if (flagtxt[0] == '\0')
3860                 strcpy(flagtxt, "<none>");
3861         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 24-27: %s", flagtxt);
3862         flagtxt[0]='\0';
3863
3864         if (bitmap & (1 << 28))
3865                 strcat(flagtxt, "maxlink ");
3866
3867         if (bitmap & (1 << 29))
3868                 strcat(flagtxt, "maxname ");
3869         
3870         if (bitmap & (1 << 30))
3871                 strcat(flagtxt, "maxread ");
3872
3873         if (bitmap & (1 << 31))
3874                 strcat(flagtxt, "maxwrite ");
3875
3876         if (flagtxt[0] == '\0')
3877                 strcpy(flagtxt, "<none>");
3878         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 28-31: %s", flagtxt);
3879         flagtxt[0]='\0';
3880
3881         bitmap = EXTRACT_UINT(pd, offset);
3882         offset += 4;
3883
3884         if (bitmap & (1 << 0))
3885                 strcat(flagtxt, "mimetype ");
3886
3887         if (bitmap & (1 << 1))
3888                 strcat(flagtxt, "mode ");
3889                 
3890         if (bitmap & (1 << 2))
3891                 strcat(flagtxt, "no_trunc ");
3892
3893         if (bitmap & (1 << 3))
3894                 strcat(flagtxt, "numlinks ");
3895
3896         if (flagtxt[0] == '\0')
3897                 strcpy(flagtxt, "<none>");
3898         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 32-35: %s", flagtxt);
3899         flagtxt[0]='\0';
3900         
3901         if (bitmap & (1 << 4))
3902                 strcat(flagtxt, "owner ");
3903
3904         if (bitmap & (1 << 5))
3905                 strcat(flagtxt, "owner_group ");
3906         
3907         if (bitmap & (1 << 6))
3908                 strcat(flagtxt, "quota_hard ");
3909         
3910         if (bitmap & (1 << 7))
3911                 strcat(flagtxt, "quota_soft ");
3912
3913         if (flagtxt[0] == '\0')
3914                 strcpy(flagtxt, "<none>");
3915         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 36-39: %s", flagtxt);
3916         flagtxt[0]='\0';
3917
3918         if (bitmap & (1 << 8))
3919                 strcat(flagtxt, "quota_used ");
3920
3921         if (bitmap & (1 << 9))
3922                 strcat(flagtxt, "rawdev ");
3923
3924         if (bitmap & (1 << 10))
3925                 strcat(flagtxt, "space_avail ");
3926
3927         if (bitmap & (1 << 11))
3928                 strcat(flagtxt, "space_free ");
3929
3930         if (flagtxt[0] == '\0')
3931                 strcpy(flagtxt, "<none>");
3932         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 40-43: %s", flagtxt);
3933         flagtxt[0]='\0';
3934
3935         if (bitmap & (1 << 12))
3936                 strcat(flagtxt, "space_total ");
3937         
3938         if (bitmap & (1 << 13))
3939                 strcat(flagtxt, "space_used ");
3940
3941         if (bitmap & (1 << 14))
3942                 strcat(flagtxt, "system ");
3943
3944         if (flagtxt[0] == '\0')
3945                 strcpy(flagtxt, "<none>");
3946         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 44-47: %s", flagtxt);
3947         flagtxt[0]='\0';
3948
3949         if (bitmap & (1 << 15))
3950                 strcat(flagtxt, "time_access ");
3951
3952         if (bitmap & (1 << 16))
3953                 strcat(flagtxt, "time_access_set ");
3954
3955         if (bitmap & (1 << 17))
3956                 strcat(flagtxt, "time_backup ");
3957
3958         if (bitmap & (1 << 18))
3959                 strcat(flagtxt, "time_create ");
3960
3961         if (flagtxt[0] == '\0')
3962                 strcpy(flagtxt, "<none>");
3963         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 48-51: %s", flagtxt);
3964         flagtxt[0]='\0';
3965
3966         if (bitmap & (1 << 19))
3967                 strcat(flagtxt, "time_delta ");
3968
3969         if (bitmap & (1 << 20))
3970                 strcat(flagtxt, "time_metadata ");
3971
3972         if (bitmap & (1 << 21))
3973                 strcat(flagtxt, "time_modify ");
3974
3975         if (bitmap & (1 << 22))
3976                 strcat(flagtxt, "time_modify_set ");
3977
3978         if (flagtxt[0] == '\0')
3979                 strcpy(flagtxt, "<none>");
3980         proto_tree_add_text(newftree, NullTVB, offset, 0, "Bits 52-55: %s", flagtxt);
3981
3982         /* 
3983          * If there are any more bits in this bitfield, we don't know how to
3984          * handle them as per the NFSv4 draft spec 07
3985          */
3986         if (bitmap_len > 2)
3987         {
3988                 guint i;
3989
3990                 for (i = 0; i < (bitmap_len-2); i++)
3991                         offset += 4;
3992         }
3993
3994         return offset;
3995 }
3996
3997 int
3998 dissect_nfs_clientaddr4(const u_char *pd, int offset, frame_data *fd,
3999         proto_tree *tree, char *name)
4000 {
4001         offset = dissect_nfs_opaque4(pd, offset, fd, tree, "network id");
4002         offset = dissect_nfs_opaque4(pd, offset, fd, tree, "universal address");
4003
4004         return offset;
4005 }
4006         
4007
4008 int
4009 dissect_nfs_cb_client4(const u_char *pd, int offset, frame_data *fd,
4010         proto_tree *tree, char *name)
4011 {
4012         offset = dissect_rpc_uint32(pd, offset, fd, tree, "cb_program");
4013         offset = dissect_nfs_clientaddr4(pd, offset, fd, tree, "cb_location");
4014
4015         return offset;
4016 }
4017
4018 int
4019 dissect_nfs_stable_how4(const u_char *pd, int offset, frame_data *fd,
4020         proto_tree *tree, char *name)
4021 {
4022         return dissect_rpc_uint32(pd, offset, fd, tree, "stable_how4");
4023 }
4024
4025 int
4026 dissect_nfs_opaque4(const u_char *pd, int offset, frame_data *fd,
4027         proto_tree *tree, char *name)
4028 {
4029         return dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data);
4030 }
4031
4032 /* There is probably a better (built-in?) way to do this, but this works
4033  * for now.
4034  */
4035
4036 static const value_string names_nfsv4_operation[] = {
4037         {       NFS4_OP_ACCESS,                                 "ACCESS"        },
4038         {       NFS4_OP_CLOSE,                                          "CLOSE" },
4039         {       NFS4_OP_COMMIT,                                 "COMMIT"        },
4040         {       NFS4_OP_CREATE,                                 "CREATE"        },
4041         {       NFS4_OP_DELEGPURGE,                             "DELEGPURGE"    },
4042         {       NFS4_OP_DELEGRETURN,                            "DELEGRETURN"   },
4043         {       NFS4_OP_GETATTR,                                        "GETATTR"       },
4044         {       NFS4_OP_GETFH,                                          "GETFH" },
4045         {       NFS4_OP_LINK,                                           "LINK"  },
4046         {       NFS4_OP_LOCK,                                           "LOCK"  },
4047         {       NFS4_OP_LOCKT,                                          "LOCKT" },
4048         {       NFS4_OP_LOCKU,                                          "LOCKU" },
4049         {       NFS4_OP_LOOKUP,                                 "LOOKUP"        },
4050         {       NFS4_OP_NVERIFY,                                        "NVERIFY"       },
4051         {       NFS4_OP_OPEN,                                           "OPEN"  },
4052         {       NFS4_OP_OPENATTR,                                       "OPENATTR"      },
4053         {       NFS4_OP_OPEN_CONFIRM,                   "OPEN_CONFIRM"  },
4054         {       NFS4_OP_OPEN_DOWNGRADE,                 "OPEN_DOWNGRADE"        },
4055         {       NFS4_OP_PUTFH,                                          "PUTFH" },
4056         {       NFS4_OP_PUTPUBFH,                                       "PUTPUBFH"      },
4057         {       NFS4_OP_PUTROOTFH,                              "PUTROOTFH"     },
4058         {       NFS4_OP_READ,                                           "READ"  },
4059         {       NFS4_OP_READDIR,                                        "READDIR"       },
4060         {       NFS4_OP_READLINK,                                       "READLINK"      },
4061         {       NFS4_OP_REMOVE,                                 "REMOVE"        },
4062         {       NFS4_OP_RENAME,                                 "RENAME"        },
4063         {       NFS4_OP_RENEW,                                          "RENEW" },
4064         {       NFS4_OP_RESTOREFH,                              "RESTOREFH"     },
4065         {       NFS4_OP_SAVEFH,                                 "SAVEFH"        },
4066         {       NFS4_OP_SECINFO,                                        "SECINFO"       },
4067         {       NFS4_OP_SETATTR,                                        "SETATTR"       },
4068         {       NFS4_OP_SETCLIENTID,                            "SETCLIENTID"   },
4069         {       NFS4_OP_SETCLIENTID_CONFIRM,    "SETCLIENTID_CONFIRM"   },
4070         {       NFS4_OP_VERIFY,                                 "VERIFY"        },
4071         {       NFS4_OP_WRITE,                                          "WRITE" },
4072         { 0, NULL }
4073 };
4074
4075 guint *nfsv4_operation_ett[] =
4076 {
4077          &ett_nfs_access4 ,
4078          &ett_nfs_close4 ,
4079          &ett_nfs_commit4 ,
4080          &ett_nfs_create4 ,
4081          &ett_nfs_delegpurge4 ,
4082          &ett_nfs_delegreturn4 ,
4083          &ett_nfs_getattr4 ,
4084          &ett_nfs_getfh4 ,
4085          &ett_nfs_link4 ,
4086          &ett_nfs_lock4 ,
4087          &ett_nfs_lockt4 ,
4088          &ett_nfs_locku4 ,
4089          &ett_nfs_lookup4 ,
4090          &ett_nfs_lookupp4 ,
4091          &ett_nfs_nverify4 ,
4092          &ett_nfs_open4 ,
4093          &ett_nfs_openattr4 ,
4094          &ett_nfs_open_confirm4 ,
4095          &ett_nfs_open_downgrade4 ,
4096          &ett_nfs_putfh4 ,
4097          &ett_nfs_putpubfh4 ,
4098          &ett_nfs_putrootfh4 ,
4099          &ett_nfs_read4 ,
4100          &ett_nfs_readdir4 ,
4101          &ett_nfs_readlink4 ,
4102          &ett_nfs_remove4 ,
4103          &ett_nfs_rename4 ,
4104          &ett_nfs_renew4 ,
4105          &ett_nfs_restorefh4 ,
4106          &ett_nfs_savefh4 ,
4107          &ett_nfs_secinfo4 ,
4108          &ett_nfs_setattr4 ,
4109          &ett_nfs_setclientid4 ,
4110          &ett_nfs_setclientid_confirm4 ,
4111          &ett_nfs_verify4 ,
4112          &ett_nfs_write4 
4113 };
4114
4115
4116 int
4117 dissect_nfs_stat4(const u_char *pd, int offset, frame_data *fd, 
4118         proto_tree *tree, char *name)
4119 {
4120         return dissect_rpc_uint32(pd, offset, fd, tree, name);
4121 }
4122
4123 int
4124 dissect_nfs_dirlist4(const u_char *pd, int offset, frame_data *fd,
4125         proto_tree *tree, char *name)
4126 {
4127         proto_tree *newftree = NULL;
4128         guint nextentry;
4129
4130         newftree = proto_item_add_subtree(tree, ett_nfs_dirlist4);
4131         if (newftree==NULL) return offset;
4132
4133         nextentry = EXTRACT_UINT(pd, offset);
4134         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "data follows?");
4135
4136         while (nextentry)
4137         {
4138                 offset = dissect_nfs_cookie4(pd, offset, fd, newftree, "cookie");
4139                 offset = dissect_nfs_component4(pd, offset, fd, newftree, "name");
4140                 offset = dissect_nfs_fattr4(pd, offset, fd, newftree, "attrs");
4141                 nextentry = EXTRACT_UINT(pd, offset);
4142                 offset += 4;
4143         }
4144
4145         return dissect_rpc_uint32(pd, offset, fd, newftree, "eof");
4146 }
4147
4148 int
4149 dissect_nfs_changeid4(const u_char *pd, int offset, frame_data *fd,
4150         proto_tree *tree, char *name)
4151 {
4152         return dissect_rpc_uint64(pd, offset, fd, tree, name);
4153 }
4154
4155 int
4156 dissect_nfs_change_info4(const u_char *pd, int offset, frame_data *fd,
4157         proto_tree *tree, char *name)
4158 {
4159         proto_tree *newftree = NULL;
4160         proto_tree *fitem = NULL;
4161
4162         fitem = proto_tree_add_text(tree, NullTVB, offset, 0, "%s", name);
4163
4164         if (fitem) {
4165                 newftree=proto_item_add_subtree(fitem, ett_nfs_change_info4);
4166
4167                 if (newftree) {
4168                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "atomic? ");
4169                         offset = dissect_nfs_changeid4(pd, offset, fd, newftree, "before");
4170                         offset = dissect_nfs_changeid4(pd, offset, fd, newftree, "after");
4171                 }
4172         }
4173
4174         return offset;
4175 }
4176
4177 int
4178 dissect_nfs_lock4denied(const u_char *pd, int offset, frame_data *fd,
4179         proto_tree *tree, char *name)
4180 {
4181         offset = dissect_nfs_lockowner4(pd, offset, fd, tree, "owner");
4182         offset = dissect_nfs_offset4(pd, offset, fd, tree, "offset");
4183         return dissect_nfs_length4(pd, offset, fd, tree, "length");
4184 }
4185
4186 int
4187 dissect_nfs_acetype4(const u_char *pd, int offset, frame_data *fd,
4188         proto_tree *tree, char *name)
4189 {
4190         return dissect_rpc_uint32(pd, offset, fd, tree, name);
4191 }
4192
4193 int
4194 dissect_nfs_aceflag4(const u_char *pd, int offset, frame_data *fd,
4195         proto_tree *tree, char *name)
4196 {
4197         return dissect_rpc_uint32(pd, offset, fd, tree, name);
4198 }
4199
4200 int
4201 dissect_nfs_acemask4(const u_char *pd, int offset, frame_data *fd,
4202         proto_tree *tree, char *name)
4203 {
4204         return dissect_rpc_uint32(pd, offset, fd, tree, name);
4205 }
4206
4207 int
4208 dissect_nfs_ace4(const u_char *pd, int offset, frame_data *fd, 
4209         proto_tree *tree, char *name)
4210 {
4211         offset = dissect_nfs_acetype4(pd, offset, fd, tree, "type");
4212         offset = dissect_nfs_aceflag4(pd, offset, fd, tree, "flag");
4213         offset = dissect_nfs_acemask4(pd, offset, fd, tree, "access_mask");
4214         return dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_ace4, NULL);
4215 }
4216
4217 int
4218 dissect_nfs_open_read_delegation4(const u_char *pd, int offset, frame_data *fd,
4219         proto_tree *tree)
4220 {
4221         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "State ID");
4222         offset = dissect_rpc_uint32(pd, offset, fd, tree, "recall?");
4223         return dissect_nfs_ace4(pd, offset, fd, tree, "permissions");
4224 }
4225
4226 int
4227 dissect_nfs_modified_limit4(const u_char *pd, int offset, frame_data *fd,
4228         proto_tree *tree, char *name)
4229 {
4230         offset = dissect_rpc_uint32(pd, offset, fd, tree, "num_blocks");
4231         return dissect_rpc_uint32(pd, offset, fd, tree, "bytes_per_block");
4232 }
4233
4234 #define NFS_LIMIT_SIZE                                          1
4235 #define NFS_LIMIT_BLOCKS                                        2
4236 static const value_string names_limit_by4[] = {
4237         {       NFS_LIMIT_SIZE,  "NFS_LIMIT_SIZE"  },
4238         {       NFS_LIMIT_BLOCKS, "NFS_LIMIT_BLOCKS" },
4239         { 0, NULL }
4240 };
4241
4242 int
4243 dissect_nfs_space_limit4(const u_char *pd, int offset, frame_data *fd,
4244         proto_tree *tree, char *name)
4245 {
4246         guint limitby;
4247
4248         limitby = EXTRACT_UINT(pd, offset);
4249         proto_tree_add_uint(tree, hf_nfs_limit_by4, NullTVB, offset+0, 4, limitby);
4250         offset += 4;
4251
4252         switch(limitby)
4253         {
4254         case NFS_LIMIT_SIZE:
4255                 offset = dissect_rpc_uint64(pd, offset, fd, tree, "filesize");
4256                 break;
4257
4258         case NFS_LIMIT_BLOCKS:
4259                 offset = dissect_nfs_modified_limit4(pd, offset, fd, tree, "mod_blocks");
4260                 break;
4261
4262         default:
4263                 break;
4264         }
4265
4266         return offset;
4267 }
4268
4269 int
4270 dissect_nfs_open_write_delegation4(const u_char *pd, int offset, 
4271         frame_data *fd, proto_tree *tree)
4272 {
4273         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "State ID");
4274         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_recall);
4275         offset = dissect_nfs_space_limit4(pd, offset, fd, tree, "space_limit");
4276         return dissect_nfs_ace4(pd, offset, fd, tree, "permissions");
4277 }
4278
4279 #define OPEN_DELEGATE_NONE 0
4280 #define OPEN_DELEGATE_READ 1
4281 #define OPEN_DELEGATE_WRITE 2
4282 static const value_string names_open_delegation_type4[] = {
4283         {       OPEN_DELEGATE_NONE,  "OPEN_DELEGATE_NONE"  },
4284         {       OPEN_DELEGATE_READ,     "OPEN_DELEGATE_READ" },
4285         {       OPEN_DELEGATE_WRITE,    "OPEN_DELEGATE_WRITE" },
4286         { 0, NULL }
4287 };
4288
4289 int
4290 dissect_nfs_open_delegation4(const u_char *pd, int offset, frame_data *fd,
4291         proto_tree *tree, char *name)
4292 {
4293         guint delegation_type;
4294         proto_tree *newftree = NULL;
4295         proto_item *fitem = NULL;
4296
4297         delegation_type = EXTRACT_UINT(pd, offset);
4298         proto_tree_add_uint(tree, hf_nfs_open_delegation_type4, NullTVB, offset+0, 
4299                 4, delegation_type);
4300         offset += 4;
4301
4302         if (fitem) {
4303                 newftree = proto_item_add_subtree(fitem, ett_nfs_open_delegation4);
4304
4305                 switch(delegation_type)
4306                 {
4307                 case OPEN_DELEGATE_NONE:
4308                         break;
4309
4310                 case OPEN_DELEGATE_READ:
4311                         offset = dissect_nfs_open_read_delegation4(pd, offset, fd, newftree);
4312                         break;
4313
4314                 case OPEN_DELEGATE_WRITE:
4315                         offset = dissect_nfs_open_write_delegation4(pd, offset, fd, newftree);
4316                         break;
4317
4318                 default:
4319                         break;
4320                 }
4321         }
4322
4323         return offset;
4324 }
4325
4326
4327 int
4328 dissect_nfs_argop4(const u_char *pd, int offset, frame_data *fd, 
4329         proto_tree *tree, char *name)
4330 {
4331         guint ops, ops_counter;
4332         guint opcode;
4333         proto_item *fitem;
4334         proto_tree *ftree = NULL;
4335         proto_tree *newftree = NULL;
4336
4337         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4338
4339         ops = EXTRACT_UINT(pd, offset+0);
4340
4341         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, 
4342                 "Operations (count: %d)", ops);
4343         offset+=4;
4344
4345         if (fitem == NULL) return offset;
4346
4347         ftree = proto_item_add_subtree(fitem, ett_nfs_argop4);
4348
4349         if (ftree == NULL) return offset;
4350
4351         for (ops_counter=0; ops_counter<ops; ops_counter++)
4352         {
4353                 if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4354
4355                 opcode = EXTRACT_UINT(pd, offset);
4356                 fitem = proto_tree_add_uint(ftree, hf_nfs_argop4, NullTVB, offset, 4, 
4357                         opcode);
4358                 offset += 4;
4359
4360                 if (fitem == NULL)      break;
4361
4362                 newftree = proto_item_add_subtree(fitem, *nfsv4_operation_ett[opcode-3]);
4363
4364                 if (newftree == NULL)   break;
4365
4366                 switch(opcode)
4367                 {
4368                 case NFS4_OP_ACCESS:
4369                         offset = dissect_access(pd, offset, fd, newftree, "access");
4370                         break;
4371
4372                 case NFS4_OP_CLOSE:
4373                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree, "Sequence ID");
4374                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4375                         break;
4376
4377                 case NFS4_OP_COMMIT:
4378                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
4379                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "count");
4380                         break;
4381
4382                 case NFS4_OP_CREATE:
4383                         {
4384                                 guint create_type;
4385
4386                                 offset = dissect_nfs_component4(pd, offset, fd, newftree, 
4387                                         "objname");
4388
4389                                 create_type = EXTRACT_UINT(pd, offset);
4390                                 offset = dissect_nfs_ftype4(pd, offset, fd, newftree, "type");
4391
4392                                 switch(create_type)
4393                                 {
4394                                 case NF4LNK:
4395                                         offset = dissect_nfs_linktext4(pd, offset, fd, newftree, 
4396                                                 "linkdata");
4397                                         break;
4398                                 
4399                                 case NF4BLK:
4400                                 case NF4CHR:
4401                                         offset = dissect_nfs_specdata4(pd, offset, fd, 
4402                                                 newftree, "devdata");
4403                                         break;
4404
4405                                 case NF4SOCK:
4406                                 case NF4FIFO:
4407                                 case NF4DIR:
4408                                         break;
4409
4410                                 default:
4411                                         break;
4412                                 }
4413                         }
4414                         break;
4415
4416                 case NFS4_OP_DELEGPURGE:
4417                         offset = dissect_nfs_clientid4(pd, offset, fd, newftree, "Client ID");
4418                         break;
4419
4420                 case NFS4_OP_DELEGRETURN:
4421                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4422                         break;
4423
4424                 case NFS4_OP_GETATTR:
4425                         offset = dissect_nfs_bitmap4(pd, offset, fd, newftree, "attr_request");
4426                         break;
4427
4428                 case NFS4_OP_GETFH:
4429                         break;
4430
4431                 case NFS4_OP_LINK:
4432                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "newname");
4433                         break;
4434
4435                 case NFS4_OP_LOCK:
4436                         offset = dissect_nfs_lock_type4(pd, offset, fd, newftree, "locktype");
4437                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree, "Sequence ID");
4438                         offset = dissect_nfs_reclaim4(pd, offset, fd, newftree, "reclaim");
4439                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4440                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
4441                         offset = dissect_nfs_length4(pd, offset, fd, newftree, "length");
4442                         break;
4443
4444                 case NFS4_OP_LOCKT:
4445                         offset = dissect_nfs_lock_type4(pd, offset, fd, newftree, "locktype");
4446                         offset = dissect_nfs_lockowner4(pd, offset, fd, newftree, "owner");
4447                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
4448                         offset = dissect_nfs_length4(pd, offset, fd, newftree, "length");
4449                         break;
4450
4451                 case NFS4_OP_LOCKU:
4452                         offset = dissect_nfs_lock_type4(pd, offset, fd, newftree, "type");
4453                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree, "Sequence ID");
4454                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4455                         offset =        dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
4456                         offset = dissect_nfs_length4(pd, offset, fd, newftree, "length");
4457                         break;
4458
4459                 case NFS4_OP_LOOKUP:
4460                         offset = dissect_nfs_pathname4(pd, offset, fd, newftree, "path");
4461                         break;
4462
4463                 case NFS4_OP_LOOKUPP:
4464                         break;
4465
4466                 case NFS4_OP_NVERIFY:
4467                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
4468                                 "obj_attributes");
4469                         break;
4470
4471                 case NFS4_OP_OPEN:
4472                         offset = dissect_nfs_open_claim4(pd, offset, fd, newftree, "claim");
4473                         offset = dissect_nfs_openflag4(pd, offset, fd, newftree);
4474                         offset = dissect_nfs_lockowner4(pd, offset, fd, newftree, "Owner");
4475                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree, "Sequence ID");
4476                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "Share Access");
4477                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "Share Deny");
4478                         break;
4479
4480                 case NFS4_OP_OPENATTR:
4481                         break;
4482
4483                 case NFS4_OP_OPEN_CONFIRM:
4484                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree, "Sequence ID");
4485                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, 
4486                                 "open_confirm");
4487                         break;
4488
4489                 case NFS4_OP_OPEN_DOWNGRADE:
4490                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4491                         offset = dissect_nfs_seqid4(pd, offset, fd, newftree, "Sequence ID");
4492                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "Share Access");
4493                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "Share Deny");
4494                         break;
4495
4496                 case NFS4_OP_PUTFH:
4497                         offset = dissect_nfs_fh4(pd, offset, fd, newftree, "filehandle");
4498                         break;
4499
4500                 case NFS4_OP_PUTPUBFH:
4501                 case NFS4_OP_PUTROOTFH:
4502                         break;
4503
4504                 case NFS4_OP_READ:
4505                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4506                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
4507                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "count");
4508                         break;
4509
4510                 case NFS4_OP_READDIR:
4511                         offset = dissect_nfs_cookie4(pd, offset, fd, newftree, "cookie");
4512                         offset = dissect_nfs_cookieverf4(pd, offset, fd, newftree, 
4513                                 "cookieverf");
4514                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "dircount");
4515                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "maxcount");
4516                         offset = dissect_nfs_bitmap4(pd, offset, fd, newftree, "attr");
4517                         break;
4518
4519                 case NFS4_OP_READLINK:
4520                         break;
4521
4522                 case NFS4_OP_REMOVE:
4523                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "target");
4524                         break;
4525
4526                 case NFS4_OP_RENAME:
4527                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "oldname");
4528                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "newname");
4529                         break;
4530
4531                 case NFS4_OP_RENEW:
4532                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4533                         break;
4534         
4535                 case NFS4_OP_RESTOREFH:
4536                 case NFS4_OP_SAVEFH:
4537                         break;
4538
4539                 case NFS4_OP_SECINFO:
4540                         offset = dissect_nfs_component4(pd, offset, fd, newftree, "name");
4541                         break;
4542
4543                 case NFS4_OP_SETATTR:
4544                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4545                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
4546                                 "obj_attributes");
4547                         break;
4548
4549                 case NFS4_OP_SETCLIENTID:
4550                         {
4551                                 proto_tree *client_tree = NULL;
4552
4553                                 fitem = proto_tree_add_text(newftree, NullTVB, offset, 0, "Client");
4554
4555                                 if (fitem) {
4556                                         client_tree = proto_item_add_subtree(fitem, 
4557                                                 ett_nfs_client_id4);
4558
4559                                         if (newftree)
4560                                                 offset = dissect_nfs_client_id4(pd, offset, fd, 
4561                                                         client_tree, "client");
4562                                 }
4563
4564                                 fitem = proto_tree_add_text(newftree, NullTVB, offset, 0,
4565                                         "Callback");
4566                                 if (fitem) {
4567                                         newftree = proto_item_add_subtree(fitem, ett_nfs_cb_client4);
4568                                         if (newftree)
4569                                                 offset = dissect_nfs_cb_client4(pd, offset, fd, newftree, 
4570                                                         "callback");
4571                                 }
4572                         }
4573                         break;
4574
4575                 case NFS4_OP_SETCLIENTID_CONFIRM:
4576                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree,
4577                                                 "setclientid_confirm");
4578                         break;
4579                 
4580                 case NFS4_OP_VERIFY:
4581                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
4582                                                 "obj_attributes");
4583                         break;
4584
4585                 case NFS4_OP_WRITE:
4586                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4587                         offset = dissect_nfs_offset4(pd, offset, fd, newftree, "offset");
4588                         offset = dissect_nfs_stable_how4(pd, offset, fd, newftree, "stable");
4589                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "data");
4590                         break;
4591                 
4592                 default:
4593                         break;
4594                 }
4595         }
4596
4597         return offset;
4598 }
4599
4600 int
4601 dissect_nfs4_compound_call(const u_char* pd, int offset, frame_data* fd, 
4602         proto_tree* tree)
4603 {
4604         offset = dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_tag4, NULL);
4605         offset = dissect_rpc_uint32(pd, offset, fd, tree, "minorversion");
4606         offset = dissect_nfs_argop4(pd, offset, fd, tree, "arguments");
4607
4608         return offset;
4609 }
4610
4611 static const value_string names_nfsstat4[] = {
4612         {       0,                      "NFS4_OK"                                                       },
4613         {       1,                      "NFS4ERR_PERM"                                          },
4614         {       2,                      "NFS4ERR_NOENT"                                 },
4615         {       5,                      "NFS4ERR_IO"                                            },
4616         {       6,                      "NFS4ERR_NXIO"                                          },
4617         {       13,             "NFS4ERR_ACCES"                                 },
4618         {       17,             "NFS4ERR_EXIST"                                 },
4619         {       18,             "NFS4ERR_XDEV"                                          },
4620         {       19,             "NFS4ERR_NODEV"                                 },
4621         {       20,             "NFS4ERR_NOTDIR"                                        },
4622         {       21,             "NFS4ERR_ISDIR"                                 },
4623         {       22,             "NFS4ERR_INVAL"                                 },
4624         {       27,             "NFS4ERR_FBIG"                                          },
4625         {       28,             "NFS4ERR_NOSPC"                                 },
4626         {       30,             "NFS4ERR_ROFS"                                          },
4627         {       31,             "NFS4ERR_MLINK"                                 },
4628         {       63,             "NFS4ERR_NAMETOOLONG"                   },
4629         {       66,             "NFS4ERR_NOTEMPTY"                              },
4630         {       69,             "NFS4ERR_DQUOT"                                 },
4631         {       70,             "NFS4ERR_STALE"                                 },
4632         {       10001,  "NFS4ERR_BADHANDLE"                             },
4633         {       10003,  "NFS4ERR_BAD_COOKIE"                            },
4634         {       10004,  "NFS4ERR_NOTSUPP"                                       },
4635         {       10005,  "NFS4ERR_TOOSMALL"                              },
4636         {       10006,  "NFS4ERR_SERVERFAULT"                   },
4637         {       10007,  "NFS4ERR_BADTYPE"                                       },
4638         {       10008,  "NFS4ERR_DELAY"                                 },
4639         {       10009,  "NFS4ERR_SAME"                                          },
4640         {       10010,  "NFS4ERR_DENIED"                                        },
4641         {       10011,  "NFS4ERR_EXPIRED"                                       },
4642         {       10012,  "NFS4ERR_LOCKED"                                        },
4643         {       10013,  "NFS4ERR_GRACE"                                 },
4644         {       10014,  "NFS4ERR_FHEXPIRED"                             },
4645         {       10015,  "NFS4ERR_SHARE_DENIED"                  },
4646         {       10016,  "NFS4ERR_WRONGSEC"                              },
4647         {       10017,  "NFS4ERR_CLID_INUSE"                            },
4648         {       10018,  "NFS4ERR_RESOURCE"                              },
4649         {       10019,  "NFS4ERR_MOVED"                                 },
4650         {       10020,  "NFS4ERR_NOFILEHANDLE"                  },
4651         {       10021,  "NFS4ERR_MINOR_VERS_MISMATCH"   },
4652         {       10022,  "NFS4ERR_STALE_CLIENTID"                },
4653         {       10023,  "NFS4ERR_STALE_STATEID"                 },
4654         {       10024,  "NFS4ERR_OLD_STATEID"                   },
4655         {       10025,  "NFS4ERR_BAD_STATEID"                   },
4656         {       10026,  "NFS4ERR_BAD_SEQID"                             },
4657         {       10027,  "NFS4ERR_NOT_SAME"                              },
4658         {       10028,  "NFS4ERR_LOCK_RANGE"                            },
4659         {       10029,  "NFS4ERR_SYMLINK"                                       },
4660         {       10030,  "NFS4ERR_READDIR_NOSPC"                 },
4661         {       10031,  "NFS4ERR_LEASE_MOVED"                   },
4662         { 0, NULL }
4663 };
4664
4665 int
4666 dissect_nfs_nfsstat4(const u_char *pd, int offset, frame_data *fd, 
4667         proto_tree *tree)
4668 {
4669         guint status;
4670
4671         status = EXTRACT_UINT(pd, offset);
4672         proto_tree_add_uint(tree, hf_nfs_nfsstat4, NullTVB, offset, 4, status);
4673         offset += 4;
4674
4675         return offset;
4676 }
4677
4678 int
4679 dissect_nfs_resop4(const u_char *pd, int offset, frame_data *fd, 
4680         proto_tree *tree, char *name)
4681 {
4682         guint ops, ops_counter;
4683         guint opcode;
4684         proto_item *fitem;
4685         proto_tree *ftree = NULL;
4686         proto_tree *newftree = NULL;
4687         guint status;
4688
4689         ops = EXTRACT_UINT(pd, offset+0);
4690
4691         fitem = proto_tree_add_text(tree, NullTVB, offset, 4, 
4692                 "Operations (count: %d)", ops);
4693         offset += 4;
4694
4695         if (fitem == NULL)      return offset;
4696
4697         ftree = proto_item_add_subtree(fitem, ett_nfs_resop4);
4698
4699         if (ftree == NULL)      return offset;          /* error adding new subtree */
4700
4701         for (ops_counter = 0; ops_counter < ops; ops_counter++)
4702         {
4703                 if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4704
4705                 opcode = EXTRACT_UINT(pd, offset);
4706
4707                 if (opcode < NFS4_OP_ACCESS || opcode > NFS4_OP_WRITE)  break;
4708
4709                 if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
4710
4711                 fitem = proto_tree_add_uint(ftree, hf_nfs_resop4, NullTVB, offset, 4, 
4712                         opcode);
4713                 offset += 4;
4714
4715                 if (fitem == NULL)      break;          /* error adding new item to tree */
4716
4717                 newftree = proto_item_add_subtree(fitem, *nfsv4_operation_ett[opcode-3]);
4718
4719                 if (newftree == NULL)
4720                         break;          /* error adding new subtree to operation item */
4721
4722                 status = EXTRACT_UINT(pd, offset);
4723                 offset = dissect_nfs_nfsstat4(pd, offset, fd, newftree);
4724
4725                 if (status != NFS4_OK && 
4726                         (opcode != NFS4_OP_LOCK || opcode != NFS4_OP_LOCKT))
4727                         continue;
4728
4729                 /* These parsing routines are only executed if the status is NFS4_OK */
4730                 switch(opcode)
4731                 {
4732                 case NFS4_OP_ACCESS:
4733                         offset = dissect_access(pd, offset, fd, newftree, "Supported");
4734                         offset = dissect_access(pd, offset, fd, newftree, "Access");
4735                         break;
4736
4737                 case NFS4_OP_CLOSE:
4738                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4739                         break;
4740
4741                 case NFS4_OP_COMMIT:
4742                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, "writeverf");
4743                         break;
4744
4745                 case NFS4_OP_CREATE:
4746                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, "cinfo");
4747                         break;
4748
4749                 case NFS4_OP_DELEGPURGE:
4750                         /* void */
4751                         break;
4752
4753                 case NFS4_OP_DELEGRETURN:
4754                         /* void */
4755                         break;
4756
4757                 case NFS4_OP_GETATTR:
4758                         offset = dissect_nfs_fattr4(pd, offset, fd, newftree, 
4759                                 "obj_attributes");
4760                         break;
4761
4762                 case NFS4_OP_GETFH:
4763                         offset = dissect_nfs_fh4(pd, offset, fd, newftree, "Filehandle");
4764                         break;
4765
4766                 case NFS4_OP_LINK:
4767                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, "cinfo");
4768                         break;
4769
4770                 case NFS4_OP_LOCK:
4771                 case NFS4_OP_LOCKT:
4772                         if (status==NFS4_OK)
4773                                 offset = dissect_nfs_stateid4(pd, offset, fd, newftree, 
4774                                         "State ID");
4775                         else
4776                         if (status==NFS4ERR_DENIED)
4777                                 offset = dissect_nfs_lock4denied(pd, offset, fd, newftree, 
4778                                         "denied");
4779                         break;
4780
4781                 case NFS4_OP_LOCKU:
4782                         offset = dissect_nfs_stateid4(pd, offset, fd, newftree, "State ID");
4783                         break;
4784
4785                 case NFS4_OP_LOOKUP:
4786                         /* void */
4787                         break;
4788
4789                 case NFS4_OP_LOOKUPP:
4790                         /* void */
4791                         break;
4792
4793                 case NFS4_OP_NVERIFY:
4794                         /* void */
4795                         break;
4796
4797                 case NFS4_OP_OPEN:
4798                         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "State ID");
4799                         offset = dissect_nfs_change_info4(pd, offset, fd, tree, "cinfo");
4800                         offset = dissect_rpc_uint32(pd, offset, fd, tree, "rflags");
4801                         offset = dissect_nfs_verifier4(pd, offset, fd, tree, "open_confirm");
4802                         offset = dissect_nfs_open_delegation4(pd, offset, fd, tree, 
4803                                 "delegation");
4804                         break;
4805
4806                 case NFS4_OP_OPENATTR:
4807                         /* void */
4808                         break;
4809
4810                 case NFS4_OP_OPEN_CONFIRM:
4811                 case NFS4_OP_OPEN_DOWNGRADE:
4812                         offset = dissect_nfs_stateid4(pd, offset, fd, tree, "State ID");
4813                         break;
4814
4815                 case NFS4_OP_PUTFH:
4816                         /* void */
4817                         break;
4818
4819                 case NFS4_OP_PUTPUBFH:
4820                         /* void */
4821                         break;
4822                 
4823                 case NFS4_OP_PUTROOTFH:
4824                         /* void */
4825                         break;
4826
4827                 case NFS4_OP_READ:
4828                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "eof?");
4829                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "data");
4830                         break;
4831
4832                 case NFS4_OP_READDIR:
4833                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree, 
4834                                 "cookieverf");
4835                         offset = dissect_nfs_dirlist4(pd, offset, fd, newftree, "reply");
4836                         break;
4837
4838                 case NFS4_OP_READLINK:
4839                         offset = dissect_nfs_linktext4(pd, offset, fd, newftree, "link");       
4840                         break;
4841
4842                 case NFS4_OP_REMOVE:
4843                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, "cinfo");
4844                         break;
4845
4846                 case NFS4_OP_RENAME:
4847                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree, 
4848                                 "source_cinfo");
4849                         offset = dissect_nfs_change_info4(pd, offset, fd, newftree,
4850                                 "target_cinfo");
4851                         break;
4852
4853                 case NFS4_OP_RENEW:
4854                         /* void */
4855                         break;
4856
4857                 case NFS4_OP_RESTOREFH:
4858                         /* void */
4859                         break;
4860
4861                 case NFS4_OP_SAVEFH:
4862                         /* void */
4863                         break;
4864
4865                 case NFS4_OP_SECINFO:
4866                         offset = dissect_rpc_uint32(pd, offset, fd, newftree, "flavor");
4867                         offset = dissect_nfs_opaque4(pd, offset, fd, newftree, "flavor_info");
4868                         break;
4869
4870                 case NFS4_OP_SETATTR:
4871                         offset = dissect_nfs_bitmap4(pd, offset, fd, newftree, "attrsset");
4872                         break;
4873
4874                 case NFS4_OP_SETCLIENTID:
4875                         if (status == NFS4_OK)
4876                         {
4877                                 offset = dissect_nfs_clientid4(pd, offset, fd, newftree, 
4878                                         "Client ID");
4879                                 offset = dissect_nfs_verifier4(pd, offset, fd, newftree,
4880                                         "setclientid_confirm");
4881                         }
4882                         else
4883                         if (status == NFS4ERR_CLID_INUSE)
4884                         {
4885                                 offset = dissect_nfs_clientaddr4(pd, offset, fd, newftree,
4886                                         "client_using");
4887                         }
4888                         break;
4889
4890                 case NFS4_OP_SETCLIENTID_CONFIRM:
4891                         /* void */
4892                         break;
4893
4894                 case NFS4_OP_VERIFY:
4895                         /* void */
4896                         break;
4897
4898                 case NFS4_OP_WRITE:
4899                         offset = dissect_nfs_count4(pd, offset, fd, newftree, "count");
4900                         offset = dissect_nfs_stable_how4(pd, offset, fd, newftree, 
4901                                 "committed");
4902                         offset = dissect_nfs_verifier4(pd, offset, fd, newftree,
4903                                 "writeverf");
4904                         break;
4905
4906                 default:
4907                         break;
4908                 }
4909         }
4910
4911         return offset;
4912 }
4913
4914 int
4915 dissect_nfs4_compound_reply(const u_char* pd, int offset, frame_data* fd, 
4916         proto_tree* tree)
4917 {
4918         offset = dissect_nfs_nfsstat4(pd, offset, fd, tree);
4919         offset = dissect_nfs_utf8string(pd, offset, fd, tree, hf_nfs_tag4, NULL);
4920         offset = dissect_nfs_resop4(pd, offset, fd, tree, "arguments");
4921
4922         return offset;
4923 }
4924
4925
4926 /* proc number, "proc name", dissect_request, dissect_reply */
4927 /* NULL as function pointer means: take the generic one. */
4928 const vsff nfs3_proc[] = {
4929         { 0,    "NULL",         /* OK */
4930         NULL,                           NULL },
4931         { 1,    "GETATTR",      /* OK */
4932         dissect_nfs3_getattr_call,      dissect_nfs3_getattr_reply },
4933         { 2,    "SETATTR",      /* OK */
4934         dissect_nfs3_setattr_call,      dissect_nfs3_setattr_reply },
4935         { 3,    "LOOKUP",       /* OK */
4936         dissect_nfs3_lookup_call,       dissect_nfs3_lookup_reply },
4937         { 4,    "ACCESS",       /* OK */
4938         dissect_nfs3_access_call,       dissect_nfs3_access_reply },
4939         { 5,    "READLINK",     /* OK */
4940         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_readlink_reply },
4941         { 6,    "READ",         /* OK */
4942         dissect_nfs3_read_call,         dissect_nfs3_read_reply },
4943         { 7,    "WRITE",        /* OK */
4944         dissect_nfs3_write_call,        dissect_nfs3_write_reply },
4945         { 8,    "CREATE",       /* OK */
4946         dissect_nfs3_create_call,       dissect_nfs3_create_reply },
4947         { 9,    "MKDIR",        /* OK */
4948         dissect_nfs3_mkdir_call,        dissect_nfs3_create_reply },
4949         { 10,   "SYMLINK",      /* OK */
4950         dissect_nfs3_symlink_call,      dissect_nfs3_create_reply },
4951         { 11,   "MKNOD",        /* OK */
4952         dissect_nfs3_mknod_call,        dissect_nfs3_create_reply },
4953         { 12,   "REMOVE",       /* OK */
4954         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
4955         { 13,   "RMDIR",        /* OK */
4956         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
4957         { 14,   "RENAME",       /* OK */
4958         dissect_nfs3_rename_call,       dissect_nfs3_rename_reply },
4959         { 15,   "LINK",         /* OK */
4960         dissect_nfs3_link_call,         dissect_nfs3_link_reply },
4961         { 16,   "READDIR",      /* OK */
4962         dissect_nfs3_readdir_call,      dissect_nfs3_readdir_reply },
4963         { 17,   "READDIRPLUS",  /* OK */
4964         dissect_nfs3_readdirplus_call,  dissect_nfs3_readdirplus_reply },
4965         { 18,   "FSSTAT",       /* OK */
4966         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsstat_reply },
4967         { 19,   "FSINFO",       /* OK */
4968         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsinfo_reply },
4969         { 20,   "PATHCONF",     /* OK */
4970         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_pathconf_reply },
4971         { 21,   "COMMIT",       /* OK */
4972         dissect_nfs3_commit_call,       dissect_nfs3_commit_reply },
4973         { 0,NULL,NULL,NULL }
4974 };
4975 /* end of NFS Version 3 */
4976
4977 const vsff nfs4_proc[] = {
4978         { 0, "NULL",
4979         NULL, NULL },
4980         { 1, "COMPOUND",
4981         dissect_nfs4_compound_call, dissect_nfs4_compound_reply },
4982         { 0, NULL, NULL, NULL }
4983 };
4984
4985
4986 static struct true_false_string yesno = { "Yes", "No" };
4987
4988
4989 void
4990 proto_register_nfs(void)
4991 {
4992         static hf_register_info hf[] = {
4993                 { &hf_nfs_fh_fsid_major, {
4994                         "major", "nfs.fh.fsid.major", FT_UINT32, BASE_DEC,
4995                         NULL, 0, "major file system ID" }},
4996                 { &hf_nfs_fh_fsid_minor, {
4997                         "minor", "nfs.fh.fsid.minor", FT_UINT32, BASE_DEC,
4998                         NULL, 0, "minor file system ID" }},
4999                 { &hf_nfs_fh_xfsid_major, {
5000                         "exported major", "nfs.fh.xfsid.major", FT_UINT32, BASE_DEC,
5001                         NULL, 0, "exported major file system ID" }},
5002                 { &hf_nfs_fh_xfsid_minor, {
5003                         "exported minor", "nfs.fh.xfsid.minor", FT_UINT32, BASE_DEC,
5004                         NULL, 0, "exported minor file system ID" }},
5005                 { &hf_nfs_fh_fstype, {
5006                         "file system type", "nfs.fh.fstype", FT_UINT32, BASE_DEC,
5007                         NULL, 0, "file system type" }},
5008                 { &hf_nfs_fh_fn, {
5009                         "file number", "nfs.fh.fn", FT_UINT32, BASE_DEC,
5010                         NULL, 0, "file number" }},
5011                 { &hf_nfs_fh_fn_len, {
5012                         "length", "nfs.fh.fn.len", FT_UINT32, BASE_DEC,
5013                         NULL, 0, "file number length" }},
5014                 { &hf_nfs_fh_fn_inode, {
5015                         "inode", "nfs.fh.fn.inode", FT_UINT32, BASE_DEC,
5016                         NULL, 0, "file number inode" }},
5017                 { &hf_nfs_fh_fn_generation, {
5018                         "generation", "nfs.fh.fn.generation", FT_UINT32, BASE_DEC,
5019                         NULL, 0, "file number generation" }},
5020                 { &hf_nfs_fh_xfn, {
5021                         "exported file number", "nfs.fh.xfn", FT_UINT32, BASE_DEC,
5022                         NULL, 0, "exported file number" }},
5023                 { &hf_nfs_fh_xfn_len, {
5024                         "length", "nfs.fh.xfn.len", FT_UINT32, BASE_DEC,
5025                         NULL, 0, "exported file number length" }},
5026                 { &hf_nfs_fh_xfn_inode, {
5027                         "exported inode", "nfs.fh.xfn.inode", FT_UINT32, BASE_DEC,
5028                         NULL, 0, "exported file number inode" }},
5029                 { &hf_nfs_fh_xfn_generation, {
5030                         "generation", "nfs.fh.xfn.generation", FT_UINT32, BASE_DEC,
5031                         NULL, 0, "exported file number generation" }},
5032                 { &hf_nfs_fh_dentry, {
5033                         "dentry", "nfs.fh.dentry", FT_UINT32, BASE_HEX,
5034                         NULL, 0, "dentry (cookie)" }},
5035                 { &hf_nfs_fh_dev, {
5036                         "device", "nfs.fh.dev", FT_UINT32, BASE_DEC,
5037                         NULL, 0, "device" }},
5038                 { &hf_nfs_fh_xdev, {
5039                         "exported device", "nfs.fh.xdev", FT_UINT32, BASE_DEC,
5040                         NULL, 0, "exported device" }},
5041                 { &hf_nfs_fh_dirinode, {
5042                         "directory inode", "nfs.fh.dirinode", FT_UINT32, BASE_DEC,
5043                         NULL, 0, "directory inode" }},
5044                 { &hf_nfs_fh_pinode, {
5045                         "pseudo inode", "nfs.fh.pinode", FT_UINT32, BASE_HEX,
5046                         NULL, 0, "pseudo inode" }},
5047                 { &hf_nfs_fh_hp_len, {
5048                         "length", "nfs.fh.hp.len", FT_UINT32, BASE_DEC,
5049                         NULL, 0, "hash path length" }},
5050                 { &hf_nfs_stat, {
5051                         "Status", "nfs.status2", FT_UINT32, BASE_DEC,
5052                         VALS(names_nfs_stat), 0, "Reply status" }},
5053                 { &hf_nfs_name, {
5054                         "Name", "nfs.name", FT_STRING, BASE_DEC,
5055                         NULL, 0, "Name" }},
5056                 { &hf_nfs_readlink_data, {
5057                         "Data", "nfs.readlink.data", FT_STRING, BASE_DEC,
5058                         NULL, 0, "Symbolic Link Data" }},
5059                 { &hf_nfs_read_offset, {
5060                         "Offset", "nfs.read.offset", FT_UINT32, BASE_DEC,
5061                         NULL, 0, "Read Offset" }},
5062                 { &hf_nfs_read_count, {
5063                         "Count", "nfs.read.count", FT_UINT32, BASE_DEC,
5064                         NULL, 0, "Read Count" }},
5065                 { &hf_nfs_read_totalcount, {
5066                         "Total Count", "nfs.read.totalcount", FT_UINT32, BASE_DEC,
5067                         NULL, 0, "Total Count (obsolete)" }},
5068                 { &hf_nfs_data, {
5069                         "Data", "nfs.data", FT_STRING, BASE_DEC,
5070                         NULL, 0, "Data" }},
5071                 { &hf_nfs_write_beginoffset, {
5072                         "Begin Offset", "nfs.write.beginoffset", FT_UINT32, BASE_DEC,
5073                         NULL, 0, "Begin offset (obsolete)" }},
5074                 { &hf_nfs_write_offset, {
5075                         "Offset", "nfs.write.offset", FT_UINT32, BASE_DEC,
5076                         NULL, 0, "Offset" }},
5077                 { &hf_nfs_write_totalcount, {
5078                         "Total Count", "nfs.write.totalcount", FT_UINT32, BASE_DEC,
5079                         NULL, 0, "Total Count (obsolete)" }},
5080                 { &hf_nfs_symlink_to, {
5081                         "To", "nfs.symlink.to", FT_STRING, BASE_DEC,
5082                         NULL, 0, "Symbolic link destination name" }},
5083                 { &hf_nfs_readdir_cookie, {
5084                         "Cookie", "nfs.readdir.cookie", FT_UINT32, BASE_DEC,
5085                         NULL, 0, "Directory Cookie" }},
5086                 { &hf_nfs_readdir_count, {
5087                         "Count", "nfs.readdir.count", FT_UINT32, BASE_DEC,
5088                         NULL, 0, "Directory Count" }},
5089                 { &hf_nfs_readdir_entry, {
5090                         "Entry", "nfs.readdir.entry", FT_NONE, 0,
5091                         NULL, 0, "Directory Entry" }},
5092                 { &hf_nfs_readdir_entry_fileid, {
5093                         "File ID", "nfs.readdir.entry.fileid", FT_UINT32, BASE_DEC,
5094                         NULL, 0, "File ID" }},
5095                 { &hf_nfs_readdir_entry_name, {
5096                         "Name", "nfs.readdir.entry.name", FT_STRING, BASE_DEC,
5097                         NULL, 0, "Name" }},
5098                 { &hf_nfs_readdirplus_entry_name, {
5099                         "Name", "nfs.readdirplus.entry.name", FT_STRING, BASE_DEC,
5100                         NULL, 0, "Name" }},
5101                 { &hf_nfs_readdir_entry_cookie, {
5102                         "Cookie", "nfs.readdir.entry.cookie", FT_UINT32, BASE_DEC,
5103                         NULL, 0, "Directory Cookie" }},
5104                 { &hf_nfs_readdir_eof, {
5105                         "EOF", "nfs.readdir.eof", FT_UINT32, BASE_DEC,
5106                         NULL, 0, "EOF" }},
5107                 { &hf_nfs_statfs_tsize, {
5108                         "Transfer Size", "nfs.statfs.tsize", FT_UINT32, BASE_DEC,
5109                         NULL, 0, "Transfer Size" }},
5110                 { &hf_nfs_statfs_bsize, {
5111                         "Block Size", "nfs.statfs.bsize", FT_UINT32, BASE_DEC,
5112                         NULL, 0, "Block Size" }},
5113                 { &hf_nfs_statfs_blocks, {
5114                         "Total Blocks", "nfs.statfs.blocks", FT_UINT32, BASE_DEC,
5115                         NULL, 0, "Total Blocks" }},
5116                 { &hf_nfs_statfs_bfree, {
5117                         "Free Blocks", "nfs.statfs.bfree", FT_UINT32, BASE_DEC,
5118                         NULL, 0, "Free Blocks" }},
5119                 { &hf_nfs_statfs_bavail, {
5120                         "Available Blocks", "nfs.statfs.bavail", FT_UINT32, BASE_DEC,
5121                         NULL, 0, "Available Blocks" }},
5122                 { &hf_nfs_ftype3, {
5123                         "Type", "nfs.type", FT_UINT32, BASE_DEC,
5124                         VALS(names_nfs_ftype3), 0, "File Type" }},
5125                 { &hf_nfs_nfsstat3, {
5126                         "Status", "nfs.status", FT_UINT32, BASE_DEC,
5127                         VALS(names_nfs_nfsstat3), 0, "Reply status" }},
5128                 { &hf_nfs_read_eof, {
5129                         "EOF", "nfs.read.eof", FT_BOOLEAN, BASE_NONE,
5130                         &yesno, 0, "EOF" }},
5131                 { &hf_nfs_write_stable, {
5132                         "Stable", "nfs.write.stable", FT_UINT32, BASE_DEC,
5133                         VALS(names_stable_how), 0, "Stable" }},
5134                 { &hf_nfs_write_committed, {
5135                         "Committed", "nfs.write.committed", FT_UINT32, BASE_DEC,
5136                         VALS(names_stable_how), 0, "Committed" }},
5137                 { &hf_nfs_createmode3, {
5138                         "Create Mode", "nfs.createmode", FT_UINT32, BASE_DEC,
5139                         VALS(names_createmode3), 0, "Create Mode" }},
5140                 { &hf_nfs_fsstat_invarsec, {
5141                         "invarsec", "nfs.fsstat.invarsec", FT_UINT32, BASE_DEC,
5142                         NULL, 0, "probable number of seconds of file system invariance" }},
5143                 { &hf_nfs_fsinfo_rtmax, {
5144                         "rtmax", "nfs.fsinfo.rtmax", FT_UINT32, BASE_DEC,
5145                         NULL, 0, "maximum READ request" }},
5146                 { &hf_nfs_fsinfo_rtpref, {
5147                         "rtpref", "nfs.fsinfo.rtpref", FT_UINT32, BASE_DEC,
5148                         NULL, 0, "preferred READ request" }},
5149                 { &hf_nfs_fsinfo_rtmult, {
5150                         "rtmult", "nfs.fsinfo.rtmult", FT_UINT32, BASE_DEC,
5151                         NULL, 0, "suggested READ multiple" }},
5152                 { &hf_nfs_fsinfo_wtmax, {
5153                         "wtmax", "nfs.fsinfo.wtmax", FT_UINT32, BASE_DEC,
5154                         NULL, 0, "maximum WRITE request" }},
5155                 { &hf_nfs_fsinfo_wtpref, {
5156                         "wtpref", "nfs.fsinfo.wtpref", FT_UINT32, BASE_DEC,
5157                         NULL, 0, "preferred WRITE request" }},
5158                 { &hf_nfs_fsinfo_wtmult, {
5159                         "wtmult", "nfs.fsinfo.wtmult", FT_UINT32, BASE_DEC,
5160                         NULL, 0, "suggested WRITE multiple" }},
5161                 { &hf_nfs_fsinfo_dtpref, {
5162                         "dtpref", "nfs.fsinfo.dtpref", FT_UINT32, BASE_DEC,
5163                         NULL, 0, "preferred READDIR request" }},
5164                 { &hf_nfs_fsinfo_properties, {
5165                         "Properties", "nfs.fsinfo.propeties", FT_UINT32, BASE_HEX,
5166                         NULL, 0, "File System Properties" }},
5167                 { &hf_nfs_pathconf_linkmax, {
5168                         "linkmax", "nfs.pathconf.linkmax", FT_UINT32, BASE_DEC,
5169                         NULL, 0, "Maximum number of hard links" }},
5170                 { &hf_nfs_pathconf_name_max, {
5171                         "name_max", "nfs.pathconf.name_max", FT_UINT32, BASE_DEC,
5172                         NULL, 0, "Maximum file name length" }},
5173                 { &hf_nfs_pathconf_no_trunc, {
5174                         "no_trunc", "nfs.pathconf.no_trunc", FT_BOOLEAN, BASE_NONE,
5175                         &yesno, 0, "No long file name truncation" }},
5176                 { &hf_nfs_pathconf_chown_restricted, {
5177                         "chown_restricted", "nfs.pathconf.chown_restricted", FT_BOOLEAN, BASE_NONE,
5178                         &yesno, 0, "chown is restricted to root" }},
5179                 { &hf_nfs_pathconf_case_insensitive, {
5180                         "case_insensitive", "nfs.pathconf.case_insensitive", FT_BOOLEAN, BASE_NONE,
5181                         &yesno, 0, "file names are treated case insensitive" }},
5182                 { &hf_nfs_pathconf_case_preserving, {
5183                         "case_preserving", "nfs.pathconf.case_preserving", FT_BOOLEAN, BASE_NONE,
5184                         &yesno, 0, "file name cases are preserved" }},
5185
5186                 /* NFSv4 */
5187
5188                 { &hf_nfs_argop4, {
5189                         "Opcode", "nfs.call.operation", FT_UINT32, BASE_DEC,
5190                         VALS(names_nfsv4_operation), 0, "Opcode" }},
5191
5192                 { &hf_nfs_resop4,       {
5193                         "Opcode", "nfs.reply.operation", FT_UINT32, BASE_DEC,
5194                         VALS(names_nfsv4_operation), 0, "Opcode" }},
5195
5196                 { &hf_nfs_linktext4, {
5197                         "Name", "nfs.symlink.linktext", FT_STRING, BASE_DEC,
5198                         NULL, 0, "Symbolic link contents" }},
5199
5200                 { &hf_nfs_component4, {
5201                         "Filename", "nfs.pathname.component", FT_STRING, BASE_DEC,
5202                         NULL, 0, "Pathname component" }},
5203
5204                 { &hf_nfs_tag4, {
5205                         "Tag", "nfs.tag", FT_STRING, BASE_DEC,
5206                         NULL, 0, "Tag" }},
5207
5208                 { &hf_nfs_clientid4, {
5209                         "Client ID", "nfs.clientid", FT_STRING, BASE_DEC,
5210                         NULL, 0, "Name" }},
5211
5212                 { &hf_nfs_ace4, {
5213                         "ace", "nfs.ace", FT_STRING, BASE_DEC,
5214                         NULL, 0, "Access Control Entry" }},
5215
5216                 { &hf_nfs_recall, {
5217                         "EOF", "nfs.recall", FT_BOOLEAN, BASE_NONE,
5218                         &yesno, 0, "Recall" }},
5219
5220                 { &hf_nfs_open_claim_type4, {
5221                         "Claim Type", "nfs.open.claim_type", FT_UINT32, BASE_DEC,
5222                         VALS(names_claim_type4), 0, "Claim Type" }},
5223
5224                 { &hf_nfs_opentype4, {
5225                         "Open Type", "nfs.open.opentype", FT_UINT32, BASE_DEC,
5226                         VALS(names_opentype4), 0, "Open Type" }},
5227
5228                 { &hf_nfs_limit_by4, {
5229                         "Space Limit", "nfs.open.limit_by", FT_UINT32, BASE_DEC,
5230                         VALS(names_limit_by4), 0, "Limit By" }},
5231
5232                 { &hf_nfs_open_delegation_type4, {
5233                         "Delegation Type", "nfs.open.delegation_type", FT_UINT32, BASE_DEC,
5234                         VALS(names_open_delegation_type4), 0, "Delegation Type" }},
5235
5236                 { &hf_nfs_ftype4, {
5237                         "File Type", "nfs.ftype4", FT_UINT32, BASE_DEC,
5238                         VALS(names_ftype4), 0, "File Type" }},
5239
5240                 { &hf_nfs_nfsstat4, {
5241                         "Status", "nfs.nfsstat4", FT_UINT32, BASE_DEC,
5242                         VALS(names_nfsstat4), 0, "Status" }}
5243         };
5244
5245         static gint *ett[] = {
5246                 &ett_nfs,
5247                 &ett_nfs_fh_fsid,
5248                 &ett_nfs_fh_xfsid,
5249                 &ett_nfs_fh_fn,
5250                 &ett_nfs_fh_xfn,
5251                 &ett_nfs_fh_hp,
5252                 &ett_nfs_fhandle,
5253                 &ett_nfs_timeval,
5254                 &ett_nfs_mode,
5255                 &ett_nfs_fattr,
5256                 &ett_nfs_sattr,
5257                 &ett_nfs_diropargs,
5258                 &ett_nfs_readdir_entry,
5259                 &ett_nfs_mode3,
5260                 &ett_nfs_specdata3,
5261                 &ett_nfs_fh3,
5262                 &ett_nfs_nfstime3,
5263                 &ett_nfs_fattr3,
5264                 &ett_nfs_post_op_fh3,
5265                 &ett_nfs_sattr3,
5266                 &ett_nfs_diropargs3,
5267                 &ett_nfs_sattrguard3,
5268                 &ett_nfs_set_mode3,
5269                 &ett_nfs_set_uid3,
5270                 &ett_nfs_set_gid3,
5271                 &ett_nfs_set_size3,
5272                 &ett_nfs_set_atime,
5273                 &ett_nfs_set_mtime,
5274                 &ett_nfs_pre_op_attr,
5275                 &ett_nfs_post_op_attr,
5276                 &ett_nfs_wcc_attr,
5277                 &ett_nfs_wcc_data,
5278                 &ett_nfs_access,
5279                 &ett_nfs_fsinfo_properties,
5280                 &ett_nfs_compound_call4,
5281                 &ett_nfs_utf8string,
5282                 &ett_nfs_argop4,
5283                 &ett_nfs_resop4,
5284                 &ett_nfs_access4,
5285                 &ett_nfs_close4,
5286                 &ett_nfs_commit4,
5287                 &ett_nfs_create4,
5288                 &ett_nfs_delegpurge4,
5289                 &ett_nfs_delegreturn4,
5290                 &ett_nfs_getattr4,
5291                 &ett_nfs_getfh4,
5292                 &ett_nfs_link4,
5293                 &ett_nfs_lock4,
5294                 &ett_nfs_lockt4,
5295                 &ett_nfs_locku4,
5296                 &ett_nfs_lookup4,
5297                 &ett_nfs_lookupp4,
5298                 &ett_nfs_nverify4,
5299                 &ett_nfs_open4,
5300                 &ett_nfs_openattr4,
5301                 &ett_nfs_open_confirm4,
5302                 &ett_nfs_open_downgrade4,
5303                 &ett_nfs_putfh4,
5304                 &ett_nfs_putpubfh4,
5305                 &ett_nfs_putrootfh4,
5306                 &ett_nfs_read4,
5307                 &ett_nfs_readdir4,
5308                 &ett_nfs_readlink4,
5309                 &ett_nfs_remove4,
5310                 &ett_nfs_rename4,
5311                 &ett_nfs_renew4,
5312                 &ett_nfs_restorefh4,
5313                 &ett_nfs_savefh4,
5314                 &ett_nfs_secinfo4,
5315                 &ett_nfs_setattr4,
5316                 &ett_nfs_setclientid4,
5317                 &ett_nfs_setclientid_confirm4,
5318                 &ett_nfs_verify4,
5319                 &ett_nfs_write4,
5320                 &ett_nfs_verifier4,
5321                 &ett_nfs_opaque,
5322                 &ett_nfs_dirlist4,
5323                 &ett_nfs_pathname4,
5324                 &ett_nfs_change_info4,
5325                 &ett_nfs_open_delegation4,
5326                 &ett_nfs_open_claim4,
5327                 &ett_nfs_opentype4,
5328                 &ett_nfs_lockowner4,
5329                 &ett_nfs_cb_client4,
5330                 &ett_nfs_client_id4,
5331                 &ett_nfs_bitmap4
5332         };
5333         proto_nfs = proto_register_protocol("Network File System", "NFS", "nfs");
5334         proto_register_field_array(proto_nfs, hf, array_length(hf));
5335         proto_register_subtree_array(ett, array_length(ett));
5336 }
5337
5338 void
5339 proto_reg_handoff_nfs(void)
5340 {
5341         /* Register the protocol as RPC */
5342         rpc_init_prog(proto_nfs, NFS_PROGRAM, ett_nfs);
5343         /* Register the procedure tables */
5344         rpc_init_proc_table(NFS_PROGRAM, 2, nfs2_proc);
5345         rpc_init_proc_table(NFS_PROGRAM, 3, nfs3_proc);
5346         rpc_init_proc_table(NFS_PROGRAM, 4, nfs4_proc);
5347 }