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