This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / contrib / tcpdump / tcpdump / print-nfs.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1990, 1991, 1992 The Regents of the University of California.
3 * All rights reserved.
4 *
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
16 * written permission.
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.
20 */
21
22#ifndef lint
23static char rcsid[] =
78ed81a3 24 "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-nfs.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
15637ed4
RG
25#endif
26
27#include <stdio.h>
28#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <net/if.h>
32#include <netinet/in.h>
33#include <netinet/if_ether.h>
34#include <netinet/in_systm.h>
35#include <netinet/ip.h>
36#include <netinet/ip_var.h>
37
38#include <sys/time.h>
39#include <errno.h>
78ed81a3 40#include <rpc/rpc.h>
15637ed4
RG
41
42#include <ctype.h>
43
44#include "interface.h"
45/* These must come after interface.h for BSD. */
46#if BSD >= 199006
47#include <sys/ucred.h>
48#include <nfs/nfsv2.h>
49#endif
50#include <nfs/nfs.h>
51
52#include "addrtoname.h"
53#include "extract.h"
54
55static void nfs_printfh();
56static void nfs_printfn();
57
58#if BYTE_ORDER == LITTLE_ENDIAN
59/*
60 * Byte swap an array of n words.
61 * Assume input is word-aligned.
62 * Check that buffer is bounded by "snapend".
63 */
64static void
65bswap(bp, n)
66 register u_long *bp;
67 register u_int n;
68{
69 register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp);
70
71 if (nwords > n)
72 nwords = n;
73 for (; --nwords >= 0; ++bp)
74 *bp = ntohl(*bp);
75}
76#endif
77
78void
79nfsreply_print(rp, length, ip)
80 register struct rpc_msg *rp;
81 int length;
82 register struct ip *ip;
83{
84#if BYTE_ORDER == LITTLE_ENDIAN
85 bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
86#endif
87 if (!nflag)
88 (void)printf("%s.nfs > %s.%x: reply %s %d",
89 ipaddr_string(&ip->ip_src),
90 ipaddr_string(&ip->ip_dst),
91 rp->rm_xid,
92 rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR",
93 length);
94 else
95 (void)printf("%s.%x > %s.%x: reply %s %d",
96 ipaddr_string(&ip->ip_src),
97 NFS_PORT,
98 ipaddr_string(&ip->ip_dst),
99 rp->rm_xid,
100 rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR",
101 length);
102}
103
104/*
105 * Return a pointer to the first file handle in the packet.
106 * If the packet was truncated, return 0.
107 */
108static u_long *
109parsereq(rp, length)
110 register struct rpc_msg *rp;
111 register int length;
112{
113 register u_long *dp = (u_long *)&rp->rm_call.cb_cred;
114 register u_long *ep = (u_long *)snapend;
115
116 /*
117 * find the start of the req data (if we captured it)
118 * note that dp[1] was already byte swapped by bswap()
119 */
120 if (dp < ep && dp[1] < length) {
121 dp += (dp[1] + (2*sizeof(u_long) + 3)) / sizeof(u_long);
122 if ((dp < ep) && (dp[1] < length)) {
123 dp += (dp[1] + (2*sizeof(u_long) + 3)) /
124 sizeof(u_long);
125 if (dp < ep)
126 return (dp);
127 }
128 }
129 return (0);
130}
131
132/*
133 * Print out an NFS file handle and return a pointer to following word.
134 * If packet was truncated, return 0.
135 */
136static u_long *
137parsefh(dp)
138 register u_long *dp;
139{
140 if (dp + 8 <= (u_long *)snapend) {
141 nfs_printfh(dp);
142 return (dp + 8);
143 }
144 return (0);
145}
146
147/*
148 * Print out a file name and return pointer to longword past it.
149 * If packet was truncated, return 0.
150 */
151static u_long *
152parsefn(dp)
153 register u_long *dp;
154{
155 register int len;
156 register u_char *cp;
157
158 /* Bail if we don't have the string length */
159 if ((u_char *)dp > snapend - sizeof(*dp))
160 return(0);
161
162 /* Fetch string length; convert to host order */
163 len = *dp++;
164 NTOHL(len);
165
166 cp = (u_char *)dp;
167 /* Update long pointer (NFS filenames are padded to long) */
168 dp += ((len + 3) & ~3) / sizeof(*dp);
169 if ((u_char *)dp > snapend)
170 return (0);
171 nfs_printfn(cp, len);
172
173 return (dp);
174}
175
176/*
177 * Print out file handle and file name.
178 * Return pointer to longword past file name.
179 * If packet was truncated (or there was some other error), return 0.
180 */
181static u_long *
182parsefhn(dp)
183 register u_long *dp;
184{
185 dp = parsefh(dp);
186 if (dp == 0)
187 return (0);
188 putchar(' ');
189 return (parsefn(dp));
190}
191
192void
193nfsreq_print(rp, length, ip)
194 register struct rpc_msg *rp;
195 int length;
196 register struct ip *ip;
197{
198 register u_long *dp;
199 register u_char *ep = snapend;
200#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break
201
202#if BYTE_ORDER == LITTLE_ENDIAN
203 bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
204#endif
205
206 if (!nflag)
207 (void)printf("%s.%x > %s.nfs: %d",
208 ipaddr_string(&ip->ip_src),
209 rp->rm_xid,
210 ipaddr_string(&ip->ip_dst),
211 length);
212 else
213 (void)printf("%s.%x > %s.%x: %d",
214 ipaddr_string(&ip->ip_src),
215 rp->rm_xid,
216 ipaddr_string(&ip->ip_dst),
217 NFS_PORT,
218 length);
219
220 switch (rp->rm_call.cb_proc) {
221#ifdef NFSPROC_NOOP
222 case NFSPROC_NOOP:
223 printf(" nop");
224 return;
225#else
226#define NFSPROC_NOOP -1
227#endif
228 case RFS_NULL:
229 printf(" null");
230 return;
231
232 case RFS_GETATTR:
233 printf(" getattr");
234 if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
235 return;
236 break;
237
238 case RFS_SETATTR:
239 printf(" setattr");
240 if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
241 return;
242 break;
243
244#if RFS_ROOT != NFSPROC_NOOP
245 case RFS_ROOT:
246 printf(" root");
247 break;
248#endif
249 case RFS_LOOKUP:
250 printf(" lookup");
251 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
252 return;
253 break;
254
255 case RFS_READLINK:
256 printf(" readlink");
257 if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
258 return;
259 break;
260
261 case RFS_READ:
262 printf(" read");
263 if ((dp = parsereq(rp, length)) != 0 &&
264 (dp = parsefh(dp)) != 0) {
265 TCHECK(dp, 3 * sizeof(*dp));
266 printf(" %lu (%lu) bytes @ %lu",
267 ntohl(dp[1]), ntohl(dp[2]), ntohl(dp[0]));
268 return;
269 }
270 break;
271
272#if RFS_WRITECACHE != NFSPROC_NOOP
273 case RFS_WRITECACHE:
274 printf(" writecache");
275 if ((dp = parsereq(rp, length)) != 0 &&
276 (dp = parsefh(dp)) != 0) {
277 TCHECK(dp, 4 * sizeof(*dp));
278 printf(" %lu (%lu) bytes @ %lu (%lu)",
279 ntohl(dp[3]), ntohl(dp[2]),
280 ntohl(dp[1]), ntohl(dp[0]));
281 return;
282 }
283 break;
284#endif
285 case RFS_WRITE:
286 printf(" write");
287 if ((dp = parsereq(rp, length)) != 0 &&
288 (dp = parsefh(dp)) != 0) {
289 TCHECK(dp, 4 * sizeof(*dp));
290 printf(" %lu (%lu) bytes @ %lu (%lu)",
291 ntohl(dp[3]), ntohl(dp[2]),
292 ntohl(dp[1]), ntohl(dp[0]));
293 return;
294 }
295 break;
296
297 case RFS_CREATE:
298 printf(" create");
299 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
300 return;
301 break;
302
303 case RFS_REMOVE:
304 printf(" remove");
305 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
306 return;
307 break;
308
309 case RFS_RENAME:
310 printf(" rename");
311 if ((dp = parsereq(rp, length)) != 0 &&
312 (dp = parsefhn(dp)) != 0) {
313 fputs(" ->", stdout);
314 if (parsefhn(dp) != 0)
315 return;
316 }
317 break;
318
319 case RFS_LINK:
320 printf(" link");
321 if ((dp = parsereq(rp, length)) != 0 &&
322 (dp = parsefh(dp)) != 0) {
323 fputs(" ->", stdout);
324 if (parsefhn(dp) != 0)
325 return;
326 }
327 break;
328
329 case RFS_SYMLINK:
330 printf(" symlink");
331 if ((dp = parsereq(rp, length)) != 0 &&
332 (dp = parsefhn(dp)) != 0) {
333 fputs(" -> ", stdout);
334 if (parsefn(dp) != 0)
335 return;
336 }
337 break;
338
339 case RFS_MKDIR:
340 printf(" mkdir");
341 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
342 return;
343 break;
344
345 case RFS_RMDIR:
346 printf(" rmdir");
347 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
348 return;
349 break;
350
351 case RFS_READDIR:
352 printf(" readdir");
353 if ((dp = parsereq(rp, length)) != 0 &&
354 (dp = parsefh(dp)) != 0) {
355 TCHECK(dp, 2 * sizeof(*dp));
356 printf(" %lu bytes @ %lu", ntohl(dp[1]), ntohl(dp[0]));
357 return;
358 }
359 break;
360
361 case RFS_STATFS:
362 printf(" statfs");
363 if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
364 return;
365 break;
366
367 default:
368 printf(" proc-%lu", rp->rm_call.cb_proc);
369 return;
370 }
371 fputs(" [|nfs]", stdout);
372#undef TCHECK
373}
374
375/*
376 * Print out an NFS file handle.
377 * We assume packet was not truncated before the end of the
378 * file handle pointed to by dp.
379 */
380static void
381nfs_printfh(dp)
382 register u_long *dp;
383{
384 /*
385 * take a wild guess at the structure of file handles.
386 * On sun 3s, there are 2 longs of fsid, a short
387 * len == 8, a long of inode & a long of generation number.
388 * On sun 4s, the len == 10 & there are 2 bytes of
389 * padding immediately following it.
390 */
391 if (dp[2] == 0xa0000) {
392 if (dp[1])
393 (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], dp[3]);
394 else
395 (void) printf(" fh %ld.%ld", dp[0], dp[3]);
396 } else if ((dp[2] >> 16) == 8)
397 /*
398 * 'dp' is longword aligned, so we must use the extract
399 * macros below for dp+10 which cannot possibly be aligned.
400 */
401 if (dp[1])
402 (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1],
403 EXTRACT_LONG((u_char *)dp + 10));
404 else
405 (void) printf(" fh %ld.%ld", dp[0],
406 EXTRACT_LONG((u_char *)dp + 10));
407 /* On Ultrix pre-4.0, three longs: fsid, fno, fgen and then zeros */
408 else if (dp[3] == 0) {
409 (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]),
410 dp[1], dp[2]);
411 }
412 /*
413 * On Ultrix 4.0,
414 * five longs: fsid, fno, fgen, eno, egen and then zeros
415 */
416 else if (dp[5] == 0) {
417 (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]),
418 dp[1], dp[2]);
419 if (vflag) {
420 /* print additional info */
421 (void)printf("[%ld.%ld]", dp[3], dp[4]);
422 }
423 }
424 else
425 (void) printf(" fh %lu.%lu.%lu.%lu",
426 dp[0], dp[1], dp[2], dp[3]);
427}
428
429/*
430 * Print out an NFS filename.
431 * Assumes that len bytes from cp are present in packet.
432 */
433static void
434nfs_printfn(cp, len)
435 register u_char *cp;
436 register int len;
437{
438 register char c;
439
440 /* Sanity */
441 if (len >= 64) {
442 fputs("[\">]", stdout);
443 return;
444 }
445 /* Print out the filename */
446 putchar('"');
447 while (--len >= 0) {
448 c = toascii(*cp++);
449 if (!isascii(c)) {
450 c = toascii(c);
451 putchar('M');
452 putchar('-');
453 }
454 if (!isprint(c)) {
455 c ^= 0x40; /* DEL to ?, others to alpha */
456 putchar('^');
457 }
458 putchar(c);
459 }
460 putchar('"');
461}