freebsd-skq/contrib/tcpdump/print-rx.c

2799 lines
60 KiB
C
Raw Normal View History

/*
* Copyright: (c) 2000 United States Government as represented by the
* Secretary of the Navy. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* This code unmangles RX packets. RX is the mutant form of RPC that AFS
* uses to communicate between clients and servers.
*
* In this code, I mainly concern myself with decoding the AFS calls, not
* with the guts of RX, per se.
*
* Bah. If I never look at rx_packet.h again, it will be too soon.
*
* Ken Hornstein <kenh@cmf.nrl.navy.mil>
*/
#ifndef lint
static const char rcsid[] _U_ =
Update tcpdump to 4.1.1. Changes: Thu. April 1, 2010. guy@alum.mit.edu. Summary for 4.1.1 tcpdump release Fix build on systems with PF, such as FreeBSD and OpenBSD. Don't blow up if a zero-length link-layer address is passed to linkaddr_string(). Thu. March 11, 2010. ken@netfunctional.ca/guy@alum.mit.edu. Summary for 4.1.0 tcpdump release Fix printing of MAC addresses for VLAN frames with a length field Add some additional bounds checks and use the EXTRACT_ macros more Add a -b flag to print the AS number in BGP packets in ASDOT notation rather than ASPLAIN notation Add ICMPv6 RFC 5006 support Decode the access flags in NFS access requests Handle the new DLT_ for memory-mapped USB captures on Linux Make the default snapshot (-s) the maximum Print name of device (when -L is used) Support for OpenSolaris (and SXCE build 125 and later) Print new TCP flags Add support for RPL DIO Add support for TCP User Timeout (UTO) Add support for non-standard Ethertypes used by 3com PPPoE gear Add support for 802.11n and 802.11s Add support for Transparent Ethernet Bridge ethertype in GRE Add 4 byte AS support for BGP printer Add support for the MDT SAFI 66 BG printer Add basic IPv6 support to print-olsr Add USB printer Add printer for ForCES Handle frames with an FCS Handle 802.11n Control Wrapper, Block Acq Req and Block Ack frames Fix TCP sequence number printing Report 802.2 packets as 802.2 instead of 802.3 Don't include -L/usr/lib in LDFLAGS On x86_64 Linux, look in lib64 directory too Lots of code clean ups Autoconf clean ups Update testcases to make output changes Fix compiling with/out smi (--with{,out}-smi) Fix compiling without IPv6 support (--disable-ipv6)
2010-10-28 16:23:25 +00:00
"@(#) $Header: /tcpdump/master/tcpdump/print-rx.c,v 1.42 2008-07-01 07:44:50 guy Exp $";
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tcpdump-stdinc.h>
#include "interface.h"
#include "addrtoname.h"
#include "extract.h"
#include "rx.h"
#include "ip.h"
static struct tok rx_types[] = {
{ RX_PACKET_TYPE_DATA, "data" },
{ RX_PACKET_TYPE_ACK, "ack" },
{ RX_PACKET_TYPE_BUSY, "busy" },
{ RX_PACKET_TYPE_ABORT, "abort" },
{ RX_PACKET_TYPE_ACKALL, "ackall" },
{ RX_PACKET_TYPE_CHALLENGE, "challenge" },
{ RX_PACKET_TYPE_RESPONSE, "response" },
{ RX_PACKET_TYPE_DEBUG, "debug" },
{ RX_PACKET_TYPE_PARAMS, "params" },
{ RX_PACKET_TYPE_VERSION, "version" },
{ 0, NULL },
};
static struct double_tok {
int flag; /* Rx flag */
int packetType; /* Packet type */
const char *s; /* Flag string */
} rx_flags[] = {
{ RX_CLIENT_INITIATED, 0, "client-init" },
{ RX_REQUEST_ACK, 0, "req-ack" },
{ RX_LAST_PACKET, 0, "last-pckt" },
{ RX_MORE_PACKETS, 0, "more-pckts" },
{ RX_FREE_PACKET, 0, "free-pckt" },
{ RX_SLOW_START_OK, RX_PACKET_TYPE_ACK, "slow-start" },
{ RX_JUMBO_PACKET, RX_PACKET_TYPE_DATA, "jumbogram" }
};
static struct tok fs_req[] = {
{ 130, "fetch-data" },
{ 131, "fetch-acl" },
{ 132, "fetch-status" },
{ 133, "store-data" },
{ 134, "store-acl" },
{ 135, "store-status" },
{ 136, "remove-file" },
{ 137, "create-file" },
{ 138, "rename" },
{ 139, "symlink" },
{ 140, "link" },
{ 141, "makedir" },
{ 142, "rmdir" },
{ 143, "oldsetlock" },
{ 144, "oldextlock" },
{ 145, "oldrellock" },
{ 146, "get-stats" },
{ 147, "give-cbs" },
{ 148, "get-vlinfo" },
{ 149, "get-vlstats" },
{ 150, "set-vlstats" },
{ 151, "get-rootvl" },
{ 152, "check-token" },
{ 153, "get-time" },
{ 154, "nget-vlinfo" },
{ 155, "bulk-stat" },
{ 156, "setlock" },
{ 157, "extlock" },
{ 158, "rellock" },
{ 159, "xstat-ver" },
{ 160, "get-xstat" },
{ 161, "dfs-lookup" },
{ 162, "dfs-flushcps" },
{ 163, "dfs-symlink" },
{ 220, "residency" },
2009-03-21 16:23:46 +00:00
{ 65536, "inline-bulk-status" },
{ 65537, "fetch-data-64" },
{ 65538, "store-data-64" },
{ 65539, "give-up-all-cbs" },
{ 65540, "get-caps" },
{ 65541, "cb-rx-conn-addr" },
{ 0, NULL },
};
static struct tok cb_req[] = {
{ 204, "callback" },
{ 205, "initcb" },
{ 206, "probe" },
{ 207, "getlock" },
{ 208, "getce" },
{ 209, "xstatver" },
{ 210, "getxstat" },
{ 211, "initcb2" },
{ 212, "whoareyou" },
{ 213, "initcb3" },
{ 214, "probeuuid" },
{ 215, "getsrvprefs" },
{ 216, "getcellservdb" },
{ 217, "getlocalcell" },
{ 218, "getcacheconf" },
2009-03-21 16:23:46 +00:00
{ 65536, "getce64" },
{ 65537, "getcellbynum" },
{ 65538, "tellmeaboutyourself" },
{ 0, NULL },
};
static struct tok pt_req[] = {
{ 500, "new-user" },
{ 501, "where-is-it" },
{ 502, "dump-entry" },
{ 503, "add-to-group" },
{ 504, "name-to-id" },
{ 505, "id-to-name" },
{ 506, "delete" },
{ 507, "remove-from-group" },
{ 508, "get-cps" },
{ 509, "new-entry" },
{ 510, "list-max" },
{ 511, "set-max" },
{ 512, "list-entry" },
{ 513, "change-entry" },
{ 514, "list-elements" },
{ 515, "same-mbr-of" },
{ 516, "set-fld-sentry" },
{ 517, "list-owned" },
{ 518, "get-cps2" },
{ 519, "get-host-cps" },
{ 520, "update-entry" },
{ 521, "list-entries" },
2009-03-21 16:23:46 +00:00
{ 530, "list-super-groups" },
{ 0, NULL },
};
static struct tok vldb_req[] = {
{ 501, "create-entry" },
{ 502, "delete-entry" },
{ 503, "get-entry-by-id" },
{ 504, "get-entry-by-name" },
{ 505, "get-new-volume-id" },
{ 506, "replace-entry" },
{ 507, "update-entry" },
{ 508, "setlock" },
{ 509, "releaselock" },
{ 510, "list-entry" },
{ 511, "list-attrib" },
{ 512, "linked-list" },
{ 513, "get-stats" },
{ 514, "probe" },
{ 515, "get-addrs" },
{ 516, "change-addr" },
{ 517, "create-entry-n" },
{ 518, "get-entry-by-id-n" },
{ 519, "get-entry-by-name-n" },
{ 520, "replace-entry-n" },
{ 521, "list-entry-n" },
{ 522, "list-attrib-n" },
{ 523, "linked-list-n" },
{ 524, "update-entry-by-name" },
{ 525, "create-entry-u" },
{ 526, "get-entry-by-id-u" },
{ 527, "get-entry-by-name-u" },
{ 528, "replace-entry-u" },
{ 529, "list-entry-u" },
{ 530, "list-attrib-u" },
{ 531, "linked-list-u" },
{ 532, "regaddr" },
{ 533, "get-addrs-u" },
{ 534, "list-attrib-n2" },
{ 0, NULL },
};
static struct tok kauth_req[] = {
{ 1, "auth-old" },
{ 21, "authenticate" },
{ 22, "authenticate-v2" },
{ 2, "change-pw" },
{ 3, "get-ticket-old" },
{ 23, "get-ticket" },
{ 4, "set-pw" },
{ 5, "set-fields" },
{ 6, "create-user" },
{ 7, "delete-user" },
{ 8, "get-entry" },
{ 9, "list-entry" },
{ 10, "get-stats" },
{ 11, "debug" },
{ 12, "get-pw" },
{ 13, "get-random-key" },
{ 14, "unlock" },
{ 15, "lock-status" },
{ 0, NULL },
};
static struct tok vol_req[] = {
{ 100, "create-volume" },
{ 101, "delete-volume" },
{ 102, "restore" },
{ 103, "forward" },
{ 104, "end-trans" },
{ 105, "clone" },
{ 106, "set-flags" },
{ 107, "get-flags" },
{ 108, "trans-create" },
{ 109, "dump" },
{ 110, "get-nth-volume" },
{ 111, "set-forwarding" },
{ 112, "get-name" },
{ 113, "get-status" },
{ 114, "sig-restore" },
{ 115, "list-partitions" },
{ 116, "list-volumes" },
{ 117, "set-id-types" },
{ 118, "monitor" },
{ 119, "partition-info" },
{ 120, "reclone" },
{ 121, "list-one-volume" },
{ 122, "nuke" },
{ 123, "set-date" },
{ 124, "x-list-volumes" },
{ 125, "x-list-one-volume" },
{ 126, "set-info" },
{ 127, "x-list-partitions" },
{ 128, "forward-multiple" },
2009-03-21 16:23:46 +00:00
{ 65536, "convert-ro" },
{ 65537, "get-size" },
{ 65538, "dump-v2" },
{ 0, NULL },
};
static struct tok bos_req[] = {
{ 80, "create-bnode" },
{ 81, "delete-bnode" },
{ 82, "set-status" },
{ 83, "get-status" },
{ 84, "enumerate-instance" },
{ 85, "get-instance-info" },
{ 86, "get-instance-parm" },
{ 87, "add-superuser" },
{ 88, "delete-superuser" },
{ 89, "list-superusers" },
{ 90, "list-keys" },
{ 91, "add-key" },
{ 92, "delete-key" },
{ 93, "set-cell-name" },
{ 94, "get-cell-name" },
{ 95, "get-cell-host" },
{ 96, "add-cell-host" },
{ 97, "delete-cell-host" },
{ 98, "set-t-status" },
{ 99, "shutdown-all" },
{ 100, "restart-all" },
{ 101, "startup-all" },
{ 102, "set-noauth-flag" },
{ 103, "re-bozo" },
{ 104, "restart" },
{ 105, "start-bozo-install" },
{ 106, "uninstall" },
{ 107, "get-dates" },
{ 108, "exec" },
{ 109, "prune" },
{ 110, "set-restart-time" },
{ 111, "get-restart-time" },
{ 112, "start-bozo-log" },
{ 113, "wait-all" },
{ 114, "get-instance-strings" },
{ 115, "get-restricted" },
{ 116, "set-restricted" },
{ 0, NULL },
};
static struct tok ubik_req[] = {
{ 10000, "vote-beacon" },
{ 10001, "vote-debug-old" },
{ 10002, "vote-sdebug-old" },
{ 10003, "vote-getsyncsite" },
{ 10004, "vote-debug" },
{ 10005, "vote-sdebug" },
2009-03-21 16:23:46 +00:00
{ 10006, "vote-xdebug" },
{ 10007, "vote-xsdebug" },
{ 20000, "disk-begin" },
{ 20001, "disk-commit" },
{ 20002, "disk-lock" },
{ 20003, "disk-write" },
{ 20004, "disk-getversion" },
{ 20005, "disk-getfile" },
{ 20006, "disk-sendfile" },
{ 20007, "disk-abort" },
{ 20008, "disk-releaselocks" },
{ 20009, "disk-truncate" },
{ 20010, "disk-probe" },
{ 20011, "disk-writev" },
{ 20012, "disk-interfaceaddr" },
{ 20013, "disk-setversion" },
{ 0, NULL },
};
#define VOTE_LOW 10000
2009-03-21 16:23:46 +00:00
#define VOTE_HIGH 10007
#define DISK_LOW 20000
#define DISK_HIGH 20013
static struct tok cb_types[] = {
{ 1, "exclusive" },
{ 2, "shared" },
{ 3, "dropped" },
{ 0, NULL },
};
static struct tok ubik_lock_types[] = {
{ 1, "read" },
{ 2, "write" },
{ 3, "wait" },
{ 0, NULL },
};
static const char *voltype[] = { "read-write", "read-only", "backup" };
static struct tok afs_fs_errors[] = {
{ 101, "salvage volume" },
{ 102, "no such vnode" },
{ 103, "no such volume" },
{ 104, "volume exist" },
{ 105, "no service" },
{ 106, "volume offline" },
{ 107, "voline online" },
{ 108, "diskfull" },
{ 109, "diskquota exceeded" },
{ 110, "volume busy" },
{ 111, "volume moved" },
{ 112, "AFS IO error" },
{ -100, "restarting fileserver" },
{ 0, NULL }
};
/*
* Reasons for acknowledging a packet
*/
static struct tok rx_ack_reasons[] = {
{ 1, "ack requested" },
{ 2, "duplicate packet" },
{ 3, "out of sequence" },
{ 4, "exceeds window" },
{ 5, "no buffer space" },
{ 6, "ping" },
{ 7, "ping response" },
{ 8, "delay" },
{ 9, "idle" },
{ 0, NULL },
};
/*
* Cache entries we keep around so we can figure out the RX opcode
* numbers for replies. This allows us to make sense of RX reply packets.
*/
struct rx_cache_entry {
u_int32_t callnum; /* Call number (net order) */
struct in_addr client; /* client IP address (net order) */
struct in_addr server; /* server IP address (net order) */
int dport; /* server port (host order) */
u_short serviceId; /* Service identifier (net order) */
u_int32_t opcode; /* RX opcode (host order) */
};
#define RX_CACHE_SIZE 64
static struct rx_cache_entry rx_cache[RX_CACHE_SIZE];
static int rx_cache_next = 0;
static int rx_cache_hint = 0;
static void rx_cache_insert(const u_char *, const struct ip *, int);
static int rx_cache_find(const struct rx_header *, const struct ip *,
int, int32_t *);
static void fs_print(const u_char *, int);
static void fs_reply_print(const u_char *, int, int32_t);
static void acl_print(u_char *, int, u_char *);
static void cb_print(const u_char *, int);
static void cb_reply_print(const u_char *, int, int32_t);
static void prot_print(const u_char *, int);
static void prot_reply_print(const u_char *, int, int32_t);
static void vldb_print(const u_char *, int);
static void vldb_reply_print(const u_char *, int, int32_t);
static void kauth_print(const u_char *, int);
static void kauth_reply_print(const u_char *, int, int32_t);
static void vol_print(const u_char *, int);
static void vol_reply_print(const u_char *, int, int32_t);
static void bos_print(const u_char *, int);
static void bos_reply_print(const u_char *, int, int32_t);
static void ubik_print(const u_char *);
static void ubik_reply_print(const u_char *, int, int32_t);
static void rx_ack_print(const u_char *, int);
static int is_ubik(u_int32_t);
/*
* Handle the rx-level packet. See if we know what port it's going to so
* we can peek at the afs call inside
*/
void
rx_print(register const u_char *bp, int length, int sport, int dport,
u_char *bp2)
{
register struct rx_header *rxh;
int i;
int32_t opcode;
if (snapend - bp < (int)sizeof (struct rx_header)) {
printf(" [|rx] (%d)", length);
return;
}
rxh = (struct rx_header *) bp;
printf(" rx %s", tok2str(rx_types, "type %d", rxh->type));
if (vflag) {
int firstflag = 0;
if (vflag > 1)
printf(" cid %08x call# %d",
(int) EXTRACT_32BITS(&rxh->cid),
(int) EXTRACT_32BITS(&rxh->callNumber));
printf(" seq %d ser %d",
(int) EXTRACT_32BITS(&rxh->seq),
(int) EXTRACT_32BITS(&rxh->serial));
if (vflag > 2)
printf(" secindex %d serviceid %hu",
(int) rxh->securityIndex,
EXTRACT_16BITS(&rxh->serviceId));
if (vflag > 1)
for (i = 0; i < NUM_RX_FLAGS; i++) {
if (rxh->flags & rx_flags[i].flag &&
(!rx_flags[i].packetType ||
rxh->type == rx_flags[i].packetType)) {
if (!firstflag) {
firstflag = 1;
printf(" ");
} else {
printf(",");
}
printf("<%s>", rx_flags[i].s);
}
}
}
/*
* Try to handle AFS calls that we know about. Check the destination
* port and make sure it's a data packet. Also, make sure the
* seq number is 1 (because otherwise it's a continuation packet,
* and we can't interpret that). Also, seems that reply packets
* do not have the client-init flag set, so we check for that
* as well.
*/
if (rxh->type == RX_PACKET_TYPE_DATA &&
EXTRACT_32BITS(&rxh->seq) == 1 &&
rxh->flags & RX_CLIENT_INITIATED) {
/*
* Insert this call into the call cache table, so we
* have a chance to print out replies
*/
rx_cache_insert(bp, (const struct ip *) bp2, dport);
switch (dport) {
case FS_RX_PORT: /* AFS file service */
fs_print(bp, length);
break;
case CB_RX_PORT: /* AFS callback service */
cb_print(bp, length);
break;
case PROT_RX_PORT: /* AFS protection service */
prot_print(bp, length);
break;
case VLDB_RX_PORT: /* AFS VLDB service */
vldb_print(bp, length);
break;
case KAUTH_RX_PORT: /* AFS Kerberos auth service */
kauth_print(bp, length);
break;
case VOL_RX_PORT: /* AFS Volume service */
vol_print(bp, length);
break;
case BOS_RX_PORT: /* AFS BOS service */
bos_print(bp, length);
break;
default:
;
}
/*
* If it's a reply (client-init is _not_ set, but seq is one)
* then look it up in the cache. If we find it, call the reply
* printing functions Note that we handle abort packets here,
* because printing out the return code can be useful at times.
*/
} else if (((rxh->type == RX_PACKET_TYPE_DATA &&
EXTRACT_32BITS(&rxh->seq) == 1) ||
rxh->type == RX_PACKET_TYPE_ABORT) &&
(rxh->flags & RX_CLIENT_INITIATED) == 0 &&
rx_cache_find(rxh, (const struct ip *) bp2,
sport, &opcode)) {
switch (sport) {
case FS_RX_PORT: /* AFS file service */
fs_reply_print(bp, length, opcode);
break;
case CB_RX_PORT: /* AFS callback service */
cb_reply_print(bp, length, opcode);
break;
case PROT_RX_PORT: /* AFS PT service */
prot_reply_print(bp, length, opcode);
break;
case VLDB_RX_PORT: /* AFS VLDB service */
vldb_reply_print(bp, length, opcode);
break;
case KAUTH_RX_PORT: /* AFS Kerberos auth service */
kauth_reply_print(bp, length, opcode);
break;
case VOL_RX_PORT: /* AFS Volume service */
vol_reply_print(bp, length, opcode);
break;
case BOS_RX_PORT: /* AFS BOS service */
bos_reply_print(bp, length, opcode);
break;
default:
;
}
/*
* If it's an RX ack packet, then use the appropriate ack decoding
* function (there isn't any service-specific information in the
* ack packet, so we can use one for all AFS services)
*/
} else if (rxh->type == RX_PACKET_TYPE_ACK)
rx_ack_print(bp, length);
printf(" (%d)", length);
}
/*
* Insert an entry into the cache. Taken from print-nfs.c
*/
static void
rx_cache_insert(const u_char *bp, const struct ip *ip, int dport)
{
struct rx_cache_entry *rxent;
const struct rx_header *rxh = (const struct rx_header *) bp;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t)))
return;
rxent = &rx_cache[rx_cache_next];
if (++rx_cache_next >= RX_CACHE_SIZE)
rx_cache_next = 0;
rxent->callnum = rxh->callNumber;
rxent->client = ip->ip_src;
rxent->server = ip->ip_dst;
rxent->dport = dport;
rxent->serviceId = rxh->serviceId;
rxent->opcode = EXTRACT_32BITS(bp + sizeof(struct rx_header));
}
/*
* Lookup an entry in the cache. Also taken from print-nfs.c
*
* Note that because this is a reply, we're looking at the _source_
* port.
*/
static int
rx_cache_find(const struct rx_header *rxh, const struct ip *ip, int sport,
int32_t *opcode)
{
int i;
struct rx_cache_entry *rxent;
u_int32_t clip = ip->ip_dst.s_addr;
u_int32_t sip = ip->ip_src.s_addr;
/* Start the search where we last left off */
i = rx_cache_hint;
do {
rxent = &rx_cache[i];
if (rxent->callnum == rxh->callNumber &&
rxent->client.s_addr == clip &&
rxent->server.s_addr == sip &&
rxent->serviceId == rxh->serviceId &&
rxent->dport == sport) {
/* We got a match! */
rx_cache_hint = i;
*opcode = rxent->opcode;
return(1);
}
if (++i > RX_CACHE_SIZE)
i = 0;
} while (i != rx_cache_hint);
/* Our search failed */
return(0);
}
/*
* These extrememly grody macros handle the printing of various AFS stuff.
*/
#define FIDOUT() { unsigned long n1, n2, n3; \
TCHECK2(bp[0], sizeof(int32_t) * 3); \
n1 = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
n2 = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
n3 = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
printf(" fid %d/%d/%d", (int) n1, (int) n2, (int) n3); \
}
#define STROUT(MAX) { unsigned int i; \
TCHECK2(bp[0], sizeof(int32_t)); \
i = EXTRACT_32BITS(bp); \
if (i > (MAX)) \
goto trunc; \
bp += sizeof(int32_t); \
printf(" \""); \
if (fn_printn(bp, i, snapend)) \
goto trunc; \
printf("\""); \
bp += ((i + sizeof(int32_t) - 1) / sizeof(int32_t)) * sizeof(int32_t); \
}
#define INTOUT() { int i; \
TCHECK2(bp[0], sizeof(int32_t)); \
i = (int) EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
printf(" %d", i); \
}
#define UINTOUT() { unsigned long i; \
TCHECK2(bp[0], sizeof(int32_t)); \
i = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
printf(" %lu", i); \
}
2009-03-21 16:23:46 +00:00
#define UINT64OUT() { u_int64_t i; \
TCHECK2(bp[0], sizeof(u_int64_t)); \
i = EXTRACT_64BITS(bp); \
bp += sizeof(u_int64_t); \
printf(" %" PRIu64, i); \
}
#define DATEOUT() { time_t t; struct tm *tm; char str[256]; \
TCHECK2(bp[0], sizeof(int32_t)); \
t = (time_t) EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
tm = localtime(&t); \
strftime(str, 256, "%Y/%m/%d %T", tm); \
printf(" %s", str); \
}
#define STOREATTROUT() { unsigned long mask, i; \
TCHECK2(bp[0], (sizeof(int32_t)*6)); \
mask = EXTRACT_32BITS(bp); bp += sizeof(int32_t); \
if (mask) printf (" StoreStatus"); \
if (mask & 1) { printf(" date"); DATEOUT(); } \
else bp += sizeof(int32_t); \
i = EXTRACT_32BITS(bp); bp += sizeof(int32_t); \
if (mask & 2) printf(" owner %lu", i); \
i = EXTRACT_32BITS(bp); bp += sizeof(int32_t); \
if (mask & 4) printf(" group %lu", i); \
i = EXTRACT_32BITS(bp); bp += sizeof(int32_t); \
if (mask & 8) printf(" mode %lo", i & 07777); \
i = EXTRACT_32BITS(bp); bp += sizeof(int32_t); \
if (mask & 16) printf(" segsize %lu", i); \
/* undocumented in 3.3 docu */ \
if (mask & 1024) printf(" fsync"); \
}
#define UBIK_VERSIONOUT() {int32_t epoch; int32_t counter; \
TCHECK2(bp[0], sizeof(int32_t) * 2); \
epoch = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
counter = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
printf(" %d.%d", epoch, counter); \
}
#define AFSUUIDOUT() {u_int32_t temp; int i; \
TCHECK2(bp[0], 11*sizeof(u_int32_t)); \
temp = EXTRACT_32BITS(bp); \
bp += sizeof(u_int32_t); \
printf(" %08x", temp); \
temp = EXTRACT_32BITS(bp); \
bp += sizeof(u_int32_t); \
printf("%04x", temp); \
temp = EXTRACT_32BITS(bp); \
bp += sizeof(u_int32_t); \
printf("%04x", temp); \
for (i = 0; i < 8; i++) { \
temp = EXTRACT_32BITS(bp); \
bp += sizeof(u_int32_t); \
printf("%02x", (unsigned char) temp); \
} \
}
/*
* This is the sickest one of all
*/
#define VECOUT(MAX) { u_char *sp; \
u_char s[AFSNAMEMAX]; \
int k; \
if ((MAX) + 1 > sizeof(s)) \
goto trunc; \
TCHECK2(bp[0], (MAX) * sizeof(int32_t)); \
sp = s; \
for (k = 0; k < (MAX); k++) { \
*sp++ = (u_char) EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
} \
s[(MAX)] = '\0'; \
printf(" \""); \
fn_print(s, NULL); \
printf("\""); \
}
2009-03-21 16:23:46 +00:00
#define DESTSERVEROUT() { unsigned long n1, n2, n3; \
TCHECK2(bp[0], sizeof(int32_t) * 3); \
n1 = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
n2 = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
n3 = EXTRACT_32BITS(bp); \
bp += sizeof(int32_t); \
printf(" server %d:%d:%d", (int) n1, (int) n2, (int) n3); \
}
/*
* Handle calls to the AFS file service (fs)
*/
static void
fs_print(register const u_char *bp, int length)
{
int fs_op;
unsigned long i;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afsint.xg
*/
fs_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" fs call %s", tok2str(fs_req, "op#%d", fs_op));
/*
* Print out arguments to some of the AFS calls. This stuff is
* all from afsint.xg
*/
bp += sizeof(struct rx_header) + 4;
/*
* Sigh. This is gross. Ritchie forgive me.
*/
switch (fs_op) {
case 130: /* Fetch data */
FIDOUT();
printf(" offset");
UINTOUT();
printf(" length");
UINTOUT();
break;
case 131: /* Fetch ACL */
case 132: /* Fetch Status */
case 143: /* Old set lock */
case 144: /* Old extend lock */
case 145: /* Old release lock */
case 156: /* Set lock */
case 157: /* Extend lock */
case 158: /* Release lock */
FIDOUT();
break;
case 135: /* Store status */
FIDOUT();
STOREATTROUT();
break;
case 133: /* Store data */
FIDOUT();
STOREATTROUT();
printf(" offset");
UINTOUT();
printf(" length");
UINTOUT();
printf(" flen");
UINTOUT();
break;
case 134: /* Store ACL */
{
char a[AFSOPAQUEMAX+1];
FIDOUT();
TCHECK2(bp[0], 4);
i = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
TCHECK2(bp[0], i);
i = min(AFSOPAQUEMAX, i);
strncpy(a, (char *) bp, i);
a[i] = '\0';
acl_print((u_char *) a, sizeof(a), (u_char *) a + i);
break;
}
case 137: /* Create file */
case 141: /* MakeDir */
FIDOUT();
STROUT(AFSNAMEMAX);
STOREATTROUT();
break;
case 136: /* Remove file */
case 142: /* Remove directory */
FIDOUT();
STROUT(AFSNAMEMAX);
break;
case 138: /* Rename file */
printf(" old");
FIDOUT();
STROUT(AFSNAMEMAX);
printf(" new");
FIDOUT();
STROUT(AFSNAMEMAX);
break;
case 139: /* Symlink */
FIDOUT();
STROUT(AFSNAMEMAX);
printf(" link to");
STROUT(AFSNAMEMAX);
break;
case 140: /* Link */
FIDOUT();
STROUT(AFSNAMEMAX);
printf(" link to");
FIDOUT();
break;
case 148: /* Get volume info */
STROUT(AFSNAMEMAX);
break;
case 149: /* Get volume stats */
case 150: /* Set volume stats */
printf(" volid");
UINTOUT();
break;
case 154: /* New get volume info */
printf(" volname");
STROUT(AFSNAMEMAX);
break;
case 155: /* Bulk stat */
2009-03-21 16:23:46 +00:00
case 65536: /* Inline bulk stat */
{
unsigned long j;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (i = 0; i < j; i++) {
FIDOUT();
if (i != j - 1)
printf(",");
}
if (j == 0)
printf(" <none!>");
}
2009-03-21 16:23:46 +00:00
case 65537: /* Fetch data 64 */
FIDOUT();
printf(" offset");
UINT64OUT();
printf(" length");
UINT64OUT();
break;
case 65538: /* Store data 64 */
FIDOUT();
STOREATTROUT();
printf(" offset");
UINT64OUT();
printf(" length");
UINT64OUT();
printf(" flen");
UINT64OUT();
break;
case 65541: /* CallBack rx conn address */
printf(" addr");
UINTOUT();
default:
;
}
return;
trunc:
printf(" [|fs]");
}
/*
* Handle replies to the AFS file service
*/
static void
fs_reply_print(register const u_char *bp, int length, int32_t opcode)
{
unsigned long i;
struct rx_header *rxh;
if (length <= (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afsint.xg
*/
printf(" fs reply %s", tok2str(fs_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response
*/
if (rxh->type == RX_PACKET_TYPE_DATA) {
switch (opcode) {
case 131: /* Fetch ACL */
{
char a[AFSOPAQUEMAX+1];
TCHECK2(bp[0], 4);
i = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
TCHECK2(bp[0], i);
i = min(AFSOPAQUEMAX, i);
strncpy(a, (char *) bp, i);
a[i] = '\0';
acl_print((u_char *) a, sizeof(a), (u_char *) a + i);
break;
}
case 137: /* Create file */
case 141: /* MakeDir */
printf(" new");
FIDOUT();
break;
case 151: /* Get root volume */
printf(" root volume");
STROUT(AFSNAMEMAX);
break;
case 153: /* Get time */
DATEOUT();
break;
default:
;
}
} else if (rxh->type == RX_PACKET_TYPE_ABORT) {
int i;
/*
* Otherwise, just print out the return code
*/
TCHECK2(bp[0], sizeof(int32_t));
i = (int) EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
printf(" error %s", tok2str(afs_fs_errors, "#%d", i));
} else {
printf(" strange fs reply of type %d", rxh->type);
}
return;
trunc:
printf(" [|fs]");
}
/*
* Print out an AFS ACL string. An AFS ACL is a string that has the
* following format:
*
* <positive> <negative>
* <uid1> <aclbits1>
* ....
*
* "positive" and "negative" are integers which contain the number of
* positive and negative ACL's in the string. The uid/aclbits pair are
* ASCII strings containing the UID/PTS record and and a ascii number
* representing a logical OR of all the ACL permission bits
*/
static void
acl_print(u_char *s, int maxsize, u_char *end)
{
int pos, neg, acl;
int n, i;
char *user;
2007-10-16 02:20:42 +00:00
char fmt[1024];
if ((user = (char *)malloc(maxsize)) == NULL)
return;
if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
goto finish;
s += n;
if (s > end)
goto finish;
/*
* This wacky order preserves the order used by the "fs" command
*/
#define ACLOUT(acl) \
if (acl & PRSFS_READ) \
printf("r"); \
if (acl & PRSFS_LOOKUP) \
printf("l"); \
if (acl & PRSFS_INSERT) \
printf("i"); \
if (acl & PRSFS_DELETE) \
printf("d"); \
if (acl & PRSFS_WRITE) \
printf("w"); \
if (acl & PRSFS_LOCK) \
printf("k"); \
if (acl & PRSFS_ADMINISTER) \
printf("a");
for (i = 0; i < pos; i++) {
2007-10-16 02:20:42 +00:00
snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
goto finish;
s += n;
printf(" +{");
fn_print((u_char *)user, NULL);
printf(" ");
ACLOUT(acl);
printf("}");
if (s > end)
goto finish;
}
for (i = 0; i < neg; i++) {
2007-10-16 02:20:42 +00:00
snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
goto finish;
s += n;
printf(" -{");
fn_print((u_char *)user, NULL);
printf(" ");
ACLOUT(acl);
printf("}");
if (s > end)
goto finish;
}
finish:
free(user);
return;
}
#undef ACLOUT
/*
* Handle calls to the AFS callback service
*/
static void
cb_print(register const u_char *bp, int length)
{
int cb_op;
unsigned long i;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afscbint.xg
*/
cb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" cb call %s", tok2str(cb_req, "op#%d", cb_op));
bp += sizeof(struct rx_header) + 4;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afscbint.xg
*/
switch (cb_op) {
case 204: /* Callback */
{
unsigned long j, t;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (i = 0; i < j; i++) {
FIDOUT();
if (i != j - 1)
printf(",");
}
if (j == 0)
printf(" <none!>");
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
if (j != 0)
printf(";");
for (i = 0; i < j; i++) {
printf(" ver");
INTOUT();
printf(" expires");
DATEOUT();
TCHECK2(bp[0], 4);
t = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
tok2str(cb_types, "type %d", t);
}
}
case 214: {
printf(" afsuuid");
AFSUUIDOUT();
break;
}
default:
;
}
return;
trunc:
printf(" [|cb]");
}
/*
* Handle replies to the AFS Callback Service
*/
static void
cb_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
if (length <= (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afscbint.xg
*/
printf(" cb reply %s", tok2str(cb_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (rxh->type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 213: /* InitCallBackState3 */
AFSUUIDOUT();
break;
default:
;
}
else {
/*
* Otherwise, just print out the return code
*/
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|cb]");
}
/*
* Handle calls to the AFS protection database server
*/
static void
prot_print(register const u_char *bp, int length)
{
unsigned long i;
int pt_op;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from ptserver/ptint.xg
*/
pt_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" pt");
if (is_ubik(pt_op)) {
ubik_print(bp);
return;
}
printf(" call %s", tok2str(pt_req, "op#%d", pt_op));
/*
* Decode some of the arguments to the PT calls
*/
bp += sizeof(struct rx_header) + 4;
switch (pt_op) {
case 500: /* I New User */
STROUT(PRNAMEMAX);
printf(" id");
INTOUT();
printf(" oldid");
INTOUT();
break;
case 501: /* Where is it */
case 506: /* Delete */
case 508: /* Get CPS */
case 512: /* List entry */
case 514: /* List elements */
case 517: /* List owned */
case 518: /* Get CPS2 */
case 519: /* Get host CPS */
2009-03-21 16:23:46 +00:00
case 530: /* List super groups */
printf(" id");
INTOUT();
break;
case 502: /* Dump entry */
printf(" pos");
INTOUT();
break;
case 503: /* Add to group */
case 507: /* Remove from group */
case 515: /* Is a member of? */
printf(" uid");
INTOUT();
printf(" gid");
INTOUT();
break;
case 504: /* Name to ID */
{
unsigned long j;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
/*
* Who designed this chicken-shit protocol?
*
* Each character is stored as a 32-bit
* integer!
*/
for (i = 0; i < j; i++) {
VECOUT(PRNAMEMAX);
}
if (j == 0)
printf(" <none!>");
}
break;
case 505: /* Id to name */
{
unsigned long j;
printf(" ids:");
TCHECK2(bp[0], 4);
i = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (j = 0; j < i; j++)
INTOUT();
if (j == 0)
printf(" <none!>");
}
break;
case 509: /* New entry */
STROUT(PRNAMEMAX);
printf(" flag");
INTOUT();
printf(" oid");
INTOUT();
break;
case 511: /* Set max */
printf(" id");
INTOUT();
printf(" gflag");
INTOUT();
break;
case 513: /* Change entry */
printf(" id");
INTOUT();
STROUT(PRNAMEMAX);
printf(" oldid");
INTOUT();
printf(" newid");
INTOUT();
break;
case 520: /* Update entry */
printf(" id");
INTOUT();
STROUT(PRNAMEMAX);
break;
default:
;
}
return;
trunc:
printf(" [|pt]");
}
/*
* Handle replies to the AFS protection service
*/
static void
prot_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
unsigned long i;
if (length < (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from ptserver/ptint.xg. Check to see if it's a
* Ubik call, however.
*/
printf(" pt");
if (is_ubik(opcode)) {
ubik_reply_print(bp, length, opcode);
return;
}
printf(" reply %s", tok2str(pt_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response
*/
if (rxh->type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 504: /* Name to ID */
{
unsigned long j;
printf(" ids:");
TCHECK2(bp[0], 4);
i = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (j = 0; j < i; j++)
INTOUT();
if (j == 0)
printf(" <none!>");
}
break;
case 505: /* ID to name */
{
unsigned long j;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
/*
* Who designed this chicken-shit protocol?
*
* Each character is stored as a 32-bit
* integer!
*/
for (i = 0; i < j; i++) {
VECOUT(PRNAMEMAX);
}
if (j == 0)
printf(" <none!>");
}
break;
case 508: /* Get CPS */
case 514: /* List elements */
case 517: /* List owned */
case 518: /* Get CPS2 */
case 519: /* Get host CPS */
{
unsigned long j;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (i = 0; i < j; i++) {
INTOUT();
}
if (j == 0)
printf(" <none!>");
}
break;
case 510: /* List max */
printf(" maxuid");
INTOUT();
printf(" maxgid");
INTOUT();
break;
default:
;
}
else {
/*
* Otherwise, just print out the return code
*/
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|pt]");
}
/*
* Handle calls to the AFS volume location database service
*/
static void
vldb_print(register const u_char *bp, int length)
{
int vldb_op;
unsigned long i;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from vlserver/vldbint.xg
*/
vldb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" vldb");
if (is_ubik(vldb_op)) {
ubik_print(bp);
return;
}
printf(" call %s", tok2str(vldb_req, "op#%d", vldb_op));
/*
* Decode some of the arguments to the VLDB calls
*/
bp += sizeof(struct rx_header) + 4;
switch (vldb_op) {
case 501: /* Create new volume */
case 517: /* Create entry N */
VECOUT(VLNAMEMAX);
break;
case 502: /* Delete entry */
case 503: /* Get entry by ID */
case 507: /* Update entry */
case 508: /* Set lock */
case 509: /* Release lock */
case 518: /* Get entry by ID N */
printf(" volid");
INTOUT();
TCHECK2(bp[0], sizeof(int32_t));
i = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
if (i <= 2)
printf(" type %s", voltype[i]);
break;
case 504: /* Get entry by name */
case 519: /* Get entry by name N */
case 524: /* Update entry by name */
case 527: /* Get entry by name U */
STROUT(VLNAMEMAX);
break;
case 505: /* Get new vol id */
printf(" bump");
INTOUT();
break;
case 506: /* Replace entry */
case 520: /* Replace entry N */
printf(" volid");
INTOUT();
TCHECK2(bp[0], sizeof(int32_t));
i = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
if (i <= 2)
printf(" type %s", voltype[i]);
VECOUT(VLNAMEMAX);
break;
case 510: /* List entry */
case 521: /* List entry N */
printf(" index");
INTOUT();
break;
default:
;
}
return;
trunc:
printf(" [|vldb]");
}
/*
* Handle replies to the AFS volume location database service
*/
static void
vldb_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
unsigned long i;
if (length < (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from vlserver/vldbint.xg. Check to see if it's a
* Ubik call, however.
*/
printf(" vldb");
if (is_ubik(opcode)) {
ubik_reply_print(bp, length, opcode);
return;
}
printf(" reply %s", tok2str(vldb_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response
*/
if (rxh->type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 510: /* List entry */
printf(" count");
INTOUT();
printf(" nextindex");
INTOUT();
case 503: /* Get entry by id */
case 504: /* Get entry by name */
{ unsigned long nservers, j;
VECOUT(VLNAMEMAX);
TCHECK2(bp[0], sizeof(int32_t));
bp += sizeof(int32_t);
printf(" numservers");
TCHECK2(bp[0], sizeof(int32_t));
nservers = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
printf(" %lu", nservers);
printf(" servers");
for (i = 0; i < 8; i++) {
TCHECK2(bp[0], sizeof(int32_t));
if (i < nservers)
printf(" %s",
intoa(((struct in_addr *) bp)->s_addr));
bp += sizeof(int32_t);
}
printf(" partitions");
for (i = 0; i < 8; i++) {
TCHECK2(bp[0], sizeof(int32_t));
j = EXTRACT_32BITS(bp);
if (i < nservers && j <= 26)
printf(" %c", 'a' + (int)j);
else if (i < nservers)
printf(" %lu", j);
bp += sizeof(int32_t);
}
TCHECK2(bp[0], 8 * sizeof(int32_t));
bp += 8 * sizeof(int32_t);
printf(" rwvol");
UINTOUT();
printf(" rovol");
UINTOUT();
printf(" backup");
UINTOUT();
}
break;
case 505: /* Get new volume ID */
printf(" newvol");
UINTOUT();
break;
case 521: /* List entry */
case 529: /* List entry U */
printf(" count");
INTOUT();
printf(" nextindex");
INTOUT();
case 518: /* Get entry by ID N */
case 519: /* Get entry by name N */
{ unsigned long nservers, j;
VECOUT(VLNAMEMAX);
printf(" numservers");
TCHECK2(bp[0], sizeof(int32_t));
nservers = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
printf(" %lu", nservers);
printf(" servers");
for (i = 0; i < 13; i++) {
TCHECK2(bp[0], sizeof(int32_t));
if (i < nservers)
printf(" %s",
intoa(((struct in_addr *) bp)->s_addr));
bp += sizeof(int32_t);
}
printf(" partitions");
for (i = 0; i < 13; i++) {
TCHECK2(bp[0], sizeof(int32_t));
j = EXTRACT_32BITS(bp);
if (i < nservers && j <= 26)
printf(" %c", 'a' + (int)j);
else if (i < nservers)
printf(" %lu", j);
bp += sizeof(int32_t);
}
TCHECK2(bp[0], 13 * sizeof(int32_t));
bp += 13 * sizeof(int32_t);
printf(" rwvol");
UINTOUT();
printf(" rovol");
UINTOUT();
printf(" backup");
UINTOUT();
}
break;
case 526: /* Get entry by ID U */
case 527: /* Get entry by name U */
{ unsigned long nservers, j;
VECOUT(VLNAMEMAX);
printf(" numservers");
TCHECK2(bp[0], sizeof(int32_t));
nservers = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
printf(" %lu", nservers);
printf(" servers");
for (i = 0; i < 13; i++) {
if (i < nservers) {
printf(" afsuuid");
AFSUUIDOUT();
} else {
TCHECK2(bp[0], 44);
bp += 44;
}
}
TCHECK2(bp[0], 4 * 13);
bp += 4 * 13;
printf(" partitions");
for (i = 0; i < 13; i++) {
TCHECK2(bp[0], sizeof(int32_t));
j = EXTRACT_32BITS(bp);
if (i < nservers && j <= 26)
printf(" %c", 'a' + (int)j);
else if (i < nservers)
printf(" %lu", j);
bp += sizeof(int32_t);
}
TCHECK2(bp[0], 13 * sizeof(int32_t));
bp += 13 * sizeof(int32_t);
printf(" rwvol");
UINTOUT();
printf(" rovol");
UINTOUT();
printf(" backup");
UINTOUT();
}
default:
;
}
else {
/*
* Otherwise, just print out the return code
*/
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|vldb]");
}
/*
* Handle calls to the AFS Kerberos Authentication service
*/
static void
kauth_print(register const u_char *bp, int length)
{
int kauth_op;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from kauth/kauth.rg
*/
kauth_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" kauth");
if (is_ubik(kauth_op)) {
ubik_print(bp);
return;
}
printf(" call %s", tok2str(kauth_req, "op#%d", kauth_op));
/*
* Decode some of the arguments to the KA calls
*/
bp += sizeof(struct rx_header) + 4;
switch (kauth_op) {
case 1: /* Authenticate old */;
case 21: /* Authenticate */
case 22: /* Authenticate-V2 */
case 2: /* Change PW */
case 5: /* Set fields */
case 6: /* Create user */
case 7: /* Delete user */
case 8: /* Get entry */
case 14: /* Unlock */
case 15: /* Lock status */
printf(" principal");
STROUT(KANAMEMAX);
STROUT(KANAMEMAX);
break;
case 3: /* GetTicket-old */
case 23: /* GetTicket */
{
int i;
printf(" kvno");
INTOUT();
printf(" domain");
STROUT(KANAMEMAX);
TCHECK2(bp[0], sizeof(int32_t));
i = (int) EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
TCHECK2(bp[0], i);
bp += i;
printf(" principal");
STROUT(KANAMEMAX);
STROUT(KANAMEMAX);
break;
}
case 4: /* Set Password */
printf(" principal");
STROUT(KANAMEMAX);
STROUT(KANAMEMAX);
printf(" kvno");
INTOUT();
break;
case 12: /* Get password */
printf(" name");
STROUT(KANAMEMAX);
break;
default:
;
}
return;
trunc:
printf(" [|kauth]");
}
/*
* Handle replies to the AFS Kerberos Authentication Service
*/
static void
kauth_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
if (length <= (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from kauth/kauth.rg
*/
printf(" kauth");
if (is_ubik(opcode)) {
ubik_reply_print(bp, length, opcode);
return;
}
printf(" reply %s", tok2str(kauth_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (rxh->type == RX_PACKET_TYPE_DATA)
/* Well, no, not really. Leave this for later */
;
else {
/*
* Otherwise, just print out the return code
*/
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|kauth]");
}
/*
* Handle calls to the AFS Volume location service
*/
static void
vol_print(register const u_char *bp, int length)
{
int vol_op;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from volser/volint.xg
*/
vol_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" vol call %s", tok2str(vol_req, "op#%d", vol_op));
2009-03-21 16:23:46 +00:00
bp += sizeof(struct rx_header) + 4;
2009-03-21 16:23:46 +00:00
switch (vol_op) {
case 100: /* Create volume */
printf(" partition");
UINTOUT();
printf(" name");
STROUT(AFSNAMEMAX);
printf(" type");
UINTOUT();
printf(" parent");
UINTOUT();
break;
case 101: /* Delete volume */
case 107: /* Get flags */
printf(" trans");
UINTOUT();
break;
case 102: /* Restore */
printf(" totrans");
UINTOUT();
printf(" flags");
UINTOUT();
break;
case 103: /* Forward */
printf(" fromtrans");
UINTOUT();
printf(" fromdate");
DATEOUT();
DESTSERVEROUT();
printf(" desttrans");
INTOUT();
break;
case 104: /* End trans */
printf(" trans");
UINTOUT();
break;
case 105: /* Clone */
printf(" trans");
UINTOUT();
printf(" purgevol");
UINTOUT();
printf(" newtype");
UINTOUT();
printf(" newname");
STROUT(AFSNAMEMAX);
break;
case 106: /* Set flags */
printf(" trans");
UINTOUT();
printf(" flags");
UINTOUT();
break;
case 108: /* Trans create */
printf(" vol");
UINTOUT();
printf(" partition");
UINTOUT();
printf(" flags");
UINTOUT();
break;
case 109: /* Dump */
case 655537: /* Get size */
printf(" fromtrans");
UINTOUT();
printf(" fromdate");
DATEOUT();
break;
case 110: /* Get n-th volume */
printf(" index");
UINTOUT();
break;
case 111: /* Set forwarding */
printf(" tid");
UINTOUT();
printf(" newsite");
UINTOUT();
break;
case 112: /* Get name */
case 113: /* Get status */
printf(" tid");
break;
case 114: /* Signal restore */
printf(" name");
STROUT(AFSNAMEMAX);
printf(" type");
UINTOUT();
printf(" pid");
UINTOUT();
printf(" cloneid");
UINTOUT();
break;
case 116: /* List volumes */
printf(" partition");
UINTOUT();
printf(" flags");
UINTOUT();
break;
case 117: /* Set id types */
printf(" tid");
UINTOUT();
printf(" name");
STROUT(AFSNAMEMAX);
printf(" type");
UINTOUT();
printf(" pid");
UINTOUT();
printf(" clone");
UINTOUT();
printf(" backup");
UINTOUT();
break;
case 119: /* Partition info */
printf(" name");
STROUT(AFSNAMEMAX);
break;
case 120: /* Reclone */
printf(" tid");
UINTOUT();
break;
case 121: /* List one volume */
case 122: /* Nuke volume */
case 124: /* Extended List volumes */
case 125: /* Extended List one volume */
case 65536: /* Convert RO to RW volume */
printf(" partid");
UINTOUT();
printf(" volid");
UINTOUT();
break;
case 123: /* Set date */
printf(" tid");
UINTOUT();
printf(" date");
DATEOUT();
break;
case 126: /* Set info */
printf(" tid");
UINTOUT();
break;
case 128: /* Forward multiple */
printf(" fromtrans");
UINTOUT();
printf(" fromdate");
DATEOUT();
{
unsigned long i, j;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (i = 0; i < j; i++) {
DESTSERVEROUT();
if (i != j - 1)
printf(",");
}
if (j == 0)
printf(" <none!>");
}
break;
case 65538: /* Dump version 2 */
printf(" fromtrans");
UINTOUT();
printf(" fromdate");
DATEOUT();
printf(" flags");
UINTOUT();
break;
default:
;
}
return;
trunc:
printf(" [|vol]");
}
/*
* Handle replies to the AFS Volume Service
*/
static void
vol_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
if (length <= (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from volser/volint.xg
*/
printf(" vol reply %s", tok2str(vol_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
2009-03-21 16:23:46 +00:00
if (rxh->type == RX_PACKET_TYPE_DATA) {
switch (opcode) {
case 100: /* Create volume */
printf(" volid");
UINTOUT();
printf(" trans");
UINTOUT();
break;
case 104: /* End transaction */
UINTOUT();
break;
case 105: /* Clone */
printf(" newvol");
UINTOUT();
break;
case 107: /* Get flags */
UINTOUT();
break;
case 108: /* Transaction create */
printf(" trans");
UINTOUT();
break;
case 110: /* Get n-th volume */
printf(" volume");
UINTOUT();
printf(" partition");
UINTOUT();
break;
case 112: /* Get name */
STROUT(AFSNAMEMAX);
break;
case 113: /* Get status */
printf(" volid");
UINTOUT();
printf(" nextuniq");
UINTOUT();
printf(" type");
UINTOUT();
printf(" parentid");
UINTOUT();
printf(" clone");
UINTOUT();
printf(" backup");
UINTOUT();
printf(" restore");
UINTOUT();
printf(" maxquota");
UINTOUT();
printf(" minquota");
UINTOUT();
printf(" owner");
UINTOUT();
printf(" create");
DATEOUT();
printf(" access");
DATEOUT();
printf(" update");
DATEOUT();
printf(" expire");
DATEOUT();
printf(" backup");
DATEOUT();
printf(" copy");
DATEOUT();
break;
case 115: /* Old list partitions */
break;
case 116: /* List volumes */
case 121: /* List one volume */
{
unsigned long i, j;
TCHECK2(bp[0], 4);
j = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
for (i = 0; i < j; i++) {
printf(" name");
VECOUT(32);
printf(" volid");
UINTOUT();
printf(" type");
bp += sizeof(int32_t) * 21;
if (i != j - 1)
printf(",");
}
if (j == 0)
printf(" <none!>");
}
break;
default:
;
}
} else {
/*
* Otherwise, just print out the return code
*/
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|vol]");
}
/*
* Handle calls to the AFS BOS service
*/
static void
bos_print(register const u_char *bp, int length)
{
int bos_op;
if (length <= (int)sizeof(struct rx_header))
return;
if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
goto trunc;
}
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from bozo/bosint.xg
*/
bos_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" bos call %s", tok2str(bos_req, "op#%d", bos_op));
/*
* Decode some of the arguments to the BOS calls
*/
bp += sizeof(struct rx_header) + 4;
switch (bos_op) {
case 80: /* Create B node */
printf(" type");
STROUT(BOSNAMEMAX);
printf(" instance");
STROUT(BOSNAMEMAX);
break;
case 81: /* Delete B node */
case 83: /* Get status */
case 85: /* Get instance info */
case 87: /* Add super user */
case 88: /* Delete super user */
case 93: /* Set cell name */
case 96: /* Add cell host */
case 97: /* Delete cell host */
case 104: /* Restart */
case 106: /* Uninstall */
case 108: /* Exec */
case 112: /* Getlog */
case 114: /* Get instance strings */
STROUT(BOSNAMEMAX);
break;
case 82: /* Set status */
case 98: /* Set T status */
STROUT(BOSNAMEMAX);
printf(" status");
INTOUT();
break;
case 86: /* Get instance parm */
STROUT(BOSNAMEMAX);
printf(" num");
INTOUT();
break;
case 84: /* Enumerate instance */
case 89: /* List super users */
case 90: /* List keys */
case 91: /* Add key */
case 92: /* Delete key */
case 95: /* Get cell host */
INTOUT();
break;
case 105: /* Install */
STROUT(BOSNAMEMAX);
printf(" size");
INTOUT();
printf(" flags");
INTOUT();
printf(" date");
INTOUT();
break;
default:
;
}
return;
trunc:
printf(" [|bos]");
}
/*
* Handle replies to the AFS BOS Service
*/
static void
bos_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
if (length <= (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from volser/volint.xg
*/
printf(" bos reply %s", tok2str(bos_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (rxh->type == RX_PACKET_TYPE_DATA)
/* Well, no, not really. Leave this for later */
;
else {
/*
* Otherwise, just print out the return code
*/
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|bos]");
}
/*
* Check to see if this is a Ubik opcode.
*/
static int
is_ubik(u_int32_t opcode)
{
if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) ||
(opcode >= DISK_LOW && opcode <= DISK_HIGH))
return(1);
else
return(0);
}
/*
* Handle Ubik opcodes to any one of the replicated database services
*/
static void
ubik_print(register const u_char *bp)
{
int ubik_op;
int32_t temp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from ubik/ubik_int.xg
*/
ubik_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
printf(" ubik call %s", tok2str(ubik_req, "op#%d", ubik_op));
/*
* Decode some of the arguments to the Ubik calls
*/
bp += sizeof(struct rx_header) + 4;
switch (ubik_op) {
case 10000: /* Beacon */
TCHECK2(bp[0], 4);
temp = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
printf(" syncsite %s", temp ? "yes" : "no");
printf(" votestart");
DATEOUT();
printf(" dbversion");
UBIK_VERSIONOUT();
printf(" tid");
UBIK_VERSIONOUT();
break;
case 10003: /* Get sync site */
printf(" site");
UINTOUT();
break;
case 20000: /* Begin */
case 20001: /* Commit */
case 20007: /* Abort */
case 20008: /* Release locks */
case 20010: /* Writev */
printf(" tid");
UBIK_VERSIONOUT();
break;
case 20002: /* Lock */
printf(" tid");
UBIK_VERSIONOUT();
printf(" file");
INTOUT();
printf(" pos");
INTOUT();
printf(" length");
INTOUT();
temp = EXTRACT_32BITS(bp);
bp += sizeof(int32_t);
tok2str(ubik_lock_types, "type %d", temp);
break;
case 20003: /* Write */
printf(" tid");
UBIK_VERSIONOUT();
printf(" file");
INTOUT();
printf(" pos");
INTOUT();
break;
case 20005: /* Get file */
printf(" file");
INTOUT();
break;
case 20006: /* Send file */
printf(" file");
INTOUT();
printf(" length");
INTOUT();
printf(" dbversion");
UBIK_VERSIONOUT();
break;
case 20009: /* Truncate */
printf(" tid");
UBIK_VERSIONOUT();
printf(" file");
INTOUT();
printf(" length");
INTOUT();
break;
case 20012: /* Set version */
printf(" tid");
UBIK_VERSIONOUT();
printf(" oldversion");
UBIK_VERSIONOUT();
printf(" newversion");
UBIK_VERSIONOUT();
break;
default:
;
}
return;
trunc:
printf(" [|ubik]");
}
/*
* Handle Ubik replies to any one of the replicated database services
*/
static void
ubik_reply_print(register const u_char *bp, int length, int32_t opcode)
{
struct rx_header *rxh;
if (length < (int)sizeof(struct rx_header))
return;
rxh = (struct rx_header *) bp;
/*
* Print out the ubik call we're invoking. This table was gleaned
* from ubik/ubik_int.xg
*/
printf(" ubik reply %s", tok2str(ubik_req, "op#%d", opcode));
bp += sizeof(struct rx_header);
/*
* If it was a data packet, print out the arguments to the Ubik calls
*/
if (rxh->type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 10000: /* Beacon */
printf(" vote no");
break;
case 20004: /* Get version */
printf(" dbversion");
UBIK_VERSIONOUT();
break;
default:
;
}
/*
* Otherwise, print out "yes" it it was a beacon packet (because
* that's how yes votes are returned, go figure), otherwise
* just print out the error code.
*/
else
switch (opcode) {
case 10000: /* Beacon */
printf(" vote yes until");
DATEOUT();
break;
default:
printf(" errcode");
INTOUT();
}
return;
trunc:
printf(" [|ubik]");
}
/*
* Handle RX ACK packets.
*/
static void
rx_ack_print(register const u_char *bp, int length)
{
struct rx_ackPacket *rxa;
int i, start, last;
2007-10-16 02:20:42 +00:00
u_int32_t firstPacket;
if (length < (int)sizeof(struct rx_header))
return;
bp += sizeof(struct rx_header);
/*
* This may seem a little odd .... the rx_ackPacket structure
* contains an array of individual packet acknowledgements
* (used for selective ack/nack), but since it's variable in size,
* we don't want to truncate based on the size of the whole
* rx_ackPacket structure.
*/
TCHECK2(bp[0], sizeof(struct rx_ackPacket) - RX_MAXACKS);
rxa = (struct rx_ackPacket *) bp;
bp += (sizeof(struct rx_ackPacket) - RX_MAXACKS);
/*
* Print out a few useful things from the ack packet structure
*/
if (vflag > 2)
printf(" bufspace %d maxskew %d",
(int) EXTRACT_16BITS(&rxa->bufferSpace),
(int) EXTRACT_16BITS(&rxa->maxSkew));
2007-10-16 02:20:42 +00:00
firstPacket = EXTRACT_32BITS(&rxa->firstPacket);
printf(" first %d serial %d reason %s",
2007-10-16 02:20:42 +00:00
firstPacket, EXTRACT_32BITS(&rxa->serial),
tok2str(rx_ack_reasons, "#%d", (int) rxa->reason));
/*
* Okay, now we print out the ack array. The way _this_ works
* is that we start at "first", and step through the ack array.
* If we have a contiguous range of acks/nacks, try to
* collapse them into a range.
*
* If you're really clever, you might have noticed that this
* doesn't seem quite correct. Specifically, due to structure
* padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually
* yield the start of the ack array (because RX_MAXACKS is 255
* and the structure will likely get padded to a 2 or 4 byte
* boundary). However, this is the way it's implemented inside
* of AFS - the start of the extra fields are at
* sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_
* the exact start of the ack array. Sigh. That's why we aren't
* using bp, but instead use rxa->acks[]. But nAcks gets added
* to bp after this, so bp ends up at the right spot. Go figure.
*/
if (rxa->nAcks != 0) {
TCHECK2(bp[0], rxa->nAcks);
/*
* Sigh, this is gross, but it seems to work to collapse
* ranges correctly.
*/
for (i = 0, start = last = -2; i < rxa->nAcks; i++)
if (rxa->acks[i] == RX_ACK_TYPE_ACK) {
/*
* I figured this deserved _some_ explanation.
* First, print "acked" and the packet seq
* number if this is the first time we've
* seen an acked packet.
*/
if (last == -2) {
printf(" acked %d",
2007-10-16 02:20:42 +00:00
firstPacket + i);
start = i;
}
/*
* Otherwise, if the there is a skip in
* the range (such as an nacked packet in
* the middle of some acked packets),
* then print the current packet number
* seperated from the last number by
* a comma.
*/
else if (last != i - 1) {
2007-10-16 02:20:42 +00:00
printf(",%d", firstPacket + i);
start = i;
}
/*
* We always set last to the value of
* the last ack we saw. Conversely, start
* is set to the value of the first ack
* we saw in a range.
*/
last = i;
/*
* Okay, this bit a code gets executed when
* we hit a nack ... in _this_ case we
* want to print out the range of packets
* that were acked, so we need to print
* the _previous_ packet number seperated
* from the first by a dash (-). Since we
* already printed the first packet above,
* just print the final packet. Don't
* do this if there will be a single-length
* range.
*/
} else if (last == i - 1 && start != last)
2007-10-16 02:20:42 +00:00
printf("-%d", firstPacket + i - 1);
/*
* So, what's going on here? We ran off the end of the
* ack list, and if we got a range we need to finish it up.
* So we need to determine if the last packet in the list
* was an ack (if so, then last will be set to it) and
* we need to see if the last range didn't start with the
* last packet (because if it _did_, then that would mean
* that the packet number has already been printed and
* we don't need to print it again).
*/
if (last == i - 1 && start != last)
2007-10-16 02:20:42 +00:00
printf("-%d", firstPacket + i - 1);
/*
* Same as above, just without comments
*/
for (i = 0, start = last = -2; i < rxa->nAcks; i++)
if (rxa->acks[i] == RX_ACK_TYPE_NACK) {
if (last == -2) {
printf(" nacked %d",
2007-10-16 02:20:42 +00:00
firstPacket + i);
start = i;
} else if (last != i - 1) {
2007-10-16 02:20:42 +00:00
printf(",%d", firstPacket + i);
start = i;
}
last = i;
} else if (last == i - 1 && start != last)
2007-10-16 02:20:42 +00:00
printf("-%d", firstPacket + i - 1);
if (last == i - 1 && start != last)
2007-10-16 02:20:42 +00:00
printf("-%d", firstPacket + i - 1);
bp += rxa->nAcks;
}
/*
* These are optional fields; depending on your version of AFS,
* you may or may not see them
*/
#define TRUNCRET(n) if (snapend - bp + 1 <= n) return;
if (vflag > 1) {
TRUNCRET(4);
printf(" ifmtu");
INTOUT();
TRUNCRET(4);
printf(" maxmtu");
INTOUT();
TRUNCRET(4);
printf(" rwind");
INTOUT();
TRUNCRET(4);
printf(" maxpackets");
INTOUT();
}
return;
trunc:
printf(" [|ack]");
}
#undef TRUNCRET