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