]>
The Tcpdump Group git mirrors - tcpdump/blob - print-nfs.c
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 #define NETDISSECT_REWORKED
27 #include <tcpdump-stdinc.h>
32 #include "interface.h"
33 #include "addrtoname.h"
46 static const char tstr
[] = " [|nfs]";
48 static void nfs_printfh(netdissect_options
*, const uint32_t *, const u_int
);
49 static int xid_map_enter(netdissect_options
*, const struct sunrpc_msg
*, const u_char
*);
50 static int xid_map_find(const struct sunrpc_msg
*, const u_char
*,
51 uint32_t *, uint32_t *);
52 static void interp_reply(netdissect_options
*, const struct sunrpc_msg
*, uint32_t, uint32_t, int);
53 static const uint32_t *parse_post_op_attr(netdissect_options
*, const uint32_t *, int);
56 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
58 uint32_t nfsv3_procid
[NFS_NPROCS
] = {
87 static const struct tok nfsproc_str
[] = {
88 { NFSPROC_NOOP
, "nop" },
89 { NFSPROC_NULL
, "null" },
90 { NFSPROC_GETATTR
, "getattr" },
91 { NFSPROC_SETATTR
, "setattr" },
92 { NFSPROC_LOOKUP
, "lookup" },
93 { NFSPROC_ACCESS
, "access" },
94 { NFSPROC_READLINK
, "readlink" },
95 { NFSPROC_READ
, "read" },
96 { NFSPROC_WRITE
, "write" },
97 { NFSPROC_CREATE
, "create" },
98 { NFSPROC_MKDIR
, "mkdir" },
99 { NFSPROC_SYMLINK
, "symlink" },
100 { NFSPROC_MKNOD
, "mknod" },
101 { NFSPROC_REMOVE
, "remove" },
102 { NFSPROC_RMDIR
, "rmdir" },
103 { NFSPROC_RENAME
, "rename" },
104 { NFSPROC_LINK
, "link" },
105 { NFSPROC_READDIR
, "readdir" },
106 { NFSPROC_READDIRPLUS
, "readdirplus" },
107 { NFSPROC_FSSTAT
, "fsstat" },
108 { NFSPROC_FSINFO
, "fsinfo" },
109 { NFSPROC_PATHCONF
, "pathconf" },
110 { NFSPROC_COMMIT
, "commit" },
115 * NFS V2 and V3 status values.
117 * Some of these come from the RFCs for NFS V2 and V3, with the message
118 * strings taken from the FreeBSD C library "errlst.c".
120 * Others are errors that are not in the RFC but that I suspect some
121 * NFS servers could return; the values are FreeBSD errno values, as
122 * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
123 * was primarily BSD-derived.
125 static const struct tok status2str
[] = {
126 { 1, "Operation not permitted" }, /* EPERM */
127 { 2, "No such file or directory" }, /* ENOENT */
128 { 5, "Input/output error" }, /* EIO */
129 { 6, "Device not configured" }, /* ENXIO */
130 { 11, "Resource deadlock avoided" }, /* EDEADLK */
131 { 12, "Cannot allocate memory" }, /* ENOMEM */
132 { 13, "Permission denied" }, /* EACCES */
133 { 17, "File exists" }, /* EEXIST */
134 { 18, "Cross-device link" }, /* EXDEV */
135 { 19, "Operation not supported by device" }, /* ENODEV */
136 { 20, "Not a directory" }, /* ENOTDIR */
137 { 21, "Is a directory" }, /* EISDIR */
138 { 22, "Invalid argument" }, /* EINVAL */
139 { 26, "Text file busy" }, /* ETXTBSY */
140 { 27, "File too large" }, /* EFBIG */
141 { 28, "No space left on device" }, /* ENOSPC */
142 { 30, "Read-only file system" }, /* EROFS */
143 { 31, "Too many links" }, /* EMLINK */
144 { 45, "Operation not supported" }, /* EOPNOTSUPP */
145 { 62, "Too many levels of symbolic links" }, /* ELOOP */
146 { 63, "File name too long" }, /* ENAMETOOLONG */
147 { 66, "Directory not empty" }, /* ENOTEMPTY */
148 { 69, "Disc quota exceeded" }, /* EDQUOT */
149 { 70, "Stale NFS file handle" }, /* ESTALE */
150 { 71, "Too many levels of remote in path" }, /* EREMOTE */
151 { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
152 { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */
153 { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
154 { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
155 { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */
156 { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
157 { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
158 { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
159 { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
163 static const struct tok nfsv3_writemodes
[] = {
170 static const struct tok type2str
[] = {
181 static const struct tok sunrpc_auth_str
[] = {
182 { SUNRPC_AUTH_OK
, "OK" },
183 { SUNRPC_AUTH_BADCRED
, "Bogus Credentials (seal broken)" },
184 { SUNRPC_AUTH_REJECTEDCRED
, "Rejected Credentials (client should begin new session)" },
185 { SUNRPC_AUTH_BADVERF
, "Bogus Verifier (seal broken)" },
186 { SUNRPC_AUTH_REJECTEDVERF
, "Verifier expired or was replayed" },
187 { SUNRPC_AUTH_TOOWEAK
, "Credentials are too weak" },
188 { SUNRPC_AUTH_INVALIDRESP
, "Bogus response verifier" },
189 { SUNRPC_AUTH_FAILED
, "Unknown failure" },
193 static const struct tok sunrpc_str
[] = {
194 { SUNRPC_PROG_UNAVAIL
, "PROG_UNAVAIL" },
195 { SUNRPC_PROG_MISMATCH
, "PROG_MISMATCH" },
196 { SUNRPC_PROC_UNAVAIL
, "PROC_UNAVAIL" },
197 { SUNRPC_GARBAGE_ARGS
, "GARBAGE_ARGS" },
198 { SUNRPC_SYSTEM_ERR
, "SYSTEM_ERR" },
203 print_nfsaddr(netdissect_options
*ndo
,
204 const u_char
*bp
, const char *s
, const char *d
)
209 char srcaddr
[INET6_ADDRSTRLEN
], dstaddr
[INET6_ADDRSTRLEN
];
211 #ifndef INET_ADDRSTRLEN
212 #define INET_ADDRSTRLEN 16
214 char srcaddr
[INET_ADDRSTRLEN
], dstaddr
[INET_ADDRSTRLEN
];
217 srcaddr
[0] = dstaddr
[0] = '\0';
218 switch (IP_V((struct ip
*)bp
)) {
220 ip
= (struct ip
*)bp
;
221 strlcpy(srcaddr
, ipaddr_string(ndo
, &ip
->ip_src
), sizeof(srcaddr
));
222 strlcpy(dstaddr
, ipaddr_string(ndo
, &ip
->ip_dst
), sizeof(dstaddr
));
226 ip6
= (struct ip6_hdr
*)bp
;
227 strlcpy(srcaddr
, ip6addr_string(ndo
, &ip6
->ip6_src
),
229 strlcpy(dstaddr
, ip6addr_string(ndo
, &ip6
->ip6_dst
),
234 strlcpy(srcaddr
, "?", sizeof(srcaddr
));
235 strlcpy(dstaddr
, "?", sizeof(dstaddr
));
239 ND_PRINT((ndo
, "%s.%s > %s.%s: ", srcaddr
, s
, dstaddr
, d
));
242 static const uint32_t *
243 parse_sattr3(netdissect_options
*ndo
,
244 const uint32_t *dp
, struct nfsv3_sattr
*sa3
)
247 sa3
->sa_modeset
= EXTRACT_32BITS(dp
);
249 if (sa3
->sa_modeset
) {
251 sa3
->sa_mode
= EXTRACT_32BITS(dp
);
256 sa3
->sa_uidset
= EXTRACT_32BITS(dp
);
258 if (sa3
->sa_uidset
) {
260 sa3
->sa_uid
= EXTRACT_32BITS(dp
);
265 sa3
->sa_gidset
= EXTRACT_32BITS(dp
);
267 if (sa3
->sa_gidset
) {
269 sa3
->sa_gid
= EXTRACT_32BITS(dp
);
274 sa3
->sa_sizeset
= EXTRACT_32BITS(dp
);
276 if (sa3
->sa_sizeset
) {
278 sa3
->sa_size
= EXTRACT_32BITS(dp
);
283 sa3
->sa_atimetype
= EXTRACT_32BITS(dp
);
285 if (sa3
->sa_atimetype
== NFSV3SATTRTIME_TOCLIENT
) {
287 sa3
->sa_atime
.nfsv3_sec
= EXTRACT_32BITS(dp
);
289 sa3
->sa_atime
.nfsv3_nsec
= EXTRACT_32BITS(dp
);
294 sa3
->sa_mtimetype
= EXTRACT_32BITS(dp
);
296 if (sa3
->sa_mtimetype
== NFSV3SATTRTIME_TOCLIENT
) {
298 sa3
->sa_mtime
.nfsv3_sec
= EXTRACT_32BITS(dp
);
300 sa3
->sa_mtime
.nfsv3_nsec
= EXTRACT_32BITS(dp
);
309 static int nfserr
; /* true if we error rather than trunc */
312 print_sattr3(netdissect_options
*ndo
,
313 const struct nfsv3_sattr
*sa3
, int verbose
)
316 ND_PRINT((ndo
, " mode %o", sa3
->sa_mode
));
318 ND_PRINT((ndo
, " uid %u", sa3
->sa_uid
));
320 ND_PRINT((ndo
, " gid %u", sa3
->sa_gid
));
322 if (sa3
->sa_atimetype
== NFSV3SATTRTIME_TOCLIENT
)
323 ND_PRINT((ndo
, " atime %u.%06u", sa3
->sa_atime
.nfsv3_sec
,
324 sa3
->sa_atime
.nfsv3_nsec
));
325 if (sa3
->sa_mtimetype
== NFSV3SATTRTIME_TOCLIENT
)
326 ND_PRINT((ndo
, " mtime %u.%06u", sa3
->sa_mtime
.nfsv3_sec
,
327 sa3
->sa_mtime
.nfsv3_nsec
));
332 nfsreply_print(netdissect_options
*ndo
,
333 register const u_char
*bp
, u_int length
,
334 register const u_char
*bp2
)
336 register const struct sunrpc_msg
*rp
;
337 char srcid
[20], dstid
[20]; /*fits 32bit*/
339 nfserr
= 0; /* assume no error */
340 rp
= (const struct sunrpc_msg
*)bp
;
342 ND_TCHECK(rp
->rm_xid
);
343 if (!ndo
->ndo_nflag
) {
344 strlcpy(srcid
, "nfs", sizeof(srcid
));
345 snprintf(dstid
, sizeof(dstid
), "%u",
346 EXTRACT_32BITS(&rp
->rm_xid
));
348 snprintf(srcid
, sizeof(srcid
), "%u", NFS_PORT
);
349 snprintf(dstid
, sizeof(dstid
), "%u",
350 EXTRACT_32BITS(&rp
->rm_xid
));
352 print_nfsaddr(ndo
, bp2
, srcid
, dstid
);
354 nfsreply_print_noaddr(ndo
, bp
, length
, bp2
);
359 ND_PRINT((ndo
, "%s", tstr
));
363 nfsreply_print_noaddr(netdissect_options
*ndo
,
364 register const u_char
*bp
, u_int length
,
365 register const u_char
*bp2
)
367 register const struct sunrpc_msg
*rp
;
368 uint32_t proc
, vers
, reply_stat
;
369 enum sunrpc_reject_stat rstat
;
372 enum sunrpc_auth_stat rwhy
;
374 nfserr
= 0; /* assume no error */
375 rp
= (const struct sunrpc_msg
*)bp
;
377 ND_TCHECK(rp
->rm_reply
.rp_stat
);
378 reply_stat
= EXTRACT_32BITS(&rp
->rm_reply
.rp_stat
);
379 switch (reply_stat
) {
381 case SUNRPC_MSG_ACCEPTED
:
382 ND_PRINT((ndo
, "reply ok %u", length
));
383 if (xid_map_find(rp
, bp2
, &proc
, &vers
) >= 0)
384 interp_reply(ndo
, rp
, proc
, vers
, length
);
387 case SUNRPC_MSG_DENIED
:
388 ND_PRINT((ndo
, "reply ERR %u: ", length
));
389 ND_TCHECK(rp
->rm_reply
.rp_reject
.rj_stat
);
390 rstat
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_stat
);
393 case SUNRPC_RPC_MISMATCH
:
394 ND_TCHECK(rp
->rm_reply
.rp_reject
.rj_vers
.high
);
395 rlow
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_vers
.low
);
396 rhigh
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_vers
.high
);
397 ND_PRINT((ndo
, "RPC Version mismatch (%u-%u)", rlow
, rhigh
));
400 case SUNRPC_AUTH_ERROR
:
401 ND_TCHECK(rp
->rm_reply
.rp_reject
.rj_why
);
402 rwhy
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_why
);
403 ND_PRINT((ndo
, "Auth %s", tok2str(sunrpc_auth_str
, "Invalid failure code %u", rwhy
)));
407 ND_PRINT((ndo
, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat
));
413 ND_PRINT((ndo
, "reply Unknown rpc response code=%u %u", reply_stat
, length
));
420 ND_PRINT((ndo
, "%s", tstr
));
424 * Return a pointer to the first file handle in the packet.
425 * If the packet was truncated, return 0.
427 static const uint32_t *
428 parsereq(netdissect_options
*ndo
,
429 register const struct sunrpc_msg
*rp
, register u_int length
)
431 register const uint32_t *dp
;
435 * find the start of the req data (if we captured it)
437 dp
= (uint32_t *)&rp
->rm_call
.cb_cred
;
439 len
= EXTRACT_32BITS(&dp
[1]);
441 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
443 len
= EXTRACT_32BITS(&dp
[1]);
445 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
446 ND_TCHECK2(dp
[0], 0);
455 * Print out an NFS file handle and return a pointer to following word.
456 * If packet was truncated, return 0.
458 static const uint32_t *
459 parsefh(netdissect_options
*ndo
,
460 register const uint32_t *dp
, int v3
)
466 len
= EXTRACT_32BITS(dp
) / 4;
471 if (ND_TTEST2(*dp
, len
* sizeof(*dp
))) {
472 nfs_printfh(ndo
, dp
, len
);
480 * Print out a file name and return pointer to 32-bit word past it.
481 * If packet was truncated, return 0.
483 static const uint32_t *
484 parsefn(netdissect_options
*ndo
,
485 register const uint32_t *dp
)
487 register uint32_t len
;
488 register const u_char
*cp
;
490 /* Bail if we don't have the string length */
493 /* Fetch string length; convert to host order */
497 ND_TCHECK2(*dp
, ((len
+ 3) & ~3));
500 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
501 dp
+= ((len
+ 3) & ~3) / sizeof(*dp
);
502 ND_PRINT((ndo
, "\""));
503 if (fn_printn(ndo
, cp
, len
, ndo
->ndo_snapend
)) {
504 ND_PRINT((ndo
, "\""));
507 ND_PRINT((ndo
, "\""));
515 * Print out file handle and file name.
516 * Return pointer to 32-bit word past file name.
517 * If packet was truncated (or there was some other error), return 0.
519 static const uint32_t *
520 parsefhn(netdissect_options
*ndo
,
521 register const uint32_t *dp
, int v3
)
523 dp
= parsefh(ndo
, dp
, v3
);
526 ND_PRINT((ndo
, " "));
527 return (parsefn(ndo
, dp
));
531 nfsreq_print_noaddr(netdissect_options
*ndo
,
532 register const u_char
*bp
, u_int length
,
533 register const u_char
*bp2
)
535 register const struct sunrpc_msg
*rp
;
536 register const uint32_t *dp
;
540 uint32_t access_flags
;
541 struct nfsv3_sattr sa3
;
543 ND_PRINT((ndo
, "%d", length
));
544 nfserr
= 0; /* assume no error */
545 rp
= (const struct sunrpc_msg
*)bp
;
547 if (!xid_map_enter(ndo
, rp
, bp2
)) /* record proc number for later on */
550 v3
= (EXTRACT_32BITS(&rp
->rm_call
.cb_vers
) == NFS_VER3
);
551 proc
= EXTRACT_32BITS(&rp
->rm_call
.cb_proc
);
553 if (!v3
&& proc
< NFS_NPROCS
)
554 proc
= nfsv3_procid
[proc
];
556 ND_PRINT((ndo
, " %s", tok2str(nfsproc_str
, "proc-%u", proc
)));
559 case NFSPROC_GETATTR
:
560 case NFSPROC_SETATTR
:
561 case NFSPROC_READLINK
:
564 case NFSPROC_PATHCONF
:
565 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
566 parsefh(ndo
, dp
, v3
) != NULL
)
575 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
576 parsefhn(ndo
, dp
, v3
) != NULL
)
581 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
582 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
584 access_flags
= EXTRACT_32BITS(&dp
[0]);
585 if (access_flags
& ~NFSV3ACCESS_FULL
) {
586 /* NFSV3ACCESS definitions aren't up to date */
587 ND_PRINT((ndo
, " %04x", access_flags
));
588 } else if ((access_flags
& NFSV3ACCESS_FULL
) == NFSV3ACCESS_FULL
) {
589 ND_PRINT((ndo
, " NFS_ACCESS_FULL"));
591 char separator
= ' ';
592 if (access_flags
& NFSV3ACCESS_READ
) {
593 ND_PRINT((ndo
, " NFS_ACCESS_READ"));
596 if (access_flags
& NFSV3ACCESS_LOOKUP
) {
597 ND_PRINT((ndo
, "%cNFS_ACCESS_LOOKUP", separator
));
600 if (access_flags
& NFSV3ACCESS_MODIFY
) {
601 ND_PRINT((ndo
, "%cNFS_ACCESS_MODIFY", separator
));
604 if (access_flags
& NFSV3ACCESS_EXTEND
) {
605 ND_PRINT((ndo
, "%cNFS_ACCESS_EXTEND", separator
));
608 if (access_flags
& NFSV3ACCESS_DELETE
) {
609 ND_PRINT((ndo
, "%cNFS_ACCESS_DELETE", separator
));
612 if (access_flags
& NFSV3ACCESS_EXECUTE
)
613 ND_PRINT((ndo
, "%cNFS_ACCESS_EXECUTE", separator
));
620 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
621 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
624 ND_PRINT((ndo
, " %u bytes @ %" PRIu64
,
625 EXTRACT_32BITS(&dp
[2]),
626 EXTRACT_64BITS(&dp
[0])));
629 ND_PRINT((ndo
, " %u bytes @ %u",
630 EXTRACT_32BITS(&dp
[1]),
631 EXTRACT_32BITS(&dp
[0])));
638 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
639 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
642 ND_PRINT((ndo
, " %u (%u) bytes @ %" PRIu64
,
643 EXTRACT_32BITS(&dp
[4]),
644 EXTRACT_32BITS(&dp
[2]),
645 EXTRACT_64BITS(&dp
[0])));
646 if (ndo
->ndo_vflag
) {
649 ND_PRINT((ndo
, " <%s>",
650 tok2str(nfsv3_writemodes
,
651 NULL
, EXTRACT_32BITS(dp
))));
655 ND_PRINT((ndo
, " %u (%u) bytes @ %u (%u)",
656 EXTRACT_32BITS(&dp
[3]),
657 EXTRACT_32BITS(&dp
[2]),
658 EXTRACT_32BITS(&dp
[1]),
659 EXTRACT_32BITS(&dp
[0])));
665 case NFSPROC_SYMLINK
:
666 if ((dp
= parsereq(ndo
, rp
, length
)) != 0 &&
667 (dp
= parsefhn(ndo
, dp
, v3
)) != 0) {
668 ND_PRINT((ndo
, " ->"));
669 if (v3
&& (dp
= parse_sattr3(ndo
, dp
, &sa3
)) == 0)
671 if (parsefn(ndo
, dp
) == 0)
673 if (v3
&& ndo
->ndo_vflag
)
674 print_sattr3(ndo
, &sa3
, ndo
->ndo_vflag
);
680 if ((dp
= parsereq(ndo
, rp
, length
)) != 0 &&
681 (dp
= parsefhn(ndo
, dp
, v3
)) != 0) {
683 type
= (nfs_type
)EXTRACT_32BITS(dp
);
685 if ((dp
= parse_sattr3(ndo
, dp
, &sa3
)) == 0)
687 ND_PRINT((ndo
, " %s", tok2str(type2str
, "unk-ft %d", type
)));
688 if (ndo
->ndo_vflag
&& (type
== NFCHR
|| type
== NFBLK
)) {
690 ND_PRINT((ndo
, " %u/%u",
691 EXTRACT_32BITS(&dp
[0]),
692 EXTRACT_32BITS(&dp
[1])));
696 print_sattr3(ndo
, &sa3
, ndo
->ndo_vflag
);
702 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
703 (dp
= parsefhn(ndo
, dp
, v3
)) != NULL
) {
704 ND_PRINT((ndo
, " ->"));
705 if (parsefhn(ndo
, dp
, v3
) != NULL
)
711 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
712 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
713 ND_PRINT((ndo
, " ->"));
714 if (parsefhn(ndo
, dp
, v3
) != NULL
)
719 case NFSPROC_READDIR
:
720 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
721 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
725 * We shouldn't really try to interpret the
726 * offset cookie here.
728 ND_PRINT((ndo
, " %u bytes @ %" PRId64
,
729 EXTRACT_32BITS(&dp
[4]),
730 EXTRACT_64BITS(&dp
[0])));
732 ND_PRINT((ndo
, " verf %08x%08x", dp
[2], dp
[3]));
736 * Print the offset as signed, since -1 is
737 * common, but offsets > 2^31 aren't.
739 ND_PRINT((ndo
, " %u bytes @ %d",
740 EXTRACT_32BITS(&dp
[1]),
741 EXTRACT_32BITS(&dp
[0])));
747 case NFSPROC_READDIRPLUS
:
748 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
749 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
752 * We don't try to interpret the offset
755 ND_PRINT((ndo
, " %u bytes @ %" PRId64
,
756 EXTRACT_32BITS(&dp
[4]),
757 EXTRACT_64BITS(&dp
[0])));
758 if (ndo
->ndo_vflag
) {
760 ND_PRINT((ndo
, " max %u verf %08x%08x",
761 EXTRACT_32BITS(&dp
[5]), dp
[2], dp
[3]));
768 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
769 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
771 ND_PRINT((ndo
, " %u bytes @ %" PRIu64
,
772 EXTRACT_32BITS(&dp
[2]),
773 EXTRACT_64BITS(&dp
[0])));
784 ND_PRINT((ndo
, "%s", tstr
));
788 * Print out an NFS file handle.
789 * We assume packet was not truncated before the end of the
790 * file handle pointed to by dp.
792 * Note: new version (using portable file-handle parser) doesn't produce
793 * generation number. It probably could be made to do that, with some
794 * additional hacking on the parser code.
797 nfs_printfh(netdissect_options
*ndo
,
798 register const uint32_t *dp
, const u_int len
)
802 const char *sfsname
= NULL
;
805 if (ndo
->ndo_uflag
) {
807 char const *sep
= "";
809 ND_PRINT((ndo
, " fh["));
810 for (i
=0; i
<len
; i
++) {
811 ND_PRINT((ndo
, "%s%x", sep
, dp
[i
]));
814 ND_PRINT((ndo
, "]"));
818 Parse_fh((const u_char
*)dp
, len
, &fsid
, &ino
, NULL
, &sfsname
, 0);
821 /* file system ID is ASCII, not numeric, for this server OS */
822 static char temp
[NFSX_V3FHMAX
+1];
824 /* Make sure string is null-terminated */
825 strncpy(temp
, sfsname
, NFSX_V3FHMAX
);
826 temp
[sizeof(temp
) - 1] = '\0';
827 /* Remove trailing spaces */
828 spacep
= strchr(temp
, ' ');
832 ND_PRINT((ndo
, " fh %s/", temp
));
834 ND_PRINT((ndo
, " fh %d,%d/",
835 fsid
.Fsid_dev
.Major
, fsid
.Fsid_dev
.Minor
));
838 if(fsid
.Fsid_dev
.Minor
== 257)
839 /* Print the undecoded handle */
840 ND_PRINT((ndo
, "%s", fsid
.Opaque_Handle
));
842 ND_PRINT((ndo
, "%ld", (long) ino
));
846 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
847 * us to match up replies with requests and thus to know how to parse
851 struct xid_map_entry
{
852 uint32_t xid
; /* transaction ID (net order) */
853 int ipver
; /* IP version (4 or 6) */
855 struct in6_addr client
; /* client IP address (net order) */
856 struct in6_addr server
; /* server IP address (net order) */
858 struct in_addr client
; /* client IP address (net order) */
859 struct in_addr server
; /* server IP address (net order) */
861 uint32_t proc
; /* call proc number (host order) */
862 uint32_t vers
; /* program version (host order) */
866 * Map entries are kept in an array that we manage as a ring;
867 * new entries are always added at the tail of the ring. Initially,
868 * all the entries are zero and hence don't match anything.
871 #define XIDMAPSIZE 64
873 struct xid_map_entry xid_map
[XIDMAPSIZE
];
875 int xid_map_next
= 0;
876 int xid_map_hint
= 0;
879 xid_map_enter(netdissect_options
*ndo
,
880 const struct sunrpc_msg
*rp
, const u_char
*bp
)
882 struct ip
*ip
= NULL
;
884 struct ip6_hdr
*ip6
= NULL
;
886 struct xid_map_entry
*xmep
;
888 if (!ND_TTEST(rp
->rm_call
.cb_vers
))
890 switch (IP_V((struct ip
*)bp
)) {
892 ip
= (struct ip
*)bp
;
896 ip6
= (struct ip6_hdr
*)bp
;
903 xmep
= &xid_map
[xid_map_next
];
905 if (++xid_map_next
>= XIDMAPSIZE
)
908 UNALIGNED_MEMCPY(&xmep
->xid
, &rp
->rm_xid
, sizeof(xmep
->xid
));
911 UNALIGNED_MEMCPY(&xmep
->client
, &ip
->ip_src
, sizeof(ip
->ip_src
));
912 UNALIGNED_MEMCPY(&xmep
->server
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
917 UNALIGNED_MEMCPY(&xmep
->client
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
918 UNALIGNED_MEMCPY(&xmep
->server
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
921 xmep
->proc
= EXTRACT_32BITS(&rp
->rm_call
.cb_proc
);
922 xmep
->vers
= EXTRACT_32BITS(&rp
->rm_call
.cb_vers
);
927 * Returns 0 and puts NFSPROC_xxx in proc return and
928 * version in vers return, or returns -1 on failure
931 xid_map_find(const struct sunrpc_msg
*rp
, const u_char
*bp
, uint32_t *proc
,
935 struct xid_map_entry
*xmep
;
937 struct ip
*ip
= (struct ip
*)bp
;
939 struct ip6_hdr
*ip6
= (struct ip6_hdr
*)bp
;
943 UNALIGNED_MEMCPY(&xid
, &rp
->rm_xid
, sizeof(xmep
->xid
));
944 /* Start searching from where we last left off */
949 if (xmep
->ipver
!= IP_V(ip
) || xmep
->xid
!= xid
)
951 switch (xmep
->ipver
) {
953 if (UNALIGNED_MEMCMP(&ip
->ip_src
, &xmep
->server
,
954 sizeof(ip
->ip_src
)) != 0 ||
955 UNALIGNED_MEMCMP(&ip
->ip_dst
, &xmep
->client
,
956 sizeof(ip
->ip_dst
)) != 0) {
962 if (UNALIGNED_MEMCMP(&ip6
->ip6_src
, &xmep
->server
,
963 sizeof(ip6
->ip6_src
)) != 0 ||
964 UNALIGNED_MEMCMP(&ip6
->ip6_dst
, &xmep
->client
,
965 sizeof(ip6
->ip6_dst
)) != 0) {
982 if (++i
>= XIDMAPSIZE
)
984 } while (i
!= xid_map_hint
);
991 * Routines for parsing reply packets
995 * Return a pointer to the beginning of the actual results.
996 * If the packet was truncated, return 0.
998 static const uint32_t *
999 parserep(netdissect_options
*ndo
,
1000 register const struct sunrpc_msg
*rp
, register u_int length
)
1002 register const uint32_t *dp
;
1004 enum sunrpc_accept_stat astat
;
1008 * Here we find the address of the ar_verf credentials.
1009 * Originally, this calculation was
1010 * dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf
1011 * On the wire, the rp_acpt field starts immediately after
1012 * the (32 bit) rp_stat field. However, rp_acpt (which is a
1013 * "struct accepted_reply") contains a "struct opaque_auth",
1014 * whose internal representation contains a pointer, so on a
1015 * 64-bit machine the compiler inserts 32 bits of padding
1016 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
1017 * the internal representation to parse the on-the-wire
1018 * representation. Instead, we skip past the rp_stat field,
1019 * which is an "enum" and so occupies one 32-bit word.
1021 dp
= ((const uint32_t *)&rp
->rm_reply
) + 1;
1023 len
= EXTRACT_32BITS(&dp
[1]);
1027 * skip past the ar_verf credentials.
1029 dp
+= (len
+ (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t);
1030 ND_TCHECK2(dp
[0], 0);
1033 * now we can check the ar_stat field
1035 astat
= (enum sunrpc_accept_stat
) EXTRACT_32BITS(dp
);
1036 if (astat
!= SUNRPC_SUCCESS
) {
1037 ND_PRINT((ndo
, " %s", tok2str(sunrpc_str
, "ar_stat %d", astat
)));
1038 nfserr
= 1; /* suppress trunc string */
1041 /* successful return */
1042 ND_TCHECK2(*dp
, sizeof(astat
));
1043 return ((uint32_t *) (sizeof(astat
) + ((char *)dp
)));
1048 static const uint32_t *
1049 parsestatus(netdissect_options
*ndo
,
1050 const uint32_t *dp
, int *er
)
1056 errnum
= EXTRACT_32BITS(&dp
[0]);
1060 if (!ndo
->ndo_qflag
)
1061 ND_PRINT((ndo
, " ERROR: %s",
1062 tok2str(status2str
, "unk %d", errnum
)));
1070 static const uint32_t *
1071 parsefattr(netdissect_options
*ndo
,
1072 const uint32_t *dp
, int verbose
, int v3
)
1074 const struct nfs_fattr
*fap
;
1076 fap
= (const struct nfs_fattr
*)dp
;
1077 ND_TCHECK(fap
->fa_gid
);
1079 ND_PRINT((ndo
, " %s %o ids %d/%d",
1080 tok2str(type2str
, "unk-ft %d ",
1081 EXTRACT_32BITS(&fap
->fa_type
)),
1082 EXTRACT_32BITS(&fap
->fa_mode
),
1083 EXTRACT_32BITS(&fap
->fa_uid
),
1084 EXTRACT_32BITS(&fap
->fa_gid
)));
1086 ND_TCHECK(fap
->fa3_size
);
1087 ND_PRINT((ndo
, " sz %" PRIu64
,
1088 EXTRACT_64BITS((uint32_t *)&fap
->fa3_size
)));
1090 ND_TCHECK(fap
->fa2_size
);
1091 ND_PRINT((ndo
, " sz %d", EXTRACT_32BITS(&fap
->fa2_size
)));
1094 /* print lots more stuff */
1097 ND_TCHECK(fap
->fa3_ctime
);
1098 ND_PRINT((ndo
, " nlink %d rdev %d/%d",
1099 EXTRACT_32BITS(&fap
->fa_nlink
),
1100 EXTRACT_32BITS(&fap
->fa3_rdev
.specdata1
),
1101 EXTRACT_32BITS(&fap
->fa3_rdev
.specdata2
)));
1102 ND_PRINT((ndo
, " fsid %" PRIx64
,
1103 EXTRACT_64BITS((uint32_t *)&fap
->fa3_fsid
)));
1104 ND_PRINT((ndo
, " fileid %" PRIx64
,
1105 EXTRACT_64BITS((uint32_t *)&fap
->fa3_fileid
)));
1106 ND_PRINT((ndo
, " a/m/ctime %u.%06u",
1107 EXTRACT_32BITS(&fap
->fa3_atime
.nfsv3_sec
),
1108 EXTRACT_32BITS(&fap
->fa3_atime
.nfsv3_nsec
)));
1109 ND_PRINT((ndo
, " %u.%06u",
1110 EXTRACT_32BITS(&fap
->fa3_mtime
.nfsv3_sec
),
1111 EXTRACT_32BITS(&fap
->fa3_mtime
.nfsv3_nsec
)));
1112 ND_PRINT((ndo
, " %u.%06u",
1113 EXTRACT_32BITS(&fap
->fa3_ctime
.nfsv3_sec
),
1114 EXTRACT_32BITS(&fap
->fa3_ctime
.nfsv3_nsec
)));
1116 ND_TCHECK(fap
->fa2_ctime
);
1117 ND_PRINT((ndo
, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime",
1118 EXTRACT_32BITS(&fap
->fa_nlink
),
1119 EXTRACT_32BITS(&fap
->fa2_rdev
),
1120 EXTRACT_32BITS(&fap
->fa2_fsid
),
1121 EXTRACT_32BITS(&fap
->fa2_fileid
)));
1122 ND_PRINT((ndo
, " %u.%06u",
1123 EXTRACT_32BITS(&fap
->fa2_atime
.nfsv2_sec
),
1124 EXTRACT_32BITS(&fap
->fa2_atime
.nfsv2_usec
)));
1125 ND_PRINT((ndo
, " %u.%06u",
1126 EXTRACT_32BITS(&fap
->fa2_mtime
.nfsv2_sec
),
1127 EXTRACT_32BITS(&fap
->fa2_mtime
.nfsv2_usec
)));
1128 ND_PRINT((ndo
, " %u.%06u",
1129 EXTRACT_32BITS(&fap
->fa2_ctime
.nfsv2_sec
),
1130 EXTRACT_32BITS(&fap
->fa2_ctime
.nfsv2_usec
)));
1133 return ((const uint32_t *)((unsigned char *)dp
+
1134 (v3
? NFSX_V3FATTR
: NFSX_V2FATTR
)));
1140 parseattrstat(netdissect_options
*ndo
,
1141 const uint32_t *dp
, int verbose
, int v3
)
1145 dp
= parsestatus(ndo
, dp
, &er
);
1151 return (parsefattr(ndo
, dp
, verbose
, v3
) != NULL
);
1155 parsediropres(netdissect_options
*ndo
,
1160 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1165 dp
= parsefh(ndo
, dp
, 0);
1169 return (parsefattr(ndo
, dp
, ndo
->ndo_vflag
, 0) != NULL
);
1173 parselinkres(netdissect_options
*ndo
,
1174 const uint32_t *dp
, int v3
)
1178 dp
= parsestatus(ndo
, dp
, &er
);
1183 if (v3
&& !(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1185 ND_PRINT((ndo
, " "));
1186 return (parsefn(ndo
, dp
) != NULL
);
1190 parsestatfs(netdissect_options
*ndo
,
1191 const uint32_t *dp
, int v3
)
1193 const struct nfs_statfs
*sfsp
;
1196 dp
= parsestatus(ndo
, dp
, &er
);
1207 ND_PRINT((ndo
, " POST:"));
1208 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1212 ND_TCHECK2(*dp
, (v3
? NFSX_V3STATFS
: NFSX_V2STATFS
));
1214 sfsp
= (const struct nfs_statfs
*)dp
;
1217 ND_PRINT((ndo
, " tbytes %" PRIu64
" fbytes %" PRIu64
" abytes %" PRIu64
,
1218 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_tbytes
),
1219 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_fbytes
),
1220 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_abytes
)));
1221 if (ndo
->ndo_vflag
) {
1222 ND_PRINT((ndo
, " tfiles %" PRIu64
" ffiles %" PRIu64
" afiles %" PRIu64
" invar %u",
1223 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_tfiles
),
1224 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_ffiles
),
1225 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_afiles
),
1226 EXTRACT_32BITS(&sfsp
->sf_invarsec
)));
1229 ND_PRINT((ndo
, " tsize %d bsize %d blocks %d bfree %d bavail %d",
1230 EXTRACT_32BITS(&sfsp
->sf_tsize
),
1231 EXTRACT_32BITS(&sfsp
->sf_bsize
),
1232 EXTRACT_32BITS(&sfsp
->sf_blocks
),
1233 EXTRACT_32BITS(&sfsp
->sf_bfree
),
1234 EXTRACT_32BITS(&sfsp
->sf_bavail
)));
1243 parserddires(netdissect_options
*ndo
,
1248 dp
= parsestatus(ndo
, dp
, &er
);
1257 ND_PRINT((ndo
, " offset 0x%x size %d ",
1258 EXTRACT_32BITS(&dp
[0]), EXTRACT_32BITS(&dp
[1])));
1260 ND_PRINT((ndo
, " eof"));
1267 static const uint32_t *
1268 parse_wcc_attr(netdissect_options
*ndo
,
1271 ND_PRINT((ndo
, " sz %" PRIu64
, EXTRACT_64BITS(&dp
[0])));
1272 ND_PRINT((ndo
, " mtime %u.%06u ctime %u.%06u",
1273 EXTRACT_32BITS(&dp
[2]), EXTRACT_32BITS(&dp
[3]),
1274 EXTRACT_32BITS(&dp
[4]), EXTRACT_32BITS(&dp
[5])));
1279 * Pre operation attributes. Print only if vflag > 1.
1281 static const uint32_t *
1282 parse_pre_op_attr(netdissect_options
*ndo
,
1283 const uint32_t *dp
, int verbose
)
1286 if (!EXTRACT_32BITS(&dp
[0]))
1289 ND_TCHECK2(*dp
, 24);
1291 return parse_wcc_attr(ndo
, dp
);
1293 /* If not verbose enough, just skip over wcc_attr */
1301 * Post operation attributes are printed if vflag >= 1
1303 static const uint32_t *
1304 parse_post_op_attr(netdissect_options
*ndo
,
1305 const uint32_t *dp
, int verbose
)
1308 if (!EXTRACT_32BITS(&dp
[0]))
1312 return parsefattr(ndo
, dp
, verbose
, 1);
1314 return (dp
+ (NFSX_V3FATTR
/ sizeof (uint32_t)));
1319 static const uint32_t *
1320 parse_wcc_data(netdissect_options
*ndo
,
1321 const uint32_t *dp
, int verbose
)
1324 ND_PRINT((ndo
, " PRE:"));
1325 if (!(dp
= parse_pre_op_attr(ndo
, dp
, verbose
)))
1329 ND_PRINT((ndo
, " POST:"));
1330 return parse_post_op_attr(ndo
, dp
, verbose
);
1333 static const uint32_t *
1334 parsecreateopres(netdissect_options
*ndo
,
1335 const uint32_t *dp
, int verbose
)
1339 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1342 dp
= parse_wcc_data(ndo
, dp
, verbose
);
1345 if (!EXTRACT_32BITS(&dp
[0]))
1348 if (!(dp
= parsefh(ndo
, dp
, 1)))
1351 if (!(dp
= parse_post_op_attr(ndo
, dp
, verbose
)))
1353 if (ndo
->ndo_vflag
> 1) {
1354 ND_PRINT((ndo
, " dir attr:"));
1355 dp
= parse_wcc_data(ndo
, dp
, verbose
);
1365 parsewccres(netdissect_options
*ndo
,
1366 const uint32_t *dp
, int verbose
)
1370 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1372 return parse_wcc_data(ndo
, dp
, verbose
) != 0;
1375 static const uint32_t *
1376 parsev3rddirres(netdissect_options
*ndo
,
1377 const uint32_t *dp
, int verbose
)
1381 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1384 ND_PRINT((ndo
, " POST:"));
1385 if (!(dp
= parse_post_op_attr(ndo
, dp
, verbose
)))
1389 if (ndo
->ndo_vflag
) {
1391 ND_PRINT((ndo
, " verf %08x%08x", dp
[0], dp
[1]));
1400 parsefsinfo(netdissect_options
*ndo
,
1403 struct nfsv3_fsinfo
*sfp
;
1406 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1409 ND_PRINT((ndo
, " POST:"));
1410 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1415 sfp
= (struct nfsv3_fsinfo
*)dp
;
1417 ND_PRINT((ndo
, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1418 EXTRACT_32BITS(&sfp
->fs_rtmax
),
1419 EXTRACT_32BITS(&sfp
->fs_rtpref
),
1420 EXTRACT_32BITS(&sfp
->fs_wtmax
),
1421 EXTRACT_32BITS(&sfp
->fs_wtpref
),
1422 EXTRACT_32BITS(&sfp
->fs_dtpref
)));
1423 if (ndo
->ndo_vflag
) {
1424 ND_PRINT((ndo
, " rtmult %u wtmult %u maxfsz %" PRIu64
,
1425 EXTRACT_32BITS(&sfp
->fs_rtmult
),
1426 EXTRACT_32BITS(&sfp
->fs_wtmult
),
1427 EXTRACT_64BITS((uint32_t *)&sfp
->fs_maxfilesize
)));
1428 ND_PRINT((ndo
, " delta %u.%06u ",
1429 EXTRACT_32BITS(&sfp
->fs_timedelta
.nfsv3_sec
),
1430 EXTRACT_32BITS(&sfp
->fs_timedelta
.nfsv3_nsec
)));
1438 parsepathconf(netdissect_options
*ndo
,
1442 struct nfsv3_pathconf
*spp
;
1444 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1447 ND_PRINT((ndo
, " POST:"));
1448 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1453 spp
= (struct nfsv3_pathconf
*)dp
;
1456 ND_PRINT((ndo
, " linkmax %u namemax %u %s %s %s %s",
1457 EXTRACT_32BITS(&spp
->pc_linkmax
),
1458 EXTRACT_32BITS(&spp
->pc_namemax
),
1459 EXTRACT_32BITS(&spp
->pc_notrunc
) ? "notrunc" : "",
1460 EXTRACT_32BITS(&spp
->pc_chownrestricted
) ? "chownres" : "",
1461 EXTRACT_32BITS(&spp
->pc_caseinsensitive
) ? "igncase" : "",
1462 EXTRACT_32BITS(&spp
->pc_casepreserving
) ? "keepcase" : ""));
1469 interp_reply(netdissect_options
*ndo
,
1470 const struct sunrpc_msg
*rp
, uint32_t proc
, uint32_t vers
, int length
)
1472 register const uint32_t *dp
;
1476 v3
= (vers
== NFS_VER3
);
1478 if (!v3
&& proc
< NFS_NPROCS
)
1479 proc
= nfsv3_procid
[proc
];
1481 ND_PRINT((ndo
, " %s", tok2str(nfsproc_str
, "proc-%u", proc
)));
1484 case NFSPROC_GETATTR
:
1485 dp
= parserep(ndo
, rp
, length
);
1486 if (dp
!= NULL
&& parseattrstat(ndo
, dp
, !ndo
->ndo_qflag
, v3
) != 0)
1490 case NFSPROC_SETATTR
:
1491 if (!(dp
= parserep(ndo
, rp
, length
)))
1494 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1497 if (parseattrstat(ndo
, dp
, !ndo
->ndo_qflag
, 0) != 0)
1502 case NFSPROC_LOOKUP
:
1503 if (!(dp
= parserep(ndo
, rp
, length
)))
1506 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1509 if (ndo
->ndo_vflag
> 1) {
1510 ND_PRINT((ndo
, " post dattr:"));
1511 dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
);
1514 if (!(dp
= parsefh(ndo
, dp
, v3
)))
1516 if ((dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)) &&
1517 ndo
->ndo_vflag
> 1) {
1518 ND_PRINT((ndo
, " post dattr:"));
1519 dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
);
1525 if (parsediropres(ndo
, dp
) != 0)
1530 case NFSPROC_ACCESS
:
1531 if (!(dp
= parserep(ndo
, rp
, length
)))
1533 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1536 ND_PRINT((ndo
, " attr:"));
1537 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1540 ND_PRINT((ndo
, " c %04x", EXTRACT_32BITS(&dp
[0])));
1543 case NFSPROC_READLINK
:
1544 dp
= parserep(ndo
, rp
, length
);
1545 if (dp
!= NULL
&& parselinkres(ndo
, dp
, v3
) != 0)
1550 if (!(dp
= parserep(ndo
, rp
, length
)))
1553 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1555 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1559 if (ndo
->ndo_vflag
) {
1561 ND_PRINT((ndo
, " %u bytes", EXTRACT_32BITS(&dp
[0])));
1562 if (EXTRACT_32BITS(&dp
[1]))
1563 ND_PRINT((ndo
, " EOF"));
1567 if (parseattrstat(ndo
, dp
, ndo
->ndo_vflag
, 0) != 0)
1573 if (!(dp
= parserep(ndo
, rp
, length
)))
1576 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1578 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1582 if (ndo
->ndo_vflag
) {
1584 ND_PRINT((ndo
, " %u bytes", EXTRACT_32BITS(&dp
[0])));
1585 if (ndo
->ndo_vflag
> 1) {
1587 ND_PRINT((ndo
, " <%s>",
1588 tok2str(nfsv3_writemodes
,
1589 NULL
, EXTRACT_32BITS(&dp
[1]))));
1594 if (parseattrstat(ndo
, dp
, ndo
->ndo_vflag
, v3
) != 0)
1599 case NFSPROC_CREATE
:
1601 if (!(dp
= parserep(ndo
, rp
, length
)))
1604 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1607 if (parsediropres(ndo
, dp
) != 0)
1612 case NFSPROC_SYMLINK
:
1613 if (!(dp
= parserep(ndo
, rp
, length
)))
1616 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1619 if (parsestatus(ndo
, dp
, &er
) != 0)
1625 if (!(dp
= parserep(ndo
, rp
, length
)))
1627 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1631 case NFSPROC_REMOVE
:
1633 if (!(dp
= parserep(ndo
, rp
, length
)))
1636 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1639 if (parsestatus(ndo
, dp
, &er
) != 0)
1644 case NFSPROC_RENAME
:
1645 if (!(dp
= parserep(ndo
, rp
, length
)))
1648 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1650 if (ndo
->ndo_vflag
) {
1651 ND_PRINT((ndo
, " from:"));
1652 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1654 ND_PRINT((ndo
, " to:"));
1655 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1660 if (parsestatus(ndo
, dp
, &er
) != 0)
1666 if (!(dp
= parserep(ndo
, rp
, length
)))
1669 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1671 if (ndo
->ndo_vflag
) {
1672 ND_PRINT((ndo
, " file POST:"));
1673 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1675 ND_PRINT((ndo
, " dir:"));
1676 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1681 if (parsestatus(ndo
, dp
, &er
) != 0)
1686 case NFSPROC_READDIR
:
1687 if (!(dp
= parserep(ndo
, rp
, length
)))
1690 if (parsev3rddirres(ndo
, dp
, ndo
->ndo_vflag
))
1693 if (parserddires(ndo
, dp
) != 0)
1698 case NFSPROC_READDIRPLUS
:
1699 if (!(dp
= parserep(ndo
, rp
, length
)))
1701 if (parsev3rddirres(ndo
, dp
, ndo
->ndo_vflag
))
1705 case NFSPROC_FSSTAT
:
1706 dp
= parserep(ndo
, rp
, length
);
1707 if (dp
!= NULL
&& parsestatfs(ndo
, dp
, v3
) != 0)
1711 case NFSPROC_FSINFO
:
1712 dp
= parserep(ndo
, rp
, length
);
1713 if (dp
!= NULL
&& parsefsinfo(ndo
, dp
) != 0)
1717 case NFSPROC_PATHCONF
:
1718 dp
= parserep(ndo
, rp
, length
);
1719 if (dp
!= NULL
&& parsepathconf(ndo
, dp
) != 0)
1723 case NFSPROC_COMMIT
:
1724 dp
= parserep(ndo
, rp
, length
);
1725 if (dp
!= NULL
&& parsewccres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1734 ND_PRINT((ndo
, "%s", tstr
));