tcpdump/print-rx.c

2893 lines
64 KiB
C
Raw Normal View History

2001-10-20 15:41:55 +08:00
/*
* 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:
2002-06-12 01:08:37 +08:00
*
2001-10-20 15:41:55 +08:00
* 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.
2002-06-12 01:08:37 +08:00
*
2001-10-20 15:41:55 +08:00
* 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.
*/
/* \summary: AFS RX printer */
/*
* 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>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "netdissect-stdinc.h"
#include "netdissect.h"
#include "addrtoname.h"
#include "extract.h"
#include "ip.h"
#define FS_RX_PORT 7000
#define CB_RX_PORT 7001
#define PROT_RX_PORT 7002
#define VLDB_RX_PORT 7003
#define KAUTH_RX_PORT 7004
#define VOL_RX_PORT 7005
#define ERROR_RX_PORT 7006 /* Doesn't seem to be used */
#define BOS_RX_PORT 7007
#define AFSNAMEMAX 256
#define AFSOPAQUEMAX 1024
#define PRNAMEMAX 64
#define VLNAMEMAX 65
#define KANAMEMAX 64
#define BOSNAMEMAX 256
#define PRSFS_READ 1 /* Read files */
#define PRSFS_WRITE 2 /* Write files */
#define PRSFS_INSERT 4 /* Insert files into a directory */
#define PRSFS_LOOKUP 8 /* Lookup files into a directory */
#define PRSFS_DELETE 16 /* Delete files */
#define PRSFS_LOCK 32 /* Lock files */
#define PRSFS_ADMINISTER 64 /* Change ACL's */
struct rx_header {
nd_uint32_t epoch;
nd_uint32_t cid;
nd_uint32_t callNumber;
nd_uint32_t seq;
nd_uint32_t serial;
nd_uint8_t type;
#define RX_PACKET_TYPE_DATA 1
#define RX_PACKET_TYPE_ACK 2
#define RX_PACKET_TYPE_BUSY 3
#define RX_PACKET_TYPE_ABORT 4
#define RX_PACKET_TYPE_ACKALL 5
#define RX_PACKET_TYPE_CHALLENGE 6
#define RX_PACKET_TYPE_RESPONSE 7
#define RX_PACKET_TYPE_DEBUG 8
#define RX_PACKET_TYPE_PARAMS 9
#define RX_PACKET_TYPE_VERSION 13
nd_uint8_t flags;
#define RX_CLIENT_INITIATED 1
#define RX_REQUEST_ACK 2
#define RX_LAST_PACKET 4
#define RX_MORE_PACKETS 8
#define RX_FREE_PACKET 16
#define RX_SLOW_START_OK 32
#define RX_JUMBO_PACKET 32
nd_uint8_t userStatus;
nd_uint8_t securityIndex;
nd_uint16_t spare; /* How clever: even though the AFS */
nd_uint16_t serviceId; /* header files indicate that the */
}; /* serviceId is first, it's really */
/* encoded _after_ the spare field */
/* I wasted a day figuring that out! */
#define NUM_RX_FLAGS 7
#define RX_MAXACKS 255
struct rx_ackPacket {
nd_uint16_t bufferSpace; /* Number of packet buffers available */
nd_uint16_t maxSkew; /* Max diff between ack'd packet and */
/* highest packet received */
nd_uint32_t firstPacket; /* The first packet in ack list */
nd_uint32_t previousPacket; /* Previous packet recv'd (obsolete) */
nd_uint32_t serial; /* # of packet that prompted the ack */
nd_uint8_t reason; /* Reason for acknowledgement */
nd_uint8_t nAcks; /* Number of acknowledgements */
/* Followed by nAcks acknowledgments */
#if 0
uint8_t acks[RX_MAXACKS]; /* Up to RX_MAXACKS acknowledgements */
#endif
};
/*
* Values for the acks array
*/
#define RX_ACK_TYPE_NACK 0 /* Don't have this packet */
#define RX_ACK_TYPE_ACK 1 /* I have this packet */
static const 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 const struct double_tok {
uint32_t flag; /* Rx flag */
uint32_t packetType; /* Packet type */
Add a few more GCC warnings on GCC >= 2 for ".devel" builds. From Neil T. Spring: fixes for many of those warnings: addrtoname.c, configure.in: Linux needs netinet/ether.h for ether_ntohost print-*.c: change char *foo = "bar" to const char *foo = "bar" to appease -Wwrite-strings; should affect no run-time behavior. print-*.c: make some variables unsigned. print-bgp.c: plen ('prefix len') is unsigned, no reason to validate by comparing to zero. print-cnfp.c, print-rx.c: use intoa, provided by addrtoname, instead of inet_ntoa. print-domain.c: unsigned int l; (l=foo()) < 0 is guaranteed to be false, so check for (u_int)-1, which represents failure, explicitly. print-isakmp.c: complete initialization of attrmap objects. print-lwres.c: "if(x); print foo;" seemed much more likely to be intended to be "if(x) { print foo; }". print-smb.c: complete initialization of some structures. In addition, add some fixes for the signed vs. unsigned comparison warnings: extract.h: cast the result of the byte-extraction-and-combining, as, at least for the 16-bit version, C's integral promotions will turn "u_int16_t" into "int" if there are other "int"s nearby. print-*.c: make some more variables unsigned, or add casts to an unsigned type of signed values known not to be negative, or add casts to "int" of unsigned values known to fit in an "int", and make other changes needed to handle the aforementioned variables now being unsigned. print-isakmp.c: clean up the handling of error/status indicators in notify messages. print-ppp.c: get rid of a check that an unsigned quantity is >= 0. print-radius.c: clean up some of the bounds checking. print-smb.c: extract the word count into a "u_int" to avoid the aforementioned problems with C's integral promotions. print-snmp.c: change a check that an unsigned variable is >= 0 to a check that it's != 0. Also, fix some formats to use "%u" rather than "%d" for unsigned quantities.
2002-09-05 08:00:07 +08:00
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 const 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" },
{ 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 const 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" },
{ 65536, "getce64" },
{ 65537, "getcellbynum" },
{ 65538, "tellmeaboutyourself" },
{ 0, NULL },
};
static const 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" },
{ 530, "list-super-groups" },
{ 0, NULL },
};
static const 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 const 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 const 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" },
{ 65536, "convert-ro" },
{ 65537, "get-size" },
{ 65538, "dump-v2" },
{ 0, NULL },
};
static const 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 const struct tok ubik_req[] = {
{ 10000, "vote-beacon" },
{ 10001, "vote-debug-old" },
{ 10002, "vote-sdebug-old" },
{ 10003, "vote-getsyncsite" },
{ 10004, "vote-debug" },
{ 10005, "vote-sdebug" },
{ 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
#define VOTE_HIGH 10007
#define DISK_LOW 20000
#define DISK_HIGH 20013
static const struct tok cb_types[] = {
{ 1, "exclusive" },
{ 2, "shared" },
{ 3, "dropped" },
{ 0, NULL },
};
static const struct tok ubik_lock_types[] = {
{ 1, "read" },
{ 2, "write" },
{ 3, "wait" },
{ 0, NULL },
};
Add a few more GCC warnings on GCC >= 2 for ".devel" builds. From Neil T. Spring: fixes for many of those warnings: addrtoname.c, configure.in: Linux needs netinet/ether.h for ether_ntohost print-*.c: change char *foo = "bar" to const char *foo = "bar" to appease -Wwrite-strings; should affect no run-time behavior. print-*.c: make some variables unsigned. print-bgp.c: plen ('prefix len') is unsigned, no reason to validate by comparing to zero. print-cnfp.c, print-rx.c: use intoa, provided by addrtoname, instead of inet_ntoa. print-domain.c: unsigned int l; (l=foo()) < 0 is guaranteed to be false, so check for (u_int)-1, which represents failure, explicitly. print-isakmp.c: complete initialization of attrmap objects. print-lwres.c: "if(x); print foo;" seemed much more likely to be intended to be "if(x) { print foo; }". print-smb.c: complete initialization of some structures. In addition, add some fixes for the signed vs. unsigned comparison warnings: extract.h: cast the result of the byte-extraction-and-combining, as, at least for the 16-bit version, C's integral promotions will turn "u_int16_t" into "int" if there are other "int"s nearby. print-*.c: make some more variables unsigned, or add casts to an unsigned type of signed values known not to be negative, or add casts to "int" of unsigned values known to fit in an "int", and make other changes needed to handle the aforementioned variables now being unsigned. print-isakmp.c: clean up the handling of error/status indicators in notify messages. print-ppp.c: get rid of a check that an unsigned quantity is >= 0. print-radius.c: clean up some of the bounds checking. print-smb.c: extract the word count into a "u_int" to avoid the aforementioned problems with C's integral promotions. print-snmp.c: change a check that an unsigned variable is >= 0 to a check that it's != 0. Also, fix some formats to use "%u" rather than "%d" for unsigned quantities.
2002-09-05 08:00:07 +08:00
static const char *voltype[] = { "read-write", "read-only", "backup" };
static const 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" },
{ 0xffffff9c, "restarting fileserver" }, /* -100, sic! */
{ 0, NULL }
};
/*
* Reasons for acknowledging a packet
*/
static const 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 {
uint32_t callnum; /* Call number (net order) */
struct in_addr client; /* client IP address (net order) */
struct in_addr server; /* server IP address (net order) */
u_int dport; /* server port (host order) */
uint16_t serviceId; /* Service identifier (net order) */
uint32_t opcode; /* RX opcode (host order) */
};
#define RX_CACHE_SIZE 64
static struct rx_cache_entry rx_cache[RX_CACHE_SIZE];
static uint32_t rx_cache_next = 0;
static uint32_t rx_cache_hint = 0;
static void rx_cache_insert(netdissect_options *, const u_char *, const struct ip *, u_int);
static int rx_cache_find(const struct rx_header *, const struct ip *,
uint32_t, uint32_t *);
static void fs_print(netdissect_options *, const u_char *, u_int);
static void fs_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
2014-03-30 23:16:23 +08:00
static void acl_print(netdissect_options *, u_char *, int, u_char *);
static void cb_print(netdissect_options *, const u_char *, u_int);
static void cb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
static void prot_print(netdissect_options *, const u_char *, u_int);
static void prot_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
static void vldb_print(netdissect_options *, const u_char *, u_int);
static void vldb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
static void kauth_print(netdissect_options *, const u_char *, u_int);
static void kauth_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
static void vol_print(netdissect_options *, const u_char *, u_int);
static void vol_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
static void bos_print(netdissect_options *, const u_char *, u_int);
static void bos_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
2014-03-30 23:16:23 +08:00
static void ubik_print(netdissect_options *, const u_char *);
static void ubik_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
2014-03-30 23:16:23 +08:00
static void rx_ack_print(netdissect_options *, const u_char *, u_int);
static int is_ubik(uint32_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
2014-03-30 23:16:23 +08:00
rx_print(netdissect_options *ndo,
const u_char *bp, u_int length, u_int sport, u_int dport,
2015-04-27 08:24:42 +08:00
const u_char *bp2)
{
const struct rx_header *rxh;
uint32_t i;
uint8_t type, flags;
uint32_t opcode;
if (!ND_TTEST_LEN(bp, sizeof(struct rx_header))) {
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|rx] (%u)", length);
return;
}
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
type = EXTRACT_U_1(rxh->type);
2018-01-07 18:47:30 +08:00
ND_PRINT(" rx %s", tok2str(rx_types, "type %u", type));
flags = EXTRACT_U_1(rxh->flags);
2014-03-30 23:16:23 +08:00
if (ndo->ndo_vflag) {
int firstflag = 0;
2014-03-30 23:16:23 +08:00
if (ndo->ndo_vflag > 1)
2018-01-07 18:47:30 +08:00
ND_PRINT(" cid %08x call# %u",
EXTRACT_BE_U_4(rxh->cid),
2018-01-07 18:47:30 +08:00
EXTRACT_BE_U_4(rxh->callNumber));
2018-01-07 18:47:30 +08:00
ND_PRINT(" seq %u ser %u",
EXTRACT_BE_U_4(rxh->seq),
2018-01-07 18:47:30 +08:00
EXTRACT_BE_U_4(rxh->serial));
2014-03-30 23:16:23 +08:00
if (ndo->ndo_vflag > 2)
2018-01-07 18:47:30 +08:00
ND_PRINT(" secindex %u serviceid %hu",
EXTRACT_U_1(rxh->securityIndex),
2018-01-07 18:47:30 +08:00
EXTRACT_BE_U_2(rxh->serviceId));
2014-03-30 23:16:23 +08:00
if (ndo->ndo_vflag > 1)
for (i = 0; i < NUM_RX_FLAGS; i++) {
if (flags & rx_flags[i].flag &&
(!rx_flags[i].packetType ||
type == rx_flags[i].packetType)) {
if (!firstflag) {
firstflag = 1;
2018-01-07 18:47:30 +08:00
ND_PRINT(" ");
} else {
2018-01-07 18:47:30 +08:00
ND_PRINT(",");
}
2018-01-07 18:47:30 +08:00
ND_PRINT("<%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 (type == RX_PACKET_TYPE_DATA &&
EXTRACT_BE_U_4(rxh->seq) == 1 &&
flags & RX_CLIENT_INITIATED) {
/*
* Insert this call into the call cache table, so we
* have a chance to print out replies
*/
2014-03-30 23:16:23 +08:00
rx_cache_insert(ndo, bp, (const struct ip *) bp2, dport);
switch (dport) {
case FS_RX_PORT: /* AFS file service */
2014-03-30 23:16:23 +08:00
fs_print(ndo, bp, length);
break;
case CB_RX_PORT: /* AFS callback service */
2014-03-30 23:16:23 +08:00
cb_print(ndo, bp, length);
break;
case PROT_RX_PORT: /* AFS protection service */
2014-03-30 23:16:23 +08:00
prot_print(ndo, bp, length);
break;
case VLDB_RX_PORT: /* AFS VLDB service */
2014-03-30 23:16:23 +08:00
vldb_print(ndo, bp, length);
break;
case KAUTH_RX_PORT: /* AFS Kerberos auth service */
2014-03-30 23:16:23 +08:00
kauth_print(ndo, bp, length);
break;
case VOL_RX_PORT: /* AFS Volume service */
2014-03-30 23:16:23 +08:00
vol_print(ndo, bp, length);
break;
case BOS_RX_PORT: /* AFS BOS service */
2014-03-30 23:16:23 +08:00
bos_print(ndo, bp, length);
break;
default:
;
}
2002-06-12 01:08:37 +08:00
/*
* 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 (((type == RX_PACKET_TYPE_DATA &&
EXTRACT_BE_U_4(rxh->seq) == 1) ||
type == RX_PACKET_TYPE_ABORT) &&
(flags & RX_CLIENT_INITIATED) == 0 &&
rx_cache_find(rxh, (const struct ip *) bp2,
sport, &opcode)) {
switch (sport) {
case FS_RX_PORT: /* AFS file service */
2014-03-30 23:16:23 +08:00
fs_reply_print(ndo, bp, length, opcode);
break;
case CB_RX_PORT: /* AFS callback service */
2014-03-30 23:16:23 +08:00
cb_reply_print(ndo, bp, length, opcode);
break;
case PROT_RX_PORT: /* AFS PT service */
2014-03-30 23:16:23 +08:00
prot_reply_print(ndo, bp, length, opcode);
break;
case VLDB_RX_PORT: /* AFS VLDB service */
2014-03-30 23:16:23 +08:00
vldb_reply_print(ndo, bp, length, opcode);
break;
case KAUTH_RX_PORT: /* AFS Kerberos auth service */
2014-03-30 23:16:23 +08:00
kauth_reply_print(ndo, bp, length, opcode);
break;
case VOL_RX_PORT: /* AFS Volume service */
2014-03-30 23:16:23 +08:00
vol_reply_print(ndo, bp, length, opcode);
break;
case BOS_RX_PORT: /* AFS BOS service */
2014-03-30 23:16:23 +08:00
bos_reply_print(ndo, 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 (type == RX_PACKET_TYPE_ACK)
2014-03-30 23:16:23 +08:00
rx_ack_print(ndo, bp, length);
2018-01-07 18:47:30 +08:00
ND_PRINT(" (%u)", length);
}
/*
* Insert an entry into the cache. Taken from print-nfs.c
*/
static void
2014-03-30 23:16:23 +08:00
rx_cache_insert(netdissect_options *ndo,
const u_char *bp, const struct ip *ip, u_int dport)
{
struct rx_cache_entry *rxent;
const struct rx_header *rxh = (const struct rx_header *) bp;
if (!ND_TTEST_4(bp + sizeof(struct rx_header)))
return;
rxent = &rx_cache[rx_cache_next];
if (++rx_cache_next >= RX_CACHE_SIZE)
rx_cache_next = 0;
2002-06-12 01:08:37 +08:00
rxent->callnum = EXTRACT_BE_U_4(rxh->callNumber);
UNALIGNED_MEMCPY(&rxent->client, &ip->ip_src, sizeof(uint32_t));
UNALIGNED_MEMCPY(&rxent->server, &ip->ip_dst, sizeof(uint32_t));
rxent->dport = dport;
rxent->serviceId = EXTRACT_BE_U_4(rxh->serviceId);
rxent->opcode = EXTRACT_BE_U_4(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, u_int sport,
uint32_t *opcode)
{
uint32_t i;
struct rx_cache_entry *rxent;
uint32_t clip;
uint32_t sip;
UNALIGNED_MEMCPY(&clip, &ip->ip_dst, sizeof(uint32_t));
UNALIGNED_MEMCPY(&sip, &ip->ip_src, sizeof(uint32_t));
/* Start the search where we last left off */
i = rx_cache_hint;
do {
rxent = &rx_cache[i];
if (rxent->callnum == EXTRACT_BE_U_4(rxh->callNumber) &&
rxent->client.s_addr == clip &&
2002-06-12 01:08:37 +08:00
rxent->server.s_addr == sip &&
rxent->serviceId == EXTRACT_BE_U_4(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() { uint32_t n1, n2, n3; \
ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
n1 = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
n2 = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
n3 = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" fid %u/%u/%u", n1, n2, n3); \
}
#define STROUT(MAX) { uint32_t _i; \
ND_TCHECK_LEN(bp, sizeof(uint32_t)); \
_i = EXTRACT_BE_U_4(bp); \
if (_i > (MAX)) \
goto trunc; \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" \""); \
if (fn_printn(ndo, bp, _i, ndo->ndo_snapend)) \
goto trunc; \
2018-01-07 18:47:30 +08:00
ND_PRINT("\""); \
bp += ((_i + sizeof(uint32_t) - 1) / sizeof(uint32_t)) * sizeof(uint32_t); \
}
#define INTOUT() { int32_t _i; \
ND_TCHECK_4(bp); \
_i = EXTRACT_BE_S_4(bp); \
bp += sizeof(int32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" %d", _i); \
}
#define UINTOUT() { uint32_t _i; \
ND_TCHECK_4(bp); \
_i = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", _i); \
}
#define UINT64OUT() { uint64_t _i; \
ND_TCHECK_LEN(bp, sizeof(uint64_t)); \
_i = EXTRACT_BE_U_8(bp); \
bp += sizeof(uint64_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" %" PRIu64, _i); \
}
#define DATEOUT() { time_t _t; struct tm *tm; char str[256]; \
ND_TCHECK_4(bp); \
_t = (time_t) EXTRACT_BE_S_4(bp); \
bp += sizeof(int32_t); \
tm = localtime(&_t); \
strftime(str, 256, "%Y/%m/%d %H:%M:%S", tm); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" %s", str); \
}
#define STOREATTROUT() { uint32_t mask, _i; \
ND_TCHECK_LEN(bp, (sizeof(uint32_t) * 6)); \
mask = EXTRACT_BE_U_4(bp); bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
if (mask) ND_PRINT(" StoreStatus"); \
if (mask & 1) { ND_PRINT(" date"); DATEOUT(); } \
else bp += sizeof(uint32_t); \
_i = EXTRACT_BE_U_4(bp); bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
if (mask & 2) ND_PRINT(" owner %u", _i); \
_i = EXTRACT_BE_U_4(bp); bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
if (mask & 4) ND_PRINT(" group %u", _i); \
_i = EXTRACT_BE_U_4(bp); bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
if (mask & 8) ND_PRINT(" mode %o", _i & 07777); \
_i = EXTRACT_BE_U_4(bp); bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
if (mask & 16) ND_PRINT(" segsize %u", _i); \
/* undocumented in 3.3 docu */ \
2018-01-07 18:47:30 +08:00
if (mask & 1024) ND_PRINT(" fsync"); \
}
#define UBIK_VERSIONOUT() {uint32_t epoch; uint32_t counter; \
ND_TCHECK_LEN(bp, sizeof(uint32_t) * 2); \
epoch = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
counter = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u.%u", epoch, counter); \
}
#define AFSUUIDOUT() {uint32_t temp; int _i; \
ND_TCHECK_LEN(bp, 11 * sizeof(uint32_t)); \
temp = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" %08x", temp); \
temp = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT("%04x", temp); \
temp = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT("%04x", temp); \
for (_i = 0; _i < 8; _i++) { \
temp = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT("%02x", (unsigned char) temp); \
} \
}
/*
* This is the sickest one of all
*/
#define VECOUT(MAX) { u_char *sp; \
u_char s[AFSNAMEMAX]; \
uint32_t k; \
if ((MAX) + 1 > sizeof(s)) \
goto trunc; \
ND_TCHECK_LEN(bp, (MAX) * sizeof(uint32_t)); \
sp = s; \
for (k = 0; k < (MAX); k++) { \
*sp++ = (u_char) EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
} \
s[(MAX)] = '\0'; \
2018-01-07 18:47:30 +08:00
ND_PRINT(" \""); \
2014-04-14 14:53:46 +08:00
fn_print(ndo, s, NULL); \
2018-01-07 18:47:30 +08:00
ND_PRINT("\""); \
}
#define DESTSERVEROUT() { uint32_t n1, n2, n3; \
ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
n1 = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
n2 = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
n3 = EXTRACT_BE_U_4(bp); \
bp += sizeof(uint32_t); \
2018-01-07 18:47:30 +08:00
ND_PRINT(" server %u:%u:%u", n1, n2, n3); \
}
/*
* Handle calls to the AFS file service (fs)
*/
static void
2014-03-30 23:16:23 +08:00
fs_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t fs_op;
uint32_t i;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afsint.xg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
fs_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" fs call %s", tok2str(fs_req, "op#%u", 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();
2018-01-07 18:47:30 +08:00
ND_PRINT(" offset");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" 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();
2018-01-07 18:47:30 +08:00
ND_PRINT(" offset");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" length");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flen");
UINTOUT();
break;
case 134: /* Store ACL */
{
char a[AFSOPAQUEMAX+1];
FIDOUT();
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
ND_TCHECK_LEN(bp, i);
i = min(AFSOPAQUEMAX, i);
2015-04-27 08:24:42 +08:00
strncpy(a, (const char *) bp, i);
a[i] = '\0';
2014-03-30 23:16:23 +08:00
acl_print(ndo, (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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" old");
FIDOUT();
STROUT(AFSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" new");
FIDOUT();
STROUT(AFSNAMEMAX);
break;
case 139: /* Symlink */
FIDOUT();
STROUT(AFSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" link to");
STROUT(AFSNAMEMAX);
break;
case 140: /* Link */
FIDOUT();
STROUT(AFSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" link to");
FIDOUT();
break;
case 148: /* Get volume info */
STROUT(AFSNAMEMAX);
break;
case 149: /* Get volume stats */
case 150: /* Set volume stats */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
UINTOUT();
break;
case 154: /* New get volume info */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volname");
STROUT(AFSNAMEMAX);
break;
case 155: /* Bulk stat */
case 65536: /* Inline bulk stat */
{
uint32_t j;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (i = 0; i < j; i++) {
FIDOUT();
if (i != j - 1)
2018-01-07 18:47:30 +08:00
ND_PRINT(",");
}
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
case 65537: /* Fetch data 64 */
FIDOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" offset");
UINT64OUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" length");
UINT64OUT();
break;
case 65538: /* Store data 64 */
FIDOUT();
STOREATTROUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" offset");
UINT64OUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" length");
UINT64OUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flen");
UINT64OUT();
break;
case 65541: /* CallBack rx conn address */
2018-01-07 18:47:30 +08:00
ND_PRINT(" addr");
UINTOUT();
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|fs]");
}
/*
* Handle replies to the AFS file service
*/
static void
2014-03-30 23:16:23 +08:00
fs_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
uint32_t i;
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
if (length <= sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afsint.xg
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" fs reply %s", tok2str(fs_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response
*/
if (type == RX_PACKET_TYPE_DATA) {
switch (opcode) {
case 131: /* Fetch ACL */
{
char a[AFSOPAQUEMAX+1];
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
ND_TCHECK_LEN(bp, i);
i = min(AFSOPAQUEMAX, i);
2015-04-27 08:24:42 +08:00
strncpy(a, (const char *) bp, i);
a[i] = '\0';
2014-03-30 23:16:23 +08:00
acl_print(ndo, (u_char *) a, sizeof(a), (u_char *) a + i);
break;
}
case 137: /* Create file */
case 141: /* MakeDir */
2018-01-07 18:47:30 +08:00
ND_PRINT(" new");
FIDOUT();
break;
case 151: /* Get root volume */
2018-01-07 18:47:30 +08:00
ND_PRINT(" root volume");
STROUT(AFSNAMEMAX);
break;
case 153: /* Get time */
DATEOUT();
break;
default:
;
}
} else if (type == RX_PACKET_TYPE_ABORT) {
2002-06-12 01:08:37 +08:00
/*
* Otherwise, just print out the return code
*/
int32_t errcode;
ND_TCHECK_4(bp);
errcode = EXTRACT_BE_S_4(bp);
2002-06-12 01:08:37 +08:00
bp += sizeof(int32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" error %s", tok2str(afs_fs_errors, "#%d", errcode));
} else {
2018-01-07 18:47:30 +08:00
ND_PRINT(" strange fs reply of type %u", type);
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|fs]");
}
/*
* Print out an AFS ACL string. An AFS ACL is a string that has the
* following format:
*
* <positive> <negative>
* <uid1> <aclbits1>
* ....
2002-06-12 01:08:37 +08:00
*
* "positive" and "negative" are integers which contain the number of
* positive and negative ACL's in the string. The uid/aclbits pair are
2017-08-10 16:52:46 +08:00
* ASCII strings containing the UID/PTS record and an ASCII number
* representing a logical OR of all the ACL permission bits
*/
static void
2014-03-30 23:16:23 +08:00
acl_print(netdissect_options *ndo,
u_char *s, int maxsize, u_char *end)
{
int pos, neg, acl;
int n, i;
char *user;
char fmt[1024];
if ((user = (char *)malloc(maxsize)) == NULL)
return;
if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
goto finish;
2002-06-12 01:08:37 +08:00
s += n;
if (s > end)
goto finish;
/*
* This wacky order preserves the order used by the "fs" command
*/
#define ACLOUT(acl) \
2018-01-07 18:47:30 +08:00
ND_PRINT("%s%s%s%s%s%s%s", \
2014-03-30 23:16:23 +08:00
acl & PRSFS_READ ? "r" : "", \
acl & PRSFS_LOOKUP ? "l" : "", \
acl & PRSFS_INSERT ? "i" : "", \
acl & PRSFS_DELETE ? "d" : "", \
acl & PRSFS_WRITE ? "w" : "", \
acl & PRSFS_LOCK ? "k" : "", \
2018-01-07 18:47:30 +08:00
acl & PRSFS_ADMINISTER ? "a" : "");
for (i = 0; i < pos; i++) {
snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
goto finish;
s += n;
2018-01-07 18:47:30 +08:00
ND_PRINT(" +{");
2014-04-14 14:53:46 +08:00
fn_print(ndo, (u_char *)user, NULL);
2018-01-07 18:47:30 +08:00
ND_PRINT(" ");
ACLOUT(acl);
2018-01-07 18:47:30 +08:00
ND_PRINT("}");
if (s > end)
goto finish;
}
for (i = 0; i < neg; i++) {
snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
goto finish;
s += n;
2018-01-07 18:47:30 +08:00
ND_PRINT(" -{");
2014-04-14 14:53:46 +08:00
fn_print(ndo, (u_char *)user, NULL);
2018-01-07 18:47:30 +08:00
ND_PRINT(" ");
ACLOUT(acl);
2018-01-07 18:47:30 +08:00
ND_PRINT("}");
if (s > end)
goto finish;
}
finish:
free(user);
return;
}
#undef ACLOUT
/*
* Handle calls to the AFS callback service
*/
static void
2014-03-30 23:16:23 +08:00
cb_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t cb_op;
uint32_t i;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afscbint.xg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
cb_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" cb call %s", tok2str(cb_req, "op#%u", 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 */
{
uint32_t j, t;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (i = 0; i < j; i++) {
FIDOUT();
if (i != j - 1)
2018-01-07 18:47:30 +08:00
ND_PRINT(",");
}
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
if (j != 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(";");
for (i = 0; i < j; i++) {
2018-01-07 18:47:30 +08:00
ND_PRINT(" ver");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" expires");
DATEOUT();
ND_TCHECK_4(bp);
t = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
tok2str(cb_types, "type %u", t);
}
}
case 214: {
2018-01-07 18:47:30 +08:00
ND_PRINT(" afsuuid");
AFSUUIDOUT();
break;
}
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|cb]");
}
/*
* Handle replies to the AFS Callback Service
*/
static void
2014-03-30 23:16:23 +08:00
cb_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
if (length <= sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from fsint/afscbint.xg
*/
2002-06-12 01:08:37 +08:00
2018-01-07 18:47:30 +08:00
ND_PRINT(" cb reply %s", tok2str(cb_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 213: /* InitCallBackState3 */
AFSUUIDOUT();
break;
default:
;
}
else {
/*
* Otherwise, just print out the return code
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|cb]");
}
/*
* Handle calls to the AFS protection database server
*/
static void
2014-03-30 23:16:23 +08:00
prot_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t i;
uint32_t pt_op;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from ptserver/ptint.xg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
pt_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" pt");
if (is_ubik(pt_op)) {
2014-03-30 23:16:23 +08:00
ubik_print(ndo, bp);
return;
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" call %s", tok2str(pt_req, "op#%u", 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);
2018-01-07 18:47:30 +08:00
ND_PRINT(" id");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" 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 */
case 530: /* List super groups */
2018-01-07 18:47:30 +08:00
ND_PRINT(" id");
INTOUT();
break;
case 502: /* Dump entry */
2018-01-07 18:47:30 +08:00
ND_PRINT(" pos");
INTOUT();
break;
case 503: /* Add to group */
case 507: /* Remove from group */
case 515: /* Is a member of? */
2018-01-07 18:47:30 +08:00
ND_PRINT(" uid");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" gid");
INTOUT();
break;
case 504: /* Name to ID */
{
uint32_t j;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_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)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
case 505: /* Id to name */
{
uint32_t j;
2018-01-07 18:47:30 +08:00
ND_PRINT(" ids:");
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (j = 0; j < i; j++)
INTOUT();
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
case 509: /* New entry */
STROUT(PRNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" flag");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" oid");
INTOUT();
break;
case 511: /* Set max */
2018-01-07 18:47:30 +08:00
ND_PRINT(" id");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" gflag");
INTOUT();
break;
case 513: /* Change entry */
2018-01-07 18:47:30 +08:00
ND_PRINT(" id");
INTOUT();
STROUT(PRNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" oldid");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" newid");
INTOUT();
break;
case 520: /* Update entry */
2018-01-07 18:47:30 +08:00
ND_PRINT(" id");
INTOUT();
STROUT(PRNAMEMAX);
break;
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|pt]");
}
/*
* Handle replies to the AFS protection service
*/
static void
2014-03-30 23:16:23 +08:00
prot_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
uint32_t i;
if (length < sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const 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.
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" pt");
if (is_ubik(opcode)) {
2014-03-30 23:16:23 +08:00
ubik_reply_print(ndo, bp, length, opcode);
return;
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" reply %s", tok2str(pt_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response
*/
if (type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 504: /* Name to ID */
{
uint32_t j;
2018-01-07 18:47:30 +08:00
ND_PRINT(" ids:");
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (j = 0; j < i; j++)
INTOUT();
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
case 505: /* ID to name */
{
uint32_t j;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_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)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
case 508: /* Get CPS */
case 514: /* List elements */
case 517: /* List owned */
case 518: /* Get CPS2 */
case 519: /* Get host CPS */
{
uint32_t j;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (i = 0; i < j; i++) {
INTOUT();
}
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
case 510: /* List max */
2018-01-07 18:47:30 +08:00
ND_PRINT(" maxuid");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" maxgid");
INTOUT();
break;
default:
;
}
else {
/*
* Otherwise, just print out the return code
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|pt]");
}
/*
* Handle calls to the AFS volume location database service
*/
static void
2014-03-30 23:16:23 +08:00
vldb_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t vldb_op;
uint32_t i;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from vlserver/vldbint.xg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
vldb_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" vldb");
if (is_ubik(vldb_op)) {
2014-03-30 23:16:23 +08:00
ubik_print(ndo, bp);
return;
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" call %s", tok2str(vldb_req, "op#%u", 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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
INTOUT();
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
if (i <= 2)
2018-01-07 18:47:30 +08:00
ND_PRINT(" 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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" bump");
INTOUT();
break;
case 506: /* Replace entry */
case 520: /* Replace entry N */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
INTOUT();
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
if (i <= 2)
2018-01-07 18:47:30 +08:00
ND_PRINT(" type %s", voltype[i]);
VECOUT(VLNAMEMAX);
break;
case 510: /* List entry */
case 521: /* List entry N */
2018-01-07 18:47:30 +08:00
ND_PRINT(" index");
INTOUT();
break;
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|vldb]");
}
/*
* Handle replies to the AFS volume location database service
*/
static void
2014-03-30 23:16:23 +08:00
vldb_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
uint32_t i;
if (length < sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const 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.
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" vldb");
if (is_ubik(opcode)) {
2014-03-30 23:16:23 +08:00
ubik_reply_print(ndo, bp, length, opcode);
return;
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" reply %s", tok2str(vldb_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response
*/
if (type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 510: /* List entry */
2018-01-07 18:47:30 +08:00
ND_PRINT(" count");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" nextindex");
INTOUT();
case 503: /* Get entry by id */
case 504: /* Get entry by name */
{ uint32_t nservers, j;
VECOUT(VLNAMEMAX);
ND_TCHECK_4(bp);
bp += sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" numservers");
ND_TCHECK_4(bp);
nservers = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", nservers);
ND_PRINT(" servers");
for (i = 0; i < 8; i++) {
ND_TCHECK_4(bp);
if (i < nservers)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %s",
intoa(((const struct in_addr *) bp)->s_addr));
bp += sizeof(uint32_t);
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" partitions");
for (i = 0; i < 8; i++) {
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
if (i < nservers && j <= 26)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %c", 'a' + j);
else if (i < nservers)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", j);
bp += sizeof(uint32_t);
}
ND_TCHECK_LEN(bp, 8 * sizeof(uint32_t));
bp += 8 * sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" rwvol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" rovol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" backup");
UINTOUT();
}
break;
case 505: /* Get new volume ID */
2018-01-07 18:47:30 +08:00
ND_PRINT(" newvol");
UINTOUT();
break;
case 521: /* List entry */
case 529: /* List entry U */
2018-01-07 18:47:30 +08:00
ND_PRINT(" count");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" nextindex");
INTOUT();
case 518: /* Get entry by ID N */
case 519: /* Get entry by name N */
{ uint32_t nservers, j;
VECOUT(VLNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" numservers");
ND_TCHECK_4(bp);
nservers = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", nservers);
ND_PRINT(" servers");
for (i = 0; i < 13; i++) {
ND_TCHECK_4(bp);
if (i < nservers)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %s",
intoa(((const struct in_addr *) bp)->s_addr));
bp += sizeof(uint32_t);
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" partitions");
for (i = 0; i < 13; i++) {
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
if (i < nservers && j <= 26)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %c", 'a' + j);
else if (i < nservers)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", j);
bp += sizeof(uint32_t);
}
ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
bp += 13 * sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" rwvol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" rovol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" backup");
UINTOUT();
}
break;
case 526: /* Get entry by ID U */
case 527: /* Get entry by name U */
{ uint32_t nservers, j;
VECOUT(VLNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" numservers");
ND_TCHECK_4(bp);
nservers = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", nservers);
ND_PRINT(" servers");
for (i = 0; i < 13; i++) {
if (i < nservers) {
2018-01-07 18:47:30 +08:00
ND_PRINT(" afsuuid");
AFSUUIDOUT();
} else {
ND_TCHECK_LEN(bp, 44);
bp += 44;
}
}
ND_TCHECK_LEN(bp, 4 * 13);
bp += 4 * 13;
2018-01-07 18:47:30 +08:00
ND_PRINT(" partitions");
for (i = 0; i < 13; i++) {
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
if (i < nservers && j <= 26)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %c", 'a' + j);
else if (i < nservers)
2018-01-07 18:47:30 +08:00
ND_PRINT(" %u", j);
bp += sizeof(uint32_t);
}
ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
bp += 13 * sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" rwvol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" rovol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" backup");
UINTOUT();
}
default:
;
}
2002-06-12 01:08:37 +08:00
else {
/*
* Otherwise, just print out the return code
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|vldb]");
}
/*
* Handle calls to the AFS Kerberos Authentication service
*/
static void
2014-03-30 23:16:23 +08:00
kauth_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t kauth_op;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from kauth/kauth.rg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
kauth_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" kauth");
if (is_ubik(kauth_op)) {
2014-03-30 23:16:23 +08:00
ubik_print(ndo, bp);
return;
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" call %s", tok2str(kauth_req, "op#%u", 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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" principal");
STROUT(KANAMEMAX);
STROUT(KANAMEMAX);
break;
case 3: /* GetTicket-old */
case 23: /* GetTicket */
{
uint32_t i;
2018-01-07 18:47:30 +08:00
ND_PRINT(" kvno");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" domain");
STROUT(KANAMEMAX);
ND_TCHECK_4(bp);
i = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
ND_TCHECK_LEN(bp, i);
bp += i;
2018-01-07 18:47:30 +08:00
ND_PRINT(" principal");
STROUT(KANAMEMAX);
STROUT(KANAMEMAX);
break;
}
case 4: /* Set Password */
2018-01-07 18:47:30 +08:00
ND_PRINT(" principal");
STROUT(KANAMEMAX);
STROUT(KANAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" kvno");
INTOUT();
break;
case 12: /* Get password */
2018-01-07 18:47:30 +08:00
ND_PRINT(" name");
STROUT(KANAMEMAX);
break;
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|kauth]");
}
/*
* Handle replies to the AFS Kerberos Authentication Service
*/
static void
2014-03-30 23:16:23 +08:00
kauth_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
if (length <= sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from kauth/kauth.rg
*/
2002-06-12 01:08:37 +08:00
2018-01-07 18:47:30 +08:00
ND_PRINT(" kauth");
if (is_ubik(opcode)) {
2014-03-30 23:16:23 +08:00
ubik_reply_print(ndo, bp, length, opcode);
return;
}
2018-01-07 18:47:30 +08:00
ND_PRINT(" reply %s", tok2str(kauth_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (type == RX_PACKET_TYPE_DATA)
/* Well, no, not really. Leave this for later */
;
else {
/*
* Otherwise, just print out the return code
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|kauth]");
}
/*
* Handle calls to the AFS Volume location service
*/
static void
2014-03-30 23:16:23 +08:00
vol_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t vol_op;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from volser/volint.xg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
vol_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" vol call %s", tok2str(vol_req, "op#%u", vol_op));
bp += sizeof(struct rx_header) + 4;
switch (vol_op) {
case 100: /* Create volume */
2018-01-07 18:47:30 +08:00
ND_PRINT(" partition");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" name");
STROUT(AFSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" type");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" parent");
UINTOUT();
break;
case 101: /* Delete volume */
case 107: /* Get flags */
2018-01-07 18:47:30 +08:00
ND_PRINT(" trans");
UINTOUT();
break;
case 102: /* Restore */
2018-01-07 18:47:30 +08:00
ND_PRINT(" totrans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flags");
UINTOUT();
break;
case 103: /* Forward */
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromtrans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromdate");
DATEOUT();
DESTSERVEROUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" desttrans");
INTOUT();
break;
case 104: /* End trans */
2018-01-07 18:47:30 +08:00
ND_PRINT(" trans");
UINTOUT();
break;
case 105: /* Clone */
2018-01-07 18:47:30 +08:00
ND_PRINT(" trans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" purgevol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" newtype");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" newname");
STROUT(AFSNAMEMAX);
break;
case 106: /* Set flags */
2018-01-07 18:47:30 +08:00
ND_PRINT(" trans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flags");
UINTOUT();
break;
case 108: /* Trans create */
2018-01-07 18:47:30 +08:00
ND_PRINT(" vol");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" partition");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flags");
UINTOUT();
break;
case 109: /* Dump */
case 655537: /* Get size */
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromtrans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromdate");
DATEOUT();
break;
case 110: /* Get n-th volume */
2018-01-07 18:47:30 +08:00
ND_PRINT(" index");
UINTOUT();
break;
case 111: /* Set forwarding */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" newsite");
UINTOUT();
break;
case 112: /* Get name */
case 113: /* Get status */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
break;
case 114: /* Signal restore */
2018-01-07 18:47:30 +08:00
ND_PRINT(" name");
STROUT(AFSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" type");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" pid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" cloneid");
UINTOUT();
break;
case 116: /* List volumes */
2018-01-07 18:47:30 +08:00
ND_PRINT(" partition");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flags");
UINTOUT();
break;
case 117: /* Set id types */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" name");
STROUT(AFSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" type");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" pid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" clone");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" backup");
UINTOUT();
break;
case 119: /* Partition info */
2018-01-07 18:47:30 +08:00
ND_PRINT(" name");
STROUT(AFSNAMEMAX);
break;
case 120: /* Reclone */
2018-01-07 18:47:30 +08:00
ND_PRINT(" 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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" partid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
UINTOUT();
break;
case 123: /* Set date */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" date");
DATEOUT();
break;
case 126: /* Set info */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UINTOUT();
break;
case 128: /* Forward multiple */
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromtrans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromdate");
DATEOUT();
{
uint32_t i, j;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (i = 0; i < j; i++) {
DESTSERVEROUT();
if (i != j - 1)
2018-01-07 18:47:30 +08:00
ND_PRINT(",");
}
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
case 65538: /* Dump version 2 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromtrans");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" fromdate");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flags");
UINTOUT();
break;
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|vol]");
}
/*
* Handle replies to the AFS Volume Service
*/
static void
2014-03-30 23:16:23 +08:00
vol_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
if (length <= sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from volser/volint.xg
*/
2002-06-12 01:08:37 +08:00
2018-01-07 18:47:30 +08:00
ND_PRINT(" vol reply %s", tok2str(vol_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (type == RX_PACKET_TYPE_DATA) {
switch (opcode) {
case 100: /* Create volume */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" trans");
UINTOUT();
break;
case 104: /* End transaction */
UINTOUT();
break;
case 105: /* Clone */
2018-01-07 18:47:30 +08:00
ND_PRINT(" newvol");
UINTOUT();
break;
case 107: /* Get flags */
UINTOUT();
break;
case 108: /* Transaction create */
2018-01-07 18:47:30 +08:00
ND_PRINT(" trans");
UINTOUT();
break;
case 110: /* Get n-th volume */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volume");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" partition");
UINTOUT();
break;
case 112: /* Get name */
STROUT(AFSNAMEMAX);
break;
case 113: /* Get status */
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" nextuniq");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" type");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" parentid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" clone");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" backup");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" restore");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" maxquota");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" minquota");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" owner");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" create");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" access");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" update");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" expire");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" backup");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" copy");
DATEOUT();
break;
case 115: /* Old list partitions */
break;
case 116: /* List volumes */
case 121: /* List one volume */
{
uint32_t i, j;
ND_TCHECK_4(bp);
j = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
for (i = 0; i < j; i++) {
2018-01-07 18:47:30 +08:00
ND_PRINT(" name");
VECOUT(32);
2018-01-07 18:47:30 +08:00
ND_PRINT(" volid");
UINTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" type");
bp += sizeof(uint32_t) * 21;
if (i != j - 1)
2018-01-07 18:47:30 +08:00
ND_PRINT(",");
}
if (j == 0)
2018-01-07 18:47:30 +08:00
ND_PRINT(" <none!>");
}
break;
2014-01-02 10:27:54 +08:00
default:
;
}
} else {
/*
* Otherwise, just print out the return code
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|vol]");
}
/*
* Handle calls to the AFS BOS service
*/
static void
2014-03-30 23:16:23 +08:00
bos_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
uint32_t bos_op;
if (length <= sizeof(struct rx_header))
return;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from bozo/bosint.xg
*/
ND_TCHECK_4(bp + sizeof(struct rx_header));
bos_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" bos call %s", tok2str(bos_req, "op#%u", 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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" type");
STROUT(BOSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" 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);
2018-01-07 18:47:30 +08:00
ND_PRINT(" status");
INTOUT();
break;
case 86: /* Get instance parm */
STROUT(BOSNAMEMAX);
2018-01-07 18:47:30 +08:00
ND_PRINT(" 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);
2018-01-07 18:47:30 +08:00
ND_PRINT(" size");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" flags");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" date");
INTOUT();
break;
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|bos]");
}
/*
* Handle replies to the AFS BOS Service
*/
static void
2014-03-30 23:16:23 +08:00
bos_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
if (length <= sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from volser/volint.xg
*/
2002-06-12 01:08:37 +08:00
2018-01-07 18:47:30 +08:00
ND_PRINT(" bos reply %s", tok2str(bos_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, interpret the response.
*/
if (type == RX_PACKET_TYPE_DATA)
/* Well, no, not really. Leave this for later */
;
else {
/*
* Otherwise, just print out the return code
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|bos]");
}
/*
* Check to see if this is a Ubik opcode.
*/
static int
is_ubik(uint32_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
2014-03-30 23:16:23 +08:00
ubik_print(netdissect_options *ndo,
const u_char *bp)
{
uint32_t ubik_op;
uint32_t temp;
/*
* Print out the afs call we're invoking. The table used here was
* gleaned from ubik/ubik_int.xg
*/
/* Every function that calls this function first makes a bounds check
* for (sizeof(rx_header) + 4) bytes, so long as it remains this way
* the line below will not over-read.
*/
ubik_op = EXTRACT_BE_U_4(bp + sizeof(struct rx_header));
2018-01-07 18:47:30 +08:00
ND_PRINT(" ubik call %s", tok2str(ubik_req, "op#%u", ubik_op));
/*
* Decode some of the arguments to the Ubik calls
*/
bp += sizeof(struct rx_header) + 4;
switch (ubik_op) {
case 10000: /* Beacon */
ND_TCHECK_4(bp);
temp = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
2018-01-07 18:47:30 +08:00
ND_PRINT(" syncsite %s", temp ? "yes" : "no");
ND_PRINT(" votestart");
DATEOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" dbversion");
UBIK_VERSIONOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UBIK_VERSIONOUT();
break;
case 10003: /* Get sync site */
2018-01-07 18:47:30 +08:00
ND_PRINT(" site");
UINTOUT();
break;
case 20000: /* Begin */
case 20001: /* Commit */
case 20007: /* Abort */
case 20008: /* Release locks */
case 20010: /* Writev */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UBIK_VERSIONOUT();
break;
case 20002: /* Lock */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UBIK_VERSIONOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" file");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" pos");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" length");
INTOUT();
ND_TCHECK_4(bp);
temp = EXTRACT_BE_U_4(bp);
bp += sizeof(uint32_t);
tok2str(ubik_lock_types, "type %u", temp);
break;
case 20003: /* Write */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UBIK_VERSIONOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" file");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" pos");
INTOUT();
break;
case 20005: /* Get file */
2018-01-07 18:47:30 +08:00
ND_PRINT(" file");
INTOUT();
break;
case 20006: /* Send file */
2018-01-07 18:47:30 +08:00
ND_PRINT(" file");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" length");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" dbversion");
UBIK_VERSIONOUT();
break;
case 20009: /* Truncate */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UBIK_VERSIONOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" file");
INTOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" length");
INTOUT();
break;
case 20012: /* Set version */
2018-01-07 18:47:30 +08:00
ND_PRINT(" tid");
UBIK_VERSIONOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" oldversion");
UBIK_VERSIONOUT();
2018-01-07 18:47:30 +08:00
ND_PRINT(" newversion");
UBIK_VERSIONOUT();
break;
default:
;
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|ubik]");
}
/*
* Handle Ubik replies to any one of the replicated database services
*/
static void
2014-03-30 23:16:23 +08:00
ubik_reply_print(netdissect_options *ndo,
const u_char *bp, u_int length, uint32_t opcode)
{
2015-04-27 08:24:42 +08:00
const struct rx_header *rxh;
uint8_t type;
if (length < sizeof(struct rx_header))
return;
2015-04-27 08:24:42 +08:00
rxh = (const struct rx_header *) bp;
/*
* Print out the ubik call we're invoking. This table was gleaned
* from ubik/ubik_int.xg
*/
2018-01-07 18:47:30 +08:00
ND_PRINT(" ubik reply %s", tok2str(ubik_req, "op#%u", opcode));
type = EXTRACT_U_1(rxh->type);
bp += sizeof(struct rx_header);
/*
* If it was a data packet, print out the arguments to the Ubik calls
*/
2002-06-12 01:08:37 +08:00
if (type == RX_PACKET_TYPE_DATA)
switch (opcode) {
case 10000: /* Beacon */
2018-01-07 18:47:30 +08:00
ND_PRINT(" vote no");
break;
case 20004: /* Get version */
2018-01-07 18:47:30 +08:00
ND_PRINT(" dbversion");
UBIK_VERSIONOUT();
break;
default:
;
}
2002-06-12 01:08:37 +08:00
/*
* 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 */
2018-01-07 18:47:30 +08:00
ND_PRINT(" vote yes until");
DATEOUT();
break;
default:
2018-01-07 18:47:30 +08:00
ND_PRINT(" errcode");
INTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|ubik]");
}
/*
* Handle RX ACK packets.
*/
static void
2014-03-30 23:16:23 +08:00
rx_ack_print(netdissect_options *ndo,
const u_char *bp, u_int length)
{
2015-04-27 08:24:42 +08:00
const struct rx_ackPacket *rxa;
uint8_t nAcks;
int i, start, last;
uint32_t firstPacket;
if (length < sizeof(struct rx_header))
return;
bp += sizeof(struct rx_header);
ND_TCHECK_LEN(bp, sizeof(struct rx_ackPacket));
2015-04-27 08:24:42 +08:00
rxa = (const struct rx_ackPacket *) bp;
bp += sizeof(struct rx_ackPacket);
/*
* Print out a few useful things from the ack packet structure
*/
2014-03-30 23:16:23 +08:00
if (ndo->ndo_vflag > 2)
2018-01-12 03:52:30 +08:00
ND_PRINT(" bufspace %u maxskew %u",
EXTRACT_BE_U_2(rxa->bufferSpace),
2018-01-07 18:47:30 +08:00
EXTRACT_BE_U_2(rxa->maxSkew));
2002-06-12 01:08:37 +08:00
firstPacket = EXTRACT_BE_U_4(rxa->firstPacket);
2018-01-07 18:47:30 +08:00
ND_PRINT(" first %u serial %u reason %s",
firstPacket, EXTRACT_BE_U_4(rxa->serial),
2018-01-07 18:47:30 +08:00
tok2str(rx_ack_reasons, "#%u", EXTRACT_U_1(rxa->reason)));
2002-06-12 01:08:37 +08:00
/*
* 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
2002-06-12 01:08:37 +08:00
* 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.
*/
nAcks = EXTRACT_U_1(rxa->nAcks);
if (nAcks != 0) {
ND_TCHECK_LEN(bp, nAcks);
/*
* Sigh, this is gross, but it seems to work to collapse
* ranges correctly.
*/
for (i = 0, start = last = -2; i < nAcks; i++)
if (EXTRACT_U_1(bp + 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) {
2018-01-07 18:47:30 +08:00
ND_PRINT(" acked %u", firstPacket + i);
start = i;
}
/*
2014-04-05 17:49:45 +08:00
* Otherwise, if 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) {
2018-01-07 18:47:30 +08:00
ND_PRINT(",%u", 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)
2018-01-07 18:47:30 +08:00
ND_PRINT("-%u", firstPacket + i - 1);
2002-06-12 01:08:37 +08:00
/*
* 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)
2018-01-07 18:47:30 +08:00
ND_PRINT("-%u", firstPacket + i - 1);
/*
* Same as above, just without comments
*/
2002-06-12 01:08:37 +08:00
for (i = 0, start = last = -2; i < nAcks; i++)
if (EXTRACT_U_1(bp + i) == RX_ACK_TYPE_NACK) {
if (last == -2) {
2018-01-07 18:47:30 +08:00
ND_PRINT(" nacked %u", firstPacket + i);
start = i;
} else if (last != i - 1) {
2018-01-07 18:47:30 +08:00
ND_PRINT(",%u", firstPacket + i);
start = i;
}
last = i;
} else if (last == i - 1 && start != last)
2018-01-07 18:47:30 +08:00
ND_PRINT("-%u", firstPacket + i - 1);
2002-06-12 01:08:37 +08:00
if (last == i - 1 && start != last)
2018-01-07 18:47:30 +08:00
ND_PRINT("-%u", firstPacket + i - 1);
bp += nAcks;
}
/* Padding. */
bp += 3;
/*
* These are optional fields; depending on your version of AFS,
* you may or may not see them
*/
2014-03-30 23:16:23 +08:00
#define TRUNCRET(n) if (ndo->ndo_snapend - bp + 1 <= n) return;
2014-03-30 23:16:23 +08:00
if (ndo->ndo_vflag > 1) {
TRUNCRET(4);
2018-01-07 18:47:30 +08:00
ND_PRINT(" ifmtu");
UINTOUT();
TRUNCRET(4);
2018-01-07 18:47:30 +08:00
ND_PRINT(" maxmtu");
UINTOUT();
TRUNCRET(4);
2018-01-07 18:47:30 +08:00
ND_PRINT(" rwind");
UINTOUT();
TRUNCRET(4);
2018-01-07 18:47:30 +08:00
ND_PRINT(" maxpackets");
UINTOUT();
}
return;
trunc:
2018-01-07 18:47:30 +08:00
ND_PRINT(" [|ack]");
}
#undef TRUNCRET