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