]>
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
;
936 uint32_t xid
= rp
->rm_xid
;
937 struct ip
*ip
= (struct ip
*)bp
;
939 struct ip6_hdr
*ip6
= (struct ip6_hdr
*)bp
;
943 /* Start searching from where we last left off */
948 if (xmep
->ipver
!= IP_V(ip
) || xmep
->xid
!= xid
)
950 switch (xmep
->ipver
) {
952 if (UNALIGNED_MEMCMP(&ip
->ip_src
, &xmep
->server
,
953 sizeof(ip
->ip_src
)) != 0 ||
954 UNALIGNED_MEMCMP(&ip
->ip_dst
, &xmep
->client
,
955 sizeof(ip
->ip_dst
)) != 0) {
961 if (UNALIGNED_MEMCMP(&ip6
->ip6_src
, &xmep
->server
,
962 sizeof(ip6
->ip6_src
)) != 0 ||
963 UNALIGNED_MEMCMP(&ip6
->ip6_dst
, &xmep
->client
,
964 sizeof(ip6
->ip6_dst
)) != 0) {
981 if (++i
>= XIDMAPSIZE
)
983 } while (i
!= xid_map_hint
);
990 * Routines for parsing reply packets
994 * Return a pointer to the beginning of the actual results.
995 * If the packet was truncated, return 0.
997 static const uint32_t *
998 parserep(netdissect_options
*ndo
,
999 register const struct sunrpc_msg
*rp
, register u_int length
)
1001 register const uint32_t *dp
;
1003 enum sunrpc_accept_stat astat
;
1007 * Here we find the address of the ar_verf credentials.
1008 * Originally, this calculation was
1009 * dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf
1010 * On the wire, the rp_acpt field starts immediately after
1011 * the (32 bit) rp_stat field. However, rp_acpt (which is a
1012 * "struct accepted_reply") contains a "struct opaque_auth",
1013 * whose internal representation contains a pointer, so on a
1014 * 64-bit machine the compiler inserts 32 bits of padding
1015 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
1016 * the internal representation to parse the on-the-wire
1017 * representation. Instead, we skip past the rp_stat field,
1018 * which is an "enum" and so occupies one 32-bit word.
1020 dp
= ((const uint32_t *)&rp
->rm_reply
) + 1;
1022 len
= EXTRACT_32BITS(&dp
[1]);
1026 * skip past the ar_verf credentials.
1028 dp
+= (len
+ (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t);
1029 ND_TCHECK2(dp
[0], 0);
1032 * now we can check the ar_stat field
1034 astat
= (enum sunrpc_accept_stat
) EXTRACT_32BITS(dp
);
1035 if (astat
!= SUNRPC_SUCCESS
) {
1036 ND_PRINT((ndo
, " %s", tok2str(sunrpc_str
, "ar_stat %d", astat
)));
1037 nfserr
= 1; /* suppress trunc string */
1040 /* successful return */
1041 ND_TCHECK2(*dp
, sizeof(astat
));
1042 return ((uint32_t *) (sizeof(astat
) + ((char *)dp
)));
1047 static const uint32_t *
1048 parsestatus(netdissect_options
*ndo
,
1049 const uint32_t *dp
, int *er
)
1055 errnum
= EXTRACT_32BITS(&dp
[0]);
1059 if (!ndo
->ndo_qflag
)
1060 ND_PRINT((ndo
, " ERROR: %s",
1061 tok2str(status2str
, "unk %d", errnum
)));
1069 static const uint32_t *
1070 parsefattr(netdissect_options
*ndo
,
1071 const uint32_t *dp
, int verbose
, int v3
)
1073 const struct nfs_fattr
*fap
;
1075 fap
= (const struct nfs_fattr
*)dp
;
1076 ND_TCHECK(fap
->fa_gid
);
1078 ND_PRINT((ndo
, " %s %o ids %d/%d",
1079 tok2str(type2str
, "unk-ft %d ",
1080 EXTRACT_32BITS(&fap
->fa_type
)),
1081 EXTRACT_32BITS(&fap
->fa_mode
),
1082 EXTRACT_32BITS(&fap
->fa_uid
),
1083 EXTRACT_32BITS(&fap
->fa_gid
)));
1085 ND_TCHECK(fap
->fa3_size
);
1086 ND_PRINT((ndo
, " sz %" PRIu64
,
1087 EXTRACT_64BITS((uint32_t *)&fap
->fa3_size
)));
1089 ND_TCHECK(fap
->fa2_size
);
1090 ND_PRINT((ndo
, " sz %d", EXTRACT_32BITS(&fap
->fa2_size
)));
1093 /* print lots more stuff */
1096 ND_TCHECK(fap
->fa3_ctime
);
1097 ND_PRINT((ndo
, " nlink %d rdev %d/%d",
1098 EXTRACT_32BITS(&fap
->fa_nlink
),
1099 EXTRACT_32BITS(&fap
->fa3_rdev
.specdata1
),
1100 EXTRACT_32BITS(&fap
->fa3_rdev
.specdata2
)));
1101 ND_PRINT((ndo
, " fsid %" PRIx64
,
1102 EXTRACT_64BITS((uint32_t *)&fap
->fa3_fsid
)));
1103 ND_PRINT((ndo
, " fileid %" PRIx64
,
1104 EXTRACT_64BITS((uint32_t *)&fap
->fa3_fileid
)));
1105 ND_PRINT((ndo
, " a/m/ctime %u.%06u",
1106 EXTRACT_32BITS(&fap
->fa3_atime
.nfsv3_sec
),
1107 EXTRACT_32BITS(&fap
->fa3_atime
.nfsv3_nsec
)));
1108 ND_PRINT((ndo
, " %u.%06u",
1109 EXTRACT_32BITS(&fap
->fa3_mtime
.nfsv3_sec
),
1110 EXTRACT_32BITS(&fap
->fa3_mtime
.nfsv3_nsec
)));
1111 ND_PRINT((ndo
, " %u.%06u",
1112 EXTRACT_32BITS(&fap
->fa3_ctime
.nfsv3_sec
),
1113 EXTRACT_32BITS(&fap
->fa3_ctime
.nfsv3_nsec
)));
1115 ND_TCHECK(fap
->fa2_ctime
);
1116 ND_PRINT((ndo
, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime",
1117 EXTRACT_32BITS(&fap
->fa_nlink
),
1118 EXTRACT_32BITS(&fap
->fa2_rdev
),
1119 EXTRACT_32BITS(&fap
->fa2_fsid
),
1120 EXTRACT_32BITS(&fap
->fa2_fileid
)));
1121 ND_PRINT((ndo
, " %u.%06u",
1122 EXTRACT_32BITS(&fap
->fa2_atime
.nfsv2_sec
),
1123 EXTRACT_32BITS(&fap
->fa2_atime
.nfsv2_usec
)));
1124 ND_PRINT((ndo
, " %u.%06u",
1125 EXTRACT_32BITS(&fap
->fa2_mtime
.nfsv2_sec
),
1126 EXTRACT_32BITS(&fap
->fa2_mtime
.nfsv2_usec
)));
1127 ND_PRINT((ndo
, " %u.%06u",
1128 EXTRACT_32BITS(&fap
->fa2_ctime
.nfsv2_sec
),
1129 EXTRACT_32BITS(&fap
->fa2_ctime
.nfsv2_usec
)));
1132 return ((const uint32_t *)((unsigned char *)dp
+
1133 (v3
? NFSX_V3FATTR
: NFSX_V2FATTR
)));
1139 parseattrstat(netdissect_options
*ndo
,
1140 const uint32_t *dp
, int verbose
, int v3
)
1144 dp
= parsestatus(ndo
, dp
, &er
);
1150 return (parsefattr(ndo
, dp
, verbose
, v3
) != NULL
);
1154 parsediropres(netdissect_options
*ndo
,
1159 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1164 dp
= parsefh(ndo
, dp
, 0);
1168 return (parsefattr(ndo
, dp
, ndo
->ndo_vflag
, 0) != NULL
);
1172 parselinkres(netdissect_options
*ndo
,
1173 const uint32_t *dp
, int v3
)
1177 dp
= parsestatus(ndo
, dp
, &er
);
1182 if (v3
&& !(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1184 ND_PRINT((ndo
, " "));
1185 return (parsefn(ndo
, dp
) != NULL
);
1189 parsestatfs(netdissect_options
*ndo
,
1190 const uint32_t *dp
, int v3
)
1192 const struct nfs_statfs
*sfsp
;
1195 dp
= parsestatus(ndo
, dp
, &er
);
1206 ND_PRINT((ndo
, " POST:"));
1207 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1211 ND_TCHECK2(*dp
, (v3
? NFSX_V3STATFS
: NFSX_V2STATFS
));
1213 sfsp
= (const struct nfs_statfs
*)dp
;
1216 ND_PRINT((ndo
, " tbytes %" PRIu64
" fbytes %" PRIu64
" abytes %" PRIu64
,
1217 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_tbytes
),
1218 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_fbytes
),
1219 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_abytes
)));
1220 if (ndo
->ndo_vflag
) {
1221 ND_PRINT((ndo
, " tfiles %" PRIu64
" ffiles %" PRIu64
" afiles %" PRIu64
" invar %u",
1222 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_tfiles
),
1223 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_ffiles
),
1224 EXTRACT_64BITS((uint32_t *)&sfsp
->sf_afiles
),
1225 EXTRACT_32BITS(&sfsp
->sf_invarsec
)));
1228 ND_PRINT((ndo
, " tsize %d bsize %d blocks %d bfree %d bavail %d",
1229 EXTRACT_32BITS(&sfsp
->sf_tsize
),
1230 EXTRACT_32BITS(&sfsp
->sf_bsize
),
1231 EXTRACT_32BITS(&sfsp
->sf_blocks
),
1232 EXTRACT_32BITS(&sfsp
->sf_bfree
),
1233 EXTRACT_32BITS(&sfsp
->sf_bavail
)));
1242 parserddires(netdissect_options
*ndo
,
1247 dp
= parsestatus(ndo
, dp
, &er
);
1256 ND_PRINT((ndo
, " offset 0x%x size %d ",
1257 EXTRACT_32BITS(&dp
[0]), EXTRACT_32BITS(&dp
[1])));
1259 ND_PRINT((ndo
, " eof"));
1266 static const uint32_t *
1267 parse_wcc_attr(netdissect_options
*ndo
,
1270 ND_PRINT((ndo
, " sz %" PRIu64
, EXTRACT_64BITS(&dp
[0])));
1271 ND_PRINT((ndo
, " mtime %u.%06u ctime %u.%06u",
1272 EXTRACT_32BITS(&dp
[2]), EXTRACT_32BITS(&dp
[3]),
1273 EXTRACT_32BITS(&dp
[4]), EXTRACT_32BITS(&dp
[5])));
1278 * Pre operation attributes. Print only if vflag > 1.
1280 static const uint32_t *
1281 parse_pre_op_attr(netdissect_options
*ndo
,
1282 const uint32_t *dp
, int verbose
)
1285 if (!EXTRACT_32BITS(&dp
[0]))
1288 ND_TCHECK2(*dp
, 24);
1290 return parse_wcc_attr(ndo
, dp
);
1292 /* If not verbose enough, just skip over wcc_attr */
1300 * Post operation attributes are printed if vflag >= 1
1302 static const uint32_t *
1303 parse_post_op_attr(netdissect_options
*ndo
,
1304 const uint32_t *dp
, int verbose
)
1307 if (!EXTRACT_32BITS(&dp
[0]))
1311 return parsefattr(ndo
, dp
, verbose
, 1);
1313 return (dp
+ (NFSX_V3FATTR
/ sizeof (uint32_t)));
1318 static const uint32_t *
1319 parse_wcc_data(netdissect_options
*ndo
,
1320 const uint32_t *dp
, int verbose
)
1323 ND_PRINT((ndo
, " PRE:"));
1324 if (!(dp
= parse_pre_op_attr(ndo
, dp
, verbose
)))
1328 ND_PRINT((ndo
, " POST:"));
1329 return parse_post_op_attr(ndo
, dp
, verbose
);
1332 static const uint32_t *
1333 parsecreateopres(netdissect_options
*ndo
,
1334 const uint32_t *dp
, int verbose
)
1338 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1341 dp
= parse_wcc_data(ndo
, dp
, verbose
);
1344 if (!EXTRACT_32BITS(&dp
[0]))
1347 if (!(dp
= parsefh(ndo
, dp
, 1)))
1350 if (!(dp
= parse_post_op_attr(ndo
, dp
, verbose
)))
1352 if (ndo
->ndo_vflag
> 1) {
1353 ND_PRINT((ndo
, " dir attr:"));
1354 dp
= parse_wcc_data(ndo
, dp
, verbose
);
1364 parsewccres(netdissect_options
*ndo
,
1365 const uint32_t *dp
, int verbose
)
1369 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1371 return parse_wcc_data(ndo
, dp
, verbose
) != 0;
1374 static const uint32_t *
1375 parsev3rddirres(netdissect_options
*ndo
,
1376 const uint32_t *dp
, int verbose
)
1380 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1383 ND_PRINT((ndo
, " POST:"));
1384 if (!(dp
= parse_post_op_attr(ndo
, dp
, verbose
)))
1388 if (ndo
->ndo_vflag
) {
1390 ND_PRINT((ndo
, " verf %08x%08x", dp
[0], dp
[1]));
1399 parsefsinfo(netdissect_options
*ndo
,
1402 struct nfsv3_fsinfo
*sfp
;
1405 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1408 ND_PRINT((ndo
, " POST:"));
1409 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1414 sfp
= (struct nfsv3_fsinfo
*)dp
;
1416 ND_PRINT((ndo
, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1417 EXTRACT_32BITS(&sfp
->fs_rtmax
),
1418 EXTRACT_32BITS(&sfp
->fs_rtpref
),
1419 EXTRACT_32BITS(&sfp
->fs_wtmax
),
1420 EXTRACT_32BITS(&sfp
->fs_wtpref
),
1421 EXTRACT_32BITS(&sfp
->fs_dtpref
)));
1422 if (ndo
->ndo_vflag
) {
1423 ND_PRINT((ndo
, " rtmult %u wtmult %u maxfsz %" PRIu64
,
1424 EXTRACT_32BITS(&sfp
->fs_rtmult
),
1425 EXTRACT_32BITS(&sfp
->fs_wtmult
),
1426 EXTRACT_64BITS((uint32_t *)&sfp
->fs_maxfilesize
)));
1427 ND_PRINT((ndo
, " delta %u.%06u ",
1428 EXTRACT_32BITS(&sfp
->fs_timedelta
.nfsv3_sec
),
1429 EXTRACT_32BITS(&sfp
->fs_timedelta
.nfsv3_nsec
)));
1437 parsepathconf(netdissect_options
*ndo
,
1441 struct nfsv3_pathconf
*spp
;
1443 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1446 ND_PRINT((ndo
, " POST:"));
1447 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1452 spp
= (struct nfsv3_pathconf
*)dp
;
1455 ND_PRINT((ndo
, " linkmax %u namemax %u %s %s %s %s",
1456 EXTRACT_32BITS(&spp
->pc_linkmax
),
1457 EXTRACT_32BITS(&spp
->pc_namemax
),
1458 EXTRACT_32BITS(&spp
->pc_notrunc
) ? "notrunc" : "",
1459 EXTRACT_32BITS(&spp
->pc_chownrestricted
) ? "chownres" : "",
1460 EXTRACT_32BITS(&spp
->pc_caseinsensitive
) ? "igncase" : "",
1461 EXTRACT_32BITS(&spp
->pc_casepreserving
) ? "keepcase" : ""));
1468 interp_reply(netdissect_options
*ndo
,
1469 const struct sunrpc_msg
*rp
, uint32_t proc
, uint32_t vers
, int length
)
1471 register const uint32_t *dp
;
1475 v3
= (vers
== NFS_VER3
);
1477 if (!v3
&& proc
< NFS_NPROCS
)
1478 proc
= nfsv3_procid
[proc
];
1480 ND_PRINT((ndo
, " %s", tok2str(nfsproc_str
, "proc-%u", proc
)));
1483 case NFSPROC_GETATTR
:
1484 dp
= parserep(ndo
, rp
, length
);
1485 if (dp
!= NULL
&& parseattrstat(ndo
, dp
, !ndo
->ndo_qflag
, v3
) != 0)
1489 case NFSPROC_SETATTR
:
1490 if (!(dp
= parserep(ndo
, rp
, length
)))
1493 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1496 if (parseattrstat(ndo
, dp
, !ndo
->ndo_qflag
, 0) != 0)
1501 case NFSPROC_LOOKUP
:
1502 if (!(dp
= parserep(ndo
, rp
, length
)))
1505 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1508 if (ndo
->ndo_vflag
> 1) {
1509 ND_PRINT((ndo
, " post dattr:"));
1510 dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
);
1513 if (!(dp
= parsefh(ndo
, dp
, v3
)))
1515 if ((dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)) &&
1516 ndo
->ndo_vflag
> 1) {
1517 ND_PRINT((ndo
, " post dattr:"));
1518 dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
);
1524 if (parsediropres(ndo
, dp
) != 0)
1529 case NFSPROC_ACCESS
:
1530 if (!(dp
= parserep(ndo
, rp
, length
)))
1532 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1535 ND_PRINT((ndo
, " attr:"));
1536 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1539 ND_PRINT((ndo
, " c %04x", EXTRACT_32BITS(&dp
[0])));
1542 case NFSPROC_READLINK
:
1543 dp
= parserep(ndo
, rp
, length
);
1544 if (dp
!= NULL
&& parselinkres(ndo
, dp
, v3
) != 0)
1549 if (!(dp
= parserep(ndo
, rp
, length
)))
1552 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1554 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1558 if (ndo
->ndo_vflag
) {
1560 ND_PRINT((ndo
, " %u bytes", EXTRACT_32BITS(&dp
[0])));
1561 if (EXTRACT_32BITS(&dp
[1]))
1562 ND_PRINT((ndo
, " EOF"));
1566 if (parseattrstat(ndo
, dp
, ndo
->ndo_vflag
, 0) != 0)
1572 if (!(dp
= parserep(ndo
, rp
, length
)))
1575 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1577 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1581 if (ndo
->ndo_vflag
) {
1583 ND_PRINT((ndo
, " %u bytes", EXTRACT_32BITS(&dp
[0])));
1584 if (ndo
->ndo_vflag
> 1) {
1586 ND_PRINT((ndo
, " <%s>",
1587 tok2str(nfsv3_writemodes
,
1588 NULL
, EXTRACT_32BITS(&dp
[1]))));
1593 if (parseattrstat(ndo
, dp
, ndo
->ndo_vflag
, v3
) != 0)
1598 case NFSPROC_CREATE
:
1600 if (!(dp
= parserep(ndo
, rp
, length
)))
1603 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1606 if (parsediropres(ndo
, dp
) != 0)
1611 case NFSPROC_SYMLINK
:
1612 if (!(dp
= parserep(ndo
, rp
, length
)))
1615 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1618 if (parsestatus(ndo
, dp
, &er
) != 0)
1624 if (!(dp
= parserep(ndo
, rp
, length
)))
1626 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1630 case NFSPROC_REMOVE
:
1632 if (!(dp
= parserep(ndo
, rp
, length
)))
1635 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1638 if (parsestatus(ndo
, dp
, &er
) != 0)
1643 case NFSPROC_RENAME
:
1644 if (!(dp
= parserep(ndo
, rp
, length
)))
1647 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1649 if (ndo
->ndo_vflag
) {
1650 ND_PRINT((ndo
, " from:"));
1651 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1653 ND_PRINT((ndo
, " to:"));
1654 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1659 if (parsestatus(ndo
, dp
, &er
) != 0)
1665 if (!(dp
= parserep(ndo
, rp
, length
)))
1668 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1670 if (ndo
->ndo_vflag
) {
1671 ND_PRINT((ndo
, " file POST:"));
1672 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1674 ND_PRINT((ndo
, " dir:"));
1675 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1680 if (parsestatus(ndo
, dp
, &er
) != 0)
1685 case NFSPROC_READDIR
:
1686 if (!(dp
= parserep(ndo
, rp
, length
)))
1689 if (parsev3rddirres(ndo
, dp
, ndo
->ndo_vflag
))
1692 if (parserddires(ndo
, dp
) != 0)
1697 case NFSPROC_READDIRPLUS
:
1698 if (!(dp
= parserep(ndo
, rp
, length
)))
1700 if (parsev3rddirres(ndo
, dp
, ndo
->ndo_vflag
))
1704 case NFSPROC_FSSTAT
:
1705 dp
= parserep(ndo
, rp
, length
);
1706 if (dp
!= NULL
&& parsestatfs(ndo
, dp
, v3
) != 0)
1710 case NFSPROC_FSINFO
:
1711 dp
= parserep(ndo
, rp
, length
);
1712 if (dp
!= NULL
&& parsefsinfo(ndo
, dp
) != 0)
1716 case NFSPROC_PATHCONF
:
1717 dp
= parserep(ndo
, rp
, length
);
1718 if (dp
!= NULL
&& parsepathconf(ndo
, dp
) != 0)
1722 case NFSPROC_COMMIT
:
1723 dp
= parserep(ndo
, rp
, length
);
1724 if (dp
!= NULL
&& parsewccres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1733 ND_PRINT((ndo
, "%s", tstr
));