]>
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 u_int32_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 u_int32_t
*, u_int32_t
*);
52 static void interp_reply(netdissect_options
*, const struct sunrpc_msg
*, u_int32_t
, u_int32_t
, int);
53 static const u_int32_t
*parse_post_op_attr(netdissect_options
*, const u_int32_t
*, int);
56 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
58 u_int32_t nfsv3_procid
[NFS_NPROCS
] = {
88 * NFS V2 and V3 status values.
90 * Some of these come from the RFCs for NFS V2 and V3, with the message
91 * strings taken from the FreeBSD C library "errlst.c".
93 * Others are errors that are not in the RFC but that I suspect some
94 * NFS servers could return; the values are FreeBSD errno values, as
95 * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
96 * was primarily BSD-derived.
98 static const struct tok status2str
[] = {
99 { 1, "Operation not permitted" }, /* EPERM */
100 { 2, "No such file or directory" }, /* ENOENT */
101 { 5, "Input/output error" }, /* EIO */
102 { 6, "Device not configured" }, /* ENXIO */
103 { 11, "Resource deadlock avoided" }, /* EDEADLK */
104 { 12, "Cannot allocate memory" }, /* ENOMEM */
105 { 13, "Permission denied" }, /* EACCES */
106 { 17, "File exists" }, /* EEXIST */
107 { 18, "Cross-device link" }, /* EXDEV */
108 { 19, "Operation not supported by device" }, /* ENODEV */
109 { 20, "Not a directory" }, /* ENOTDIR */
110 { 21, "Is a directory" }, /* EISDIR */
111 { 22, "Invalid argument" }, /* EINVAL */
112 { 26, "Text file busy" }, /* ETXTBSY */
113 { 27, "File too large" }, /* EFBIG */
114 { 28, "No space left on device" }, /* ENOSPC */
115 { 30, "Read-only file system" }, /* EROFS */
116 { 31, "Too many links" }, /* EMLINK */
117 { 45, "Operation not supported" }, /* EOPNOTSUPP */
118 { 62, "Too many levels of symbolic links" }, /* ELOOP */
119 { 63, "File name too long" }, /* ENAMETOOLONG */
120 { 66, "Directory not empty" }, /* ENOTEMPTY */
121 { 69, "Disc quota exceeded" }, /* EDQUOT */
122 { 70, "Stale NFS file handle" }, /* ESTALE */
123 { 71, "Too many levels of remote in path" }, /* EREMOTE */
124 { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
125 { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */
126 { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
127 { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
128 { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */
129 { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
130 { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
131 { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
132 { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
136 static const struct tok nfsv3_writemodes
[] = {
143 static const struct tok type2str
[] = {
155 print_nfsaddr(netdissect_options
*ndo
,
156 const u_char
*bp
, const char *s
, const char *d
)
161 char srcaddr
[INET6_ADDRSTRLEN
], dstaddr
[INET6_ADDRSTRLEN
];
163 #ifndef INET_ADDRSTRLEN
164 #define INET_ADDRSTRLEN 16
166 char srcaddr
[INET_ADDRSTRLEN
], dstaddr
[INET_ADDRSTRLEN
];
169 srcaddr
[0] = dstaddr
[0] = '\0';
170 switch (IP_V((struct ip
*)bp
)) {
172 ip
= (struct ip
*)bp
;
173 strlcpy(srcaddr
, ipaddr_string(ndo
, &ip
->ip_src
), sizeof(srcaddr
));
174 strlcpy(dstaddr
, ipaddr_string(ndo
, &ip
->ip_dst
), sizeof(dstaddr
));
178 ip6
= (struct ip6_hdr
*)bp
;
179 strlcpy(srcaddr
, ip6addr_string(ndo
, &ip6
->ip6_src
),
181 strlcpy(dstaddr
, ip6addr_string(ndo
, &ip6
->ip6_dst
),
186 strlcpy(srcaddr
, "?", sizeof(srcaddr
));
187 strlcpy(dstaddr
, "?", sizeof(dstaddr
));
191 ND_PRINT((ndo
, "%s.%s > %s.%s: ", srcaddr
, s
, dstaddr
, d
));
194 static const u_int32_t
*
195 parse_sattr3(netdissect_options
*ndo
,
196 const u_int32_t
*dp
, struct nfsv3_sattr
*sa3
)
199 sa3
->sa_modeset
= EXTRACT_32BITS(dp
);
201 if (sa3
->sa_modeset
) {
203 sa3
->sa_mode
= EXTRACT_32BITS(dp
);
208 sa3
->sa_uidset
= EXTRACT_32BITS(dp
);
210 if (sa3
->sa_uidset
) {
212 sa3
->sa_uid
= EXTRACT_32BITS(dp
);
217 sa3
->sa_gidset
= EXTRACT_32BITS(dp
);
219 if (sa3
->sa_gidset
) {
221 sa3
->sa_gid
= EXTRACT_32BITS(dp
);
226 sa3
->sa_sizeset
= EXTRACT_32BITS(dp
);
228 if (sa3
->sa_sizeset
) {
230 sa3
->sa_size
= EXTRACT_32BITS(dp
);
235 sa3
->sa_atimetype
= EXTRACT_32BITS(dp
);
237 if (sa3
->sa_atimetype
== NFSV3SATTRTIME_TOCLIENT
) {
239 sa3
->sa_atime
.nfsv3_sec
= EXTRACT_32BITS(dp
);
241 sa3
->sa_atime
.nfsv3_nsec
= EXTRACT_32BITS(dp
);
246 sa3
->sa_mtimetype
= EXTRACT_32BITS(dp
);
248 if (sa3
->sa_mtimetype
== NFSV3SATTRTIME_TOCLIENT
) {
250 sa3
->sa_mtime
.nfsv3_sec
= EXTRACT_32BITS(dp
);
252 sa3
->sa_mtime
.nfsv3_nsec
= EXTRACT_32BITS(dp
);
261 static int nfserr
; /* true if we error rather than trunc */
264 print_sattr3(netdissect_options
*ndo
,
265 const struct nfsv3_sattr
*sa3
, int verbose
)
268 ND_PRINT((ndo
, " mode %o", sa3
->sa_mode
));
270 ND_PRINT((ndo
, " uid %u", sa3
->sa_uid
));
272 ND_PRINT((ndo
, " gid %u", sa3
->sa_gid
));
274 if (sa3
->sa_atimetype
== NFSV3SATTRTIME_TOCLIENT
)
275 ND_PRINT((ndo
, " atime %u.%06u", sa3
->sa_atime
.nfsv3_sec
,
276 sa3
->sa_atime
.nfsv3_nsec
));
277 if (sa3
->sa_mtimetype
== NFSV3SATTRTIME_TOCLIENT
)
278 ND_PRINT((ndo
, " mtime %u.%06u", sa3
->sa_mtime
.nfsv3_sec
,
279 sa3
->sa_mtime
.nfsv3_nsec
));
284 nfsreply_print(netdissect_options
*ndo
,
285 register const u_char
*bp
, u_int length
,
286 register const u_char
*bp2
)
288 register const struct sunrpc_msg
*rp
;
289 char srcid
[20], dstid
[20]; /*fits 32bit*/
291 nfserr
= 0; /* assume no error */
292 rp
= (const struct sunrpc_msg
*)bp
;
294 ND_TCHECK(rp
->rm_xid
);
295 if (!ndo
->ndo_nflag
) {
296 strlcpy(srcid
, "nfs", sizeof(srcid
));
297 snprintf(dstid
, sizeof(dstid
), "%u",
298 EXTRACT_32BITS(&rp
->rm_xid
));
300 snprintf(srcid
, sizeof(srcid
), "%u", NFS_PORT
);
301 snprintf(dstid
, sizeof(dstid
), "%u",
302 EXTRACT_32BITS(&rp
->rm_xid
));
304 print_nfsaddr(ndo
, bp2
, srcid
, dstid
);
306 nfsreply_print_noaddr(ndo
, bp
, length
, bp2
);
311 ND_PRINT((ndo
, "%s", tstr
));
315 nfsreply_print_noaddr(netdissect_options
*ndo
,
316 register const u_char
*bp
, u_int length
,
317 register const u_char
*bp2
)
319 register const struct sunrpc_msg
*rp
;
320 u_int32_t proc
, vers
, reply_stat
;
321 enum sunrpc_reject_stat rstat
;
324 enum sunrpc_auth_stat rwhy
;
326 nfserr
= 0; /* assume no error */
327 rp
= (const struct sunrpc_msg
*)bp
;
329 ND_TCHECK(rp
->rm_reply
.rp_stat
);
330 reply_stat
= EXTRACT_32BITS(&rp
->rm_reply
.rp_stat
);
331 switch (reply_stat
) {
333 case SUNRPC_MSG_ACCEPTED
:
334 ND_PRINT((ndo
, "reply ok %u", length
));
335 if (xid_map_find(rp
, bp2
, &proc
, &vers
) >= 0)
336 interp_reply(ndo
, rp
, proc
, vers
, length
);
339 case SUNRPC_MSG_DENIED
:
340 ND_PRINT((ndo
, "reply ERR %u: ", length
));
341 ND_TCHECK(rp
->rm_reply
.rp_reject
.rj_stat
);
342 rstat
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_stat
);
345 case SUNRPC_RPC_MISMATCH
:
346 ND_TCHECK(rp
->rm_reply
.rp_reject
.rj_vers
.high
);
347 rlow
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_vers
.low
);
348 rhigh
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_vers
.high
);
349 ND_PRINT((ndo
, "RPC Version mismatch (%u-%u)", rlow
, rhigh
));
352 case SUNRPC_AUTH_ERROR
:
353 ND_TCHECK(rp
->rm_reply
.rp_reject
.rj_why
);
354 rwhy
= EXTRACT_32BITS(&rp
->rm_reply
.rp_reject
.rj_why
);
355 ND_PRINT((ndo
, "Auth "));
359 ND_PRINT((ndo
, "OK"));
362 case SUNRPC_AUTH_BADCRED
:
363 ND_PRINT((ndo
, "Bogus Credentials (seal broken)"));
366 case SUNRPC_AUTH_REJECTEDCRED
:
367 ND_PRINT((ndo
, "Rejected Credentials (client should begin new session)"));
370 case SUNRPC_AUTH_BADVERF
:
371 ND_PRINT((ndo
, "Bogus Verifier (seal broken)"));
374 case SUNRPC_AUTH_REJECTEDVERF
:
375 ND_PRINT((ndo
, "Verifier expired or was replayed"));
378 case SUNRPC_AUTH_TOOWEAK
:
379 ND_PRINT((ndo
, "Credentials are too weak"));
382 case SUNRPC_AUTH_INVALIDRESP
:
383 ND_PRINT((ndo
, "Bogus response verifier"));
386 case SUNRPC_AUTH_FAILED
:
387 ND_PRINT((ndo
, "Unknown failure"));
391 ND_PRINT((ndo
, "Invalid failure code %u", (unsigned int)rwhy
));
397 ND_PRINT((ndo
, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat
));
403 ND_PRINT((ndo
, "reply Unknown rpc response code=%u %u", reply_stat
, length
));
410 ND_PRINT((ndo
, "%s", tstr
));
414 * Return a pointer to the first file handle in the packet.
415 * If the packet was truncated, return 0.
417 static const u_int32_t
*
418 parsereq(netdissect_options
*ndo
,
419 register const struct sunrpc_msg
*rp
, register u_int length
)
421 register const u_int32_t
*dp
;
425 * find the start of the req data (if we captured it)
427 dp
= (u_int32_t
*)&rp
->rm_call
.cb_cred
;
429 len
= EXTRACT_32BITS(&dp
[1]);
431 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
433 len
= EXTRACT_32BITS(&dp
[1]);
435 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
436 ND_TCHECK2(dp
[0], 0);
445 * Print out an NFS file handle and return a pointer to following word.
446 * If packet was truncated, return 0.
448 static const u_int32_t
*
449 parsefh(netdissect_options
*ndo
,
450 register const u_int32_t
*dp
, int v3
)
456 len
= EXTRACT_32BITS(dp
) / 4;
461 if (ND_TTEST2(*dp
, len
* sizeof(*dp
))) {
462 nfs_printfh(ndo
, dp
, len
);
470 * Print out a file name and return pointer to 32-bit word past it.
471 * If packet was truncated, return 0.
473 static const u_int32_t
*
474 parsefn(netdissect_options
*ndo
,
475 register const u_int32_t
*dp
)
477 register u_int32_t len
;
478 register const u_char
*cp
;
480 /* Bail if we don't have the string length */
483 /* Fetch string length; convert to host order */
487 ND_TCHECK2(*dp
, ((len
+ 3) & ~3));
490 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
491 dp
+= ((len
+ 3) & ~3) / sizeof(*dp
);
492 ND_PRINT((ndo
, "\""));
493 if (fn_printn(cp
, len
, ndo
->ndo_snapend
)) {
494 ND_PRINT((ndo
, "\""));
497 ND_PRINT((ndo
, "\""));
505 * Print out file handle and file name.
506 * Return pointer to 32-bit word past file name.
507 * If packet was truncated (or there was some other error), return 0.
509 static const u_int32_t
*
510 parsefhn(netdissect_options
*ndo
,
511 register const u_int32_t
*dp
, int v3
)
513 dp
= parsefh(ndo
, dp
, v3
);
516 ND_PRINT((ndo
, " "));
517 return (parsefn(ndo
, dp
));
521 nfsreq_print(netdissect_options
*ndo
,
522 register const u_char
*bp
, u_int length
,
523 register const u_char
*bp2
)
525 register const struct sunrpc_msg
*rp
;
526 char srcid
[20], dstid
[20]; /*fits 32bit*/
528 nfserr
= 0; /* assume no error */
529 rp
= (const struct sunrpc_msg
*)bp
;
531 ND_TCHECK(rp
->rm_xid
);
532 if (!ndo
->ndo_nflag
) {
533 snprintf(srcid
, sizeof(srcid
), "%u",
534 EXTRACT_32BITS(&rp
->rm_xid
));
535 strlcpy(dstid
, "nfs", sizeof(dstid
));
537 snprintf(srcid
, sizeof(srcid
), "%u",
538 EXTRACT_32BITS(&rp
->rm_xid
));
539 snprintf(dstid
, sizeof(dstid
), "%u", NFS_PORT
);
541 print_nfsaddr(ndo
, bp2
, srcid
, dstid
);
543 nfsreq_print_noaddr(ndo
, bp
, length
, bp2
);
548 ND_PRINT((ndo
, "%s", tstr
));
552 nfsreq_print_noaddr(netdissect_options
*ndo
,
553 register const u_char
*bp
, u_int length
,
554 register const u_char
*bp2
)
556 register const struct sunrpc_msg
*rp
;
557 register const u_int32_t
*dp
;
561 u_int32_t access_flags
;
562 struct nfsv3_sattr sa3
;
564 ND_PRINT((ndo
, "%d", length
));
565 nfserr
= 0; /* assume no error */
566 rp
= (const struct sunrpc_msg
*)bp
;
568 if (!xid_map_enter(ndo
, rp
, bp2
)) /* record proc number for later on */
571 v3
= (EXTRACT_32BITS(&rp
->rm_call
.cb_vers
) == NFS_VER3
);
572 proc
= EXTRACT_32BITS(&rp
->rm_call
.cb_proc
);
574 if (!v3
&& proc
< NFS_NPROCS
)
575 proc
= nfsv3_procid
[proc
];
579 ND_PRINT((ndo
, " nop"));
582 ND_PRINT((ndo
, " null"));
585 case NFSPROC_GETATTR
:
586 ND_PRINT((ndo
, " getattr"));
587 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
588 parsefh(ndo
, dp
, v3
) != NULL
)
592 case NFSPROC_SETATTR
:
593 ND_PRINT((ndo
, " setattr"));
594 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
595 parsefh(ndo
, dp
, v3
) != NULL
)
600 ND_PRINT((ndo
, " lookup"));
601 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
602 parsefhn(ndo
, dp
, v3
) != NULL
)
607 ND_PRINT((ndo
, " access"));
608 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
609 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
611 access_flags
= EXTRACT_32BITS(&dp
[0]);
612 if (access_flags
& ~NFSV3ACCESS_FULL
) {
613 /* NFSV3ACCESS definitions aren't up to date */
614 ND_PRINT((ndo
, " %04x", access_flags
));
615 } else if ((access_flags
& NFSV3ACCESS_FULL
) == NFSV3ACCESS_FULL
) {
616 ND_PRINT((ndo
, " NFS_ACCESS_FULL"));
618 char separator
= ' ';
619 if (access_flags
& NFSV3ACCESS_READ
) {
620 ND_PRINT((ndo
, " NFS_ACCESS_READ"));
623 if (access_flags
& NFSV3ACCESS_LOOKUP
) {
624 ND_PRINT((ndo
, "%cNFS_ACCESS_LOOKUP", separator
));
627 if (access_flags
& NFSV3ACCESS_MODIFY
) {
628 ND_PRINT((ndo
, "%cNFS_ACCESS_MODIFY", separator
));
631 if (access_flags
& NFSV3ACCESS_EXTEND
) {
632 ND_PRINT((ndo
, "%cNFS_ACCESS_EXTEND", separator
));
635 if (access_flags
& NFSV3ACCESS_DELETE
) {
636 ND_PRINT((ndo
, "%cNFS_ACCESS_DELETE", separator
));
639 if (access_flags
& NFSV3ACCESS_EXECUTE
)
640 ND_PRINT((ndo
, "%cNFS_ACCESS_EXECUTE", separator
));
646 case NFSPROC_READLINK
:
647 ND_PRINT((ndo
, " readlink"));
648 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
649 parsefh(ndo
, dp
, v3
) != NULL
)
654 ND_PRINT((ndo
, " read"));
655 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
656 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
659 ND_PRINT((ndo
, " %u bytes @ %" PRIu64
,
660 EXTRACT_32BITS(&dp
[2]),
661 EXTRACT_64BITS(&dp
[0])));
664 ND_PRINT((ndo
, " %u bytes @ %u",
665 EXTRACT_32BITS(&dp
[1]),
666 EXTRACT_32BITS(&dp
[0])));
673 ND_PRINT((ndo
, " write"));
674 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
675 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
678 ND_PRINT((ndo
, " %u (%u) bytes @ %" PRIu64
,
679 EXTRACT_32BITS(&dp
[4]),
680 EXTRACT_32BITS(&dp
[2]),
681 EXTRACT_64BITS(&dp
[0])));
682 if (ndo
->ndo_vflag
) {
685 ND_PRINT((ndo
, " <%s>",
686 tok2str(nfsv3_writemodes
,
687 NULL
, EXTRACT_32BITS(dp
))));
691 ND_PRINT((ndo
, " %u (%u) bytes @ %u (%u)",
692 EXTRACT_32BITS(&dp
[3]),
693 EXTRACT_32BITS(&dp
[2]),
694 EXTRACT_32BITS(&dp
[1]),
695 EXTRACT_32BITS(&dp
[0])));
702 ND_PRINT((ndo
, " create"));
703 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
704 parsefhn(ndo
, dp
, v3
) != NULL
)
709 ND_PRINT((ndo
, " mkdir"));
710 if ((dp
= parsereq(ndo
, rp
, length
)) != 0 && parsefhn(ndo
, dp
, v3
) != 0)
714 case NFSPROC_SYMLINK
:
715 ND_PRINT((ndo
, " symlink"));
716 if ((dp
= parsereq(ndo
, rp
, length
)) != 0 &&
717 (dp
= parsefhn(ndo
, dp
, v3
)) != 0) {
718 ND_PRINT((ndo
, " ->"));
719 if (v3
&& (dp
= parse_sattr3(ndo
, dp
, &sa3
)) == 0)
721 if (parsefn(ndo
, dp
) == 0)
723 if (v3
&& ndo
->ndo_vflag
)
724 print_sattr3(ndo
, &sa3
, ndo
->ndo_vflag
);
730 ND_PRINT((ndo
, " mknod"));
731 if ((dp
= parsereq(ndo
, rp
, length
)) != 0 &&
732 (dp
= parsefhn(ndo
, dp
, v3
)) != 0) {
734 type
= (nfs_type
)EXTRACT_32BITS(dp
);
736 if ((dp
= parse_sattr3(ndo
, dp
, &sa3
)) == 0)
738 ND_PRINT((ndo
, " %s", tok2str(type2str
, "unk-ft %d", type
)));
739 if (ndo
->ndo_vflag
&& (type
== NFCHR
|| type
== NFBLK
)) {
741 ND_PRINT((ndo
, " %u/%u",
742 EXTRACT_32BITS(&dp
[0]),
743 EXTRACT_32BITS(&dp
[1])));
747 print_sattr3(ndo
, &sa3
, ndo
->ndo_vflag
);
753 ND_PRINT((ndo
, " remove"));
754 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
755 parsefhn(ndo
, dp
, v3
) != NULL
)
760 ND_PRINT((ndo
, " rmdir"));
761 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
762 parsefhn(ndo
, dp
, v3
) != NULL
)
767 ND_PRINT((ndo
, " rename"));
768 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
769 (dp
= parsefhn(ndo
, dp
, v3
)) != NULL
) {
770 ND_PRINT((ndo
, " ->"));
771 if (parsefhn(ndo
, dp
, v3
) != NULL
)
777 ND_PRINT((ndo
, " link"));
778 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
779 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
780 ND_PRINT((ndo
, " ->"));
781 if (parsefhn(ndo
, dp
, v3
) != NULL
)
786 case NFSPROC_READDIR
:
787 ND_PRINT((ndo
, " readdir"));
788 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
789 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
793 * We shouldn't really try to interpret the
794 * offset cookie here.
796 ND_PRINT((ndo
, " %u bytes @ %" PRId64
,
797 EXTRACT_32BITS(&dp
[4]),
798 EXTRACT_64BITS(&dp
[0])));
800 ND_PRINT((ndo
, " verf %08x%08x", dp
[2], dp
[3]));
804 * Print the offset as signed, since -1 is
805 * common, but offsets > 2^31 aren't.
807 ND_PRINT((ndo
, " %u bytes @ %d",
808 EXTRACT_32BITS(&dp
[1]),
809 EXTRACT_32BITS(&dp
[0])));
815 case NFSPROC_READDIRPLUS
:
816 ND_PRINT((ndo
, " readdirplus"));
817 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
818 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
821 * We don't try to interpret the offset
824 ND_PRINT((ndo
, " %u bytes @ %" PRId64
,
825 EXTRACT_32BITS(&dp
[4]),
826 EXTRACT_64BITS(&dp
[0])));
827 if (ndo
->ndo_vflag
) {
829 ND_PRINT((ndo
, " max %u verf %08x%08x",
830 EXTRACT_32BITS(&dp
[5]), dp
[2], dp
[3]));
837 ND_PRINT((ndo
, " fsstat"));
838 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
839 parsefh(ndo
, dp
, v3
) != NULL
)
844 ND_PRINT((ndo
, " fsinfo"));
845 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
846 parsefh(ndo
, dp
, v3
) != NULL
)
850 case NFSPROC_PATHCONF
:
851 ND_PRINT((ndo
, " pathconf"));
852 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
853 parsefh(ndo
, dp
, v3
) != NULL
)
858 ND_PRINT((ndo
, " commit"));
859 if ((dp
= parsereq(ndo
, rp
, length
)) != NULL
&&
860 (dp
= parsefh(ndo
, dp
, v3
)) != NULL
) {
862 ND_PRINT((ndo
, " %u bytes @ %" PRIu64
,
863 EXTRACT_32BITS(&dp
[2]),
864 EXTRACT_64BITS(&dp
[0])));
870 ND_PRINT((ndo
, " proc-%u", EXTRACT_32BITS(&rp
->rm_call
.cb_proc
)));
876 ND_PRINT((ndo
, "%s", tstr
));
880 * Print out an NFS file handle.
881 * We assume packet was not truncated before the end of the
882 * file handle pointed to by dp.
884 * Note: new version (using portable file-handle parser) doesn't produce
885 * generation number. It probably could be made to do that, with some
886 * additional hacking on the parser code.
889 nfs_printfh(netdissect_options
*ndo
,
890 register const u_int32_t
*dp
, const u_int len
)
894 const char *sfsname
= NULL
;
897 if (ndo
->ndo_uflag
) {
899 char const *sep
= "";
901 ND_PRINT((ndo
, " fh["));
902 for (i
=0; i
<len
; i
++) {
903 ND_PRINT((ndo
, "%s%x", sep
, dp
[i
]));
906 ND_PRINT((ndo
, "]"));
910 Parse_fh((const u_char
*)dp
, len
, &fsid
, &ino
, NULL
, &sfsname
, 0);
913 /* file system ID is ASCII, not numeric, for this server OS */
914 static char temp
[NFSX_V3FHMAX
+1];
916 /* Make sure string is null-terminated */
917 strncpy(temp
, sfsname
, NFSX_V3FHMAX
);
918 temp
[sizeof(temp
) - 1] = '\0';
919 /* Remove trailing spaces */
920 spacep
= strchr(temp
, ' ');
924 ND_PRINT((ndo
, " fh %s/", temp
));
926 ND_PRINT((ndo
, " fh %d,%d/",
927 fsid
.Fsid_dev
.Major
, fsid
.Fsid_dev
.Minor
));
930 if(fsid
.Fsid_dev
.Minor
== 257)
931 /* Print the undecoded handle */
932 ND_PRINT((ndo
, "%s", fsid
.Opaque_Handle
));
934 ND_PRINT((ndo
, "%ld", (long) ino
));
938 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
939 * us to match up replies with requests and thus to know how to parse
943 struct xid_map_entry
{
944 u_int32_t xid
; /* transaction ID (net order) */
945 int ipver
; /* IP version (4 or 6) */
947 struct in6_addr client
; /* client IP address (net order) */
948 struct in6_addr server
; /* server IP address (net order) */
950 struct in_addr client
; /* client IP address (net order) */
951 struct in_addr server
; /* server IP address (net order) */
953 u_int32_t proc
; /* call proc number (host order) */
954 u_int32_t vers
; /* program version (host order) */
958 * Map entries are kept in an array that we manage as a ring;
959 * new entries are always added at the tail of the ring. Initially,
960 * all the entries are zero and hence don't match anything.
963 #define XIDMAPSIZE 64
965 struct xid_map_entry xid_map
[XIDMAPSIZE
];
967 int xid_map_next
= 0;
968 int xid_map_hint
= 0;
971 xid_map_enter(netdissect_options
*ndo
,
972 const struct sunrpc_msg
*rp
, const u_char
*bp
)
974 struct ip
*ip
= NULL
;
976 struct ip6_hdr
*ip6
= NULL
;
978 struct xid_map_entry
*xmep
;
980 if (!ND_TTEST(rp
->rm_call
.cb_vers
))
982 switch (IP_V((struct ip
*)bp
)) {
984 ip
= (struct ip
*)bp
;
988 ip6
= (struct ip6_hdr
*)bp
;
995 xmep
= &xid_map
[xid_map_next
];
997 if (++xid_map_next
>= XIDMAPSIZE
)
1000 xmep
->xid
= rp
->rm_xid
;
1003 UNALIGNED_MEMCPY(&xmep
->client
, &ip
->ip_src
, sizeof(ip
->ip_src
));
1004 UNALIGNED_MEMCPY(&xmep
->server
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
1009 UNALIGNED_MEMCPY(&xmep
->client
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
1010 UNALIGNED_MEMCPY(&xmep
->server
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
1013 xmep
->proc
= EXTRACT_32BITS(&rp
->rm_call
.cb_proc
);
1014 xmep
->vers
= EXTRACT_32BITS(&rp
->rm_call
.cb_vers
);
1019 * Returns 0 and puts NFSPROC_xxx in proc return and
1020 * version in vers return, or returns -1 on failure
1023 xid_map_find(const struct sunrpc_msg
*rp
, const u_char
*bp
, u_int32_t
*proc
,
1027 struct xid_map_entry
*xmep
;
1028 u_int32_t xid
= rp
->rm_xid
;
1029 struct ip
*ip
= (struct ip
*)bp
;
1031 struct ip6_hdr
*ip6
= (struct ip6_hdr
*)bp
;
1035 /* Start searching from where we last left off */
1040 if (xmep
->ipver
!= IP_V(ip
) || xmep
->xid
!= xid
)
1042 switch (xmep
->ipver
) {
1044 if (UNALIGNED_MEMCMP(&ip
->ip_src
, &xmep
->server
,
1045 sizeof(ip
->ip_src
)) != 0 ||
1046 UNALIGNED_MEMCMP(&ip
->ip_dst
, &xmep
->client
,
1047 sizeof(ip
->ip_dst
)) != 0) {
1053 if (UNALIGNED_MEMCMP(&ip6
->ip6_src
, &xmep
->server
,
1054 sizeof(ip6
->ip6_src
)) != 0 ||
1055 UNALIGNED_MEMCMP(&ip6
->ip6_dst
, &xmep
->client
,
1056 sizeof(ip6
->ip6_dst
)) != 0) {
1073 if (++i
>= XIDMAPSIZE
)
1075 } while (i
!= xid_map_hint
);
1082 * Routines for parsing reply packets
1086 * Return a pointer to the beginning of the actual results.
1087 * If the packet was truncated, return 0.
1089 static const u_int32_t
*
1090 parserep(netdissect_options
*ndo
,
1091 register const struct sunrpc_msg
*rp
, register u_int length
)
1093 register const u_int32_t
*dp
;
1095 enum sunrpc_accept_stat astat
;
1099 * Here we find the address of the ar_verf credentials.
1100 * Originally, this calculation was
1101 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
1102 * On the wire, the rp_acpt field starts immediately after
1103 * the (32 bit) rp_stat field. However, rp_acpt (which is a
1104 * "struct accepted_reply") contains a "struct opaque_auth",
1105 * whose internal representation contains a pointer, so on a
1106 * 64-bit machine the compiler inserts 32 bits of padding
1107 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
1108 * the internal representation to parse the on-the-wire
1109 * representation. Instead, we skip past the rp_stat field,
1110 * which is an "enum" and so occupies one 32-bit word.
1112 dp
= ((const u_int32_t
*)&rp
->rm_reply
) + 1;
1114 len
= EXTRACT_32BITS(&dp
[1]);
1118 * skip past the ar_verf credentials.
1120 dp
+= (len
+ (2*sizeof(u_int32_t
) + 3)) / sizeof(u_int32_t
);
1121 ND_TCHECK2(dp
[0], 0);
1124 * now we can check the ar_stat field
1126 astat
= (enum sunrpc_accept_stat
) EXTRACT_32BITS(dp
);
1129 case SUNRPC_SUCCESS
:
1132 case SUNRPC_PROG_UNAVAIL
:
1133 ND_PRINT((ndo
, " PROG_UNAVAIL"));
1134 nfserr
= 1; /* suppress trunc string */
1137 case SUNRPC_PROG_MISMATCH
:
1138 ND_PRINT((ndo
, " PROG_MISMATCH"));
1139 nfserr
= 1; /* suppress trunc string */
1142 case SUNRPC_PROC_UNAVAIL
:
1143 ND_PRINT((ndo
, " PROC_UNAVAIL"));
1144 nfserr
= 1; /* suppress trunc string */
1147 case SUNRPC_GARBAGE_ARGS
:
1148 ND_PRINT((ndo
, " GARBAGE_ARGS"));
1149 nfserr
= 1; /* suppress trunc string */
1152 case SUNRPC_SYSTEM_ERR
:
1153 ND_PRINT((ndo
, " SYSTEM_ERR"));
1154 nfserr
= 1; /* suppress trunc string */
1158 ND_PRINT((ndo
, " ar_stat %d", astat
));
1159 nfserr
= 1; /* suppress trunc string */
1162 /* successful return */
1163 ND_TCHECK2(*dp
, sizeof(astat
));
1164 return ((u_int32_t
*) (sizeof(astat
) + ((char *)dp
)));
1169 static const u_int32_t
*
1170 parsestatus(netdissect_options
*ndo
,
1171 const u_int32_t
*dp
, int *er
)
1177 errnum
= EXTRACT_32BITS(&dp
[0]);
1181 if (!ndo
->ndo_qflag
)
1182 ND_PRINT((ndo
, " ERROR: %s",
1183 tok2str(status2str
, "unk %d", errnum
)));
1191 static const u_int32_t
*
1192 parsefattr(netdissect_options
*ndo
,
1193 const u_int32_t
*dp
, int verbose
, int v3
)
1195 const struct nfs_fattr
*fap
;
1197 fap
= (const struct nfs_fattr
*)dp
;
1198 ND_TCHECK(fap
->fa_gid
);
1200 ND_PRINT((ndo
, " %s %o ids %d/%d",
1201 tok2str(type2str
, "unk-ft %d ",
1202 EXTRACT_32BITS(&fap
->fa_type
)),
1203 EXTRACT_32BITS(&fap
->fa_mode
),
1204 EXTRACT_32BITS(&fap
->fa_uid
),
1205 EXTRACT_32BITS(&fap
->fa_gid
)));
1207 ND_TCHECK(fap
->fa3_size
);
1208 ND_PRINT((ndo
, " sz %" PRIu64
,
1209 EXTRACT_64BITS((u_int32_t
*)&fap
->fa3_size
)));
1211 ND_TCHECK(fap
->fa2_size
);
1212 ND_PRINT((ndo
, " sz %d", EXTRACT_32BITS(&fap
->fa2_size
)));
1215 /* print lots more stuff */
1218 ND_TCHECK(fap
->fa3_ctime
);
1219 ND_PRINT((ndo
, " nlink %d rdev %d/%d",
1220 EXTRACT_32BITS(&fap
->fa_nlink
),
1221 EXTRACT_32BITS(&fap
->fa3_rdev
.specdata1
),
1222 EXTRACT_32BITS(&fap
->fa3_rdev
.specdata2
)));
1223 ND_PRINT((ndo
, " fsid %" PRIx64
,
1224 EXTRACT_64BITS((u_int32_t
*)&fap
->fa3_fsid
)));
1225 ND_PRINT((ndo
, " fileid %" PRIx64
,
1226 EXTRACT_64BITS((u_int32_t
*)&fap
->fa3_fileid
)));
1227 ND_PRINT((ndo
, " a/m/ctime %u.%06u",
1228 EXTRACT_32BITS(&fap
->fa3_atime
.nfsv3_sec
),
1229 EXTRACT_32BITS(&fap
->fa3_atime
.nfsv3_nsec
)));
1230 ND_PRINT((ndo
, " %u.%06u",
1231 EXTRACT_32BITS(&fap
->fa3_mtime
.nfsv3_sec
),
1232 EXTRACT_32BITS(&fap
->fa3_mtime
.nfsv3_nsec
)));
1233 ND_PRINT((ndo
, " %u.%06u",
1234 EXTRACT_32BITS(&fap
->fa3_ctime
.nfsv3_sec
),
1235 EXTRACT_32BITS(&fap
->fa3_ctime
.nfsv3_nsec
)));
1237 ND_TCHECK(fap
->fa2_ctime
);
1238 ND_PRINT((ndo
, " nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1239 EXTRACT_32BITS(&fap
->fa_nlink
),
1240 EXTRACT_32BITS(&fap
->fa2_rdev
),
1241 EXTRACT_32BITS(&fap
->fa2_fsid
),
1242 EXTRACT_32BITS(&fap
->fa2_fileid
)));
1243 ND_PRINT((ndo
, " %u.%06u",
1244 EXTRACT_32BITS(&fap
->fa2_atime
.nfsv2_sec
),
1245 EXTRACT_32BITS(&fap
->fa2_atime
.nfsv2_usec
)));
1246 ND_PRINT((ndo
, " %u.%06u",
1247 EXTRACT_32BITS(&fap
->fa2_mtime
.nfsv2_sec
),
1248 EXTRACT_32BITS(&fap
->fa2_mtime
.nfsv2_usec
)));
1249 ND_PRINT((ndo
, " %u.%06u",
1250 EXTRACT_32BITS(&fap
->fa2_ctime
.nfsv2_sec
),
1251 EXTRACT_32BITS(&fap
->fa2_ctime
.nfsv2_usec
)));
1254 return ((const u_int32_t
*)((unsigned char *)dp
+
1255 (v3
? NFSX_V3FATTR
: NFSX_V2FATTR
)));
1261 parseattrstat(netdissect_options
*ndo
,
1262 const u_int32_t
*dp
, int verbose
, int v3
)
1266 dp
= parsestatus(ndo
, dp
, &er
);
1272 return (parsefattr(ndo
, dp
, verbose
, v3
) != NULL
);
1276 parsediropres(netdissect_options
*ndo
,
1277 const u_int32_t
*dp
)
1281 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1286 dp
= parsefh(ndo
, dp
, 0);
1290 return (parsefattr(ndo
, dp
, ndo
->ndo_vflag
, 0) != NULL
);
1294 parselinkres(netdissect_options
*ndo
,
1295 const u_int32_t
*dp
, int v3
)
1299 dp
= parsestatus(ndo
, dp
, &er
);
1304 if (v3
&& !(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1306 ND_PRINT((ndo
, " "));
1307 return (parsefn(ndo
, dp
) != NULL
);
1311 parsestatfs(netdissect_options
*ndo
,
1312 const u_int32_t
*dp
, int v3
)
1314 const struct nfs_statfs
*sfsp
;
1317 dp
= parsestatus(ndo
, dp
, &er
);
1328 ND_PRINT((ndo
, " POST:"));
1329 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1333 ND_TCHECK2(*dp
, (v3
? NFSX_V3STATFS
: NFSX_V2STATFS
));
1335 sfsp
= (const struct nfs_statfs
*)dp
;
1338 ND_PRINT((ndo
, " tbytes %" PRIu64
" fbytes %" PRIu64
" abytes %" PRIu64
,
1339 EXTRACT_64BITS((u_int32_t
*)&sfsp
->sf_tbytes
),
1340 EXTRACT_64BITS((u_int32_t
*)&sfsp
->sf_fbytes
),
1341 EXTRACT_64BITS((u_int32_t
*)&sfsp
->sf_abytes
)));
1342 if (ndo
->ndo_vflag
) {
1343 ND_PRINT((ndo
, " tfiles %" PRIu64
" ffiles %" PRIu64
" afiles %" PRIu64
" invar %u",
1344 EXTRACT_64BITS((u_int32_t
*)&sfsp
->sf_tfiles
),
1345 EXTRACT_64BITS((u_int32_t
*)&sfsp
->sf_ffiles
),
1346 EXTRACT_64BITS((u_int32_t
*)&sfsp
->sf_afiles
),
1347 EXTRACT_32BITS(&sfsp
->sf_invarsec
)));
1350 ND_PRINT((ndo
, " tsize %d bsize %d blocks %d bfree %d bavail %d",
1351 EXTRACT_32BITS(&sfsp
->sf_tsize
),
1352 EXTRACT_32BITS(&sfsp
->sf_bsize
),
1353 EXTRACT_32BITS(&sfsp
->sf_blocks
),
1354 EXTRACT_32BITS(&sfsp
->sf_bfree
),
1355 EXTRACT_32BITS(&sfsp
->sf_bavail
)));
1364 parserddires(netdissect_options
*ndo
,
1365 const u_int32_t
*dp
)
1369 dp
= parsestatus(ndo
, dp
, &er
);
1378 ND_PRINT((ndo
, " offset %x size %d ",
1379 EXTRACT_32BITS(&dp
[0]), EXTRACT_32BITS(&dp
[1])));
1381 ND_PRINT((ndo
, " eof"));
1388 static const u_int32_t
*
1389 parse_wcc_attr(netdissect_options
*ndo
,
1390 const u_int32_t
*dp
)
1392 ND_PRINT((ndo
, " sz %" PRIu64
, EXTRACT_64BITS(&dp
[0])));
1393 ND_PRINT((ndo
, " mtime %u.%06u ctime %u.%06u",
1394 EXTRACT_32BITS(&dp
[2]), EXTRACT_32BITS(&dp
[3]),
1395 EXTRACT_32BITS(&dp
[4]), EXTRACT_32BITS(&dp
[5])));
1400 * Pre operation attributes. Print only if vflag > 1.
1402 static const u_int32_t
*
1403 parse_pre_op_attr(netdissect_options
*ndo
,
1404 const u_int32_t
*dp
, int verbose
)
1407 if (!EXTRACT_32BITS(&dp
[0]))
1410 ND_TCHECK2(*dp
, 24);
1412 return parse_wcc_attr(ndo
, dp
);
1414 /* If not verbose enough, just skip over wcc_attr */
1422 * Post operation attributes are printed if vflag >= 1
1424 static const u_int32_t
*
1425 parse_post_op_attr(netdissect_options
*ndo
,
1426 const u_int32_t
*dp
, int verbose
)
1429 if (!EXTRACT_32BITS(&dp
[0]))
1433 return parsefattr(ndo
, dp
, verbose
, 1);
1435 return (dp
+ (NFSX_V3FATTR
/ sizeof (u_int32_t
)));
1440 static const u_int32_t
*
1441 parse_wcc_data(netdissect_options
*ndo
,
1442 const u_int32_t
*dp
, int verbose
)
1445 ND_PRINT((ndo
, " PRE:"));
1446 if (!(dp
= parse_pre_op_attr(ndo
, dp
, verbose
)))
1450 ND_PRINT((ndo
, " POST:"));
1451 return parse_post_op_attr(ndo
, dp
, verbose
);
1454 static const u_int32_t
*
1455 parsecreateopres(netdissect_options
*ndo
,
1456 const u_int32_t
*dp
, int verbose
)
1460 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1463 dp
= parse_wcc_data(ndo
, dp
, verbose
);
1466 if (!EXTRACT_32BITS(&dp
[0]))
1469 if (!(dp
= parsefh(ndo
, dp
, 1)))
1472 if (!(dp
= parse_post_op_attr(ndo
, dp
, verbose
)))
1474 if (ndo
->ndo_vflag
> 1) {
1475 ND_PRINT((ndo
, " dir attr:"));
1476 dp
= parse_wcc_data(ndo
, dp
, verbose
);
1486 parsewccres(netdissect_options
*ndo
,
1487 const u_int32_t
*dp
, int verbose
)
1491 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1493 return parse_wcc_data(ndo
, dp
, verbose
) != 0;
1496 static const u_int32_t
*
1497 parsev3rddirres(netdissect_options
*ndo
,
1498 const u_int32_t
*dp
, int verbose
)
1502 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1505 ND_PRINT((ndo
, " POST:"));
1506 if (!(dp
= parse_post_op_attr(ndo
, dp
, verbose
)))
1510 if (ndo
->ndo_vflag
) {
1512 ND_PRINT((ndo
, " verf %08x%08x", dp
[0], dp
[1]));
1521 parsefsinfo(netdissect_options
*ndo
,
1522 const u_int32_t
*dp
)
1524 struct nfsv3_fsinfo
*sfp
;
1527 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1530 ND_PRINT((ndo
, " POST:"));
1531 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1536 sfp
= (struct nfsv3_fsinfo
*)dp
;
1538 ND_PRINT((ndo
, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1539 EXTRACT_32BITS(&sfp
->fs_rtmax
),
1540 EXTRACT_32BITS(&sfp
->fs_rtpref
),
1541 EXTRACT_32BITS(&sfp
->fs_wtmax
),
1542 EXTRACT_32BITS(&sfp
->fs_wtpref
),
1543 EXTRACT_32BITS(&sfp
->fs_dtpref
)));
1544 if (ndo
->ndo_vflag
) {
1545 ND_PRINT((ndo
, " rtmult %u wtmult %u maxfsz %" PRIu64
,
1546 EXTRACT_32BITS(&sfp
->fs_rtmult
),
1547 EXTRACT_32BITS(&sfp
->fs_wtmult
),
1548 EXTRACT_64BITS((u_int32_t
*)&sfp
->fs_maxfilesize
)));
1549 ND_PRINT((ndo
, " delta %u.%06u ",
1550 EXTRACT_32BITS(&sfp
->fs_timedelta
.nfsv3_sec
),
1551 EXTRACT_32BITS(&sfp
->fs_timedelta
.nfsv3_nsec
)));
1559 parsepathconf(netdissect_options
*ndo
,
1560 const u_int32_t
*dp
)
1563 struct nfsv3_pathconf
*spp
;
1565 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1568 ND_PRINT((ndo
, " POST:"));
1569 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1574 spp
= (struct nfsv3_pathconf
*)dp
;
1577 ND_PRINT((ndo
, " linkmax %u namemax %u %s %s %s %s",
1578 EXTRACT_32BITS(&spp
->pc_linkmax
),
1579 EXTRACT_32BITS(&spp
->pc_namemax
),
1580 EXTRACT_32BITS(&spp
->pc_notrunc
) ? "notrunc" : "",
1581 EXTRACT_32BITS(&spp
->pc_chownrestricted
) ? "chownres" : "",
1582 EXTRACT_32BITS(&spp
->pc_caseinsensitive
) ? "igncase" : "",
1583 EXTRACT_32BITS(&spp
->pc_casepreserving
) ? "keepcase" : ""));
1590 interp_reply(netdissect_options
*ndo
,
1591 const struct sunrpc_msg
*rp
, u_int32_t proc
, u_int32_t vers
, int length
)
1593 register const u_int32_t
*dp
;
1597 v3
= (vers
== NFS_VER3
);
1599 if (!v3
&& proc
< NFS_NPROCS
)
1600 proc
= nfsv3_procid
[proc
];
1605 ND_PRINT((ndo
, " nop"));
1609 ND_PRINT((ndo
, " null"));
1612 case NFSPROC_GETATTR
:
1613 ND_PRINT((ndo
, " getattr"));
1614 dp
= parserep(ndo
, rp
, length
);
1615 if (dp
!= NULL
&& parseattrstat(ndo
, dp
, !ndo
->ndo_qflag
, v3
) != 0)
1619 case NFSPROC_SETATTR
:
1620 ND_PRINT((ndo
, " setattr"));
1621 if (!(dp
= parserep(ndo
, rp
, length
)))
1624 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1627 if (parseattrstat(ndo
, dp
, !ndo
->ndo_qflag
, 0) != 0)
1632 case NFSPROC_LOOKUP
:
1633 ND_PRINT((ndo
, " lookup"));
1634 if (!(dp
= parserep(ndo
, rp
, length
)))
1637 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1640 if (ndo
->ndo_vflag
> 1) {
1641 ND_PRINT((ndo
, " post dattr:"));
1642 dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
);
1645 if (!(dp
= parsefh(ndo
, dp
, v3
)))
1647 if ((dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)) &&
1648 ndo
->ndo_vflag
> 1) {
1649 ND_PRINT((ndo
, " post dattr:"));
1650 dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
);
1656 if (parsediropres(ndo
, dp
) != 0)
1661 case NFSPROC_ACCESS
:
1662 ND_PRINT((ndo
, " access"));
1663 if (!(dp
= parserep(ndo
, rp
, length
)))
1665 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1668 ND_PRINT((ndo
, " attr:"));
1669 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1672 ND_PRINT((ndo
, " c %04x", EXTRACT_32BITS(&dp
[0])));
1675 case NFSPROC_READLINK
:
1676 ND_PRINT((ndo
, " readlink"));
1677 dp
= parserep(ndo
, rp
, length
);
1678 if (dp
!= NULL
&& parselinkres(ndo
, dp
, v3
) != 0)
1683 ND_PRINT((ndo
, " read"));
1684 if (!(dp
= parserep(ndo
, rp
, length
)))
1687 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1689 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1693 if (ndo
->ndo_vflag
) {
1695 ND_PRINT((ndo
, " %u bytes", EXTRACT_32BITS(&dp
[0])));
1696 if (EXTRACT_32BITS(&dp
[1]))
1697 ND_PRINT((ndo
, " EOF"));
1701 if (parseattrstat(ndo
, dp
, ndo
->ndo_vflag
, 0) != 0)
1707 ND_PRINT((ndo
, " write"));
1708 if (!(dp
= parserep(ndo
, rp
, length
)))
1711 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1713 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1717 if (ndo
->ndo_vflag
) {
1719 ND_PRINT((ndo
, " %u bytes", EXTRACT_32BITS(&dp
[0])));
1720 if (ndo
->ndo_vflag
> 1) {
1722 ND_PRINT((ndo
, " <%s>",
1723 tok2str(nfsv3_writemodes
,
1724 NULL
, EXTRACT_32BITS(&dp
[1]))));
1729 if (parseattrstat(ndo
, dp
, ndo
->ndo_vflag
, v3
) != 0)
1734 case NFSPROC_CREATE
:
1735 ND_PRINT((ndo
, " create"));
1736 if (!(dp
= parserep(ndo
, rp
, length
)))
1739 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1742 if (parsediropres(ndo
, dp
) != 0)
1748 ND_PRINT((ndo
, " mkdir"));
1749 if (!(dp
= parserep(ndo
, rp
, length
)))
1752 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1755 if (parsediropres(ndo
, dp
) != 0)
1760 case NFSPROC_SYMLINK
:
1761 ND_PRINT((ndo
, " symlink"));
1762 if (!(dp
= parserep(ndo
, rp
, length
)))
1765 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1768 if (parsestatus(ndo
, dp
, &er
) != 0)
1774 ND_PRINT((ndo
, " mknod"));
1775 if (!(dp
= parserep(ndo
, rp
, length
)))
1777 if (parsecreateopres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1781 case NFSPROC_REMOVE
:
1782 ND_PRINT((ndo
, " remove"));
1783 if (!(dp
= parserep(ndo
, rp
, length
)))
1786 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1789 if (parsestatus(ndo
, dp
, &er
) != 0)
1795 ND_PRINT((ndo
, " rmdir"));
1796 if (!(dp
= parserep(ndo
, rp
, length
)))
1799 if (parsewccres(ndo
, dp
, ndo
->ndo_vflag
))
1802 if (parsestatus(ndo
, dp
, &er
) != 0)
1807 case NFSPROC_RENAME
:
1808 ND_PRINT((ndo
, " rename"));
1809 if (!(dp
= parserep(ndo
, rp
, length
)))
1812 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1814 if (ndo
->ndo_vflag
) {
1815 ND_PRINT((ndo
, " from:"));
1816 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1818 ND_PRINT((ndo
, " to:"));
1819 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1824 if (parsestatus(ndo
, dp
, &er
) != 0)
1830 ND_PRINT((ndo
, " link"));
1831 if (!(dp
= parserep(ndo
, rp
, length
)))
1834 if (!(dp
= parsestatus(ndo
, dp
, &er
)))
1836 if (ndo
->ndo_vflag
) {
1837 ND_PRINT((ndo
, " file POST:"));
1838 if (!(dp
= parse_post_op_attr(ndo
, dp
, ndo
->ndo_vflag
)))
1840 ND_PRINT((ndo
, " dir:"));
1841 if (!(dp
= parse_wcc_data(ndo
, dp
, ndo
->ndo_vflag
)))
1846 if (parsestatus(ndo
, dp
, &er
) != 0)
1851 case NFSPROC_READDIR
:
1852 ND_PRINT((ndo
, " readdir"));
1853 if (!(dp
= parserep(ndo
, rp
, length
)))
1856 if (parsev3rddirres(ndo
, dp
, ndo
->ndo_vflag
))
1859 if (parserddires(ndo
, dp
) != 0)
1864 case NFSPROC_READDIRPLUS
:
1865 ND_PRINT((ndo
, " readdirplus"));
1866 if (!(dp
= parserep(ndo
, rp
, length
)))
1868 if (parsev3rddirres(ndo
, dp
, ndo
->ndo_vflag
))
1872 case NFSPROC_FSSTAT
:
1873 ND_PRINT((ndo
, " fsstat"));
1874 dp
= parserep(ndo
, rp
, length
);
1875 if (dp
!= NULL
&& parsestatfs(ndo
, dp
, v3
) != 0)
1879 case NFSPROC_FSINFO
:
1880 ND_PRINT((ndo
, " fsinfo"));
1881 dp
= parserep(ndo
, rp
, length
);
1882 if (dp
!= NULL
&& parsefsinfo(ndo
, dp
) != 0)
1886 case NFSPROC_PATHCONF
:
1887 ND_PRINT((ndo
, " pathconf"));
1888 dp
= parserep(ndo
, rp
, length
);
1889 if (dp
!= NULL
&& parsepathconf(ndo
, dp
) != 0)
1893 case NFSPROC_COMMIT
:
1894 ND_PRINT((ndo
, " commit"));
1895 dp
= parserep(ndo
, rp
, length
);
1896 if (dp
!= NULL
&& parsewccres(ndo
, dp
, ndo
->ndo_vflag
) != 0)
1901 ND_PRINT((ndo
, " proc-%u", proc
));
1906 ND_PRINT((ndo
, "%s", tstr
));