2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 static const char rcsid[] _U_ =
26 "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.106.2.4 2007/06/15 23:17:40 guy Exp $ (LBL)";
33 #include <tcpdump-stdinc.h>
39 #include "interface.h"
40 #include "addrtoname.h"
53 static void nfs_printfh(const u_int32_t *, const u_int);
54 static void xid_map_enter(const struct sunrpc_msg *, const u_char *);
55 static int32_t xid_map_find(const struct sunrpc_msg *, const u_char *,
56 u_int32_t *, u_int32_t *);
57 static void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int);
58 static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
59 static void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
60 static void print_nfsaddr(const u_char *, const char *, const char *);
63 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
65 u_int32_t nfsv3_procid[NFS_NPROCS] = {
95 * NFS V2 and V3 status values.
97 * Some of these come from the RFCs for NFS V2 and V3, with the message
98 * strings taken from the FreeBSD C library "errlst.c".
100 * Others are errors that are not in the RFC but that I suspect some
101 * NFS servers could return; the values are FreeBSD errno values, as
102 * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
103 * was primarily BSD-derived.
105 static struct tok status2str[] = {
106 { 1, "Operation not permitted" }, /* EPERM */
107 { 2, "No such file or directory" }, /* ENOENT */
108 { 5, "Input/output error" }, /* EIO */
109 { 6, "Device not configured" }, /* ENXIO */
110 { 11, "Resource deadlock avoided" }, /* EDEADLK */
111 { 12, "Cannot allocate memory" }, /* ENOMEM */
112 { 13, "Permission denied" }, /* EACCES */
113 { 17, "File exists" }, /* EEXIST */
114 { 18, "Cross-device link" }, /* EXDEV */
115 { 19, "Operation not supported by device" }, /* ENODEV */
116 { 20, "Not a directory" }, /* ENOTDIR */
117 { 21, "Is a directory" }, /* EISDIR */
118 { 22, "Invalid argument" }, /* EINVAL */
119 { 26, "Text file busy" }, /* ETXTBSY */
120 { 27, "File too large" }, /* EFBIG */
121 { 28, "No space left on device" }, /* ENOSPC */
122 { 30, "Read-only file system" }, /* EROFS */
123 { 31, "Too many links" }, /* EMLINK */
124 { 45, "Operation not supported" }, /* EOPNOTSUPP */
125 { 62, "Too many levels of symbolic links" }, /* ELOOP */
126 { 63, "File name too long" }, /* ENAMETOOLONG */
127 { 66, "Directory not empty" }, /* ENOTEMPTY */
128 { 69, "Disc quota exceeded" }, /* EDQUOT */
129 { 70, "Stale NFS file handle" }, /* ESTALE */
130 { 71, "Too many levels of remote in path" }, /* EREMOTE */
131 { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
132 { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */
133 { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
134 { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
135 { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */
136 { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
137 { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
138 { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
139 { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
143 static struct tok nfsv3_writemodes[] = {
150 static struct tok type2str[] = {
162 print_nfsaddr(const u_char *bp, const char *s, const char *d)
167 char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
169 #ifndef INET_ADDRSTRLEN
170 #define INET_ADDRSTRLEN 16
172 char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
175 srcaddr[0] = dstaddr[0] = '\0';
176 switch (IP_V((struct ip *)bp)) {
178 ip = (struct ip *)bp;
179 strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr));
180 strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr));
184 ip6 = (struct ip6_hdr *)bp;
185 strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src),
187 strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst),
192 strlcpy(srcaddr, "?", sizeof(srcaddr));
193 strlcpy(dstaddr, "?", sizeof(dstaddr));
197 (void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);
200 static const u_int32_t *
201 parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
204 sa3->sa_modeset = EXTRACT_32BITS(dp);
206 if (sa3->sa_modeset) {
208 sa3->sa_mode = EXTRACT_32BITS(dp);
213 sa3->sa_uidset = EXTRACT_32BITS(dp);
215 if (sa3->sa_uidset) {
217 sa3->sa_uid = EXTRACT_32BITS(dp);
222 sa3->sa_gidset = EXTRACT_32BITS(dp);
224 if (sa3->sa_gidset) {
226 sa3->sa_gid = EXTRACT_32BITS(dp);
231 sa3->sa_sizeset = EXTRACT_32BITS(dp);
233 if (sa3->sa_sizeset) {
235 sa3->sa_size = EXTRACT_32BITS(dp);
240 sa3->sa_atimetype = EXTRACT_32BITS(dp);
242 if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
244 sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
246 sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
251 sa3->sa_mtimetype = EXTRACT_32BITS(dp);
253 if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
255 sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
257 sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
266 static int nfserr; /* true if we error rather than trunc */
269 print_sattr3(const struct nfsv3_sattr *sa3, int verbose)
272 printf(" mode %o", sa3->sa_mode);
274 printf(" uid %u", sa3->sa_uid);
276 printf(" gid %u", sa3->sa_gid);
278 if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
279 printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
280 sa3->sa_atime.nfsv3_nsec);
281 if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
282 printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
283 sa3->sa_mtime.nfsv3_nsec);
288 nfsreply_print(register const u_char *bp, u_int length,
289 register const u_char *bp2)
291 register const struct sunrpc_msg *rp;
292 u_int32_t proc, vers, reply_stat;
293 char srcid[20], dstid[20]; /*fits 32bit*/
294 enum sunrpc_reject_stat rstat;
297 enum sunrpc_auth_stat rwhy;
299 nfserr = 0; /* assume no error */
300 rp = (const struct sunrpc_msg *)bp;
303 strlcpy(srcid, "nfs", sizeof(srcid));
304 snprintf(dstid, sizeof(dstid), "%u",
305 EXTRACT_32BITS(&rp->rm_xid));
307 snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
308 snprintf(dstid, sizeof(dstid), "%u",
309 EXTRACT_32BITS(&rp->rm_xid));
311 print_nfsaddr(bp2, srcid, dstid);
312 reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
313 switch (reply_stat) {
315 case SUNRPC_MSG_ACCEPTED:
316 (void)printf("reply ok %u", length);
317 if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
318 interp_reply(rp, proc, vers, length);
321 case SUNRPC_MSG_DENIED:
322 (void)printf("reply ERR %u: ", length);
323 rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
326 case SUNRPC_RPC_MISMATCH:
327 rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
328 rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
329 (void)printf("RPC Version mismatch (%u-%u)",
333 case SUNRPC_AUTH_ERROR:
334 rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
335 (void)printf("Auth ");
342 case SUNRPC_AUTH_BADCRED:
343 (void)printf("Bogus Credentials (seal broken)");
346 case SUNRPC_AUTH_REJECTEDCRED:
347 (void)printf("Rejected Credentials (client should begin new session)");
350 case SUNRPC_AUTH_BADVERF:
351 (void)printf("Bogus Verifier (seal broken)");
354 case SUNRPC_AUTH_REJECTEDVERF:
355 (void)printf("Verifier expired or was replayed");
358 case SUNRPC_AUTH_TOOWEAK:
359 (void)printf("Credentials are too weak");
362 case SUNRPC_AUTH_INVALIDRESP:
363 (void)printf("Bogus response verifier");
366 case SUNRPC_AUTH_FAILED:
367 (void)printf("Unknown failure");
371 (void)printf("Invalid failure code %u",
378 (void)printf("Unknown reason for rejecting rpc message %u",
379 (unsigned int)rstat);
385 (void)printf("reply Unknown rpc response code=%u %u",
392 * Return a pointer to the first file handle in the packet.
393 * If the packet was truncated, return 0.
395 static const u_int32_t *
396 parsereq(register const struct sunrpc_msg *rp, register u_int length)
398 register const u_int32_t *dp;
402 * find the start of the req data (if we captured it)
404 dp = (u_int32_t *)&rp->rm_call.cb_cred;
406 len = EXTRACT_32BITS(&dp[1]);
408 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
410 len = EXTRACT_32BITS(&dp[1]);
412 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
422 * Print out an NFS file handle and return a pointer to following word.
423 * If packet was truncated, return 0.
425 static const u_int32_t *
426 parsefh(register const u_int32_t *dp, int v3)
432 len = EXTRACT_32BITS(dp) / 4;
437 if (TTEST2(*dp, len * sizeof(*dp))) {
438 nfs_printfh(dp, len);
446 * Print out a file name and return pointer to 32-bit word past it.
447 * If packet was truncated, return 0.
449 static const u_int32_t *
450 parsefn(register const u_int32_t *dp)
452 register u_int32_t len;
453 register const u_char *cp;
455 /* Bail if we don't have the string length */
458 /* Fetch string length; convert to host order */
462 TCHECK2(*dp, ((len + 3) & ~3));
465 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
466 dp += ((len + 3) & ~3) / sizeof(*dp);
468 if (fn_printn(cp, len, snapend)) {
480 * Print out file handle and file name.
481 * Return pointer to 32-bit word past file name.
482 * If packet was truncated (or there was some other error), return 0.
484 static const u_int32_t *
485 parsefhn(register const u_int32_t *dp, int v3)
487 dp = parsefh(dp, v3);
491 return (parsefn(dp));
495 nfsreq_print(register const u_char *bp, u_int length,
496 register const u_char *bp2)
498 register const struct sunrpc_msg *rp;
499 register const u_int32_t *dp;
503 struct nfsv3_sattr sa3;
504 char srcid[20], dstid[20]; /*fits 32bit*/
506 nfserr = 0; /* assume no error */
507 rp = (const struct sunrpc_msg *)bp;
509 snprintf(srcid, sizeof(srcid), "%u",
510 EXTRACT_32BITS(&rp->rm_xid));
511 strlcpy(dstid, "nfs", sizeof(dstid));
513 snprintf(srcid, sizeof(srcid), "%u",
514 EXTRACT_32BITS(&rp->rm_xid));
515 snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
517 print_nfsaddr(bp2, srcid, dstid);
518 (void)printf("%d", length);
520 xid_map_enter(rp, bp2); /* record proc number for later on */
522 v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
523 proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
525 if (!v3 && proc < NFS_NPROCS)
526 proc = nfsv3_procid[proc];
536 case NFSPROC_GETATTR:
538 if ((dp = parsereq(rp, length)) != NULL &&
539 parsefh(dp, v3) != NULL)
543 case NFSPROC_SETATTR:
545 if ((dp = parsereq(rp, length)) != NULL &&
546 parsefh(dp, v3) != NULL)
552 if ((dp = parsereq(rp, length)) != NULL &&
553 parsefhn(dp, v3) != NULL)
559 if ((dp = parsereq(rp, length)) != NULL &&
560 (dp = parsefh(dp, v3)) != NULL) {
562 printf(" %04x", EXTRACT_32BITS(&dp[0]));
567 case NFSPROC_READLINK:
569 if ((dp = parsereq(rp, length)) != NULL &&
570 parsefh(dp, v3) != NULL)
576 if ((dp = parsereq(rp, length)) != NULL &&
577 (dp = parsefh(dp, v3)) != NULL) {
580 printf(" %u bytes @ %" PRIu64,
581 EXTRACT_32BITS(&dp[2]),
582 EXTRACT_64BITS(&dp[0]));
585 printf(" %u bytes @ %u",
586 EXTRACT_32BITS(&dp[1]),
587 EXTRACT_32BITS(&dp[0]));
595 if ((dp = parsereq(rp, length)) != NULL &&
596 (dp = parsefh(dp, v3)) != NULL) {
599 printf(" %u (%u) bytes @ %" PRIu64,
600 EXTRACT_32BITS(&dp[4]),
601 EXTRACT_32BITS(&dp[2]),
602 EXTRACT_64BITS(&dp[0]));
607 tok2str(nfsv3_writemodes,
608 NULL, EXTRACT_32BITS(dp)));
612 printf(" %u (%u) bytes @ %u (%u)",
613 EXTRACT_32BITS(&dp[3]),
614 EXTRACT_32BITS(&dp[2]),
615 EXTRACT_32BITS(&dp[1]),
616 EXTRACT_32BITS(&dp[0]));
624 if ((dp = parsereq(rp, length)) != NULL &&
625 parsefhn(dp, v3) != NULL)
631 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
635 case NFSPROC_SYMLINK:
637 if ((dp = parsereq(rp, length)) != 0 &&
638 (dp = parsefhn(dp, v3)) != 0) {
639 fputs(" ->", stdout);
640 if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
642 if (parsefn(dp) == 0)
645 print_sattr3(&sa3, vflag);
652 if ((dp = parsereq(rp, length)) != 0 &&
653 (dp = parsefhn(dp, v3)) != 0) {
655 type = (nfs_type)EXTRACT_32BITS(dp);
657 if ((dp = parse_sattr3(dp, &sa3)) == 0)
659 printf(" %s", tok2str(type2str, "unk-ft %d", type));
660 if (vflag && (type == NFCHR || type == NFBLK)) {
663 EXTRACT_32BITS(&dp[0]),
664 EXTRACT_32BITS(&dp[1]));
668 print_sattr3(&sa3, vflag);
675 if ((dp = parsereq(rp, length)) != NULL &&
676 parsefhn(dp, v3) != NULL)
682 if ((dp = parsereq(rp, length)) != NULL &&
683 parsefhn(dp, v3) != NULL)
689 if ((dp = parsereq(rp, length)) != NULL &&
690 (dp = parsefhn(dp, v3)) != NULL) {
691 fputs(" ->", stdout);
692 if (parsefhn(dp, v3) != NULL)
699 if ((dp = parsereq(rp, length)) != NULL &&
700 (dp = parsefh(dp, v3)) != NULL) {
701 fputs(" ->", stdout);
702 if (parsefhn(dp, v3) != NULL)
707 case NFSPROC_READDIR:
709 if ((dp = parsereq(rp, length)) != NULL &&
710 (dp = parsefh(dp, v3)) != NULL) {
714 * We shouldn't really try to interpret the
715 * offset cookie here.
717 printf(" %u bytes @ %" PRId64,
718 EXTRACT_32BITS(&dp[4]),
719 EXTRACT_64BITS(&dp[0]));
721 printf(" verf %08x%08x", dp[2],
726 * Print the offset as signed, since -1 is
727 * common, but offsets > 2^31 aren't.
729 printf(" %u bytes @ %d",
730 EXTRACT_32BITS(&dp[1]),
731 EXTRACT_32BITS(&dp[0]));
737 case NFSPROC_READDIRPLUS:
738 printf(" readdirplus");
739 if ((dp = parsereq(rp, length)) != NULL &&
740 (dp = parsefh(dp, v3)) != NULL) {
743 * We don't try to interpret the offset
746 printf(" %u bytes @ %" PRId64,
747 EXTRACT_32BITS(&dp[4]),
748 EXTRACT_64BITS(&dp[0]));
751 printf(" max %u verf %08x%08x",
752 EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
760 if ((dp = parsereq(rp, length)) != NULL &&
761 parsefh(dp, v3) != NULL)
767 if ((dp = parsereq(rp, length)) != NULL &&
768 parsefh(dp, v3) != NULL)
772 case NFSPROC_PATHCONF:
774 if ((dp = parsereq(rp, length)) != NULL &&
775 parsefh(dp, v3) != NULL)
781 if ((dp = parsereq(rp, length)) != NULL &&
782 (dp = parsefh(dp, v3)) != NULL) {
784 printf(" %u bytes @ %" PRIu64,
785 EXTRACT_32BITS(&dp[2]),
786 EXTRACT_64BITS(&dp[0]));
792 printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
798 fputs(" [|nfs]", stdout);
802 * Print out an NFS file handle.
803 * We assume packet was not truncated before the end of the
804 * file handle pointed to by dp.
806 * Note: new version (using portable file-handle parser) doesn't produce
807 * generation number. It probably could be made to do that, with some
808 * additional hacking on the parser code.
811 nfs_printfh(register const u_int32_t *dp, const u_int len)
815 const char *sfsname = NULL;
820 char const *sep = "";
823 for (i=0; i<len; i++) {
824 (void)printf("%s%x", sep, dp[i]);
831 Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
834 /* file system ID is ASCII, not numeric, for this server OS */
835 static char temp[NFSX_V3FHMAX+1];
837 /* Make sure string is null-terminated */
838 strncpy(temp, sfsname, NFSX_V3FHMAX);
839 temp[sizeof(temp) - 1] = '\0';
840 /* Remove trailing spaces */
841 spacep = strchr(temp, ' ');
845 (void)printf(" fh %s/", temp);
847 (void)printf(" fh %d,%d/",
848 fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
851 if(fsid.Fsid_dev.Minor == 257)
852 /* Print the undecoded handle */
853 (void)printf("%s", fsid.Opaque_Handle);
855 (void)printf("%ld", (long) ino);
859 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
860 * us to match up replies with requests and thus to know how to parse
864 struct xid_map_entry {
865 u_int32_t xid; /* transaction ID (net order) */
866 int ipver; /* IP version (4 or 6) */
868 struct in6_addr client; /* client IP address (net order) */
869 struct in6_addr server; /* server IP address (net order) */
871 struct in_addr client; /* client IP address (net order) */
872 struct in_addr server; /* server IP address (net order) */
874 u_int32_t proc; /* call proc number (host order) */
875 u_int32_t vers; /* program version (host order) */
879 * Map entries are kept in an array that we manage as a ring;
880 * new entries are always added at the tail of the ring. Initially,
881 * all the entries are zero and hence don't match anything.
884 #define XIDMAPSIZE 64
886 struct xid_map_entry xid_map[XIDMAPSIZE];
888 int xid_map_next = 0;
889 int xid_map_hint = 0;
892 xid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
894 struct ip *ip = NULL;
896 struct ip6_hdr *ip6 = NULL;
898 struct xid_map_entry *xmep;
900 switch (IP_V((struct ip *)bp)) {
902 ip = (struct ip *)bp;
906 ip6 = (struct ip6_hdr *)bp;
913 xmep = &xid_map[xid_map_next];
915 if (++xid_map_next >= XIDMAPSIZE)
918 xmep->xid = rp->rm_xid;
921 memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
922 memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
927 memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
928 memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
931 xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
932 xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
936 * Returns 0 and puts NFSPROC_xxx in proc return and
937 * version in vers return, or returns -1 on failure
940 xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
944 struct xid_map_entry *xmep;
945 u_int32_t xid = rp->rm_xid;
946 struct ip *ip = (struct ip *)bp;
948 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
952 /* Start searching from where we last left off */
957 if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
959 switch (xmep->ipver) {
961 if (memcmp(&ip->ip_src, &xmep->server,
962 sizeof(ip->ip_src)) != 0 ||
963 memcmp(&ip->ip_dst, &xmep->client,
964 sizeof(ip->ip_dst)) != 0) {
970 if (memcmp(&ip6->ip6_src, &xmep->server,
971 sizeof(ip6->ip6_src)) != 0 ||
972 memcmp(&ip6->ip6_dst, &xmep->client,
973 sizeof(ip6->ip6_dst)) != 0) {
990 if (++i >= XIDMAPSIZE)
992 } while (i != xid_map_hint);
999 * Routines for parsing reply packets
1003 * Return a pointer to the beginning of the actual results.
1004 * If the packet was truncated, return 0.
1006 static const u_int32_t *
1007 parserep(register const struct sunrpc_msg *rp, register u_int length)
1009 register const u_int32_t *dp;
1011 enum sunrpc_accept_stat astat;
1015 * Here we find the address of the ar_verf credentials.
1016 * Originally, this calculation was
1017 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
1018 * On the wire, the rp_acpt field starts immediately after
1019 * the (32 bit) rp_stat field. However, rp_acpt (which is a
1020 * "struct accepted_reply") contains a "struct opaque_auth",
1021 * whose internal representation contains a pointer, so on a
1022 * 64-bit machine the compiler inserts 32 bits of padding
1023 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
1024 * the internal representation to parse the on-the-wire
1025 * representation. Instead, we skip past the rp_stat field,
1026 * which is an "enum" and so occupies one 32-bit word.
1028 dp = ((const u_int32_t *)&rp->rm_reply) + 1;
1030 len = EXTRACT_32BITS(&dp[1]);
1034 * skip past the ar_verf credentials.
1036 dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
1040 * now we can check the ar_stat field
1042 astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
1045 case SUNRPC_SUCCESS:
1048 case SUNRPC_PROG_UNAVAIL:
1049 printf(" PROG_UNAVAIL");
1050 nfserr = 1; /* suppress trunc string */
1053 case SUNRPC_PROG_MISMATCH:
1054 printf(" PROG_MISMATCH");
1055 nfserr = 1; /* suppress trunc string */
1058 case SUNRPC_PROC_UNAVAIL:
1059 printf(" PROC_UNAVAIL");
1060 nfserr = 1; /* suppress trunc string */
1063 case SUNRPC_GARBAGE_ARGS:
1064 printf(" GARBAGE_ARGS");
1065 nfserr = 1; /* suppress trunc string */
1068 case SUNRPC_SYSTEM_ERR:
1069 printf(" SYSTEM_ERR");
1070 nfserr = 1; /* suppress trunc string */
1074 printf(" ar_stat %d", astat);
1075 nfserr = 1; /* suppress trunc string */
1078 /* successful return */
1079 TCHECK2(*dp, sizeof(astat));
1080 return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
1085 static const u_int32_t *
1086 parsestatus(const u_int32_t *dp, int *er)
1092 errnum = EXTRACT_32BITS(&dp[0]);
1097 printf(" ERROR: %s",
1098 tok2str(status2str, "unk %d", errnum));
1106 static const u_int32_t *
1107 parsefattr(const u_int32_t *dp, int verbose, int v3)
1109 const struct nfs_fattr *fap;
1111 fap = (const struct nfs_fattr *)dp;
1112 TCHECK(fap->fa_gid);
1114 printf(" %s %o ids %d/%d",
1115 tok2str(type2str, "unk-ft %d ",
1116 EXTRACT_32BITS(&fap->fa_type)),
1117 EXTRACT_32BITS(&fap->fa_mode),
1118 EXTRACT_32BITS(&fap->fa_uid),
1119 EXTRACT_32BITS(&fap->fa_gid));
1121 TCHECK(fap->fa3_size);
1122 printf(" sz %" PRIu64,
1123 EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
1125 TCHECK(fap->fa2_size);
1126 printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
1129 /* print lots more stuff */
1132 TCHECK(fap->fa3_ctime);
1133 printf(" nlink %d rdev %d/%d",
1134 EXTRACT_32BITS(&fap->fa_nlink),
1135 EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1136 EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1137 printf(" fsid %" PRIx64,
1138 EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1139 printf(" fileid %" PRIx64,
1140 EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1141 printf(" a/m/ctime %u.%06u",
1142 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1143 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1145 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1146 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1148 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1149 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
1151 TCHECK(fap->fa2_ctime);
1152 printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1153 EXTRACT_32BITS(&fap->fa_nlink),
1154 EXTRACT_32BITS(&fap->fa2_rdev),
1155 EXTRACT_32BITS(&fap->fa2_fsid),
1156 EXTRACT_32BITS(&fap->fa2_fileid));
1158 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1159 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1161 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1162 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1164 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1165 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
1168 return ((const u_int32_t *)((unsigned char *)dp +
1169 (v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
1175 parseattrstat(const u_int32_t *dp, int verbose, int v3)
1179 dp = parsestatus(dp, &er);
1185 return (parsefattr(dp, verbose, v3) != NULL);
1189 parsediropres(const u_int32_t *dp)
1193 if (!(dp = parsestatus(dp, &er)))
1198 dp = parsefh(dp, 0);
1202 return (parsefattr(dp, vflag, 0) != NULL);
1206 parselinkres(const u_int32_t *dp, int v3)
1210 dp = parsestatus(dp, &er);
1215 if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
1218 return (parsefn(dp) != NULL);
1222 parsestatfs(const u_int32_t *dp, int v3)
1224 const struct nfs_statfs *sfsp;
1227 dp = parsestatus(dp, &er);
1239 if (!(dp = parse_post_op_attr(dp, vflag)))
1243 TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
1245 sfsp = (const struct nfs_statfs *)dp;
1248 printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1249 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1250 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1251 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
1253 printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1254 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1255 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1256 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1257 EXTRACT_32BITS(&sfsp->sf_invarsec));
1260 printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1261 EXTRACT_32BITS(&sfsp->sf_tsize),
1262 EXTRACT_32BITS(&sfsp->sf_bsize),
1263 EXTRACT_32BITS(&sfsp->sf_blocks),
1264 EXTRACT_32BITS(&sfsp->sf_bfree),
1265 EXTRACT_32BITS(&sfsp->sf_bavail));
1274 parserddires(const u_int32_t *dp)
1278 dp = parsestatus(dp, &er);
1287 printf(" offset %x size %d ",
1288 EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
1297 static const u_int32_t *
1298 parse_wcc_attr(const u_int32_t *dp)
1300 printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
1301 printf(" mtime %u.%06u ctime %u.%06u",
1302 EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1303 EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
1308 * Pre operation attributes. Print only if vflag > 1.
1310 static const u_int32_t *
1311 parse_pre_op_attr(const u_int32_t *dp, int verbose)
1314 if (!EXTRACT_32BITS(&dp[0]))
1319 return parse_wcc_attr(dp);
1321 /* If not verbose enough, just skip over wcc_attr */
1329 * Post operation attributes are printed if vflag >= 1
1331 static const u_int32_t *
1332 parse_post_op_attr(const u_int32_t *dp, int verbose)
1335 if (!EXTRACT_32BITS(&dp[0]))
1339 return parsefattr(dp, verbose, 1);
1341 return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
1346 static const u_int32_t *
1347 parse_wcc_data(const u_int32_t *dp, int verbose)
1351 if (!(dp = parse_pre_op_attr(dp, verbose)))
1356 return parse_post_op_attr(dp, verbose);
1359 static const u_int32_t *
1360 parsecreateopres(const u_int32_t *dp, int verbose)
1364 if (!(dp = parsestatus(dp, &er)))
1367 dp = parse_wcc_data(dp, verbose);
1370 if (!EXTRACT_32BITS(&dp[0]))
1373 if (!(dp = parsefh(dp, 1)))
1376 if (!(dp = parse_post_op_attr(dp, verbose)))
1379 printf(" dir attr:");
1380 dp = parse_wcc_data(dp, verbose);
1390 parsewccres(const u_int32_t *dp, int verbose)
1394 if (!(dp = parsestatus(dp, &er)))
1396 return parse_wcc_data(dp, verbose) != 0;
1399 static const u_int32_t *
1400 parsev3rddirres(const u_int32_t *dp, int verbose)
1404 if (!(dp = parsestatus(dp, &er)))
1408 if (!(dp = parse_post_op_attr(dp, verbose)))
1414 printf(" verf %08x%08x", dp[0], dp[1]);
1423 parsefsinfo(const u_int32_t *dp)
1425 struct nfsv3_fsinfo *sfp;
1428 if (!(dp = parsestatus(dp, &er)))
1432 if (!(dp = parse_post_op_attr(dp, vflag)))
1437 sfp = (struct nfsv3_fsinfo *)dp;
1439 printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1440 EXTRACT_32BITS(&sfp->fs_rtmax),
1441 EXTRACT_32BITS(&sfp->fs_rtpref),
1442 EXTRACT_32BITS(&sfp->fs_wtmax),
1443 EXTRACT_32BITS(&sfp->fs_wtpref),
1444 EXTRACT_32BITS(&sfp->fs_dtpref));
1446 printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1447 EXTRACT_32BITS(&sfp->fs_rtmult),
1448 EXTRACT_32BITS(&sfp->fs_wtmult),
1449 EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
1450 printf(" delta %u.%06u ",
1451 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1452 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
1460 parsepathconf(const u_int32_t *dp)
1463 struct nfsv3_pathconf *spp;
1465 if (!(dp = parsestatus(dp, &er)))
1469 if (!(dp = parse_post_op_attr(dp, vflag)))
1474 spp = (struct nfsv3_pathconf *)dp;
1477 printf(" linkmax %u namemax %u %s %s %s %s",
1478 EXTRACT_32BITS(&spp->pc_linkmax),
1479 EXTRACT_32BITS(&spp->pc_namemax),
1480 EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1481 EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1482 EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1483 EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1490 interp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
1492 register const u_int32_t *dp;
1496 v3 = (vers == NFS_VER3);
1498 if (!v3 && proc < NFS_NPROCS)
1499 proc = nfsv3_procid[proc];
1511 case NFSPROC_GETATTR:
1513 dp = parserep(rp, length);
1514 if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
1518 case NFSPROC_SETATTR:
1520 if (!(dp = parserep(rp, length)))
1523 if (parsewccres(dp, vflag))
1526 if (parseattrstat(dp, !qflag, 0) != 0)
1531 case NFSPROC_LOOKUP:
1533 if (!(dp = parserep(rp, length)))
1536 if (!(dp = parsestatus(dp, &er)))
1540 printf(" post dattr:");
1541 dp = parse_post_op_attr(dp, vflag);
1544 if (!(dp = parsefh(dp, v3)))
1546 if ((dp = parse_post_op_attr(dp, vflag)) &&
1548 printf(" post dattr:");
1549 dp = parse_post_op_attr(dp, vflag);
1555 if (parsediropres(dp) != 0)
1560 case NFSPROC_ACCESS:
1562 if (!(dp = parserep(rp, length)))
1564 if (!(dp = parsestatus(dp, &er)))
1568 if (!(dp = parse_post_op_attr(dp, vflag)))
1571 printf(" c %04x", EXTRACT_32BITS(&dp[0]));
1574 case NFSPROC_READLINK:
1575 printf(" readlink");
1576 dp = parserep(rp, length);
1577 if (dp != NULL && parselinkres(dp, v3) != 0)
1583 if (!(dp = parserep(rp, length)))
1586 if (!(dp = parsestatus(dp, &er)))
1588 if (!(dp = parse_post_op_attr(dp, vflag)))
1594 printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1595 if (EXTRACT_32BITS(&dp[1]))
1600 if (parseattrstat(dp, vflag, 0) != 0)
1607 if (!(dp = parserep(rp, length)))
1610 if (!(dp = parsestatus(dp, &er)))
1612 if (!(dp = parse_wcc_data(dp, vflag)))
1618 printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1622 tok2str(nfsv3_writemodes,
1623 NULL, EXTRACT_32BITS(&dp[1])));
1628 if (parseattrstat(dp, vflag, v3) != 0)
1633 case NFSPROC_CREATE:
1635 if (!(dp = parserep(rp, length)))
1638 if (parsecreateopres(dp, vflag) != 0)
1641 if (parsediropres(dp) != 0)
1648 if (!(dp = parserep(rp, length)))
1651 if (parsecreateopres(dp, vflag) != 0)
1654 if (parsediropres(dp) != 0)
1659 case NFSPROC_SYMLINK:
1661 if (!(dp = parserep(rp, length)))
1664 if (parsecreateopres(dp, vflag) != 0)
1667 if (parsestatus(dp, &er) != 0)
1674 if (!(dp = parserep(rp, length)))
1676 if (parsecreateopres(dp, vflag) != 0)
1680 case NFSPROC_REMOVE:
1682 if (!(dp = parserep(rp, length)))
1685 if (parsewccres(dp, vflag))
1688 if (parsestatus(dp, &er) != 0)
1695 if (!(dp = parserep(rp, length)))
1698 if (parsewccres(dp, vflag))
1701 if (parsestatus(dp, &er) != 0)
1706 case NFSPROC_RENAME:
1708 if (!(dp = parserep(rp, length)))
1711 if (!(dp = parsestatus(dp, &er)))
1715 if (!(dp = parse_wcc_data(dp, vflag)))
1718 if (!(dp = parse_wcc_data(dp, vflag)))
1723 if (parsestatus(dp, &er) != 0)
1730 if (!(dp = parserep(rp, length)))
1733 if (!(dp = parsestatus(dp, &er)))
1736 printf(" file POST:");
1737 if (!(dp = parse_post_op_attr(dp, vflag)))
1740 if (!(dp = parse_wcc_data(dp, vflag)))
1745 if (parsestatus(dp, &er) != 0)
1750 case NFSPROC_READDIR:
1752 if (!(dp = parserep(rp, length)))
1755 if (parsev3rddirres(dp, vflag))
1758 if (parserddires(dp) != 0)
1763 case NFSPROC_READDIRPLUS:
1764 printf(" readdirplus");
1765 if (!(dp = parserep(rp, length)))
1767 if (parsev3rddirres(dp, vflag))
1771 case NFSPROC_FSSTAT:
1773 dp = parserep(rp, length);
1774 if (dp != NULL && parsestatfs(dp, v3) != 0)
1778 case NFSPROC_FSINFO:
1780 dp = parserep(rp, length);
1781 if (dp != NULL && parsefsinfo(dp) != 0)
1785 case NFSPROC_PATHCONF:
1786 printf(" pathconf");
1787 dp = parserep(rp, length);
1788 if (dp != NULL && parsepathconf(dp) != 0)
1792 case NFSPROC_COMMIT:
1794 dp = parserep(rp, length);
1795 if (dp != NULL && parsewccres(dp, vflag) != 0)
1800 printf(" proc-%u", proc);
1805 fputs(" [|nfs]", stdout);