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. 2017680Spst */ 2117680Spst 22313537Sglebius/* \summary: Network File System (NFS) printer */ 23313537Sglebius 2475118Sfenner#ifdef HAVE_CONFIG_H 2575118Sfenner#include "config.h" 2675118Sfenner#endif 2775118Sfenner 28313537Sglebius#include <netdissect-stdinc.h> 2917680Spst 3017680Spst#include <stdio.h> 3117680Spst#include <string.h> 3217680Spst 33313537Sglebius#include "netdissect.h" 3417680Spst#include "addrtoname.h" 35127675Sbms#include "extract.h" 3617680Spst 3718976Sdfr#include "nfs.h" 3817680Spst#include "nfsfh.h" 3917680Spst 4075118Sfenner#include "ip.h" 4175118Sfenner#include "ip6.h" 42146778Ssam#include "rpc_auth.h" 43146778Ssam#include "rpc_msg.h" 4475118Sfenner 45276788Sdelphijstatic const char tstr[] = " [|nfs]"; 4617680Spst 47276788Sdelphijstatic void nfs_printfh(netdissect_options *, const uint32_t *, const u_int); 48276788Sdelphijstatic int xid_map_enter(netdissect_options *, const struct sunrpc_msg *, const u_char *); 49276788Sdelphijstatic int xid_map_find(const struct sunrpc_msg *, const u_char *, 50276788Sdelphij uint32_t *, uint32_t *); 51276788Sdelphijstatic void interp_reply(netdissect_options *, const struct sunrpc_msg *, uint32_t, uint32_t, int); 52276788Sdelphijstatic const uint32_t *parse_post_op_attr(netdissect_options *, const uint32_t *, int); 53276788Sdelphij 5418976Sdfr/* 5518976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 5618976Sdfr */ 57313537Sglebiusstatic uint32_t nfsv3_procid[NFS_NPROCS] = { 5818976Sdfr NFSPROC_NULL, 5918976Sdfr NFSPROC_GETATTR, 6018976Sdfr NFSPROC_SETATTR, 6118976Sdfr NFSPROC_NOOP, 6218976Sdfr NFSPROC_LOOKUP, 6318976Sdfr NFSPROC_READLINK, 6418976Sdfr NFSPROC_READ, 6518976Sdfr NFSPROC_NOOP, 6618976Sdfr NFSPROC_WRITE, 6718976Sdfr NFSPROC_CREATE, 6818976Sdfr NFSPROC_REMOVE, 6918976Sdfr NFSPROC_RENAME, 7018976Sdfr NFSPROC_LINK, 7118976Sdfr NFSPROC_SYMLINK, 7218976Sdfr NFSPROC_MKDIR, 7318976Sdfr NFSPROC_RMDIR, 7418976Sdfr NFSPROC_READDIR, 7518976Sdfr NFSPROC_FSSTAT, 7618976Sdfr NFSPROC_NOOP, 7718976Sdfr NFSPROC_NOOP, 7818976Sdfr NFSPROC_NOOP, 7918976Sdfr NFSPROC_NOOP, 8018976Sdfr NFSPROC_NOOP, 8118976Sdfr NFSPROC_NOOP, 8218976Sdfr NFSPROC_NOOP, 8318976Sdfr NFSPROC_NOOP 8418976Sdfr}; 8518976Sdfr 86276788Sdelphijstatic const struct tok nfsproc_str[] = { 87276788Sdelphij { NFSPROC_NOOP, "nop" }, 88276788Sdelphij { NFSPROC_NULL, "null" }, 89276788Sdelphij { NFSPROC_GETATTR, "getattr" }, 90276788Sdelphij { NFSPROC_SETATTR, "setattr" }, 91276788Sdelphij { NFSPROC_LOOKUP, "lookup" }, 92276788Sdelphij { NFSPROC_ACCESS, "access" }, 93276788Sdelphij { NFSPROC_READLINK, "readlink" }, 94276788Sdelphij { NFSPROC_READ, "read" }, 95276788Sdelphij { NFSPROC_WRITE, "write" }, 96276788Sdelphij { NFSPROC_CREATE, "create" }, 97276788Sdelphij { NFSPROC_MKDIR, "mkdir" }, 98276788Sdelphij { NFSPROC_SYMLINK, "symlink" }, 99276788Sdelphij { NFSPROC_MKNOD, "mknod" }, 100276788Sdelphij { NFSPROC_REMOVE, "remove" }, 101276788Sdelphij { NFSPROC_RMDIR, "rmdir" }, 102276788Sdelphij { NFSPROC_RENAME, "rename" }, 103276788Sdelphij { NFSPROC_LINK, "link" }, 104276788Sdelphij { NFSPROC_READDIR, "readdir" }, 105276788Sdelphij { NFSPROC_READDIRPLUS, "readdirplus" }, 106276788Sdelphij { NFSPROC_FSSTAT, "fsstat" }, 107276788Sdelphij { NFSPROC_FSINFO, "fsinfo" }, 108276788Sdelphij { NFSPROC_PATHCONF, "pathconf" }, 109276788Sdelphij { NFSPROC_COMMIT, "commit" }, 110276788Sdelphij { 0, NULL } 111276788Sdelphij}; 112276788Sdelphij 11375118Sfenner/* 11475118Sfenner * NFS V2 and V3 status values. 11575118Sfenner * 11675118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message 11775118Sfenner * strings taken from the FreeBSD C library "errlst.c". 11875118Sfenner * 11975118Sfenner * Others are errors that are not in the RFC but that I suspect some 12075118Sfenner * NFS servers could return; the values are FreeBSD errno values, as 12175118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS 12275118Sfenner * was primarily BSD-derived. 12375118Sfenner */ 124276788Sdelphijstatic const struct tok status2str[] = { 12575118Sfenner { 1, "Operation not permitted" }, /* EPERM */ 12675118Sfenner { 2, "No such file or directory" }, /* ENOENT */ 12775118Sfenner { 5, "Input/output error" }, /* EIO */ 12875118Sfenner { 6, "Device not configured" }, /* ENXIO */ 12975118Sfenner { 11, "Resource deadlock avoided" }, /* EDEADLK */ 13075118Sfenner { 12, "Cannot allocate memory" }, /* ENOMEM */ 13175118Sfenner { 13, "Permission denied" }, /* EACCES */ 13275118Sfenner { 17, "File exists" }, /* EEXIST */ 13375118Sfenner { 18, "Cross-device link" }, /* EXDEV */ 13475118Sfenner { 19, "Operation not supported by device" }, /* ENODEV */ 13575118Sfenner { 20, "Not a directory" }, /* ENOTDIR */ 13675118Sfenner { 21, "Is a directory" }, /* EISDIR */ 13775118Sfenner { 22, "Invalid argument" }, /* EINVAL */ 13875118Sfenner { 26, "Text file busy" }, /* ETXTBSY */ 13975118Sfenner { 27, "File too large" }, /* EFBIG */ 14075118Sfenner { 28, "No space left on device" }, /* ENOSPC */ 14175118Sfenner { 30, "Read-only file system" }, /* EROFS */ 14275118Sfenner { 31, "Too many links" }, /* EMLINK */ 14375118Sfenner { 45, "Operation not supported" }, /* EOPNOTSUPP */ 14475118Sfenner { 62, "Too many levels of symbolic links" }, /* ELOOP */ 14575118Sfenner { 63, "File name too long" }, /* ENAMETOOLONG */ 14675118Sfenner { 66, "Directory not empty" }, /* ENOTEMPTY */ 14775118Sfenner { 69, "Disc quota exceeded" }, /* EDQUOT */ 14875118Sfenner { 70, "Stale NFS file handle" }, /* ESTALE */ 14975118Sfenner { 71, "Too many levels of remote in path" }, /* EREMOTE */ 15075118Sfenner { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */ 15175118Sfenner { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */ 15275118Sfenner { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */ 15375118Sfenner { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */ 15475118Sfenner { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */ 15575118Sfenner { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */ 15675118Sfenner { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */ 15775118Sfenner { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */ 15875118Sfenner { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */ 15975118Sfenner { 0, NULL } 16018976Sdfr}; 16118976Sdfr 162276788Sdelphijstatic const struct tok nfsv3_writemodes[] = { 16375118Sfenner { 0, "unstable" }, 16475118Sfenner { 1, "datasync" }, 16575118Sfenner { 2, "filesync" }, 16675118Sfenner { 0, NULL } 16775118Sfenner}; 16875118Sfenner 169276788Sdelphijstatic const struct tok type2str[] = { 17018976Sdfr { NFNON, "NON" }, 17118976Sdfr { NFREG, "REG" }, 17218976Sdfr { NFDIR, "DIR" }, 17318976Sdfr { NFBLK, "BLK" }, 17418976Sdfr { NFCHR, "CHR" }, 17518976Sdfr { NFLNK, "LNK" }, 17618976Sdfr { NFFIFO, "FIFO" }, 17718976Sdfr { 0, NULL } 17818976Sdfr}; 17918976Sdfr 180276788Sdelphijstatic const struct tok sunrpc_auth_str[] = { 181276788Sdelphij { SUNRPC_AUTH_OK, "OK" }, 182276788Sdelphij { SUNRPC_AUTH_BADCRED, "Bogus Credentials (seal broken)" }, 183276788Sdelphij { SUNRPC_AUTH_REJECTEDCRED, "Rejected Credentials (client should begin new session)" }, 184276788Sdelphij { SUNRPC_AUTH_BADVERF, "Bogus Verifier (seal broken)" }, 185276788Sdelphij { SUNRPC_AUTH_REJECTEDVERF, "Verifier expired or was replayed" }, 186276788Sdelphij { SUNRPC_AUTH_TOOWEAK, "Credentials are too weak" }, 187276788Sdelphij { SUNRPC_AUTH_INVALIDRESP, "Bogus response verifier" }, 188276788Sdelphij { SUNRPC_AUTH_FAILED, "Unknown failure" }, 189276788Sdelphij { 0, NULL } 190276788Sdelphij}; 191276788Sdelphij 192276788Sdelphijstatic const struct tok sunrpc_str[] = { 193276788Sdelphij { SUNRPC_PROG_UNAVAIL, "PROG_UNAVAIL" }, 194276788Sdelphij { SUNRPC_PROG_MISMATCH, "PROG_MISMATCH" }, 195276788Sdelphij { SUNRPC_PROC_UNAVAIL, "PROC_UNAVAIL" }, 196276788Sdelphij { SUNRPC_GARBAGE_ARGS, "GARBAGE_ARGS" }, 197276788Sdelphij { SUNRPC_SYSTEM_ERR, "SYSTEM_ERR" }, 198276788Sdelphij { 0, NULL } 199276788Sdelphij}; 200276788Sdelphij 20175118Sfennerstatic void 202276788Sdelphijprint_nfsaddr(netdissect_options *ndo, 203276788Sdelphij const u_char *bp, const char *s, const char *d) 20475118Sfenner{ 205313537Sglebius const struct ip *ip; 206313537Sglebius const struct ip6_hdr *ip6; 20775118Sfenner char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN]; 20875118Sfenner 20975118Sfenner srcaddr[0] = dstaddr[0] = '\0'; 210313537Sglebius switch (IP_V((const struct ip *)bp)) { 21175118Sfenner case 4: 212313537Sglebius ip = (const struct ip *)bp; 213276788Sdelphij strlcpy(srcaddr, ipaddr_string(ndo, &ip->ip_src), sizeof(srcaddr)); 214276788Sdelphij strlcpy(dstaddr, ipaddr_string(ndo, &ip->ip_dst), sizeof(dstaddr)); 21575118Sfenner break; 21675118Sfenner case 6: 217313537Sglebius ip6 = (const struct ip6_hdr *)bp; 218276788Sdelphij strlcpy(srcaddr, ip6addr_string(ndo, &ip6->ip6_src), 21975118Sfenner sizeof(srcaddr)); 220276788Sdelphij strlcpy(dstaddr, ip6addr_string(ndo, &ip6->ip6_dst), 22175118Sfenner sizeof(dstaddr)); 22275118Sfenner break; 22375118Sfenner default: 22475118Sfenner strlcpy(srcaddr, "?", sizeof(srcaddr)); 22575118Sfenner strlcpy(dstaddr, "?", sizeof(dstaddr)); 22675118Sfenner break; 22775118Sfenner } 22875118Sfenner 229276788Sdelphij ND_PRINT((ndo, "%s.%s > %s.%s: ", srcaddr, s, dstaddr, d)); 23075118Sfenner} 23175118Sfenner 232276788Sdelphijstatic const uint32_t * 233276788Sdelphijparse_sattr3(netdissect_options *ndo, 234276788Sdelphij const uint32_t *dp, struct nfsv3_sattr *sa3) 23518976Sdfr{ 236276788Sdelphij ND_TCHECK(dp[0]); 237127675Sbms sa3->sa_modeset = EXTRACT_32BITS(dp); 238127675Sbms dp++; 239127675Sbms if (sa3->sa_modeset) { 240276788Sdelphij ND_TCHECK(dp[0]); 241127675Sbms sa3->sa_mode = EXTRACT_32BITS(dp); 242127675Sbms dp++; 24318976Sdfr } 24418976Sdfr 245276788Sdelphij ND_TCHECK(dp[0]); 246127675Sbms sa3->sa_uidset = EXTRACT_32BITS(dp); 247127675Sbms dp++; 248127675Sbms if (sa3->sa_uidset) { 249276788Sdelphij ND_TCHECK(dp[0]); 250127675Sbms sa3->sa_uid = EXTRACT_32BITS(dp); 251127675Sbms dp++; 25218976Sdfr } 25318976Sdfr 254276788Sdelphij ND_TCHECK(dp[0]); 255127675Sbms sa3->sa_gidset = EXTRACT_32BITS(dp); 256127675Sbms dp++; 257127675Sbms if (sa3->sa_gidset) { 258276788Sdelphij ND_TCHECK(dp[0]); 259127675Sbms sa3->sa_gid = EXTRACT_32BITS(dp); 260127675Sbms dp++; 26118976Sdfr } 26218976Sdfr 263276788Sdelphij ND_TCHECK(dp[0]); 264127675Sbms sa3->sa_sizeset = EXTRACT_32BITS(dp); 265127675Sbms dp++; 266127675Sbms if (sa3->sa_sizeset) { 267276788Sdelphij ND_TCHECK(dp[0]); 268127675Sbms sa3->sa_size = EXTRACT_32BITS(dp); 269127675Sbms dp++; 27018976Sdfr } 27118976Sdfr 272276788Sdelphij ND_TCHECK(dp[0]); 273127675Sbms sa3->sa_atimetype = EXTRACT_32BITS(dp); 274127675Sbms dp++; 275127675Sbms if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) { 276276788Sdelphij ND_TCHECK(dp[1]); 277127675Sbms sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp); 278127675Sbms dp++; 279127675Sbms sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp); 280127675Sbms dp++; 28118976Sdfr } 28218976Sdfr 283276788Sdelphij ND_TCHECK(dp[0]); 284127675Sbms sa3->sa_mtimetype = EXTRACT_32BITS(dp); 285127675Sbms dp++; 286127675Sbms if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) { 287276788Sdelphij ND_TCHECK(dp[1]); 288127675Sbms sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp); 289127675Sbms dp++; 290127675Sbms sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp); 291127675Sbms dp++; 29218976Sdfr } 29318976Sdfr 29418976Sdfr return dp; 29575118Sfennertrunc: 29675118Sfenner return NULL; 29718976Sdfr} 29818976Sdfr 29975118Sfennerstatic int nfserr; /* true if we error rather than trunc */ 30075118Sfenner 30175118Sfennerstatic void 302276788Sdelphijprint_sattr3(netdissect_options *ndo, 303276788Sdelphij const struct nfsv3_sattr *sa3, int verbose) 30418976Sdfr{ 30518976Sdfr if (sa3->sa_modeset) 306276788Sdelphij ND_PRINT((ndo, " mode %o", sa3->sa_mode)); 30718976Sdfr if (sa3->sa_uidset) 308276788Sdelphij ND_PRINT((ndo, " uid %u", sa3->sa_uid)); 30918976Sdfr if (sa3->sa_gidset) 310276788Sdelphij ND_PRINT((ndo, " gid %u", sa3->sa_gid)); 31118976Sdfr if (verbose > 1) { 31218976Sdfr if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) 313276788Sdelphij ND_PRINT((ndo, " atime %u.%06u", sa3->sa_atime.nfsv3_sec, 314276788Sdelphij sa3->sa_atime.nfsv3_nsec)); 31518976Sdfr if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) 316276788Sdelphij ND_PRINT((ndo, " mtime %u.%06u", sa3->sa_mtime.nfsv3_sec, 317276788Sdelphij sa3->sa_mtime.nfsv3_nsec)); 31818976Sdfr } 31918976Sdfr} 32018976Sdfr 32118976Sdfrvoid 322276788Sdelphijnfsreply_print(netdissect_options *ndo, 323276788Sdelphij register const u_char *bp, u_int length, 324276788Sdelphij register const u_char *bp2) 32517680Spst{ 326146778Ssam register const struct sunrpc_msg *rp; 32775118Sfenner char srcid[20], dstid[20]; /*fits 32bit*/ 32817680Spst 32926183Sfenner nfserr = 0; /* assume no error */ 330146778Ssam rp = (const struct sunrpc_msg *)bp; 33117680Spst 332276788Sdelphij ND_TCHECK(rp->rm_xid); 333276788Sdelphij if (!ndo->ndo_nflag) { 33475118Sfenner strlcpy(srcid, "nfs", sizeof(srcid)); 33575118Sfenner snprintf(dstid, sizeof(dstid), "%u", 336127675Sbms EXTRACT_32BITS(&rp->rm_xid)); 33775118Sfenner } else { 33875118Sfenner snprintf(srcid, sizeof(srcid), "%u", NFS_PORT); 33975118Sfenner snprintf(dstid, sizeof(dstid), "%u", 340127675Sbms EXTRACT_32BITS(&rp->rm_xid)); 34175118Sfenner } 342276788Sdelphij print_nfsaddr(ndo, bp2, srcid, dstid); 343276788Sdelphij 344276788Sdelphij nfsreply_print_noaddr(ndo, bp, length, bp2); 345276788Sdelphij return; 346276788Sdelphij 347276788Sdelphijtrunc: 348276788Sdelphij if (!nfserr) 349276788Sdelphij ND_PRINT((ndo, "%s", tstr)); 350276788Sdelphij} 351276788Sdelphij 352276788Sdelphijvoid 353276788Sdelphijnfsreply_print_noaddr(netdissect_options *ndo, 354276788Sdelphij register const u_char *bp, u_int length, 355276788Sdelphij register const u_char *bp2) 356276788Sdelphij{ 357276788Sdelphij register const struct sunrpc_msg *rp; 358276788Sdelphij uint32_t proc, vers, reply_stat; 359276788Sdelphij enum sunrpc_reject_stat rstat; 360276788Sdelphij uint32_t rlow; 361276788Sdelphij uint32_t rhigh; 362276788Sdelphij enum sunrpc_auth_stat rwhy; 363276788Sdelphij 364276788Sdelphij nfserr = 0; /* assume no error */ 365276788Sdelphij rp = (const struct sunrpc_msg *)bp; 366276788Sdelphij 367276788Sdelphij ND_TCHECK(rp->rm_reply.rp_stat); 368172686Smlaier reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat); 369172686Smlaier switch (reply_stat) { 37017680Spst 371172686Smlaier case SUNRPC_MSG_ACCEPTED: 372276788Sdelphij ND_PRINT((ndo, "reply ok %u", length)); 373172686Smlaier if (xid_map_find(rp, bp2, &proc, &vers) >= 0) 374276788Sdelphij interp_reply(ndo, rp, proc, vers, length); 375172686Smlaier break; 376172686Smlaier 377172686Smlaier case SUNRPC_MSG_DENIED: 378276788Sdelphij ND_PRINT((ndo, "reply ERR %u: ", length)); 379276788Sdelphij ND_TCHECK(rp->rm_reply.rp_reject.rj_stat); 380172686Smlaier rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat); 381172686Smlaier switch (rstat) { 382172686Smlaier 383172686Smlaier case SUNRPC_RPC_MISMATCH: 384276788Sdelphij ND_TCHECK(rp->rm_reply.rp_reject.rj_vers.high); 385172686Smlaier rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low); 386172686Smlaier rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high); 387276788Sdelphij ND_PRINT((ndo, "RPC Version mismatch (%u-%u)", rlow, rhigh)); 388172686Smlaier break; 389172686Smlaier 390172686Smlaier case SUNRPC_AUTH_ERROR: 391276788Sdelphij ND_TCHECK(rp->rm_reply.rp_reject.rj_why); 392172686Smlaier rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why); 393276788Sdelphij ND_PRINT((ndo, "Auth %s", tok2str(sunrpc_auth_str, "Invalid failure code %u", rwhy))); 394172686Smlaier break; 395172686Smlaier 396172686Smlaier default: 397276788Sdelphij ND_PRINT((ndo, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat)); 398172686Smlaier break; 399172686Smlaier } 400172686Smlaier break; 401172686Smlaier 402172686Smlaier default: 403276788Sdelphij ND_PRINT((ndo, "reply Unknown rpc response code=%u %u", reply_stat, length)); 404172686Smlaier break; 405172686Smlaier } 406190207Srpaulo return; 407190207Srpaulo 408190207Srpaulotrunc: 409190207Srpaulo if (!nfserr) 410276788Sdelphij ND_PRINT((ndo, "%s", tstr)); 41117680Spst} 41217680Spst 41317680Spst/* 41417680Spst * Return a pointer to the first file handle in the packet. 41575118Sfenner * If the packet was truncated, return 0. 41617680Spst */ 417276788Sdelphijstatic const uint32_t * 418276788Sdelphijparsereq(netdissect_options *ndo, 419276788Sdelphij register const struct sunrpc_msg *rp, register u_int length) 42017680Spst{ 421276788Sdelphij register const uint32_t *dp; 42217680Spst register u_int len; 42317680Spst 42417680Spst /* 42517680Spst * find the start of the req data (if we captured it) 42617680Spst */ 427313537Sglebius dp = (const uint32_t *)&rp->rm_call.cb_cred; 428276788Sdelphij ND_TCHECK(dp[1]); 429127675Sbms len = EXTRACT_32BITS(&dp[1]); 43026183Sfenner if (len < length) { 43126183Sfenner dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 432276788Sdelphij ND_TCHECK(dp[1]); 433127675Sbms len = EXTRACT_32BITS(&dp[1]); 43426183Sfenner if (len < length) { 43526183Sfenner dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 436276788Sdelphij ND_TCHECK2(dp[0], 0); 43726183Sfenner return (dp); 43817680Spst } 43917680Spst } 44026183Sfennertrunc: 44126183Sfenner return (NULL); 44217680Spst} 44317680Spst 44417680Spst/* 44517680Spst * Print out an NFS file handle and return a pointer to following word. 44675118Sfenner * If packet was truncated, return 0. 44717680Spst */ 448276788Sdelphijstatic const uint32_t * 449276788Sdelphijparsefh(netdissect_options *ndo, 450276788Sdelphij register const uint32_t *dp, int v3) 45117680Spst{ 452127675Sbms u_int len; 45318976Sdfr 45418976Sdfr if (v3) { 455276788Sdelphij ND_TCHECK(dp[0]); 456127675Sbms len = EXTRACT_32BITS(dp) / 4; 45718976Sdfr dp++; 45818976Sdfr } else 45918976Sdfr len = NFSX_V2FH / 4; 46018976Sdfr 461276788Sdelphij if (ND_TTEST2(*dp, len * sizeof(*dp))) { 462276788Sdelphij nfs_printfh(ndo, dp, len); 46318976Sdfr return (dp + len); 46417680Spst } 46526183Sfennertrunc: 46626183Sfenner return (NULL); 46717680Spst} 46817680Spst 46917680Spst/* 47017680Spst * Print out a file name and return pointer to 32-bit word past it. 47175118Sfenner * If packet was truncated, return 0. 47217680Spst */ 473276788Sdelphijstatic const uint32_t * 474276788Sdelphijparsefn(netdissect_options *ndo, 475276788Sdelphij register const uint32_t *dp) 47617680Spst{ 477276788Sdelphij register uint32_t len; 47817680Spst register const u_char *cp; 47917680Spst 48017680Spst /* Bail if we don't have the string length */ 481276788Sdelphij ND_TCHECK(*dp); 48217680Spst 48317680Spst /* Fetch string length; convert to host order */ 48417680Spst len = *dp++; 48517680Spst NTOHL(len); 48617680Spst 487276788Sdelphij ND_TCHECK2(*dp, ((len + 3) & ~3)); 48875118Sfenner 489313537Sglebius cp = (const u_char *)dp; 49017680Spst /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ 49117680Spst dp += ((len + 3) & ~3) / sizeof(*dp); 492276788Sdelphij ND_PRINT((ndo, "\"")); 493276788Sdelphij if (fn_printn(ndo, cp, len, ndo->ndo_snapend)) { 494276788Sdelphij ND_PRINT((ndo, "\"")); 495147904Ssam goto trunc; 496147904Ssam } 497276788Sdelphij ND_PRINT((ndo, "\"")); 49817680Spst 49917680Spst return (dp); 50075118Sfennertrunc: 50175118Sfenner return NULL; 50217680Spst} 50317680Spst 50417680Spst/* 50517680Spst * Print out file handle and file name. 50617680Spst * Return pointer to 32-bit word past file name. 50775118Sfenner * If packet was truncated (or there was some other error), return 0. 50817680Spst */ 509276788Sdelphijstatic const uint32_t * 510276788Sdelphijparsefhn(netdissect_options *ndo, 511276788Sdelphij register const uint32_t *dp, int v3) 51217680Spst{ 513276788Sdelphij dp = parsefh(ndo, dp, v3); 51426183Sfenner if (dp == NULL) 51526183Sfenner return (NULL); 516276788Sdelphij ND_PRINT((ndo, " ")); 517276788Sdelphij return (parsefn(ndo, dp)); 51817680Spst} 51917680Spst 52017680Spstvoid 521276788Sdelphijnfsreq_print_noaddr(netdissect_options *ndo, 522276788Sdelphij register const u_char *bp, u_int length, 523276788Sdelphij register const u_char *bp2) 52417680Spst{ 525146778Ssam register const struct sunrpc_msg *rp; 526276788Sdelphij register const uint32_t *dp; 52775118Sfenner nfs_type type; 52875118Sfenner int v3; 529276788Sdelphij uint32_t proc; 530276788Sdelphij uint32_t access_flags; 53118976Sdfr struct nfsv3_sattr sa3; 53217680Spst 533276788Sdelphij ND_PRINT((ndo, "%d", length)); 53426183Sfenner nfserr = 0; /* assume no error */ 535146778Ssam rp = (const struct sunrpc_msg *)bp; 536190207Srpaulo 537276788Sdelphij if (!xid_map_enter(ndo, rp, bp2)) /* record proc number for later on */ 538190207Srpaulo goto trunc; 53917680Spst 540127675Sbms v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3); 541127675Sbms proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 54218976Sdfr 54318976Sdfr if (!v3 && proc < NFS_NPROCS) 54418976Sdfr proc = nfsv3_procid[proc]; 54518976Sdfr 546276788Sdelphij ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc))); 54718976Sdfr switch (proc) { 54817680Spst 54917680Spst case NFSPROC_GETATTR: 55017680Spst case NFSPROC_SETATTR: 551276788Sdelphij case NFSPROC_READLINK: 552276788Sdelphij case NFSPROC_FSSTAT: 553276788Sdelphij case NFSPROC_FSINFO: 554276788Sdelphij case NFSPROC_PATHCONF: 555276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 556276788Sdelphij parsefh(ndo, dp, v3) != NULL) 55717680Spst return; 55817680Spst break; 55917680Spst 56017680Spst case NFSPROC_LOOKUP: 561276788Sdelphij case NFSPROC_CREATE: 562276788Sdelphij case NFSPROC_MKDIR: 563276788Sdelphij case NFSPROC_REMOVE: 564276788Sdelphij case NFSPROC_RMDIR: 565276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 566276788Sdelphij parsefhn(ndo, dp, v3) != NULL) 56717680Spst return; 56817680Spst break; 56917680Spst 57018976Sdfr case NFSPROC_ACCESS: 571276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 572276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 573276788Sdelphij ND_TCHECK(dp[0]); 574214478Srpaulo access_flags = EXTRACT_32BITS(&dp[0]); 575214478Srpaulo if (access_flags & ~NFSV3ACCESS_FULL) { 576214478Srpaulo /* NFSV3ACCESS definitions aren't up to date */ 577276788Sdelphij ND_PRINT((ndo, " %04x", access_flags)); 578214478Srpaulo } else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) { 579276788Sdelphij ND_PRINT((ndo, " NFS_ACCESS_FULL")); 580214478Srpaulo } else { 581214478Srpaulo char separator = ' '; 582214478Srpaulo if (access_flags & NFSV3ACCESS_READ) { 583276788Sdelphij ND_PRINT((ndo, " NFS_ACCESS_READ")); 584214478Srpaulo separator = '|'; 585214478Srpaulo } 586214478Srpaulo if (access_flags & NFSV3ACCESS_LOOKUP) { 587276788Sdelphij ND_PRINT((ndo, "%cNFS_ACCESS_LOOKUP", separator)); 588214478Srpaulo separator = '|'; 589214478Srpaulo } 590214478Srpaulo if (access_flags & NFSV3ACCESS_MODIFY) { 591276788Sdelphij ND_PRINT((ndo, "%cNFS_ACCESS_MODIFY", separator)); 592214478Srpaulo separator = '|'; 593214478Srpaulo } 594214478Srpaulo if (access_flags & NFSV3ACCESS_EXTEND) { 595276788Sdelphij ND_PRINT((ndo, "%cNFS_ACCESS_EXTEND", separator)); 596214478Srpaulo separator = '|'; 597214478Srpaulo } 598214478Srpaulo if (access_flags & NFSV3ACCESS_DELETE) { 599276788Sdelphij ND_PRINT((ndo, "%cNFS_ACCESS_DELETE", separator)); 600214478Srpaulo separator = '|'; 601214478Srpaulo } 602214478Srpaulo if (access_flags & NFSV3ACCESS_EXECUTE) 603276788Sdelphij ND_PRINT((ndo, "%cNFS_ACCESS_EXECUTE", separator)); 604214478Srpaulo } 60518976Sdfr return; 60618976Sdfr } 60718976Sdfr break; 60818976Sdfr 60917680Spst case NFSPROC_READ: 610276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 611276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 61218976Sdfr if (v3) { 613276788Sdelphij ND_TCHECK(dp[2]); 614276788Sdelphij ND_PRINT((ndo, " %u bytes @ %" PRIu64, 615146778Ssam EXTRACT_32BITS(&dp[2]), 616276788Sdelphij EXTRACT_64BITS(&dp[0]))); 61718976Sdfr } else { 618276788Sdelphij ND_TCHECK(dp[1]); 619276788Sdelphij ND_PRINT((ndo, " %u bytes @ %u", 620127675Sbms EXTRACT_32BITS(&dp[1]), 621276788Sdelphij EXTRACT_32BITS(&dp[0]))); 62218976Sdfr } 62317680Spst return; 62417680Spst } 62517680Spst break; 62617680Spst 62717680Spst case NFSPROC_WRITE: 628276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 629276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 63018976Sdfr if (v3) { 631327234Semaste ND_TCHECK(dp[4]); 632276788Sdelphij ND_PRINT((ndo, " %u (%u) bytes @ %" PRIu64, 633146778Ssam EXTRACT_32BITS(&dp[4]), 634146778Ssam EXTRACT_32BITS(&dp[2]), 635276788Sdelphij EXTRACT_64BITS(&dp[0]))); 636276788Sdelphij if (ndo->ndo_vflag) { 637276788Sdelphij ND_PRINT((ndo, " <%s>", 63875118Sfenner tok2str(nfsv3_writemodes, 639327234Semaste NULL, EXTRACT_32BITS(&dp[3])))); 64018976Sdfr } 64118976Sdfr } else { 642276788Sdelphij ND_TCHECK(dp[3]); 643276788Sdelphij ND_PRINT((ndo, " %u (%u) bytes @ %u (%u)", 644127675Sbms EXTRACT_32BITS(&dp[3]), 645127675Sbms EXTRACT_32BITS(&dp[2]), 646127675Sbms EXTRACT_32BITS(&dp[1]), 647276788Sdelphij EXTRACT_32BITS(&dp[0]))); 64818976Sdfr } 64917680Spst return; 65017680Spst } 65117680Spst break; 65217680Spst 65318976Sdfr case NFSPROC_SYMLINK: 654313537Sglebius if ((dp = parsereq(ndo, rp, length)) != NULL && 655313537Sglebius (dp = parsefhn(ndo, dp, v3)) != NULL) { 656276788Sdelphij ND_PRINT((ndo, " ->")); 657313537Sglebius if (v3 && (dp = parse_sattr3(ndo, dp, &sa3)) == NULL) 65818976Sdfr break; 659313537Sglebius if (parsefn(ndo, dp) == NULL) 66018976Sdfr break; 661276788Sdelphij if (v3 && ndo->ndo_vflag) 662276788Sdelphij print_sattr3(ndo, &sa3, ndo->ndo_vflag); 66318976Sdfr return; 66418976Sdfr } 66518976Sdfr break; 66618976Sdfr 66718976Sdfr case NFSPROC_MKNOD: 668313537Sglebius if ((dp = parsereq(ndo, rp, length)) != NULL && 669313537Sglebius (dp = parsefhn(ndo, dp, v3)) != NULL) { 670276788Sdelphij ND_TCHECK(*dp); 671127675Sbms type = (nfs_type)EXTRACT_32BITS(dp); 672127675Sbms dp++; 673313537Sglebius if ((dp = parse_sattr3(ndo, dp, &sa3)) == NULL) 67418976Sdfr break; 675276788Sdelphij ND_PRINT((ndo, " %s", tok2str(type2str, "unk-ft %d", type))); 676276788Sdelphij if (ndo->ndo_vflag && (type == NFCHR || type == NFBLK)) { 677276788Sdelphij ND_TCHECK(dp[1]); 678276788Sdelphij ND_PRINT((ndo, " %u/%u", 679127675Sbms EXTRACT_32BITS(&dp[0]), 680276788Sdelphij EXTRACT_32BITS(&dp[1]))); 68118976Sdfr dp += 2; 68218976Sdfr } 683276788Sdelphij if (ndo->ndo_vflag) 684276788Sdelphij print_sattr3(ndo, &sa3, ndo->ndo_vflag); 68518976Sdfr return; 68618976Sdfr } 68718976Sdfr break; 68818976Sdfr 68917680Spst case NFSPROC_RENAME: 690276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 691276788Sdelphij (dp = parsefhn(ndo, dp, v3)) != NULL) { 692276788Sdelphij ND_PRINT((ndo, " ->")); 693276788Sdelphij if (parsefhn(ndo, dp, v3) != NULL) 69417680Spst return; 69517680Spst } 69617680Spst break; 69717680Spst 69817680Spst case NFSPROC_LINK: 699276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 700276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 701276788Sdelphij ND_PRINT((ndo, " ->")); 702276788Sdelphij if (parsefhn(ndo, dp, v3) != NULL) 70317680Spst return; 70417680Spst } 70517680Spst break; 70617680Spst 70718976Sdfr case NFSPROC_READDIR: 708276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 709276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 71018976Sdfr if (v3) { 711276788Sdelphij ND_TCHECK(dp[4]); 71218976Sdfr /* 71318976Sdfr * We shouldn't really try to interpret the 71418976Sdfr * offset cookie here. 71518976Sdfr */ 716276788Sdelphij ND_PRINT((ndo, " %u bytes @ %" PRId64, 717146778Ssam EXTRACT_32BITS(&dp[4]), 718276788Sdelphij EXTRACT_64BITS(&dp[0]))); 719276788Sdelphij if (ndo->ndo_vflag) 720276788Sdelphij ND_PRINT((ndo, " verf %08x%08x", dp[2], dp[3])); 72118976Sdfr } else { 722276788Sdelphij ND_TCHECK(dp[1]); 72318976Sdfr /* 72418976Sdfr * Print the offset as signed, since -1 is 72518976Sdfr * common, but offsets > 2^31 aren't. 72618976Sdfr */ 727276788Sdelphij ND_PRINT((ndo, " %u bytes @ %d", 728127675Sbms EXTRACT_32BITS(&dp[1]), 729276788Sdelphij EXTRACT_32BITS(&dp[0]))); 73018976Sdfr } 73118976Sdfr return; 73217680Spst } 73317680Spst break; 73417680Spst 73518976Sdfr case NFSPROC_READDIRPLUS: 736276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 737276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 738276788Sdelphij ND_TCHECK(dp[4]); 73918976Sdfr /* 74018976Sdfr * We don't try to interpret the offset 74118976Sdfr * cookie here. 74218976Sdfr */ 743276788Sdelphij ND_PRINT((ndo, " %u bytes @ %" PRId64, 744146778Ssam EXTRACT_32BITS(&dp[4]), 745276788Sdelphij EXTRACT_64BITS(&dp[0]))); 746276788Sdelphij if (ndo->ndo_vflag) { 747276788Sdelphij ND_TCHECK(dp[5]); 748276788Sdelphij ND_PRINT((ndo, " max %u verf %08x%08x", 749276788Sdelphij EXTRACT_32BITS(&dp[5]), dp[2], dp[3])); 750146778Ssam } 75117680Spst return; 75218976Sdfr } 75317680Spst break; 75417680Spst 75518976Sdfr case NFSPROC_COMMIT: 756276788Sdelphij if ((dp = parsereq(ndo, rp, length)) != NULL && 757276788Sdelphij (dp = parsefh(ndo, dp, v3)) != NULL) { 758276788Sdelphij ND_TCHECK(dp[2]); 759276788Sdelphij ND_PRINT((ndo, " %u bytes @ %" PRIu64, 760146778Ssam EXTRACT_32BITS(&dp[2]), 761276788Sdelphij EXTRACT_64BITS(&dp[0]))); 76217680Spst return; 76317680Spst } 76417680Spst break; 76517680Spst 76617680Spst default: 76717680Spst return; 76817680Spst } 76975118Sfenner 77017680Spsttrunc: 77126183Sfenner if (!nfserr) 772276788Sdelphij ND_PRINT((ndo, "%s", tstr)); 77317680Spst} 77417680Spst 77517680Spst/* 77617680Spst * Print out an NFS file handle. 77717680Spst * We assume packet was not truncated before the end of the 77817680Spst * file handle pointed to by dp. 77917680Spst * 78017680Spst * Note: new version (using portable file-handle parser) doesn't produce 78117680Spst * generation number. It probably could be made to do that, with some 78217680Spst * additional hacking on the parser code. 78317680Spst */ 78417680Spststatic void 785276788Sdelphijnfs_printfh(netdissect_options *ndo, 786276788Sdelphij register const uint32_t *dp, const u_int len) 78717680Spst{ 78817680Spst my_fsid fsid; 789276788Sdelphij uint32_t ino; 790127675Sbms const char *sfsname = NULL; 791127675Sbms char *spacep; 79217680Spst 793276788Sdelphij if (ndo->ndo_uflag) { 794127675Sbms u_int i; 795127675Sbms char const *sep = ""; 79617680Spst 797276788Sdelphij ND_PRINT((ndo, " fh[")); 798127675Sbms for (i=0; i<len; i++) { 799276788Sdelphij ND_PRINT((ndo, "%s%x", sep, dp[i])); 800127675Sbms sep = ":"; 801127675Sbms } 802276788Sdelphij ND_PRINT((ndo, "]")); 803127675Sbms return; 804127675Sbms } 805127675Sbms 806127675Sbms Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0); 807127675Sbms 80817680Spst if (sfsname) { 80926183Sfenner /* file system ID is ASCII, not numeric, for this server OS */ 810327234Semaste char temp[NFSX_V3FHMAX+1]; 811327234Semaste u_int stringlen; 81217680Spst 81326183Sfenner /* Make sure string is null-terminated */ 814327234Semaste stringlen = len; 815327234Semaste if (stringlen > NFSX_V3FHMAX) 816327234Semaste stringlen = NFSX_V3FHMAX; 817327234Semaste strncpy(temp, sfsname, stringlen); 818327234Semaste temp[stringlen] = '\0'; 81926183Sfenner /* Remove trailing spaces */ 820127675Sbms spacep = strchr(temp, ' '); 821127675Sbms if (spacep) 822127675Sbms *spacep = '\0'; 82317680Spst 824276788Sdelphij ND_PRINT((ndo, " fh %s/", temp)); 82526183Sfenner } else { 826276788Sdelphij ND_PRINT((ndo, " fh %d,%d/", 827276788Sdelphij fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor)); 82817680Spst } 82975118Sfenner 830127675Sbms if(fsid.Fsid_dev.Minor == 257) 831127675Sbms /* Print the undecoded handle */ 832276788Sdelphij ND_PRINT((ndo, "%s", fsid.Opaque_Handle)); 83375118Sfenner else 834276788Sdelphij ND_PRINT((ndo, "%ld", (long) ino)); 83517680Spst} 83617680Spst 83717680Spst/* 83817680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow 83917680Spst * us to match up replies with requests and thus to know how to parse 84017680Spst * the reply. 84117680Spst */ 84217680Spst 84317680Spststruct xid_map_entry { 844276788Sdelphij uint32_t xid; /* transaction ID (net order) */ 84575118Sfenner int ipver; /* IP version (4 or 6) */ 84675118Sfenner struct in6_addr client; /* client IP address (net order) */ 84775118Sfenner struct in6_addr server; /* server IP address (net order) */ 848276788Sdelphij uint32_t proc; /* call proc number (host order) */ 849276788Sdelphij uint32_t vers; /* program version (host order) */ 85017680Spst}; 85117680Spst 85217680Spst/* 85317680Spst * Map entries are kept in an array that we manage as a ring; 85417680Spst * new entries are always added at the tail of the ring. Initially, 85517680Spst * all the entries are zero and hence don't match anything. 85617680Spst */ 85717680Spst 85817680Spst#define XIDMAPSIZE 64 85917680Spst 860313537Sglebiusstatic struct xid_map_entry xid_map[XIDMAPSIZE]; 86117680Spst 862313537Sglebiusstatic int xid_map_next = 0; 863313537Sglebiusstatic int xid_map_hint = 0; 86417680Spst 865190207Srpaulostatic int 866276788Sdelphijxid_map_enter(netdissect_options *ndo, 867276788Sdelphij const struct sunrpc_msg *rp, const u_char *bp) 86817680Spst{ 869313537Sglebius const struct ip *ip = NULL; 870313537Sglebius const struct ip6_hdr *ip6 = NULL; 87117680Spst struct xid_map_entry *xmep; 87217680Spst 873327234Semaste if (!ND_TTEST(rp->rm_call.cb_proc)) 874190207Srpaulo return (0); 875313537Sglebius switch (IP_V((const struct ip *)bp)) { 87675118Sfenner case 4: 877313537Sglebius ip = (const struct ip *)bp; 87875118Sfenner break; 87975118Sfenner case 6: 880313537Sglebius ip6 = (const struct ip6_hdr *)bp; 88175118Sfenner break; 88275118Sfenner default: 883190207Srpaulo return (1); 88475118Sfenner } 88575118Sfenner 88617680Spst xmep = &xid_map[xid_map_next]; 88717680Spst 88817680Spst if (++xid_map_next >= XIDMAPSIZE) 88917680Spst xid_map_next = 0; 89017680Spst 891276788Sdelphij UNALIGNED_MEMCPY(&xmep->xid, &rp->rm_xid, sizeof(xmep->xid)); 89275118Sfenner if (ip) { 89375118Sfenner xmep->ipver = 4; 894276788Sdelphij UNALIGNED_MEMCPY(&xmep->client, &ip->ip_src, sizeof(ip->ip_src)); 895276788Sdelphij UNALIGNED_MEMCPY(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst)); 89675118Sfenner } 89775118Sfenner else if (ip6) { 89875118Sfenner xmep->ipver = 6; 899276788Sdelphij UNALIGNED_MEMCPY(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src)); 900276788Sdelphij UNALIGNED_MEMCPY(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); 90175118Sfenner } 902127675Sbms xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 903127675Sbms xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers); 904190207Srpaulo return (1); 90517680Spst} 90617680Spst 90726183Sfenner/* 90826183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and 90926183Sfenner * version in vers return, or returns -1 on failure 91026183Sfenner */ 91118976Sdfrstatic int 912276788Sdelphijxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, uint32_t *proc, 913276788Sdelphij uint32_t *vers) 91417680Spst{ 91517680Spst int i; 91617680Spst struct xid_map_entry *xmep; 917313537Sglebius uint32_t xid; 918313537Sglebius const struct ip *ip = (const struct ip *)bp; 919313537Sglebius const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp; 92075118Sfenner int cmp; 92117680Spst 922313537Sglebius UNALIGNED_MEMCPY(&xid, &rp->rm_xid, sizeof(xmep->xid)); 92317680Spst /* Start searching from where we last left off */ 924127675Sbms i = xid_map_hint; 92517680Spst do { 92617680Spst xmep = &xid_map[i]; 92775118Sfenner cmp = 1; 92875118Sfenner if (xmep->ipver != IP_V(ip) || xmep->xid != xid) 92975118Sfenner goto nextitem; 93075118Sfenner switch (xmep->ipver) { 93175118Sfenner case 4: 932276788Sdelphij if (UNALIGNED_MEMCMP(&ip->ip_src, &xmep->server, 93375118Sfenner sizeof(ip->ip_src)) != 0 || 934276788Sdelphij UNALIGNED_MEMCMP(&ip->ip_dst, &xmep->client, 93575118Sfenner sizeof(ip->ip_dst)) != 0) { 93675118Sfenner cmp = 0; 93775118Sfenner } 93875118Sfenner break; 93975118Sfenner case 6: 940276788Sdelphij if (UNALIGNED_MEMCMP(&ip6->ip6_src, &xmep->server, 94175118Sfenner sizeof(ip6->ip6_src)) != 0 || 942276788Sdelphij UNALIGNED_MEMCMP(&ip6->ip6_dst, &xmep->client, 94375118Sfenner sizeof(ip6->ip6_dst)) != 0) { 94475118Sfenner cmp = 0; 94575118Sfenner } 94675118Sfenner break; 94775118Sfenner default: 94875118Sfenner cmp = 0; 94975118Sfenner break; 95075118Sfenner } 95175118Sfenner if (cmp) { 95217680Spst /* match */ 95317680Spst xid_map_hint = i; 95418976Sdfr *proc = xmep->proc; 95518976Sdfr *vers = xmep->vers; 95618976Sdfr return 0; 95717680Spst } 95875118Sfenner nextitem: 95917680Spst if (++i >= XIDMAPSIZE) 96017680Spst i = 0; 96117680Spst } while (i != xid_map_hint); 96217680Spst 96317680Spst /* search failed */ 96475118Sfenner return (-1); 96517680Spst} 96617680Spst 96717680Spst/* 96817680Spst * Routines for parsing reply packets 96917680Spst */ 97017680Spst 97117680Spst/* 97217680Spst * Return a pointer to the beginning of the actual results. 97375118Sfenner * If the packet was truncated, return 0. 97417680Spst */ 975276788Sdelphijstatic const uint32_t * 976276788Sdelphijparserep(netdissect_options *ndo, 977276788Sdelphij register const struct sunrpc_msg *rp, register u_int length) 97817680Spst{ 979276788Sdelphij register const uint32_t *dp; 98075118Sfenner u_int len; 981146778Ssam enum sunrpc_accept_stat astat; 98217680Spst 98317680Spst /* 98417680Spst * Portability note: 98517680Spst * Here we find the address of the ar_verf credentials. 98617680Spst * Originally, this calculation was 987276788Sdelphij * dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf 98817680Spst * On the wire, the rp_acpt field starts immediately after 98917680Spst * the (32 bit) rp_stat field. However, rp_acpt (which is a 99017680Spst * "struct accepted_reply") contains a "struct opaque_auth", 99117680Spst * whose internal representation contains a pointer, so on a 99217680Spst * 64-bit machine the compiler inserts 32 bits of padding 99317680Spst * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use 99417680Spst * the internal representation to parse the on-the-wire 99517680Spst * representation. Instead, we skip past the rp_stat field, 99617680Spst * which is an "enum" and so occupies one 32-bit word. 99717680Spst */ 998276788Sdelphij dp = ((const uint32_t *)&rp->rm_reply) + 1; 999276788Sdelphij ND_TCHECK(dp[1]); 1000127675Sbms len = EXTRACT_32BITS(&dp[1]); 100117680Spst if (len >= length) 100226183Sfenner return (NULL); 100317680Spst /* 100417680Spst * skip past the ar_verf credentials. 100517680Spst */ 1006276788Sdelphij dp += (len + (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t); 100717680Spst 100817680Spst /* 100917680Spst * now we can check the ar_stat field 101017680Spst */ 1011327234Semaste ND_TCHECK(dp[0]); 1012147904Ssam astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp); 1013276788Sdelphij if (astat != SUNRPC_SUCCESS) { 1014276788Sdelphij ND_PRINT((ndo, " %s", tok2str(sunrpc_str, "ar_stat %d", astat))); 101526183Sfenner nfserr = 1; /* suppress trunc string */ 101626183Sfenner return (NULL); 101717680Spst } 101817680Spst /* successful return */ 1019276788Sdelphij ND_TCHECK2(*dp, sizeof(astat)); 1020313537Sglebius return ((const uint32_t *) (sizeof(astat) + ((const char *)dp))); 102126183Sfennertrunc: 102275118Sfenner return (0); 102317680Spst} 102417680Spst 1025276788Sdelphijstatic const uint32_t * 1026276788Sdelphijparsestatus(netdissect_options *ndo, 1027276788Sdelphij const uint32_t *dp, int *er) 102817680Spst{ 102975118Sfenner int errnum; 103017680Spst 1031276788Sdelphij ND_TCHECK(dp[0]); 103275118Sfenner 1033127675Sbms errnum = EXTRACT_32BITS(&dp[0]); 103418976Sdfr if (er) 103526183Sfenner *er = errnum; 103626183Sfenner if (errnum != 0) { 1037276788Sdelphij if (!ndo->ndo_qflag) 1038276788Sdelphij ND_PRINT((ndo, " ERROR: %s", 1039276788Sdelphij tok2str(status2str, "unk %d", errnum))); 104026183Sfenner nfserr = 1; 104117680Spst } 104217680Spst return (dp + 1); 104326183Sfennertrunc: 104475118Sfenner return NULL; 104517680Spst} 104617680Spst 1047276788Sdelphijstatic const uint32_t * 1048276788Sdelphijparsefattr(netdissect_options *ndo, 1049276788Sdelphij const uint32_t *dp, int verbose, int v3) 105017680Spst{ 105118976Sdfr const struct nfs_fattr *fap; 105217680Spst 105318976Sdfr fap = (const struct nfs_fattr *)dp; 1054276788Sdelphij ND_TCHECK(fap->fa_gid); 105517680Spst if (verbose) { 1056276788Sdelphij ND_PRINT((ndo, " %s %o ids %d/%d", 105775118Sfenner tok2str(type2str, "unk-ft %d ", 1058127675Sbms EXTRACT_32BITS(&fap->fa_type)), 1059127675Sbms EXTRACT_32BITS(&fap->fa_mode), 1060127675Sbms EXTRACT_32BITS(&fap->fa_uid), 1061276788Sdelphij EXTRACT_32BITS(&fap->fa_gid))); 106218976Sdfr if (v3) { 1063276788Sdelphij ND_TCHECK(fap->fa3_size); 1064276788Sdelphij ND_PRINT((ndo, " sz %" PRIu64, 1065313537Sglebius EXTRACT_64BITS((const uint32_t *)&fap->fa3_size))); 106626184Sfenner } else { 1067276788Sdelphij ND_TCHECK(fap->fa2_size); 1068276788Sdelphij ND_PRINT((ndo, " sz %d", EXTRACT_32BITS(&fap->fa2_size))); 106918976Sdfr } 107017680Spst } 107117680Spst /* print lots more stuff */ 107217680Spst if (verbose > 1) { 107318976Sdfr if (v3) { 1074276788Sdelphij ND_TCHECK(fap->fa3_ctime); 1075276788Sdelphij ND_PRINT((ndo, " nlink %d rdev %d/%d", 1076127675Sbms EXTRACT_32BITS(&fap->fa_nlink), 1077127675Sbms EXTRACT_32BITS(&fap->fa3_rdev.specdata1), 1078276788Sdelphij EXTRACT_32BITS(&fap->fa3_rdev.specdata2))); 1079276788Sdelphij ND_PRINT((ndo, " fsid %" PRIx64, 1080313537Sglebius EXTRACT_64BITS((const uint32_t *)&fap->fa3_fsid))); 1081276788Sdelphij ND_PRINT((ndo, " fileid %" PRIx64, 1082313537Sglebius EXTRACT_64BITS((const uint32_t *)&fap->fa3_fileid))); 1083276788Sdelphij ND_PRINT((ndo, " a/m/ctime %u.%06u", 1084127675Sbms EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec), 1085276788Sdelphij EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec))); 1086276788Sdelphij ND_PRINT((ndo, " %u.%06u", 1087127675Sbms EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec), 1088276788Sdelphij EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec))); 1089276788Sdelphij ND_PRINT((ndo, " %u.%06u", 1090127675Sbms EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec), 1091276788Sdelphij EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec))); 109218976Sdfr } else { 1093276788Sdelphij ND_TCHECK(fap->fa2_ctime); 1094276788Sdelphij ND_PRINT((ndo, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime", 1095127675Sbms EXTRACT_32BITS(&fap->fa_nlink), 1096127675Sbms EXTRACT_32BITS(&fap->fa2_rdev), 1097127675Sbms EXTRACT_32BITS(&fap->fa2_fsid), 1098276788Sdelphij EXTRACT_32BITS(&fap->fa2_fileid))); 1099276788Sdelphij ND_PRINT((ndo, " %u.%06u", 1100127675Sbms EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec), 1101276788Sdelphij EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec))); 1102276788Sdelphij ND_PRINT((ndo, " %u.%06u", 1103127675Sbms EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec), 1104276788Sdelphij EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec))); 1105276788Sdelphij ND_PRINT((ndo, " %u.%06u", 1106127675Sbms EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec), 1107276788Sdelphij EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec))); 110818976Sdfr } 110917680Spst } 1110313537Sglebius return ((const uint32_t *)((const unsigned char *)dp + 111118976Sdfr (v3 ? NFSX_V3FATTR : NFSX_V2FATTR))); 111226184Sfennertrunc: 111326184Sfenner return (NULL); 111417680Spst} 111517680Spst 111617680Spststatic int 1117276788Sdelphijparseattrstat(netdissect_options *ndo, 1118276788Sdelphij const uint32_t *dp, int verbose, int v3) 111917680Spst{ 112018976Sdfr int er; 112118976Sdfr 1122276788Sdelphij dp = parsestatus(ndo, dp, &er); 1123111729Sfenner if (dp == NULL) 112417680Spst return (0); 1125111729Sfenner if (er) 1126111729Sfenner return (1); 112717680Spst 1128276788Sdelphij return (parsefattr(ndo, dp, verbose, v3) != NULL); 112917680Spst} 113017680Spst 113117680Spststatic int 1132276788Sdelphijparsediropres(netdissect_options *ndo, 1133276788Sdelphij const uint32_t *dp) 113417680Spst{ 113518976Sdfr int er; 113618976Sdfr 1137276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 113817680Spst return (0); 1139111729Sfenner if (er) 1140111729Sfenner return (1); 114117680Spst 1142276788Sdelphij dp = parsefh(ndo, dp, 0); 114317680Spst if (dp == NULL) 114417680Spst return (0); 114517680Spst 1146276788Sdelphij return (parsefattr(ndo, dp, ndo->ndo_vflag, 0) != NULL); 114717680Spst} 114817680Spst 114917680Spststatic int 1150276788Sdelphijparselinkres(netdissect_options *ndo, 1151276788Sdelphij const uint32_t *dp, int v3) 115217680Spst{ 115318976Sdfr int er; 115418976Sdfr 1155276788Sdelphij dp = parsestatus(ndo, dp, &er); 1156111729Sfenner if (dp == NULL) 115717680Spst return(0); 1158111729Sfenner if (er) 1159111729Sfenner return(1); 1160276788Sdelphij if (v3 && !(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 116118976Sdfr return (0); 1162276788Sdelphij ND_PRINT((ndo, " ")); 1163276788Sdelphij return (parsefn(ndo, dp) != NULL); 116417680Spst} 116517680Spst 116617680Spststatic int 1167276788Sdelphijparsestatfs(netdissect_options *ndo, 1168276788Sdelphij const uint32_t *dp, int v3) 116917680Spst{ 117018976Sdfr const struct nfs_statfs *sfsp; 117118976Sdfr int er; 117217680Spst 1173276788Sdelphij dp = parsestatus(ndo, dp, &er); 1174111729Sfenner if (dp == NULL) 117575118Sfenner return (0); 1176111729Sfenner if (!v3 && er) 1177111729Sfenner return (1); 117817680Spst 1179276788Sdelphij if (ndo->ndo_qflag) 118018976Sdfr return(1); 118118976Sdfr 118218976Sdfr if (v3) { 1183276788Sdelphij if (ndo->ndo_vflag) 1184276788Sdelphij ND_PRINT((ndo, " POST:")); 1185276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 118618976Sdfr return (0); 118717680Spst } 118817680Spst 1189276788Sdelphij ND_TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS)); 119018976Sdfr 119118976Sdfr sfsp = (const struct nfs_statfs *)dp; 119218976Sdfr 119318976Sdfr if (v3) { 1194276788Sdelphij ND_PRINT((ndo, " tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64, 1195313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfsp->sf_tbytes), 1196313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfsp->sf_fbytes), 1197313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfsp->sf_abytes))); 1198276788Sdelphij if (ndo->ndo_vflag) { 1199276788Sdelphij ND_PRINT((ndo, " tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u", 1200313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfsp->sf_tfiles), 1201313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfsp->sf_ffiles), 1202313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfsp->sf_afiles), 1203276788Sdelphij EXTRACT_32BITS(&sfsp->sf_invarsec))); 120418976Sdfr } 120518976Sdfr } else { 1206276788Sdelphij ND_PRINT((ndo, " tsize %d bsize %d blocks %d bfree %d bavail %d", 1207127675Sbms EXTRACT_32BITS(&sfsp->sf_tsize), 1208127675Sbms EXTRACT_32BITS(&sfsp->sf_bsize), 1209127675Sbms EXTRACT_32BITS(&sfsp->sf_blocks), 1210127675Sbms EXTRACT_32BITS(&sfsp->sf_bfree), 1211276788Sdelphij EXTRACT_32BITS(&sfsp->sf_bavail))); 121218976Sdfr } 121318976Sdfr 121417680Spst return (1); 121526184Sfennertrunc: 121626184Sfenner return (0); 121717680Spst} 121817680Spst 121917680Spststatic int 1220276788Sdelphijparserddires(netdissect_options *ndo, 1221276788Sdelphij const uint32_t *dp) 122217680Spst{ 122318976Sdfr int er; 122418976Sdfr 1225276788Sdelphij dp = parsestatus(ndo, dp, &er); 1226111729Sfenner if (dp == NULL) 122717680Spst return (0); 1228111729Sfenner if (er) 1229111729Sfenner return (1); 1230276788Sdelphij if (ndo->ndo_qflag) 123118976Sdfr return (1); 123218976Sdfr 1233276788Sdelphij ND_TCHECK(dp[2]); 1234276788Sdelphij ND_PRINT((ndo, " offset 0x%x size %d ", 1235276788Sdelphij EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]))); 123618976Sdfr if (dp[2] != 0) 1237276788Sdelphij ND_PRINT((ndo, " eof")); 123818976Sdfr 123918976Sdfr return (1); 124026184Sfennertrunc: 124126184Sfenner return (0); 124218976Sdfr} 124318976Sdfr 1244276788Sdelphijstatic const uint32_t * 1245276788Sdelphijparse_wcc_attr(netdissect_options *ndo, 1246276788Sdelphij const uint32_t *dp) 124718976Sdfr{ 1248327234Semaste /* Our caller has already checked this */ 1249276788Sdelphij ND_PRINT((ndo, " sz %" PRIu64, EXTRACT_64BITS(&dp[0]))); 1250276788Sdelphij ND_PRINT((ndo, " mtime %u.%06u ctime %u.%06u", 1251127675Sbms EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]), 1252276788Sdelphij EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]))); 125318976Sdfr return (dp + 6); 125418976Sdfr} 125518976Sdfr 125618976Sdfr/* 125718976Sdfr * Pre operation attributes. Print only if vflag > 1. 125818976Sdfr */ 1259276788Sdelphijstatic const uint32_t * 1260276788Sdelphijparse_pre_op_attr(netdissect_options *ndo, 1261276788Sdelphij const uint32_t *dp, int verbose) 126218976Sdfr{ 1263276788Sdelphij ND_TCHECK(dp[0]); 1264127675Sbms if (!EXTRACT_32BITS(&dp[0])) 126518976Sdfr return (dp + 1); 126618976Sdfr dp++; 1267276788Sdelphij ND_TCHECK2(*dp, 24); 126818976Sdfr if (verbose > 1) { 1269276788Sdelphij return parse_wcc_attr(ndo, dp); 127018976Sdfr } else { 127118976Sdfr /* If not verbose enough, just skip over wcc_attr */ 127218976Sdfr return (dp + 6); 127317680Spst } 127426184Sfennertrunc: 127526184Sfenner return (NULL); 127618976Sdfr} 127717680Spst 127818976Sdfr/* 127918976Sdfr * Post operation attributes are printed if vflag >= 1 128018976Sdfr */ 1281276788Sdelphijstatic const uint32_t * 1282276788Sdelphijparse_post_op_attr(netdissect_options *ndo, 1283276788Sdelphij const uint32_t *dp, int verbose) 128418976Sdfr{ 1285276788Sdelphij ND_TCHECK(dp[0]); 1286127675Sbms if (!EXTRACT_32BITS(&dp[0])) 128718976Sdfr return (dp + 1); 128818976Sdfr dp++; 128918976Sdfr if (verbose) { 1290276788Sdelphij return parsefattr(ndo, dp, verbose, 1); 129118976Sdfr } else 1292276788Sdelphij return (dp + (NFSX_V3FATTR / sizeof (uint32_t))); 129326184Sfennertrunc: 129426184Sfenner return (NULL); 129518976Sdfr} 129618976Sdfr 1297276788Sdelphijstatic const uint32_t * 1298276788Sdelphijparse_wcc_data(netdissect_options *ndo, 1299276788Sdelphij const uint32_t *dp, int verbose) 130018976Sdfr{ 130118976Sdfr if (verbose > 1) 1302276788Sdelphij ND_PRINT((ndo, " PRE:")); 1303276788Sdelphij if (!(dp = parse_pre_op_attr(ndo, dp, verbose))) 130475118Sfenner return (0); 130518976Sdfr 130618976Sdfr if (verbose) 1307276788Sdelphij ND_PRINT((ndo, " POST:")); 1308276788Sdelphij return parse_post_op_attr(ndo, dp, verbose); 130918976Sdfr} 131018976Sdfr 1311276788Sdelphijstatic const uint32_t * 1312276788Sdelphijparsecreateopres(netdissect_options *ndo, 1313276788Sdelphij const uint32_t *dp, int verbose) 131418976Sdfr{ 131518976Sdfr int er; 131618976Sdfr 1317276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 131875118Sfenner return (0); 131918976Sdfr if (er) 1320276788Sdelphij dp = parse_wcc_data(ndo, dp, verbose); 132118976Sdfr else { 1322276788Sdelphij ND_TCHECK(dp[0]); 1323127675Sbms if (!EXTRACT_32BITS(&dp[0])) 132418976Sdfr return (dp + 1); 132518976Sdfr dp++; 1326276788Sdelphij if (!(dp = parsefh(ndo, dp, 1))) 132775118Sfenner return (0); 132818976Sdfr if (verbose) { 1329276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, verbose))) 133075118Sfenner return (0); 1331276788Sdelphij if (ndo->ndo_vflag > 1) { 1332276788Sdelphij ND_PRINT((ndo, " dir attr:")); 1333276788Sdelphij dp = parse_wcc_data(ndo, dp, verbose); 133418976Sdfr } 133518976Sdfr } 133618976Sdfr } 133718976Sdfr return (dp); 133826184Sfennertrunc: 133926184Sfenner return (NULL); 134018976Sdfr} 134118976Sdfr 134218976Sdfrstatic int 1343276788Sdelphijparsewccres(netdissect_options *ndo, 1344276788Sdelphij const uint32_t *dp, int verbose) 134518976Sdfr{ 134618976Sdfr int er; 134718976Sdfr 1348276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 134918976Sdfr return (0); 1350313537Sglebius return parse_wcc_data(ndo, dp, verbose) != NULL; 135118976Sdfr} 135218976Sdfr 1353276788Sdelphijstatic const uint32_t * 1354276788Sdelphijparsev3rddirres(netdissect_options *ndo, 1355276788Sdelphij const uint32_t *dp, int verbose) 135618976Sdfr{ 135718976Sdfr int er; 135818976Sdfr 1359276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 136075118Sfenner return (0); 1361276788Sdelphij if (ndo->ndo_vflag) 1362276788Sdelphij ND_PRINT((ndo, " POST:")); 1363276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, verbose))) 136475118Sfenner return (0); 136518976Sdfr if (er) 136618976Sdfr return dp; 1367276788Sdelphij if (ndo->ndo_vflag) { 1368276788Sdelphij ND_TCHECK(dp[1]); 1369276788Sdelphij ND_PRINT((ndo, " verf %08x%08x", dp[0], dp[1])); 137018976Sdfr dp += 2; 137118976Sdfr } 137218976Sdfr return dp; 137326184Sfennertrunc: 137426184Sfenner return (NULL); 137518976Sdfr} 137618976Sdfr 137718976Sdfrstatic int 1378276788Sdelphijparsefsinfo(netdissect_options *ndo, 1379276788Sdelphij const uint32_t *dp) 138018976Sdfr{ 1381313537Sglebius const struct nfsv3_fsinfo *sfp; 138218976Sdfr int er; 138318976Sdfr 1384276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 138518976Sdfr return (0); 1386276788Sdelphij if (ndo->ndo_vflag) 1387276788Sdelphij ND_PRINT((ndo, " POST:")); 1388276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 138918976Sdfr return (0); 139018976Sdfr if (er) 139118976Sdfr return (1); 139218976Sdfr 1393313537Sglebius sfp = (const struct nfsv3_fsinfo *)dp; 1394276788Sdelphij ND_TCHECK(*sfp); 1395276788Sdelphij ND_PRINT((ndo, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u", 1396127675Sbms EXTRACT_32BITS(&sfp->fs_rtmax), 1397127675Sbms EXTRACT_32BITS(&sfp->fs_rtpref), 1398127675Sbms EXTRACT_32BITS(&sfp->fs_wtmax), 1399127675Sbms EXTRACT_32BITS(&sfp->fs_wtpref), 1400276788Sdelphij EXTRACT_32BITS(&sfp->fs_dtpref))); 1401276788Sdelphij if (ndo->ndo_vflag) { 1402276788Sdelphij ND_PRINT((ndo, " rtmult %u wtmult %u maxfsz %" PRIu64, 1403127675Sbms EXTRACT_32BITS(&sfp->fs_rtmult), 1404146778Ssam EXTRACT_32BITS(&sfp->fs_wtmult), 1405313537Sglebius EXTRACT_64BITS((const uint32_t *)&sfp->fs_maxfilesize))); 1406276788Sdelphij ND_PRINT((ndo, " delta %u.%06u ", 1407127675Sbms EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec), 1408276788Sdelphij EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec))); 140918976Sdfr } 1410111729Sfenner return (1); 1411111729Sfennertrunc: 141275118Sfenner return (0); 141318976Sdfr} 141418976Sdfr 141518976Sdfrstatic int 1416276788Sdelphijparsepathconf(netdissect_options *ndo, 1417276788Sdelphij const uint32_t *dp) 141818976Sdfr{ 141918976Sdfr int er; 1420313537Sglebius const struct nfsv3_pathconf *spp; 142118976Sdfr 1422276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 142318976Sdfr return (0); 1424276788Sdelphij if (ndo->ndo_vflag) 1425276788Sdelphij ND_PRINT((ndo, " POST:")); 1426276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 142718976Sdfr return (0); 142818976Sdfr if (er) 142918976Sdfr return (1); 143018976Sdfr 1431313537Sglebius spp = (const struct nfsv3_pathconf *)dp; 1432276788Sdelphij ND_TCHECK(*spp); 143318976Sdfr 1434276788Sdelphij ND_PRINT((ndo, " linkmax %u namemax %u %s %s %s %s", 1435127675Sbms EXTRACT_32BITS(&spp->pc_linkmax), 1436127675Sbms EXTRACT_32BITS(&spp->pc_namemax), 1437127675Sbms EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "", 1438127675Sbms EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "", 1439127675Sbms EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "", 1440276788Sdelphij EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "")); 1441111729Sfenner return (1); 1442111729Sfennertrunc: 144375118Sfenner return (0); 144417680Spst} 144575118Sfenner 144617680Spststatic void 1447276788Sdelphijinterp_reply(netdissect_options *ndo, 1448276788Sdelphij const struct sunrpc_msg *rp, uint32_t proc, uint32_t vers, int length) 144917680Spst{ 1450276788Sdelphij register const uint32_t *dp; 145118976Sdfr register int v3; 145218976Sdfr int er; 145317680Spst 145418976Sdfr v3 = (vers == NFS_VER3); 145518976Sdfr 145618976Sdfr if (!v3 && proc < NFS_NPROCS) 145718976Sdfr proc = nfsv3_procid[proc]; 145818976Sdfr 1459276788Sdelphij ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc))); 146017680Spst switch (proc) { 146117680Spst 146217680Spst case NFSPROC_GETATTR: 1463276788Sdelphij dp = parserep(ndo, rp, length); 1464276788Sdelphij if (dp != NULL && parseattrstat(ndo, dp, !ndo->ndo_qflag, v3) != 0) 146517680Spst return; 146617680Spst break; 146717680Spst 146817680Spst case NFSPROC_SETATTR: 1469276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 147017680Spst return; 147118976Sdfr if (v3) { 1472276788Sdelphij if (parsewccres(ndo, dp, ndo->ndo_vflag)) 147318976Sdfr return; 147418976Sdfr } else { 1475276788Sdelphij if (parseattrstat(ndo, dp, !ndo->ndo_qflag, 0) != 0) 147618976Sdfr return; 147718976Sdfr } 147817680Spst break; 147917680Spst 148017680Spst case NFSPROC_LOOKUP: 1481276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 148218976Sdfr break; 148318976Sdfr if (v3) { 1484276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 148518976Sdfr break; 148618976Sdfr if (er) { 1487276788Sdelphij if (ndo->ndo_vflag > 1) { 1488276788Sdelphij ND_PRINT((ndo, " post dattr:")); 1489276788Sdelphij dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag); 149018976Sdfr } 149118976Sdfr } else { 1492276788Sdelphij if (!(dp = parsefh(ndo, dp, v3))) 149318976Sdfr break; 1494276788Sdelphij if ((dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)) && 1495276788Sdelphij ndo->ndo_vflag > 1) { 1496276788Sdelphij ND_PRINT((ndo, " post dattr:")); 1497276788Sdelphij dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag); 149818976Sdfr } 149918976Sdfr } 150075118Sfenner if (dp) 150118976Sdfr return; 150218976Sdfr } else { 1503276788Sdelphij if (parsediropres(ndo, dp) != 0) 150418976Sdfr return; 150518976Sdfr } 150617680Spst break; 150717680Spst 150818976Sdfr case NFSPROC_ACCESS: 1509276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 151098527Sfenner break; 1511276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 151218976Sdfr break; 1513276788Sdelphij if (ndo->ndo_vflag) 1514276788Sdelphij ND_PRINT((ndo, " attr:")); 1515276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 151618976Sdfr break; 1517327234Semaste if (!er) { 1518327234Semaste ND_TCHECK(dp[0]); 1519276788Sdelphij ND_PRINT((ndo, " c %04x", EXTRACT_32BITS(&dp[0]))); 1520327234Semaste } 152118976Sdfr return; 152218976Sdfr 152317680Spst case NFSPROC_READLINK: 1524276788Sdelphij dp = parserep(ndo, rp, length); 1525276788Sdelphij if (dp != NULL && parselinkres(ndo, dp, v3) != 0) 152617680Spst return; 152717680Spst break; 152817680Spst 152917680Spst case NFSPROC_READ: 1530276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 153118976Sdfr break; 153218976Sdfr if (v3) { 1533276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 153418976Sdfr break; 1535276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 153618976Sdfr break; 153718976Sdfr if (er) 153818976Sdfr return; 1539276788Sdelphij if (ndo->ndo_vflag) { 1540276788Sdelphij ND_TCHECK(dp[1]); 1541276788Sdelphij ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0]))); 1542127675Sbms if (EXTRACT_32BITS(&dp[1])) 1543276788Sdelphij ND_PRINT((ndo, " EOF")); 154418976Sdfr } 154517680Spst return; 154618976Sdfr } else { 1547276788Sdelphij if (parseattrstat(ndo, dp, ndo->ndo_vflag, 0) != 0) 154818976Sdfr return; 154918976Sdfr } 155017680Spst break; 155117680Spst 155217680Spst case NFSPROC_WRITE: 1553276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 155418976Sdfr break; 155518976Sdfr if (v3) { 1556276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 155718976Sdfr break; 1558276788Sdelphij if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 155918976Sdfr break; 156018976Sdfr if (er) 156118976Sdfr return; 1562276788Sdelphij if (ndo->ndo_vflag) { 1563276788Sdelphij ND_TCHECK(dp[0]); 1564276788Sdelphij ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0]))); 1565276788Sdelphij if (ndo->ndo_vflag > 1) { 1566276788Sdelphij ND_TCHECK(dp[1]); 1567276788Sdelphij ND_PRINT((ndo, " <%s>", 156875118Sfenner tok2str(nfsv3_writemodes, 1569276788Sdelphij NULL, EXTRACT_32BITS(&dp[1])))); 157018976Sdfr } 157118976Sdfr } 1572356341Scy return; 157318976Sdfr } else { 1574276788Sdelphij if (parseattrstat(ndo, dp, ndo->ndo_vflag, v3) != 0) 157518976Sdfr return; 157618976Sdfr } 157717680Spst break; 157817680Spst 157917680Spst case NFSPROC_CREATE: 158018976Sdfr case NFSPROC_MKDIR: 1581276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 158218976Sdfr break; 158318976Sdfr if (v3) { 1584313537Sglebius if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL) 158518976Sdfr return; 158618976Sdfr } else { 1587276788Sdelphij if (parsediropres(ndo, dp) != 0) 158818976Sdfr return; 158918976Sdfr } 159018976Sdfr break; 159118976Sdfr 159218976Sdfr case NFSPROC_SYMLINK: 1593276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 159418976Sdfr break; 159518976Sdfr if (v3) { 1596313537Sglebius if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL) 159718976Sdfr return; 159818976Sdfr } else { 1599313537Sglebius if (parsestatus(ndo, dp, &er) != NULL) 160018976Sdfr return; 160118976Sdfr } 160218976Sdfr break; 160318976Sdfr 160418976Sdfr case NFSPROC_MKNOD: 1605276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 160618976Sdfr break; 1607313537Sglebius if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL) 160817680Spst return; 160917680Spst break; 161017680Spst 161117680Spst case NFSPROC_REMOVE: 161218976Sdfr case NFSPROC_RMDIR: 1613276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 161418976Sdfr break; 161518976Sdfr if (v3) { 1616276788Sdelphij if (parsewccres(ndo, dp, ndo->ndo_vflag)) 161718976Sdfr return; 161818976Sdfr } else { 1619313537Sglebius if (parsestatus(ndo, dp, &er) != NULL) 162018976Sdfr return; 162118976Sdfr } 162218976Sdfr break; 162318976Sdfr 162417680Spst case NFSPROC_RENAME: 1625276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 162618976Sdfr break; 162718976Sdfr if (v3) { 1628276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 162918976Sdfr break; 1630276788Sdelphij if (ndo->ndo_vflag) { 1631276788Sdelphij ND_PRINT((ndo, " from:")); 1632276788Sdelphij if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 163318976Sdfr break; 1634276788Sdelphij ND_PRINT((ndo, " to:")); 1635276788Sdelphij if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 163618976Sdfr break; 163718976Sdfr } 163817680Spst return; 163918976Sdfr } else { 1640313537Sglebius if (parsestatus(ndo, dp, &er) != NULL) 164118976Sdfr return; 164218976Sdfr } 164317680Spst break; 164417680Spst 164517680Spst case NFSPROC_LINK: 1646276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 164718976Sdfr break; 164818976Sdfr if (v3) { 1649276788Sdelphij if (!(dp = parsestatus(ndo, dp, &er))) 165018976Sdfr break; 1651276788Sdelphij if (ndo->ndo_vflag) { 1652276788Sdelphij ND_PRINT((ndo, " file POST:")); 1653276788Sdelphij if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 165418976Sdfr break; 1655276788Sdelphij ND_PRINT((ndo, " dir:")); 1656276788Sdelphij if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 165718976Sdfr break; 165818976Sdfr } 1659356341Scy return; 166018976Sdfr } else { 1661313537Sglebius if (parsestatus(ndo, dp, &er) != NULL) 166218976Sdfr return; 166318976Sdfr } 166417680Spst break; 166517680Spst 166618976Sdfr case NFSPROC_READDIR: 1667276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 166818976Sdfr break; 166918976Sdfr if (v3) { 1670276788Sdelphij if (parsev3rddirres(ndo, dp, ndo->ndo_vflag)) 167118976Sdfr return; 167218976Sdfr } else { 1673276788Sdelphij if (parserddires(ndo, dp) != 0) 167418976Sdfr return; 167518976Sdfr } 167618976Sdfr break; 167718976Sdfr 167818976Sdfr case NFSPROC_READDIRPLUS: 1679276788Sdelphij if (!(dp = parserep(ndo, rp, length))) 168018976Sdfr break; 1681276788Sdelphij if (parsev3rddirres(ndo, dp, ndo->ndo_vflag)) 168217680Spst return; 168317680Spst break; 168417680Spst 168518976Sdfr case NFSPROC_FSSTAT: 1686276788Sdelphij dp = parserep(ndo, rp, length); 1687276788Sdelphij if (dp != NULL && parsestatfs(ndo, dp, v3) != 0) 168817680Spst return; 168917680Spst break; 169017680Spst 169118976Sdfr case NFSPROC_FSINFO: 1692276788Sdelphij dp = parserep(ndo, rp, length); 1693276788Sdelphij if (dp != NULL && parsefsinfo(ndo, dp) != 0) 169417680Spst return; 169517680Spst break; 169617680Spst 169718976Sdfr case NFSPROC_PATHCONF: 1698276788Sdelphij dp = parserep(ndo, rp, length); 1699276788Sdelphij if (dp != NULL && parsepathconf(ndo, dp) != 0) 170017680Spst return; 170117680Spst break; 170217680Spst 170318976Sdfr case NFSPROC_COMMIT: 1704276788Sdelphij dp = parserep(ndo, rp, length); 1705276788Sdelphij if (dp != NULL && parsewccres(ndo, dp, ndo->ndo_vflag) != 0) 170617680Spst return; 170717680Spst break; 170817680Spst 170917680Spst default: 171017680Spst return; 171117680Spst } 171218976Sdfrtrunc: 171326183Sfenner if (!nfserr) 1714276788Sdelphij ND_PRINT((ndo, "%s", tstr)); 171517680Spst} 1716