117680Spst/* 239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2075118Sfenner * 2175118Sfenner * $FreeBSD$ 2217680Spst */ 2317680Spst 2417680Spst#ifndef lint 25127675Sbmsstatic const char rcsid[] _U_ = 26214478Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.111 2007-12-22 03:08:04 guy Exp $ (LBL)"; 2717680Spst#endif 2817680Spst 2975118Sfenner#ifdef HAVE_CONFIG_H 3075118Sfenner#include "config.h" 3175118Sfenner#endif 3275118Sfenner 33127675Sbms#include <tcpdump-stdinc.h> 3417680Spst 3526183Sfenner#include <pcap.h> 3617680Spst#include <stdio.h> 3717680Spst#include <string.h> 3817680Spst 3917680Spst#include "interface.h" 4017680Spst#include "addrtoname.h" 41127675Sbms#include "extract.h" 4217680Spst 4318976Sdfr#include "nfs.h" 4417680Spst#include "nfsfh.h" 4517680Spst 4675118Sfenner#include "ip.h" 4775118Sfenner#ifdef INET6 4875118Sfenner#include "ip6.h" 4975118Sfenner#endif 50146778Ssam#include "rpc_auth.h" 51146778Ssam#include "rpc_msg.h" 5275118Sfenner 5375118Sfennerstatic void nfs_printfh(const u_int32_t *, const u_int); 54190207Srpaulostatic int xid_map_enter(const struct sunrpc_msg *, const u_char *); 55146778Ssamstatic int32_t xid_map_find(const struct sunrpc_msg *, const u_char *, 5675118Sfenner u_int32_t *, u_int32_t *); 57146778Ssamstatic void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int); 5818976Sdfrstatic const u_int32_t *parse_post_op_attr(const u_int32_t *, int); 5975118Sfennerstatic void print_sattr3(const struct nfsv3_sattr *sa3, int verbose); 6075118Sfennerstatic void print_nfsaddr(const u_char *, const char *, const char *); 6117680Spst 6218976Sdfr/* 6318976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 6418976Sdfr */ 6518976Sdfru_int32_t nfsv3_procid[NFS_NPROCS] = { 6618976Sdfr NFSPROC_NULL, 6718976Sdfr NFSPROC_GETATTR, 6818976Sdfr NFSPROC_SETATTR, 6918976Sdfr NFSPROC_NOOP, 7018976Sdfr NFSPROC_LOOKUP, 7118976Sdfr NFSPROC_READLINK, 7218976Sdfr NFSPROC_READ, 7318976Sdfr NFSPROC_NOOP, 7418976Sdfr NFSPROC_WRITE, 7518976Sdfr NFSPROC_CREATE, 7618976Sdfr NFSPROC_REMOVE, 7718976Sdfr NFSPROC_RENAME, 7818976Sdfr NFSPROC_LINK, 7918976Sdfr NFSPROC_SYMLINK, 8018976Sdfr NFSPROC_MKDIR, 8118976Sdfr NFSPROC_RMDIR, 8218976Sdfr NFSPROC_READDIR, 8318976Sdfr NFSPROC_FSSTAT, 8418976Sdfr NFSPROC_NOOP, 8518976Sdfr NFSPROC_NOOP, 8618976Sdfr NFSPROC_NOOP, 8718976Sdfr NFSPROC_NOOP, 8818976Sdfr NFSPROC_NOOP, 8918976Sdfr NFSPROC_NOOP, 9018976Sdfr NFSPROC_NOOP, 9118976Sdfr NFSPROC_NOOP 9218976Sdfr}; 9318976Sdfr 9475118Sfenner/* 9575118Sfenner * NFS V2 and V3 status values. 9675118Sfenner * 9775118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message 9875118Sfenner * strings taken from the FreeBSD C library "errlst.c". 9975118Sfenner * 10075118Sfenner * Others are errors that are not in the RFC but that I suspect some 10175118Sfenner * NFS servers could return; the values are FreeBSD errno values, as 10275118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS 10375118Sfenner * was primarily BSD-derived. 10475118Sfenner */ 10575118Sfennerstatic struct tok status2str[] = { 10675118Sfenner { 1, "Operation not permitted" }, /* EPERM */ 10775118Sfenner { 2, "No such file or directory" }, /* ENOENT */ 10875118Sfenner { 5, "Input/output error" }, /* EIO */ 10975118Sfenner { 6, "Device not configured" }, /* ENXIO */ 11075118Sfenner { 11, "Resource deadlock avoided" }, /* EDEADLK */ 11175118Sfenner { 12, "Cannot allocate memory" }, /* ENOMEM */ 11275118Sfenner { 13, "Permission denied" }, /* EACCES */ 11375118Sfenner { 17, "File exists" }, /* EEXIST */ 11475118Sfenner { 18, "Cross-device link" }, /* EXDEV */ 11575118Sfenner { 19, "Operation not supported by device" }, /* ENODEV */ 11675118Sfenner { 20, "Not a directory" }, /* ENOTDIR */ 11775118Sfenner { 21, "Is a directory" }, /* EISDIR */ 11875118Sfenner { 22, "Invalid argument" }, /* EINVAL */ 11975118Sfenner { 26, "Text file busy" }, /* ETXTBSY */ 12075118Sfenner { 27, "File too large" }, /* EFBIG */ 12175118Sfenner { 28, "No space left on device" }, /* ENOSPC */ 12275118Sfenner { 30, "Read-only file system" }, /* EROFS */ 12375118Sfenner { 31, "Too many links" }, /* EMLINK */ 12475118Sfenner { 45, "Operation not supported" }, /* EOPNOTSUPP */ 12575118Sfenner { 62, "Too many levels of symbolic links" }, /* ELOOP */ 12675118Sfenner { 63, "File name too long" }, /* ENAMETOOLONG */ 12775118Sfenner { 66, "Directory not empty" }, /* ENOTEMPTY */ 12875118Sfenner { 69, "Disc quota exceeded" }, /* EDQUOT */ 12975118Sfenner { 70, "Stale NFS file handle" }, /* ESTALE */ 13075118Sfenner { 71, "Too many levels of remote in path" }, /* EREMOTE */ 13175118Sfenner { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */ 13275118Sfenner { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */ 13375118Sfenner { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */ 13475118Sfenner { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */ 13575118Sfenner { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */ 13675118Sfenner { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */ 13775118Sfenner { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */ 13875118Sfenner { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */ 13975118Sfenner { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */ 14075118Sfenner { 0, NULL } 14118976Sdfr}; 14218976Sdfr 14375118Sfennerstatic struct tok nfsv3_writemodes[] = { 14475118Sfenner { 0, "unstable" }, 14575118Sfenner { 1, "datasync" }, 14675118Sfenner { 2, "filesync" }, 14775118Sfenner { 0, NULL } 14875118Sfenner}; 14975118Sfenner 15018976Sdfrstatic struct tok type2str[] = { 15118976Sdfr { NFNON, "NON" }, 15218976Sdfr { NFREG, "REG" }, 15318976Sdfr { NFDIR, "DIR" }, 15418976Sdfr { NFBLK, "BLK" }, 15518976Sdfr { NFCHR, "CHR" }, 15618976Sdfr { NFLNK, "LNK" }, 15718976Sdfr { NFFIFO, "FIFO" }, 15818976Sdfr { 0, NULL } 15918976Sdfr}; 16018976Sdfr 16175118Sfennerstatic void 16275118Sfennerprint_nfsaddr(const u_char *bp, const char *s, const char *d) 16375118Sfenner{ 16475118Sfenner struct ip *ip; 16575118Sfenner#ifdef INET6 16675118Sfenner struct ip6_hdr *ip6; 16775118Sfenner char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN]; 16875118Sfenner#else 16975118Sfenner#ifndef INET_ADDRSTRLEN 17075118Sfenner#define INET_ADDRSTRLEN 16 17175118Sfenner#endif 17275118Sfenner char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN]; 17375118Sfenner#endif 17475118Sfenner 17575118Sfenner srcaddr[0] = dstaddr[0] = '\0'; 17675118Sfenner switch (IP_V((struct ip *)bp)) { 17775118Sfenner case 4: 17875118Sfenner ip = (struct ip *)bp; 17975118Sfenner strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr)); 18075118Sfenner strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr)); 18175118Sfenner break; 18275118Sfenner#ifdef INET6 18375118Sfenner case 6: 18475118Sfenner ip6 = (struct ip6_hdr *)bp; 18575118Sfenner strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src), 18675118Sfenner sizeof(srcaddr)); 18775118Sfenner strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst), 18875118Sfenner sizeof(dstaddr)); 18975118Sfenner break; 19075118Sfenner#endif 19175118Sfenner default: 19275118Sfenner strlcpy(srcaddr, "?", sizeof(srcaddr)); 19375118Sfenner strlcpy(dstaddr, "?", sizeof(dstaddr)); 19475118Sfenner break; 19575118Sfenner } 19675118Sfenner 19775118Sfenner (void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d); 19875118Sfenner} 19975118Sfenner 20018976Sdfrstatic const u_int32_t * 20118976Sdfrparse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3) 20218976Sdfr{ 20375118Sfenner TCHECK(dp[0]); 204127675Sbms sa3->sa_modeset = EXTRACT_32BITS(dp); 205127675Sbms dp++; 206127675Sbms if (sa3->sa_modeset) { 20775118Sfenner TCHECK(dp[0]); 208127675Sbms sa3->sa_mode = EXTRACT_32BITS(dp); 209127675Sbms dp++; 21018976Sdfr } 21118976Sdfr 21275118Sfenner TCHECK(dp[0]); 213127675Sbms sa3->sa_uidset = EXTRACT_32BITS(dp); 214127675Sbms dp++; 215127675Sbms if (sa3->sa_uidset) { 21675118Sfenner TCHECK(dp[0]); 217127675Sbms sa3->sa_uid = EXTRACT_32BITS(dp); 218127675Sbms dp++; 21918976Sdfr } 22018976Sdfr 22175118Sfenner TCHECK(dp[0]); 222127675Sbms sa3->sa_gidset = EXTRACT_32BITS(dp); 223127675Sbms dp++; 224127675Sbms if (sa3->sa_gidset) { 22575118Sfenner TCHECK(dp[0]); 226127675Sbms sa3->sa_gid = EXTRACT_32BITS(dp); 227127675Sbms dp++; 22818976Sdfr } 22918976Sdfr 23075118Sfenner TCHECK(dp[0]); 231127675Sbms sa3->sa_sizeset = EXTRACT_32BITS(dp); 232127675Sbms dp++; 233127675Sbms if (sa3->sa_sizeset) { 23475118Sfenner TCHECK(dp[0]); 235127675Sbms sa3->sa_size = EXTRACT_32BITS(dp); 236127675Sbms dp++; 23718976Sdfr } 23818976Sdfr 23975118Sfenner TCHECK(dp[0]); 240127675Sbms sa3->sa_atimetype = EXTRACT_32BITS(dp); 241127675Sbms dp++; 242127675Sbms if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) { 24375118Sfenner TCHECK(dp[1]); 244127675Sbms sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp); 245127675Sbms dp++; 246127675Sbms sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp); 247127675Sbms dp++; 24818976Sdfr } 24918976Sdfr 25075118Sfenner TCHECK(dp[0]); 251127675Sbms sa3->sa_mtimetype = EXTRACT_32BITS(dp); 252127675Sbms dp++; 253127675Sbms if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) { 25475118Sfenner TCHECK(dp[1]); 255127675Sbms sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp); 256127675Sbms dp++; 257127675Sbms sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp); 258127675Sbms dp++; 25918976Sdfr } 26018976Sdfr 26118976Sdfr return dp; 26275118Sfennertrunc: 26375118Sfenner return NULL; 26418976Sdfr} 26518976Sdfr 26675118Sfennerstatic int nfserr; /* true if we error rather than trunc */ 26775118Sfenner 26875118Sfennerstatic void 26918976Sdfrprint_sattr3(const struct nfsv3_sattr *sa3, int verbose) 27018976Sdfr{ 27118976Sdfr if (sa3->sa_modeset) 27218976Sdfr printf(" mode %o", sa3->sa_mode); 27318976Sdfr if (sa3->sa_uidset) 27418976Sdfr printf(" uid %u", sa3->sa_uid); 27518976Sdfr if (sa3->sa_gidset) 27618976Sdfr printf(" gid %u", sa3->sa_gid); 27718976Sdfr if (verbose > 1) { 27818976Sdfr if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) 27918976Sdfr printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec, 28018976Sdfr sa3->sa_atime.nfsv3_nsec); 28118976Sdfr if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) 28218976Sdfr printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec, 28318976Sdfr sa3->sa_mtime.nfsv3_nsec); 28418976Sdfr } 28518976Sdfr} 28618976Sdfr 28718976Sdfrvoid 28817680Spstnfsreply_print(register const u_char *bp, u_int length, 28917680Spst register const u_char *bp2) 29017680Spst{ 291146778Ssam register const struct sunrpc_msg *rp; 292172686Smlaier u_int32_t proc, vers, reply_stat; 29375118Sfenner char srcid[20], dstid[20]; /*fits 32bit*/ 294172686Smlaier enum sunrpc_reject_stat rstat; 295172686Smlaier u_int32_t rlow; 296172686Smlaier u_int32_t rhigh; 297172686Smlaier enum sunrpc_auth_stat rwhy; 29817680Spst 29926183Sfenner nfserr = 0; /* assume no error */ 300146778Ssam rp = (const struct sunrpc_msg *)bp; 30117680Spst 302190207Srpaulo TCHECK(rp->rm_xid); 30375118Sfenner if (!nflag) { 30475118Sfenner strlcpy(srcid, "nfs", sizeof(srcid)); 30575118Sfenner snprintf(dstid, sizeof(dstid), "%u", 306127675Sbms EXTRACT_32BITS(&rp->rm_xid)); 30775118Sfenner } else { 30875118Sfenner snprintf(srcid, sizeof(srcid), "%u", NFS_PORT); 30975118Sfenner snprintf(dstid, sizeof(dstid), "%u", 310127675Sbms EXTRACT_32BITS(&rp->rm_xid)); 31175118Sfenner } 31275118Sfenner print_nfsaddr(bp2, srcid, dstid); 313190207Srpaulo TCHECK(rp->rm_reply.rp_stat); 314172686Smlaier reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat); 315172686Smlaier switch (reply_stat) { 31617680Spst 317172686Smlaier case SUNRPC_MSG_ACCEPTED: 318172686Smlaier (void)printf("reply ok %u", length); 319172686Smlaier if (xid_map_find(rp, bp2, &proc, &vers) >= 0) 320172686Smlaier interp_reply(rp, proc, vers, length); 321172686Smlaier break; 322172686Smlaier 323172686Smlaier case SUNRPC_MSG_DENIED: 324172686Smlaier (void)printf("reply ERR %u: ", length); 325190207Srpaulo TCHECK(rp->rm_reply.rp_reject.rj_stat); 326172686Smlaier rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat); 327172686Smlaier switch (rstat) { 328172686Smlaier 329172686Smlaier case SUNRPC_RPC_MISMATCH: 330190207Srpaulo TCHECK(rp->rm_reply.rp_reject.rj_vers.high); 331172686Smlaier rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low); 332172686Smlaier rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high); 333172686Smlaier (void)printf("RPC Version mismatch (%u-%u)", 334172686Smlaier rlow, rhigh); 335172686Smlaier break; 336172686Smlaier 337172686Smlaier case SUNRPC_AUTH_ERROR: 338190207Srpaulo TCHECK(rp->rm_reply.rp_reject.rj_why); 339172686Smlaier rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why); 340172686Smlaier (void)printf("Auth "); 341172686Smlaier switch (rwhy) { 342172686Smlaier 343172686Smlaier case SUNRPC_AUTH_OK: 344172686Smlaier (void)printf("OK"); 345172686Smlaier break; 346172686Smlaier 347172686Smlaier case SUNRPC_AUTH_BADCRED: 348172686Smlaier (void)printf("Bogus Credentials (seal broken)"); 349172686Smlaier break; 350172686Smlaier 351172686Smlaier case SUNRPC_AUTH_REJECTEDCRED: 352172686Smlaier (void)printf("Rejected Credentials (client should begin new session)"); 353172686Smlaier break; 354172686Smlaier 355172686Smlaier case SUNRPC_AUTH_BADVERF: 356172686Smlaier (void)printf("Bogus Verifier (seal broken)"); 357172686Smlaier break; 358172686Smlaier 359172686Smlaier case SUNRPC_AUTH_REJECTEDVERF: 360172686Smlaier (void)printf("Verifier expired or was replayed"); 361172686Smlaier break; 362172686Smlaier 363172686Smlaier case SUNRPC_AUTH_TOOWEAK: 364172686Smlaier (void)printf("Credentials are too weak"); 365172686Smlaier break; 366172686Smlaier 367172686Smlaier case SUNRPC_AUTH_INVALIDRESP: 368172686Smlaier (void)printf("Bogus response verifier"); 369172686Smlaier break; 370172686Smlaier 371172686Smlaier case SUNRPC_AUTH_FAILED: 372172686Smlaier (void)printf("Unknown failure"); 373172686Smlaier break; 374172686Smlaier 375172686Smlaier default: 376172686Smlaier (void)printf("Invalid failure code %u", 377172686Smlaier (unsigned int)rwhy); 378172686Smlaier break; 379172686Smlaier } 380172686Smlaier break; 381172686Smlaier 382172686Smlaier default: 383172686Smlaier (void)printf("Unknown reason for rejecting rpc message %u", 384172686Smlaier (unsigned int)rstat); 385172686Smlaier break; 386172686Smlaier } 387172686Smlaier break; 388172686Smlaier 389172686Smlaier default: 390172686Smlaier (void)printf("reply Unknown rpc response code=%u %u", 391172686Smlaier reply_stat, length); 392172686Smlaier break; 393172686Smlaier } 394190207Srpaulo return; 395190207Srpaulo 396190207Srpaulotrunc: 397190207Srpaulo if (!nfserr) 398190207Srpaulo fputs(" [|nfs]", stdout); 39917680Spst} 40017680Spst 40117680Spst/* 40217680Spst * Return a pointer to the first file handle in the packet. 40375118Sfenner * If the packet was truncated, return 0. 40417680Spst */ 40517680Spststatic const u_int32_t * 406146778Ssamparsereq(register const struct sunrpc_msg *rp, register u_int length) 40717680Spst{ 40826183Sfenner register const u_int32_t *dp; 40917680Spst register u_int len; 41017680Spst 41117680Spst /* 41217680Spst * find the start of the req data (if we captured it) 41317680Spst */ 41426183Sfenner dp = (u_int32_t *)&rp->rm_call.cb_cred; 41526183Sfenner TCHECK(dp[1]); 416127675Sbms len = EXTRACT_32BITS(&dp[1]); 41726183Sfenner if (len < length) { 41826183Sfenner dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 41926183Sfenner TCHECK(dp[1]); 420127675Sbms len = EXTRACT_32BITS(&dp[1]); 42126183Sfenner if (len < length) { 42226183Sfenner dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 42326183Sfenner TCHECK2(dp[0], 0); 42426183Sfenner return (dp); 42517680Spst } 42617680Spst } 42726183Sfennertrunc: 42826183Sfenner return (NULL); 42917680Spst} 43017680Spst 43117680Spst/* 43217680Spst * Print out an NFS file handle and return a pointer to following word. 43375118Sfenner * If packet was truncated, return 0. 43417680Spst */ 43517680Spststatic const u_int32_t * 43618976Sdfrparsefh(register const u_int32_t *dp, int v3) 43717680Spst{ 438127675Sbms u_int len; 43918976Sdfr 44018976Sdfr if (v3) { 44126183Sfenner TCHECK(dp[0]); 442127675Sbms len = EXTRACT_32BITS(dp) / 4; 44318976Sdfr dp++; 44418976Sdfr } else 44518976Sdfr len = NFSX_V2FH / 4; 44618976Sdfr 44726183Sfenner if (TTEST2(*dp, len * sizeof(*dp))) { 44818976Sdfr nfs_printfh(dp, len); 44918976Sdfr return (dp + len); 45017680Spst } 45126183Sfennertrunc: 45226183Sfenner return (NULL); 45317680Spst} 45417680Spst 45517680Spst/* 45617680Spst * Print out a file name and return pointer to 32-bit word past it. 45775118Sfenner * If packet was truncated, return 0. 45817680Spst */ 45917680Spststatic const u_int32_t * 46017680Spstparsefn(register const u_int32_t *dp) 46117680Spst{ 46217680Spst register u_int32_t len; 46317680Spst register const u_char *cp; 46417680Spst 46517680Spst /* Bail if we don't have the string length */ 46675118Sfenner TCHECK(*dp); 46717680Spst 46817680Spst /* Fetch string length; convert to host order */ 46917680Spst len = *dp++; 47017680Spst NTOHL(len); 47117680Spst 47275118Sfenner TCHECK2(*dp, ((len + 3) & ~3)); 47375118Sfenner 47417680Spst cp = (u_char *)dp; 47517680Spst /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ 47617680Spst dp += ((len + 3) & ~3) / sizeof(*dp); 47726183Sfenner putchar('"'); 478147904Ssam if (fn_printn(cp, len, snapend)) { 479147904Ssam putchar('"'); 480147904Ssam goto trunc; 481147904Ssam } 48226183Sfenner putchar('"'); 48317680Spst 48417680Spst return (dp); 48575118Sfennertrunc: 48675118Sfenner return NULL; 48717680Spst} 48817680Spst 48917680Spst/* 49017680Spst * Print out file handle and file name. 49117680Spst * Return pointer to 32-bit word past file name. 49275118Sfenner * If packet was truncated (or there was some other error), return 0. 49317680Spst */ 49417680Spststatic const u_int32_t * 49518976Sdfrparsefhn(register const u_int32_t *dp, int v3) 49617680Spst{ 49718976Sdfr dp = parsefh(dp, v3); 49826183Sfenner if (dp == NULL) 49926183Sfenner return (NULL); 50017680Spst putchar(' '); 50117680Spst return (parsefn(dp)); 50217680Spst} 50317680Spst 50417680Spstvoid 50517680Spstnfsreq_print(register const u_char *bp, u_int length, 50617680Spst register const u_char *bp2) 50717680Spst{ 508146778Ssam register const struct sunrpc_msg *rp; 50917680Spst register const u_int32_t *dp; 51075118Sfenner nfs_type type; 51175118Sfenner int v3; 51275118Sfenner u_int32_t proc; 513214478Srpaulo u_int32_t access_flags; 51418976Sdfr struct nfsv3_sattr sa3; 51575118Sfenner char srcid[20], dstid[20]; /*fits 32bit*/ 51617680Spst 51726183Sfenner nfserr = 0; /* assume no error */ 518146778Ssam rp = (const struct sunrpc_msg *)bp; 519190207Srpaulo 520190207Srpaulo TCHECK(rp->rm_xid); 52175118Sfenner if (!nflag) { 52275118Sfenner snprintf(srcid, sizeof(srcid), "%u", 523127675Sbms EXTRACT_32BITS(&rp->rm_xid)); 52475118Sfenner strlcpy(dstid, "nfs", sizeof(dstid)); 52575118Sfenner } else { 52675118Sfenner snprintf(srcid, sizeof(srcid), "%u", 527127675Sbms EXTRACT_32BITS(&rp->rm_xid)); 52875118Sfenner snprintf(dstid, sizeof(dstid), "%u", NFS_PORT); 52975118Sfenner } 53075118Sfenner print_nfsaddr(bp2, srcid, dstid); 53175118Sfenner (void)printf("%d", length); 53217680Spst 533190207Srpaulo if (!xid_map_enter(rp, bp2)) /* record proc number for later on */ 534190207Srpaulo goto trunc; 53517680Spst 536127675Sbms v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3); 537127675Sbms proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 53818976Sdfr 53918976Sdfr if (!v3 && proc < NFS_NPROCS) 54018976Sdfr proc = nfsv3_procid[proc]; 54118976Sdfr 54218976Sdfr switch (proc) { 54317680Spst case NFSPROC_NOOP: 54417680Spst printf(" nop"); 54517680Spst return; 54617680Spst case NFSPROC_NULL: 54717680Spst printf(" null"); 54817680Spst return; 54917680Spst 55017680Spst case NFSPROC_GETATTR: 55117680Spst printf(" getattr"); 55275118Sfenner if ((dp = parsereq(rp, length)) != NULL && 55375118Sfenner parsefh(dp, v3) != NULL) 55417680Spst return; 55517680Spst break; 55617680Spst 55717680Spst case NFSPROC_SETATTR: 55817680Spst printf(" setattr"); 55975118Sfenner if ((dp = parsereq(rp, length)) != NULL && 56075118Sfenner parsefh(dp, v3) != NULL) 56117680Spst return; 56217680Spst break; 56317680Spst 56417680Spst case NFSPROC_LOOKUP: 56517680Spst printf(" lookup"); 56675118Sfenner if ((dp = parsereq(rp, length)) != NULL && 56775118Sfenner parsefhn(dp, v3) != NULL) 56817680Spst return; 56917680Spst break; 57017680Spst 57118976Sdfr case NFSPROC_ACCESS: 57218976Sdfr printf(" access"); 57326183Sfenner if ((dp = parsereq(rp, length)) != NULL && 57426183Sfenner (dp = parsefh(dp, v3)) != NULL) { 57575118Sfenner TCHECK(dp[0]); 576214478Srpaulo access_flags = EXTRACT_32BITS(&dp[0]); 577214478Srpaulo if (access_flags & ~NFSV3ACCESS_FULL) { 578214478Srpaulo /* NFSV3ACCESS definitions aren't up to date */ 579214478Srpaulo printf(" %04x", access_flags); 580214478Srpaulo } else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) { 581214478Srpaulo printf(" NFS_ACCESS_FULL"); 582214478Srpaulo } else { 583214478Srpaulo char separator = ' '; 584214478Srpaulo if (access_flags & NFSV3ACCESS_READ) { 585214478Srpaulo printf(" NFS_ACCESS_READ"); 586214478Srpaulo separator = '|'; 587214478Srpaulo } 588214478Srpaulo if (access_flags & NFSV3ACCESS_LOOKUP) { 589214478Srpaulo printf("%cNFS_ACCESS_LOOKUP", separator); 590214478Srpaulo separator = '|'; 591214478Srpaulo } 592214478Srpaulo if (access_flags & NFSV3ACCESS_MODIFY) { 593214478Srpaulo printf("%cNFS_ACCESS_MODIFY", separator); 594214478Srpaulo separator = '|'; 595214478Srpaulo } 596214478Srpaulo if (access_flags & NFSV3ACCESS_EXTEND) { 597214478Srpaulo printf("%cNFS_ACCESS_EXTEND", separator); 598214478Srpaulo separator = '|'; 599214478Srpaulo } 600214478Srpaulo if (access_flags & NFSV3ACCESS_DELETE) { 601214478Srpaulo printf("%cNFS_ACCESS_DELETE", separator); 602214478Srpaulo separator = '|'; 603214478Srpaulo } 604214478Srpaulo if (access_flags & NFSV3ACCESS_EXECUTE) 605214478Srpaulo printf("%cNFS_ACCESS_EXECUTE", separator); 606214478Srpaulo } 60718976Sdfr return; 60818976Sdfr } 60918976Sdfr break; 61018976Sdfr 61117680Spst case NFSPROC_READLINK: 61217680Spst printf(" readlink"); 61375118Sfenner if ((dp = parsereq(rp, length)) != NULL && 61475118Sfenner parsefh(dp, v3) != NULL) 61517680Spst return; 61617680Spst break; 61717680Spst 61817680Spst case NFSPROC_READ: 61917680Spst printf(" read"); 62026183Sfenner if ((dp = parsereq(rp, length)) != NULL && 62126183Sfenner (dp = parsefh(dp, v3)) != NULL) { 62218976Sdfr if (v3) { 62375118Sfenner TCHECK(dp[2]); 624146778Ssam printf(" %u bytes @ %" PRIu64, 625146778Ssam EXTRACT_32BITS(&dp[2]), 626146778Ssam EXTRACT_64BITS(&dp[0])); 62718976Sdfr } else { 62875118Sfenner TCHECK(dp[1]); 62975118Sfenner printf(" %u bytes @ %u", 630127675Sbms EXTRACT_32BITS(&dp[1]), 631127675Sbms EXTRACT_32BITS(&dp[0])); 63218976Sdfr } 63317680Spst return; 63417680Spst } 63517680Spst break; 63617680Spst 63717680Spst case NFSPROC_WRITE: 63817680Spst printf(" write"); 63926183Sfenner if ((dp = parsereq(rp, length)) != NULL && 64026183Sfenner (dp = parsefh(dp, v3)) != NULL) { 64118976Sdfr if (v3) { 642146778Ssam TCHECK(dp[2]); 643146778Ssam printf(" %u (%u) bytes @ %" PRIu64, 644146778Ssam EXTRACT_32BITS(&dp[4]), 645146778Ssam EXTRACT_32BITS(&dp[2]), 646146778Ssam EXTRACT_64BITS(&dp[0])); 64718976Sdfr if (vflag) { 64818976Sdfr dp += 3; 64975118Sfenner TCHECK(dp[0]); 65018976Sdfr printf(" <%s>", 65175118Sfenner tok2str(nfsv3_writemodes, 652127675Sbms NULL, EXTRACT_32BITS(dp))); 65318976Sdfr } 65418976Sdfr } else { 65575118Sfenner TCHECK(dp[3]); 65675118Sfenner printf(" %u (%u) bytes @ %u (%u)", 657127675Sbms EXTRACT_32BITS(&dp[3]), 658127675Sbms EXTRACT_32BITS(&dp[2]), 659127675Sbms EXTRACT_32BITS(&dp[1]), 660127675Sbms EXTRACT_32BITS(&dp[0])); 66118976Sdfr } 66217680Spst return; 66317680Spst } 66417680Spst break; 66517680Spst 66617680Spst case NFSPROC_CREATE: 66717680Spst printf(" create"); 66875118Sfenner if ((dp = parsereq(rp, length)) != NULL && 66975118Sfenner parsefhn(dp, v3) != NULL) 67017680Spst return; 67117680Spst break; 67217680Spst 67318976Sdfr case NFSPROC_MKDIR: 67418976Sdfr printf(" mkdir"); 67575118Sfenner if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0) 67618976Sdfr return; 67718976Sdfr break; 67818976Sdfr 67918976Sdfr case NFSPROC_SYMLINK: 68018976Sdfr printf(" symlink"); 68175118Sfenner if ((dp = parsereq(rp, length)) != 0 && 68275118Sfenner (dp = parsefhn(dp, v3)) != 0) { 68375118Sfenner fputs(" ->", stdout); 68475118Sfenner if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0) 68518976Sdfr break; 68675118Sfenner if (parsefn(dp) == 0) 68718976Sdfr break; 68818976Sdfr if (v3 && vflag) 68918976Sdfr print_sattr3(&sa3, vflag); 69018976Sdfr return; 69118976Sdfr } 69218976Sdfr break; 69318976Sdfr 69418976Sdfr case NFSPROC_MKNOD: 69518976Sdfr printf(" mknod"); 69675118Sfenner if ((dp = parsereq(rp, length)) != 0 && 69775118Sfenner (dp = parsefhn(dp, v3)) != 0) { 69875118Sfenner TCHECK(*dp); 699127675Sbms type = (nfs_type)EXTRACT_32BITS(dp); 700127675Sbms dp++; 70175118Sfenner if ((dp = parse_sattr3(dp, &sa3)) == 0) 70218976Sdfr break; 70318976Sdfr printf(" %s", tok2str(type2str, "unk-ft %d", type)); 70418976Sdfr if (vflag && (type == NFCHR || type == NFBLK)) { 70575118Sfenner TCHECK(dp[1]); 70675118Sfenner printf(" %u/%u", 707127675Sbms EXTRACT_32BITS(&dp[0]), 708127675Sbms EXTRACT_32BITS(&dp[1])); 70918976Sdfr dp += 2; 71018976Sdfr } 71118976Sdfr if (vflag) 71218976Sdfr print_sattr3(&sa3, vflag); 71318976Sdfr return; 71418976Sdfr } 71518976Sdfr break; 71618976Sdfr 71717680Spst case NFSPROC_REMOVE: 71817680Spst printf(" remove"); 71975118Sfenner if ((dp = parsereq(rp, length)) != NULL && 72075118Sfenner parsefhn(dp, v3) != NULL) 72117680Spst return; 72217680Spst break; 72317680Spst 72418976Sdfr case NFSPROC_RMDIR: 72518976Sdfr printf(" rmdir"); 72675118Sfenner if ((dp = parsereq(rp, length)) != NULL && 72775118Sfenner parsefhn(dp, v3) != NULL) 72818976Sdfr return; 72918976Sdfr break; 73018976Sdfr 73117680Spst case NFSPROC_RENAME: 73217680Spst printf(" rename"); 73326183Sfenner if ((dp = parsereq(rp, length)) != NULL && 73426183Sfenner (dp = parsefhn(dp, v3)) != NULL) { 73517680Spst fputs(" ->", stdout); 73626183Sfenner if (parsefhn(dp, v3) != NULL) 73717680Spst return; 73817680Spst } 73917680Spst break; 74017680Spst 74117680Spst case NFSPROC_LINK: 74217680Spst printf(" link"); 74326183Sfenner if ((dp = parsereq(rp, length)) != NULL && 74426183Sfenner (dp = parsefh(dp, v3)) != NULL) { 74517680Spst fputs(" ->", stdout); 74626183Sfenner if (parsefhn(dp, v3) != NULL) 74717680Spst return; 74817680Spst } 74917680Spst break; 75017680Spst 75118976Sdfr case NFSPROC_READDIR: 75218976Sdfr printf(" readdir"); 75326183Sfenner if ((dp = parsereq(rp, length)) != NULL && 75426183Sfenner (dp = parsefh(dp, v3)) != NULL) { 75518976Sdfr if (v3) { 75675118Sfenner TCHECK(dp[4]); 75718976Sdfr /* 75818976Sdfr * We shouldn't really try to interpret the 75918976Sdfr * offset cookie here. 76018976Sdfr */ 761146778Ssam printf(" %u bytes @ %" PRId64, 762146778Ssam EXTRACT_32BITS(&dp[4]), 763146778Ssam EXTRACT_64BITS(&dp[0])); 76418976Sdfr if (vflag) 76526183Sfenner printf(" verf %08x%08x", dp[2], 76618976Sdfr dp[3]); 76718976Sdfr } else { 76875118Sfenner TCHECK(dp[1]); 76918976Sdfr /* 77018976Sdfr * Print the offset as signed, since -1 is 77118976Sdfr * common, but offsets > 2^31 aren't. 77218976Sdfr */ 77375118Sfenner printf(" %u bytes @ %d", 774127675Sbms EXTRACT_32BITS(&dp[1]), 775127675Sbms EXTRACT_32BITS(&dp[0])); 77618976Sdfr } 77718976Sdfr return; 77817680Spst } 77917680Spst break; 78017680Spst 78118976Sdfr case NFSPROC_READDIRPLUS: 78218976Sdfr printf(" readdirplus"); 78326183Sfenner if ((dp = parsereq(rp, length)) != NULL && 78426183Sfenner (dp = parsefh(dp, v3)) != NULL) { 78575118Sfenner TCHECK(dp[4]); 78618976Sdfr /* 78718976Sdfr * We don't try to interpret the offset 78818976Sdfr * cookie here. 78918976Sdfr */ 790146778Ssam printf(" %u bytes @ %" PRId64, 791146778Ssam EXTRACT_32BITS(&dp[4]), 792146778Ssam EXTRACT_64BITS(&dp[0])); 793146778Ssam if (vflag) { 794146778Ssam TCHECK(dp[5]); 79575118Sfenner printf(" max %u verf %08x%08x", 796127675Sbms EXTRACT_32BITS(&dp[5]), dp[2], dp[3]); 797146778Ssam } 79817680Spst return; 79918976Sdfr } 80017680Spst break; 80117680Spst 80218976Sdfr case NFSPROC_FSSTAT: 80318976Sdfr printf(" fsstat"); 80475118Sfenner if ((dp = parsereq(rp, length)) != NULL && 80575118Sfenner parsefh(dp, v3) != NULL) 80617680Spst return; 80717680Spst break; 80817680Spst 80918976Sdfr case NFSPROC_FSINFO: 81018976Sdfr printf(" fsinfo"); 811111729Sfenner if ((dp = parsereq(rp, length)) != NULL && 812111729Sfenner parsefh(dp, v3) != NULL) 813111729Sfenner return; 81418976Sdfr break; 81518976Sdfr 81618976Sdfr case NFSPROC_PATHCONF: 81718976Sdfr printf(" pathconf"); 818111729Sfenner if ((dp = parsereq(rp, length)) != NULL && 819111729Sfenner parsefh(dp, v3) != NULL) 820111729Sfenner return; 82118976Sdfr break; 82218976Sdfr 82318976Sdfr case NFSPROC_COMMIT: 82418976Sdfr printf(" commit"); 82526183Sfenner if ((dp = parsereq(rp, length)) != NULL && 82626183Sfenner (dp = parsefh(dp, v3)) != NULL) { 827146778Ssam TCHECK(dp[2]); 828146778Ssam printf(" %u bytes @ %" PRIu64, 829146778Ssam EXTRACT_32BITS(&dp[2]), 830146778Ssam EXTRACT_64BITS(&dp[0])); 83117680Spst return; 83217680Spst } 83317680Spst break; 83417680Spst 83517680Spst default: 836127675Sbms printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc)); 83717680Spst return; 83817680Spst } 83975118Sfenner 84017680Spsttrunc: 84126183Sfenner if (!nfserr) 84226183Sfenner fputs(" [|nfs]", stdout); 84317680Spst} 84417680Spst 84517680Spst/* 84617680Spst * Print out an NFS file handle. 84717680Spst * We assume packet was not truncated before the end of the 84817680Spst * file handle pointed to by dp. 84917680Spst * 85017680Spst * Note: new version (using portable file-handle parser) doesn't produce 85117680Spst * generation number. It probably could be made to do that, with some 85217680Spst * additional hacking on the parser code. 85317680Spst */ 85417680Spststatic void 85575118Sfennernfs_printfh(register const u_int32_t *dp, const u_int len) 85617680Spst{ 85717680Spst my_fsid fsid; 85817680Spst ino_t ino; 859127675Sbms const char *sfsname = NULL; 860127675Sbms char *spacep; 86117680Spst 862127675Sbms if (uflag) { 863127675Sbms u_int i; 864127675Sbms char const *sep = ""; 86517680Spst 866127675Sbms printf(" fh["); 867127675Sbms for (i=0; i<len; i++) { 868127675Sbms (void)printf("%s%x", sep, dp[i]); 869127675Sbms sep = ":"; 870127675Sbms } 871127675Sbms printf("]"); 872127675Sbms return; 873127675Sbms } 874127675Sbms 875127675Sbms Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0); 876127675Sbms 87717680Spst if (sfsname) { 87826183Sfenner /* file system ID is ASCII, not numeric, for this server OS */ 87926183Sfenner static char temp[NFSX_V3FHMAX+1]; 88017680Spst 88126183Sfenner /* Make sure string is null-terminated */ 88226183Sfenner strncpy(temp, sfsname, NFSX_V3FHMAX); 88375118Sfenner temp[sizeof(temp) - 1] = '\0'; 88426183Sfenner /* Remove trailing spaces */ 885127675Sbms spacep = strchr(temp, ' '); 886127675Sbms if (spacep) 887127675Sbms *spacep = '\0'; 88817680Spst 88975118Sfenner (void)printf(" fh %s/", temp); 89026183Sfenner } else { 89175118Sfenner (void)printf(" fh %d,%d/", 89275118Sfenner fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor); 89317680Spst } 89475118Sfenner 895127675Sbms if(fsid.Fsid_dev.Minor == 257) 896127675Sbms /* Print the undecoded handle */ 89775118Sfenner (void)printf("%s", fsid.Opaque_Handle); 89875118Sfenner else 89975118Sfenner (void)printf("%ld", (long) ino); 90017680Spst} 90117680Spst 90217680Spst/* 90317680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow 90417680Spst * us to match up replies with requests and thus to know how to parse 90517680Spst * the reply. 90617680Spst */ 90717680Spst 90817680Spststruct xid_map_entry { 90975118Sfenner u_int32_t xid; /* transaction ID (net order) */ 91075118Sfenner int ipver; /* IP version (4 or 6) */ 91175118Sfenner#ifdef INET6 91275118Sfenner struct in6_addr client; /* client IP address (net order) */ 91375118Sfenner struct in6_addr server; /* server IP address (net order) */ 91475118Sfenner#else 91517680Spst struct in_addr client; /* client IP address (net order) */ 91617680Spst struct in_addr server; /* server IP address (net order) */ 91775118Sfenner#endif 91875118Sfenner u_int32_t proc; /* call proc number (host order) */ 91975118Sfenner u_int32_t vers; /* program version (host order) */ 92017680Spst}; 92117680Spst 92217680Spst/* 92317680Spst * Map entries are kept in an array that we manage as a ring; 92417680Spst * new entries are always added at the tail of the ring. Initially, 92517680Spst * all the entries are zero and hence don't match anything. 92617680Spst */ 92717680Spst 92817680Spst#define XIDMAPSIZE 64 92917680Spst 93017680Spststruct xid_map_entry xid_map[XIDMAPSIZE]; 93117680Spst 93217680Spstint xid_map_next = 0; 93317680Spstint xid_map_hint = 0; 93417680Spst 935190207Srpaulostatic int 936146778Ssamxid_map_enter(const struct sunrpc_msg *rp, const u_char *bp) 93717680Spst{ 93875118Sfenner struct ip *ip = NULL; 93975118Sfenner#ifdef INET6 94075118Sfenner struct ip6_hdr *ip6 = NULL; 94175118Sfenner#endif 94217680Spst struct xid_map_entry *xmep; 94317680Spst 944190207Srpaulo if (!TTEST(rp->rm_call.cb_vers)) 945190207Srpaulo return (0); 94675118Sfenner switch (IP_V((struct ip *)bp)) { 94775118Sfenner case 4: 94875118Sfenner ip = (struct ip *)bp; 94975118Sfenner break; 95075118Sfenner#ifdef INET6 95175118Sfenner case 6: 95275118Sfenner ip6 = (struct ip6_hdr *)bp; 95375118Sfenner break; 95475118Sfenner#endif 95575118Sfenner default: 956190207Srpaulo return (1); 95775118Sfenner } 95875118Sfenner 95917680Spst xmep = &xid_map[xid_map_next]; 96017680Spst 96117680Spst if (++xid_map_next >= XIDMAPSIZE) 96217680Spst xid_map_next = 0; 96317680Spst 96417680Spst xmep->xid = rp->rm_xid; 96575118Sfenner if (ip) { 96675118Sfenner xmep->ipver = 4; 96775118Sfenner memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src)); 96875118Sfenner memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst)); 96975118Sfenner } 97075118Sfenner#ifdef INET6 97175118Sfenner else if (ip6) { 97275118Sfenner xmep->ipver = 6; 97375118Sfenner memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src)); 97475118Sfenner memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); 97575118Sfenner } 97675118Sfenner#endif 977127675Sbms xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 978127675Sbms xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers); 979190207Srpaulo return (1); 98017680Spst} 98117680Spst 98226183Sfenner/* 98326183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and 98426183Sfenner * version in vers return, or returns -1 on failure 98526183Sfenner */ 98618976Sdfrstatic int 987146778Ssamxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc, 98818976Sdfr u_int32_t *vers) 98917680Spst{ 99017680Spst int i; 99117680Spst struct xid_map_entry *xmep; 99217680Spst u_int32_t xid = rp->rm_xid; 99375118Sfenner struct ip *ip = (struct ip *)bp; 99475118Sfenner#ifdef INET6 99575118Sfenner struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 99675118Sfenner#endif 99775118Sfenner int cmp; 99817680Spst 99917680Spst /* Start searching from where we last left off */ 1000127675Sbms i = xid_map_hint; 100117680Spst do { 100217680Spst xmep = &xid_map[i]; 100375118Sfenner cmp = 1; 100475118Sfenner if (xmep->ipver != IP_V(ip) || xmep->xid != xid) 100575118Sfenner goto nextitem; 100675118Sfenner switch (xmep->ipver) { 100775118Sfenner case 4: 100875118Sfenner if (memcmp(&ip->ip_src, &xmep->server, 100975118Sfenner sizeof(ip->ip_src)) != 0 || 101075118Sfenner memcmp(&ip->ip_dst, &xmep->client, 101175118Sfenner sizeof(ip->ip_dst)) != 0) { 101275118Sfenner cmp = 0; 101375118Sfenner } 101475118Sfenner break; 101575118Sfenner#ifdef INET6 101675118Sfenner case 6: 101775118Sfenner if (memcmp(&ip6->ip6_src, &xmep->server, 101875118Sfenner sizeof(ip6->ip6_src)) != 0 || 101975118Sfenner memcmp(&ip6->ip6_dst, &xmep->client, 102075118Sfenner sizeof(ip6->ip6_dst)) != 0) { 102175118Sfenner cmp = 0; 102275118Sfenner } 102375118Sfenner break; 102475118Sfenner#endif 102575118Sfenner default: 102675118Sfenner cmp = 0; 102775118Sfenner break; 102875118Sfenner } 102975118Sfenner if (cmp) { 103017680Spst /* match */ 103117680Spst xid_map_hint = i; 103218976Sdfr *proc = xmep->proc; 103318976Sdfr *vers = xmep->vers; 103418976Sdfr return 0; 103517680Spst } 103675118Sfenner nextitem: 103717680Spst if (++i >= XIDMAPSIZE) 103817680Spst i = 0; 103917680Spst } while (i != xid_map_hint); 104017680Spst 104117680Spst /* search failed */ 104275118Sfenner return (-1); 104317680Spst} 104417680Spst 104517680Spst/* 104617680Spst * Routines for parsing reply packets 104717680Spst */ 104817680Spst 104917680Spst/* 105017680Spst * Return a pointer to the beginning of the actual results. 105175118Sfenner * If the packet was truncated, return 0. 105217680Spst */ 105317680Spststatic const u_int32_t * 1054146778Ssamparserep(register const struct sunrpc_msg *rp, register u_int length) 105517680Spst{ 105617680Spst register const u_int32_t *dp; 105775118Sfenner u_int len; 1058146778Ssam enum sunrpc_accept_stat astat; 105917680Spst 106017680Spst /* 106117680Spst * Portability note: 106217680Spst * Here we find the address of the ar_verf credentials. 106317680Spst * Originally, this calculation was 106417680Spst * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf 106517680Spst * On the wire, the rp_acpt field starts immediately after 106617680Spst * the (32 bit) rp_stat field. However, rp_acpt (which is a 106717680Spst * "struct accepted_reply") contains a "struct opaque_auth", 106817680Spst * whose internal representation contains a pointer, so on a 106917680Spst * 64-bit machine the compiler inserts 32 bits of padding 107017680Spst * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use 107117680Spst * the internal representation to parse the on-the-wire 107217680Spst * representation. Instead, we skip past the rp_stat field, 107317680Spst * which is an "enum" and so occupies one 32-bit word. 107417680Spst */ 107517680Spst dp = ((const u_int32_t *)&rp->rm_reply) + 1; 107675118Sfenner TCHECK(dp[1]); 1077127675Sbms len = EXTRACT_32BITS(&dp[1]); 107817680Spst if (len >= length) 107926183Sfenner return (NULL); 108017680Spst /* 108117680Spst * skip past the ar_verf credentials. 108217680Spst */ 108317680Spst dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t); 108426183Sfenner TCHECK2(dp[0], 0); 108517680Spst 108617680Spst /* 108717680Spst * now we can check the ar_stat field 108817680Spst */ 1089147904Ssam astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp); 109017680Spst switch (astat) { 109117680Spst 1092146778Ssam case SUNRPC_SUCCESS: 109317680Spst break; 109417680Spst 1095146778Ssam case SUNRPC_PROG_UNAVAIL: 109617680Spst printf(" PROG_UNAVAIL"); 109726183Sfenner nfserr = 1; /* suppress trunc string */ 109826183Sfenner return (NULL); 109917680Spst 1100146778Ssam case SUNRPC_PROG_MISMATCH: 110117680Spst printf(" PROG_MISMATCH"); 110226183Sfenner nfserr = 1; /* suppress trunc string */ 110326183Sfenner return (NULL); 110417680Spst 1105146778Ssam case SUNRPC_PROC_UNAVAIL: 110617680Spst printf(" PROC_UNAVAIL"); 110726183Sfenner nfserr = 1; /* suppress trunc string */ 110826183Sfenner return (NULL); 110917680Spst 1110146778Ssam case SUNRPC_GARBAGE_ARGS: 111117680Spst printf(" GARBAGE_ARGS"); 111226183Sfenner nfserr = 1; /* suppress trunc string */ 111326183Sfenner return (NULL); 111417680Spst 1115146778Ssam case SUNRPC_SYSTEM_ERR: 111617680Spst printf(" SYSTEM_ERR"); 111726183Sfenner nfserr = 1; /* suppress trunc string */ 111826183Sfenner return (NULL); 111917680Spst 112017680Spst default: 112117680Spst printf(" ar_stat %d", astat); 112226183Sfenner nfserr = 1; /* suppress trunc string */ 112326183Sfenner return (NULL); 112417680Spst } 112517680Spst /* successful return */ 112675118Sfenner TCHECK2(*dp, sizeof(astat)); 112775118Sfenner return ((u_int32_t *) (sizeof(astat) + ((char *)dp))); 112826183Sfennertrunc: 112975118Sfenner return (0); 113017680Spst} 113117680Spst 113217680Spststatic const u_int32_t * 113318976Sdfrparsestatus(const u_int32_t *dp, int *er) 113417680Spst{ 113575118Sfenner int errnum; 113617680Spst 113726183Sfenner TCHECK(dp[0]); 113875118Sfenner 1139127675Sbms errnum = EXTRACT_32BITS(&dp[0]); 114018976Sdfr if (er) 114126183Sfenner *er = errnum; 114226183Sfenner if (errnum != 0) { 114326183Sfenner if (!qflag) 114475118Sfenner printf(" ERROR: %s", 114575118Sfenner tok2str(status2str, "unk %d", errnum)); 114626183Sfenner nfserr = 1; 114717680Spst } 114817680Spst return (dp + 1); 114926183Sfennertrunc: 115075118Sfenner return NULL; 115117680Spst} 115217680Spst 115317680Spststatic const u_int32_t * 115418976Sdfrparsefattr(const u_int32_t *dp, int verbose, int v3) 115517680Spst{ 115618976Sdfr const struct nfs_fattr *fap; 115717680Spst 115818976Sdfr fap = (const struct nfs_fattr *)dp; 115926184Sfenner TCHECK(fap->fa_gid); 116017680Spst if (verbose) { 116175118Sfenner printf(" %s %o ids %d/%d", 116275118Sfenner tok2str(type2str, "unk-ft %d ", 1163127675Sbms EXTRACT_32BITS(&fap->fa_type)), 1164127675Sbms EXTRACT_32BITS(&fap->fa_mode), 1165127675Sbms EXTRACT_32BITS(&fap->fa_uid), 1166127675Sbms EXTRACT_32BITS(&fap->fa_gid)); 116718976Sdfr if (v3) { 116826184Sfenner TCHECK(fap->fa3_size); 1169146778Ssam printf(" sz %" PRIu64, 1170146778Ssam EXTRACT_64BITS((u_int32_t *)&fap->fa3_size)); 117126184Sfenner } else { 117226184Sfenner TCHECK(fap->fa2_size); 1173127675Sbms printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size)); 117418976Sdfr } 117517680Spst } 117617680Spst /* print lots more stuff */ 117717680Spst if (verbose > 1) { 117818976Sdfr if (v3) { 117926184Sfenner TCHECK(fap->fa3_ctime); 1180127675Sbms printf(" nlink %d rdev %d/%d", 1181127675Sbms EXTRACT_32BITS(&fap->fa_nlink), 1182127675Sbms EXTRACT_32BITS(&fap->fa3_rdev.specdata1), 1183127675Sbms EXTRACT_32BITS(&fap->fa3_rdev.specdata2)); 1184146778Ssam printf(" fsid %" PRIx64, 1185146778Ssam EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid)); 1186146778Ssam printf(" fileid %" PRIx64, 1187146778Ssam EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid)); 1188127675Sbms printf(" a/m/ctime %u.%06u", 1189127675Sbms EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec), 1190127675Sbms EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec)); 1191127675Sbms printf(" %u.%06u", 1192127675Sbms EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec), 1193127675Sbms EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec)); 1194127675Sbms printf(" %u.%06u", 1195127675Sbms EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec), 1196127675Sbms EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec)); 119718976Sdfr } else { 119826184Sfenner TCHECK(fap->fa2_ctime); 1199127675Sbms printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime", 1200127675Sbms EXTRACT_32BITS(&fap->fa_nlink), 1201127675Sbms EXTRACT_32BITS(&fap->fa2_rdev), 1202127675Sbms EXTRACT_32BITS(&fap->fa2_fsid), 1203127675Sbms EXTRACT_32BITS(&fap->fa2_fileid)); 1204127675Sbms printf(" %u.%06u", 1205127675Sbms EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec), 1206127675Sbms EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec)); 1207127675Sbms printf(" %u.%06u", 1208127675Sbms EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec), 1209127675Sbms EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec)); 1210127675Sbms printf(" %u.%06u", 1211127675Sbms EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec), 1212127675Sbms EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec)); 121318976Sdfr } 121417680Spst } 121518976Sdfr return ((const u_int32_t *)((unsigned char *)dp + 121618976Sdfr (v3 ? NFSX_V3FATTR : NFSX_V2FATTR))); 121726184Sfennertrunc: 121826184Sfenner return (NULL); 121917680Spst} 122017680Spst 122117680Spststatic int 122218976Sdfrparseattrstat(const u_int32_t *dp, int verbose, int v3) 122317680Spst{ 122418976Sdfr int er; 122518976Sdfr 122618976Sdfr dp = parsestatus(dp, &er); 1227111729Sfenner if (dp == NULL) 122817680Spst return (0); 1229111729Sfenner if (er) 1230111729Sfenner return (1); 123117680Spst 123226183Sfenner return (parsefattr(dp, verbose, v3) != NULL); 123317680Spst} 123417680Spst 123517680Spststatic int 123617680Spstparsediropres(const u_int32_t *dp) 123717680Spst{ 123818976Sdfr int er; 123918976Sdfr 1240111729Sfenner if (!(dp = parsestatus(dp, &er))) 124117680Spst return (0); 1242111729Sfenner if (er) 1243111729Sfenner return (1); 124417680Spst 124518976Sdfr dp = parsefh(dp, 0); 124617680Spst if (dp == NULL) 124717680Spst return (0); 124817680Spst 124918976Sdfr return (parsefattr(dp, vflag, 0) != NULL); 125017680Spst} 125117680Spst 125217680Spststatic int 125318976Sdfrparselinkres(const u_int32_t *dp, int v3) 125417680Spst{ 125518976Sdfr int er; 125618976Sdfr 125718976Sdfr dp = parsestatus(dp, &er); 1258111729Sfenner if (dp == NULL) 125917680Spst return(0); 1260111729Sfenner if (er) 1261111729Sfenner return(1); 126275118Sfenner if (v3 && !(dp = parse_post_op_attr(dp, vflag))) 126318976Sdfr return (0); 126417680Spst putchar(' '); 126517680Spst return (parsefn(dp) != NULL); 126617680Spst} 126717680Spst 126817680Spststatic int 126918976Sdfrparsestatfs(const u_int32_t *dp, int v3) 127017680Spst{ 127118976Sdfr const struct nfs_statfs *sfsp; 127218976Sdfr int er; 127317680Spst 127418976Sdfr dp = parsestatus(dp, &er); 1275111729Sfenner if (dp == NULL) 127675118Sfenner return (0); 1277111729Sfenner if (!v3 && er) 1278111729Sfenner return (1); 127917680Spst 128018976Sdfr if (qflag) 128118976Sdfr return(1); 128218976Sdfr 128318976Sdfr if (v3) { 128418976Sdfr if (vflag) 128518976Sdfr printf(" POST:"); 128675118Sfenner if (!(dp = parse_post_op_attr(dp, vflag))) 128718976Sdfr return (0); 128817680Spst } 128917680Spst 1290111729Sfenner TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS)); 129118976Sdfr 129218976Sdfr sfsp = (const struct nfs_statfs *)dp; 129318976Sdfr 129418976Sdfr if (v3) { 1295146778Ssam printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64, 1296146778Ssam EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes), 1297146778Ssam EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes), 1298146778Ssam EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes)); 129918976Sdfr if (vflag) { 1300146778Ssam printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u", 1301146778Ssam EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles), 1302146778Ssam EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles), 1303146778Ssam EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles), 1304127675Sbms EXTRACT_32BITS(&sfsp->sf_invarsec)); 130518976Sdfr } 130618976Sdfr } else { 130775118Sfenner printf(" tsize %d bsize %d blocks %d bfree %d bavail %d", 1308127675Sbms EXTRACT_32BITS(&sfsp->sf_tsize), 1309127675Sbms EXTRACT_32BITS(&sfsp->sf_bsize), 1310127675Sbms EXTRACT_32BITS(&sfsp->sf_blocks), 1311127675Sbms EXTRACT_32BITS(&sfsp->sf_bfree), 1312127675Sbms EXTRACT_32BITS(&sfsp->sf_bavail)); 131318976Sdfr } 131418976Sdfr 131517680Spst return (1); 131626184Sfennertrunc: 131726184Sfenner return (0); 131817680Spst} 131917680Spst 132017680Spststatic int 132117680Spstparserddires(const u_int32_t *dp) 132217680Spst{ 132318976Sdfr int er; 132418976Sdfr 132518976Sdfr dp = parsestatus(dp, &er); 1326111729Sfenner if (dp == NULL) 132717680Spst return (0); 1328111729Sfenner if (er) 1329111729Sfenner return (1); 133018976Sdfr if (qflag) 133118976Sdfr return (1); 133218976Sdfr 133326184Sfenner TCHECK(dp[2]); 133475118Sfenner printf(" offset %x size %d ", 1335127675Sbms EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1])); 133618976Sdfr if (dp[2] != 0) 133775118Sfenner printf(" eof"); 133818976Sdfr 133918976Sdfr return (1); 134026184Sfennertrunc: 134126184Sfenner return (0); 134218976Sdfr} 134318976Sdfr 134418976Sdfrstatic const u_int32_t * 134518976Sdfrparse_wcc_attr(const u_int32_t *dp) 134618976Sdfr{ 1347146778Ssam printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0])); 134875118Sfenner printf(" mtime %u.%06u ctime %u.%06u", 1349127675Sbms EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]), 1350127675Sbms EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5])); 135118976Sdfr return (dp + 6); 135218976Sdfr} 135318976Sdfr 135418976Sdfr/* 135518976Sdfr * Pre operation attributes. Print only if vflag > 1. 135618976Sdfr */ 135718976Sdfrstatic const u_int32_t * 135818976Sdfrparse_pre_op_attr(const u_int32_t *dp, int verbose) 135918976Sdfr{ 136026184Sfenner TCHECK(dp[0]); 1361127675Sbms if (!EXTRACT_32BITS(&dp[0])) 136218976Sdfr return (dp + 1); 136318976Sdfr dp++; 1364111729Sfenner TCHECK2(*dp, 24); 136518976Sdfr if (verbose > 1) { 136618976Sdfr return parse_wcc_attr(dp); 136718976Sdfr } else { 136818976Sdfr /* If not verbose enough, just skip over wcc_attr */ 136918976Sdfr return (dp + 6); 137017680Spst } 137126184Sfennertrunc: 137226184Sfenner return (NULL); 137318976Sdfr} 137417680Spst 137518976Sdfr/* 137618976Sdfr * Post operation attributes are printed if vflag >= 1 137718976Sdfr */ 137818976Sdfrstatic const u_int32_t * 137918976Sdfrparse_post_op_attr(const u_int32_t *dp, int verbose) 138018976Sdfr{ 138126184Sfenner TCHECK(dp[0]); 1382127675Sbms if (!EXTRACT_32BITS(&dp[0])) 138318976Sdfr return (dp + 1); 138418976Sdfr dp++; 138518976Sdfr if (verbose) { 138618976Sdfr return parsefattr(dp, verbose, 1); 138718976Sdfr } else 138818976Sdfr return (dp + (NFSX_V3FATTR / sizeof (u_int32_t))); 138926184Sfennertrunc: 139026184Sfenner return (NULL); 139118976Sdfr} 139218976Sdfr 139318976Sdfrstatic const u_int32_t * 139418976Sdfrparse_wcc_data(const u_int32_t *dp, int verbose) 139518976Sdfr{ 139618976Sdfr if (verbose > 1) 139718976Sdfr printf(" PRE:"); 139875118Sfenner if (!(dp = parse_pre_op_attr(dp, verbose))) 139975118Sfenner return (0); 140018976Sdfr 140118976Sdfr if (verbose) 140218976Sdfr printf(" POST:"); 140318976Sdfr return parse_post_op_attr(dp, verbose); 140418976Sdfr} 140518976Sdfr 140618976Sdfrstatic const u_int32_t * 140718976Sdfrparsecreateopres(const u_int32_t *dp, int verbose) 140818976Sdfr{ 140918976Sdfr int er; 141018976Sdfr 141175118Sfenner if (!(dp = parsestatus(dp, &er))) 141275118Sfenner return (0); 141318976Sdfr if (er) 141418976Sdfr dp = parse_wcc_data(dp, verbose); 141518976Sdfr else { 141626184Sfenner TCHECK(dp[0]); 1417127675Sbms if (!EXTRACT_32BITS(&dp[0])) 141818976Sdfr return (dp + 1); 141918976Sdfr dp++; 142075118Sfenner if (!(dp = parsefh(dp, 1))) 142175118Sfenner return (0); 142218976Sdfr if (verbose) { 142375118Sfenner if (!(dp = parse_post_op_attr(dp, verbose))) 142475118Sfenner return (0); 142518976Sdfr if (vflag > 1) { 1426127675Sbms printf(" dir attr:"); 142718976Sdfr dp = parse_wcc_data(dp, verbose); 142818976Sdfr } 142918976Sdfr } 143018976Sdfr } 143118976Sdfr return (dp); 143226184Sfennertrunc: 143326184Sfenner return (NULL); 143418976Sdfr} 143518976Sdfr 143618976Sdfrstatic int 143718976Sdfrparsewccres(const u_int32_t *dp, int verbose) 143818976Sdfr{ 143918976Sdfr int er; 144018976Sdfr 144175118Sfenner if (!(dp = parsestatus(dp, &er))) 144218976Sdfr return (0); 144375118Sfenner return parse_wcc_data(dp, verbose) != 0; 144418976Sdfr} 144518976Sdfr 144618976Sdfrstatic const u_int32_t * 144718976Sdfrparsev3rddirres(const u_int32_t *dp, int verbose) 144818976Sdfr{ 144918976Sdfr int er; 145018976Sdfr 145175118Sfenner if (!(dp = parsestatus(dp, &er))) 145275118Sfenner return (0); 145318976Sdfr if (vflag) 145418976Sdfr printf(" POST:"); 145575118Sfenner if (!(dp = parse_post_op_attr(dp, verbose))) 145675118Sfenner return (0); 145718976Sdfr if (er) 145818976Sdfr return dp; 145918976Sdfr if (vflag) { 146026184Sfenner TCHECK(dp[1]); 146126183Sfenner printf(" verf %08x%08x", dp[0], dp[1]); 146218976Sdfr dp += 2; 146318976Sdfr } 146418976Sdfr return dp; 146526184Sfennertrunc: 146626184Sfenner return (NULL); 146718976Sdfr} 146818976Sdfr 146918976Sdfrstatic int 147018976Sdfrparsefsinfo(const u_int32_t *dp) 147118976Sdfr{ 147218976Sdfr struct nfsv3_fsinfo *sfp; 147318976Sdfr int er; 147418976Sdfr 147575118Sfenner if (!(dp = parsestatus(dp, &er))) 147618976Sdfr return (0); 147718976Sdfr if (vflag) 147818976Sdfr printf(" POST:"); 147975118Sfenner if (!(dp = parse_post_op_attr(dp, vflag))) 148018976Sdfr return (0); 148118976Sdfr if (er) 148218976Sdfr return (1); 148318976Sdfr 148418976Sdfr sfp = (struct nfsv3_fsinfo *)dp; 148526184Sfenner TCHECK(*sfp); 148675118Sfenner printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u", 1487127675Sbms EXTRACT_32BITS(&sfp->fs_rtmax), 1488127675Sbms EXTRACT_32BITS(&sfp->fs_rtpref), 1489127675Sbms EXTRACT_32BITS(&sfp->fs_wtmax), 1490127675Sbms EXTRACT_32BITS(&sfp->fs_wtpref), 1491127675Sbms EXTRACT_32BITS(&sfp->fs_dtpref)); 149218976Sdfr if (vflag) { 1493146778Ssam printf(" rtmult %u wtmult %u maxfsz %" PRIu64, 1494127675Sbms EXTRACT_32BITS(&sfp->fs_rtmult), 1495146778Ssam EXTRACT_32BITS(&sfp->fs_wtmult), 1496146778Ssam EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize)); 149775118Sfenner printf(" delta %u.%06u ", 1498127675Sbms EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec), 1499127675Sbms EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec)); 150018976Sdfr } 1501111729Sfenner return (1); 1502111729Sfennertrunc: 150375118Sfenner return (0); 150418976Sdfr} 150518976Sdfr 150618976Sdfrstatic int 150718976Sdfrparsepathconf(const u_int32_t *dp) 150818976Sdfr{ 150918976Sdfr int er; 151018976Sdfr struct nfsv3_pathconf *spp; 151118976Sdfr 151275118Sfenner if (!(dp = parsestatus(dp, &er))) 151318976Sdfr return (0); 151418976Sdfr if (vflag) 151518976Sdfr printf(" POST:"); 151675118Sfenner if (!(dp = parse_post_op_attr(dp, vflag))) 151718976Sdfr return (0); 151818976Sdfr if (er) 151918976Sdfr return (1); 152018976Sdfr 152118976Sdfr spp = (struct nfsv3_pathconf *)dp; 152226184Sfenner TCHECK(*spp); 152318976Sdfr 152475118Sfenner printf(" linkmax %u namemax %u %s %s %s %s", 1525127675Sbms EXTRACT_32BITS(&spp->pc_linkmax), 1526127675Sbms EXTRACT_32BITS(&spp->pc_namemax), 1527127675Sbms EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "", 1528127675Sbms EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "", 1529127675Sbms EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "", 1530127675Sbms EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : ""); 1531111729Sfenner return (1); 1532111729Sfennertrunc: 153375118Sfenner return (0); 153417680Spst} 153575118Sfenner 153617680Spststatic void 1537146778Ssaminterp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length) 153817680Spst{ 153917680Spst register const u_int32_t *dp; 154018976Sdfr register int v3; 154118976Sdfr int er; 154217680Spst 154318976Sdfr v3 = (vers == NFS_VER3); 154418976Sdfr 154518976Sdfr if (!v3 && proc < NFS_NPROCS) 154618976Sdfr proc = nfsv3_procid[proc]; 154718976Sdfr 154817680Spst switch (proc) { 154917680Spst 155017680Spst case NFSPROC_NOOP: 155117680Spst printf(" nop"); 155217680Spst return; 155318976Sdfr 155417680Spst case NFSPROC_NULL: 155517680Spst printf(" null"); 155617680Spst return; 155717680Spst 155817680Spst case NFSPROC_GETATTR: 155917680Spst printf(" getattr"); 156017680Spst dp = parserep(rp, length); 156126183Sfenner if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0) 156217680Spst return; 156317680Spst break; 156417680Spst 156517680Spst case NFSPROC_SETATTR: 156617680Spst printf(" setattr"); 156775118Sfenner if (!(dp = parserep(rp, length))) 156817680Spst return; 156918976Sdfr if (v3) { 157075118Sfenner if (parsewccres(dp, vflag)) 157118976Sdfr return; 157218976Sdfr } else { 157318976Sdfr if (parseattrstat(dp, !qflag, 0) != 0) 157418976Sdfr return; 157518976Sdfr } 157617680Spst break; 157717680Spst 157817680Spst case NFSPROC_LOOKUP: 157917680Spst printf(" lookup"); 158075118Sfenner if (!(dp = parserep(rp, length))) 158118976Sdfr break; 158218976Sdfr if (v3) { 158375118Sfenner if (!(dp = parsestatus(dp, &er))) 158418976Sdfr break; 158518976Sdfr if (er) { 158618976Sdfr if (vflag > 1) { 158718976Sdfr printf(" post dattr:"); 158818976Sdfr dp = parse_post_op_attr(dp, vflag); 158918976Sdfr } 159018976Sdfr } else { 159175118Sfenner if (!(dp = parsefh(dp, v3))) 159218976Sdfr break; 159375118Sfenner if ((dp = parse_post_op_attr(dp, vflag)) && 159475118Sfenner vflag > 1) { 159518976Sdfr printf(" post dattr:"); 159618976Sdfr dp = parse_post_op_attr(dp, vflag); 159718976Sdfr } 159818976Sdfr } 159975118Sfenner if (dp) 160018976Sdfr return; 160118976Sdfr } else { 160218976Sdfr if (parsediropres(dp) != 0) 160318976Sdfr return; 160418976Sdfr } 160517680Spst break; 160617680Spst 160718976Sdfr case NFSPROC_ACCESS: 160818976Sdfr printf(" access"); 160998527Sfenner if (!(dp = parserep(rp, length))) 161098527Sfenner break; 161175118Sfenner if (!(dp = parsestatus(dp, &er))) 161218976Sdfr break; 161318976Sdfr if (vflag) 161418976Sdfr printf(" attr:"); 161575118Sfenner if (!(dp = parse_post_op_attr(dp, vflag))) 161618976Sdfr break; 161718976Sdfr if (!er) 1618127675Sbms printf(" c %04x", EXTRACT_32BITS(&dp[0])); 161918976Sdfr return; 162018976Sdfr 162117680Spst case NFSPROC_READLINK: 162217680Spst printf(" readlink"); 162317680Spst dp = parserep(rp, length); 162426183Sfenner if (dp != NULL && parselinkres(dp, v3) != 0) 162517680Spst return; 162617680Spst break; 162717680Spst 162817680Spst case NFSPROC_READ: 162917680Spst printf(" read"); 163075118Sfenner if (!(dp = parserep(rp, length))) 163118976Sdfr break; 163218976Sdfr if (v3) { 163375118Sfenner if (!(dp = parsestatus(dp, &er))) 163418976Sdfr break; 163575118Sfenner if (!(dp = parse_post_op_attr(dp, vflag))) 163618976Sdfr break; 163718976Sdfr if (er) 163818976Sdfr return; 163918976Sdfr if (vflag) { 164075118Sfenner TCHECK(dp[1]); 1641127675Sbms printf(" %u bytes", EXTRACT_32BITS(&dp[0])); 1642127675Sbms if (EXTRACT_32BITS(&dp[1])) 164318976Sdfr printf(" EOF"); 164418976Sdfr } 164517680Spst return; 164618976Sdfr } else { 164718976Sdfr if (parseattrstat(dp, vflag, 0) != 0) 164818976Sdfr return; 164918976Sdfr } 165017680Spst break; 165117680Spst 165217680Spst case NFSPROC_WRITE: 165317680Spst printf(" write"); 165475118Sfenner if (!(dp = parserep(rp, length))) 165518976Sdfr break; 165618976Sdfr if (v3) { 165775118Sfenner if (!(dp = parsestatus(dp, &er))) 165818976Sdfr break; 165975118Sfenner if (!(dp = parse_wcc_data(dp, vflag))) 166018976Sdfr break; 166118976Sdfr if (er) 166218976Sdfr return; 166318976Sdfr if (vflag) { 166475118Sfenner TCHECK(dp[0]); 1665127675Sbms printf(" %u bytes", EXTRACT_32BITS(&dp[0])); 166618976Sdfr if (vflag > 1) { 166775118Sfenner TCHECK(dp[1]); 166818976Sdfr printf(" <%s>", 166975118Sfenner tok2str(nfsv3_writemodes, 1670127675Sbms NULL, EXTRACT_32BITS(&dp[1]))); 167118976Sdfr } 167218976Sdfr return; 167318976Sdfr } 167418976Sdfr } else { 167518976Sdfr if (parseattrstat(dp, vflag, v3) != 0) 167618976Sdfr return; 167718976Sdfr } 167817680Spst break; 167917680Spst 168017680Spst case NFSPROC_CREATE: 168117680Spst printf(" create"); 168275118Sfenner if (!(dp = parserep(rp, length))) 168318976Sdfr break; 168418976Sdfr if (v3) { 168575118Sfenner if (parsecreateopres(dp, vflag) != 0) 168618976Sdfr return; 168718976Sdfr } else { 168818976Sdfr if (parsediropres(dp) != 0) 168918976Sdfr return; 169018976Sdfr } 169118976Sdfr break; 169218976Sdfr 169318976Sdfr case NFSPROC_MKDIR: 169418976Sdfr printf(" mkdir"); 169575118Sfenner if (!(dp = parserep(rp, length))) 169618976Sdfr break; 169718976Sdfr if (v3) { 169875118Sfenner if (parsecreateopres(dp, vflag) != 0) 169918976Sdfr return; 170018976Sdfr } else { 170118976Sdfr if (parsediropres(dp) != 0) 170218976Sdfr return; 170318976Sdfr } 170418976Sdfr break; 170518976Sdfr 170618976Sdfr case NFSPROC_SYMLINK: 170718976Sdfr printf(" symlink"); 170875118Sfenner if (!(dp = parserep(rp, length))) 170918976Sdfr break; 171018976Sdfr if (v3) { 171175118Sfenner if (parsecreateopres(dp, vflag) != 0) 171218976Sdfr return; 171318976Sdfr } else { 171475118Sfenner if (parsestatus(dp, &er) != 0) 171518976Sdfr return; 171618976Sdfr } 171718976Sdfr break; 171818976Sdfr 171918976Sdfr case NFSPROC_MKNOD: 172018976Sdfr printf(" mknod"); 172175118Sfenner if (!(dp = parserep(rp, length))) 172218976Sdfr break; 172375118Sfenner if (parsecreateopres(dp, vflag) != 0) 172417680Spst return; 172517680Spst break; 172617680Spst 172717680Spst case NFSPROC_REMOVE: 172817680Spst printf(" remove"); 172975118Sfenner if (!(dp = parserep(rp, length))) 173018976Sdfr break; 173118976Sdfr if (v3) { 173275118Sfenner if (parsewccres(dp, vflag)) 173318976Sdfr return; 173418976Sdfr } else { 173575118Sfenner if (parsestatus(dp, &er) != 0) 173618976Sdfr return; 173718976Sdfr } 173817680Spst break; 173917680Spst 174018976Sdfr case NFSPROC_RMDIR: 174118976Sdfr printf(" rmdir"); 174275118Sfenner if (!(dp = parserep(rp, length))) 174318976Sdfr break; 174418976Sdfr if (v3) { 174575118Sfenner if (parsewccres(dp, vflag)) 174618976Sdfr return; 174718976Sdfr } else { 174875118Sfenner if (parsestatus(dp, &er) != 0) 174918976Sdfr return; 175018976Sdfr } 175118976Sdfr break; 175218976Sdfr 175317680Spst case NFSPROC_RENAME: 175417680Spst printf(" rename"); 175575118Sfenner if (!(dp = parserep(rp, length))) 175618976Sdfr break; 175718976Sdfr if (v3) { 175875118Sfenner if (!(dp = parsestatus(dp, &er))) 175918976Sdfr break; 176018976Sdfr if (vflag) { 176118976Sdfr printf(" from:"); 176275118Sfenner if (!(dp = parse_wcc_data(dp, vflag))) 176318976Sdfr break; 176418976Sdfr printf(" to:"); 176575118Sfenner if (!(dp = parse_wcc_data(dp, vflag))) 176618976Sdfr break; 176718976Sdfr } 176817680Spst return; 176918976Sdfr } else { 177075118Sfenner if (parsestatus(dp, &er) != 0) 177118976Sdfr return; 177218976Sdfr } 177317680Spst break; 177417680Spst 177517680Spst case NFSPROC_LINK: 177617680Spst printf(" link"); 177775118Sfenner if (!(dp = parserep(rp, length))) 177818976Sdfr break; 177918976Sdfr if (v3) { 178075118Sfenner if (!(dp = parsestatus(dp, &er))) 178118976Sdfr break; 178218976Sdfr if (vflag) { 178318976Sdfr printf(" file POST:"); 178475118Sfenner if (!(dp = parse_post_op_attr(dp, vflag))) 178518976Sdfr break; 178618976Sdfr printf(" dir:"); 178775118Sfenner if (!(dp = parse_wcc_data(dp, vflag))) 178818976Sdfr break; 178918976Sdfr return; 179018976Sdfr } 179118976Sdfr } else { 179275118Sfenner if (parsestatus(dp, &er) != 0) 179318976Sdfr return; 179418976Sdfr } 179517680Spst break; 179617680Spst 179718976Sdfr case NFSPROC_READDIR: 179818976Sdfr printf(" readdir"); 179975118Sfenner if (!(dp = parserep(rp, length))) 180018976Sdfr break; 180118976Sdfr if (v3) { 180275118Sfenner if (parsev3rddirres(dp, vflag)) 180318976Sdfr return; 180418976Sdfr } else { 180518976Sdfr if (parserddires(dp) != 0) 180618976Sdfr return; 180718976Sdfr } 180818976Sdfr break; 180918976Sdfr 181018976Sdfr case NFSPROC_READDIRPLUS: 181118976Sdfr printf(" readdirplus"); 181275118Sfenner if (!(dp = parserep(rp, length))) 181318976Sdfr break; 181475118Sfenner if (parsev3rddirres(dp, vflag)) 181517680Spst return; 181617680Spst break; 181717680Spst 181818976Sdfr case NFSPROC_FSSTAT: 181918976Sdfr printf(" fsstat"); 182017680Spst dp = parserep(rp, length); 182175118Sfenner if (dp != NULL && parsestatfs(dp, v3) != 0) 182217680Spst return; 182317680Spst break; 182417680Spst 182518976Sdfr case NFSPROC_FSINFO: 182618976Sdfr printf(" fsinfo"); 182717680Spst dp = parserep(rp, length); 182875118Sfenner if (dp != NULL && parsefsinfo(dp) != 0) 182917680Spst return; 183017680Spst break; 183117680Spst 183218976Sdfr case NFSPROC_PATHCONF: 183318976Sdfr printf(" pathconf"); 183417680Spst dp = parserep(rp, length); 183526183Sfenner if (dp != NULL && parsepathconf(dp) != 0) 183617680Spst return; 183717680Spst break; 183817680Spst 183918976Sdfr case NFSPROC_COMMIT: 184018976Sdfr printf(" commit"); 184117680Spst dp = parserep(rp, length); 184226183Sfenner if (dp != NULL && parsewccres(dp, vflag) != 0) 184317680Spst return; 184417680Spst break; 184517680Spst 184617680Spst default: 184726183Sfenner printf(" proc-%u", proc); 184817680Spst return; 184917680Spst } 185018976Sdfrtrunc: 185126183Sfenner if (!nfserr) 185226183Sfenner fputs(" [|nfs]", stdout); 185317680Spst} 1854