Ethereal-dev: [ethereal-dev] NFS dissector continued

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Uwe Girlich <Uwe.Girlich@xxxxxxxxxxx>
Date: Thu, 4 Nov 1999 14:51:26 +0100
I just finished the first part of the NFS dissector. It can only dissect
GETATTR requests and replies (V2 and V3) but it is a start. I want to discuss
some points I found during the implementation:

* How should I print times of files? NFS v2 uses a microsecond resolution and
NFS v3 a nanosecond one. I would prefer a generic time print routine.

* What do we do with 64 Bit numbers? I used %u, if the upper part is zero
and %x%08x, if the upper part is non-zero. Maybe I can use %llu on GNU C
systems.

* I would like to dissect the NFS file handle a bit further (major,minor of
the device, inode of the file). The problem is only, every NFS server uses a
different encoding scheme. tcpdump contains some heuristics for some systems
(and I know the SVR4 encoding) but this may not always be correct.

* I give almost always the type of a field in the dissector tree like in
mode (mode3): 777
Is this overkill?

In case someone doesn't have a capture of NFS I provide two short capture files
as attachements (tcpdump).

Oh, and BTW, the RPC part became a face lift too. Now I have a generic
RPC string parse routine (used for Credentials, machinename).

Index: packet-nfs.c
===================================================================
RCS file: /cvsroot/ethereal/packet-nfs.c,v
retrieving revision 1.1
diff -u -r1.1 packet-nfs.c
--- packet-nfs.c	1999/10/29 01:11:23	1.1
+++ packet-nfs.c	1999/11/04 13:11:02
@@ -41,130 +41,780 @@
 
 static int proto_nfs = -1;
 
-int dissect_fh2(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
 
-/*
-This is the table with the dissector functions. As almost all functions
-start with a file handle and I had no more time, this is all I did up to now.
-The RPC layer will cope with any following data and interpret it as data.
-I'm not sure, if all compilers fill undefined structure members with zeros,
-so I give the NULL value in all cases.
-*/
+/***************************/
+/* NFS Version 2, RFC 1094 */
+/***************************/
 
-/* proc number, "proc name", dissect_request, dissect_reply */
-/* NULL as function pointer means: take the generic one. */
-const vsff nfs2_proc[] = {
-	{ 0,	"NULL",		NULL,		NULL },
-	{ 1,	"GETATTR",	dissect_fh2,	NULL },
-	{ 2,	"SETATTR",	dissect_fh2,	NULL },
-	{ 3,	"ROOT",		NULL,		NULL },
-	{ 4,	"LOOKUP",	dissect_fh2,	NULL },
-	{ 5,	"READLINK",	dissect_fh2,	NULL },
-	{ 6,	"READ",		dissect_fh2,	NULL },
-	{ 7,	"WRITECACHE",	dissect_fh2,	NULL },
-	{ 8,	"WRITE",	dissect_fh2,	NULL },
-	{ 9,	"CREATE",	dissect_fh2,	NULL },
-	{ 10,	"REMOVE",	dissect_fh2,	NULL },
-	{ 11,	"RENAME",	dissect_fh2,	NULL },
-	{ 12,	"LINK",		dissect_fh2,	NULL },
-	{ 13,	"SYMLINK",	dissect_fh2,	NULL },
-	{ 14,	"MKDIR",	dissect_fh2,	NULL },
-	{ 15,	"RMDIR",	dissect_fh2,	NULL },
-	{ 16,	"READDIR",	dissect_fh2,	NULL },
-	{ 17,	"STATFS",	dissect_fh2,	NULL },
-	{ 0,	NULL,		NULL,		NULL }
-};
 
-int dissect_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
-int dissect_nfs3_getattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
+/* base 32 bit type for NFS v2 */
+int
+dissect_unsigned_int(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"unsigned int");
+	return offset;
+}
 
 
-const vsff nfs3_proc[] = {
-	{ 0,	"NULL",		NULL,		NULL },
-	{ 1,	"GETATTR",	dissect_nfs3_getattr_call,	NULL },
-	{ 2,	"SETATTR",	dissect_fh3,	NULL },
-	{ 3,	"LOOKUP",	dissect_fh3,	NULL },
-	{ 4,	"ACCESS",	dissect_fh3,	NULL },
-	{ 5,	"READLINK",	dissect_fh3,	NULL },
-	{ 6,	"READ",		dissect_fh3,	NULL },
-	{ 7,	"WRITE",	dissect_fh3,	NULL },
-	{ 8,	"CREATE",	dissect_fh3,	NULL },
-	{ 9,	"MKDIR",	dissect_fh3,	NULL },
-	{ 10,	"SYMLINK",	dissect_fh3,	NULL },
-	{ 11,	"MKNOD",	dissect_fh3,	NULL },
-	{ 12,	"REMOVE",	dissect_fh3,	NULL },
-	{ 13,	"RMDIR",	dissect_fh3,	NULL },
-	{ 14,	"RENAME",	dissect_fh3,	NULL },
-	{ 15,	"LINK",		dissect_fh3,	NULL },
-	{ 16,	"READDIR",	dissect_fh3,	NULL },
-	{ 17,	"READDIRPLUS",	dissect_fh3,	NULL },
-	{ 18,	"FSSTAT",	dissect_fh3,	NULL },
-	{ 19,	"FSINFO",	dissect_fh3,	NULL },
-	{ 20,	"PATHCONF",	dissect_fh3,	NULL },
-	{ 21,	"COMMIT",	dissect_fh3,	NULL },
-	{ 0,	NULL,		NULL,		NULL }
-};
+/* RFC 1094, Page 12 */
+int
+dissect_stat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name, guint32* status)
+{
+	guint32 stat;
+	char* stat_name = NULL;
 
+	const value_string nfs2_stat[] =
+	{
+		{	0,	"OK" },
+		{	1,	"ERR_PERM" },
+		{	2,	"ERR_NOENT" },
+		{	5,	"ERR_IO" },
+		{	6,	"ERR_NX_IO" },
+		{	13,	"ERR_ACCES" },
+		{	17,	"ERR_EXIST" },
+		{	19,	"ERR_NODEV" },
+		{	20,	"ERR_NOTDIR" },
+		{	21,	"ERR_ISDIR" },
+		{	27,	"ERR_FBIG" },
+		{	28,	"ERR_NOSPC" },
+		{	30,	"ERR_ROFS" },
+		{	63,	"ERR_NAMETOOLONG" },
+		{	66,	"ERR_NOTEMPTY" },
+		{	69,	"ERR_DQUOT" },
+		{	70,	"ERR_STALE" },
+		{	99,	"ERR_WFLUSH" },
+		{	0,	NULL }
+	};
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	stat = EXTRACT_UINT(pd, offset+0);
+	stat_name = val_to_str(stat, nfs2_stat, "%u");
+	
+	if (tree) {
+		proto_tree_add_text(tree, offset, 4,
+			"%s (stat): %s (%u)", name, stat_name, stat);
+	}
 
+	offset += 4;
+	*status = stat;
+	return offset;
+}
+
+
+/* RFC 1094, Page 15 */
+int
+dissect_ftype(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	guint32 ftype;
+	char* ftype_name = NULL;
+
+	const value_string nfs2_ftype[] =
+	{
+		{	0,	"Non-File" },
+		{	1,	"Regular File" },
+		{	2,	"Directory" },
+		{	3,	"Block Special Device" },
+		{	4,	"Character Special Device" },
+		{	5,	"Symbolic Link" },
+		{	0,	NULL }
+	};
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	ftype = EXTRACT_UINT(pd, offset+0);
+	ftype_name = val_to_str(ftype, nfs2_ftype, "%u");
+	
+	if (tree) {
+		proto_tree_add_text(tree, offset, 4,
+			"%s (ftype): %s (%u)", name, ftype_name, ftype);
+	}
+
+	offset += 4;
+	return offset;
+}
+
+
+/* RFC 1094, Page 15 */
 int
-dissect_fh2(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+dissect_fhandle(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
 {
 	proto_item* fitem;
 	proto_tree* ftree = NULL;
 
 	if (tree) {
 		fitem = proto_tree_add_text(tree, offset, FHSIZE,
-			"file handle");
+			"%s (fhandle)", name);
 		if (fitem)
-			ftree = proto_item_add_subtree(fitem, ETT_NFS2_FH);
+			ftree = proto_item_add_subtree(fitem, ETT_NFS_FHANDLE);
 	}
 
 	if (ftree) {
 		proto_tree_add_text(ftree,offset+0,FHSIZE,
-					"opaque data");
+					"file handle (opaque data)");
 	}
+
 	offset += FHSIZE;
 	return offset;
 }
 
+
+int
+dissect_timeval(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
+{
+	guint32	seconds;
+	guint32 mseconds;
+
+	proto_item* time_item;
+	proto_tree* time_tree = NULL;
+
+	if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
+	seconds = EXTRACT_UINT(pd, offset+0);
+	mseconds = EXTRACT_UINT(pd, offset+4);
+	
+	if (tree) {
+		time_item = proto_tree_add_text(tree, offset, 8,
+			"%s (timeval): %u.%06u", name, seconds, mseconds);
+		if (time_item)
+			time_tree = proto_item_add_subtree(time_item, ETT_NFS_TIMEVAL);
+	}
+
+	if (time_tree) {
+		proto_tree_add_text(time_tree,offset+0,4,
+					"seconds: %u", seconds);
+		proto_tree_add_text(time_tree,offset+4,4,
+					"micro seconds: %u", mseconds);
+	}
+	offset += 8;
+	return offset;
+}
+
+
+/* RFC 1094, Page 16 */
+const value_string nfs2_mode_names[] = {
+	{	0040000,	"Directory"	},
+	{	0020000,	"Character Special Device"	},
+	{	0060000,	"Block Special Device"	},
+	{	0100000,	"Regular File"	},
+	{	0120000,	"Symbolic Link"	},
+	{	0140000,	"Named Socket"	},
+};
+
+int
+dissect_mode(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	guint32 mode;
+	proto_item* mode_item = NULL;
+	proto_tree* mode_tree = NULL;
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	mode = EXTRACT_UINT(pd, offset+0);
+	
+	if (tree) {
+		mode_item = proto_tree_add_text(tree, offset, 4,
+			"%s (mode): 0%o", name, mode);
+		if (mode_item)
+			mode_tree = proto_item_add_subtree(mode_item, ETT_NFS_MODE);
+	}
+
+	if (mode_tree) {
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+			decode_enumerated_bitfield(mode,  0160000, 16,
+			nfs2_mode_names, "%s"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,   04000, 16, "Set user id on exec", "not SUID"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,   02000, 16, "Set group id on exec", "not SGID"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,   01000, 16, "Save swapped text even after use", "not save swapped text"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,    0400, 16, "Read permission for owner", "no Read permission for owner"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,    0200, 16, "Write permission for owner", "no Write permission for owner"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,    0100, 16, "Execute permission for owner", "no Execute permission for owner"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,     040, 16, "Read permission for group", "no Read permission for group"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,     020, 16, "Write permission for group", "no Write permission for group"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,     010, 16, "Execute permission for group", "no Execute permission for group"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,      04, 16, "Read permission for others", "no Read permission for others"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,      02, 16, "Write permission for others", "no Write permission for others"));
+		proto_tree_add_text(mode_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode,      01, 16, "Execute permission for others", "no Execute permission for others"));
+	}
+
+	offset += 4;
+	return offset;
+}
+
+
+/* RFC 1094, Page 15 */
+int
+dissect_fattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
+{
+	proto_item* fattr_item = NULL;
+	proto_tree* fattr_tree = NULL;
+	int old_offset = offset;
+
+	if (tree) {
+		fattr_item = proto_tree_add_text(tree, offset,
+			END_OF_FRAME, "%s (fattr)", name);
+		if (fattr_item)
+			fattr_tree = proto_item_add_subtree(fattr_item, ETT_NFS_FATTR);
+	}
+
+	offset = dissect_ftype        (pd,offset,fd,fattr_tree,"type");
+	offset = dissect_mode         (pd,offset,fd,fattr_tree,"mode");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"nlink");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"uid");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"gid");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"size");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocksize");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"rdev");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocks");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fsid");
+	offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fileid");
+	offset = dissect_timeval      (pd,offset,fd,fattr_tree,"atime");
+	offset = dissect_timeval      (pd,offset,fd,fattr_tree,"mtime");
+	offset = dissect_timeval      (pd,offset,fd,fattr_tree,"ctime");
+
+	/* now we know, that fattr is shorter */
+	if (fattr_item) {
+		proto_item_set_len(fattr_item, offset - old_offset);
+	}
+
+	return offset;
+}
+
+
+/* generic NFS2 call dissector */
+int
+dissect_nfs2_any_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+{
+	offset = dissect_fhandle(pd, offset, fd, tree, "object");
+
+	return offset;
+}
+
+
+/* generic NFS2 reply dissector */
+int
+dissect_nfs2_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
+{
+	guint32 status;
+
+	offset = dissect_stat(pd, offset, fd, tree, "status", &status);
+
+	return offset;
+}
+
+
+/* RFC 1094, Page 5 */
+int
+dissect_nfs2_getattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+{
+	offset = dissect_fhandle(pd, offset, fd, tree, "object");
+
+	return offset;
+}
+
+
+/* RFC 1094, Page 5 */
+int
+dissect_nfs2_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
+{
+	guint32 status;
+
+	/* attrstat: RFC 1094, Page 17 */
+	offset = dissect_stat(pd, offset, fd, tree, "status", &status);
+	switch (status) {
+		case 0:
+			offset = dissect_fattr(pd, offset, fd, tree, "attributes");
+		break;
+		default:
+			/* do nothing */
+		break;
+	}
+
+	return offset;
+}
+
+/* more to come here */
+
+
+/* proc number, "proc name", dissect_request, dissect_reply */
+/* NULL as function pointer means: take the generic one. */
+const vsff nfs2_proc[] = {
+	{ 0,	"NULL",		NULL,				NULL },
+	{ 1,	"GETATTR",	dissect_nfs2_getattr_call,	dissect_nfs2_getattr_reply },
+	{ 2,	"SETATTR",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 3,	"ROOT",		NULL,				NULL },
+	{ 4,	"LOOKUP",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 5,	"READLINK",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 6,	"READ",		dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 7,	"WRITECACHE",	NULL,				NULL },
+	{ 8,	"WRITE",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 9,	"CREATE",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 10,	"REMOVE",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 11,	"RENAME",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 12,	"LINK",		dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 13,	"SYMLINK",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 14,	"MKDIR",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 15,	"RMDIR",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 16,	"READDIR",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 17,	"STATFS",	dissect_nfs2_any_call,		dissect_nfs2_any_reply },
+	{ 0,	NULL,		NULL,				NULL }
+};
+/* end of NFS Version 2 */
+
+
+/***************************/
+/* NFS Version 3, RFC 1813 */
+/***************************/
+
+
+/* RFC 1813, Page 15 */
+int
+dissect_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"uint64");
+	return offset;
+}
+
+
+/* RFC 1813, Page 15 */
+int
+dissect_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uint32");
+	return offset;
+}
+
+
+/* RFC 1813, Page 15 */
+int
+dissect_fileid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"fileid3");
+	return offset;
+}
+
+
+/* RFC 1813, Page 16 */
 int
-dissect_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+dissect_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
 {
+	offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uid3"); 
+	return offset;
+}
+
+
+/* RFC 1813, Page 16 */
+int
+dissect_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"gid3"); 
+	return offset;
+}
+
+
+/* RFC 1813, Page 16 */
+int
+dissect_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"size3"); 
+	return offset;
+}
+
+
+/* RFC 1813, Page 16 */
+int
+dissect_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	guint32 mode3;
+	proto_item* mode3_item = NULL;
+	proto_tree* mode3_tree = NULL;
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	mode3 = EXTRACT_UINT(pd, offset+0);
+	
+	if (tree) {
+		mode3_item = proto_tree_add_text(tree, offset, 4,
+			"%s (mode3): 0%o", name, mode3);
+		if (mode3_item)
+			mode3_tree = proto_item_add_subtree(mode3_item, ETT_NFS_MODE3);
+	}
+
+	/* RFC 1813, Page 23 */
+	if (mode3_tree) {
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,   0x800, 12, "Set user id on exec", "not SUID"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,   0x400, 12, "Set group id on exec", "not SGID"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,   0x200, 12, "Save swapped text even after use", "not save swapped text"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,   0x100, 12, "Read permission for owner", "no Read permission for owner"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,    0x80, 12, "Write permission for owner", "no Write permission for owner"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,    0x40, 12, "Execute permission for owner", "no Execute permission for owner"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,    0x20, 12, "Read permission for group", "no Read permission for group"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,    0x10, 12, "Write permission for group", "no Write permission for group"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,     0x8, 12, "Execute permission for group", "no Execute permission for group"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,     0x4, 12, "Read permission for others", "no Read permission for others"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,     0x2, 12, "Write permission for others", "no Write permission for others"));
+		proto_tree_add_text(mode3_tree, offset, 4, "%s",
+		decode_boolean_bitfield(mode3,     0x1, 12, "Execute permission for others", "no Execute permission for others"));
+	}
+
+	offset += 4;
+	return offset;
+}
+
+
+/* RFC 1813, Page 16 */
+int
+dissect_count3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name, char* type)
+{
+	offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"count");
+	return offset;
+}
+
+
+/* RFC 1813, Page 16 */
+int
+dissect_nfsstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name, guint32* status)
+{
+	guint32 nfsstat3;
+	char* nfsstat3_name = NULL;
+
+	const value_string nfs3_nfsstat3[] =
+	{
+		{	0,	"OK" },
+		{	1,	"ERR_PERM" },
+		{	2,	"ERR_NOENT" },
+		{	5,	"ERR_IO" },
+		{	6,	"ERR_NX_IO" },
+		{	13,	"ERR_ACCES" },
+		{	17,	"ERR_EXIST" },
+		{	18,	"ERR_XDEV" },
+		{	19,	"ERR_NODEV" },
+		{	20,	"ERR_NOTDIR" },
+		{	21,	"ERR_ISDIR" },
+		{	22,	"ERR_INVAL" },
+		{	27,	"ERR_FBIG" },
+		{	28,	"ERR_NOSPC" },
+		{	30,	"ERR_ROFS" },
+		{	31,	"ERR_MLINK" },
+		{	63,	"ERR_NAMETOOLONG" },
+		{	66,	"ERR_NOTEMPTY" },
+		{	69,	"ERR_DQUOT" },
+		{	70,	"ERR_STALE" },
+		{	71,	"ERR_REMOTE" },
+		{	10001,	"ERR_BADHANDLE" },
+/* RFC 1813, Page 17 */
+		{	10002,	"ERR_NOT_SYNC" },
+		{	10003,	"ERR_BAD_COOKIE" },
+		{	10004,	"ERR_NOTSUPP" },
+		{	10005,	"ERR_TOOSMALL" },
+		{	10006,	"ERR_SERVERFAULT" },
+		{	10007,	"ERR_BADTYPE" },
+		{	10008,	"ERR_JUKEBOX" },
+		{	0,	NULL }
+	};
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	nfsstat3 = EXTRACT_UINT(pd, offset+0);
+	nfsstat3_name = val_to_str(nfsstat3, nfs3_nfsstat3, "%u");
+	
+	if (tree) {
+		proto_tree_add_text(tree, offset, 4,
+			"%s (nfsstat3): %s (%u)", name, nfsstat3_name, nfsstat3);
+	}
+
+	offset += 4;
+	*status = nfsstat3;
+	return offset;
+}
+
+
+/* RFC 1813, Page 17, 18, 19, 20: error explanations */
+
+
+/* RFC 1813, Page 20 */
+int
+dissect_ftype3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name)
+{
+	guint32 ftype3;
+	char* ftype3_name = NULL;
+
+	const value_string nfs3_ftype3[] =
+	{
+		{	1,	"Regular File" },
+		{	2,	"Directory" },
+		{	3,	"Block Special Device" },
+		{	4,	"Character Special Device" },
+		{	5,	"Symbolic Link" },
+		{	6,	"Socket" },
+		{	7,	"Named Pipe" },
+		{	0,	NULL }
+	};
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	ftype3 = EXTRACT_UINT(pd, offset+0);
+	ftype3_name = val_to_str(ftype3, nfs3_ftype3, "%u");
+	
+	if (tree) {
+		proto_tree_add_text(tree, offset, 4,
+			"%s (ftype3): %s (%u)", name, ftype3_name, ftype3);
+	}
+
+	offset += 4;
+	return offset;
+}
+
+
+/* RFC 1813, Page 20 */
+int
+dissect_specdata3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
+{
+	guint32	specdata1;
+	guint32	specdata2;
+
+	proto_item* specdata3_item;
+	proto_tree* specdata3_tree = NULL;
+
+	if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
+	specdata1 = EXTRACT_UINT(pd, offset+0);
+	specdata2 = EXTRACT_UINT(pd, offset+4);
+	
+	if (tree) {
+		specdata3_item = proto_tree_add_text(tree, offset, 8,
+			"%s (specdata3) : %u,%u", name, specdata1, specdata2);
+		if (specdata3_item)
+			specdata3_tree = proto_item_add_subtree(specdata3_item,
+					ETT_NFS_SPECDATA3);
+	}
+
+	if (specdata3_tree) {
+		proto_tree_add_text(specdata3_tree,offset+0,4,
+					"specdata1: %u", specdata1);
+		proto_tree_add_text(specdata3_tree,offset+4,4,
+					"specdata2: %u", specdata2);
+	}
+
+	offset += 8;
+	return offset;
+}
+
+
+/* RFC 1813, Page 21 */
+int
+dissect_nfs_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
+{
 	guint fh_len;
 	guint fh_len_full;
+	guint fh_fill;
 	proto_item* fitem;
 	proto_tree* ftree = NULL;
 
 	fh_len = EXTRACT_UINT(pd, offset+0);
 	fh_len_full = roundup(fh_len);
+	fh_fill = fh_len_full - fh_len;
 	
 	if (tree) {
 		fitem = proto_tree_add_text(tree, offset, 4+fh_len_full,
-			"file handle");
+			"%s (nfs_fh3)", name);
 		if (fitem)
-			ftree = proto_item_add_subtree(fitem, ETT_NFS3_FH);
+			ftree = proto_item_add_subtree(fitem, ETT_NFS_FH3);
 	}
 
 	if (ftree) {
 		proto_tree_add_text(ftree,offset+0,4,
-					"length: %d", fh_len);
+					"length: %u", fh_len);
 		proto_tree_add_text(ftree,offset+4,fh_len,
-					"opaque data");
+					"file handle (opaque data)");
+		if (fh_fill)
+			proto_tree_add_text(ftree,offset+4+fh_len,fh_fill,
+				"fill bytes");
 	}
 	offset += 4 + fh_len_full;
 	return offset;
 }
 
+
+/* RFC 1813, Page 21 */
+int
+dissect_nfs3time(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,char* name)
+{
+	guint32	seconds;
+	guint32 nseconds;
+
+	proto_item* time_item;
+	proto_tree* time_tree = NULL;
+
+	if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
+	seconds = EXTRACT_UINT(pd, offset+0);
+	nseconds = EXTRACT_UINT(pd, offset+4);
+	
+	if (tree) {
+		time_item = proto_tree_add_text(tree, offset, 8,
+			"%s (nfs3time): %u.%09u", name, seconds, nseconds);
+		if (time_item)
+			time_tree = proto_item_add_subtree(time_item, ETT_NFS_NFSTIME3);
+	}
+
+	if (time_tree) {
+		proto_tree_add_text(time_tree,offset+0,4,
+					"seconds: %u", seconds);
+		proto_tree_add_text(time_tree,offset+4,4,
+					"nano seconds: %u", nseconds);
+	}
+	offset += 8;
+	return offset;
+}
+
+
+/* RFC 1813, Page 22 */
+int
+dissect_fattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
+{
+	proto_item* fattr3_item = NULL;
+	proto_tree* fattr3_tree = NULL;
+	int old_offset = offset;
+
+	if (tree) {
+		fattr3_item = proto_tree_add_text(tree, offset,
+			END_OF_FRAME, "%s (fattr3)", name);
+		if (fattr3_item)
+			fattr3_tree = proto_item_add_subtree(fattr3_item, ETT_NFS_FATTR3);
+	}
+
+	offset = dissect_ftype3   (pd,offset,fd,fattr3_tree,"type");
+	offset = dissect_mode3    (pd,offset,fd,fattr3_tree,"mode");
+	offset = dissect_uint32   (pd,offset,fd,fattr3_tree,"nlink");
+	offset = dissect_uid3     (pd,offset,fd,fattr3_tree,"uid");
+	offset = dissect_gid3     (pd,offset,fd,fattr3_tree,"gid");
+	offset = dissect_size3    (pd,offset,fd,fattr3_tree,"size");
+	offset = dissect_size3    (pd,offset,fd,fattr3_tree,"used");
+	offset = dissect_specdata3(pd,offset,fd,fattr3_tree,"rdev");
+	offset = dissect_uint64   (pd,offset,fd,fattr3_tree,"fsid");
+	offset = dissect_fileid3  (pd,offset,fd,fattr3_tree,"fileid");
+	offset = dissect_nfs3time (pd,offset,fd,fattr3_tree,"atime");
+	offset = dissect_nfs3time (pd,offset,fd,fattr3_tree,"mtime");
+	offset = dissect_nfs3time (pd,offset,fd,fattr3_tree,"ctime");
+
+	/* now we know, that fattr3 is shorter */
+	if (fattr3_item) {
+		proto_item_set_len(fattr3_item, offset - old_offset);
+	}
+
+	return offset;
+}
+
+
+/* generic NFS3 call dissector */
+int
+dissect_nfs3_any_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
+{
+	offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
+	return offset;
+}
+
+
+/* generic NFS3 reply dissector */
+int
+dissect_nfs3_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
+{
+	guint32 status;
+
+	offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status);
+
+	return offset;
+
+}
 
-/* In fact, this routine serves only as a place to copy some ideas for
-more complicated dissectors. */
 
+/* RFC 1813, Page 32 */
 int
 dissect_nfs3_getattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
+{
+	offset = dissect_nfs_fh3(pd, offset, fd, tree, "object");
+	return offset;
+}
+
+
+/* RFC 1813, Page 32 */
+int
+dissect_nfs3_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
 {
-	offset = dissect_fh3(pd, offset, fd, tree);
+	guint32 status;
+
+	offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status);
+	switch (status) {
+		case 0:
+			offset = dissect_fattr3(pd, offset, fd, tree, "obj_attributes");
+		break;
+		default:
+			/* void */
+		break;
+	}
+		
 	return offset;
 }
+
+
+/* proc number, "proc name", dissect_request, dissect_reply */
+/* NULL as function pointer means: take the generic one. */
+const vsff nfs3_proc[] = {
+	{ 0,	"NULL",		NULL,				NULL },
+	{ 1,	"GETATTR",	dissect_nfs3_getattr_call,	dissect_nfs3_getattr_reply },
+	{ 2,	"SETATTR",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 3,	"LOOKUP",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 4,	"ACCESS",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 5,	"READLINK",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 6,	"READ",		dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 7,	"WRITE",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 8,	"CREATE",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 9,	"MKDIR",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 10,	"SYMLINK",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 11,	"MKNOD",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 12,	"REMOVE",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 13,	"RMDIR",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 14,	"RENAME",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 15,	"LINK",		dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 16,	"READDIR",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 17,	"READDIRPLUS",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 18,	"FSSTAT",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 19,	"FSINFO",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 20,	"PATHCONF",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 21,	"COMMIT",	dissect_nfs3_any_call,		dissect_nfs3_any_reply },
+	{ 0,	NULL,		NULL,				NULL }
+};
+/* end of NFS Version 3 */
+
 
 void
 proto_register_nfs(void)
Index: packet-rpc.c
===================================================================
RCS file: /cvsroot/ethereal/packet-rpc.c,v
retrieving revision 1.2
diff -u -r1.2 packet-rpc.c
--- packet-rpc.c	1999/10/29 02:25:53	1.2
+++ packet-rpc.c	1999/11/04 13:11:06
@@ -322,6 +322,96 @@
 }
 
 
+int
+dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name, char* type)
+{
+	guint32 value;
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	value = EXTRACT_UINT(pd, offset+0);
+
+	if (tree) {
+		proto_tree_add_text(tree, offset, 4,
+		"%s (%s): %u", name, type, value);
+	}
+
+	offset += 4;
+	return offset;
+}
+
+
+int
+dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+char* name, char* type)
+{
+	guint32 value_low;
+	guint32 value_high;
+
+	if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
+	value_high = EXTRACT_UINT(pd, offset+0);
+	value_low = EXTRACT_UINT(pd, offset+4);
+
+	if (tree) {
+		if (value_high)
+			proto_tree_add_text(tree, offset, 8,
+				"%s (%s): %x%08x", name, type, value_high, value_low);
+		else
+			proto_tree_add_text(tree, offset, 8,
+				"%s (%s): %u", name, type, value_low);
+	}
+
+	offset += 8;
+	return offset;
+}
+
+
+
+/* arbitrary limit */
+#define RPC_STRING_MAXBUF 1024
+
+int
+dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
+{
+	proto_item *string_item;
+	proto_tree *string_tree = NULL;
+
+	guint32 string_length;
+	guint32 string_fill;
+	guint32 string_length_full;
+	char string_buffer[RPC_STRING_MAXBUF];
+
+	if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
+	string_length = EXTRACT_UINT(pd,offset+0);
+	string_length_full = roundup(string_length);
+	string_fill = string_length_full - string_length;
+	if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
+	if (string_length>=sizeof(string_buffer)) return offset;
+	memcpy(string_buffer,pd+offset+4,string_length);
+	string_buffer[string_length] = '\0';
+	if (tree) {
+		string_item = proto_tree_add_text(tree,offset+0,
+			4+string_length_full,
+			"%s: %s", name, string_buffer);
+		if (string_item) {
+			string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
+		}
+	}
+	if (string_tree) {
+		proto_tree_add_text(string_tree,offset+0,4,
+			"length: %u", string_length);
+		proto_tree_add_text(string_tree,offset+4,string_length,
+			"text: %s", string_buffer);
+		if (string_fill)
+			proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
+				"fill bytes: opaque data");
+	}
+
+	offset += 4 + string_length_full;
+	return offset;
+}
+
+
 void
 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
 {
@@ -338,9 +428,9 @@
 
 	if (tree) {
 		proto_tree_add_text(tree,offset+0,4,
-		"Flavor: %s (%d)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor);
+		"Flavor: %s (%u)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor);
 		proto_tree_add_text(tree,offset+4,4,
-			"Length: %d", length);
+			"Length: %u", length);
 	}
 
 	offset += 8;
@@ -348,9 +438,6 @@
 	switch (flavor) {
 		case AUTH_UNIX: {
 			guint stamp;
-			guint machinename_count;
-			guint machinename_full;
-			char machinename_buffer[256];
 			guint uid;
 			guint gid;
 			guint gids_count;
@@ -366,32 +453,20 @@
 					"stamp: 0x%08x", stamp);
 			offset += 4;
 
-			/* all the following stuff should go into something
-			   like dissect_rpc_string() */
-			if (!BYTES_ARE_IN_FRAME(offset,4)) return;
-			machinename_count = EXTRACT_UINT(pd,offset+0);
-			machinename_full = roundup(machinename_count);
-			if (!BYTES_ARE_IN_FRAME(offset+4,machinename_full)) return;
-			if (machinename_count>=sizeof(machinename_buffer)) return;
-			memcpy(machinename_buffer,pd+offset+4,machinename_count);
-			machinename_buffer[machinename_count] = '\0';
-			if (tree)
-				proto_tree_add_text(tree,offset+0,4+machinename_full,
-				"machinename: %s", machinename_buffer);
-			offset += 4 + machinename_full;
+			offset = dissect_rpc_string(pd,offset,fd,tree,"machinename");
 
 			if (!BYTES_ARE_IN_FRAME(offset,4)) return;
 			uid = EXTRACT_UINT(pd,offset+0);
 			if (tree)
 				proto_tree_add_text(tree,offset+0,4,
-					"uid: %d", uid);
+					"uid: %u", uid);
 			offset += 4;
 
 			if (!BYTES_ARE_IN_FRAME(offset,4)) return;
 			gid = EXTRACT_UINT(pd,offset+0);
 			if (tree)
 				proto_tree_add_text(tree,offset+0,4,
-					"gid: %d", gid);
+					"gid: %u", gid);
 			offset += 4;
 
 			if (!BYTES_ARE_IN_FRAME(offset,4)) return;
@@ -407,7 +482,7 @@
 				gids_entry = EXTRACT_UINT(pd,offset+0);
 				if (gtree)
 				proto_tree_add_text(gtree, offset, 4, 
-					"%d", gids_entry);
+					"%u", gids_entry);
 				offset+=4;
 			}
 			/* how can I NOW change the gitem to print a list with
@@ -543,15 +618,15 @@
 	xid      = EXTRACT_UINT(pd,offset+0);
 	if (rpc_tree) {
 		proto_tree_add_text(rpc_tree,offset+0,4,
-			"XID: 0x%x (%d)", xid, xid);
+			"XID: 0x%x (%u)", xid, xid);
 	}
 
 	/* we should better compare this with the argument?! */
 	msg_type = EXTRACT_UINT(pd,offset+4);
-	msg_type_name = val_to_str(msg_type,rpc_msg_type,"%d");
+	msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
 	if (rpc_tree) {
 		proto_tree_add_text(rpc_tree,offset+4,4,
-			"msg_type: %s (%d)",
+			"msg_type: %s (%u)",
 			msg_type_name, msg_type);
 	}
 
@@ -567,14 +642,14 @@
 		rpcvers = EXTRACT_UINT(pd,offset+0);
 		if (rpc_tree) {
 			proto_tree_add_text(rpc_tree,offset+0,4,
-				"RPC Version: %d", rpcvers);
+				"RPC Version: %u", rpcvers);
 		}
 
 		prog = EXTRACT_UINT(pd,offset+4);
 		
 		if (rpc_tree) {
 			proto_tree_add_text(rpc_tree,offset+4,4,
-				"Program: %s (%d)", progname, prog);
+				"Program: %s (%u)", progname, prog);
 		}
 		
 		if (check_col(fd, COL_PROTOCOL)) {
@@ -606,12 +681,12 @@
 			/* happens only with strange program versions or
 			   non-existing dissectors */
 			dissect_function = NULL;
-			sprintf(procname_static, "proc-%d", proc);
+			sprintf(procname_static, "proc-%u", proc);
 			procname = procname_static;
 		}
 		if (rpc_tree) {
 			proto_tree_add_text(rpc_tree,offset+12,4,
-				"Procedure: %s (%d)", procname, proc);
+				"Procedure: %s (%u)", procname, proc);
 		}
 
 		if (check_col(fd, COL_INFO)) {
@@ -674,13 +749,13 @@
 				procname = rpc_call->proc_info->name;
 			}
 			else {
-				sprintf(procname_static, "proc-%d", proc);
+				sprintf(procname_static, "proc-%u", proc);
 				procname = procname_static;
 			}
 		}
 		else {
 			dissect_function = NULL;
-			sprintf(procname_static, "proc-%d", proc);
+			sprintf(procname_static, "proc-%u", proc);
 			procname = procname_static;
 		}
 		rpc_call->replies++;
@@ -714,12 +789,12 @@
 
 		if (rpc_tree) {
 			proto_tree_add_text(rpc_tree,0,0,
-				"Program: %s (%d)", 
+				"Program: %s (%u)", 
 				progname, prog);
 			proto_tree_add_text(rpc_tree,0,0,
 				"Program Version: %u", vers);
 			proto_tree_add_text(rpc_tree,0,0,
-				"Procedure: %s (%d)", procname, proc);
+				"Procedure: %s (%u)", procname, proc);
 		}
 
 		if (rpc_call->replies>1) {
@@ -732,7 +807,7 @@
 		reply_state = EXTRACT_UINT(pd,offset+0);
 		if (rpc_tree) {
 			proto_tree_add_text(rpc_tree,offset+0, 4,
-				"Reply State: %s (%d)",
+				"Reply State: %s (%u)",
 				val_to_str(reply_state,rpc_reply_state,"Unknown"),
 				reply_state);
 		}
@@ -744,7 +819,7 @@
 			accept_state = EXTRACT_UINT(pd,offset+0);
 			if (rpc_tree) {
 				proto_tree_add_text(rpc_tree,offset+0, 4,
-					"Accept State: %s (%d)", 
+					"Accept State: %s (%u)", 
 					val_to_str(accept_state,rpc_accept_state,"Unknown"),
 					accept_state);
 			}
@@ -761,11 +836,11 @@
 					if (rpc_tree) {
 						proto_tree_add_text(rpc_tree,
 							offset+0, 4,
-							"min. Program Version: %d",
+							"min. Program Version: %u",
 							vers_low);
 						proto_tree_add_text(rpc_tree,
 							offset+4, 4,
-							"max. Program Version: %d",
+							"max. Program Version: %u",
 							vers_high);
 					}
 					offset += 8;
@@ -779,7 +854,7 @@
 			reject_state = EXTRACT_UINT(pd,offset+0);
 			if (rpc_tree) {
 				proto_tree_add_text(rpc_tree, offset+0, 4,
-					"Reject State: %s (%d)",
+					"Reject State: %s (%u)",
 					val_to_str(reject_state,rpc_reject_state,"Unknown"),
 					reject_state);
 			}
@@ -792,11 +867,11 @@
 				if (rpc_tree) {
 					proto_tree_add_text(rpc_tree,
 						offset+0, 4,
-						"min. RPC Version: %d",
+						"min. RPC Version: %u",
 						vers_low);
 					proto_tree_add_text(rpc_tree,
 						offset+4, 4,
-						"max. RPC Version: %d",
+						"max. RPC Version: %u",
 						vers_high);
 				}
 				offset += 8;
@@ -806,7 +881,7 @@
 				if (rpc_tree) {
 					proto_tree_add_text(rpc_tree,
 						offset+0, 4,
-						"Authentication error: %s (%d)",
+						"Authentication error: %s (%u)",
 						val_to_str(auth_state,rpc_auth_state,"Unknown"),
 						auth_state);
 				}
Index: packet-rpc.h
===================================================================
RCS file: /cvsroot/ethereal/packet-rpc.h,v
retrieving revision 1.1
diff -u -r1.1 packet-rpc.h
--- packet-rpc.h	1999/10/29 01:11:22	1.1
+++ packet-rpc.h	1999/11/04 13:11:06
@@ -96,7 +96,10 @@
 extern void cleanup_dissect_rpc();
 
 extern unsigned int roundup(unsigned int a);
-
+extern int dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd,
+	proto_tree *tree, char* name, char* type);
+extern int dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd,
+	proto_tree *tree, char* name, char* type);
 
 
 #endif /* packet-rpc.h */
Index: packet.h
===================================================================
RCS file: /cvsroot/ethereal/packet.h,v
retrieving revision 1.124
diff -u -r1.124 packet.h
--- packet.h	1999/10/30 06:10:32	1.124
+++ packet.h	1999/11/04 13:11:11
@@ -424,12 +424,20 @@
 	ETT_SNA_RU,
 	ETT_YHOO,
 	ETT_RPC,
+	ETT_RPC_STRING,
 	ETT_RPC_CRED,
 	ETT_RPC_VERF,
 	ETT_RPC_GIDS,
 	ETT_NFS,
-	ETT_NFS2_FH,
-	ETT_NFS3_FH,
+	ETT_NFS_FHANDLE,
+	ETT_NFS_TIMEVAL,
+	ETT_NFS_MODE,
+	ETT_NFS_FATTR,
+	ETT_NFS_MODE3,
+	ETT_NFS_SPECDATA3,
+	ETT_NFS_FH3,
+	ETT_NFS_NFSTIME3,
+	ETT_NFS_FATTR3,
 	ETT_BOOT,
 	ETT_MNT,
 	ETT_NLM,

Attachment: nfs-v2
Description: Binary data

Attachment: nfs-v3
Description: Binary data