]>
git.saurik.com Git - apple/network_cmds.git/blob - tcpdump.tproj/print-nfs.c
9f7b5b2acfb65290039befe380f99a5a633f4c39
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that: (1) source code distributions
30 * retain the above copyright notice and this paragraph in its entirety, (2)
31 * distributions including binary code include the above copyright notice and
32 * this paragraph in its entirety in the documentation or other materials
33 * provided with the distribution, and (3) all advertising materials mentioning
34 * features or use of this software display the following acknowledgement:
35 * ``This product includes software developed by the University of California,
36 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
37 * the University nor the names of its contributors may be used to endorse
38 * or promote products derived from this software without specific prior
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
46 static const char rcsid
[] =
47 "@(#) $Header: /cvs/Darwin/Commands/NeXT/network_cmds/tcpdump.tproj/print-nfs.c,v 1.1.1.1 1999/05/02 03:58:34 wsanchez Exp $ (LBL)";
50 #include <sys/param.h>
52 #include <sys/socket.h>
60 #include <netinet/in.h>
61 #include <netinet/if_ether.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/ip_var.h>
73 #include "interface.h"
74 #include "addrtoname.h"
79 static void nfs_printfh(const u_int32_t
*);
80 static void xid_map_enter(const struct rpc_msg
*, const struct ip
*);
81 static int32_t xid_map_find(const struct rpc_msg
*, const struct ip
*);
82 static void interp_reply(const struct rpc_msg
*, u_int32_t
, u_int
);
84 static int nfserr
; /* true if we error rather than trunc */
87 nfsreply_print(register const u_char
*bp
, u_int length
,
88 register const u_char
*bp2
)
90 register const struct rpc_msg
*rp
;
91 register const struct ip
*ip
;
94 nfserr
= 0; /* assume no error */
95 rp
= (const struct rpc_msg
*)bp
;
96 ip
= (const struct ip
*)bp2
;
99 (void)printf("%s.nfs > %s.%x: reply %s %d",
100 ipaddr_string(&ip
->ip_src
),
101 ipaddr_string(&ip
->ip_dst
),
102 (u_int32_t
)ntohl(rp
->rm_xid
),
103 ntohl(rp
->rm_reply
.rp_stat
) == MSG_ACCEPTED
?
107 (void)printf("%s.%x > %s.%x: reply %s %d",
108 ipaddr_string(&ip
->ip_src
),
110 ipaddr_string(&ip
->ip_dst
),
111 (u_int32_t
)ntohl(rp
->rm_xid
),
112 ntohl(rp
->rm_reply
.rp_stat
) == MSG_ACCEPTED
?
116 proc
= xid_map_find(rp
, ip
);
118 interp_reply(rp
, (u_int32_t
)proc
, length
);
122 * Return a pointer to the first file handle in the packet.
123 * If the packet was truncated, return 0.
125 static const u_int32_t
*
126 parsereq(register const struct rpc_msg
*rp
, register u_int length
)
128 register const u_int32_t
*dp
;
132 * find the start of the req data (if we captured it)
134 dp
= (u_int32_t
*)&rp
->rm_call
.cb_cred
;
138 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
142 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
152 * Print out an NFS file handle and return a pointer to following word.
153 * If packet was truncated, return 0.
155 static const u_int32_t
*
156 parsefh(register const u_int32_t
*dp
)
158 if (dp
+ 8 <= (u_int32_t
*)snapend
) {
166 * Print out a file name and return pointer to 32-bit word past it.
167 * If packet was truncated, return 0.
169 static const u_int32_t
*
170 parsefn(register const u_int32_t
*dp
)
172 register u_int32_t len
;
173 register const u_char
*cp
;
175 /* Bail if we don't have the string length */
176 if ((u_char
*)dp
> snapend
- sizeof(*dp
))
179 /* Fetch string length; convert to host order */
184 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
185 dp
+= ((len
+ 3) & ~3) / sizeof(*dp
);
186 if ((u_char
*)dp
> snapend
)
188 /* XXX seems like we should be checking the length */
190 (void) fn_printn(cp
, len
, NULL
);
197 * Print out file handle and file name.
198 * Return pointer to 32-bit word past file name.
199 * If packet was truncated (or there was some other error), return 0.
201 static const u_int32_t
*
202 parsefhn(register const u_int32_t
*dp
)
208 return (parsefn(dp
));
212 nfsreq_print(register const u_char
*bp
, u_int length
,
213 register const u_char
*bp2
)
215 register const struct rpc_msg
*rp
;
216 register const struct ip
*ip
;
217 register const u_int32_t
*dp
;
219 nfserr
= 0; /* assume no error */
220 rp
= (const struct rpc_msg
*)bp
;
221 ip
= (const struct ip
*)bp2
;
223 (void)printf("%s.%x > %s.nfs: %d",
224 ipaddr_string(&ip
->ip_src
),
225 (u_int32_t
)ntohl(rp
->rm_xid
),
226 ipaddr_string(&ip
->ip_dst
),
229 (void)printf("%s.%x > %s.%x: %d",
230 ipaddr_string(&ip
->ip_src
),
231 (u_int32_t
)ntohl(rp
->rm_xid
),
232 ipaddr_string(&ip
->ip_dst
),
236 xid_map_enter(rp
, ip
); /* record proc number for later on */
238 switch (ntohl(rp
->rm_call
.cb_proc
)) {
244 #define NFSPROC_NOOP -1
250 case NFSPROC_GETATTR
:
252 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
256 case NFSPROC_SETATTR
:
258 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
262 #if NFSPROC_ROOT != NFSPROC_NOOP
269 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
273 case NFSPROC_READLINK
:
275 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
281 if ((dp
= parsereq(rp
, length
)) != NULL
&&
282 (dp
= parsefh(dp
)) != NULL
) {
283 TCHECK2(dp
[0], 3 * sizeof(*dp
));
284 printf(" %u bytes @ %u",
285 (u_int32_t
)ntohl(dp
[1]),
286 (u_int32_t
)ntohl(dp
[0]));
291 #if NFSPROC_WRITECACHE != NFSPROC_NOOP
292 case NFSPROC_WRITECACHE
:
293 printf(" writecache");
294 if ((dp
= parsereq(rp
, length
)) != NULL
&&
295 (dp
= parsefh(dp
)) != NULL
) {
296 TCHECK2(dp
[0], 4 * sizeof(*dp
));
297 printf(" %u (%u) bytes @ %u (%u)",
298 (u_int32_t
)ntohl(dp
[3]),
299 (u_int32_t
)ntohl(dp
[2]),
300 (u_int32_t
)ntohl(dp
[1]),
301 (u_int32_t
)ntohl(dp
[0]));
308 if ((dp
= parsereq(rp
, length
)) != NULL
&&
309 (dp
= parsefh(dp
)) != NULL
) {
310 TCHECK2(dp
[0], 4 * sizeof(*dp
));
311 printf(" %u (%u) bytes @ %u (%u)",
312 (u_int32_t
)ntohl(dp
[3]),
313 (u_int32_t
)ntohl(dp
[2]),
314 (u_int32_t
)ntohl(dp
[1]),
315 (u_int32_t
)ntohl(dp
[0]));
322 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
328 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
334 if ((dp
= parsereq(rp
, length
)) != NULL
&&
335 (dp
= parsefhn(dp
)) != NULL
) {
336 fputs(" ->", stdout
);
337 if (parsefhn(dp
) != NULL
)
344 if ((dp
= parsereq(rp
, length
)) != NULL
&&
345 (dp
= parsefh(dp
)) != NULL
) {
346 fputs(" ->", stdout
);
347 if (parsefhn(dp
) != NULL
)
352 case NFSPROC_SYMLINK
:
354 if ((dp
= parsereq(rp
, length
)) != NULL
&&
355 (dp
= parsefhn(dp
)) != NULL
) {
356 fputs(" -> ", stdout
);
357 if (parsefn(dp
) != NULL
)
364 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
370 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
374 case NFSPROC_READDIR
:
376 if ((dp
= parsereq(rp
, length
)) != NULL
&&
377 (dp
= parsefh(dp
)) != NULL
) {
378 TCHECK2(dp
[0], 2 * sizeof(*dp
));
380 * Print the offset as signed, since -1 is common,
381 * but offsets > 2^31 aren't.
383 printf(" %u bytes @ %d",
384 (u_int32_t
)ntohl(dp
[1]),
385 (u_int32_t
)ntohl(dp
[0]));
392 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
397 printf(" proc-%u", (u_int32_t
)ntohl(rp
->rm_call
.cb_proc
));
402 fputs(" [|nfs]", stdout
);
406 * Print out an NFS file handle.
407 * We assume packet was not truncated before the end of the
408 * file handle pointed to by dp.
410 * Note: new version (using portable file-handle parser) doesn't produce
411 * generation number. It probably could be made to do that, with some
412 * additional hacking on the parser code.
415 nfs_printfh(register const u_int32_t
*dp
)
419 char *sfsname
= NULL
;
421 Parse_fh((caddr_t
*)dp
, &fsid
, &ino
, NULL
, &sfsname
, 0);
424 /* file system ID is ASCII, not numeric, for this server OS */
425 static char temp
[NFS_FHSIZE
+1];
427 /* Make sure string is null-terminated */
428 strncpy(temp
, sfsname
, NFS_FHSIZE
);
429 /* Remove trailing spaces */
430 sfsname
= strchr(temp
, ' ');
434 (void)printf(" fh %s/%u", temp
, (u_int32_t
)ino
);
436 (void)printf(" fh %u,%u/%u",
437 fsid
.Fsid_dev
.Major
, fsid
.Fsid_dev
.Minor
, (u_int32_t
)ino
);
442 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
443 * us to match up replies with requests and thus to know how to parse
447 struct xid_map_entry
{
448 u_int32_t xid
; /* transaction ID (net order) */
449 struct in_addr client
; /* client IP address (net order) */
450 struct in_addr server
; /* server IP address (net order) */
451 u_int32_t proc
; /* call proc number (host order) */
455 * Map entries are kept in an array that we manage as a ring;
456 * new entries are always added at the tail of the ring. Initially,
457 * all the entries are zero and hence don't match anything.
460 #define XIDMAPSIZE 64
462 struct xid_map_entry xid_map
[XIDMAPSIZE
];
464 int xid_map_next
= 0;
465 int xid_map_hint
= 0;
468 xid_map_enter(const struct rpc_msg
*rp
, const struct ip
*ip
)
470 struct xid_map_entry
*xmep
;
472 xmep
= &xid_map
[xid_map_next
];
474 if (++xid_map_next
>= XIDMAPSIZE
)
477 xmep
->xid
= rp
->rm_xid
;
478 xmep
->client
= ip
->ip_src
;
479 xmep
->server
= ip
->ip_dst
;
480 xmep
->proc
= ntohl(rp
->rm_call
.cb_proc
);
483 /* Returns NFSPROC_xxx or -1 on failure */
485 xid_map_find(const struct rpc_msg
*rp
, const struct ip
*ip
)
488 struct xid_map_entry
*xmep
;
489 u_int32_t xid
= rp
->rm_xid
;
490 u_int32_t clip
= ip
->ip_dst
.s_addr
;
491 u_int32_t sip
= ip
->ip_src
.s_addr
;
493 /* Start searching from where we last left off */
497 if (xmep
->xid
== xid
&& xmep
->client
.s_addr
== clip
&&
498 xmep
->server
.s_addr
== sip
) {
501 return ((int32_t)xmep
->proc
);
503 if (++i
>= XIDMAPSIZE
)
505 } while (i
!= xid_map_hint
);
512 * Routines for parsing reply packets
516 * Return a pointer to the beginning of the actual results.
517 * If the packet was truncated, return 0.
519 static const u_int32_t
*
520 parserep(register const struct rpc_msg
*rp
, register u_int length
)
522 register const u_int32_t
*dp
;
524 enum accept_stat astat
;
528 * Here we find the address of the ar_verf credentials.
529 * Originally, this calculation was
530 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
531 * On the wire, the rp_acpt field starts immediately after
532 * the (32 bit) rp_stat field. However, rp_acpt (which is a
533 * "struct accepted_reply") contains a "struct opaque_auth",
534 * whose internal representation contains a pointer, so on a
535 * 64-bit machine the compiler inserts 32 bits of padding
536 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
537 * the internal representation to parse the on-the-wire
538 * representation. Instead, we skip past the rp_stat field,
539 * which is an "enum" and so occupies one 32-bit word.
541 dp
= ((const u_int32_t
*)&rp
->rm_reply
) + 1;
547 * skip past the ar_verf credentials.
549 dp
+= (len
+ (2*sizeof(u_int32_t
) + 3)) / sizeof(u_int32_t
);
553 * now we can check the ar_stat field
555 astat
= ntohl(*(enum accept_stat
*)dp
);
562 printf(" PROG_UNAVAIL");
563 nfserr
= 1; /* suppress trunc string */
567 printf(" PROG_MISMATCH");
568 nfserr
= 1; /* suppress trunc string */
572 printf(" PROC_UNAVAIL");
573 nfserr
= 1; /* suppress trunc string */
577 printf(" GARBAGE_ARGS");
578 nfserr
= 1; /* suppress trunc string */
582 printf(" SYSTEM_ERR");
583 nfserr
= 1; /* suppress trunc string */
587 printf(" ar_stat %d", astat
);
588 nfserr
= 1; /* suppress trunc string */
591 /* successful return */
592 if ((sizeof(astat
) + ((u_char
*)dp
)) < snapend
)
593 return ((u_int32_t
*) (sizeof(astat
) + ((char *)dp
)));
599 static const u_int32_t
*
600 parsestatus(const u_int32_t
*dp
)
605 errnum
= ntohl(dp
[0]);
608 printf(" ERROR: %s", pcap_strerror(errnum
));
609 nfserr
= 1; /* suppress trunc string */
617 static struct tok type2str
[] = {
627 static const u_int32_t
*
628 parsefattr(const u_int32_t
*dp
, int verbose
)
630 const struct nfsv2_fattr
*fap
;
632 fap
= (const struct nfsv2_fattr
*)dp
;
634 TCHECK(fap
->fa_nfssize
);
635 printf(" %s %o ids %u/%u sz %u ",
636 tok2str(type2str
, "unk-ft %d ",
637 (u_int32_t
)ntohl(fap
->fa_type
)),
638 (u_int32_t
)ntohl(fap
->fa_mode
),
639 (u_int32_t
)ntohl(fap
->fa_uid
),
640 (u_int32_t
)ntohl(fap
->fa_gid
),
641 (u_int32_t
)ntohl(fap
->fa_nfssize
));
643 /* print lots more stuff */
645 TCHECK(fap
->fa_nfsfileid
);
646 printf("nlink %u rdev %x fsid %x nodeid %x a/m/ctime ",
647 (u_int32_t
)ntohl(fap
->fa_nlink
),
648 (u_int32_t
)ntohl(fap
->fa_nfsrdev
),
649 (u_int32_t
)ntohl(fap
->fa_nfsfsid
),
650 (u_int32_t
)ntohl(fap
->fa_nfsfileid
));
651 TCHECK(fap
->fa_nfsatime
);
653 (u_int32_t
)ntohl(fap
->fa_nfsatime
.nfs_sec
),
654 (u_int32_t
)ntohl(fap
->fa_nfsatime
.nfs_usec
));
655 TCHECK(fap
->fa_nfsmtime
);
657 (u_int32_t
)ntohl(fap
->fa_nfsmtime
.nfs_sec
),
658 (u_int32_t
)ntohl(fap
->fa_nfsmtime
.nfs_usec
));
659 TCHECK(fap
->fa_nfsctime
);
661 (u_int32_t
)ntohl(fap
->fa_nfsctime
.nfs_sec
),
662 (u_int32_t
)ntohl(fap
->fa_nfsctime
.nfs_usec
));
664 return ((const u_int32_t
*)&fap
[1]);
670 parseattrstat(const u_int32_t
*dp
, int verbose
)
673 dp
= parsestatus(dp
);
677 return (parsefattr(dp
, verbose
) != NULL
);
681 parsediropres(const u_int32_t
*dp
)
684 dp
= parsestatus(dp
);
692 return (parsefattr(dp
, vflag
) != NULL
);
696 parselinkres(const u_int32_t
*dp
)
698 dp
= parsestatus(dp
);
703 return (parsefn(dp
) != NULL
);
707 parsestatfs(const u_int32_t
*dp
)
709 const struct nfsv2_statfs
*sfsp
;
711 dp
= parsestatus(dp
);
716 sfsp
= (const struct nfsv2_statfs
*)dp
;
717 TCHECK(sfsp
->sf_bavail
);
718 printf(" tsize %u bsize %u blocks %u bfree %u bavail %u",
719 (u_int32_t
)ntohl(sfsp
->sf_tsize
),
720 (u_int32_t
)ntohl(sfsp
->sf_bsize
),
721 (u_int32_t
)ntohl(sfsp
->sf_blocks
),
722 (u_int32_t
)ntohl(sfsp
->sf_bfree
),
723 (u_int32_t
)ntohl(sfsp
->sf_bavail
));
732 parserddires(const u_int32_t
*dp
)
734 dp
= parsestatus(dp
);
739 printf(" offset %x", (u_int32_t
)ntohl(dp
[0]));
741 printf(" size %u", (u_int32_t
)ntohl(dp
[1]));
753 interp_reply(const struct rpc_msg
*rp
, u_int32_t proc
, u_int length
)
755 register const u_int32_t
*dp
;
764 #define NFSPROC_NOOP -1
770 case NFSPROC_GETATTR
:
772 dp
= parserep(rp
, length
);
773 if (dp
!= NULL
&& parseattrstat(dp
, !qflag
) != 0)
777 case NFSPROC_SETATTR
:
779 dp
= parserep(rp
, length
);
780 if (dp
!= NULL
&& parseattrstat(dp
, !qflag
) != 0)
784 #if NFSPROC_ROOT != NFSPROC_NOOP
791 dp
= parserep(rp
, length
);
792 if (dp
!= NULL
&& parsediropres(dp
) != 0)
796 case NFSPROC_READLINK
:
798 dp
= parserep(rp
, length
);
799 if (dp
!= NULL
&& parselinkres(dp
) != 0)
805 dp
= parserep(rp
, length
);
806 if (dp
!= NULL
&& parseattrstat(dp
, vflag
) != 0)
810 #if NFSPROC_WRITECACHE != NFSPROC_NOOP
811 case NFSPROC_WRITECACHE
:
812 printf(" writecache");
817 dp
= parserep(rp
, length
);
818 if (dp
!= NULL
&& parseattrstat(dp
, vflag
) != 0)
824 dp
= parserep(rp
, length
);
825 if (dp
!= NULL
&& parsediropres(dp
) != 0)
831 dp
= parserep(rp
, length
);
832 if (dp
!= NULL
&& parsestatus(dp
) != 0)
838 dp
= parserep(rp
, length
);
839 if (dp
!= NULL
&& parsestatus(dp
) != 0)
845 dp
= parserep(rp
, length
);
846 if (dp
!= NULL
&& parsestatus(dp
) != 0)
850 case NFSPROC_SYMLINK
:
852 dp
= parserep(rp
, length
);
853 if (dp
!= NULL
&& parsestatus(dp
) != 0)
859 dp
= parserep(rp
, length
);
860 if (dp
!= NULL
&& parsediropres(dp
) != 0)
866 dp
= parserep(rp
, length
);
867 if (dp
!= NULL
&& parsestatus(dp
) != 0)
871 case NFSPROC_READDIR
:
873 dp
= parserep(rp
, length
);
874 if (dp
!= NULL
&& parserddires(dp
) != 0)
880 dp
= parserep(rp
, length
);
881 if (dp
!= NULL
&& parsestatfs(dp
) != 0)
886 printf(" proc-%u", proc
);
890 fputs(" [|nfs]", stdout
);