Merge remote-tracking branch 'goog/tcpdump'

* goog/tcpdump: (3066 commits)
  Remove old version. Getting ready for new tcpdump 4.5
  Support -Q for setting the capture direction.
  Clean up the TLV processing loop.
  With -A and -AA, don't send CRs to the standard output.
  Use the new libpcap <pcap/nflog.h> for NFLOG definitions and declarations.
  Do our own isascii(), isprint(), isgraph(), and toascii().
  Fix a compiler warning.
  Don't use the __attribute__((packed)) on most platforms.
  The interval in an AODV HELLO extension is not aligned on a 4-byte boundary.
  As with memcpy, so with memcmp.
  More UNALIGNED_MEM{CPY,CMP} on IP addresses.
  Another case where UNALIGNED_MEMCPY() is probably necessary.
  No need for casting back and forth.
  Only do the unaligned_mem{cpy,cmp} hack if necessary.
  No need to declare unaligned_mem{cpy,cmp} in netdissect.h *and* interface.h.
  More possibly-unaligned memcpy()s and assignments - use unaligned_memcpy().
  Check for compiling for IPv6; don't check whether we can create an IPv6 socket.
  Use unaligned_memcmp() to compare with IPv{4,6} addresses in a packet.
  Use EXTRACT_nBITS even when just testing against zero.
  Fix some more unaligned accesses.
  ...

Change-Id: I9e98707d30c989b9e32dcd5af798bd0746ab4434
diff --git a/print-nfs.c b/print-nfs.c
index 45e8869..526e543 100644
--- a/print-nfs.c
+++ b/print-nfs.c
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.106.2.4 2007/06/15 23:17:40 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.111 2007-12-22 03:08:04 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -49,8 +49,8 @@
 #include "rpc_msg.h"
 
 static void nfs_printfh(const u_int32_t *, const u_int);
-static void xid_map_enter(const struct sunrpc_msg *, const u_char *);
-static int32_t xid_map_find(const struct sunrpc_msg *, const u_char *,
+static int xid_map_enter(const struct sunrpc_msg *, const u_char *);
+static int xid_map_find(const struct sunrpc_msg *, const u_char *,
 			    u_int32_t *, u_int32_t *);
 static void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int);
 static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
@@ -100,7 +100,7 @@
  * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
  * was primarily BSD-derived.
  */
-static struct tok status2str[] = {
+static const struct tok status2str[] = {
 	{ 1,     "Operation not permitted" },	/* EPERM */
 	{ 2,     "No such file or directory" },	/* ENOENT */
 	{ 5,     "Input/output error" },	/* EIO */
@@ -138,14 +138,14 @@
 	{ 0,     NULL }
 };
 
-static struct tok nfsv3_writemodes[] = {
+static const struct tok nfsv3_writemodes[] = {
 	{ 0,		"unstable" },
 	{ 1,		"datasync" },
 	{ 2,		"filesync" },
 	{ 0,		NULL }
 };
 
-static struct tok type2str[] = {
+static const struct tok type2str[] = {
 	{ NFNON,	"NON" },
 	{ NFREG,	"REG" },
 	{ NFDIR,	"DIR" },
@@ -287,16 +287,12 @@
 	       register const u_char *bp2)
 {
 	register const struct sunrpc_msg *rp;
-	u_int32_t proc, vers, reply_stat;
 	char srcid[20], dstid[20];	/*fits 32bit*/
-	enum sunrpc_reject_stat rstat;
-	u_int32_t rlow;
-	u_int32_t rhigh;
-	enum sunrpc_auth_stat rwhy;
 
 	nfserr = 0;		/* assume no error */
 	rp = (const struct sunrpc_msg *)bp;
 
+	TCHECK(rp->rm_xid);
 	if (!nflag) {
 		strlcpy(srcid, "nfs", sizeof(srcid));
 		snprintf(dstid, sizeof(dstid), "%u",
@@ -307,6 +303,30 @@
 		    EXTRACT_32BITS(&rp->rm_xid));
 	}
 	print_nfsaddr(bp2, srcid, dstid);
+
+	nfsreply_print_noaddr(bp, length, bp2);
+	return;
+
+trunc:
+	if (!nfserr)
+		fputs(" [|nfs]", stdout);
+}
+
+void
+nfsreply_print_noaddr(register const u_char *bp, u_int length,
+	       register const u_char *bp2)
+{
+	register const struct sunrpc_msg *rp;
+	u_int32_t proc, vers, reply_stat;
+	enum sunrpc_reject_stat rstat;
+	u_int32_t rlow;
+	u_int32_t rhigh;
+	enum sunrpc_auth_stat rwhy;
+
+	nfserr = 0;		/* assume no error */
+	rp = (const struct sunrpc_msg *)bp;
+
+	TCHECK(rp->rm_reply.rp_stat);
 	reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
 	switch (reply_stat) {
 
@@ -318,10 +338,12 @@
 
 	case SUNRPC_MSG_DENIED:
 		(void)printf("reply ERR %u: ", length);
+		TCHECK(rp->rm_reply.rp_reject.rj_stat);
 		rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
 		switch (rstat) {
 
 		case SUNRPC_RPC_MISMATCH:
+			TCHECK(rp->rm_reply.rp_reject.rj_vers.high);
 			rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
 			rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
 			(void)printf("RPC Version mismatch (%u-%u)",
@@ -329,6 +351,7 @@
 			break;
 
 		case SUNRPC_AUTH_ERROR:
+			TCHECK(rp->rm_reply.rp_reject.rj_why);
 			rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
 			(void)printf("Auth ");
 			switch (rwhy) {
@@ -384,6 +407,11 @@
 		    reply_stat, length);
 		break;
 	}
+	return;
+
+trunc:
+	if (!nfserr)
+		fputs(" [|nfs]", stdout);
 }
 
 /*
@@ -494,15 +522,12 @@
     register const u_char *bp2)
 {
 	register const struct sunrpc_msg *rp;
-	register const u_int32_t *dp;
-	nfs_type type;
-	int v3;
-	u_int32_t proc;
-	struct nfsv3_sattr sa3;
 	char srcid[20], dstid[20];	/*fits 32bit*/
 
 	nfserr = 0;		/* assume no error */
 	rp = (const struct sunrpc_msg *)bp;
+
+	TCHECK(rp->rm_xid);
 	if (!nflag) {
 		snprintf(srcid, sizeof(srcid), "%u",
 		    EXTRACT_32BITS(&rp->rm_xid));
@@ -515,7 +540,31 @@
 	print_nfsaddr(bp2, srcid, dstid);
 	(void)printf("%d", length);
 
-	xid_map_enter(rp, bp2);	/* record proc number for later on */
+	nfsreq_print_noaddr(bp, length, bp2);
+	return;
+
+trunc:
+	if (!nfserr)
+		fputs(" [|nfs]", stdout);
+}
+
+void
+nfsreq_print_noaddr(register const u_char *bp, u_int length,
+    register const u_char *bp2)
+{
+	register const struct sunrpc_msg *rp;
+	register const u_int32_t *dp;
+	nfs_type type;
+	int v3;
+	u_int32_t proc;
+	u_int32_t access_flags;
+	struct nfsv3_sattr sa3;
+
+	nfserr = 0;		/* assume no error */
+	rp = (const struct sunrpc_msg *)bp;
+
+	if (!xid_map_enter(rp, bp2))	/* record proc number for later on */
+		goto trunc;
 
 	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
 	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
@@ -557,7 +606,37 @@
 		if ((dp = parsereq(rp, length)) != NULL &&
 		    (dp = parsefh(dp, v3)) != NULL) {
 			TCHECK(dp[0]);
-			printf(" %04x", EXTRACT_32BITS(&dp[0]));
+			access_flags = EXTRACT_32BITS(&dp[0]);
+			if (access_flags & ~NFSV3ACCESS_FULL) {
+				/* NFSV3ACCESS definitions aren't up to date */
+				printf(" %04x", access_flags);
+			} else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) {
+				printf(" NFS_ACCESS_FULL");
+			} else {
+				char separator = ' ';
+				if (access_flags & NFSV3ACCESS_READ) {
+					printf(" NFS_ACCESS_READ");
+					separator = '|';
+				}
+				if (access_flags & NFSV3ACCESS_LOOKUP) {
+					printf("%cNFS_ACCESS_LOOKUP", separator);
+					separator = '|';
+				}
+				if (access_flags & NFSV3ACCESS_MODIFY) {
+					printf("%cNFS_ACCESS_MODIFY", separator);
+					separator = '|';
+				}
+				if (access_flags & NFSV3ACCESS_EXTEND) {
+					printf("%cNFS_ACCESS_EXTEND", separator);
+					separator = '|';
+				}
+				if (access_flags & NFSV3ACCESS_DELETE) {
+					printf("%cNFS_ACCESS_DELETE", separator);
+					separator = '|';
+				}
+				if (access_flags & NFSV3ACCESS_EXECUTE)
+					printf("%cNFS_ACCESS_EXECUTE", separator);
+			}
 			return;
 		}
 		break;
@@ -809,7 +888,7 @@
 nfs_printfh(register const u_int32_t *dp, const u_int len)
 {
 	my_fsid fsid;
-	ino_t ino;
+	u_int32_t ino;
 	const char *sfsname = NULL;
 	char *spacep;
 
@@ -886,7 +965,7 @@
 int	xid_map_next = 0;
 int	xid_map_hint = 0;
 
-static void
+static int
 xid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
 {
 	struct ip *ip = NULL;
@@ -895,6 +974,8 @@
 #endif
 	struct xid_map_entry *xmep;
 
+	if (!TTEST(rp->rm_call.cb_vers))
+		return (0);
 	switch (IP_V((struct ip *)bp)) {
 	case 4:
 		ip = (struct ip *)bp;
@@ -905,7 +986,7 @@
 		break;
 #endif
 	default:
-		return;
+		return (1);
 	}
 
 	xmep = &xid_map[xid_map_next];
@@ -916,18 +997,19 @@
 	xmep->xid = rp->rm_xid;
 	if (ip) {
 		xmep->ipver = 4;
-		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
-		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
+		UNALIGNED_MEMCPY(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
+		UNALIGNED_MEMCPY(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
 	}
 #ifdef INET6
 	else if (ip6) {
 		xmep->ipver = 6;
-		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
-		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
+		UNALIGNED_MEMCPY(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
+		UNALIGNED_MEMCPY(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
 	}
 #endif
 	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
 	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
+	return (1);
 }
 
 /*
@@ -956,18 +1038,18 @@
 			goto nextitem;
 		switch (xmep->ipver) {
 		case 4:
-			if (memcmp(&ip->ip_src, &xmep->server,
+			if (UNALIGNED_MEMCMP(&ip->ip_src, &xmep->server,
 				   sizeof(ip->ip_src)) != 0 ||
-			    memcmp(&ip->ip_dst, &xmep->client,
+			    UNALIGNED_MEMCMP(&ip->ip_dst, &xmep->client,
 				   sizeof(ip->ip_dst)) != 0) {
 				cmp = 0;
 			}
 			break;
 #ifdef INET6
 		case 6:
-			if (memcmp(&ip6->ip6_src, &xmep->server,
+			if (UNALIGNED_MEMCMP(&ip6->ip6_src, &xmep->server,
 				   sizeof(ip6->ip6_src)) != 0 ||
-			    memcmp(&ip6->ip6_dst, &xmep->client,
+			    UNALIGNED_MEMCMP(&ip6->ip6_dst, &xmep->client,
 				   sizeof(ip6->ip6_dst)) != 0) {
 				cmp = 0;
 			}