2 * Routines for nfs dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-nfs.c,v 1.6 1999/11/19 13:09:55 gram Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@unicom.net>
9 * Copyright 1998 Gerald Combs
11 * Copied from packet-smb.c
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.
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.
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.
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
38 #include "packet-rpc.h"
39 #include "packet-nfs.h"
42 static int proto_nfs = -1;
44 static gint ett_nfs = -1;
45 static gint ett_nfs_fhandle = -1;
46 static gint ett_nfs_timeval = -1;
47 static gint ett_nfs_mode = -1;
48 static gint ett_nfs_fattr = -1;
49 static gint ett_nfs_sattr = -1;
50 static gint ett_nfs_mode3 = -1;
51 static gint ett_nfs_specdata3 = -1;
52 static gint ett_nfs_fh3 = -1;
53 static gint ett_nfs_nfstime3 = -1;
54 static gint ett_nfs_fattr3 = -1;
55 static gint ett_nfs_sattr3 = -1;
56 static gint ett_nfs_sattrguard3 = -1;
57 static gint ett_nfs_set_mode3 = -1;
58 static gint ett_nfs_set_uid3 = -1;
59 static gint ett_nfs_set_gid3 = -1;
60 static gint ett_nfs_set_size3 = -1;
61 static gint ett_nfs_set_atime = -1;
62 static gint ett_nfs_set_mtime = -1;
63 static gint ett_nfs_pre_op_attr = -1;
64 static gint ett_nfs_post_op_attr = -1;
65 static gint ett_nfs_wcc_attr = -1;
66 static gint ett_nfs_wcc_data = -1;
69 /***************************/
70 /* NFS Version 2, RFC 1094 */
71 /***************************/
74 /* base 32 bit type for NFS v2 */
76 dissect_unsigned_int(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
79 offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"unsigned int");
84 /* RFC 1094, Page 12 */
86 dissect_stat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
87 char* name, guint32* status)
90 char* stat_name = NULL;
92 const value_string nfs2_stat[] =
102 { 20, "ERR_NOTDIR" },
107 { 63, "ERR_NAMETOOLONG" },
108 { 66, "ERR_NOTEMPTY" },
111 { 99, "ERR_WFLUSH" },
115 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
116 stat = EXTRACT_UINT(pd, offset+0);
117 stat_name = val_to_str(stat, nfs2_stat, "%u");
120 proto_tree_add_text(tree, offset, 4,
121 "%s: %s (%u)", name, stat_name, stat);
130 /* RFC 1094, Page 15 */
132 dissect_ftype(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
136 char* ftype_name = NULL;
138 const value_string nfs2_ftype[] =
141 { 1, "Regular File" },
143 { 3, "Block Special Device" },
144 { 4, "Character Special Device" },
145 { 5, "Symbolic Link" },
149 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
150 ftype = EXTRACT_UINT(pd, offset+0);
151 ftype_name = val_to_str(ftype, nfs2_ftype, "%u");
154 proto_tree_add_text(tree, offset, 4,
155 "%s: %s (%u)", name, ftype_name, ftype);
163 /* RFC 1094, Page 15 */
165 dissect_fhandle(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
168 proto_tree* ftree = NULL;
171 fitem = proto_tree_add_text(tree, offset, FHSIZE,
174 ftree = proto_item_add_subtree(fitem, ett_nfs_fhandle);
178 proto_tree_add_text(ftree,offset+0,FHSIZE,
179 "file handle (opaque data)");
188 dissect_timeval(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
193 proto_item* time_item;
194 proto_tree* time_tree = NULL;
196 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
197 seconds = EXTRACT_UINT(pd, offset+0);
198 mseconds = EXTRACT_UINT(pd, offset+4);
201 time_item = proto_tree_add_text(tree, offset, 8,
202 "%s: %u.%06u", name, seconds, mseconds);
204 time_tree = proto_item_add_subtree(time_item, ett_nfs_timeval);
208 proto_tree_add_text(time_tree,offset+0,4,
209 "seconds: %u", seconds);
210 proto_tree_add_text(time_tree,offset+4,4,
211 "micro seconds: %u", mseconds);
218 /* RFC 1094, Page 16 */
219 const value_string nfs2_mode_names[] = {
220 { 0040000, "Directory" },
221 { 0020000, "Character Special Device" },
222 { 0060000, "Block Special Device" },
223 { 0100000, "Regular File" },
224 { 0120000, "Symbolic Link" },
225 { 0140000, "Named Socket" },
229 dissect_mode(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
233 proto_item* mode_item = NULL;
234 proto_tree* mode_tree = NULL;
236 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
237 mode = EXTRACT_UINT(pd, offset+0);
240 mode_item = proto_tree_add_text(tree, offset, 4,
241 "%s: 0%o", name, mode);
243 mode_tree = proto_item_add_subtree(mode_item, ett_nfs_mode);
247 proto_tree_add_text(mode_tree, offset, 4, "%s",
248 decode_enumerated_bitfield(mode, 0160000, 16,
249 nfs2_mode_names, "%s"));
250 proto_tree_add_text(mode_tree, offset, 4, "%s",
251 decode_boolean_bitfield(mode, 04000, 16, "Set user id on exec", "not SUID"));
252 proto_tree_add_text(mode_tree, offset, 4, "%s",
253 decode_boolean_bitfield(mode, 02000, 16, "Set group id on exec", "not SGID"));
254 proto_tree_add_text(mode_tree, offset, 4, "%s",
255 decode_boolean_bitfield(mode, 01000, 16, "Save swapped text even after use", "not save swapped text"));
256 proto_tree_add_text(mode_tree, offset, 4, "%s",
257 decode_boolean_bitfield(mode, 0400, 16, "Read permission for owner", "no Read permission for owner"));
258 proto_tree_add_text(mode_tree, offset, 4, "%s",
259 decode_boolean_bitfield(mode, 0200, 16, "Write permission for owner", "no Write permission for owner"));
260 proto_tree_add_text(mode_tree, offset, 4, "%s",
261 decode_boolean_bitfield(mode, 0100, 16, "Execute permission for owner", "no Execute permission for owner"));
262 proto_tree_add_text(mode_tree, offset, 4, "%s",
263 decode_boolean_bitfield(mode, 040, 16, "Read permission for group", "no Read permission for group"));
264 proto_tree_add_text(mode_tree, offset, 4, "%s",
265 decode_boolean_bitfield(mode, 020, 16, "Write permission for group", "no Write permission for group"));
266 proto_tree_add_text(mode_tree, offset, 4, "%s",
267 decode_boolean_bitfield(mode, 010, 16, "Execute permission for group", "no Execute permission for group"));
268 proto_tree_add_text(mode_tree, offset, 4, "%s",
269 decode_boolean_bitfield(mode, 04, 16, "Read permission for others", "no Read permission for others"));
270 proto_tree_add_text(mode_tree, offset, 4, "%s",
271 decode_boolean_bitfield(mode, 02, 16, "Write permission for others", "no Write permission for others"));
272 proto_tree_add_text(mode_tree, offset, 4, "%s",
273 decode_boolean_bitfield(mode, 01, 16, "Execute permission for others", "no Execute permission for others"));
281 /* RFC 1094, Page 15 */
283 dissect_fattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
285 proto_item* fattr_item = NULL;
286 proto_tree* fattr_tree = NULL;
287 int old_offset = offset;
290 fattr_item = proto_tree_add_text(tree, offset,
291 END_OF_FRAME, "%s", name);
293 fattr_tree = proto_item_add_subtree(fattr_item, ett_nfs_fattr);
296 offset = dissect_ftype (pd,offset,fd,fattr_tree,"type");
297 offset = dissect_mode (pd,offset,fd,fattr_tree,"mode");
298 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"nlink");
299 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"uid");
300 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"gid");
301 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"size");
302 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocksize");
303 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"rdev");
304 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocks");
305 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fsid");
306 offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fileid");
307 offset = dissect_timeval (pd,offset,fd,fattr_tree,"atime");
308 offset = dissect_timeval (pd,offset,fd,fattr_tree,"mtime");
309 offset = dissect_timeval (pd,offset,fd,fattr_tree,"ctime");
311 /* now we know, that fattr is shorter */
313 proto_item_set_len(fattr_item, offset - old_offset);
320 /* RFC 1094, Page 17 */
322 dissect_sattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
324 proto_item* sattr_item = NULL;
325 proto_tree* sattr_tree = NULL;
326 int old_offset = offset;
329 sattr_item = proto_tree_add_text(tree, offset,
330 END_OF_FRAME, "%s", name);
332 sattr_tree = proto_item_add_subtree(sattr_item, ett_nfs_sattr);
335 /* some how we should indicate here, that -1 means "do not set" */
336 offset = dissect_mode (pd,offset,fd,sattr_tree,"mode");
337 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"uid");
338 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"gid");
339 offset = dissect_unsigned_int (pd,offset,fd,sattr_tree,"size");
340 offset = dissect_timeval (pd,offset,fd,sattr_tree,"atime");
341 offset = dissect_timeval (pd,offset,fd,sattr_tree,"mtime");
343 /* now we know, that sattr is shorter */
345 proto_item_set_len(sattr_item, offset - old_offset);
352 /* generic NFS2 call dissector */
354 dissect_nfs2_any_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
356 offset = dissect_fhandle(pd, offset, fd, tree, "object");
362 /* generic NFS2 reply dissector */
364 dissect_nfs2_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
368 offset = dissect_stat(pd, offset, fd, tree, "status", &status);
374 /* RFC 1094, Page 5 */
376 dissect_nfs2_getattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
378 offset = dissect_fhandle(pd, offset, fd, tree, "object");
384 /* RFC 1094, Page 5 */
386 dissect_nfs2_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
390 /* attrstat: RFC 1094, Page 17 */
391 offset = dissect_stat(pd, offset, fd, tree, "status", &status);
394 offset = dissect_fattr(pd, offset, fd, tree, "attributes");
405 /* RFC 1094, Page 6 */
407 dissect_nfs2_setattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
409 offset = dissect_fhandle(pd, offset, fd, tree, "file" );
410 offset = dissect_sattr (pd, offset, fd, tree, "attributes");
416 /* RFC 1094, Page 6 */
418 dissect_nfs2_setattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
422 /* attrstat: RFC 1094, Page 17 */
423 offset = dissect_stat(pd, offset, fd, tree, "status", &status);
426 offset = dissect_fattr(pd, offset, fd, tree, "attributes");
437 /* more to come here */
440 /* proc number, "proc name", dissect_request, dissect_reply */
441 /* NULL as function pointer means: take the generic one. */
442 const vsff nfs2_proc[] = {
443 { 0, "NULL", NULL, NULL },
444 { 1, "GETATTR", dissect_nfs2_getattr_call, dissect_nfs2_getattr_reply },
445 { 2, "SETATTR", dissect_nfs2_setattr_call, dissect_nfs2_setattr_reply },
446 { 3, "ROOT", NULL, NULL },
447 { 4, "LOOKUP", dissect_nfs2_any_call, dissect_nfs2_any_reply },
448 { 5, "READLINK", dissect_nfs2_any_call, dissect_nfs2_any_reply },
449 { 6, "READ", dissect_nfs2_any_call, dissect_nfs2_any_reply },
450 { 7, "WRITECACHE", NULL, NULL },
451 { 8, "WRITE", dissect_nfs2_any_call, dissect_nfs2_any_reply },
452 { 9, "CREATE", dissect_nfs2_any_call, dissect_nfs2_any_reply },
453 { 10, "REMOVE", dissect_nfs2_any_call, dissect_nfs2_any_reply },
454 { 11, "RENAME", dissect_nfs2_any_call, dissect_nfs2_any_reply },
455 { 12, "LINK", dissect_nfs2_any_call, dissect_nfs2_any_reply },
456 { 13, "SYMLINK", dissect_nfs2_any_call, dissect_nfs2_any_reply },
457 { 14, "MKDIR", dissect_nfs2_any_call, dissect_nfs2_any_reply },
458 { 15, "RMDIR", dissect_nfs2_any_call, dissect_nfs2_any_reply },
459 { 16, "READDIR", dissect_nfs2_any_call, dissect_nfs2_any_reply },
460 { 17, "STATFS", dissect_nfs2_any_call, dissect_nfs2_any_reply },
461 { 0, NULL, NULL, NULL }
463 /* end of NFS Version 2 */
466 /***************************/
467 /* NFS Version 3, RFC 1813 */
468 /***************************/
471 /* RFC 1813, Page 15 */
473 dissect_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
476 offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"uint64");
481 /* RFC 1813, Page 15 */
483 dissect_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
486 offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uint32");
491 /* RFC 1813, Page 15 */
493 dissect_fileid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
496 offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"fileid3");
501 /* RFC 1813, Page 16 */
503 dissect_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
506 offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uid3");
511 /* RFC 1813, Page 16 */
513 dissect_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
516 offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"gid3");
521 /* RFC 1813, Page 16 */
523 dissect_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
526 offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"size3");
531 /* RFC 1813, Page 16 */
533 dissect_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
537 proto_item* mode3_item = NULL;
538 proto_tree* mode3_tree = NULL;
540 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
541 mode3 = EXTRACT_UINT(pd, offset+0);
544 mode3_item = proto_tree_add_text(tree, offset, 4,
545 "%s: 0%o", name, mode3);
547 mode3_tree = proto_item_add_subtree(mode3_item, ett_nfs_mode3);
550 /* RFC 1813, Page 23 */
552 proto_tree_add_text(mode3_tree, offset, 4, "%s",
553 decode_boolean_bitfield(mode3, 0x800, 12, "Set user id on exec", "not SUID"));
554 proto_tree_add_text(mode3_tree, offset, 4, "%s",
555 decode_boolean_bitfield(mode3, 0x400, 12, "Set group id on exec", "not SGID"));
556 proto_tree_add_text(mode3_tree, offset, 4, "%s",
557 decode_boolean_bitfield(mode3, 0x200, 12, "Save swapped text even after use", "not save swapped text"));
558 proto_tree_add_text(mode3_tree, offset, 4, "%s",
559 decode_boolean_bitfield(mode3, 0x100, 12, "Read permission for owner", "no Read permission for owner"));
560 proto_tree_add_text(mode3_tree, offset, 4, "%s",
561 decode_boolean_bitfield(mode3, 0x80, 12, "Write permission for owner", "no Write permission for owner"));
562 proto_tree_add_text(mode3_tree, offset, 4, "%s",
563 decode_boolean_bitfield(mode3, 0x40, 12, "Execute permission for owner", "no Execute permission for owner"));
564 proto_tree_add_text(mode3_tree, offset, 4, "%s",
565 decode_boolean_bitfield(mode3, 0x20, 12, "Read permission for group", "no Read permission for group"));
566 proto_tree_add_text(mode3_tree, offset, 4, "%s",
567 decode_boolean_bitfield(mode3, 0x10, 12, "Write permission for group", "no Write permission for group"));
568 proto_tree_add_text(mode3_tree, offset, 4, "%s",
569 decode_boolean_bitfield(mode3, 0x8, 12, "Execute permission for group", "no Execute permission for group"));
570 proto_tree_add_text(mode3_tree, offset, 4, "%s",
571 decode_boolean_bitfield(mode3, 0x4, 12, "Read permission for others", "no Read permission for others"));
572 proto_tree_add_text(mode3_tree, offset, 4, "%s",
573 decode_boolean_bitfield(mode3, 0x2, 12, "Write permission for others", "no Write permission for others"));
574 proto_tree_add_text(mode3_tree, offset, 4, "%s",
575 decode_boolean_bitfield(mode3, 0x1, 12, "Execute permission for others", "no Execute permission for others"));
583 /* RFC 1813, Page 16 */
585 dissect_count3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
586 char* name, char* type)
588 offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"count");
593 /* RFC 1813, Page 16 */
595 dissect_nfsstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
596 char* name, guint32* status)
599 char* nfsstat3_name = NULL;
601 const value_string nfs3_nfsstat3[] =
612 { 20, "ERR_NOTDIR" },
619 { 63, "ERR_NAMETOOLONG" },
620 { 66, "ERR_NOTEMPTY" },
623 { 71, "ERR_REMOTE" },
624 { 10001, "ERR_BADHANDLE" },
625 /* RFC 1813, Page 17 */
626 { 10002, "ERR_NOT_SYNC" },
627 { 10003, "ERR_BAD_COOKIE" },
628 { 10004, "ERR_NOTSUPP" },
629 { 10005, "ERR_TOOSMALL" },
630 { 10006, "ERR_SERVERFAULT" },
631 { 10007, "ERR_BADTYPE" },
632 { 10008, "ERR_JUKEBOX" },
636 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
637 nfsstat3 = EXTRACT_UINT(pd, offset+0);
638 nfsstat3_name = val_to_str(nfsstat3, nfs3_nfsstat3, "%u");
641 proto_tree_add_text(tree, offset, 4,
642 "%s: %s (%u)", name, nfsstat3_name, nfsstat3);
651 /* RFC 1813, Page 17, 18, 19, 20: error explanations */
654 /* RFC 1813, Page 20 */
656 dissect_ftype3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
660 char* ftype3_name = NULL;
662 const value_string nfs3_ftype3[] =
664 { 1, "Regular File" },
666 { 3, "Block Special Device" },
667 { 4, "Character Special Device" },
668 { 5, "Symbolic Link" },
674 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
675 ftype3 = EXTRACT_UINT(pd, offset+0);
676 ftype3_name = val_to_str(ftype3, nfs3_ftype3, "%u");
679 proto_tree_add_text(tree, offset, 4,
680 "%s: %s (%u)", name, ftype3_name, ftype3);
688 /* RFC 1813, Page 20 */
690 dissect_specdata3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
695 proto_item* specdata3_item;
696 proto_tree* specdata3_tree = NULL;
698 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
699 specdata1 = EXTRACT_UINT(pd, offset+0);
700 specdata2 = EXTRACT_UINT(pd, offset+4);
703 specdata3_item = proto_tree_add_text(tree, offset, 8,
704 "%s: %u,%u", name, specdata1, specdata2);
706 specdata3_tree = proto_item_add_subtree(specdata3_item,
710 if (specdata3_tree) {
711 proto_tree_add_text(specdata3_tree,offset+0,4,
712 "specdata1: %u", specdata1);
713 proto_tree_add_text(specdata3_tree,offset+4,4,
714 "specdata2: %u", specdata2);
722 /* RFC 1813, Page 21 */
724 dissect_nfs_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
730 proto_tree* ftree = NULL;
732 fh3_len = EXTRACT_UINT(pd, offset+0);
733 fh3_len_full = rpc_roundup(fh3_len);
734 fh3_fill = fh3_len_full - fh3_len;
737 fitem = proto_tree_add_text(tree, offset, 4+fh3_len_full,
740 ftree = proto_item_add_subtree(fitem, ett_nfs_fh3);
744 proto_tree_add_text(ftree,offset+0,4,
745 "length: %u", fh3_len);
746 proto_tree_add_text(ftree,offset+4,fh3_len,
747 "file handle (opaque data)");
749 proto_tree_add_text(ftree,offset+4+fh3_len,fh3_fill,
752 offset += 4 + fh3_len_full;
757 /* RFC 1813, Page 21 */
759 dissect_nfstime3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,char* name)
764 proto_item* time_item;
765 proto_tree* time_tree = NULL;
767 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
768 seconds = EXTRACT_UINT(pd, offset+0);
769 nseconds = EXTRACT_UINT(pd, offset+4);
772 time_item = proto_tree_add_text(tree, offset, 8,
773 "%s: %u.%09u", name, seconds, nseconds);
775 time_tree = proto_item_add_subtree(time_item, ett_nfs_nfstime3);
779 proto_tree_add_text(time_tree,offset+0,4,
780 "seconds: %u", seconds);
781 proto_tree_add_text(time_tree,offset+4,4,
782 "nano seconds: %u", nseconds);
789 /* RFC 1813, Page 22 */
791 dissect_fattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
793 proto_item* fattr3_item = NULL;
794 proto_tree* fattr3_tree = NULL;
795 int old_offset = offset;
798 fattr3_item = proto_tree_add_text(tree, offset,
799 END_OF_FRAME, "%s", name);
801 fattr3_tree = proto_item_add_subtree(fattr3_item, ett_nfs_fattr3);
804 offset = dissect_ftype3 (pd,offset,fd,fattr3_tree,"type");
805 offset = dissect_mode3 (pd,offset,fd,fattr3_tree,"mode");
806 offset = dissect_uint32 (pd,offset,fd,fattr3_tree,"nlink");
807 offset = dissect_uid3 (pd,offset,fd,fattr3_tree,"uid");
808 offset = dissect_gid3 (pd,offset,fd,fattr3_tree,"gid");
809 offset = dissect_size3 (pd,offset,fd,fattr3_tree,"size");
810 offset = dissect_size3 (pd,offset,fd,fattr3_tree,"used");
811 offset = dissect_specdata3(pd,offset,fd,fattr3_tree,"rdev");
812 offset = dissect_uint64 (pd,offset,fd,fattr3_tree,"fsid");
813 offset = dissect_fileid3 (pd,offset,fd,fattr3_tree,"fileid");
814 offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"atime");
815 offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"mtime");
816 offset = dissect_nfstime3 (pd,offset,fd,fattr3_tree,"ctime");
818 /* now we know, that fattr3 is shorter */
820 proto_item_set_len(fattr3_item, offset - old_offset);
827 const value_string value_follows[3] =
830 { 1, "value follows"},
835 /* RFC 1813, Page 23 */
837 dissect_post_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
839 proto_item* post_op_attr_item = NULL;
840 proto_tree* post_op_attr_tree = NULL;
841 int old_offset = offset;
842 guint32 attributes_follow;
845 post_op_attr_item = proto_tree_add_text(tree, offset,
846 END_OF_FRAME, "%s", name);
847 if (post_op_attr_item)
848 post_op_attr_tree = proto_item_add_subtree(post_op_attr_item, ett_nfs_post_op_attr);
851 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
852 attributes_follow = EXTRACT_UINT(pd, offset+0);
853 proto_tree_add_text(post_op_attr_tree, offset, 4,
854 "attributes_follow: %s (%u)",
855 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
857 switch (attributes_follow) {
859 offset = dissect_fattr3(pd, offset, fd, post_op_attr_tree,
867 /* now we know, that post_op_attr_tree is shorter */
868 if (post_op_attr_item) {
869 proto_item_set_len(post_op_attr_item, offset - old_offset);
876 /* RFC 1813, Page 24 */
878 dissect_wcc_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
880 proto_item* wcc_attr_item = NULL;
881 proto_tree* wcc_attr_tree = NULL;
882 int old_offset = offset;
885 wcc_attr_item = proto_tree_add_text(tree, offset,
886 END_OF_FRAME, "%s", name);
888 wcc_attr_tree = proto_item_add_subtree(wcc_attr_item, ett_nfs_wcc_attr);
891 offset = dissect_size3 (pd, offset, fd, wcc_attr_tree, "size" );
892 offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "mtime");
893 offset = dissect_nfstime3(pd, offset, fd, wcc_attr_tree, "ctime");
895 /* now we know, that wcc_attr_tree is shorter */
897 proto_item_set_len(wcc_attr_item, offset - old_offset);
904 /* RFC 1813, Page 24 */
906 dissect_pre_op_attr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
908 proto_item* pre_op_attr_item = NULL;
909 proto_tree* pre_op_attr_tree = NULL;
910 int old_offset = offset;
911 guint32 attributes_follow;
914 pre_op_attr_item = proto_tree_add_text(tree, offset,
915 END_OF_FRAME, "%s", name);
916 if (pre_op_attr_item)
917 pre_op_attr_tree = proto_item_add_subtree(pre_op_attr_item, ett_nfs_pre_op_attr);
920 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
921 attributes_follow = EXTRACT_UINT(pd, offset+0);
922 proto_tree_add_text(pre_op_attr_tree, offset, 4,
923 "attributes_follow: %s (%u)",
924 val_to_str(attributes_follow,value_follows,"Unknown"), attributes_follow);
926 switch (attributes_follow) {
928 offset = dissect_wcc_attr(pd, offset, fd, pre_op_attr_tree,
936 /* now we know, that pre_op_attr_tree is shorter */
937 if (pre_op_attr_item) {
938 proto_item_set_len(pre_op_attr_item, offset - old_offset);
945 /* RFC 1813, Page 24 */
947 dissect_wcc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
949 proto_item* wcc_data_item = NULL;
950 proto_tree* wcc_data_tree = NULL;
951 int old_offset = offset;
954 wcc_data_item = proto_tree_add_text(tree, offset,
955 END_OF_FRAME, "%s", name);
957 wcc_data_tree = proto_item_add_subtree(wcc_data_item, ett_nfs_wcc_data);
960 offset = dissect_pre_op_attr (pd, offset, fd, wcc_data_tree, "before");
961 offset = dissect_post_op_attr(pd, offset, fd, wcc_data_tree, "after" );
963 /* now we know, that wcc_data is shorter */
965 proto_item_set_len(wcc_data_item, offset - old_offset);
972 /* RFC 1813, Page 25 */
974 dissect_set_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
976 proto_item* set_mode3_item = NULL;
977 proto_tree* set_mode3_tree = NULL;
978 int old_offset = offset;
982 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
983 set_it = EXTRACT_UINT(pd, offset+0);
984 set_it_name = val_to_str(set_it,value_follows,"Unknown");
987 set_mode3_item = proto_tree_add_text(tree, offset,
988 END_OF_FRAME, "%s: %s", name, set_it_name);
990 set_mode3_tree = proto_item_add_subtree(set_mode3_item, ett_nfs_set_mode3);
994 proto_tree_add_text(set_mode3_tree, offset, 4,
995 "set_it: %s (%u)", set_it_name, set_it);
1001 offset = dissect_mode3(pd, offset, fd, set_mode3_tree,
1009 /* now we know, that set_mode3 is shorter */
1010 if (set_mode3_item) {
1011 proto_item_set_len(set_mode3_item, offset - old_offset);
1018 /* RFC 1813, Page 26 */
1020 dissect_set_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1022 proto_item* set_uid3_item = NULL;
1023 proto_tree* set_uid3_tree = NULL;
1024 int old_offset = offset;
1028 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1029 set_it = EXTRACT_UINT(pd, offset+0);
1030 set_it_name = val_to_str(set_it,value_follows,"Unknown");
1033 set_uid3_item = proto_tree_add_text(tree, offset,
1034 END_OF_FRAME, "%s: %s", name, set_it_name);
1036 set_uid3_tree = proto_item_add_subtree(set_uid3_item, ett_nfs_set_uid3);
1040 proto_tree_add_text(set_uid3_tree, offset, 4,
1041 "set_it: %s (%u)", set_it_name, set_it);
1047 offset = dissect_uid3(pd, offset, fd, set_uid3_tree,
1055 /* now we know, that set_uid3 is shorter */
1056 if (set_uid3_item) {
1057 proto_item_set_len(set_uid3_item, offset - old_offset);
1064 /* RFC 1813, Page 26 */
1066 dissect_set_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1068 proto_item* set_gid3_item = NULL;
1069 proto_tree* set_gid3_tree = NULL;
1070 int old_offset = offset;
1074 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1075 set_it = EXTRACT_UINT(pd, offset+0);
1076 set_it_name = val_to_str(set_it,value_follows,"Unknown");
1079 set_gid3_item = proto_tree_add_text(tree, offset,
1080 END_OF_FRAME, "%s: %s", name, set_it_name);
1082 set_gid3_tree = proto_item_add_subtree(set_gid3_item, ett_nfs_set_gid3);
1086 proto_tree_add_text(set_gid3_tree, offset, 4,
1087 "set_it: %s (%u)", set_it_name, set_it);
1093 offset = dissect_gid3(pd, offset, fd, set_gid3_tree,
1101 /* now we know, that set_gid3 is shorter */
1102 if (set_gid3_item) {
1103 proto_item_set_len(set_gid3_item, offset - old_offset);
1110 /* RFC 1813, Page 26 */
1112 dissect_set_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1114 proto_item* set_size3_item = NULL;
1115 proto_tree* set_size3_tree = NULL;
1116 int old_offset = offset;
1120 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1121 set_it = EXTRACT_UINT(pd, offset+0);
1122 set_it_name = val_to_str(set_it,value_follows,"Unknown");
1125 set_size3_item = proto_tree_add_text(tree, offset,
1126 END_OF_FRAME, "%s: %s", name, set_it_name);
1128 set_size3_tree = proto_item_add_subtree(set_size3_item, ett_nfs_set_size3);
1132 proto_tree_add_text(set_size3_tree, offset, 4,
1133 "set_it: %s (%u)", set_it_name, set_it);
1139 offset = dissect_size3(pd, offset, fd, set_size3_tree,
1147 /* now we know, that set_size3 is shorter */
1148 if (set_size3_item) {
1149 proto_item_set_len(set_size3_item, offset - old_offset);
1156 /* RFC 1813, Page 25 */
1157 #define DONT_CHANGE 0
1158 #define SET_TO_SERVER_TIME 1
1159 #define SET_TO_CLIENT_TIME 2
1161 const value_string time_how[] =
1163 { DONT_CHANGE, "don't change" },
1164 { SET_TO_SERVER_TIME, "set to server time" },
1165 { SET_TO_CLIENT_TIME, "set to client time" },
1170 /* RFC 1813, Page 26 */
1172 dissect_set_atime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1174 proto_item* set_atime_item = NULL;
1175 proto_tree* set_atime_tree = NULL;
1176 int old_offset = offset;
1180 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1181 set_it = EXTRACT_UINT(pd, offset+0);
1182 set_it_name = val_to_str(set_it,time_how,"Unknown");
1185 set_atime_item = proto_tree_add_text(tree, offset,
1186 END_OF_FRAME, "%s: %s",
1187 name, set_it_name, set_it);
1189 set_atime_tree = proto_item_add_subtree(set_atime_item, ett_nfs_set_atime);
1193 proto_tree_add_text(set_atime_tree, offset, 4,
1194 "set_it: %s (%u)", set_it_name, set_it);
1199 case SET_TO_CLIENT_TIME:
1201 offset = dissect_nfstime3(pd, offset, fd, set_atime_tree,
1209 /* now we know, that set_atime is shorter */
1210 if (set_atime_item) {
1211 proto_item_set_len(set_atime_item, offset - old_offset);
1218 /* RFC 1813, Page 26 */
1220 dissect_set_mtime(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1222 proto_item* set_mtime_item = NULL;
1223 proto_tree* set_mtime_tree = NULL;
1224 int old_offset = offset;
1228 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1229 set_it = EXTRACT_UINT(pd, offset+0);
1230 set_it_name = val_to_str(set_it,time_how,"Unknown");
1233 set_mtime_item = proto_tree_add_text(tree, offset,
1234 END_OF_FRAME, "%s: %s",
1235 name, set_it_name, set_it);
1237 set_mtime_tree = proto_item_add_subtree(set_mtime_item, ett_nfs_set_mtime);
1241 proto_tree_add_text(set_mtime_tree, offset, 4,
1242 "set_it: %s (%u)", set_it_name, set_it);
1247 case SET_TO_CLIENT_TIME:
1249 offset = dissect_nfstime3(pd, offset, fd, set_mtime_tree,
1257 /* now we know, that set_mtime is shorter */
1258 if (set_mtime_item) {
1259 proto_item_set_len(set_mtime_item, offset - old_offset);
1266 /* RFC 1813, Page 26 */
1268 dissect_sattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
1270 proto_item* sattr3_item = NULL;
1271 proto_tree* sattr3_tree = NULL;
1272 int old_offset = offset;
1275 sattr3_item = proto_tree_add_text(tree, offset,
1276 END_OF_FRAME, "%s", name);
1278 sattr3_tree = proto_item_add_subtree(sattr3_item, ett_nfs_sattr3);
1281 offset = dissect_set_mode3(pd, offset, fd, sattr3_tree, "mode");
1282 offset = dissect_set_uid3 (pd, offset, fd, sattr3_tree, "uid");
1283 offset = dissect_set_gid3 (pd, offset, fd, sattr3_tree, "gid");
1284 offset = dissect_set_size3(pd, offset, fd, sattr3_tree, "size");
1285 offset = dissect_set_atime(pd, offset, fd, sattr3_tree, "atime");
1286 offset = dissect_set_mtime(pd, offset, fd, sattr3_tree, "mtime");
1288 /* now we know, that sattr3 is shorter */
1290 proto_item_set_len(sattr3_item, offset - old_offset);
1297 /* generic NFS3 call dissector */
1299 dissect_nfs3_any_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1301 offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
1306 /* generic NFS3 reply dissector */
1308 dissect_nfs3_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1312 offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status);
1319 /* RFC 1813, Page 32 */
1321 dissect_nfs3_getattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1323 offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
1328 /* RFC 1813, Page 32 */
1330 dissect_nfs3_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1334 offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status);
1337 offset = dissect_fattr3(pd, offset, fd, tree, "obj_attributes");
1348 /* RFC 1813, Page 33 */
1350 dissect_sattrguard3(const u_char* pd, int offset, frame_data* fd, proto_tree* tree, char *name)
1352 proto_item* sattrguard3_item = NULL;
1353 proto_tree* sattrguard3_tree = NULL;
1354 int old_offset = offset;
1358 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
1359 check = EXTRACT_UINT(pd, offset+0);
1360 check_name = val_to_str(check,value_follows,"Unknown");
1363 sattrguard3_item = proto_tree_add_text(tree, offset,
1364 END_OF_FRAME, "%s: %s", name, check_name);
1365 if (sattrguard3_item)
1366 sattrguard3_tree = proto_item_add_subtree(sattrguard3_item, ett_nfs_sattrguard3);
1369 if (sattrguard3_tree)
1370 proto_tree_add_text(sattrguard3_tree, offset, 4,
1371 "check: %s (%u)", check_name, check);
1377 offset = dissect_nfstime3(pd, offset, fd, sattrguard3_tree,
1385 /* now we know, that sattrguard3 is shorter */
1386 if (sattrguard3_item) {
1387 proto_item_set_len(sattrguard3_item, offset - old_offset);
1394 /* RFC 1813, Page 33 */
1396 dissect_nfs3_setattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1398 offset = dissect_nfs_fh3 (pd, offset, fd, tree, "object");
1399 offset = dissect_sattr3 (pd, offset, fd, tree, "new_attributes");
1400 offset = dissect_sattrguard3(pd, offset, fd, tree, "guard");
1405 /* RFC 1813, Page 33 */
1407 dissect_nfs3_setattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
1411 offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status);
1414 offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
1417 offset = dissect_wcc_data(pd, offset, fd, tree, "obj_wcc");
1425 /* proc number, "proc name", dissect_request, dissect_reply */
1426 /* NULL as function pointer means: take the generic one. */
1427 const vsff nfs3_proc[] = {
1428 { 0, "NULL", NULL, NULL },
1429 { 1, "GETATTR", dissect_nfs3_getattr_call, dissect_nfs3_getattr_reply },
1430 { 2, "SETATTR", dissect_nfs3_setattr_call, dissect_nfs3_setattr_reply },
1431 { 3, "LOOKUP", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1432 { 4, "ACCESS", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1433 { 5, "READLINK", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1434 { 6, "READ", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1435 { 7, "WRITE", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1436 { 8, "CREATE", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1437 { 9, "MKDIR", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1438 { 10, "SYMLINK", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1439 { 11, "MKNOD", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1440 { 12, "REMOVE", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1441 { 13, "RMDIR", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1442 { 14, "RENAME", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1443 { 15, "LINK", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1444 { 16, "READDIR", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1445 { 17, "READDIRPLUS", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1446 { 18, "FSSTAT", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1447 { 19, "FSINFO", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1448 { 20, "PATHCONF", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1449 { 21, "COMMIT", dissect_nfs3_any_call, dissect_nfs3_any_reply },
1450 { 0, NULL, NULL, NULL }
1452 /* end of NFS Version 3 */
1456 proto_register_nfs(void)
1458 static gint *ett[] = {
1471 &ett_nfs_sattrguard3,
1478 &ett_nfs_pre_op_attr,
1479 &ett_nfs_post_op_attr,
1483 proto_nfs = proto_register_protocol("Network File System", "nfs");
1484 proto_register_subtree_array(ett, array_length(ett));
1486 /* Register the protocol as RPC */
1487 rpc_init_prog(proto_nfs, NFS_PROGRAM, ett_nfs);
1488 /* Register the procedure tables */
1489 rpc_init_proc_table(NFS_PROGRAM, 2, nfs2_proc);
1490 rpc_init_proc_table(NFS_PROGRAM, 3, nfs3_proc);