14edb46e9SPaul Traina /* 2699fc314SBill Fenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 34edb46e9SPaul Traina * The Regents of the University of California. All rights reserved. 44edb46e9SPaul Traina * 54edb46e9SPaul Traina * Redistribution and use in source and binary forms, with or without 64edb46e9SPaul Traina * modification, are permitted provided that: (1) source code distributions 74edb46e9SPaul Traina * retain the above copyright notice and this paragraph in its entirety, (2) 84edb46e9SPaul Traina * distributions including binary code include the above copyright notice and 94edb46e9SPaul Traina * this paragraph in its entirety in the documentation or other materials 104edb46e9SPaul Traina * provided with the distribution, and (3) all advertising materials mentioning 114edb46e9SPaul Traina * features or use of this software display the following acknowledgement: 124edb46e9SPaul Traina * ``This product includes software developed by the University of California, 134edb46e9SPaul Traina * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 144edb46e9SPaul Traina * the University nor the names of its contributors may be used to endorse 154edb46e9SPaul Traina * or promote products derived from this software without specific prior 164edb46e9SPaul Traina * written permission. 174edb46e9SPaul Traina * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 184edb46e9SPaul Traina * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 194edb46e9SPaul Traina * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 204edb46e9SPaul Traina */ 214edb46e9SPaul Traina 224edb46e9SPaul Traina #ifndef lint 232ebf6c05SBill Fenner static const char rcsid[] = 24699fc314SBill Fenner "@(#) $Header: print-nfs.c,v 1.65 97/08/17 13:24:22 leres Exp $ (LBL)"; 254edb46e9SPaul Traina #endif 264edb46e9SPaul Traina 274edb46e9SPaul Traina #include <sys/param.h> 284edb46e9SPaul Traina #include <sys/time.h> 294edb46e9SPaul Traina #include <sys/socket.h> 304edb46e9SPaul Traina 314edb46e9SPaul Traina #include <net/if.h> 324edb46e9SPaul Traina 334edb46e9SPaul Traina #include <netinet/in.h> 34ee3e7633SGarrett Wollman #include <net/ethernet.h> 354edb46e9SPaul Traina #include <netinet/in_systm.h> 364edb46e9SPaul Traina #include <netinet/ip.h> 374edb46e9SPaul Traina #include <netinet/ip_var.h> 384edb46e9SPaul Traina 394edb46e9SPaul Traina #include <rpc/rpc.h> 404edb46e9SPaul Traina 414edb46e9SPaul Traina #include <ctype.h> 422ebf6c05SBill Fenner #include <pcap.h> 434edb46e9SPaul Traina #include <stdio.h> 444edb46e9SPaul Traina #include <string.h> 454edb46e9SPaul Traina 464edb46e9SPaul Traina #include "interface.h" 474edb46e9SPaul Traina #include "addrtoname.h" 48647f50c3SDoug Rabson #include "extract.h" /* must come after interface.h */ 494edb46e9SPaul Traina 50647f50c3SDoug Rabson #include "nfs.h" 514edb46e9SPaul Traina #include "nfsfh.h" 524edb46e9SPaul Traina 53647f50c3SDoug Rabson static void nfs_printfh(const u_int32_t *, const int); 544edb46e9SPaul Traina static void xid_map_enter(const struct rpc_msg *, const struct ip *); 55647f50c3SDoug Rabson static int32_t xid_map_find(const struct rpc_msg *, const struct ip *, u_int32_t *, 56647f50c3SDoug Rabson u_int32_t *); 57647f50c3SDoug Rabson static void interp_reply(const struct rpc_msg *, u_int32_t, u_int32_t, int); 58647f50c3SDoug Rabson static const u_int32_t *parse_post_op_attr(const u_int32_t *, int); 59647f50c3SDoug Rabson 602ebf6c05SBill Fenner static int nfserr; /* true if we error rather than trunc */ 612ebf6c05SBill Fenner 62647f50c3SDoug Rabson /* 63647f50c3SDoug Rabson * Mapping of old NFS Version 2 RPC numbers to generic numbers. 64647f50c3SDoug Rabson */ 65647f50c3SDoug Rabson u_int32_t nfsv3_procid[NFS_NPROCS] = { 66647f50c3SDoug Rabson NFSPROC_NULL, 67647f50c3SDoug Rabson NFSPROC_GETATTR, 68647f50c3SDoug Rabson NFSPROC_SETATTR, 69647f50c3SDoug Rabson NFSPROC_NOOP, 70647f50c3SDoug Rabson NFSPROC_LOOKUP, 71647f50c3SDoug Rabson NFSPROC_READLINK, 72647f50c3SDoug Rabson NFSPROC_READ, 73647f50c3SDoug Rabson NFSPROC_NOOP, 74647f50c3SDoug Rabson NFSPROC_WRITE, 75647f50c3SDoug Rabson NFSPROC_CREATE, 76647f50c3SDoug Rabson NFSPROC_REMOVE, 77647f50c3SDoug Rabson NFSPROC_RENAME, 78647f50c3SDoug Rabson NFSPROC_LINK, 79647f50c3SDoug Rabson NFSPROC_SYMLINK, 80647f50c3SDoug Rabson NFSPROC_MKDIR, 81647f50c3SDoug Rabson NFSPROC_RMDIR, 82647f50c3SDoug Rabson NFSPROC_READDIR, 83647f50c3SDoug Rabson NFSPROC_FSSTAT, 84647f50c3SDoug Rabson NFSPROC_NOOP, 85647f50c3SDoug Rabson NFSPROC_NOOP, 86647f50c3SDoug Rabson NFSPROC_NOOP, 87647f50c3SDoug Rabson NFSPROC_NOOP, 88647f50c3SDoug Rabson NFSPROC_NOOP, 89647f50c3SDoug Rabson NFSPROC_NOOP, 90647f50c3SDoug Rabson NFSPROC_NOOP, 91647f50c3SDoug Rabson NFSPROC_NOOP 92647f50c3SDoug Rabson }; 93647f50c3SDoug Rabson 94647f50c3SDoug Rabson const char *nfsv3_writemodes[NFSV3WRITE_NMODES] = { 95647f50c3SDoug Rabson "unstable", 96647f50c3SDoug Rabson "datasync", 97647f50c3SDoug Rabson "filesync" 98647f50c3SDoug Rabson }; 99647f50c3SDoug Rabson 100647f50c3SDoug Rabson static struct tok type2str[] = { 101647f50c3SDoug Rabson { NFNON, "NON" }, 102647f50c3SDoug Rabson { NFREG, "REG" }, 103647f50c3SDoug Rabson { NFDIR, "DIR" }, 104647f50c3SDoug Rabson { NFBLK, "BLK" }, 105647f50c3SDoug Rabson { NFCHR, "CHR" }, 106647f50c3SDoug Rabson { NFLNK, "LNK" }, 107647f50c3SDoug Rabson { NFFIFO, "FIFO" }, 108647f50c3SDoug Rabson { 0, NULL } 109647f50c3SDoug Rabson }; 110647f50c3SDoug Rabson 111647f50c3SDoug Rabson /* 112647f50c3SDoug Rabson * Print out a 64-bit integer. This appears to be different on each system, 113647f50c3SDoug Rabson * try to make the best of it. The integer stored as 2 consecutive XDR 114647f50c3SDoug Rabson * encoded 32-bit integers, to which a pointer is passed. 115647f50c3SDoug Rabson * 116647f50c3SDoug Rabson * Assume that a system that has INT64_FORMAT defined, has a 64-bit 117647f50c3SDoug Rabson * integer datatype and can print it. 118647f50c3SDoug Rabson */ 119647f50c3SDoug Rabson 120647f50c3SDoug Rabson #define UNSIGNED 0 121647f50c3SDoug Rabson #define SIGNED 1 122647f50c3SDoug Rabson #define HEX 2 123647f50c3SDoug Rabson 124647f50c3SDoug Rabson #define INT64_FORMAT "%qd" 125647f50c3SDoug Rabson #define U_INT64_FORMAT "%qu" 126647f50c3SDoug Rabson #define HEX_INT64_FORMAT "%qx" 127647f50c3SDoug Rabson 128647f50c3SDoug Rabson int print_int64(const u_int32_t *dp, int how) 129647f50c3SDoug Rabson { 130647f50c3SDoug Rabson #ifdef INT64_FORMAT 131647f50c3SDoug Rabson u_int64_t res; 132647f50c3SDoug Rabson 133647f50c3SDoug Rabson res = ((u_int64_t)ntohl(dp[0]) << 32) | (u_int64_t)ntohl(dp[1]); 134647f50c3SDoug Rabson switch (how) { 135647f50c3SDoug Rabson case SIGNED: 136647f50c3SDoug Rabson printf(INT64_FORMAT, res); 137647f50c3SDoug Rabson break; 138647f50c3SDoug Rabson case UNSIGNED: 139647f50c3SDoug Rabson printf(U_INT64_FORMAT, res); 140647f50c3SDoug Rabson break; 141647f50c3SDoug Rabson case HEX: 142647f50c3SDoug Rabson printf(HEX_INT64_FORMAT, res); 143647f50c3SDoug Rabson break; 144647f50c3SDoug Rabson default: 145647f50c3SDoug Rabson return (0); 146647f50c3SDoug Rabson } 147647f50c3SDoug Rabson #else 148647f50c3SDoug Rabson /* 149647f50c3SDoug Rabson * XXX - throw upper 32 bits away. 150647f50c3SDoug Rabson * Could also go for hex: printf("0x%x%x", dp[0], dp[1]); 151647f50c3SDoug Rabson */ 152647f50c3SDoug Rabson if (how == SIGNED) 153647f50c3SDoug Rabson printf("%ld", (int)dp[1]); 154647f50c3SDoug Rabson else 155647f50c3SDoug Rabson printf("%lu", (unsigned int)dp[1]); 156647f50c3SDoug Rabson #endif 157647f50c3SDoug Rabson return 1; 158647f50c3SDoug Rabson } 159647f50c3SDoug Rabson 160647f50c3SDoug Rabson static const u_int32_t * 161647f50c3SDoug Rabson parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3) 162647f50c3SDoug Rabson { 163647f50c3SDoug Rabson register const u_int32_t *ep = (u_int32_t *)snapend; 164647f50c3SDoug Rabson 165647f50c3SDoug Rabson if (dp + 1 > ep) 1662ebf6c05SBill Fenner return (NULL); 167647f50c3SDoug Rabson if ((sa3->sa_modeset = ntohl(*dp++))) { 168647f50c3SDoug Rabson if (dp + 1 > ep) 1692ebf6c05SBill Fenner return (NULL); 170647f50c3SDoug Rabson sa3->sa_mode = ntohl(*dp++); 171647f50c3SDoug Rabson } 172647f50c3SDoug Rabson 173647f50c3SDoug Rabson if (dp + 1 > ep) 1742ebf6c05SBill Fenner return (NULL); 175647f50c3SDoug Rabson if ((sa3->sa_uidset = ntohl(*dp++))) { 176647f50c3SDoug Rabson if (dp + 1 > ep) 1772ebf6c05SBill Fenner return (NULL); 178647f50c3SDoug Rabson sa3->sa_uid = ntohl(*dp++); 179647f50c3SDoug Rabson } 180647f50c3SDoug Rabson 181647f50c3SDoug Rabson if (dp + 1 > ep) 1822ebf6c05SBill Fenner return (NULL); 183647f50c3SDoug Rabson if ((sa3->sa_gidset = ntohl(*dp++))) { 184647f50c3SDoug Rabson if (dp + 1 > ep) 1852ebf6c05SBill Fenner return (NULL); 186647f50c3SDoug Rabson sa3->sa_gid = ntohl(*dp++); 187647f50c3SDoug Rabson } 188647f50c3SDoug Rabson 189647f50c3SDoug Rabson if (dp + 1 > ep) 1902ebf6c05SBill Fenner return (NULL); 191647f50c3SDoug Rabson if ((sa3->sa_sizeset = ntohl(*dp++))) { 192647f50c3SDoug Rabson if (dp + 1 > ep) 1932ebf6c05SBill Fenner return (NULL); 194647f50c3SDoug Rabson sa3->sa_size = ntohl(*dp++); 195647f50c3SDoug Rabson } 196647f50c3SDoug Rabson 197647f50c3SDoug Rabson if (dp + 1 > ep) 1982ebf6c05SBill Fenner return (NULL); 199647f50c3SDoug Rabson if ((sa3->sa_atimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) { 200647f50c3SDoug Rabson if (dp + 2 > ep) 2012ebf6c05SBill Fenner return (NULL); 202647f50c3SDoug Rabson sa3->sa_atime.nfsv3_sec = ntohl(*dp++); 203647f50c3SDoug Rabson sa3->sa_atime.nfsv3_nsec = ntohl(*dp++); 204647f50c3SDoug Rabson } 205647f50c3SDoug Rabson 206647f50c3SDoug Rabson if (dp + 1 > ep) 2072ebf6c05SBill Fenner return (NULL); 208647f50c3SDoug Rabson if ((sa3->sa_mtimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) { 209647f50c3SDoug Rabson if (dp + 2 > ep) 2102ebf6c05SBill Fenner return (NULL); 211647f50c3SDoug Rabson sa3->sa_mtime.nfsv3_sec = ntohl(*dp++); 212647f50c3SDoug Rabson sa3->sa_mtime.nfsv3_nsec = ntohl(*dp++); 213647f50c3SDoug Rabson } 214647f50c3SDoug Rabson 215647f50c3SDoug Rabson return dp; 216647f50c3SDoug Rabson } 217647f50c3SDoug Rabson 218647f50c3SDoug Rabson void 219647f50c3SDoug Rabson print_sattr3(const struct nfsv3_sattr *sa3, int verbose) 220647f50c3SDoug Rabson { 221647f50c3SDoug Rabson if (sa3->sa_modeset) 222647f50c3SDoug Rabson printf(" mode %o", sa3->sa_mode); 223647f50c3SDoug Rabson if (sa3->sa_uidset) 224647f50c3SDoug Rabson printf(" uid %u", sa3->sa_uid); 225647f50c3SDoug Rabson if (sa3->sa_gidset) 226647f50c3SDoug Rabson printf(" gid %u", sa3->sa_gid); 227647f50c3SDoug Rabson if (verbose > 1) { 228647f50c3SDoug Rabson if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) 229647f50c3SDoug Rabson printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec, 230647f50c3SDoug Rabson sa3->sa_atime.nfsv3_nsec); 231647f50c3SDoug Rabson if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) 232647f50c3SDoug Rabson printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec, 233647f50c3SDoug Rabson sa3->sa_mtime.nfsv3_nsec); 234647f50c3SDoug Rabson } 235647f50c3SDoug Rabson } 2364edb46e9SPaul Traina 2374edb46e9SPaul Traina void 2384edb46e9SPaul Traina nfsreply_print(register const u_char *bp, u_int length, 2394edb46e9SPaul Traina register const u_char *bp2) 2404edb46e9SPaul Traina { 2414edb46e9SPaul Traina register const struct rpc_msg *rp; 2424edb46e9SPaul Traina register const struct ip *ip; 243647f50c3SDoug Rabson u_int32_t proc, vers; 2444edb46e9SPaul Traina 2452ebf6c05SBill Fenner nfserr = 0; /* assume no error */ 2464edb46e9SPaul Traina rp = (const struct rpc_msg *)bp; 2474edb46e9SPaul Traina ip = (const struct ip *)bp2; 2484edb46e9SPaul Traina 2494edb46e9SPaul Traina if (!nflag) 250699fc314SBill Fenner (void)printf("%s.nfs > %s.%u: reply %s %d", 2514edb46e9SPaul Traina ipaddr_string(&ip->ip_src), 2524edb46e9SPaul Traina ipaddr_string(&ip->ip_dst), 2534edb46e9SPaul Traina (u_int32_t)ntohl(rp->rm_xid), 2544edb46e9SPaul Traina ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED? 2554edb46e9SPaul Traina "ok":"ERR", 2564edb46e9SPaul Traina length); 2574edb46e9SPaul Traina else 258699fc314SBill Fenner (void)printf("%s.%u > %s.%u: reply %s %d", 2594edb46e9SPaul Traina ipaddr_string(&ip->ip_src), 2604edb46e9SPaul Traina NFS_PORT, 2614edb46e9SPaul Traina ipaddr_string(&ip->ip_dst), 2624edb46e9SPaul Traina (u_int32_t)ntohl(rp->rm_xid), 2634edb46e9SPaul Traina ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED? 2644edb46e9SPaul Traina "ok":"ERR", 2654edb46e9SPaul Traina length); 2664edb46e9SPaul Traina 267647f50c3SDoug Rabson if (xid_map_find(rp, ip, &proc, &vers) >= 0) 268647f50c3SDoug Rabson interp_reply(rp, proc, vers, length); 2694edb46e9SPaul Traina } 2704edb46e9SPaul Traina 2714edb46e9SPaul Traina /* 2724edb46e9SPaul Traina * Return a pointer to the first file handle in the packet. 2732ebf6c05SBill Fenner * If the packet was truncated, return NULL. 2744edb46e9SPaul Traina */ 2754edb46e9SPaul Traina static const u_int32_t * 276647f50c3SDoug Rabson parsereq(register const struct rpc_msg *rp, register int length) 2774edb46e9SPaul Traina { 2782ebf6c05SBill Fenner register const u_int32_t *dp; 2794edb46e9SPaul Traina register u_int len; 2804edb46e9SPaul Traina 2814edb46e9SPaul Traina /* 2824edb46e9SPaul Traina * find the start of the req data (if we captured it) 2834edb46e9SPaul Traina */ 2842ebf6c05SBill Fenner dp = (u_int32_t *)&rp->rm_call.cb_cred; 2852ebf6c05SBill Fenner TCHECK(dp[1]); 2864edb46e9SPaul Traina len = ntohl(dp[1]); 2872ebf6c05SBill Fenner if (len < length) { 2882ebf6c05SBill Fenner dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 2892ebf6c05SBill Fenner TCHECK(dp[1]); 2904edb46e9SPaul Traina len = ntohl(dp[1]); 2912ebf6c05SBill Fenner if (len < length) { 2922ebf6c05SBill Fenner dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 2932ebf6c05SBill Fenner TCHECK2(dp[0], 0); 2944edb46e9SPaul Traina return (dp); 2954edb46e9SPaul Traina } 2964edb46e9SPaul Traina } 2972ebf6c05SBill Fenner trunc: 2982ebf6c05SBill Fenner return (NULL); 2994edb46e9SPaul Traina } 3004edb46e9SPaul Traina 3014edb46e9SPaul Traina /* 3024edb46e9SPaul Traina * Print out an NFS file handle and return a pointer to following word. 3032ebf6c05SBill Fenner * If packet was truncated, return NULL. 3044edb46e9SPaul Traina */ 3054edb46e9SPaul Traina static const u_int32_t * 306647f50c3SDoug Rabson parsefh(register const u_int32_t *dp, int v3) 3074edb46e9SPaul Traina { 308647f50c3SDoug Rabson int len; 309647f50c3SDoug Rabson 310647f50c3SDoug Rabson if (v3) { 3112ebf6c05SBill Fenner TCHECK(dp[0]); 312647f50c3SDoug Rabson len = (int)ntohl(*dp) / 4; 313647f50c3SDoug Rabson dp++; 314647f50c3SDoug Rabson } else 315647f50c3SDoug Rabson len = NFSX_V2FH / 4; 316647f50c3SDoug Rabson 3172ebf6c05SBill Fenner if (TTEST2(*dp, len * sizeof(*dp))) { 318647f50c3SDoug Rabson nfs_printfh(dp, len); 319647f50c3SDoug Rabson return (dp + len); 3204edb46e9SPaul Traina } 3212ebf6c05SBill Fenner trunc: 3222ebf6c05SBill Fenner return (NULL); 3234edb46e9SPaul Traina } 3244edb46e9SPaul Traina 3254edb46e9SPaul Traina /* 3264edb46e9SPaul Traina * Print out a file name and return pointer to 32-bit word past it. 3272ebf6c05SBill Fenner * If packet was truncated, return NULL. 3284edb46e9SPaul Traina */ 3294edb46e9SPaul Traina static const u_int32_t * 3304edb46e9SPaul Traina parsefn(register const u_int32_t *dp) 3314edb46e9SPaul Traina { 3324edb46e9SPaul Traina register u_int32_t len; 3334edb46e9SPaul Traina register const u_char *cp; 3344edb46e9SPaul Traina 3354edb46e9SPaul Traina /* Bail if we don't have the string length */ 3364edb46e9SPaul Traina if ((u_char *)dp > snapend - sizeof(*dp)) 3372ebf6c05SBill Fenner return (NULL); 3384edb46e9SPaul Traina 3394edb46e9SPaul Traina /* Fetch string length; convert to host order */ 3404edb46e9SPaul Traina len = *dp++; 3414edb46e9SPaul Traina NTOHL(len); 3424edb46e9SPaul Traina 3434edb46e9SPaul Traina cp = (u_char *)dp; 3444edb46e9SPaul Traina /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ 3454edb46e9SPaul Traina dp += ((len + 3) & ~3) / sizeof(*dp); 3464edb46e9SPaul Traina if ((u_char *)dp > snapend) 3472ebf6c05SBill Fenner return (NULL); 3484edb46e9SPaul Traina /* XXX seems like we should be checking the length */ 3492ebf6c05SBill Fenner putchar('"'); 3504edb46e9SPaul Traina (void) fn_printn(cp, len, NULL); 3512ebf6c05SBill Fenner putchar('"'); 3524edb46e9SPaul Traina 3534edb46e9SPaul Traina return (dp); 3544edb46e9SPaul Traina } 3554edb46e9SPaul Traina 3564edb46e9SPaul Traina /* 3574edb46e9SPaul Traina * Print out file handle and file name. 3584edb46e9SPaul Traina * Return pointer to 32-bit word past file name. 3592ebf6c05SBill Fenner * If packet was truncated (or there was some other error), return NULL. 3604edb46e9SPaul Traina */ 3614edb46e9SPaul Traina static const u_int32_t * 362647f50c3SDoug Rabson parsefhn(register const u_int32_t *dp, int v3) 3634edb46e9SPaul Traina { 364647f50c3SDoug Rabson dp = parsefh(dp, v3); 3652ebf6c05SBill Fenner if (dp == NULL) 3662ebf6c05SBill Fenner return (NULL); 3674edb46e9SPaul Traina putchar(' '); 3684edb46e9SPaul Traina return (parsefn(dp)); 3694edb46e9SPaul Traina } 3704edb46e9SPaul Traina 3714edb46e9SPaul Traina void 3724edb46e9SPaul Traina nfsreq_print(register const u_char *bp, u_int length, 3734edb46e9SPaul Traina register const u_char *bp2) 3744edb46e9SPaul Traina { 3754edb46e9SPaul Traina register const struct rpc_msg *rp; 3764edb46e9SPaul Traina register const struct ip *ip; 3774edb46e9SPaul Traina register const u_int32_t *dp; 378647f50c3SDoug Rabson nfstype type; 379647f50c3SDoug Rabson int proc, v3; 380647f50c3SDoug Rabson struct nfsv3_sattr sa3; 3814edb46e9SPaul Traina 3822ebf6c05SBill Fenner nfserr = 0; /* assume no error */ 3834edb46e9SPaul Traina rp = (const struct rpc_msg *)bp; 3844edb46e9SPaul Traina ip = (const struct ip *)bp2; 3854edb46e9SPaul Traina if (!nflag) 386699fc314SBill Fenner (void)printf("%s.%u > %s.nfs: %d", 3874edb46e9SPaul Traina ipaddr_string(&ip->ip_src), 3884edb46e9SPaul Traina (u_int32_t)ntohl(rp->rm_xid), 3894edb46e9SPaul Traina ipaddr_string(&ip->ip_dst), 3904edb46e9SPaul Traina length); 3914edb46e9SPaul Traina else 392699fc314SBill Fenner (void)printf("%s.%u > %s.%u: %d", 3934edb46e9SPaul Traina ipaddr_string(&ip->ip_src), 3944edb46e9SPaul Traina (u_int32_t)ntohl(rp->rm_xid), 3954edb46e9SPaul Traina ipaddr_string(&ip->ip_dst), 3964edb46e9SPaul Traina NFS_PORT, 3974edb46e9SPaul Traina length); 3984edb46e9SPaul Traina 3994edb46e9SPaul Traina xid_map_enter(rp, ip); /* record proc number for later on */ 4004edb46e9SPaul Traina 401647f50c3SDoug Rabson v3 = (ntohl(rp->rm_call.cb_vers) == NFS_VER3); 402647f50c3SDoug Rabson proc = ntohl(rp->rm_call.cb_proc); 403647f50c3SDoug Rabson 404647f50c3SDoug Rabson if (!v3 && proc < NFS_NPROCS) 405647f50c3SDoug Rabson proc = nfsv3_procid[proc]; 406647f50c3SDoug Rabson 407647f50c3SDoug Rabson switch (proc) { 4084edb46e9SPaul Traina case NFSPROC_NOOP: 4094edb46e9SPaul Traina printf(" nop"); 4104edb46e9SPaul Traina return; 4114edb46e9SPaul Traina case NFSPROC_NULL: 4124edb46e9SPaul Traina printf(" null"); 4134edb46e9SPaul Traina return; 4144edb46e9SPaul Traina 4154edb46e9SPaul Traina case NFSPROC_GETATTR: 4164edb46e9SPaul Traina printf(" getattr"); 4172ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) 4184edb46e9SPaul Traina return; 4194edb46e9SPaul Traina break; 4204edb46e9SPaul Traina 4214edb46e9SPaul Traina case NFSPROC_SETATTR: 4224edb46e9SPaul Traina printf(" setattr"); 4232ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) 4244edb46e9SPaul Traina return; 4254edb46e9SPaul Traina break; 4264edb46e9SPaul Traina 4274edb46e9SPaul Traina case NFSPROC_LOOKUP: 4284edb46e9SPaul Traina printf(" lookup"); 4292ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL) 4304edb46e9SPaul Traina return; 4314edb46e9SPaul Traina break; 4324edb46e9SPaul Traina 433647f50c3SDoug Rabson case NFSPROC_ACCESS: 434647f50c3SDoug Rabson printf(" access"); 4352ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 4362ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 437647f50c3SDoug Rabson TCHECK(*dp); 4382ebf6c05SBill Fenner printf(" %04lx", ntohl(dp[0])); 439647f50c3SDoug Rabson return; 440647f50c3SDoug Rabson } 441647f50c3SDoug Rabson break; 442647f50c3SDoug Rabson 4434edb46e9SPaul Traina case NFSPROC_READLINK: 4444edb46e9SPaul Traina printf(" readlink"); 4452ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) 4464edb46e9SPaul Traina return; 4474edb46e9SPaul Traina break; 4484edb46e9SPaul Traina 4494edb46e9SPaul Traina case NFSPROC_READ: 4504edb46e9SPaul Traina printf(" read"); 4512ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 4522ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 453647f50c3SDoug Rabson if (v3) { 454647f50c3SDoug Rabson TCHECK2(*dp, 3 * sizeof(*dp)); 455647f50c3SDoug Rabson printf(" %lu bytes @ ", ntohl(dp[2])); 456647f50c3SDoug Rabson print_int64(dp, UNSIGNED); 457647f50c3SDoug Rabson } else { 458647f50c3SDoug Rabson TCHECK2(*dp, 2 * sizeof(*dp)); 459647f50c3SDoug Rabson printf(" %lu bytes @ %lu", 460647f50c3SDoug Rabson ntohl(dp[1]), ntohl(dp[0])); 461647f50c3SDoug Rabson } 4624edb46e9SPaul Traina return; 4634edb46e9SPaul Traina } 4644edb46e9SPaul Traina break; 4654edb46e9SPaul Traina 4664edb46e9SPaul Traina case NFSPROC_WRITE: 4674edb46e9SPaul Traina printf(" write"); 4682ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 4692ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 470647f50c3SDoug Rabson if (v3) { 471647f50c3SDoug Rabson TCHECK2(*dp, 3 * sizeof(*dp)); 472647f50c3SDoug Rabson printf(" %lu bytes @ ", ntohl(dp[4])); 473647f50c3SDoug Rabson print_int64(dp, UNSIGNED); 474647f50c3SDoug Rabson if (vflag) { 475647f50c3SDoug Rabson dp += 3; 476647f50c3SDoug Rabson TCHECK2(*dp, sizeof(*dp)); 477647f50c3SDoug Rabson printf(" <%s>", 478647f50c3SDoug Rabson nfsv3_writemodes[ntohl(*dp)]); 479647f50c3SDoug Rabson } 480647f50c3SDoug Rabson } else { 481647f50c3SDoug Rabson TCHECK2(*dp, 4 * sizeof(*dp)); 482647f50c3SDoug Rabson printf(" %lu (%lu) bytes @ %lu (%lu)", 483647f50c3SDoug Rabson ntohl(dp[3]), ntohl(dp[2]), 484647f50c3SDoug Rabson ntohl(dp[1]), ntohl(dp[0])); 485647f50c3SDoug Rabson } 4864edb46e9SPaul Traina return; 4874edb46e9SPaul Traina } 4884edb46e9SPaul Traina break; 4894edb46e9SPaul Traina 4904edb46e9SPaul Traina case NFSPROC_CREATE: 4914edb46e9SPaul Traina printf(" create"); 4922ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL) 4934edb46e9SPaul Traina return; 4944edb46e9SPaul Traina break; 4954edb46e9SPaul Traina 496647f50c3SDoug Rabson case NFSPROC_MKDIR: 497647f50c3SDoug Rabson printf(" mkdir"); 4982ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL) 499647f50c3SDoug Rabson return; 500647f50c3SDoug Rabson break; 501647f50c3SDoug Rabson 502647f50c3SDoug Rabson case NFSPROC_SYMLINK: 503647f50c3SDoug Rabson printf(" symlink"); 5042ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 5052ebf6c05SBill Fenner (dp = parsefhn(dp, v3)) != NULL) { 506647f50c3SDoug Rabson fputs(" -> ", stdout); 5072ebf6c05SBill Fenner if (v3 && (dp = parse_sattr3(dp, &sa3)) == NULL) 508647f50c3SDoug Rabson break; 5092ebf6c05SBill Fenner if (parsefn(dp) == NULL) 510647f50c3SDoug Rabson break; 511647f50c3SDoug Rabson if (v3 && vflag) 512647f50c3SDoug Rabson print_sattr3(&sa3, vflag); 513647f50c3SDoug Rabson return; 514647f50c3SDoug Rabson } 515647f50c3SDoug Rabson break; 516647f50c3SDoug Rabson 517647f50c3SDoug Rabson case NFSPROC_MKNOD: 518647f50c3SDoug Rabson printf(" mknod"); 5192ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 5202ebf6c05SBill Fenner (dp = parsefhn(dp, v3)) != NULL) { 521647f50c3SDoug Rabson if (dp + 1 > (u_int32_t *)snapend) 522647f50c3SDoug Rabson break; 523647f50c3SDoug Rabson type = (nfstype)ntohl(*dp++); 5242ebf6c05SBill Fenner if ((dp = parse_sattr3(dp, &sa3)) == NULL) 525647f50c3SDoug Rabson break; 526647f50c3SDoug Rabson printf(" %s", tok2str(type2str, "unk-ft %d", type)); 527647f50c3SDoug Rabson if (vflag && (type == NFCHR || type == NFBLK)) { 528647f50c3SDoug Rabson if (dp + 2 > (u_int32_t *)snapend) 529647f50c3SDoug Rabson break; 5302ebf6c05SBill Fenner printf(" %lu/%lu", ntohl(dp[0]), ntohl(dp[1])); 531647f50c3SDoug Rabson dp += 2; 532647f50c3SDoug Rabson } 533647f50c3SDoug Rabson if (vflag) 534647f50c3SDoug Rabson print_sattr3(&sa3, vflag); 535647f50c3SDoug Rabson return; 536647f50c3SDoug Rabson } 537647f50c3SDoug Rabson break; 538647f50c3SDoug Rabson 5394edb46e9SPaul Traina case NFSPROC_REMOVE: 5404edb46e9SPaul Traina printf(" remove"); 5412ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL) 542647f50c3SDoug Rabson return; 543647f50c3SDoug Rabson break; 544647f50c3SDoug Rabson 545647f50c3SDoug Rabson case NFSPROC_RMDIR: 546647f50c3SDoug Rabson printf(" rmdir"); 5472ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL) 5484edb46e9SPaul Traina return; 5494edb46e9SPaul Traina break; 5504edb46e9SPaul Traina 5514edb46e9SPaul Traina case NFSPROC_RENAME: 5524edb46e9SPaul Traina printf(" rename"); 5532ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 5542ebf6c05SBill Fenner (dp = parsefhn(dp, v3)) != NULL) { 5554edb46e9SPaul Traina fputs(" ->", stdout); 5562ebf6c05SBill Fenner if (parsefhn(dp, v3) != NULL) 5574edb46e9SPaul Traina return; 5584edb46e9SPaul Traina } 5594edb46e9SPaul Traina break; 5604edb46e9SPaul Traina 5614edb46e9SPaul Traina case NFSPROC_LINK: 5624edb46e9SPaul Traina printf(" link"); 5632ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 5642ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 5654edb46e9SPaul Traina fputs(" ->", stdout); 5662ebf6c05SBill Fenner if (parsefhn(dp, v3) != NULL) 5674edb46e9SPaul Traina return; 5684edb46e9SPaul Traina } 5694edb46e9SPaul Traina break; 5704edb46e9SPaul Traina 5714edb46e9SPaul Traina case NFSPROC_READDIR: 5724edb46e9SPaul Traina printf(" readdir"); 5732ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 5742ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 575647f50c3SDoug Rabson if (v3) { 576647f50c3SDoug Rabson TCHECK2(*dp, 20); 5774edb46e9SPaul Traina /* 578647f50c3SDoug Rabson * We shouldn't really try to interpret the 579647f50c3SDoug Rabson * offset cookie here. 5804edb46e9SPaul Traina */ 581647f50c3SDoug Rabson printf(" %lu bytes @ ", ntohl(dp[4])); 582647f50c3SDoug Rabson print_int64(dp, SIGNED); 583647f50c3SDoug Rabson if (vflag) 5842ebf6c05SBill Fenner printf(" verf %08x%08x", dp[2], 585647f50c3SDoug Rabson dp[3]); 586647f50c3SDoug Rabson } else { 587647f50c3SDoug Rabson TCHECK2(*dp, 2 * sizeof(*dp)); 588647f50c3SDoug Rabson /* 589647f50c3SDoug Rabson * Print the offset as signed, since -1 is 590647f50c3SDoug Rabson * common, but offsets > 2^31 aren't. 591647f50c3SDoug Rabson */ 592647f50c3SDoug Rabson printf(" %lu bytes @ %ld", ntohl(dp[1]), 593647f50c3SDoug Rabson ntohl(dp[0])); 594647f50c3SDoug Rabson } 5954edb46e9SPaul Traina return; 5964edb46e9SPaul Traina } 5974edb46e9SPaul Traina break; 5984edb46e9SPaul Traina 599647f50c3SDoug Rabson case NFSPROC_READDIRPLUS: 600647f50c3SDoug Rabson printf(" readdirplus"); 6012ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 6022ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 603647f50c3SDoug Rabson TCHECK2(*dp, 20); 604647f50c3SDoug Rabson /* 605647f50c3SDoug Rabson * We don't try to interpret the offset 606647f50c3SDoug Rabson * cookie here. 607647f50c3SDoug Rabson */ 608647f50c3SDoug Rabson printf(" %lu bytes @ ", ntohl(dp[4])); 609647f50c3SDoug Rabson print_int64(dp, SIGNED); 610647f50c3SDoug Rabson if (vflag) 6112ebf6c05SBill Fenner printf(" max %lu verf %08x%08x", 612647f50c3SDoug Rabson ntohl(dp[5]), dp[2], dp[3]); 613647f50c3SDoug Rabson return; 614647f50c3SDoug Rabson } 615647f50c3SDoug Rabson break; 616647f50c3SDoug Rabson 617647f50c3SDoug Rabson case NFSPROC_FSSTAT: 618647f50c3SDoug Rabson printf(" fsstat"); 6192ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) 6204edb46e9SPaul Traina return; 6214edb46e9SPaul Traina break; 6224edb46e9SPaul Traina 623647f50c3SDoug Rabson case NFSPROC_FSINFO: 624647f50c3SDoug Rabson printf(" fsinfo"); 625647f50c3SDoug Rabson break; 626647f50c3SDoug Rabson 627647f50c3SDoug Rabson case NFSPROC_PATHCONF: 628647f50c3SDoug Rabson printf(" pathconf"); 629647f50c3SDoug Rabson break; 630647f50c3SDoug Rabson 631647f50c3SDoug Rabson case NFSPROC_COMMIT: 632647f50c3SDoug Rabson printf(" commit"); 6332ebf6c05SBill Fenner if ((dp = parsereq(rp, length)) != NULL && 6342ebf6c05SBill Fenner (dp = parsefh(dp, v3)) != NULL) { 635647f50c3SDoug Rabson printf(" %lu bytes @ ", ntohl(dp[2])); 636647f50c3SDoug Rabson print_int64(dp, UNSIGNED); 637647f50c3SDoug Rabson return; 638647f50c3SDoug Rabson } 639647f50c3SDoug Rabson break; 640647f50c3SDoug Rabson 6414edb46e9SPaul Traina default: 642647f50c3SDoug Rabson printf(" proc-%lu", ntohl(rp->rm_call.cb_proc)); 6434edb46e9SPaul Traina return; 6444edb46e9SPaul Traina } 6454edb46e9SPaul Traina trunc: 6462ebf6c05SBill Fenner if (!nfserr) 6474edb46e9SPaul Traina fputs(" [|nfs]", stdout); 6484edb46e9SPaul Traina } 6494edb46e9SPaul Traina 6504edb46e9SPaul Traina /* 6514edb46e9SPaul Traina * Print out an NFS file handle. 6524edb46e9SPaul Traina * We assume packet was not truncated before the end of the 6534edb46e9SPaul Traina * file handle pointed to by dp. 6544edb46e9SPaul Traina * 6554edb46e9SPaul Traina * Note: new version (using portable file-handle parser) doesn't produce 6564edb46e9SPaul Traina * generation number. It probably could be made to do that, with some 6574edb46e9SPaul Traina * additional hacking on the parser code. 6584edb46e9SPaul Traina */ 6594edb46e9SPaul Traina static void 660647f50c3SDoug Rabson nfs_printfh(register const u_int32_t *dp, const int len) 6614edb46e9SPaul Traina { 6624edb46e9SPaul Traina my_fsid fsid; 6634edb46e9SPaul Traina ino_t ino; 6644edb46e9SPaul Traina char *sfsname = NULL; 6654edb46e9SPaul Traina 666647f50c3SDoug Rabson Parse_fh((caddr_t *)dp, len, &fsid, &ino, NULL, &sfsname, 0); 6674edb46e9SPaul Traina 6684edb46e9SPaul Traina if (sfsname) { 6694edb46e9SPaul Traina /* file system ID is ASCII, not numeric, for this server OS */ 670647f50c3SDoug Rabson static char temp[NFSX_V3FHMAX+1]; 6714edb46e9SPaul Traina 6724edb46e9SPaul Traina /* Make sure string is null-terminated */ 673647f50c3SDoug Rabson strncpy(temp, sfsname, NFSX_V3FHMAX); 6744edb46e9SPaul Traina /* Remove trailing spaces */ 6754edb46e9SPaul Traina sfsname = strchr(temp, ' '); 6764edb46e9SPaul Traina if (sfsname) 6774edb46e9SPaul Traina *sfsname = 0; 6784edb46e9SPaul Traina 6794edb46e9SPaul Traina (void)printf(" fh %s/%u", temp, (u_int32_t)ino); 6802ebf6c05SBill Fenner } else { 6814edb46e9SPaul Traina (void)printf(" fh %u,%u/%u", 6822ebf6c05SBill Fenner fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor, (u_int32_t)ino); 6834edb46e9SPaul Traina } 6844edb46e9SPaul Traina } 6854edb46e9SPaul Traina 6864edb46e9SPaul Traina /* 6874edb46e9SPaul Traina * Maintain a small cache of recent client.XID.server/proc pairs, to allow 6884edb46e9SPaul Traina * us to match up replies with requests and thus to know how to parse 6894edb46e9SPaul Traina * the reply. 6904edb46e9SPaul Traina */ 6914edb46e9SPaul Traina 6924edb46e9SPaul Traina struct xid_map_entry { 6934edb46e9SPaul Traina u_int32_t xid; /* transaction ID (net order) */ 6944edb46e9SPaul Traina struct in_addr client; /* client IP address (net order) */ 6954edb46e9SPaul Traina struct in_addr server; /* server IP address (net order) */ 6964edb46e9SPaul Traina u_int32_t proc; /* call proc number (host order) */ 697647f50c3SDoug Rabson u_int32_t vers; /* program version (host order) */ 6984edb46e9SPaul Traina }; 6994edb46e9SPaul Traina 7004edb46e9SPaul Traina /* 7014edb46e9SPaul Traina * Map entries are kept in an array that we manage as a ring; 7024edb46e9SPaul Traina * new entries are always added at the tail of the ring. Initially, 7034edb46e9SPaul Traina * all the entries are zero and hence don't match anything. 7044edb46e9SPaul Traina */ 7054edb46e9SPaul Traina 7064edb46e9SPaul Traina #define XIDMAPSIZE 64 7074edb46e9SPaul Traina 7084edb46e9SPaul Traina struct xid_map_entry xid_map[XIDMAPSIZE]; 7094edb46e9SPaul Traina 7104edb46e9SPaul Traina int xid_map_next = 0; 7114edb46e9SPaul Traina int xid_map_hint = 0; 7124edb46e9SPaul Traina 7134edb46e9SPaul Traina static void 7144edb46e9SPaul Traina xid_map_enter(const struct rpc_msg *rp, const struct ip *ip) 7154edb46e9SPaul Traina { 7164edb46e9SPaul Traina struct xid_map_entry *xmep; 7174edb46e9SPaul Traina 7184edb46e9SPaul Traina xmep = &xid_map[xid_map_next]; 7194edb46e9SPaul Traina 7204edb46e9SPaul Traina if (++xid_map_next >= XIDMAPSIZE) 7214edb46e9SPaul Traina xid_map_next = 0; 7224edb46e9SPaul Traina 7234edb46e9SPaul Traina xmep->xid = rp->rm_xid; 7244edb46e9SPaul Traina xmep->client = ip->ip_src; 7254edb46e9SPaul Traina xmep->server = ip->ip_dst; 7264edb46e9SPaul Traina xmep->proc = ntohl(rp->rm_call.cb_proc); 727647f50c3SDoug Rabson xmep->vers = ntohl(rp->rm_call.cb_vers); 7284edb46e9SPaul Traina } 7294edb46e9SPaul Traina 7302ebf6c05SBill Fenner /* 7312ebf6c05SBill Fenner * Returns 0 and puts NFSPROC_xxx in proc return and 7322ebf6c05SBill Fenner * version in vers return, or returns -1 on failure 7332ebf6c05SBill Fenner */ 734647f50c3SDoug Rabson static int 735647f50c3SDoug Rabson xid_map_find(const struct rpc_msg *rp, const struct ip *ip, u_int32_t *proc, 736647f50c3SDoug Rabson u_int32_t *vers) 7374edb46e9SPaul Traina { 7384edb46e9SPaul Traina int i; 7394edb46e9SPaul Traina struct xid_map_entry *xmep; 7404edb46e9SPaul Traina u_int32_t xid = rp->rm_xid; 7414edb46e9SPaul Traina u_int32_t clip = ip->ip_dst.s_addr; 7424edb46e9SPaul Traina u_int32_t sip = ip->ip_src.s_addr; 7434edb46e9SPaul Traina 7444edb46e9SPaul Traina /* Start searching from where we last left off */ 7454edb46e9SPaul Traina i = xid_map_hint; 7464edb46e9SPaul Traina do { 7474edb46e9SPaul Traina xmep = &xid_map[i]; 7484edb46e9SPaul Traina if (xmep->xid == xid && xmep->client.s_addr == clip && 7494edb46e9SPaul Traina xmep->server.s_addr == sip) { 7504edb46e9SPaul Traina /* match */ 7514edb46e9SPaul Traina xid_map_hint = i; 752647f50c3SDoug Rabson *proc = xmep->proc; 753647f50c3SDoug Rabson *vers = xmep->vers; 754647f50c3SDoug Rabson return 0; 7554edb46e9SPaul Traina } 7564edb46e9SPaul Traina if (++i >= XIDMAPSIZE) 7574edb46e9SPaul Traina i = 0; 7584edb46e9SPaul Traina } while (i != xid_map_hint); 7594edb46e9SPaul Traina 7604edb46e9SPaul Traina /* search failed */ 761699fc314SBill Fenner return (0); 7624edb46e9SPaul Traina } 7634edb46e9SPaul Traina 7644edb46e9SPaul Traina /* 7654edb46e9SPaul Traina * Routines for parsing reply packets 7664edb46e9SPaul Traina */ 7674edb46e9SPaul Traina 7684edb46e9SPaul Traina /* 7694edb46e9SPaul Traina * Return a pointer to the beginning of the actual results. 7702ebf6c05SBill Fenner * If the packet was truncated, return NULL. 7714edb46e9SPaul Traina */ 7724edb46e9SPaul Traina static const u_int32_t * 773647f50c3SDoug Rabson parserep(register const struct rpc_msg *rp, register int length) 7744edb46e9SPaul Traina { 7754edb46e9SPaul Traina register const u_int32_t *dp; 776647f50c3SDoug Rabson int len; 7774edb46e9SPaul Traina enum accept_stat astat; 7784edb46e9SPaul Traina 7794edb46e9SPaul Traina /* 7804edb46e9SPaul Traina * Portability note: 7814edb46e9SPaul Traina * Here we find the address of the ar_verf credentials. 7824edb46e9SPaul Traina * Originally, this calculation was 7834edb46e9SPaul Traina * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf 7844edb46e9SPaul Traina * On the wire, the rp_acpt field starts immediately after 7854edb46e9SPaul Traina * the (32 bit) rp_stat field. However, rp_acpt (which is a 7864edb46e9SPaul Traina * "struct accepted_reply") contains a "struct opaque_auth", 7874edb46e9SPaul Traina * whose internal representation contains a pointer, so on a 7884edb46e9SPaul Traina * 64-bit machine the compiler inserts 32 bits of padding 7894edb46e9SPaul Traina * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use 7904edb46e9SPaul Traina * the internal representation to parse the on-the-wire 7914edb46e9SPaul Traina * representation. Instead, we skip past the rp_stat field, 7924edb46e9SPaul Traina * which is an "enum" and so occupies one 32-bit word. 7934edb46e9SPaul Traina */ 7944edb46e9SPaul Traina dp = ((const u_int32_t *)&rp->rm_reply) + 1; 7952ebf6c05SBill Fenner TCHECK2(dp[0], 1); 7964edb46e9SPaul Traina len = ntohl(dp[1]); 7974edb46e9SPaul Traina if (len >= length) 7982ebf6c05SBill Fenner return (NULL); 7994edb46e9SPaul Traina /* 8004edb46e9SPaul Traina * skip past the ar_verf credentials. 8014edb46e9SPaul Traina */ 8024edb46e9SPaul Traina dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t); 8032ebf6c05SBill Fenner TCHECK2(dp[0], 0); 8044edb46e9SPaul Traina 8054edb46e9SPaul Traina /* 8064edb46e9SPaul Traina * now we can check the ar_stat field 8074edb46e9SPaul Traina */ 8084edb46e9SPaul Traina astat = ntohl(*(enum accept_stat *)dp); 8094edb46e9SPaul Traina switch (astat) { 8104edb46e9SPaul Traina 8114edb46e9SPaul Traina case SUCCESS: 8124edb46e9SPaul Traina break; 8134edb46e9SPaul Traina 8144edb46e9SPaul Traina case PROG_UNAVAIL: 8154edb46e9SPaul Traina printf(" PROG_UNAVAIL"); 8162ebf6c05SBill Fenner nfserr = 1; /* suppress trunc string */ 8172ebf6c05SBill Fenner return (NULL); 8184edb46e9SPaul Traina 8194edb46e9SPaul Traina case PROG_MISMATCH: 8204edb46e9SPaul Traina printf(" PROG_MISMATCH"); 8212ebf6c05SBill Fenner nfserr = 1; /* suppress trunc string */ 8222ebf6c05SBill Fenner return (NULL); 8234edb46e9SPaul Traina 8244edb46e9SPaul Traina case PROC_UNAVAIL: 8254edb46e9SPaul Traina printf(" PROC_UNAVAIL"); 8262ebf6c05SBill Fenner nfserr = 1; /* suppress trunc string */ 8272ebf6c05SBill Fenner return (NULL); 8284edb46e9SPaul Traina 8294edb46e9SPaul Traina case GARBAGE_ARGS: 8304edb46e9SPaul Traina printf(" GARBAGE_ARGS"); 8312ebf6c05SBill Fenner nfserr = 1; /* suppress trunc string */ 8322ebf6c05SBill Fenner return (NULL); 8334edb46e9SPaul Traina 8344edb46e9SPaul Traina case SYSTEM_ERR: 8354edb46e9SPaul Traina printf(" SYSTEM_ERR"); 8362ebf6c05SBill Fenner nfserr = 1; /* suppress trunc string */ 8372ebf6c05SBill Fenner return (NULL); 8384edb46e9SPaul Traina 8394edb46e9SPaul Traina default: 8404edb46e9SPaul Traina printf(" ar_stat %d", astat); 8412ebf6c05SBill Fenner nfserr = 1; /* suppress trunc string */ 8422ebf6c05SBill Fenner return (NULL); 8434edb46e9SPaul Traina } 8444edb46e9SPaul Traina /* successful return */ 8452ebf6c05SBill Fenner if ((sizeof(astat) + ((u_char *)dp)) < snapend) 8464edb46e9SPaul Traina return ((u_int32_t *) (sizeof(astat) + ((char *)dp))); 8474edb46e9SPaul Traina 8482ebf6c05SBill Fenner trunc: 8492ebf6c05SBill Fenner return (NULL); 8504edb46e9SPaul Traina } 8514edb46e9SPaul Traina 8524edb46e9SPaul Traina 853647f50c3SDoug Rabson static const u_int32_t * 854647f50c3SDoug Rabson parsestatus(const u_int32_t *dp, int *er) 855647f50c3SDoug Rabson { 8562ebf6c05SBill Fenner register int errnum; 857647f50c3SDoug Rabson 8582ebf6c05SBill Fenner TCHECK(dp[0]); 8592ebf6c05SBill Fenner errnum = ntohl(dp[0]); 860647f50c3SDoug Rabson if (er) 8612ebf6c05SBill Fenner *er = errnum; 8622ebf6c05SBill Fenner if (errnum != 0) { 8632ebf6c05SBill Fenner if (!qflag) 8642ebf6c05SBill Fenner printf(" ERROR: %s", pcap_strerror(errnum)); 8652ebf6c05SBill Fenner nfserr = 1; 8662ebf6c05SBill Fenner return (NULL); 8674edb46e9SPaul Traina } 8684edb46e9SPaul Traina return (dp + 1); 8692ebf6c05SBill Fenner trunc: 8702ebf6c05SBill Fenner return (NULL); 8714edb46e9SPaul Traina } 8724edb46e9SPaul Traina 8734edb46e9SPaul Traina static const u_int32_t * 874647f50c3SDoug Rabson parsefattr(const u_int32_t *dp, int verbose, int v3) 8754edb46e9SPaul Traina { 876647f50c3SDoug Rabson const struct nfs_fattr *fap; 8774edb46e9SPaul Traina 878647f50c3SDoug Rabson fap = (const struct nfs_fattr *)dp; 879685b49deSBill Fenner TCHECK(fap->fa_gid); 8804edb46e9SPaul Traina if (verbose) { 8812ebf6c05SBill Fenner printf(" %s %lo ids %ld/%ld", 882647f50c3SDoug Rabson tok2str(type2str, "unk-ft %d ", ntohl(fap->fa_type)), 883647f50c3SDoug Rabson ntohl(fap->fa_mode), ntohl(fap->fa_uid), 884647f50c3SDoug Rabson ntohl(fap->fa_gid)); 885647f50c3SDoug Rabson if (v3) { 886685b49deSBill Fenner TCHECK(fap->fa3_size); 887647f50c3SDoug Rabson printf(" sz "); 888647f50c3SDoug Rabson print_int64((u_int32_t *)&fap->fa3_size, UNSIGNED); 889647f50c3SDoug Rabson putchar(' '); 890685b49deSBill Fenner } else { 891685b49deSBill Fenner TCHECK(fap->fa2_size); 8922ebf6c05SBill Fenner printf(" sz %ld ", ntohl(fap->fa2_size)); 893647f50c3SDoug Rabson } 8944edb46e9SPaul Traina } 8954edb46e9SPaul Traina /* print lots more stuff */ 8964edb46e9SPaul Traina if (verbose > 1) { 897647f50c3SDoug Rabson if (v3) { 898685b49deSBill Fenner TCHECK(fap->fa3_ctime); 8992ebf6c05SBill Fenner printf("nlink %ld rdev %ld/%ld ", 900647f50c3SDoug Rabson ntohl(fap->fa_nlink), 901647f50c3SDoug Rabson ntohl(fap->fa3_rdev.specdata1), 902647f50c3SDoug Rabson ntohl(fap->fa3_rdev.specdata2)); 903647f50c3SDoug Rabson printf("fsid "); 904647f50c3SDoug Rabson print_int64((u_int32_t *)&fap->fa2_fsid, HEX); 905647f50c3SDoug Rabson printf(" nodeid "); 906647f50c3SDoug Rabson print_int64((u_int32_t *)&fap->fa2_fileid, HEX); 9072ebf6c05SBill Fenner printf(" a/m/ctime %lu.%06lu ", 908647f50c3SDoug Rabson ntohl(fap->fa3_atime.nfsv3_sec), 909647f50c3SDoug Rabson ntohl(fap->fa3_atime.nfsv3_nsec)); 9102ebf6c05SBill Fenner printf("%lu.%06lu ", 911647f50c3SDoug Rabson ntohl(fap->fa3_mtime.nfsv3_sec), 912647f50c3SDoug Rabson ntohl(fap->fa3_mtime.nfsv3_nsec)); 9132ebf6c05SBill Fenner printf("%lu.%06lu ", 914647f50c3SDoug Rabson ntohl(fap->fa3_ctime.nfsv3_sec), 915647f50c3SDoug Rabson ntohl(fap->fa3_ctime.nfsv3_nsec)); 916647f50c3SDoug Rabson } else { 917685b49deSBill Fenner TCHECK(fap->fa2_ctime); 9182ebf6c05SBill Fenner printf("nlink %ld rdev %lx fsid %lx nodeid %lx a/m/ctime ", 919647f50c3SDoug Rabson ntohl(fap->fa_nlink), ntohl(fap->fa2_rdev), 920647f50c3SDoug Rabson ntohl(fap->fa2_fsid), ntohl(fap->fa2_fileid)); 9212ebf6c05SBill Fenner printf("%lu.%06lu ", 922647f50c3SDoug Rabson ntohl(fap->fa2_atime.nfsv2_sec), 923647f50c3SDoug Rabson ntohl(fap->fa2_atime.nfsv2_usec)); 9242ebf6c05SBill Fenner printf("%lu.%06lu ", 925647f50c3SDoug Rabson ntohl(fap->fa2_mtime.nfsv2_sec), 926647f50c3SDoug Rabson ntohl(fap->fa2_mtime.nfsv2_usec)); 9272ebf6c05SBill Fenner printf("%lu.%06lu ", 928647f50c3SDoug Rabson ntohl(fap->fa2_ctime.nfsv2_sec), 929647f50c3SDoug Rabson ntohl(fap->fa2_ctime.nfsv2_usec)); 9304edb46e9SPaul Traina } 931647f50c3SDoug Rabson } 932647f50c3SDoug Rabson return ((const u_int32_t *)((unsigned char *)dp + 933647f50c3SDoug Rabson (v3 ? NFSX_V3FATTR : NFSX_V2FATTR))); 934685b49deSBill Fenner trunc: 935685b49deSBill Fenner return (NULL); 9364edb46e9SPaul Traina } 9374edb46e9SPaul Traina 9384edb46e9SPaul Traina static int 939647f50c3SDoug Rabson parseattrstat(const u_int32_t *dp, int verbose, int v3) 9404edb46e9SPaul Traina { 941647f50c3SDoug Rabson int er; 942647f50c3SDoug Rabson 943647f50c3SDoug Rabson dp = parsestatus(dp, &er); 944647f50c3SDoug Rabson if (dp == NULL || er) 9454edb46e9SPaul Traina return (0); 9464edb46e9SPaul Traina 9472ebf6c05SBill Fenner return (parsefattr(dp, verbose, v3) != NULL); 9484edb46e9SPaul Traina } 9494edb46e9SPaul Traina 9504edb46e9SPaul Traina static int 9514edb46e9SPaul Traina parsediropres(const u_int32_t *dp) 9524edb46e9SPaul Traina { 953647f50c3SDoug Rabson int er; 954647f50c3SDoug Rabson 9552ebf6c05SBill Fenner dp = parsestatus(dp, &er); 9562ebf6c05SBill Fenner if (dp == NULL || er) 957647f50c3SDoug Rabson return (0); 958647f50c3SDoug Rabson 959647f50c3SDoug Rabson dp = parsefh(dp, 0); 9604edb46e9SPaul Traina if (dp == NULL) 9614edb46e9SPaul Traina return (0); 9624edb46e9SPaul Traina 963647f50c3SDoug Rabson return (parsefattr(dp, vflag, 0) != NULL); 9644edb46e9SPaul Traina } 9654edb46e9SPaul Traina 9664edb46e9SPaul Traina static int 967647f50c3SDoug Rabson parselinkres(const u_int32_t *dp, int v3) 9684edb46e9SPaul Traina { 969647f50c3SDoug Rabson int er; 9704edb46e9SPaul Traina 971647f50c3SDoug Rabson dp = parsestatus(dp, &er); 972647f50c3SDoug Rabson if (dp == NULL || er) 973647f50c3SDoug Rabson return(0); 9742ebf6c05SBill Fenner 9752ebf6c05SBill Fenner if (v3 && ((dp = parse_post_op_attr(dp, vflag)) != NULL)) 976647f50c3SDoug Rabson return (0); 9772ebf6c05SBill Fenner 9784edb46e9SPaul Traina putchar(' '); 9794edb46e9SPaul Traina return (parsefn(dp) != NULL); 9804edb46e9SPaul Traina } 9814edb46e9SPaul Traina 9824edb46e9SPaul Traina static int 983647f50c3SDoug Rabson parsestatfs(const u_int32_t *dp, int v3) 9844edb46e9SPaul Traina { 985647f50c3SDoug Rabson const struct nfs_statfs *sfsp; 986647f50c3SDoug Rabson int er; 9874edb46e9SPaul Traina 988647f50c3SDoug Rabson dp = parsestatus(dp, &er); 989647f50c3SDoug Rabson if (dp == NULL || (!v3 && er)) 9904edb46e9SPaul Traina return(0); 9914edb46e9SPaul Traina 992647f50c3SDoug Rabson if (qflag) 993647f50c3SDoug Rabson return(1); 994647f50c3SDoug Rabson 995647f50c3SDoug Rabson if (v3) { 996647f50c3SDoug Rabson if (vflag) 997647f50c3SDoug Rabson printf(" POST:"); 9982ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 999647f50c3SDoug Rabson return (0); 1000647f50c3SDoug Rabson } 1001647f50c3SDoug Rabson 1002685b49deSBill Fenner TCHECK2(dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS)); 1003647f50c3SDoug Rabson 1004647f50c3SDoug Rabson sfsp = (const struct nfs_statfs *)dp; 1005647f50c3SDoug Rabson 1006647f50c3SDoug Rabson if (v3) { 1007647f50c3SDoug Rabson printf(" tbytes "); 1008647f50c3SDoug Rabson print_int64((u_int32_t *)&sfsp->sf_tbytes, UNSIGNED); 1009647f50c3SDoug Rabson printf(" fbytes "); 1010647f50c3SDoug Rabson print_int64((u_int32_t *)&sfsp->sf_fbytes, UNSIGNED); 1011647f50c3SDoug Rabson printf(" abytes "); 1012647f50c3SDoug Rabson print_int64((u_int32_t *)&sfsp->sf_abytes, UNSIGNED); 1013647f50c3SDoug Rabson if (vflag) { 1014647f50c3SDoug Rabson printf(" tfiles "); 1015647f50c3SDoug Rabson print_int64((u_int32_t *)&sfsp->sf_tfiles, UNSIGNED); 1016647f50c3SDoug Rabson printf(" ffiles "); 1017647f50c3SDoug Rabson print_int64((u_int32_t *)&sfsp->sf_ffiles, UNSIGNED); 1018647f50c3SDoug Rabson printf(" afiles "); 1019647f50c3SDoug Rabson print_int64((u_int32_t *)&sfsp->sf_afiles, UNSIGNED); 1020647f50c3SDoug Rabson printf(" invar %lu", ntohl(sfsp->sf_invarsec)); 1021647f50c3SDoug Rabson } 1022647f50c3SDoug Rabson } else { 10232ebf6c05SBill Fenner printf(" tsize %ld bsize %ld blocks %ld bfree %ld bavail %ld", 1024647f50c3SDoug Rabson ntohl(sfsp->sf_tsize), ntohl(sfsp->sf_bsize), 1025647f50c3SDoug Rabson ntohl(sfsp->sf_blocks), ntohl(sfsp->sf_bfree), 1026647f50c3SDoug Rabson ntohl(sfsp->sf_bavail)); 10274edb46e9SPaul Traina } 10284edb46e9SPaul Traina 10294edb46e9SPaul Traina return (1); 1030685b49deSBill Fenner trunc: 1031685b49deSBill Fenner return (0); 10324edb46e9SPaul Traina } 10334edb46e9SPaul Traina 10344edb46e9SPaul Traina static int 10354edb46e9SPaul Traina parserddires(const u_int32_t *dp) 10364edb46e9SPaul Traina { 1037647f50c3SDoug Rabson int er; 1038647f50c3SDoug Rabson 1039647f50c3SDoug Rabson dp = parsestatus(dp, &er); 10402ebf6c05SBill Fenner if (dp == NULL || er) 10414edb46e9SPaul Traina return (0); 1042647f50c3SDoug Rabson if (qflag) 1043647f50c3SDoug Rabson return (1); 1044647f50c3SDoug Rabson 1045685b49deSBill Fenner TCHECK(dp[2]); 10462ebf6c05SBill Fenner printf(" offset %lx size %ld ", ntohl(dp[0]), ntohl(dp[1])); 10474edb46e9SPaul Traina if (dp[2] != 0) 10484edb46e9SPaul Traina printf("eof"); 10494edb46e9SPaul Traina 10504edb46e9SPaul Traina return (1); 1051685b49deSBill Fenner trunc: 1052685b49deSBill Fenner return (0); 1053647f50c3SDoug Rabson } 1054647f50c3SDoug Rabson 1055647f50c3SDoug Rabson static const u_int32_t * 1056647f50c3SDoug Rabson parse_wcc_attr(const u_int32_t *dp) 1057647f50c3SDoug Rabson { 1058647f50c3SDoug Rabson printf(" sz "); 1059647f50c3SDoug Rabson print_int64(dp, UNSIGNED); 10602ebf6c05SBill Fenner printf(" mtime %lu.%06lu ctime %lu.%06lu", ntohl(dp[2]), ntohl(dp[3]), 1061647f50c3SDoug Rabson ntohl(dp[4]), ntohl(dp[5])); 1062647f50c3SDoug Rabson return (dp + 6); 1063647f50c3SDoug Rabson } 1064647f50c3SDoug Rabson 1065647f50c3SDoug Rabson /* 1066647f50c3SDoug Rabson * Pre operation attributes. Print only if vflag > 1. 1067647f50c3SDoug Rabson */ 1068647f50c3SDoug Rabson static const u_int32_t * 1069647f50c3SDoug Rabson parse_pre_op_attr(const u_int32_t *dp, int verbose) 1070647f50c3SDoug Rabson { 1071685b49deSBill Fenner TCHECK(dp[0]); 1072647f50c3SDoug Rabson if (!ntohl(dp[0])) 1073647f50c3SDoug Rabson return (dp + 1); 1074647f50c3SDoug Rabson dp++; 1075685b49deSBill Fenner TCHECK2(dp, 24); 1076647f50c3SDoug Rabson if (verbose > 1) { 1077647f50c3SDoug Rabson return parse_wcc_attr(dp); 1078647f50c3SDoug Rabson } else { 1079647f50c3SDoug Rabson /* If not verbose enough, just skip over wcc_attr */ 1080647f50c3SDoug Rabson return (dp + 6); 1081647f50c3SDoug Rabson } 1082685b49deSBill Fenner trunc: 1083685b49deSBill Fenner return (NULL); 1084647f50c3SDoug Rabson } 1085647f50c3SDoug Rabson 1086647f50c3SDoug Rabson /* 1087647f50c3SDoug Rabson * Post operation attributes are printed if vflag >= 1 1088647f50c3SDoug Rabson */ 1089647f50c3SDoug Rabson static const u_int32_t * 1090647f50c3SDoug Rabson parse_post_op_attr(const u_int32_t *dp, int verbose) 1091647f50c3SDoug Rabson { 1092685b49deSBill Fenner TCHECK(dp[0]); 1093647f50c3SDoug Rabson if (!ntohl(dp[0])) 1094647f50c3SDoug Rabson return (dp + 1); 1095647f50c3SDoug Rabson dp++; 1096647f50c3SDoug Rabson if (verbose) { 1097647f50c3SDoug Rabson return parsefattr(dp, verbose, 1); 1098647f50c3SDoug Rabson } else 1099647f50c3SDoug Rabson return (dp + (NFSX_V3FATTR / sizeof (u_int32_t))); 1100685b49deSBill Fenner trunc: 1101685b49deSBill Fenner return (NULL); 1102647f50c3SDoug Rabson } 1103647f50c3SDoug Rabson 1104647f50c3SDoug Rabson static const u_int32_t * 1105647f50c3SDoug Rabson parse_wcc_data(const u_int32_t *dp, int verbose) 1106647f50c3SDoug Rabson { 1107647f50c3SDoug Rabson if (verbose > 1) 1108647f50c3SDoug Rabson printf(" PRE:"); 11092ebf6c05SBill Fenner if ((dp = parse_pre_op_attr(dp, verbose)) == NULL) 11102ebf6c05SBill Fenner return (NULL); 1111647f50c3SDoug Rabson 1112647f50c3SDoug Rabson if (verbose) 1113647f50c3SDoug Rabson printf(" POST:"); 1114647f50c3SDoug Rabson return parse_post_op_attr(dp, verbose); 1115647f50c3SDoug Rabson } 1116647f50c3SDoug Rabson 1117647f50c3SDoug Rabson static const u_int32_t * 1118647f50c3SDoug Rabson parsecreateopres(const u_int32_t *dp, int verbose) 1119647f50c3SDoug Rabson { 1120647f50c3SDoug Rabson int er; 1121647f50c3SDoug Rabson 11222ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 11232ebf6c05SBill Fenner return (NULL); 1124647f50c3SDoug Rabson if (er) 1125647f50c3SDoug Rabson dp = parse_wcc_data(dp, verbose); 1126647f50c3SDoug Rabson else { 1127685b49deSBill Fenner TCHECK(dp[0]); 1128647f50c3SDoug Rabson if (!ntohl(dp[0])) 1129647f50c3SDoug Rabson return (dp + 1); 1130647f50c3SDoug Rabson dp++; 11312ebf6c05SBill Fenner if ((dp = parsefh(dp, 1)) == NULL) 11322ebf6c05SBill Fenner return (NULL); 1133647f50c3SDoug Rabson if (verbose) { 11342ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, verbose)) == NULL) 11352ebf6c05SBill Fenner return (NULL); 1136647f50c3SDoug Rabson if (vflag > 1) { 1137647f50c3SDoug Rabson printf("dir attr:"); 1138647f50c3SDoug Rabson dp = parse_wcc_data(dp, verbose); 1139647f50c3SDoug Rabson } 1140647f50c3SDoug Rabson } 1141647f50c3SDoug Rabson } 1142647f50c3SDoug Rabson return (dp); 1143685b49deSBill Fenner trunc: 1144685b49deSBill Fenner return (NULL); 1145647f50c3SDoug Rabson } 1146647f50c3SDoug Rabson 1147647f50c3SDoug Rabson static int 1148647f50c3SDoug Rabson parsewccres(const u_int32_t *dp, int verbose) 1149647f50c3SDoug Rabson { 1150647f50c3SDoug Rabson int er; 1151647f50c3SDoug Rabson 11522ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1153647f50c3SDoug Rabson return (0); 11542ebf6c05SBill Fenner return parse_wcc_data(dp, verbose) != NULL; 1155647f50c3SDoug Rabson } 1156647f50c3SDoug Rabson 1157647f50c3SDoug Rabson static const u_int32_t * 1158647f50c3SDoug Rabson parsev3rddirres(const u_int32_t *dp, int verbose) 1159647f50c3SDoug Rabson { 1160647f50c3SDoug Rabson int er; 1161647f50c3SDoug Rabson 11622ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 11632ebf6c05SBill Fenner return (NULL); 1164647f50c3SDoug Rabson if (vflag) 1165647f50c3SDoug Rabson printf(" POST:"); 11662ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, verbose)) == NULL) 11672ebf6c05SBill Fenner return (NULL); 1168647f50c3SDoug Rabson if (er) 1169647f50c3SDoug Rabson return dp; 1170647f50c3SDoug Rabson if (vflag) { 1171685b49deSBill Fenner TCHECK(dp[1]); 11722ebf6c05SBill Fenner printf(" verf %08x%08x", dp[0], dp[1]); 1173647f50c3SDoug Rabson dp += 2; 1174647f50c3SDoug Rabson } 1175647f50c3SDoug Rabson return dp; 1176685b49deSBill Fenner trunc: 1177685b49deSBill Fenner return (NULL); 1178647f50c3SDoug Rabson } 1179647f50c3SDoug Rabson 1180647f50c3SDoug Rabson static int 1181647f50c3SDoug Rabson parsefsinfo(const u_int32_t *dp) 1182647f50c3SDoug Rabson { 1183647f50c3SDoug Rabson struct nfsv3_fsinfo *sfp; 1184647f50c3SDoug Rabson int er; 1185647f50c3SDoug Rabson 11862ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1187647f50c3SDoug Rabson return (0); 1188647f50c3SDoug Rabson if (vflag) 1189647f50c3SDoug Rabson printf(" POST:"); 11902ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1191647f50c3SDoug Rabson return (0); 1192647f50c3SDoug Rabson if (er) 1193647f50c3SDoug Rabson return (1); 1194647f50c3SDoug Rabson 1195647f50c3SDoug Rabson sfp = (struct nfsv3_fsinfo *)dp; 1196685b49deSBill Fenner TCHECK(*sfp); 1197647f50c3SDoug Rabson printf(" rtmax %lu rtpref %lu wtmax %lu wtpref %lu dtpref %lu", 1198647f50c3SDoug Rabson ntohl(sfp->fs_rtmax), ntohl(sfp->fs_rtpref), 1199647f50c3SDoug Rabson ntohl(sfp->fs_wtmax), ntohl(sfp->fs_wtpref), 1200647f50c3SDoug Rabson ntohl(sfp->fs_dtpref)); 1201647f50c3SDoug Rabson if (vflag) { 1202647f50c3SDoug Rabson printf(" rtmult %lu wtmult %lu maxfsz ", 1203647f50c3SDoug Rabson ntohl(sfp->fs_rtmult), ntohl(sfp->fs_wtmult)); 1204647f50c3SDoug Rabson print_int64((u_int32_t *)&sfp->fs_maxfilesize, UNSIGNED); 12052ebf6c05SBill Fenner printf(" delta %lu.%06lu ", ntohl(sfp->fs_timedelta.nfsv3_sec), 1206647f50c3SDoug Rabson ntohl(sfp->fs_timedelta.nfsv3_nsec)); 1207647f50c3SDoug Rabson } 1208647f50c3SDoug Rabson return (1); 1209685b49deSBill Fenner trunc: 1210685b49deSBill Fenner return (0); 1211647f50c3SDoug Rabson } 1212647f50c3SDoug Rabson 1213647f50c3SDoug Rabson static int 1214647f50c3SDoug Rabson parsepathconf(const u_int32_t *dp) 1215647f50c3SDoug Rabson { 1216647f50c3SDoug Rabson int er; 1217647f50c3SDoug Rabson struct nfsv3_pathconf *spp; 1218647f50c3SDoug Rabson 12192ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1220647f50c3SDoug Rabson return (0); 1221647f50c3SDoug Rabson if (vflag) 1222647f50c3SDoug Rabson printf(" POST:"); 12232ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1224647f50c3SDoug Rabson return (0); 1225647f50c3SDoug Rabson if (er) 1226647f50c3SDoug Rabson return (1); 1227647f50c3SDoug Rabson 1228647f50c3SDoug Rabson spp = (struct nfsv3_pathconf *)dp; 1229685b49deSBill Fenner TCHECK(*spp); 1230647f50c3SDoug Rabson 1231647f50c3SDoug Rabson printf(" linkmax %lu namemax %lu %s %s %s %s", 1232647f50c3SDoug Rabson ntohl(spp->pc_linkmax), 1233647f50c3SDoug Rabson ntohl(spp->pc_namemax), 1234647f50c3SDoug Rabson ntohl(spp->pc_notrunc) ? "notrunc" : "", 1235647f50c3SDoug Rabson ntohl(spp->pc_chownrestricted) ? "chownres" : "", 1236647f50c3SDoug Rabson ntohl(spp->pc_caseinsensitive) ? "igncase" : "", 1237647f50c3SDoug Rabson ntohl(spp->pc_casepreserving) ? "keepcase" : ""); 1238685b49deSBill Fenner return (1); 1239685b49deSBill Fenner trunc: 12404edb46e9SPaul Traina return (0); 12414edb46e9SPaul Traina } 12424edb46e9SPaul Traina 12434edb46e9SPaul Traina static void 1244647f50c3SDoug Rabson interp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int32_t vers, int length) 12454edb46e9SPaul Traina { 12464edb46e9SPaul Traina register const u_int32_t *dp; 1247647f50c3SDoug Rabson register int v3; 12482ebf6c05SBill Fenner 1249647f50c3SDoug Rabson int er; 1250647f50c3SDoug Rabson 1251647f50c3SDoug Rabson v3 = (vers == NFS_VER3); 1252647f50c3SDoug Rabson 1253647f50c3SDoug Rabson if (!v3 && proc < NFS_NPROCS) 1254647f50c3SDoug Rabson proc = nfsv3_procid[proc]; 12554edb46e9SPaul Traina 12564edb46e9SPaul Traina switch (proc) { 12574edb46e9SPaul Traina 12584edb46e9SPaul Traina case NFSPROC_NOOP: 12594edb46e9SPaul Traina printf(" nop"); 12604edb46e9SPaul Traina return; 1261647f50c3SDoug Rabson 12624edb46e9SPaul Traina case NFSPROC_NULL: 12634edb46e9SPaul Traina printf(" null"); 12644edb46e9SPaul Traina return; 12654edb46e9SPaul Traina 12664edb46e9SPaul Traina case NFSPROC_GETATTR: 12674edb46e9SPaul Traina printf(" getattr"); 12684edb46e9SPaul Traina dp = parserep(rp, length); 12692ebf6c05SBill Fenner if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0) 12704edb46e9SPaul Traina return; 12714edb46e9SPaul Traina break; 12724edb46e9SPaul Traina 12734edb46e9SPaul Traina case NFSPROC_SETATTR: 12744edb46e9SPaul Traina printf(" setattr"); 12752ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 12764edb46e9SPaul Traina return; 1277647f50c3SDoug Rabson if (v3) { 12782ebf6c05SBill Fenner if (parsewccres(dp, vflag) != 0) 1279647f50c3SDoug Rabson return; 1280647f50c3SDoug Rabson } else { 1281647f50c3SDoug Rabson if (parseattrstat(dp, !qflag, 0) != 0) 1282647f50c3SDoug Rabson return; 1283647f50c3SDoug Rabson } 12844edb46e9SPaul Traina break; 12854edb46e9SPaul Traina 12864edb46e9SPaul Traina case NFSPROC_LOOKUP: 12874edb46e9SPaul Traina printf(" lookup"); 12882ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 12894edb46e9SPaul Traina break; 1290647f50c3SDoug Rabson if (v3) { 12912ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1292647f50c3SDoug Rabson break; 1293647f50c3SDoug Rabson if (er) { 1294647f50c3SDoug Rabson if (vflag > 1) { 1295647f50c3SDoug Rabson printf(" post dattr:"); 1296647f50c3SDoug Rabson dp = parse_post_op_attr(dp, vflag); 1297647f50c3SDoug Rabson } 1298647f50c3SDoug Rabson } else { 12992ebf6c05SBill Fenner if ((dp = parsefh(dp, v3)) == NULL) 1300647f50c3SDoug Rabson break; 13012ebf6c05SBill Fenner if (((dp = parse_post_op_attr(dp, vflag)) != NULL) && 13022ebf6c05SBill Fenner (vflag > 1)) { 1303647f50c3SDoug Rabson printf(" post dattr:"); 1304647f50c3SDoug Rabson dp = parse_post_op_attr(dp, vflag); 1305647f50c3SDoug Rabson } 1306647f50c3SDoug Rabson } 13072ebf6c05SBill Fenner if (dp != NULL) 1308647f50c3SDoug Rabson return; 1309647f50c3SDoug Rabson } else { 1310647f50c3SDoug Rabson if (parsediropres(dp) != 0) 1311647f50c3SDoug Rabson return; 1312647f50c3SDoug Rabson } 1313647f50c3SDoug Rabson break; 1314647f50c3SDoug Rabson 1315647f50c3SDoug Rabson case NFSPROC_ACCESS: 1316647f50c3SDoug Rabson printf(" access"); 1317647f50c3SDoug Rabson dp = parserep(rp, length); 13182ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1319647f50c3SDoug Rabson break; 1320647f50c3SDoug Rabson if (vflag) 1321647f50c3SDoug Rabson printf(" attr:"); 13222ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1323647f50c3SDoug Rabson break; 1324647f50c3SDoug Rabson if (!er) 13252ebf6c05SBill Fenner printf(" c %04lx", ntohl(dp[0])); 1326647f50c3SDoug Rabson return; 13274edb46e9SPaul Traina 13284edb46e9SPaul Traina case NFSPROC_READLINK: 13294edb46e9SPaul Traina printf(" readlink"); 13304edb46e9SPaul Traina dp = parserep(rp, length); 13312ebf6c05SBill Fenner if (dp != NULL && parselinkres(dp, v3) != 0) 13324edb46e9SPaul Traina return; 13334edb46e9SPaul Traina break; 13344edb46e9SPaul Traina 13354edb46e9SPaul Traina case NFSPROC_READ: 13364edb46e9SPaul Traina printf(" read"); 13372ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1338647f50c3SDoug Rabson break; 1339647f50c3SDoug Rabson if (v3) { 13402ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1341647f50c3SDoug Rabson break; 13422ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1343647f50c3SDoug Rabson break; 1344647f50c3SDoug Rabson if (er) 13454edb46e9SPaul Traina return; 1346647f50c3SDoug Rabson if (vflag) { 1347647f50c3SDoug Rabson TCHECK2(*dp, 8); 1348647f50c3SDoug Rabson printf("%lu bytes", ntohl(dp[0])); 1349647f50c3SDoug Rabson if (ntohl(dp[1])) 1350647f50c3SDoug Rabson printf(" EOF"); 1351647f50c3SDoug Rabson } 1352647f50c3SDoug Rabson return; 1353647f50c3SDoug Rabson } else { 1354647f50c3SDoug Rabson if (parseattrstat(dp, vflag, 0) != 0) 1355647f50c3SDoug Rabson return; 1356647f50c3SDoug Rabson } 13574edb46e9SPaul Traina break; 13584edb46e9SPaul Traina 13594edb46e9SPaul Traina case NFSPROC_WRITE: 13604edb46e9SPaul Traina printf(" write"); 13612ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1362647f50c3SDoug Rabson break; 1363647f50c3SDoug Rabson if (v3) { 13642ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1365647f50c3SDoug Rabson break; 13662ebf6c05SBill Fenner if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1367647f50c3SDoug Rabson break; 1368647f50c3SDoug Rabson if (er) 13694edb46e9SPaul Traina return; 1370647f50c3SDoug Rabson if (vflag) { 1371647f50c3SDoug Rabson TCHECK2(*dp, 4); 1372647f50c3SDoug Rabson printf("%lu bytes", ntohl(dp[0])); 1373647f50c3SDoug Rabson if (vflag > 1) { 1374647f50c3SDoug Rabson TCHECK2(*dp, 4); 1375647f50c3SDoug Rabson printf(" <%s>", 1376647f50c3SDoug Rabson nfsv3_writemodes[ntohl(dp[1])]); 1377647f50c3SDoug Rabson } 1378647f50c3SDoug Rabson return; 1379647f50c3SDoug Rabson } 1380647f50c3SDoug Rabson } else { 1381647f50c3SDoug Rabson if (parseattrstat(dp, vflag, v3) != 0) 1382647f50c3SDoug Rabson return; 1383647f50c3SDoug Rabson } 13844edb46e9SPaul Traina break; 13854edb46e9SPaul Traina 13864edb46e9SPaul Traina case NFSPROC_CREATE: 13874edb46e9SPaul Traina printf(" create"); 13882ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1389647f50c3SDoug Rabson break; 1390647f50c3SDoug Rabson if (v3) { 13912ebf6c05SBill Fenner if (parsecreateopres(dp, vflag) != NULL) 1392647f50c3SDoug Rabson return; 1393647f50c3SDoug Rabson } else { 1394647f50c3SDoug Rabson if (parsediropres(dp) != 0) 1395647f50c3SDoug Rabson return; 1396647f50c3SDoug Rabson } 1397647f50c3SDoug Rabson break; 1398647f50c3SDoug Rabson 1399647f50c3SDoug Rabson case NFSPROC_MKDIR: 1400647f50c3SDoug Rabson printf(" mkdir"); 14012ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1402647f50c3SDoug Rabson break; 1403647f50c3SDoug Rabson if (v3) { 14042ebf6c05SBill Fenner if (parsecreateopres(dp, vflag) != NULL) 1405647f50c3SDoug Rabson return; 1406647f50c3SDoug Rabson } else { 1407647f50c3SDoug Rabson if (parsediropres(dp) != 0) 1408647f50c3SDoug Rabson return; 1409647f50c3SDoug Rabson } 1410647f50c3SDoug Rabson break; 1411647f50c3SDoug Rabson 1412647f50c3SDoug Rabson case NFSPROC_SYMLINK: 1413647f50c3SDoug Rabson printf(" symlink"); 14142ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1415647f50c3SDoug Rabson break; 1416647f50c3SDoug Rabson if (v3) { 14172ebf6c05SBill Fenner if (parsecreateopres(dp, vflag) != NULL) 1418647f50c3SDoug Rabson return; 1419647f50c3SDoug Rabson } else { 14202ebf6c05SBill Fenner if (parsestatus(dp, &er) != NULL) 1421647f50c3SDoug Rabson return; 1422647f50c3SDoug Rabson } 1423647f50c3SDoug Rabson break; 1424647f50c3SDoug Rabson 1425647f50c3SDoug Rabson case NFSPROC_MKNOD: 1426647f50c3SDoug Rabson printf(" mknod"); 14272ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1428647f50c3SDoug Rabson break; 14292ebf6c05SBill Fenner if (parsecreateopres(dp, vflag) != NULL) 14304edb46e9SPaul Traina return; 14314edb46e9SPaul Traina break; 14324edb46e9SPaul Traina 14334edb46e9SPaul Traina case NFSPROC_REMOVE: 14344edb46e9SPaul Traina printf(" remove"); 14352ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 14364edb46e9SPaul Traina break; 1437647f50c3SDoug Rabson if (v3) { 14382ebf6c05SBill Fenner if (parsewccres(dp, vflag) != 0) 14394edb46e9SPaul Traina return; 1440647f50c3SDoug Rabson } else { 14412ebf6c05SBill Fenner if (parsestatus(dp, &er) != NULL) 14424edb46e9SPaul Traina return; 1443647f50c3SDoug Rabson } 14444edb46e9SPaul Traina break; 14454edb46e9SPaul Traina 14464edb46e9SPaul Traina case NFSPROC_RMDIR: 14474edb46e9SPaul Traina printf(" rmdir"); 14482ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1449647f50c3SDoug Rabson break; 1450647f50c3SDoug Rabson if (v3) { 14512ebf6c05SBill Fenner if (parsewccres(dp, vflag) != 0) 14524edb46e9SPaul Traina return; 1453647f50c3SDoug Rabson } else { 14542ebf6c05SBill Fenner if (parsestatus(dp, &er) != NULL) 1455647f50c3SDoug Rabson return; 1456647f50c3SDoug Rabson } 1457647f50c3SDoug Rabson break; 1458647f50c3SDoug Rabson 1459647f50c3SDoug Rabson case NFSPROC_RENAME: 1460647f50c3SDoug Rabson printf(" rename"); 14612ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1462647f50c3SDoug Rabson break; 1463647f50c3SDoug Rabson if (v3) { 14642ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1465647f50c3SDoug Rabson break; 1466647f50c3SDoug Rabson if (vflag) { 1467647f50c3SDoug Rabson printf(" from:"); 14682ebf6c05SBill Fenner if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1469647f50c3SDoug Rabson break; 1470647f50c3SDoug Rabson printf(" to:"); 14712ebf6c05SBill Fenner if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1472647f50c3SDoug Rabson break; 1473647f50c3SDoug Rabson } 1474647f50c3SDoug Rabson return; 1475647f50c3SDoug Rabson } else { 14762ebf6c05SBill Fenner if (parsestatus(dp, &er) != NULL) 1477647f50c3SDoug Rabson return; 1478647f50c3SDoug Rabson } 1479647f50c3SDoug Rabson break; 1480647f50c3SDoug Rabson 1481647f50c3SDoug Rabson case NFSPROC_LINK: 1482647f50c3SDoug Rabson printf(" link"); 14832ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1484647f50c3SDoug Rabson break; 1485647f50c3SDoug Rabson if (v3) { 14862ebf6c05SBill Fenner if ((dp = parsestatus(dp, &er)) == NULL) 1487647f50c3SDoug Rabson break; 1488647f50c3SDoug Rabson if (vflag) { 1489647f50c3SDoug Rabson printf(" file POST:"); 14902ebf6c05SBill Fenner if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1491647f50c3SDoug Rabson break; 1492647f50c3SDoug Rabson printf(" dir:"); 14932ebf6c05SBill Fenner if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1494647f50c3SDoug Rabson break; 1495647f50c3SDoug Rabson return; 1496647f50c3SDoug Rabson } 1497647f50c3SDoug Rabson } else { 14982ebf6c05SBill Fenner if (parsestatus(dp, &er) != NULL) 1499647f50c3SDoug Rabson return; 1500647f50c3SDoug Rabson } 15014edb46e9SPaul Traina break; 15024edb46e9SPaul Traina 15034edb46e9SPaul Traina case NFSPROC_READDIR: 15044edb46e9SPaul Traina printf(" readdir"); 15052ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1506647f50c3SDoug Rabson break; 1507647f50c3SDoug Rabson if (v3) { 15082ebf6c05SBill Fenner if (parsev3rddirres(dp, vflag) != NULL) 1509647f50c3SDoug Rabson return; 1510647f50c3SDoug Rabson } else { 1511647f50c3SDoug Rabson if (parserddires(dp) != 0) 1512647f50c3SDoug Rabson return; 1513647f50c3SDoug Rabson } 1514647f50c3SDoug Rabson break; 1515647f50c3SDoug Rabson 1516647f50c3SDoug Rabson case NFSPROC_READDIRPLUS: 1517647f50c3SDoug Rabson printf(" readdirplus"); 15182ebf6c05SBill Fenner if ((dp = parserep(rp, length)) == NULL) 1519647f50c3SDoug Rabson break; 15202ebf6c05SBill Fenner if (parsev3rddirres(dp, vflag) != NULL) 15214edb46e9SPaul Traina return; 15224edb46e9SPaul Traina break; 15234edb46e9SPaul Traina 1524647f50c3SDoug Rabson case NFSPROC_FSSTAT: 1525647f50c3SDoug Rabson printf(" fsstat"); 15264edb46e9SPaul Traina dp = parserep(rp, length); 15272ebf6c05SBill Fenner if (dp != NULL && parsestatfs(dp, v3) != NULL) 1528647f50c3SDoug Rabson return; 1529647f50c3SDoug Rabson break; 1530647f50c3SDoug Rabson 1531647f50c3SDoug Rabson case NFSPROC_FSINFO: 1532647f50c3SDoug Rabson printf(" fsinfo"); 1533647f50c3SDoug Rabson dp = parserep(rp, length); 15342ebf6c05SBill Fenner if (dp != NULL && parsefsinfo(dp) != NULL) 1535647f50c3SDoug Rabson return; 1536647f50c3SDoug Rabson break; 1537647f50c3SDoug Rabson 1538647f50c3SDoug Rabson case NFSPROC_PATHCONF: 1539647f50c3SDoug Rabson printf(" pathconf"); 1540647f50c3SDoug Rabson dp = parserep(rp, length); 15412ebf6c05SBill Fenner if (dp != NULL && parsepathconf(dp) != 0) 1542647f50c3SDoug Rabson return; 1543647f50c3SDoug Rabson break; 1544647f50c3SDoug Rabson 1545647f50c3SDoug Rabson case NFSPROC_COMMIT: 1546647f50c3SDoug Rabson printf(" commit"); 1547647f50c3SDoug Rabson dp = parserep(rp, length); 15482ebf6c05SBill Fenner if (dp != NULL && parsewccres(dp, vflag) != 0) 15494edb46e9SPaul Traina return; 15504edb46e9SPaul Traina break; 15514edb46e9SPaul Traina 15524edb46e9SPaul Traina default: 15532ebf6c05SBill Fenner printf(" proc-%u", proc); 15544edb46e9SPaul Traina return; 15554edb46e9SPaul Traina } 1556647f50c3SDoug Rabson 1557647f50c3SDoug Rabson trunc: 15582ebf6c05SBill Fenner if (!nfserr) 15594edb46e9SPaul Traina fputs(" [|nfs]", stdout); 15604edb46e9SPaul Traina } 1561