3e18772cabf12388d5c8e8dbd8230748afad1ef6
[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  *
5  * $Id: packet-nfs.c,v 1.19 2000/01/18 11:56:15 girlich Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-smb.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36
37
38 #include "packet-rpc.h"
39 #include "packet-nfs.h"
40
41
42 static int proto_nfs = -1;
43
44
45 static int hf_nfs_stat = -1;
46 static int hf_nfs_name = -1;
47 static int hf_nfs_readlink_data = -1;
48 static int hf_nfs_read_offset = -1;
49 static int hf_nfs_read_count = -1;
50 static int hf_nfs_read_totalcount = -1;
51 static int hf_nfs_data = -1;
52 static int hf_nfs_write_beginoffset = -1;
53 static int hf_nfs_write_offset = -1;
54 static int hf_nfs_write_totalcount = -1;
55 static int hf_nfs_symlink_to = -1;
56 static int hf_nfs_readdir_cookie = -1;
57 static int hf_nfs_readdir_count = -1;
58 static int hf_nfs_readdir_value_follows = -1;
59 static int hf_nfs_readdir_entry = -1;
60 static int hf_nfs_readdir_entry_fileid = -1;
61 static int hf_nfs_readdir_entry_name = -1;
62 static int hf_nfs_readdirplus_entry_name = -1;
63 static int hf_nfs_readdir_entry_cookie = -1;
64 static int hf_nfs_readdir_eof = -1;
65 static int hf_nfs_statfs_tsize = -1;
66 static int hf_nfs_statfs_bsize = -1;
67 static int hf_nfs_statfs_blocks = -1;
68 static int hf_nfs_statfs_bfree = -1;
69 static int hf_nfs_statfs_bavail = -1;
70 static int hf_nfs_ftype3 = -1;
71 static int hf_nfs_nfsstat3 = -1;
72 static int hf_nfs_read_eof = -1;
73 static int hf_nfs_write_stable = -1;
74 static int hf_nfs_write_committed = -1;
75 static int hf_nfs_createmode3 = -1;
76 static int hf_nfs_fsstat_invarsec = -1;
77 static int hf_nfs_fsinfo_rtmax = -1;
78 static int hf_nfs_fsinfo_rtpref = -1;
79 static int hf_nfs_fsinfo_rtmult = -1;
80 static int hf_nfs_fsinfo_wtmax = -1;
81 static int hf_nfs_fsinfo_wtpref = -1;
82 static int hf_nfs_fsinfo_wtmult = -1;
83 static int hf_nfs_fsinfo_dtpref = -1;
84 static int hf_nfs_fsinfo_properties = -1;
85 static int hf_nfs_pathconf_linkmax = -1;
86 static int hf_nfs_pathconf_name_max = -1;
87 static int hf_nfs_pathconf_no_trunc = -1;
88 static int hf_nfs_pathconf_chown_restricted = -1;
89 static int hf_nfs_pathconf_case_insensitive = -1;
90 static int hf_nfs_pathconf_case_preserving = -1;
91
92
93 static gint ett_nfs = -1;
94 static gint ett_nfs_fhandle = -1;
95 static gint ett_nfs_timeval = -1;
96 static gint ett_nfs_mode = -1;
97 static gint ett_nfs_fattr = -1;
98 static gint ett_nfs_sattr = -1;
99 static gint ett_nfs_diropargs = -1;
100 static gint ett_nfs_readdir_entry = -1;
101 static gint ett_nfs_mode3 = -1;
102 static gint ett_nfs_specdata3 = -1;
103 static gint ett_nfs_fh3 = -1;
104 static gint ett_nfs_nfstime3 = -1;
105 static gint ett_nfs_fattr3 = -1;
106 static gint ett_nfs_post_op_fh3 = -1;
107 static gint ett_nfs_sattr3 = -1;
108 static gint ett_nfs_diropargs3 = -1;
109 static gint ett_nfs_sattrguard3 = -1;
110 static gint ett_nfs_set_mode3 = -1;
111 static gint ett_nfs_set_uid3 = -1;
112 static gint ett_nfs_set_gid3 = -1;
113 static gint ett_nfs_set_size3 = -1;
114 static gint ett_nfs_set_atime = -1;
115 static gint ett_nfs_set_mtime = -1;
116 static gint ett_nfs_pre_op_attr = -1;
117 static gint ett_nfs_post_op_attr = -1;
118 static gint ett_nfs_wcc_attr = -1;
119 static gint ett_nfs_wcc_data = -1;
120 static gint ett_nfs_access = -1;
121 static gint ett_nfs_fsinfo_properties = -1;
122
123
124 /***************************/
125 /* NFS Version 2, RFC 1094 */
126 /***************************/
127
128
129 /* base 32 bit type for NFS v2 */
130 int
131 dissect_unsigned_int(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
132 char* name)
133 {
134         offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"unsigned int");
135         return offset;
136 }
137
138
139 /* RFC 1094, Page 12..14 */
140 const value_string names_nfs_stat[] =
141 {
142         {       0,      "OK" },
143         {       1,      "ERR_PERM" },
144         {       2,      "ERR_NOENT" },
145         {       5,      "ERR_IO" },
146         {       6,      "ERR_NX_IO" },
147         {       13,     "ERR_ACCES" },
148         {       17,     "ERR_EXIST" },
149         {       19,     "ERR_NODEV" },
150         {       20,     "ERR_NOTDIR" },
151         {       21,     "ERR_ISDIR" },
152         {       27,     "ERR_FBIG" },
153         {       28,     "ERR_NOSPC" },
154         {       30,     "ERR_ROFS" },
155         {       63,     "ERR_NAMETOOLONG" },
156         {       66,     "ERR_NOTEMPTY" },
157         {       69,     "ERR_DQUOT" },
158         {       70,     "ERR_STALE" },
159         {       99,     "ERR_WFLUSH" },
160         {       0,      NULL }
161 };
162
163
164 /* RFC 1094, Page 12..14 */
165 int
166 dissect_stat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
167 guint32* status)
168 {
169         guint32 stat;
170
171         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
172         stat = EXTRACT_UINT(pd, offset+0);
173         
174         if (tree) {
175                 /* this gives the right NFSv2 number<->message relation */
176                 /* and makes it searchable via "nfs.status" */
177                 proto_tree_add_item_format(tree, hf_nfs_nfsstat3,
178                         offset+0, 4, stat, "Status: %s (%u)", 
179                         val_to_str(stat,names_nfs_stat,"%u"), stat);
180         }
181
182         offset += 4;
183         *status = stat;
184         return offset;
185 }
186
187
188 /* RFC 1094, Page 12..14 */
189 int
190 dissect_nfs2_stat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
191 {
192         guint32 status;
193
194         offset = dissect_stat(pd, offset, fd, tree, &status);
195
196         return offset;
197 }
198
199
200 /* RFC 1094, Page 15 */
201 int
202 dissect_ftype(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
203 char* name)
204 {
205         guint32 ftype;
206         char* ftype_name = NULL;
207
208         const value_string nfs2_ftype[] =
209         {
210                 {       0,      "Non-File" },
211                 {       1,      "Regular File" },
212                 {       2,      "Directory" },
213                 {       3,      "Block Special Device" },
214                 {       4,      "Character Special Device" },
215                 {       5,      "Symbolic Link" },
216                 {       0,      NULL }
217         };
218
219         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
220         ftype = EXTRACT_UINT(pd, offset+0);
221         ftype_name = val_to_str(ftype, nfs2_ftype, "%u");
222         
223         if (tree) {
224                 proto_tree_add_text(tree, offset, 4,
225                         "%s: %s (%u)", name, ftype_name, ftype);
226         }
227
228         offset += 4;
229         return offset;
230 }
231
232
233 /* RFC 1094, Page 15 */
234 int
235 dissect_fhandle(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
236 {
237         proto_item* fitem;
238         proto_tree* ftree = NULL;
239
240         if (tree) {
241                 fitem = proto_tree_add_text(tree, offset, FHSIZE,
242                         "%s", name);
243                 if (fitem)
244                         ftree = proto_item_add_subtree(fitem, ett_nfs_fhandle);
245         }
246
247         if (ftree) {
248                 proto_tree_add_text(ftree,offset+0,FHSIZE,
249                                         "file handle (opaque data)");
250         }
251
252         offset += FHSIZE;
253         return offset;
254 }
255
256
257 /* RFC 1094, Page 15 */
258 int
259 dissect_nfs2_fhandle_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
260 {
261         offset = dissect_fhandle(pd, offset, fd, tree, "object");
262
263         return offset;
264 }
265
266
267 /* RFC 1094, Page 15 */
268 int
269 dissect_timeval(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
270 {
271         guint32 seconds;
272         guint32 mseconds;
273
274         proto_item* time_item;
275         proto_tree* time_tree = NULL;
276
277         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
278         seconds = EXTRACT_UINT(pd, offset+0);
279         mseconds = EXTRACT_UINT(pd, offset+4);
280         
281         if (tree) {
282                 time_item = proto_tree_add_text(tree, offset, 8,
283                         "%s: %u.%06u", name, seconds, mseconds);
284                 if (time_item)
285                         time_tree = proto_item_add_subtree(time_item, ett_nfs_timeval);
286         }
287
288         if (time_tree) {
289                 proto_tree_add_text(time_tree,offset+0,4,
290                                         "seconds: %u", seconds);
291                 proto_tree_add_text(time_tree,offset+4,4,
292                                         "micro seconds: %u", mseconds);
293         }
294         offset += 8;
295         return offset;
296 }
297
298
299 /* RFC 1094, Page 16 */
300 const value_string nfs2_mode_names[] = {
301         {       0040000,        "Directory"     },
302         {       0020000,        "Character Special Device"      },
303         {       0060000,        "Block Special Device"  },
304         {       0100000,        "Regular File"  },
305         {       0120000,        "Symbolic Link" },
306         {       0140000,        "Named Socket"  },
307         {       0000000,        NULL            },
308 };
309
310 int
311 dissect_mode(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
312 char* name)
313 {
314         guint32 mode;
315         proto_item* mode_item = NULL;
316         proto_tree* mode_tree = NULL;
317
318         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
319         mode = EXTRACT_UINT(pd, offset+0);
320         
321         if (tree) {
322                 mode_item = proto_tree_add_text(tree, offset, 4,
323                         "%s: 0%o", name, mode);
324                 if (mode_item)
325                         mode_tree = proto_item_add_subtree(mode_item, ett_nfs_mode);
326         }
327
328         if (mode_tree) {
329                 proto_tree_add_text(mode_tree, offset, 4, "%s",
330                         decode_enumerated_bitfield(mode,  0160000, 16,
331                         nfs2_mode_names, "%s"));
332                 proto_tree_add_text(mode_tree, offset, 4, "%s",
333                 decode_boolean_bitfield(mode,   04000, 16, "Set user id on exec", "not SUID"));
334                 proto_tree_add_text(mode_tree, offset, 4, "%s",
335                 decode_boolean_bitfield(mode,   02000, 16, "Set group id on exec", "not SGID"));
336                 proto_tree_add_text(mode_tree, offset, 4, "%s",
337                 decode_boolean_bitfield(mode,   01000, 16, "Save swapped text even after use", "not save swapped text"));
338                 proto_tree_add_text(mode_tree, offset, 4, "%s",
339                 decode_boolean_bitfield(mode,    0400, 16, "Read permission for owner", "no Read permission for owner"));
340                 proto_tree_add_text(mode_tree, offset, 4, "%s",
341                 decode_boolean_bitfield(mode,    0200, 16, "Write permission for owner", "no Write permission for owner"));
342                 proto_tree_add_text(mode_tree, offset, 4, "%s",
343                 decode_boolean_bitfield(mode,    0100, 16, "Execute permission for owner", "no Execute permission for owner"));
344                 proto_tree_add_text(mode_tree, offset, 4, "%s",
345                 decode_boolean_bitfield(mode,     040, 16, "Read permission for group", "no Read permission for group"));
346                 proto_tree_add_text(mode_tree, offset, 4, "%s",
347                 decode_boolean_bitfield(mode,     020, 16, "Write permission for group", "no Write permission for group"));
348                 proto_tree_add_text(mode_tree, offset, 4, "%s",
349                 decode_boolean_bitfield(mode,     010, 16, "Execute permission for group", "no Execute permission for group"));
350                 proto_tree_add_text(mode_tree, offset, 4, "%s",
351                 decode_boolean_bitfield(mode,      04, 16, "Read permission for others", "no Read permission for others"));
352                 proto_tree_add_text(mode_tree, offset, 4, "%s",
353                 decode_boolean_bitfield(mode,      02, 16, "Write permission for others", "no Write permission for others"));
354                 proto_tree_add_text(mode_tree, offset, 4, "%s",
355                 decode_boolean_bitfield(mode,      01, 16, "Execute permission for others", "no Execute permission for others"));
356         }
357
358         offset += 4;
359         return offset;
360 }
361
362
363 /* RFC 1094, Page 15 */
364 int
365 dissect_fattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
366 {
367         proto_item* fattr_item = NULL;
368         proto_tree* fattr_tree = NULL;
369         int old_offset = offset;
370
371         if (tree) {
372                 fattr_item = proto_tree_add_text(tree, offset,
373                         END_OF_FRAME, "%s", name);
374                 if (fattr_item)
375                         fattr_tree = proto_item_add_subtree(fattr_item, ett_nfs_fattr);
376         }
377
378         offset = dissect_ftype        (pd,offset,fd,fattr_tree,"type");
379         offset = dissect_mode         (pd,offset,fd,fattr_tree,"mode");
380         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"nlink");
381         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"uid");
382         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"gid");
383         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"size");
384         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocksize");
385         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"rdev");
386         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocks");
387         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fsid");
388         offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fileid");
389         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"atime");
390         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"mtime");
391         offset = dissect_timeval      (pd,offset,fd,fattr_tree,"ctime");
392
393         /* now we know, that fattr is shorter */
394         if (fattr_item) {
395                 proto_item_set_len(fattr_item, offset - old_offset);
396         }
397
398         return offset;
399 }
400
401
402 /* RFC 1094, Page 17 */
403 int
404 dissect_sattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
405 {
406         proto_item* sattr_item = NULL;
407         proto_tree* sattr_tree = NULL;
408         int old_offset = offset;
409
410         if (tree) {
411                 sattr_item = proto_tree_add_text(tree, offset,
412                         END_OF_FRAME, "%s", name);
413                 if (sattr_item)
414                         sattr_tree = proto_item_add_subtree(sattr_item, ett_nfs_sattr);
415         }
416
417         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
418         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
419                 offset = dissect_mode         (pd,offset,fd,sattr_tree,"mode");
420         else {
421                 proto_tree_add_text(sattr_tree, offset, 4, "mode: no value");
422                 offset += 4;
423         }
424
425         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
426         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
427                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"uid");
428         else {
429                 proto_tree_add_text(sattr_tree, offset, 4, "uid: no value");
430                 offset += 4;
431         }
432
433         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
434         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
435                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"gid");
436         else {
437                 proto_tree_add_text(sattr_tree, offset, 4, "gid: no value");
438                 offset += 4;
439         }
440
441         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
442         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
443                 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"size");
444         else {
445                 proto_tree_add_text(sattr_tree, offset, 4, "size: no value");
446                 offset += 4;
447         }
448
449         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
450         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
451                 offset = dissect_timeval      (pd,offset,fd,sattr_tree,"atime");
452         else {
453                 proto_tree_add_text(sattr_tree, offset, 8, "atime: no value");
454                 offset += 8;
455         }
456
457         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
458         if (EXTRACT_UINT(pd, offset+0) != 0xffffffff)
459                 offset = dissect_timeval      (pd,offset,fd,sattr_tree,"mtime");
460         else {
461                 proto_tree_add_text(sattr_tree, offset, 8, "mtime: no value");
462                 offset += 8;
463         }
464
465         /* now we know, that sattr is shorter */
466         if (sattr_item) {
467                 proto_item_set_len(sattr_item, offset - old_offset);
468         }
469
470         return offset;
471 }
472
473
474 /* RFC 1094, Page 17 */
475 int
476 dissect_filename(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
477 {
478         offset = dissect_rpc_string(pd,offset,fd,tree,hf);
479         return offset;
480 }
481
482
483 /* RFC 1094, Page 17 */
484 int
485 dissect_path(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
486 {
487         offset = dissect_rpc_string(pd,offset,fd,tree,hf);
488         return offset;
489 }
490
491
492 /* RFC 1094, Page 17,18 */
493 int
494 dissect_attrstat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
495         guint32 status;
496
497         offset = dissect_stat(pd, offset, fd, tree, &status);
498         switch (status) {
499                 case 0:
500                         offset = dissect_fattr(pd, offset, fd, tree, "attributes");
501                 break;
502                 default:
503                         /* do nothing */
504                 break;
505         }
506
507         return offset;
508 }
509
510
511 /* RFC 1094, Page 17,18 */
512 int
513 dissect_nfs2_attrstat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
514 {
515         offset = dissect_attrstat(pd, offset, fd, tree);
516
517         return offset;
518 }
519
520
521 /* RFC 1094, Page 18 */
522 int
523 dissect_diropargs(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
524 {
525         proto_item* diropargs_item = NULL;
526         proto_tree* diropargs_tree = NULL;
527         int old_offset = offset;
528
529         if (tree) {
530                 diropargs_item = proto_tree_add_text(tree, offset,
531                         END_OF_FRAME, "%s", name);
532                 if (diropargs_item)
533                         diropargs_tree = proto_item_add_subtree(diropargs_item, ett_nfs_diropargs);
534         }
535
536         offset = dissect_fhandle (pd,offset,fd,diropargs_tree,"dir");
537         offset = dissect_filename(pd,offset,fd,diropargs_tree,hf_nfs_name);
538
539         /* now we know, that diropargs is shorter */
540         if (diropargs_item) {
541                 proto_item_set_len(diropargs_item, offset - old_offset);
542         }
543
544         return offset;
545 }
546
547
548 /* RFC 1094, Page 18 */
549 int
550 dissect_nfs2_diropargs_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
551 {
552         offset = dissect_diropargs(pd, offset, fd, tree, "where");
553
554         return offset;
555 }
556
557
558 /* RFC 1094, Page 18 */
559 int
560 dissect_diropres(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
561 {
562         guint32 status;
563
564         offset = dissect_stat(pd, offset, fd, tree, &status);
565         switch (status) {
566                 case 0:
567                         offset = dissect_fhandle(pd, offset, fd, tree, "file");
568                         offset = dissect_fattr  (pd, offset, fd, tree, "attributes");
569                 break;
570                 default:
571                         /* do nothing */
572                 break;
573         }
574
575         return offset;
576 }
577
578
579 /* nfsdata is simply a RPC string (length, data, fill bytes) */
580 int
581 dissect_nfsdata(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
582 int hf)
583 {
584         offset = dissect_rpc_data(pd,offset,fd,tree,hf);
585
586         return offset;
587 }
588
589
590 /* RFC 1094, Page 18 */
591 int
592 dissect_nfs2_diropres_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
593 {
594         offset = dissect_diropres(pd, offset, fd, tree);
595
596         return offset;
597 }
598
599
600 /* RFC 1094, Page 6 */
601 int
602 dissect_nfs2_setattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
603 {
604         offset = dissect_fhandle(pd, offset, fd, tree, "file"      );
605         offset = dissect_sattr  (pd, offset, fd, tree, "attributes");
606
607         return offset;
608 }
609
610
611 /* RFC 1094, Page 6 */
612 int
613 dissect_nfs2_readlink_reply(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
614 {
615         guint32 status;
616
617         offset = dissect_stat(pd, offset, fd, tree, &status);
618         switch (status) {
619                 case 0:
620                         offset = dissect_path(pd, offset, fd, tree, hf_nfs_readlink_data);
621                 break;
622                 default:
623                         /* do nothing */
624                 break;
625         }
626
627         return offset;
628 }
629
630
631 /* RFC 1094, Page 7 */
632 int
633 dissect_nfs2_read_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
634 {
635         guint32 offset_value;
636         guint32 count;
637         guint32 totalcount;
638
639         offset = dissect_fhandle(pd, offset, fd, tree, "file"      );
640         if (!BYTES_ARE_IN_FRAME(offset,12)) return offset;
641         offset_value = EXTRACT_UINT(pd, offset+0);
642         count        = EXTRACT_UINT(pd, offset+4);
643         totalcount   = EXTRACT_UINT(pd, offset+8);
644         if (tree) {
645                 proto_tree_add_item(tree, hf_nfs_read_offset, 
646                 offset+0, 4, offset_value);
647                 proto_tree_add_item(tree, hf_nfs_read_count, 
648                 offset+4, 4, count);
649                 proto_tree_add_item(tree, hf_nfs_read_totalcount, 
650                 offset+8, 4, totalcount);
651         }
652         offset += 12;
653
654         return offset;
655 }
656
657
658 /* RFC 1094, Page 7 */
659 int
660 dissect_nfs2_read_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
661 {
662         guint32 status;
663
664         offset = dissect_stat(pd, offset, fd, tree, &status);
665         switch (status) {
666                 case 0:
667                         offset = dissect_fattr(pd, offset, fd, tree, "attributes");
668                         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data); 
669                 break;
670                 default:
671                         /* do nothing */
672                 break;
673         }
674
675         return offset;
676 }
677
678
679 /* RFC 1094, Page 8 */
680 int
681 dissect_nfs2_write_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
682 {
683         guint32 beginoffset;
684         guint32 offset_value;
685         guint32 totalcount;
686
687         offset = dissect_fhandle(pd, offset, fd, tree, "file"      );
688         if (!BYTES_ARE_IN_FRAME(offset,12)) return offset;
689         beginoffset  = EXTRACT_UINT(pd, offset+0);
690         offset_value = EXTRACT_UINT(pd, offset+4);
691         totalcount   = EXTRACT_UINT(pd, offset+8);
692         if (tree) {
693                 proto_tree_add_item(tree, hf_nfs_write_beginoffset, 
694                 offset+0, 4, beginoffset);
695                 proto_tree_add_item(tree, hf_nfs_write_offset, 
696                 offset+4, 4, offset_value);
697                 proto_tree_add_item(tree, hf_nfs_write_totalcount, 
698                 offset+8, 4, totalcount);
699         }
700         offset += 12;
701
702         offset = dissect_nfsdata(pd, offset, fd, tree, hf_nfs_data); 
703
704         return offset;
705 }
706
707
708 /* RFC 1094, Page 8 */
709 int
710 dissect_nfs2_createargs_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
711 {
712         offset = dissect_diropargs(pd, offset, fd, tree, "where"     );
713         offset = dissect_sattr    (pd, offset, fd, tree, "attributes");
714
715         return offset;
716 }
717
718
719 /* RFC 1094, Page 9 */
720 int
721 dissect_nfs2_rename_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
722 {
723         offset = dissect_diropargs(pd, offset, fd, tree, "from");
724         offset = dissect_diropargs(pd, offset, fd, tree, "to"  );
725
726         return offset;
727 }
728
729
730 /* RFC 1094, Page 9 */
731 int
732 dissect_nfs2_link_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
733 {
734         offset = dissect_fhandle  (pd, offset, fd, tree, "from");
735         offset = dissect_diropargs(pd, offset, fd, tree, "to"  );
736
737         return offset;
738 }
739
740
741 /* RFC 1094, Page 10 */
742 int
743 dissect_nfs2_symlink_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
744 {
745         offset = dissect_diropargs(pd, offset, fd, tree, "from"           );
746         offset = dissect_path     (pd, offset, fd, tree, hf_nfs_symlink_to);
747         offset = dissect_sattr    (pd, offset, fd, tree, "attributes"     );
748
749         return offset;
750 }
751
752
753 /* RFC 1094, Page 11 */
754 int
755 dissect_nfs2_readdir_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
756 {
757         guint32 cookie;
758         guint32 count;
759
760         offset = dissect_fhandle (pd, offset, fd, tree, "dir");
761         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
762         cookie  = EXTRACT_UINT(pd, offset+ 0);
763         count = EXTRACT_UINT(pd, offset+ 4);
764         if (tree) {
765                 proto_tree_add_item(tree, hf_nfs_readdir_cookie,
766                         offset+ 0, 4, cookie);
767                 proto_tree_add_item(tree, hf_nfs_readdir_count,
768                         offset+ 4, 4, count);
769         }
770         offset += 8;
771
772         return offset;
773 }
774
775
776 /* RFC 1094, Page 11 */
777 int
778 dissect_readdir_entry(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
779 {
780         proto_item* entry_item = NULL;
781         proto_tree* entry_tree = NULL;
782         int old_offset = offset;
783         guint32 fileid;
784         guint32 cookie;
785
786         if (tree) {
787                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry,
788                         offset+0, END_OF_FRAME, NULL);
789                 if (entry_item)
790                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
791         }
792
793         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
794         fileid = EXTRACT_UINT(pd, offset + 0);
795         if (entry_tree)
796                 proto_tree_add_item(entry_tree, hf_nfs_readdir_entry_fileid,
797                         offset+0, 4, fileid);
798         offset += 4;
799
800         offset = dissect_filename(pd, offset, fd, entry_tree, hf_nfs_readdir_entry_name);
801         
802         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
803         cookie = EXTRACT_UINT(pd, offset + 0);
804         if (entry_tree)
805                 proto_tree_add_item(entry_tree, hf_nfs_readdir_entry_cookie,
806                         offset+0, 4, cookie);
807         offset += 4;
808
809         /* now we know, that a readdir entry is shorter */
810         if (entry_item) {
811                 proto_item_set_len(entry_item, offset - old_offset);
812         }
813
814         return offset;
815 }
816
817 /* RFC 1094, Page 11 */
818 int
819 dissect_nfs2_readdir_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
820 {
821         guint32 status;
822         guint32 value_follows;
823         guint32 eof_value;
824
825         offset = dissect_stat(pd, offset, fd, tree, &status);
826         switch (status) {
827                 case 0:
828                         while (1) {
829                                 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
830                                 value_follows = EXTRACT_UINT(pd, offset+0);
831                                 proto_tree_add_item(tree,hf_nfs_readdir_value_follows,
832                                         offset+0, 4, value_follows);
833                                 offset += 4;
834                                 if (value_follows == 1) {
835                                         offset = dissect_readdir_entry(pd, offset, fd, tree);
836                                 }
837                                 else {
838                                         break;
839                                 }
840                         }
841                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
842                         eof_value = EXTRACT_UINT(pd, offset+0);
843                         if (tree)
844                                 proto_tree_add_item(tree, hf_nfs_readdir_eof,
845                                         offset+ 0, 4, eof_value);
846                         offset += 4;
847                 break;
848                 default:
849                         /* do nothing */
850                 break;
851         }
852
853         return offset;
854 }
855
856
857 /* RFC 1094, Page 12 */
858 int
859 dissect_nfs2_statfs_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
860 {
861         guint32 status;
862         guint32 tsize;
863         guint32 bsize;
864         guint32 blocks;
865         guint32 bfree;
866         guint32 bavail;
867
868         offset = dissect_stat(pd, offset, fd, tree, &status);
869         switch (status) {
870                 case 0:
871                         if (!BYTES_ARE_IN_FRAME(offset,5 * 4)) return offset;
872                         tsize  = EXTRACT_UINT(pd, offset+ 0);
873                         bsize  = EXTRACT_UINT(pd, offset+ 4);
874                         blocks = EXTRACT_UINT(pd, offset+ 8);
875                         bfree  = EXTRACT_UINT(pd, offset+12);
876                         bavail = EXTRACT_UINT(pd, offset+16);
877                         if (tree) {
878                                 proto_tree_add_item(tree, hf_nfs_statfs_tsize,
879                                         offset+ 0, 4, tsize);
880                                 proto_tree_add_item(tree, hf_nfs_statfs_bsize,
881                                         offset+ 4, 4, bsize);
882                                 proto_tree_add_item(tree, hf_nfs_statfs_blocks,
883                                         offset+ 8, 4, blocks);
884                                 proto_tree_add_item(tree, hf_nfs_statfs_bfree,
885                                         offset+12, 4, bfree);
886                                 proto_tree_add_item(tree, hf_nfs_statfs_bavail,
887                                         offset+16, 4, bavail);
888                         }
889                         offset += 20;
890                 break;
891                 default:
892                         /* do nothing */
893                 break;
894         }
895
896         return offset;
897 }
898
899
900 /* proc number, "proc name", dissect_request, dissect_reply */
901 /* NULL as function pointer means: take the generic one. */
902 const vsff nfs2_proc[] = {
903         { 0,    "NULL",         /* OK */
904         NULL,                           NULL },
905         { 1,    "GETATTR",      /* OK */
906         dissect_nfs2_fhandle_call,      dissect_nfs2_attrstat_reply },
907         { 2,    "SETATTR",      /* OK */
908         dissect_nfs2_setattr_call,      dissect_nfs2_attrstat_reply },
909         { 3,    "ROOT",         /* OK */
910         NULL,                           NULL },
911         { 4,    "LOOKUP",       /* OK */
912         dissect_nfs2_diropargs_call,    dissect_nfs2_diropres_reply },
913         { 5,    "READLINK",     /* OK */
914         dissect_nfs2_fhandle_call,      dissect_nfs2_readlink_reply },
915         { 6,    "READ",         /* OK */
916         dissect_nfs2_read_call,         dissect_nfs2_read_reply },
917         { 7,    "WRITECACHE",   /* OK */
918         NULL,                           NULL },
919         { 8,    "WRITE",        /* OK */
920         dissect_nfs2_write_call,        dissect_nfs2_attrstat_reply },
921         { 9,    "CREATE",       /* OK */
922         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
923         { 10,   "REMOVE",       /* OK */
924         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
925         { 11,   "RENAME",       /* OK */
926         dissect_nfs2_rename_call,       dissect_nfs2_stat_reply },
927         { 12,   "LINK",         /* OK */
928         dissect_nfs2_link_call,         dissect_nfs2_stat_reply },
929         { 13,   "SYMLINK",      /* OK */
930         dissect_nfs2_symlink_call,      dissect_nfs2_stat_reply },
931         { 14,   "MKDIR",        /* OK */
932         dissect_nfs2_createargs_call,   dissect_nfs2_diropres_reply },
933         { 15,   "RMDIR",        /* OK */
934         dissect_nfs2_diropargs_call,    dissect_nfs2_stat_reply },
935         { 16,   "READDIR",      /* OK */
936         dissect_nfs2_readdir_call,      dissect_nfs2_readdir_reply },
937         { 17,   "STATFS",       /* OK */
938         dissect_nfs2_fhandle_call,      dissect_nfs2_statfs_reply },
939         { 0,NULL,NULL,NULL }
940 };
941 /* end of NFS Version 2 */
942
943
944 /***************************/
945 /* NFS Version 3, RFC 1813 */
946 /***************************/
947
948
949 /* RFC 1813, Page 15 */
950 int
951 dissect_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
952 char* name)
953 {
954         offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"uint64");
955         return offset;
956 }
957
958
959 /* RFC 1813, Page 15 */
960 int
961 dissect_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
962 char* name)
963 {
964         offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uint32");
965         return offset;
966 }
967
968
969 /* RFC 1813, Page 15 */
970 int
971 dissect_filename3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
972 {
973         offset = dissect_rpc_string(pd,offset,fd,tree,hf);
974         return offset;
975 }
976
977
978 /* RFC 1813, Page 15 */
979 int
980 dissect_nfspath3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf)
981 {
982         offset = dissect_rpc_string(pd,offset,fd,tree,hf);
983         return offset;
984 }
985
986
987 /* RFC 1813, Page 15 */
988 int
989 dissect_fileid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
990 char* name)
991 {
992         offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"fileid3");
993         return offset;
994 }
995
996
997 /* RFC 1813, Page 15 */
998 int
999 dissect_cookie3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1000 char* name)
1001 {
1002         offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"cookie3");
1003         return offset;
1004 }
1005
1006
1007 /* RFC 1813, Page 15 */
1008 int
1009 dissect_cookieverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1010 {
1011         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1012         proto_tree_add_text(tree, offset, NFS3_COOKIEVERFSIZE,
1013                 "Verifier: Opaque Data");
1014         offset += NFS3_COOKIEVERFSIZE;
1015         return offset;
1016 }
1017
1018
1019 /* RFC 1813, Page 16 */
1020 int
1021 dissect_createverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1022 {
1023         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1024         proto_tree_add_text(tree, offset, NFS3_CREATEVERFSIZE,
1025                 "Verifier: Opaque Data");
1026         offset += NFS3_CREATEVERFSIZE;
1027         return offset;
1028 }
1029
1030
1031 /* RFC 1813, Page 16 */
1032 int
1033 dissect_writeverf3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1034 {
1035         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1036         proto_tree_add_text(tree, offset, NFS3_WRITEVERFSIZE,
1037                 "Verifier: Opaque Data");
1038         offset += NFS3_WRITEVERFSIZE;
1039         return offset;
1040 }
1041
1042
1043 /* RFC 1813, Page 16 */
1044 int
1045 dissect_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1046 char* name)
1047 {
1048         offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uid3"); 
1049         return offset;
1050 }
1051
1052
1053 /* RFC 1813, Page 16 */
1054 int
1055 dissect_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1056 char* name)
1057 {
1058         offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"gid3"); 
1059         return offset;
1060 }
1061
1062
1063 /* RFC 1813, Page 16 */
1064 int
1065 dissect_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1066 char* name)
1067 {
1068         offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"size3"); 
1069         return offset;
1070 }
1071
1072
1073 /* RFC 1813, Page 16 */
1074 int
1075 dissect_offset3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1076 char* name)
1077 {
1078         offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"offset3"); 
1079         return offset;
1080 }
1081
1082
1083 /* RFC 1813, Page 16 */
1084 int
1085 dissect_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1086 char* name)
1087 {
1088         guint32 mode3;
1089         proto_item* mode3_item = NULL;
1090         proto_tree* mode3_tree = NULL;
1091
1092         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1093         mode3 = EXTRACT_UINT(pd, offset+0);
1094         
1095         if (tree) {
1096                 mode3_item = proto_tree_add_text(tree, offset, 4,
1097                         "%s: 0%o", name, mode3);
1098                 if (mode3_item)
1099                         mode3_tree = proto_item_add_subtree(mode3_item, ett_nfs_mode3);
1100         }
1101
1102         /* RFC 1813, Page 23 */
1103         if (mode3_tree) {
1104                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1105                 decode_boolean_bitfield(mode3,   0x800, 12, "Set user id on exec", "not SUID"));
1106                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1107                 decode_boolean_bitfield(mode3,   0x400, 12, "Set group id on exec", "not SGID"));
1108                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1109                 decode_boolean_bitfield(mode3,   0x200, 12, "Save swapped text even after use", "not save swapped text"));
1110                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1111                 decode_boolean_bitfield(mode3,   0x100, 12, "Read permission for owner", "no Read permission for owner"));
1112                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1113                 decode_boolean_bitfield(mode3,    0x80, 12, "Write permission for owner", "no Write permission for owner"));
1114                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1115                 decode_boolean_bitfield(mode3,    0x40, 12, "Execute permission for owner", "no Execute permission for owner"));
1116                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1117                 decode_boolean_bitfield(mode3,    0x20, 12, "Read permission for group", "no Read permission for group"));
1118                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1119                 decode_boolean_bitfield(mode3,    0x10, 12, "Write permission for group", "no Write permission for group"));
1120                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1121                 decode_boolean_bitfield(mode3,     0x8, 12, "Execute permission for group", "no Execute permission for group"));
1122                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1123                 decode_boolean_bitfield(mode3,     0x4, 12, "Read permission for others", "no Read permission for others"));
1124                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1125                 decode_boolean_bitfield(mode3,     0x2, 12, "Write permission for others", "no Write permission for others"));
1126                 proto_tree_add_text(mode3_tree, offset, 4, "%s",
1127                 decode_boolean_bitfield(mode3,     0x1, 12, "Execute permission for others", "no Execute permission for others"));
1128         }
1129
1130         offset += 4;
1131         return offset;
1132 }
1133
1134
1135 /* RFC 1813, Page 16 */
1136 int
1137 dissect_count3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1138 char* name)
1139 {
1140         offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"count3");
1141         return offset;
1142 }
1143
1144
1145 /* RFC 1813, Page 16,17 */
1146 const value_string names_nfs_nfsstat3[] =
1147 {
1148         {       0,      "OK" },
1149         {       1,      "ERR_PERM" },
1150         {       2,      "ERR_NOENT" },
1151         {       5,      "ERR_IO" },
1152         {       6,      "ERR_NX_IO" },
1153         {       13,     "ERR_ACCES" },
1154         {       17,     "ERR_EXIST" },
1155         {       18,     "ERR_XDEV" },
1156         {       19,     "ERR_NODEV" },
1157         {       20,     "ERR_NOTDIR" },
1158         {       21,     "ERR_ISDIR" },
1159         {       22,     "ERR_INVAL" },
1160         {       27,     "ERR_FBIG" },
1161         {       28,     "ERR_NOSPC" },
1162         {       30,     "ERR_ROFS" },
1163         {       31,     "ERR_MLINK" },
1164         {       63,     "ERR_NAMETOOLONG" },
1165         {       66,     "ERR_NOTEMPTY" },
1166         {       69,     "ERR_DQUOT" },
1167         {       70,     "ERR_STALE" },
1168         {       71,     "ERR_REMOTE" },
1169         {       10001,  "ERR_BADHANDLE" },
1170         {       10002,  "ERR_NOT_SYNC" },
1171         {       10003,  "ERR_BAD_COOKIE" },
1172         {       10004,  "ERR_NOTSUPP" },
1173         {       10005,  "ERR_TOOSMALL" },
1174         {       10006,  "ERR_SERVERFAULT" },
1175         {       10007,  "ERR_BADTYPE" },
1176         {       10008,  "ERR_JUKEBOX" },
1177         {       0,      NULL }
1178 };
1179
1180
1181 /* RFC 1813, Page 16 */
1182 int
1183 dissect_nfsstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,guint32 *status)
1184 {
1185         guint32 nfsstat3;
1186
1187         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1188         nfsstat3 = EXTRACT_UINT(pd, offset+0);
1189         
1190         if (tree) {
1191                 proto_tree_add_item(tree, hf_nfs_nfsstat3,
1192                         offset, 4, nfsstat3);
1193         }
1194
1195         offset += 4;
1196         *status = nfsstat3;
1197         return offset;
1198 }
1199
1200
1201 const value_string names_nfs_ftype3[] =
1202 {
1203         {       NF3REG, "Regular File" },
1204         {       NF3DIR, "Directory" },
1205         {       NF3BLK, "Block Special Device" },
1206         {       NF3CHR, "Character Special Device" },
1207         {       NF3LNK, "Symbolic Link" },
1208         {       NF3SOCK,"Socket" },
1209         {       NF3FIFO,"Named Pipe" },
1210         {       0,      NULL }
1211 };
1212
1213
1214 /* RFC 1813, Page 20 */
1215 int
1216 dissect_ftype3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
1217 int hf, guint32* ftype3)
1218 {
1219         guint32 type;
1220
1221         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1222         type = EXTRACT_UINT(pd, offset+0);
1223         
1224         if (tree) {
1225                 proto_tree_add_item(tree, hf, offset, 4, type);
1226         }
1227
1228         offset += 4;
1229         *ftype3 = type;
1230         return offset;
1231 }
1232
1233
1234 /* RFC 1813, Page 20 */
1235 int
1236 dissect_specdata3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1237 {
1238         guint32 specdata1;
1239         guint32 specdata2;
1240
1241         proto_item* specdata3_item;
1242         proto_tree* specdata3_tree = NULL;
1243
1244         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1245         specdata1 = EXTRACT_UINT(pd, offset+0);
1246         specdata2 = EXTRACT_UINT(pd, offset+4);
1247         
1248         if (tree) {
1249                 specdata3_item = proto_tree_add_text(tree, offset, 8,
1250                         "%s: %u,%u", name, specdata1, specdata2);
1251                 if (specdata3_item)
1252                         specdata3_tree = proto_item_add_subtree(specdata3_item,
1253                                         ett_nfs_specdata3);
1254         }
1255
1256         if (specdata3_tree) {
1257                 proto_tree_add_text(specdata3_tree,offset+0,4,
1258                                         "specdata1: %u", specdata1);
1259                 proto_tree_add_text(specdata3_tree,offset+4,4,
1260                                         "specdata2: %u", specdata2);
1261         }
1262
1263         offset += 8;
1264         return offset;
1265 }
1266
1267
1268 /* RFC 1813, Page 21 */
1269 int
1270 dissect_nfs_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1271 {
1272         guint fh3_len;
1273         guint fh3_len_full;
1274         guint fh3_fill;
1275         proto_item* fitem;
1276         proto_tree* ftree = NULL;
1277
1278         fh3_len = EXTRACT_UINT(pd, offset+0);
1279         fh3_len_full = rpc_roundup(fh3_len);
1280         fh3_fill = fh3_len_full - fh3_len;
1281         
1282         if (tree) {
1283                 fitem = proto_tree_add_text(tree, offset, 4+fh3_len_full,
1284                         "%s", name);
1285                 if (fitem)
1286                         ftree = proto_item_add_subtree(fitem, ett_nfs_fh3);
1287         }
1288
1289         if (ftree) {
1290                 proto_tree_add_text(ftree,offset+0,4,
1291                                         "length: %u", fh3_len);
1292                 proto_tree_add_text(ftree,offset+4,fh3_len,
1293                                         "file handle (opaque data)");
1294                 if (fh3_fill)
1295                         proto_tree_add_text(ftree,offset+4+fh3_len,fh3_fill,
1296                                 "fill bytes");
1297         }
1298         offset += 4 + fh3_len_full;
1299         return offset;
1300 }
1301
1302
1303 /* RFC 1813, Page 21 */
1304 int
1305 dissect_nfstime3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,char* name)
1306 {
1307         guint32 seconds;
1308         guint32 nseconds;
1309
1310         proto_item* time_item;
1311         proto_tree* time_tree = NULL;
1312
1313         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
1314         seconds = EXTRACT_UINT(pd, offset+0);
1315         nseconds = EXTRACT_UINT(pd, offset+4);
1316         
1317         if (tree) {
1318                 time_item = proto_tree_add_text(tree, offset, 8,
1319                         "%s: %u.%09u", name, seconds, nseconds);
1320                 if (time_item)
1321                         time_tree = proto_item_add_subtree(time_item, ett_nfs_nfstime3);
1322         }
1323
1324         if (time_tree) {
1325                 proto_tree_add_text(time_tree,offset+0,4,
1326                                         "seconds: %u", seconds);
1327                 proto_tree_add_text(time_tree,offset+4,4,
1328                                         "nano seconds: %u", nseconds);
1329         }
1330         offset += 8;
1331         return offset;
1332 }
1333
1334
1335 /* RFC 1813, Page 22 */
1336 int
1337 dissect_fattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1338 {
1339         proto_item* fattr3_item = NULL;
1340         proto_tree* fattr3_tree = NULL;
1341         int old_offset = offset;
1342         guint32 type;
1343
1344         if (tree) {
1345                 fattr3_item = proto_tree_add_text(tree, offset,
1346                         END_OF_FRAME, "%s", name);
1347                 if (fattr3_item)
1348                         fattr3_tree = proto_item_add_subtree(fattr3_item, ett_nfs_fattr3);
1349         }
1350
1351         offset = dissect_ftype3   (pd,offset,fd,fattr3_tree,hf_nfs_ftype3,&type);
1352         offset = dissect_mode3    (pd,offset,fd,fattr3_tree,"mode");
1353         offset = dissect_uint32   (pd,offset,fd,fattr3_tree,"nlink");
1354         offset = dissect_uid3     (pd,offset,fd,fattr3_tree,"uid");
1355         offset = dissect_gid3     (pd,offset,fd,fattr3_tree,"gid");
1356         offset = dissect_size3    (pd,offset,fd,fattr3_tree,"size");
1357         offset = dissect_size3    (pd,offset,fd,fattr3_tree,"used");
1358         offset = dissect_specdata3(pd,offset,fd,fattr3_tree,"rdev");
1359         offset = dissect_uint64   (pd,offset,fd,fattr3_tree,"fsid");
1360         offset = dissect_fileid3  (pd,offset,fd,fattr3_tree,"fileid");
1361         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"atime");
1362         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"mtime");
1363         offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"ctime");
1364
1365         /* now we know, that fattr3 is shorter */
1366         if (fattr3_item) {
1367                 proto_item_set_len(fattr3_item, offset - old_offset);
1368         }
1369
1370         return offset;
1371 }
1372
1373
1374 const value_string value_follows[] =
1375         {
1376                 { 0, "no value" },
1377                 { 1, "value follows"},
1378                 { 0, NULL }
1379         };
1380
1381
1382 /* RFC 1813, Page 23 */
1383 int
1384 dissect_post_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1385 {
1386         proto_item* post_op_attr_item = NULL;
1387         proto_tree* post_op_attr_tree = NULL;
1388         int old_offset = offset;
1389         guint32 attributes_follow;
1390
1391         if (tree) {
1392                 post_op_attr_item = proto_tree_add_text(tree, offset,
1393                         END_OF_FRAME, "%s", name);
1394                 if (post_op_attr_item)
1395                         post_op_attr_tree = proto_item_add_subtree(post_op_attr_item, ett_nfs_post_op_attr);
1396         }
1397
1398         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1399         attributes_follow = EXTRACT_UINT(pd, offset+0);
1400         proto_tree_add_text(post_op_attr_tree, offset, 4,
1401                 "attributes_follow: %s (%u)", 
1402                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
1403         offset += 4;
1404         switch (attributes_follow) {
1405                 case TRUE:
1406                         offset = dissect_fattr3(pd, offset, fd, post_op_attr_tree,
1407                                         "attributes");
1408                 break;
1409                 case FALSE:
1410                         /* void */
1411                 break;
1412         }
1413         
1414         /* now we know, that post_op_attr_tree is shorter */
1415         if (post_op_attr_item) {
1416                 proto_item_set_len(post_op_attr_item, offset - old_offset);
1417         }
1418
1419         return offset;
1420 }
1421
1422
1423 /* RFC 1813, Page 24 */
1424 int
1425 dissect_wcc_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1426 {
1427         proto_item* wcc_attr_item = NULL;
1428         proto_tree* wcc_attr_tree = NULL;
1429         int old_offset = offset;
1430
1431         if (tree) {
1432                 wcc_attr_item = proto_tree_add_text(tree, offset,
1433                         END_OF_FRAME, "%s", name);
1434                 if (wcc_attr_item)
1435                         wcc_attr_tree = proto_item_add_subtree(wcc_attr_item, ett_nfs_wcc_attr);
1436         }
1437
1438         offset = dissect_size3   (pd, offset, fd, wcc_attr_tree, "size" );
1439         offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "mtime");
1440         offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "ctime");
1441         
1442         /* now we know, that wcc_attr_tree is shorter */
1443         if (wcc_attr_item) {
1444                 proto_item_set_len(wcc_attr_item, offset - old_offset);
1445         }
1446
1447         return offset;
1448 }
1449
1450
1451 /* RFC 1813, Page 24 */
1452 int
1453 dissect_pre_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1454 {
1455         proto_item* pre_op_attr_item = NULL;
1456         proto_tree* pre_op_attr_tree = NULL;
1457         int old_offset = offset;
1458         guint32 attributes_follow;
1459
1460         if (tree) {
1461                 pre_op_attr_item = proto_tree_add_text(tree, offset,
1462                         END_OF_FRAME, "%s", name);
1463                 if (pre_op_attr_item)
1464                         pre_op_attr_tree = proto_item_add_subtree(pre_op_attr_item, ett_nfs_pre_op_attr);
1465         }
1466
1467         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1468         attributes_follow = EXTRACT_UINT(pd, offset+0);
1469         proto_tree_add_text(pre_op_attr_tree, offset, 4,
1470                 "attributes_follow: %s (%u)", 
1471                 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
1472         offset += 4;
1473         switch (attributes_follow) {
1474                 case TRUE:
1475                         offset = dissect_wcc_attr(pd, offset, fd, pre_op_attr_tree,
1476                                         "attributes");
1477                 break;
1478                 case FALSE:
1479                         /* void */
1480                 break;
1481         }
1482         
1483         /* now we know, that pre_op_attr_tree is shorter */
1484         if (pre_op_attr_item) {
1485                 proto_item_set_len(pre_op_attr_item, offset - old_offset);
1486         }
1487
1488         return offset;
1489 }
1490
1491
1492 /* RFC 1813, Page 24 */
1493 int
1494 dissect_wcc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1495 {
1496         proto_item* wcc_data_item = NULL;
1497         proto_tree* wcc_data_tree = NULL;
1498         int old_offset = offset;
1499
1500         if (tree) {
1501                 wcc_data_item = proto_tree_add_text(tree, offset,
1502                         END_OF_FRAME, "%s", name);
1503                 if (wcc_data_item)
1504                         wcc_data_tree = proto_item_add_subtree(wcc_data_item, ett_nfs_wcc_data);
1505         }
1506
1507         offset = dissect_pre_op_attr (pd, offset, fd, wcc_data_tree, "before");
1508         offset = dissect_post_op_attr(pd, offset, fd, wcc_data_tree, "after" );
1509
1510         /* now we know, that wcc_data is shorter */
1511         if (wcc_data_item) {
1512                 proto_item_set_len(wcc_data_item, offset - old_offset);
1513         }
1514
1515         return offset;
1516 }
1517
1518
1519 /* RFC 1813, Page 25 */
1520 int
1521 dissect_post_op_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1522 {
1523         proto_item* post_op_fh3_item = NULL;
1524         proto_tree* post_op_fh3_tree = NULL;
1525         int old_offset = offset;
1526         guint32 handle_follows;
1527
1528         if (tree) {
1529                 post_op_fh3_item = proto_tree_add_text(tree, offset,
1530                         END_OF_FRAME, "%s", name);
1531                 if (post_op_fh3_item)
1532                         post_op_fh3_tree = proto_item_add_subtree(post_op_fh3_item, ett_nfs_post_op_fh3);
1533         }
1534
1535         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1536         handle_follows = EXTRACT_UINT(pd, offset+0);
1537         proto_tree_add_text(post_op_fh3_tree, offset, 4,
1538                 "handle_follows: %s (%u)", 
1539                 val_to_str(handle_follows,value_follows,"Unknown"), handle_follows);
1540         offset += 4;
1541         switch (handle_follows) {
1542                 case TRUE:
1543                         offset = dissect_nfs_fh3(pd, offset, fd, post_op_fh3_tree,
1544                                         "handle");
1545                 break;
1546                 case FALSE:
1547                         /* void */
1548                 break;
1549         }
1550         
1551         /* now we know, that post_op_fh3_tree is shorter */
1552         if (post_op_fh3_item) {
1553                 proto_item_set_len(post_op_fh3_item, offset - old_offset);
1554         }
1555
1556         return offset;
1557 }
1558
1559
1560 /* RFC 1813, Page 25 */
1561 int
1562 dissect_set_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1563 {
1564         proto_item* set_mode3_item = NULL;
1565         proto_tree* set_mode3_tree = NULL;
1566         int old_offset = offset;
1567         guint32 set_it;
1568         char* set_it_name;
1569
1570         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1571         set_it = EXTRACT_UINT(pd, offset+0);
1572         set_it_name = val_to_str(set_it,value_follows,"Unknown");
1573
1574         if (tree) {
1575                 set_mode3_item = proto_tree_add_text(tree, offset,
1576                         END_OF_FRAME, "%s: %s", name, set_it_name);
1577                 if (set_mode3_item)
1578                         set_mode3_tree = proto_item_add_subtree(set_mode3_item, ett_nfs_set_mode3);
1579         }
1580
1581         if (set_mode3_tree)
1582                 proto_tree_add_text(set_mode3_tree, offset, 4,
1583                         "set_it: %s (%u)", set_it_name, set_it);
1584
1585         offset += 4;
1586
1587         switch (set_it) {
1588                 case 1:
1589                         offset = dissect_mode3(pd, offset, fd, set_mode3_tree,
1590                                         "mode");
1591                 break;
1592                 default:
1593                         /* void */
1594                 break;
1595         }
1596         
1597         /* now we know, that set_mode3 is shorter */
1598         if (set_mode3_item) {
1599                 proto_item_set_len(set_mode3_item, offset - old_offset);
1600         }
1601
1602         return offset;
1603 }
1604
1605
1606 /* RFC 1813, Page 26 */
1607 int
1608 dissect_set_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1609 {
1610         proto_item* set_uid3_item = NULL;
1611         proto_tree* set_uid3_tree = NULL;
1612         int old_offset = offset;
1613         guint32 set_it;
1614         char* set_it_name;
1615
1616         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1617         set_it = EXTRACT_UINT(pd, offset+0);
1618         set_it_name = val_to_str(set_it,value_follows,"Unknown");
1619
1620         if (tree) {
1621                 set_uid3_item = proto_tree_add_text(tree, offset,
1622                         END_OF_FRAME, "%s: %s", name, set_it_name);
1623                 if (set_uid3_item)
1624                         set_uid3_tree = proto_item_add_subtree(set_uid3_item, ett_nfs_set_uid3);
1625         }
1626
1627         if (set_uid3_tree)
1628                 proto_tree_add_text(set_uid3_tree, offset, 4,
1629                         "set_it: %s (%u)", set_it_name, set_it);
1630
1631         offset += 4;
1632
1633         switch (set_it) {
1634                 case 1:
1635                         offset = dissect_uid3(pd, offset, fd, set_uid3_tree,
1636                                         "uid");
1637                 break;
1638                 default:
1639                         /* void */
1640                 break;
1641         }
1642
1643         /* now we know, that set_uid3 is shorter */
1644         if (set_uid3_item) {
1645                 proto_item_set_len(set_uid3_item, offset - old_offset);
1646         }
1647
1648         return offset;
1649 }
1650
1651
1652 /* RFC 1813, Page 26 */
1653 int
1654 dissect_set_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1655 {
1656         proto_item* set_gid3_item = NULL;
1657         proto_tree* set_gid3_tree = NULL;
1658         int old_offset = offset;
1659         guint32 set_it;
1660         char* set_it_name;
1661
1662         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1663         set_it = EXTRACT_UINT(pd, offset+0);
1664         set_it_name = val_to_str(set_it,value_follows,"Unknown");
1665
1666         if (tree) {
1667                 set_gid3_item = proto_tree_add_text(tree, offset,
1668                         END_OF_FRAME, "%s: %s", name, set_it_name);
1669                 if (set_gid3_item)
1670                         set_gid3_tree = proto_item_add_subtree(set_gid3_item, ett_nfs_set_gid3);
1671         }
1672
1673         if (set_gid3_tree)
1674                 proto_tree_add_text(set_gid3_tree, offset, 4,
1675                         "set_it: %s (%u)", set_it_name, set_it);
1676
1677         offset += 4;
1678
1679         switch (set_it) {
1680                 case 1:
1681                         offset = dissect_gid3(pd, offset, fd, set_gid3_tree,
1682                                         "gid");
1683                 break;
1684                 default:
1685                         /* void */
1686                 break;
1687         }
1688
1689         /* now we know, that set_gid3 is shorter */
1690         if (set_gid3_item) {
1691                 proto_item_set_len(set_gid3_item, offset - old_offset);
1692         }
1693
1694         return offset;
1695 }
1696
1697
1698 /* RFC 1813, Page 26 */
1699 int
1700 dissect_set_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1701 {
1702         proto_item* set_size3_item = NULL;
1703         proto_tree* set_size3_tree = NULL;
1704         int old_offset = offset;
1705         guint32 set_it;
1706         char* set_it_name;
1707
1708         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1709         set_it = EXTRACT_UINT(pd, offset+0);
1710         set_it_name = val_to_str(set_it,value_follows,"Unknown");
1711
1712         if (tree) {
1713                 set_size3_item = proto_tree_add_text(tree, offset,
1714                         END_OF_FRAME, "%s: %s", name, set_it_name);
1715                 if (set_size3_item)
1716                         set_size3_tree = proto_item_add_subtree(set_size3_item, ett_nfs_set_size3);
1717         }
1718
1719         if (set_size3_tree)
1720                 proto_tree_add_text(set_size3_tree, offset, 4,
1721                         "set_it: %s (%u)", set_it_name, set_it);
1722
1723         offset += 4;
1724
1725         switch (set_it) {
1726                 case 1:
1727                         offset = dissect_size3(pd, offset, fd, set_size3_tree,
1728                                         "size");
1729                 break;
1730                 default:
1731                         /* void */
1732                 break;
1733         }
1734
1735         /* now we know, that set_size3 is shorter */
1736         if (set_size3_item) {
1737                 proto_item_set_len(set_size3_item, offset - old_offset);
1738         }
1739
1740         return offset;
1741 }
1742
1743
1744 /* RFC 1813, Page 25 */
1745 #define DONT_CHANGE 0
1746 #define SET_TO_SERVER_TIME 1
1747 #define SET_TO_CLIENT_TIME 2
1748
1749 const value_string time_how[] =
1750         {
1751                 { DONT_CHANGE,  "don't change" },
1752                 { SET_TO_SERVER_TIME, "set to server time" },
1753                 { SET_TO_CLIENT_TIME, "set to client time" },
1754                 { 0, NULL }
1755         };
1756
1757
1758 /* RFC 1813, Page 26 */
1759 int
1760 dissect_set_atime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1761 {
1762         proto_item* set_atime_item = NULL;
1763         proto_tree* set_atime_tree = NULL;
1764         int old_offset = offset;
1765         guint32 set_it;
1766         char* set_it_name;
1767
1768         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1769         set_it = EXTRACT_UINT(pd, offset+0);
1770         set_it_name = val_to_str(set_it,time_how,"Unknown");
1771
1772         if (tree) {
1773                 set_atime_item = proto_tree_add_text(tree, offset,
1774                         END_OF_FRAME, "%s: %s",
1775                         name, set_it_name, set_it);
1776                 if (set_atime_item)
1777                         set_atime_tree = proto_item_add_subtree(set_atime_item, ett_nfs_set_atime);
1778         }
1779
1780         if (set_atime_tree)
1781                 proto_tree_add_text(set_atime_tree, offset, 4,
1782                         "set_it: %s (%u)", set_it_name, set_it);
1783
1784         offset += 4;
1785
1786         switch (set_it) {
1787                 case SET_TO_CLIENT_TIME:
1788                         if (set_atime_item)
1789                         offset = dissect_nfstime3(pd, offset, fd, set_atime_tree,
1790                                         "atime");
1791                 break;
1792                 default:
1793                         /* void */
1794                 break;
1795         }
1796
1797         /* now we know, that set_atime is shorter */
1798         if (set_atime_item) {
1799                 proto_item_set_len(set_atime_item, offset - old_offset);
1800         }
1801
1802         return offset;
1803 }
1804
1805
1806 /* RFC 1813, Page 26 */
1807 int
1808 dissect_set_mtime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1809 {
1810         proto_item* set_mtime_item = NULL;
1811         proto_tree* set_mtime_tree = NULL;
1812         int old_offset = offset;
1813         guint32 set_it;
1814         char* set_it_name;
1815
1816         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1817         set_it = EXTRACT_UINT(pd, offset+0);
1818         set_it_name = val_to_str(set_it,time_how,"Unknown");
1819
1820         if (tree) {
1821                 set_mtime_item = proto_tree_add_text(tree, offset,
1822                         END_OF_FRAME, "%s: %s",
1823                         name, set_it_name, set_it);
1824                 if (set_mtime_item)
1825                         set_mtime_tree = proto_item_add_subtree(set_mtime_item, ett_nfs_set_mtime);
1826         }
1827
1828         if (set_mtime_tree)
1829                 proto_tree_add_text(set_mtime_tree, offset, 4,
1830                                 "set_it: %s (%u)", set_it_name, set_it);
1831
1832         offset += 4;
1833
1834         switch (set_it) {
1835                 case SET_TO_CLIENT_TIME:
1836                         if (set_mtime_item)
1837                         offset = dissect_nfstime3(pd, offset, fd, set_mtime_tree,
1838                                         "atime");
1839                 break;
1840                 default:
1841                         /* void */
1842                 break;
1843         }
1844
1845         /* now we know, that set_mtime is shorter */
1846         if (set_mtime_item) {
1847                 proto_item_set_len(set_mtime_item, offset - old_offset);
1848         }
1849
1850         return offset;
1851 }
1852
1853
1854 /* RFC 1813, Page 25..27 */
1855 int
1856 dissect_sattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1857 {
1858         proto_item* sattr3_item = NULL;
1859         proto_tree* sattr3_tree = NULL;
1860         int old_offset = offset;
1861
1862         if (tree) {
1863                 sattr3_item = proto_tree_add_text(tree, offset,
1864                         END_OF_FRAME, "%s", name);
1865                 if (sattr3_item)
1866                         sattr3_tree = proto_item_add_subtree(sattr3_item, ett_nfs_sattr3);
1867         }
1868
1869         offset = dissect_set_mode3(pd, offset, fd, sattr3_tree, "mode");
1870         offset = dissect_set_uid3 (pd, offset, fd, sattr3_tree, "uid");
1871         offset = dissect_set_gid3 (pd, offset, fd, sattr3_tree, "gid");
1872         offset = dissect_set_size3(pd, offset, fd, sattr3_tree, "size");
1873         offset = dissect_set_atime(pd, offset, fd, sattr3_tree, "atime");
1874         offset = dissect_set_mtime(pd, offset, fd, sattr3_tree, "mtime");
1875
1876         /* now we know, that sattr3 is shorter */
1877         if (sattr3_item) {
1878                 proto_item_set_len(sattr3_item, offset - old_offset);
1879         }
1880
1881         return offset;
1882 }
1883
1884
1885 /* RFC 1813, Page 27 */
1886 int
1887 dissect_diropargs3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1888 {
1889         proto_item* diropargs3_item = NULL;
1890         proto_tree* diropargs3_tree = NULL;
1891         int old_offset = offset;
1892
1893         if (tree) {
1894                 diropargs3_item = proto_tree_add_text(tree, offset,
1895                         END_OF_FRAME, "%s", name);
1896                 if (diropargs3_item)
1897                         diropargs3_tree = proto_item_add_subtree(diropargs3_item, ett_nfs_diropargs3);
1898         }
1899
1900         offset = dissect_nfs_fh3  (pd, offset, fd, diropargs3_tree, "dir");
1901         offset = dissect_filename3(pd, offset, fd, diropargs3_tree, hf_nfs_name);
1902
1903         /* now we know, that diropargs3 is shorter */
1904         if (diropargs3_item) {
1905                 proto_item_set_len(diropargs3_item, offset - old_offset);
1906         }
1907
1908         return offset;
1909 }
1910
1911
1912 /* RFC 1813, Page 27 */
1913 int
1914 dissect_nfs3_diropargs3_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1915 {
1916         offset = dissect_diropargs3(pd, offset, fd, tree, "object");
1917
1918         return offset;
1919 }
1920
1921
1922 /* RFC 1813, Page 40 */
1923 int
1924 dissect_access(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1925 {
1926         guint32 access;
1927         proto_item* access_item = NULL;
1928         proto_tree* access_tree = NULL;
1929
1930         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1931         access = EXTRACT_UINT(pd, offset+0);
1932         
1933         if (tree) {
1934                 access_item = proto_tree_add_text(tree, offset, 4,
1935                         "%s: 0x%02x", name, access);
1936                 if (access_item)
1937                         access_tree = proto_item_add_subtree(access_item, ett_nfs_access);
1938         }
1939
1940         if (access_tree) {
1941                 proto_tree_add_text(access_tree, offset, 4, "%s READ",
1942                 decode_boolean_bitfield(access,  0x001, 6, "allow", "not allow"));
1943                 proto_tree_add_text(access_tree, offset, 4, "%s LOOKUP",
1944                 decode_boolean_bitfield(access,  0x002, 6, "allow", "not allow"));
1945                 proto_tree_add_text(access_tree, offset, 4, "%s MODIFY",
1946                 decode_boolean_bitfield(access,  0x004, 6, "allowed", "not allow"));
1947                 proto_tree_add_text(access_tree, offset, 4, "%s EXTEND",
1948                 decode_boolean_bitfield(access,  0x008, 6, "allow", "not allow"));
1949                 proto_tree_add_text(access_tree, offset, 4, "%s DELETE",
1950                 decode_boolean_bitfield(access,  0x010, 6, "allow", "not allow"));
1951                 proto_tree_add_text(access_tree, offset, 4, "%s EXECUTE",
1952                 decode_boolean_bitfield(access,  0x020, 6, "allow", "not allow"));
1953         }
1954
1955         offset += 4;
1956         return offset;
1957 }
1958
1959
1960 /* NFS3 file handle dissector */
1961 int
1962 dissect_nfs3_nfs_fh3_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1963 {
1964         offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
1965         return offset;
1966 }
1967
1968
1969 /* generic NFS3 reply dissector */
1970 int
1971 dissect_nfs3_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1972 {
1973         guint32 status;
1974
1975         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
1976
1977         return offset;
1978
1979 }
1980
1981
1982 /* RFC 1813, Page 32,33 */
1983 int
1984 dissect_nfs3_getattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1985 {
1986         offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
1987         return offset;
1988 }
1989
1990
1991 /* RFC 1813, Page 32,33 */
1992 int
1993 dissect_nfs3_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1994 {
1995         guint32 status;
1996
1997         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
1998         switch (status) {
1999                 case 0:
2000                         offset = dissect_fattr3(pd, offset, fd, tree, "obj_attributes");
2001                 break;
2002                 default:
2003                         /* void */
2004                 break;
2005         }
2006                 
2007         return offset;
2008 }
2009
2010
2011 /* RFC 1813, Page 33 */
2012 int
2013 dissect_sattrguard3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, char *name)
2014 {
2015         proto_item* sattrguard3_item = NULL;
2016         proto_tree* sattrguard3_tree = NULL;
2017         int old_offset = offset;
2018         guint32 check;
2019         char* check_name;
2020
2021         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2022         check = EXTRACT_UINT(pd, offset+0);
2023         check_name = val_to_str(check,value_follows,"Unknown");
2024
2025         if (tree) {
2026                 sattrguard3_item = proto_tree_add_text(tree, offset,
2027                         END_OF_FRAME, "%s: %s", name, check_name);
2028                 if (sattrguard3_item)
2029                         sattrguard3_tree = proto_item_add_subtree(sattrguard3_item, ett_nfs_sattrguard3);
2030         }
2031
2032         if (sattrguard3_tree)
2033                 proto_tree_add_text(sattrguard3_tree, offset, 4,
2034                         "check: %s (%u)", check_name, check);
2035
2036         offset += 4;
2037
2038         switch (check) {
2039                 case TRUE:
2040                         offset = dissect_nfstime3(pd, offset, fd, sattrguard3_tree,
2041                                         "obj_ctime");
2042                 break;
2043                 case FALSE:
2044                         /* void */
2045                 break;
2046         }
2047
2048         /* now we know, that sattrguard3 is shorter */
2049         if (sattrguard3_item) {
2050                 proto_item_set_len(sattrguard3_item, offset - old_offset);
2051         }
2052
2053         return offset;
2054 }
2055
2056
2057 /* RFC 1813, Page 33..36 */
2058 int
2059 dissect_nfs3_setattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2060 {
2061         offset = dissect_nfs_fh3    (pd, offset, fd, tree, "object");
2062         offset = dissect_sattr3     (pd, offset, fd, tree, "new_attributes");
2063         offset = dissect_sattrguard3(pd, offset, fd, tree, "guard");
2064         return offset;
2065 }
2066
2067
2068 /* RFC 1813, Page 33..36 */
2069 int
2070 dissect_nfs3_setattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2071 {
2072         guint32 status;
2073
2074         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2075         switch (status) {
2076                 case 0:
2077                         offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
2078                 break;
2079                 default:
2080                         offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
2081                 break;
2082         }
2083                 
2084         return offset;
2085 }
2086
2087
2088 /* RFC 1813, Page 37..39 */
2089 int
2090 dissect_nfs3_lookup_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2091 {
2092         offset = dissect_diropargs3 (pd, offset, fd, tree, "what");
2093         return offset;
2094 }
2095
2096
2097 /* RFC 1813, Page 37..39 */
2098 int
2099 dissect_nfs3_lookup_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2100 {
2101         guint32 status;
2102
2103         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2104         switch (status) {
2105                 case 0:
2106                         offset = dissect_nfs_fh3     (pd, offset, fd, tree, "object");
2107                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2108                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2109                 break;
2110                 default:
2111                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2112                 break;
2113         }
2114                 
2115         return offset;
2116 }
2117
2118
2119 /* RFC 1813, Page 40..43 */
2120 int
2121 dissect_nfs3_access_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2122 {
2123         offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
2124         offset = dissect_access (pd, offset, fd, tree, "access");
2125
2126         return offset;
2127 }
2128
2129
2130 /* RFC 1813, Page 40..43 */
2131 int
2132 dissect_nfs3_access_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2133 {
2134         guint32 status;
2135
2136         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2137         switch (status) {
2138                 case 0:
2139                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2140                         offset = dissect_access      (pd, offset, fd, tree, "access");
2141                 break;
2142                 default:
2143                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2144                 break;
2145         }
2146                 
2147         return offset;
2148 }
2149
2150
2151 /* RFC 1813, Page 44,45 */
2152 int
2153 dissect_nfs3_readlink_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2154 {
2155         guint32 status;
2156
2157         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2158         switch (status) {
2159                 case 0:
2160                         offset = dissect_post_op_attr(pd, offset, fd, tree, "symlink_attributes");
2161                         offset = dissect_nfspath3    (pd, offset, fd, tree, hf_nfs_readlink_data);
2162                 break;
2163                 default:
2164                         offset = dissect_post_op_attr(pd, offset, fd, tree, "symlink_attributes");
2165                 break;
2166         }
2167                 
2168         return offset;
2169 }
2170
2171
2172 /* RFC 1813, Page 46..48 */
2173 int
2174 dissect_nfs3_read_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2175 {
2176         offset = dissect_nfs_fh3(pd, offset, fd, tree, "file");
2177         offset = dissect_offset3(pd, offset, fd, tree, "offset");
2178         offset = dissect_count3 (pd, offset, fd, tree, "count");
2179
2180         return offset;
2181 }
2182
2183
2184 /* RFC 1813, Page 46..48 */
2185 int
2186 dissect_nfs3_read_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2187 {
2188         guint32 status;
2189
2190         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2191         switch (status) {
2192                 case 0:
2193                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2194                         offset = dissect_count3      (pd, offset, fd, tree, "count");
2195                         offset = dissect_rpc_bool    (pd, offset, fd, tree, hf_nfs_read_eof);
2196                         offset = dissect_nfsdata     (pd, offset, fd, tree, hf_nfs_data);
2197                 break;
2198                 default:
2199                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2200                 break;
2201         }
2202                 
2203         return offset;
2204 }
2205
2206
2207 /* RFC 1813, Page 49 */
2208 static const value_string names_stable_how[] = {
2209         {       UNSTABLE,  "UNSTABLE"  },
2210         {       DATA_SYNC, "DATA_SYNC" },
2211         {       FILE_SYNC, "FILE_SYNC" },
2212         { 0, NULL }
2213 };
2214
2215
2216 /* RFC 1813, Page 49 */
2217 int
2218 dissect_stable_how(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, int hfindex)
2219 {
2220         guint32 stable_how;
2221
2222         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2223         stable_how = EXTRACT_UINT(pd,offset+0);
2224         if (tree) {
2225                 proto_tree_add_item(tree, hfindex,
2226                         offset, 4, stable_how); 
2227         }
2228         offset += 4;
2229
2230         return offset;
2231 }
2232
2233
2234 /* RFC 1813, Page 49..54 */
2235 int
2236 dissect_nfs3_write_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2237 {
2238         offset = dissect_nfs_fh3   (pd, offset, fd, tree, "file");
2239         offset = dissect_offset3   (pd, offset, fd, tree, "offset");
2240         offset = dissect_count3    (pd, offset, fd, tree, "count");
2241         offset = dissect_stable_how(pd, offset, fd, tree, hf_nfs_write_stable);
2242         offset = dissect_nfsdata   (pd, offset, fd, tree, hf_nfs_data);
2243
2244         return offset;
2245 }
2246
2247
2248 /* RFC 1813, Page 49..54 */
2249 int
2250 dissect_nfs3_write_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2251 {
2252         guint32 status;
2253
2254         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2255         switch (status) {
2256                 case 0:
2257                         offset = dissect_wcc_data  (pd, offset, fd, tree, "file_wcc");
2258                         offset = dissect_count3    (pd, offset, fd, tree, "count");
2259                         offset = dissect_stable_how(pd, offset, fd, tree, hf_nfs_write_committed);
2260                         offset = dissect_writeverf3(pd, offset, fd, tree);
2261                 break;
2262                 default:
2263                         offset = dissect_wcc_data(pd, offset, fd, tree, "file_wcc");
2264                 break;
2265         }
2266                 
2267         return offset;
2268 }
2269
2270
2271 /* RFC 1813, Page 54 */
2272 static const value_string names_createmode3[] = {
2273         {       UNCHECKED, "UNCHECKED" },
2274         {       GUARDED,   "GUARDED" },
2275         {       EXCLUSIVE, "EXCLUSIVE" },
2276         { 0, NULL }
2277 };
2278
2279
2280 /* RFC 1813, Page 54 */
2281 int
2282 dissect_createmode3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, guint32* mode)
2283 {
2284         guint32 mode_value;
2285         
2286         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
2287         mode_value = EXTRACT_UINT(pd, offset + 0);
2288         if (tree) {
2289                 proto_tree_add_item(tree, hf_nfs_createmode3,
2290                 offset+0, 4, mode_value);
2291         }
2292         offset += 4;
2293
2294         *mode = mode_value;
2295         return offset;
2296 }
2297
2298
2299 /* RFC 1813, Page 54..58 */
2300 int
2301 dissect_nfs3_create_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2302 {
2303         guint32 mode;
2304
2305         offset = dissect_diropargs3 (pd, offset, fd, tree, "where");
2306         offset = dissect_createmode3(pd, offset, fd, tree, &mode);
2307         switch (mode) {
2308                 case UNCHECKED:
2309                 case GUARDED:
2310                         offset = dissect_sattr3     (pd, offset, fd, tree, "obj_attributes");
2311                 break;
2312                 case EXCLUSIVE:
2313                         offset = dissect_createverf3(pd, offset, fd, tree);
2314                 break;
2315         }
2316         
2317         return offset;
2318 }
2319
2320
2321 /* RFC 1813, Page 54..58 */
2322 int
2323 dissect_nfs3_create_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2324 {
2325         guint32 status;
2326
2327         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2328         switch (status) {
2329                 case 0:
2330                         offset = dissect_post_op_fh3 (pd, offset, fd, tree, "obj");
2331                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2332                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2333                 break;
2334                 default:
2335                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2336                 break;
2337         }
2338                 
2339         return offset;
2340 }
2341
2342
2343 /* RFC 1813, Page 58..60 */
2344 int
2345 dissect_nfs3_mkdir_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2346 {
2347         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2348         offset = dissect_sattr3    (pd, offset, fd, tree, "attributes");
2349         
2350         return offset;
2351 }
2352
2353
2354 /* RFC 1813, Page 61..63 */
2355 int
2356 dissect_nfs3_symlink_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2357 {
2358         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2359         offset = dissect_sattr3    (pd, offset, fd, tree, "symlink_attributes");
2360         offset = dissect_nfspath3  (pd, offset, fd, tree, hf_nfs_symlink_to);
2361         
2362         return offset;
2363 }
2364
2365
2366 /* RFC 1813, Page 63..66 */
2367 int
2368 dissect_nfs3_mknod_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2369 {
2370         guint32 type;
2371
2372         offset = dissect_diropargs3(pd, offset, fd, tree, "where");
2373         offset = dissect_ftype3(pd, offset, fd, tree, hf_nfs_ftype3, &type);
2374         switch (type) {
2375                 case NF3CHR:
2376                 case NF3BLK:
2377                         offset = dissect_sattr3(pd, offset, fd, tree, "dev_attributes");
2378                         offset = dissect_specdata3(pd, offset, fd, tree, "spec");
2379                 break;
2380                 case NF3SOCK:
2381                 case NF3FIFO:
2382                         offset = dissect_sattr3(pd, offset, fd, tree, "pipe_attributes");
2383                 break;
2384                 default:
2385                         /* nothing to do */
2386                 break;
2387         }
2388         
2389         return offset;
2390 }
2391
2392
2393 /* RFC 1813, Page 67..69 */
2394 int
2395 dissect_nfs3_remove_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2396 {
2397         guint32 status;
2398
2399         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2400         switch (status) {
2401                 case 0:
2402                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2403                 break;
2404                 default:
2405                         offset = dissect_wcc_data    (pd, offset, fd, tree, "dir_wcc");
2406                 break;
2407         }
2408                 
2409         return offset;
2410 }
2411
2412
2413 /* RFC 1813, Page 71..74 */
2414 int
2415 dissect_nfs3_rename_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2416 {
2417         offset = dissect_diropargs3(pd, offset, fd, tree, "from");
2418         offset = dissect_diropargs3(pd, offset, fd, tree, "to");
2419         
2420         return offset;
2421 }
2422
2423
2424 /* RFC 1813, Page 71..74 */
2425 int
2426 dissect_nfs3_rename_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2427 {
2428         guint32 status;
2429
2430         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2431         switch (status) {
2432                 case 0:
2433                         offset = dissect_wcc_data(pd, offset, fd, tree, "fromdir_wcc");
2434                         offset = dissect_wcc_data(pd, offset, fd, tree, "todir_wcc");
2435                 break;
2436                 default:
2437                         offset = dissect_wcc_data(pd, offset, fd, tree, "fromdir_wcc");
2438                         offset = dissect_wcc_data(pd, offset, fd, tree, "todir_wcc");
2439                 break;
2440         }
2441                 
2442         return offset;
2443 }
2444
2445
2446 /* RFC 1813, Page 74..76 */
2447 int
2448 dissect_nfs3_link_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2449 {
2450         offset = dissect_nfs_fh3   (pd, offset, fd, tree, "file");
2451         offset = dissect_diropargs3(pd, offset, fd, tree, "link");
2452         
2453         return offset;
2454 }
2455
2456
2457 /* RFC 1813, Page 74..76 */
2458 int
2459 dissect_nfs3_link_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2460 {
2461         guint32 status;
2462
2463         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2464         switch (status) {
2465                 case 0:
2466                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2467                         offset = dissect_wcc_data    (pd, offset, fd, tree, "linkdir_wcc");
2468                 break;
2469                 default:
2470                         offset = dissect_post_op_attr(pd, offset, fd, tree, "file_attributes");
2471                         offset = dissect_wcc_data    (pd, offset, fd, tree, "linkdir_wcc");
2472                 break;
2473         }
2474                 
2475         return offset;
2476 }
2477
2478
2479 /* RFC 1813, Page 76..80 */
2480 int
2481 dissect_nfs3_readdir_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2482 {
2483         offset = dissect_nfs_fh3    (pd, offset, fd, tree, "dir");
2484         offset = dissect_cookie3    (pd, offset, fd, tree, "cookie");
2485         offset = dissect_cookieverf3(pd, offset, fd, tree);
2486         offset = dissect_count3     (pd, offset, fd, tree, "count");
2487         
2488         return offset;
2489 }
2490
2491
2492 /* RFC 1813, Page 76..80 */
2493 int
2494 dissect_entry3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2495 {
2496         proto_item* entry_item = NULL;
2497         proto_tree* entry_tree = NULL;
2498         int old_offset = offset;
2499
2500         if (tree) {
2501                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry,
2502                         offset+0, END_OF_FRAME, NULL);
2503                 if (entry_item)
2504                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
2505         }
2506
2507         offset = dissect_fileid3(pd, offset, fd, entry_tree, "fileid");
2508
2509         offset = dissect_filename3(pd, offset, fd, entry_tree, hf_nfs_readdir_entry_name);
2510         
2511         offset = dissect_cookie3(pd, offset, fd, entry_tree, "cookie");
2512
2513         /* now we know, that a readdir entry is shorter */
2514         if (entry_item) {
2515                 proto_item_set_len(entry_item, offset - old_offset);
2516         }
2517
2518         return offset;
2519 }
2520
2521
2522 /* RFC 1813, Page 76..80 */
2523 int
2524 dissect_nfs3_readdir_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2525 {
2526         guint32 status;
2527         guint32 value_follows;
2528         guint32 eof_value;
2529
2530         offset = dissect_stat(pd, offset, fd, tree, &status);
2531         switch (status) {
2532                 case 0:
2533                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2534                         offset = dissect_cookieverf3(pd, offset, fd, tree);
2535                         while (1) {
2536                                 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
2537                                 value_follows = EXTRACT_UINT(pd, offset+0);
2538                                 proto_tree_add_item(tree,hf_nfs_readdir_value_follows,
2539                                         offset+0, 4, value_follows);
2540                                 offset += 4;
2541                                 if (value_follows == 1) {
2542                                         offset = dissect_entry3(pd, offset, fd, tree);
2543                                 }
2544                                 else {
2545                                         break;
2546                                 }
2547                         }
2548                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2549                         eof_value = EXTRACT_UINT(pd, offset+0);
2550                         if (tree)
2551                                 proto_tree_add_item(tree, hf_nfs_readdir_eof,
2552                                         offset+ 0, 4, eof_value);
2553                         offset += 4;
2554                 break;
2555                 default:
2556                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2557                 break;
2558         }
2559
2560         return offset;
2561 }
2562
2563
2564 /* RFC 1813, Page 80..83 */
2565 int
2566 dissect_nfs3_readdirplus_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2567 {
2568         offset = dissect_nfs_fh3    (pd, offset, fd, tree, "dir");
2569         offset = dissect_cookie3    (pd, offset, fd, tree, "cookie");
2570         offset = dissect_cookieverf3(pd, offset, fd, tree);
2571         offset = dissect_count3     (pd, offset, fd, tree, "dircount");
2572         offset = dissect_count3     (pd, offset, fd, tree, "maxcount");
2573         
2574         return offset;
2575 }
2576
2577
2578 /* RFC 1813, Page 80..83 */
2579 int
2580 dissect_entryplus3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2581 {
2582         proto_item* entry_item = NULL;
2583         proto_tree* entry_tree = NULL;
2584         int old_offset = offset;
2585
2586         if (tree) {
2587                 entry_item = proto_tree_add_item(tree, hf_nfs_readdir_entry,
2588                         offset+0, END_OF_FRAME, NULL);
2589                 if (entry_item)
2590                         entry_tree = proto_item_add_subtree(entry_item, ett_nfs_readdir_entry);
2591         }
2592
2593         offset = dissect_fileid3(pd, offset, fd, entry_tree, "fileid");
2594
2595         offset = dissect_filename3(pd, offset, fd, entry_tree, hf_nfs_readdirplus_entry_name);
2596         
2597         offset = dissect_cookie3(pd, offset, fd, entry_tree, "cookie");
2598
2599         offset = dissect_post_op_attr(pd, offset, fd, entry_tree, "name_attributes");
2600         offset = dissect_post_op_fh3(pd, offset, fd, entry_tree, "name_handle");
2601
2602         /* now we know, that a readdirplus entry is shorter */
2603         if (entry_item) {
2604                 proto_item_set_len(entry_item, offset - old_offset);
2605         }
2606
2607         return offset;
2608 }
2609
2610
2611 /* RFC 1813, Page 80..83 */
2612 int
2613 dissect_nfs3_readdirplus_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2614 {
2615         guint32 status;
2616         guint32 value_follows;
2617         guint32 eof_value;
2618
2619         offset = dissect_stat(pd, offset, fd, tree, &status);
2620         switch (status) {
2621                 case 0:
2622                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2623                         offset = dissect_cookieverf3(pd, offset, fd, tree);
2624                         while (1) {
2625                                 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
2626                                 value_follows = EXTRACT_UINT(pd, offset+0);
2627                                 proto_tree_add_item(tree,hf_nfs_readdir_value_follows,
2628                                         offset+0, 4, value_follows);
2629                                 offset += 4;
2630                                 if (value_follows == 1) {
2631                                         offset = dissect_entryplus3(pd, offset, fd, tree);
2632                                 }
2633                                 else {
2634                                         break;
2635                                 }
2636                         }
2637                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2638                         eof_value = EXTRACT_UINT(pd, offset+0);
2639                         if (tree)
2640                                 proto_tree_add_item(tree, hf_nfs_readdir_eof,
2641                                         offset+ 0, 4, eof_value);
2642                         offset += 4;
2643                 break;
2644                 default:
2645                         offset = dissect_post_op_attr(pd, offset, fd, tree, "dir_attributes");
2646                 break;
2647         }
2648
2649         return offset;
2650 }
2651
2652
2653 /* RFC 1813, Page 84..86 */
2654 int
2655 dissect_nfs3_fsstat_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2656 {
2657         guint32 status;
2658         guint32 invarsec;
2659
2660         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2661         switch (status) {
2662                 case 0:
2663                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2664                         offset = dissect_size3 (pd, offset, fd, tree, "tbytes");
2665                         offset = dissect_size3 (pd, offset, fd, tree, "fbytes");
2666                         offset = dissect_size3 (pd, offset, fd, tree, "abytes");
2667                         offset = dissect_size3 (pd, offset, fd, tree, "tfiles");
2668                         offset = dissect_size3 (pd, offset, fd, tree, "ffiles");
2669                         offset = dissect_size3 (pd, offset, fd, tree, "afiles");
2670                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
2671                         invarsec = EXTRACT_UINT(pd, offset + 0);
2672                         if (tree)
2673                                 proto_tree_add_item(tree, hf_nfs_fsstat_invarsec,
2674                                 offset+0, 4, invarsec);
2675                         offset += 4;
2676                 break;
2677                 default:
2678                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2679                 break;
2680         }
2681
2682         return offset;
2683 }
2684
2685
2686 #define FSF3_LINK        0x0001
2687 #define FSF3_SYMLINK     0x0002
2688 #define FSF3_HOMOGENEOUS 0x0008
2689 #define FSF3_CANSETTIME  0x0010
2690
2691
2692 /* RFC 1813, Page 86..90 */
2693 int
2694 dissect_nfs3_fsinfo_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2695 {
2696         guint32 status;
2697         guint32 rtmax;
2698         guint32 rtpref;
2699         guint32 rtmult;
2700         guint32 wtmax;
2701         guint32 wtpref;
2702         guint32 wtmult;
2703         guint32 dtpref;
2704         guint32 properties;
2705         proto_item*     properties_item = NULL;
2706         proto_tree*     properties_tree = NULL;
2707
2708         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2709         switch (status) {
2710                 case 0:
2711                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2712                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2713                         rtmax = EXTRACT_UINT(pd, offset+0);
2714                         if (tree)
2715                                 proto_tree_add_item(tree, hf_nfs_fsinfo_rtmax,
2716                                 offset+0, 4, rtmax);
2717                         offset += 4;
2718                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2719                         rtpref = EXTRACT_UINT(pd, offset+0);
2720                         if (tree)
2721                                 proto_tree_add_item(tree, hf_nfs_fsinfo_rtpref,
2722                                 offset+0, 4, rtpref);
2723                         offset += 4;
2724                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2725                         rtmult = EXTRACT_UINT(pd, offset+0);
2726                         if (tree)
2727                                 proto_tree_add_item(tree, hf_nfs_fsinfo_rtmult,
2728                                 offset+0, 4, rtmult);
2729                         offset += 4;
2730                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2731                         wtmax = EXTRACT_UINT(pd, offset+0);
2732                         if (tree)
2733                                 proto_tree_add_item(tree, hf_nfs_fsinfo_wtmax,
2734                                 offset+0, 4, wtmax);
2735                         offset += 4;
2736                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2737                         wtpref = EXTRACT_UINT(pd, offset+0);
2738                         if (tree)
2739                                 proto_tree_add_item(tree, hf_nfs_fsinfo_wtpref,
2740                                 offset+0, 4, wtpref);
2741                         offset += 4;
2742                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2743                         wtmult = EXTRACT_UINT(pd, offset+0);
2744                         if (tree)
2745                                 proto_tree_add_item(tree, hf_nfs_fsinfo_wtmult,
2746                                 offset+0, 4, wtmult);
2747                         offset += 4;
2748                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2749                         dtpref = EXTRACT_UINT(pd, offset+0);
2750                         if (tree)
2751                                 proto_tree_add_item(tree, hf_nfs_fsinfo_dtpref,
2752                                 offset+0, 4, dtpref);
2753                         offset += 4;
2754
2755                         offset = dissect_size3   (pd, offset, fd, tree, "maxfilesize");
2756                         offset = dissect_nfstime3(pd, offset, fd, tree, "time_delta");
2757                         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
2758                         properties = EXTRACT_UINT(pd, offset+0);
2759                         if (tree) {
2760                                 properties_item = proto_tree_add_item(tree,
2761                                 hf_nfs_fsinfo_properties,
2762                                 offset+0, 4, properties);
2763                                 if (properties_item) 
2764                                         properties_tree = proto_item_add_subtree(properties_item, ett_nfs_fsinfo_properties);
2765                                 if (properties_tree) {
2766                                         proto_tree_add_text(properties_tree,
2767                                         offset, 4, "%s",
2768                                         decode_boolean_bitfield(properties,
2769                                         FSF3_CANSETTIME,5,
2770                                         "SETATTR can set time on server",
2771                                         "SETATTR can't set time on server"));
2772
2773                                         proto_tree_add_text(properties_tree,
2774                                         offset, 4, "%s",
2775                                         decode_boolean_bitfield(properties,
2776                                         FSF3_HOMOGENEOUS,5,
2777                                         "PATHCONF is valid for all files",
2778                                         "PATHCONF should be get for every single file"));
2779
2780                                         proto_tree_add_text(properties_tree,
2781                                         offset, 4, "%s",
2782                                         decode_boolean_bitfield(properties,
2783                                         FSF3_SYMLINK,5,
2784                                         "File System supports symbolic links",
2785                                         "File System does not symbolic hard links"));
2786
2787                                         proto_tree_add_text(properties_tree,
2788                                         offset, 4, "%s",
2789                                         decode_boolean_bitfield(properties,
2790                                         FSF3_LINK,5,
2791                                         "File System supports hard links",
2792                                         "File System does not support hard links"));
2793                                 }
2794                         }
2795                         offset += 4;
2796                 break;
2797                 default:
2798                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2799                 break;
2800         }
2801
2802         return offset;
2803 }
2804
2805
2806 /* RFC 1813, Page 90..92 */
2807 int
2808 dissect_nfs3_pathconf_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2809 {
2810         guint32 status;
2811         guint32 linkmax;
2812         guint32 name_max;
2813
2814         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2815         switch (status) {
2816                 case 0:
2817                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2818                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
2819                         linkmax = EXTRACT_UINT(pd, offset + 0);
2820                         if (tree)
2821                                 proto_tree_add_item(tree, hf_nfs_pathconf_linkmax,
2822                                 offset+0, 4, linkmax);
2823                         offset += 4;
2824                         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
2825                         name_max = EXTRACT_UINT(pd, offset + 0);
2826                         if (tree)
2827                                 proto_tree_add_item(tree, hf_nfs_pathconf_name_max,
2828                                 offset+0, 4, name_max);
2829                         offset += 4;
2830                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_no_trunc);
2831                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_chown_restricted);
2832                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_case_insensitive);
2833                         offset = dissect_rpc_bool(pd, offset, fd, tree, hf_nfs_pathconf_case_preserving);
2834                 break;
2835                 default:
2836                         offset = dissect_post_op_attr(pd, offset, fd, tree, "obj_attributes");
2837                 break;
2838         }
2839
2840         return offset;
2841 }
2842
2843
2844 /* RFC 1813, Page 92..95 */
2845 int
2846 dissect_nfs3_commit_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2847 {
2848         offset = dissect_nfs_fh3(pd, offset, fd, tree, "file");
2849         offset = dissect_offset3(pd, offset, fd, tree, "offset");
2850         offset = dissect_count3 (pd, offset, fd, tree, "count");
2851         
2852         return offset;
2853 }
2854
2855
2856 /* RFC 1813, Page 92..95 */
2857 int
2858 dissect_nfs3_commit_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
2859 {
2860         guint32 status;
2861
2862         offset = dissect_nfsstat3(pd, offset, fd, tree, &status);
2863         switch (status) {
2864                 case 0:
2865                         offset = dissect_wcc_data  (pd, offset, fd, tree, "file_wcc");
2866                         offset = dissect_writeverf3(pd, offset, fd, tree);
2867                 break;
2868                 default:
2869                         offset = dissect_wcc_data(pd, offset, fd, tree, "file_wcc");
2870                 break;
2871         }
2872                 
2873         return offset;
2874 }
2875
2876
2877 /* 1 missing functions */
2878
2879
2880 /* proc number, "proc name", dissect_request, dissect_reply */
2881 /* NULL as function pointer means: take the generic one. */
2882 const vsff nfs3_proc[] = {
2883         { 0,    "NULL",         /* OK */
2884         NULL,                           NULL },
2885         { 1,    "GETATTR",      /* OK */
2886         dissect_nfs3_getattr_call,      dissect_nfs3_getattr_reply },
2887         { 2,    "SETATTR",      /* OK */
2888         dissect_nfs3_setattr_call,      dissect_nfs3_setattr_reply },
2889         { 3,    "LOOKUP",       /* OK */
2890         dissect_nfs3_lookup_call,       dissect_nfs3_lookup_reply },
2891         { 4,    "ACCESS",       /* OK */
2892         dissect_nfs3_access_call,       dissect_nfs3_access_reply },
2893         { 5,    "READLINK",     /* OK */
2894         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_readlink_reply },
2895         { 6,    "READ",         /* OK */
2896         dissect_nfs3_read_call,         dissect_nfs3_read_reply },
2897         { 7,    "WRITE",        /* OK */
2898         dissect_nfs3_write_call,        dissect_nfs3_write_reply },
2899         { 8,    "CREATE",       /* OK */
2900         dissect_nfs3_create_call,       dissect_nfs3_create_reply },
2901         { 9,    "MKDIR",        /* OK */
2902         dissect_nfs3_mkdir_call,        dissect_nfs3_create_reply },
2903         { 10,   "SYMLINK",      /* OK */
2904         dissect_nfs3_symlink_call,      dissect_nfs3_create_reply },
2905         { 11,   "MKNOD",        /* OK */
2906         dissect_nfs3_mknod_call,        dissect_nfs3_create_reply },
2907         { 12,   "REMOVE",       /* OK */
2908         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
2909         { 13,   "RMDIR",        /* OK */
2910         dissect_nfs3_diropargs3_call,   dissect_nfs3_remove_reply },
2911         { 14,   "RENAME",       /* OK */
2912         dissect_nfs3_rename_call,       dissect_nfs3_rename_reply },
2913         { 15,   "LINK",         /* OK */
2914         dissect_nfs3_link_call,         dissect_nfs3_link_reply },
2915         { 16,   "READDIR",      /* OK */
2916         dissect_nfs3_readdir_call,      dissect_nfs3_readdir_reply },
2917         { 17,   "READDIRPLUS",  /* OK */
2918         dissect_nfs3_readdirplus_call,  dissect_nfs3_readdirplus_reply },
2919         { 18,   "FSSTAT",       /* OK */
2920         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsstat_reply },
2921         { 19,   "FSINFO",       /* OK */
2922         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_fsinfo_reply },
2923         { 20,   "PATHCONF",     /* OK */
2924         dissect_nfs3_nfs_fh3_call,      dissect_nfs3_pathconf_reply },
2925         { 21,   "COMMIT",       /* OK */
2926         dissect_nfs3_commit_call,       dissect_nfs3_commit_reply },
2927         { 0,NULL,NULL,NULL }
2928 };
2929 /* end of NFS Version 3 */
2930
2931
2932 static struct true_false_string yesno = { "Yes", "No" };
2933
2934
2935 void
2936 proto_register_nfs(void)
2937 {
2938         static hf_register_info hf[] = {
2939                 { &hf_nfs_stat, {
2940                         "Status", "nfs.status2", FT_UINT32, BASE_DEC,
2941                         VALS(names_nfs_stat), 0, "Reply status" }},
2942                 { &hf_nfs_name, {
2943                         "Name", "nfs.name", FT_STRING, BASE_DEC,
2944                         NULL, 0, "Name" }},
2945                 { &hf_nfs_readlink_data, {
2946                         "Data", "nfs.readlink.data", FT_STRING, BASE_DEC,
2947                         NULL, 0, "Symbolic Link Data" }},
2948                 { &hf_nfs_read_offset, {
2949                         "Offset", "nfs.read.offset", FT_UINT32, BASE_DEC,
2950                         NULL, 0, "Read Offset" }},
2951                 { &hf_nfs_read_count, {
2952                         "Count", "nfs.read.count", FT_UINT32, BASE_DEC,
2953                         NULL, 0, "Read Count" }},
2954                 { &hf_nfs_read_totalcount, {
2955                         "Total Count", "nfs.read.totalcount", FT_UINT32, BASE_DEC,
2956                         NULL, 0, "Total Count (obsolete)" }},
2957                 { &hf_nfs_data, {
2958                         "Data", "nfs.data", FT_STRING, BASE_DEC,
2959                         NULL, 0, "Data" }},
2960                 { &hf_nfs_write_beginoffset, {
2961                         "Begin Offset", "nfs.write.beginoffset", FT_UINT32, BASE_DEC,
2962                         NULL, 0, "Begin offset (obsolete)" }},
2963                 { &hf_nfs_write_offset, {
2964                         "Offset", "nfs.write.offset", FT_UINT32, BASE_DEC,
2965                         NULL, 0, "Offset" }},
2966                 { &hf_nfs_write_totalcount, {
2967                         "Total Count", "nfs.write.totalcount", FT_UINT32, BASE_DEC,
2968                         NULL, 0, "Total Count (obsolete)" }},
2969                 { &hf_nfs_symlink_to, {
2970                         "To", "nfs.symlink.to", FT_STRING, BASE_DEC,
2971                         NULL, 0, "Symbolic link destination name" }},
2972                 { &hf_nfs_readdir_cookie, {
2973                         "Cookie", "nfs.readdir.cookie", FT_UINT32, BASE_DEC,
2974                         NULL, 0, "Directory Cookie" }},
2975                 { &hf_nfs_readdir_count, {
2976                         "Count", "nfs.readdir.count", FT_UINT32, BASE_DEC,
2977                         NULL, 0, "Directory Count" }},
2978                 { &hf_nfs_readdir_value_follows, {
2979                         "Value Follows", "nfs.readdir.value_follows", FT_BOOLEAN, BASE_NONE,
2980                         &yesno, 0, "Value Follows" }},
2981                 { &hf_nfs_readdir_entry, {
2982                         "Entry", "nfs.readdir.entry", FT_NONE, 0,
2983                         NULL, 0, "Directory Entry" }},
2984                 { &hf_nfs_readdir_entry_fileid, {
2985                         "File ID", "nfs.readdir.entry.fileid", FT_UINT32, BASE_DEC,
2986                         NULL, 0, "File ID" }},
2987                 { &hf_nfs_readdir_entry_name, {
2988                         "Name", "nfs.readdir.entry.name", FT_STRING, BASE_DEC,
2989                         NULL, 0, "Name" }},
2990                 { &hf_nfs_readdirplus_entry_name, {
2991                         "Name", "nfs.readdirplus.entry.name", FT_STRING, BASE_DEC,
2992                         NULL, 0, "Name" }},
2993                 { &hf_nfs_readdir_entry_cookie, {
2994                         "Cookie", "nfs.readdir.entry.cookie", FT_UINT32, BASE_DEC,
2995                         NULL, 0, "Directory Cookie" }},
2996                 { &hf_nfs_readdir_eof, {
2997                         "EOF", "nfs.readdir.eof", FT_UINT32, BASE_DEC,
2998                         NULL, 0, "EOF" }},
2999                 { &hf_nfs_statfs_tsize, {
3000                         "Transfer Size", "nfs.statfs.tsize", FT_UINT32, BASE_DEC,
3001                         NULL, 0, "Transfer Size" }},
3002                 { &hf_nfs_statfs_bsize, {
3003                         "Block Size", "nfs.statfs.bsize", FT_UINT32, BASE_DEC,
3004                         NULL, 0, "Block Size" }},
3005                 { &hf_nfs_statfs_blocks, {
3006                         "Total Blocks", "nfs.statfs.blocks", FT_UINT32, BASE_DEC,
3007                         NULL, 0, "Total Blocks" }},
3008                 { &hf_nfs_statfs_bfree, {
3009                         "Free Blocks", "nfs.statfs.bfree", FT_UINT32, BASE_DEC,
3010                         NULL, 0, "Free Blocks" }},
3011                 { &hf_nfs_statfs_bavail, {
3012                         "Available Blocks", "nfs.statfs.bavail", FT_UINT32, BASE_DEC,
3013                         NULL, 0, "Available Blocks" }},
3014                 { &hf_nfs_ftype3, {
3015                         "Type", "nfs.type", FT_UINT32, BASE_DEC,
3016                         VALS(names_nfs_ftype3), 0, "File Type" }},
3017                 { &hf_nfs_nfsstat3, {
3018                         "Status", "nfs.status", FT_UINT32, BASE_DEC,
3019                         VALS(names_nfs_nfsstat3), 0, "Reply status" }},
3020                 { &hf_nfs_read_eof, {
3021                         "EOF", "nfs.read.eof", FT_BOOLEAN, BASE_NONE,
3022                         &yesno, 0, "EOF" }},
3023                 { &hf_nfs_write_stable, {
3024                         "Stable", "nfs.write.stable", FT_UINT32, BASE_DEC,
3025                         VALS(names_stable_how), 0, "Stable" }},
3026                 { &hf_nfs_write_committed, {
3027                         "Committed", "nfs.write.committed", FT_UINT32, BASE_DEC,
3028                         VALS(names_stable_how), 0, "Committed" }},
3029                 { &hf_nfs_createmode3, {
3030                         "Create Mode", "nfs.createmode", FT_UINT32, BASE_DEC,
3031                         VALS(names_createmode3), 0, "Create Mode" }},
3032                 { &hf_nfs_fsstat_invarsec, {
3033                         "invarsec", "nfs.fsstat.invarsec", FT_UINT32, BASE_DEC,
3034                         NULL, 0, "probable number of seconds of file system invariance" }},
3035                 { &hf_nfs_fsinfo_rtmax, {
3036                         "rtmax", "nfs.fsinfo.rtmax", FT_UINT32, BASE_DEC,
3037                         NULL, 0, "maximum READ request" }},
3038                 { &hf_nfs_fsinfo_rtpref, {
3039                         "rtpref", "nfs.fsinfo.rtpref", FT_UINT32, BASE_DEC,
3040                         NULL, 0, "preferred READ request" }},
3041                 { &hf_nfs_fsinfo_rtmult, {
3042                         "rtmult", "nfs.fsinfo.rtmult", FT_UINT32, BASE_DEC,
3043                         NULL, 0, "suggested READ multiple" }},
3044                 { &hf_nfs_fsinfo_wtmax, {
3045                         "wtmax", "nfs.fsinfo.rtmax", FT_UINT32, BASE_DEC,
3046                         NULL, 0, "maximum WRITE request" }},
3047                 { &hf_nfs_fsinfo_wtpref, {
3048                         "wtpref", "nfs.fsinfo.rtpref", FT_UINT32, BASE_DEC,
3049                         NULL, 0, "preferred WRITE request" }},
3050                 { &hf_nfs_fsinfo_wtmult, {
3051                         "wtmult", "nfs.fsinfo.rtmult", FT_UINT32, BASE_DEC,
3052                         NULL, 0, "suggested WRITE multiple" }},
3053                 { &hf_nfs_fsinfo_dtpref, {
3054                         "dtpref", "nfs.fsinfo.dtpref", FT_UINT32, BASE_DEC,
3055                         NULL, 0, "preferred READDIR request" }},
3056                 { &hf_nfs_fsinfo_properties, {
3057                         "Properties", "nfs.fsinfo.propeties", FT_UINT32, BASE_HEX,
3058                         NULL, 0, "File System Properties" }},
3059                 { &hf_nfs_pathconf_linkmax, {
3060                         "linkmax", "nfs.pathconf.linkmax", FT_UINT32, BASE_DEC,
3061                         NULL, 0, "Maximum number of hard links" }},
3062                 { &hf_nfs_pathconf_name_max, {
3063                         "name_max", "nfs.pathconf.name_max", FT_UINT32, BASE_DEC,
3064                         NULL, 0, "Maximum file name length" }},
3065                 { &hf_nfs_pathconf_no_trunc, {
3066                         "no_trunc", "nfs.pathconf.no_trunc", FT_BOOLEAN, BASE_NONE,
3067                         &yesno, 0, "No long file name truncation" }},
3068                 { &hf_nfs_pathconf_chown_restricted, {
3069                         "chown_restricted", "nfs.pathconf.chown_restricted", FT_BOOLEAN, BASE_NONE,
3070                         &yesno, 0, "chown is restricted to root" }},
3071                 { &hf_nfs_pathconf_case_insensitive, {
3072                         "case_insensitive", "nfs.pathconf.case_insensitive", FT_BOOLEAN, BASE_NONE,
3073                         &yesno, 0, "file names are treated case insensitive" }},
3074                 { &hf_nfs_pathconf_case_preserving, {
3075                         "case_preserving", "nfs.pathconf.case_preserving", FT_BOOLEAN, BASE_NONE,
3076                         &yesno, 0, "file name cases are preserved" }}
3077         };
3078
3079         static gint *ett[] = {
3080                 &ett_nfs,
3081                 &ett_nfs_fhandle,
3082                 &ett_nfs_timeval,
3083                 &ett_nfs_mode,
3084                 &ett_nfs_fattr,
3085                 &ett_nfs_sattr,
3086                 &ett_nfs_diropargs,
3087                 &ett_nfs_readdir_entry,
3088                 &ett_nfs_mode3,
3089                 &ett_nfs_specdata3,
3090                 &ett_nfs_fh3,
3091                 &ett_nfs_nfstime3,
3092                 &ett_nfs_fattr3,
3093                 &ett_nfs_post_op_fh3,
3094                 &ett_nfs_sattr3,
3095                 &ett_nfs_diropargs3,
3096                 &ett_nfs_sattrguard3,
3097                 &ett_nfs_set_mode3,
3098                 &ett_nfs_set_uid3,
3099                 &ett_nfs_set_gid3,
3100                 &ett_nfs_set_size3,
3101                 &ett_nfs_set_atime,
3102                 &ett_nfs_set_mtime,
3103                 &ett_nfs_pre_op_attr,
3104                 &ett_nfs_post_op_attr,
3105                 &ett_nfs_wcc_attr,
3106                 &ett_nfs_wcc_data,
3107                 &ett_nfs_access,
3108                 &ett_nfs_fsinfo_properties
3109         };
3110         proto_nfs = proto_register_protocol("Network File System", "nfs");
3111         proto_register_field_array(proto_nfs, hf, array_length(hf));
3112         proto_register_subtree_array(ett, array_length(ett));
3113
3114         /* Register the protocol as RPC */
3115         rpc_init_prog(proto_nfs, NFS_PROGRAM, ett_nfs);
3116         /* Register the procedure tables */
3117         rpc_init_proc_table(NFS_PROGRAM, 2, nfs2_proc);
3118         rpc_init_proc_table(NFS_PROGRAM, 3, nfs3_proc);
3119 }