xref: /freebsd/contrib/tcpdump/print-rx.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
1 /*
2  * Copyright: (c) 2000 United States Government as represented by the
3  *	Secretary of the Navy. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in
13  *      the documentation and/or other materials provided with the
14  *      distribution.
15  *   3. The names of the authors may not be used to endorse or promote
16  *      products derived from this software without specific prior
17  *      written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 
24 /* \summary: AFS RX printer */
25 
26 /*
27  * This code unmangles RX packets.  RX is the mutant form of RPC that AFS
28  * uses to communicate between clients and servers.
29  *
30  * In this code, I mainly concern myself with decoding the AFS calls, not
31  * with the guts of RX, per se.
32  *
33  * Bah.  If I never look at rx_packet.h again, it will be too soon.
34  *
35  * Ken Hornstein <kenh@cmf.nrl.navy.mil>
36  */
37 
38 #include <config.h>
39 
40 #include <stdio.h>
41 #include <string.h>
42 #include "netdissect-stdinc.h"
43 
44 #include "netdissect.h"
45 #include "addrtoname.h"
46 #include "extract.h"
47 
48 #include "ip.h"
49 
50 #define FS_RX_PORT	7000
51 #define CB_RX_PORT	7001
52 #define PROT_RX_PORT	7002
53 #define VLDB_RX_PORT	7003
54 #define KAUTH_RX_PORT	7004
55 #define VOL_RX_PORT	7005
56 #define ERROR_RX_PORT	7006		/* Doesn't seem to be used */
57 #define BOS_RX_PORT	7007
58 
59 #define AFSOPAQUEMAX 1024
60 #define AFSNAMEMAX 256			/* Must be >= PRNAMEMAX + 1, VLNAMEMAX + 1, and 32 + 1 */
61 #define PRNAMEMAX 64
62 #define VLNAMEMAX 65
63 #define KANAMEMAX 64
64 #define BOSNAMEMAX 256
65 #define USERNAMEMAX 1024		/* AFSOPAQUEMAX was used for this; does it need to be this big? */
66 
67 #define	PRSFS_READ		1 /* Read files */
68 #define	PRSFS_WRITE		2 /* Write files */
69 #define	PRSFS_INSERT		4 /* Insert files into a directory */
70 #define	PRSFS_LOOKUP		8 /* Lookup files into a directory */
71 #define	PRSFS_DELETE		16 /* Delete files */
72 #define	PRSFS_LOCK		32 /* Lock files */
73 #define	PRSFS_ADMINISTER	64 /* Change ACL's */
74 
75 struct rx_header {
76 	nd_uint32_t epoch;
77 	nd_uint32_t cid;
78 	nd_uint32_t callNumber;
79 	nd_uint32_t seq;
80 	nd_uint32_t serial;
81 	nd_uint8_t type;
82 #define RX_PACKET_TYPE_DATA		1
83 #define RX_PACKET_TYPE_ACK		2
84 #define RX_PACKET_TYPE_BUSY		3
85 #define RX_PACKET_TYPE_ABORT		4
86 #define RX_PACKET_TYPE_ACKALL		5
87 #define RX_PACKET_TYPE_CHALLENGE	6
88 #define RX_PACKET_TYPE_RESPONSE		7
89 #define RX_PACKET_TYPE_DEBUG		8
90 #define RX_PACKET_TYPE_PARAMS		9
91 #define RX_PACKET_TYPE_VERSION		13
92 	nd_uint8_t flags;
93 #define RX_CLIENT_INITIATED	1
94 #define RX_REQUEST_ACK		2
95 #define RX_LAST_PACKET		4
96 #define RX_MORE_PACKETS		8
97 #define RX_FREE_PACKET		16
98 #define RX_SLOW_START_OK	32
99 #define RX_JUMBO_PACKET		32
100 	nd_uint8_t userStatus;
101 	nd_uint8_t securityIndex;
102 	nd_uint16_t spare;		/* How clever: even though the AFS */
103 	nd_uint16_t serviceId;		/* header files indicate that the */
104 };					/* serviceId is first, it's really */
105 					/* encoded _after_ the spare field */
106 					/* I wasted a day figuring that out! */
107 
108 #define NUM_RX_FLAGS 7
109 
110 #define RX_MAXACKS 255
111 
112 struct rx_ackPacket {
113 	nd_uint16_t bufferSpace;	/* Number of packet buffers available */
114 	nd_uint16_t maxSkew;		/* Max diff between ack'd packet and */
115 					/* highest packet received */
116 	nd_uint32_t firstPacket;	/* The first packet in ack list */
117 	nd_uint32_t previousPacket;	/* Previous packet recv'd (obsolete) */
118 	nd_uint32_t serial;		/* # of packet that prompted the ack */
119 	nd_uint8_t reason;		/* Reason for acknowledgement */
120 	nd_uint8_t nAcks;		/* Number of acknowledgements */
121 	/* Followed by nAcks acknowledgments */
122 #if 0
123 	uint8_t acks[RX_MAXACKS];	/* Up to RX_MAXACKS acknowledgements */
124 #endif
125 };
126 
127 /*
128  * Values for the acks array
129  */
130 
131 #define RX_ACK_TYPE_NACK	0	/* Don't have this packet */
132 #define RX_ACK_TYPE_ACK		1	/* I have this packet */
133 
134 static const struct tok rx_types[] = {
135 	{ RX_PACKET_TYPE_DATA,		"data" },
136 	{ RX_PACKET_TYPE_ACK,		"ack" },
137 	{ RX_PACKET_TYPE_BUSY,		"busy" },
138 	{ RX_PACKET_TYPE_ABORT,		"abort" },
139 	{ RX_PACKET_TYPE_ACKALL,	"ackall" },
140 	{ RX_PACKET_TYPE_CHALLENGE,	"challenge" },
141 	{ RX_PACKET_TYPE_RESPONSE,	"response" },
142 	{ RX_PACKET_TYPE_DEBUG,		"debug" },
143 	{ RX_PACKET_TYPE_PARAMS,	"params" },
144 	{ RX_PACKET_TYPE_VERSION,	"version" },
145 	{ 0,				NULL },
146 };
147 
148 static const struct double_tok {
149 	uint32_t flag;		/* Rx flag */
150 	uint32_t packetType;	/* Packet type */
151 	const char *s;		/* Flag string */
152 } rx_flags[] = {
153 	{ RX_CLIENT_INITIATED,	0,			"client-init" },
154 	{ RX_REQUEST_ACK,	0,			"req-ack" },
155 	{ RX_LAST_PACKET,	0,			"last-pckt" },
156 	{ RX_MORE_PACKETS,	0,			"more-pckts" },
157 	{ RX_FREE_PACKET,	0,			"free-pckt" },
158 	{ RX_SLOW_START_OK,	RX_PACKET_TYPE_ACK,	"slow-start" },
159 	{ RX_JUMBO_PACKET,	RX_PACKET_TYPE_DATA,	"jumbogram" }
160 };
161 
162 static const struct tok fs_req[] = {
163 	{ 130,		"fetch-data" },
164 	{ 131,		"fetch-acl" },
165 	{ 132,		"fetch-status" },
166 	{ 133,		"store-data" },
167 	{ 134,		"store-acl" },
168 	{ 135,		"store-status" },
169 	{ 136,		"remove-file" },
170 	{ 137,		"create-file" },
171 	{ 138,		"rename" },
172 	{ 139,		"symlink" },
173 	{ 140,		"link" },
174 	{ 141,		"makedir" },
175 	{ 142,		"rmdir" },
176 	{ 143,		"oldsetlock" },
177 	{ 144,		"oldextlock" },
178 	{ 145,		"oldrellock" },
179 	{ 146,		"get-stats" },
180 	{ 147,		"give-cbs" },
181 	{ 148,		"get-vlinfo" },
182 	{ 149,		"get-vlstats" },
183 	{ 150,		"set-vlstats" },
184 	{ 151,		"get-rootvl" },
185 	{ 152,		"check-token" },
186 	{ 153,		"get-time" },
187 	{ 154,		"nget-vlinfo" },
188 	{ 155,		"bulk-stat" },
189 	{ 156,		"setlock" },
190 	{ 157,		"extlock" },
191 	{ 158,		"rellock" },
192 	{ 159,		"xstat-ver" },
193 	{ 160,		"get-xstat" },
194 	{ 161,		"dfs-lookup" },
195 	{ 162,		"dfs-flushcps" },
196 	{ 163,		"dfs-symlink" },
197 	{ 220,		"residency" },
198 	{ 65536,        "inline-bulk-status" },
199 	{ 65537,        "fetch-data-64" },
200 	{ 65538,        "store-data-64" },
201 	{ 65539,        "give-up-all-cbs" },
202 	{ 65540,        "get-caps" },
203 	{ 65541,        "cb-rx-conn-addr" },
204 	{ 0,		NULL },
205 };
206 
207 static const struct tok cb_req[] = {
208 	{ 204,		"callback" },
209 	{ 205,		"initcb" },
210 	{ 206,		"probe" },
211 	{ 207,		"getlock" },
212 	{ 208,		"getce" },
213 	{ 209,		"xstatver" },
214 	{ 210,		"getxstat" },
215 	{ 211,		"initcb2" },
216 	{ 212,		"whoareyou" },
217 	{ 213,		"initcb3" },
218 	{ 214,		"probeuuid" },
219 	{ 215,		"getsrvprefs" },
220 	{ 216,		"getcellservdb" },
221 	{ 217,		"getlocalcell" },
222 	{ 218,		"getcacheconf" },
223 	{ 65536,        "getce64" },
224 	{ 65537,        "getcellbynum" },
225 	{ 65538,        "tellmeaboutyourself" },
226 	{ 0,		NULL },
227 };
228 
229 static const struct tok pt_req[] = {
230 	{ 500,		"new-user" },
231 	{ 501,		"where-is-it" },
232 	{ 502,		"dump-entry" },
233 	{ 503,		"add-to-group" },
234 	{ 504,		"name-to-id" },
235 	{ 505,		"id-to-name" },
236 	{ 506,		"delete" },
237 	{ 507,		"remove-from-group" },
238 	{ 508,		"get-cps" },
239 	{ 509,		"new-entry" },
240 	{ 510,		"list-max" },
241 	{ 511,		"set-max" },
242 	{ 512,		"list-entry" },
243 	{ 513,		"change-entry" },
244 	{ 514,		"list-elements" },
245 	{ 515,		"same-mbr-of" },
246 	{ 516,		"set-fld-sentry" },
247 	{ 517,		"list-owned" },
248 	{ 518,		"get-cps2" },
249 	{ 519,		"get-host-cps" },
250 	{ 520,		"update-entry" },
251 	{ 521,		"list-entries" },
252 	{ 530,		"list-super-groups" },
253 	{ 0,		NULL },
254 };
255 
256 static const struct tok vldb_req[] = {
257 	{ 501,		"create-entry" },
258 	{ 502,		"delete-entry" },
259 	{ 503,		"get-entry-by-id" },
260 	{ 504,		"get-entry-by-name" },
261 	{ 505,		"get-new-volume-id" },
262 	{ 506,		"replace-entry" },
263 	{ 507,		"update-entry" },
264 	{ 508,		"setlock" },
265 	{ 509,		"releaselock" },
266 	{ 510,		"list-entry" },
267 	{ 511,		"list-attrib" },
268 	{ 512,		"linked-list" },
269 	{ 513,		"get-stats" },
270 	{ 514,		"probe" },
271 	{ 515,		"get-addrs" },
272 	{ 516,		"change-addr" },
273 	{ 517,		"create-entry-n" },
274 	{ 518,		"get-entry-by-id-n" },
275 	{ 519,		"get-entry-by-name-n" },
276 	{ 520,		"replace-entry-n" },
277 	{ 521,		"list-entry-n" },
278 	{ 522,		"list-attrib-n" },
279 	{ 523,		"linked-list-n" },
280 	{ 524,		"update-entry-by-name" },
281 	{ 525,		"create-entry-u" },
282 	{ 526,		"get-entry-by-id-u" },
283 	{ 527,		"get-entry-by-name-u" },
284 	{ 528,		"replace-entry-u" },
285 	{ 529,		"list-entry-u" },
286 	{ 530,		"list-attrib-u" },
287 	{ 531,		"linked-list-u" },
288 	{ 532,		"regaddr" },
289 	{ 533,		"get-addrs-u" },
290 	{ 534,		"list-attrib-n2" },
291 	{ 0,		NULL },
292 };
293 
294 static const struct tok kauth_req[] = {
295 	{ 1,		"auth-old" },
296 	{ 21,		"authenticate" },
297 	{ 22,		"authenticate-v2" },
298 	{ 2,		"change-pw" },
299 	{ 3,		"get-ticket-old" },
300 	{ 23,		"get-ticket" },
301 	{ 4,		"set-pw" },
302 	{ 5,		"set-fields" },
303 	{ 6,		"create-user" },
304 	{ 7,		"delete-user" },
305 	{ 8,		"get-entry" },
306 	{ 9,		"list-entry" },
307 	{ 10,		"get-stats" },
308 	{ 11,		"debug" },
309 	{ 12,		"get-pw" },
310 	{ 13,		"get-random-key" },
311 	{ 14,		"unlock" },
312 	{ 15,		"lock-status" },
313 	{ 0,		NULL },
314 };
315 
316 static const struct tok vol_req[] = {
317 	{ 100,		"create-volume" },
318 	{ 101,		"delete-volume" },
319 	{ 102,		"restore" },
320 	{ 103,		"forward" },
321 	{ 104,		"end-trans" },
322 	{ 105,		"clone" },
323 	{ 106,		"set-flags" },
324 	{ 107,		"get-flags" },
325 	{ 108,		"trans-create" },
326 	{ 109,		"dump" },
327 	{ 110,		"get-nth-volume" },
328 	{ 111,		"set-forwarding" },
329 	{ 112,		"get-name" },
330 	{ 113,		"get-status" },
331 	{ 114,		"sig-restore" },
332 	{ 115,		"list-partitions" },
333 	{ 116,		"list-volumes" },
334 	{ 117,		"set-id-types" },
335 	{ 118,		"monitor" },
336 	{ 119,		"partition-info" },
337 	{ 120,		"reclone" },
338 	{ 121,		"list-one-volume" },
339 	{ 122,		"nuke" },
340 	{ 123,		"set-date" },
341 	{ 124,		"x-list-volumes" },
342 	{ 125,		"x-list-one-volume" },
343 	{ 126,		"set-info" },
344 	{ 127,		"x-list-partitions" },
345 	{ 128,		"forward-multiple" },
346 	{ 65536,	"convert-ro" },
347 	{ 65537,	"get-size" },
348 	{ 65538,	"dump-v2" },
349 	{ 0,		NULL },
350 };
351 
352 static const struct tok bos_req[] = {
353 	{ 80,		"create-bnode" },
354 	{ 81,		"delete-bnode" },
355 	{ 82,		"set-status" },
356 	{ 83,		"get-status" },
357 	{ 84,		"enumerate-instance" },
358 	{ 85,		"get-instance-info" },
359 	{ 86,		"get-instance-parm" },
360 	{ 87,		"add-superuser" },
361 	{ 88,		"delete-superuser" },
362 	{ 89,		"list-superusers" },
363 	{ 90,		"list-keys" },
364 	{ 91,		"add-key" },
365 	{ 92,		"delete-key" },
366 	{ 93,		"set-cell-name" },
367 	{ 94,		"get-cell-name" },
368 	{ 95,		"get-cell-host" },
369 	{ 96,		"add-cell-host" },
370 	{ 97,		"delete-cell-host" },
371 	{ 98,		"set-t-status" },
372 	{ 99,		"shutdown-all" },
373 	{ 100,		"restart-all" },
374 	{ 101,		"startup-all" },
375 	{ 102,		"set-noauth-flag" },
376 	{ 103,		"re-bozo" },
377 	{ 104,		"restart" },
378 	{ 105,		"start-bozo-install" },
379 	{ 106,		"uninstall" },
380 	{ 107,		"get-dates" },
381 	{ 108,		"exec" },
382 	{ 109,		"prune" },
383 	{ 110,		"set-restart-time" },
384 	{ 111,		"get-restart-time" },
385 	{ 112,		"start-bozo-log" },
386 	{ 113,		"wait-all" },
387 	{ 114,		"get-instance-strings" },
388 	{ 115,		"get-restricted" },
389 	{ 116,		"set-restricted" },
390 	{ 0,		NULL },
391 };
392 
393 static const struct tok ubik_req[] = {
394 	{ 10000,	"vote-beacon" },
395 	{ 10001,	"vote-debug-old" },
396 	{ 10002,	"vote-sdebug-old" },
397 	{ 10003,	"vote-getsyncsite" },
398 	{ 10004,	"vote-debug" },
399 	{ 10005,	"vote-sdebug" },
400 	{ 10006,	"vote-xdebug" },
401 	{ 10007,	"vote-xsdebug" },
402 	{ 20000,	"disk-begin" },
403 	{ 20001,	"disk-commit" },
404 	{ 20002,	"disk-lock" },
405 	{ 20003,	"disk-write" },
406 	{ 20004,	"disk-getversion" },
407 	{ 20005,	"disk-getfile" },
408 	{ 20006,	"disk-sendfile" },
409 	{ 20007,	"disk-abort" },
410 	{ 20008,	"disk-releaselocks" },
411 	{ 20009,	"disk-truncate" },
412 	{ 20010,	"disk-probe" },
413 	{ 20011,	"disk-writev" },
414 	{ 20012,	"disk-interfaceaddr" },
415 	{ 20013,	"disk-setversion" },
416 	{ 0,		NULL },
417 };
418 
419 #define VOTE_LOW	10000
420 #define VOTE_HIGH	10007
421 #define DISK_LOW	20000
422 #define DISK_HIGH	20013
423 
424 static const struct tok cb_types[] = {
425 	{ 1,		"exclusive" },
426 	{ 2,		"shared" },
427 	{ 3,		"dropped" },
428 	{ 0,		NULL },
429 };
430 
431 static const struct tok ubik_lock_types[] = {
432 	{ 1,		"read" },
433 	{ 2,		"write" },
434 	{ 3,		"wait" },
435 	{ 0,		NULL },
436 };
437 
438 static const char *voltype[] = { "read-write", "read-only", "backup" };
439 
440 static const struct tok afs_fs_errors[] = {
441 	{ 101,		"salvage volume" },
442 	{ 102,		"no such vnode" },
443 	{ 103,		"no such volume" },
444 	{ 104,		"volume exist" },
445 	{ 105,		"no service" },
446 	{ 106,		"volume offline" },
447 	{ 107,		"voline online" },
448 	{ 108,		"diskfull" },
449 	{ 109,		"diskquota exceeded" },
450 	{ 110,		"volume busy" },
451 	{ 111,		"volume moved" },
452 	{ 112,		"AFS IO error" },
453 	{ 0xffffff9c,	"restarting fileserver" }, /* -100, sic! */
454 	{ 0,		NULL }
455 };
456 
457 /*
458  * Reasons for acknowledging a packet
459  */
460 
461 static const struct tok rx_ack_reasons[] = {
462 	{ 1,		"ack requested" },
463 	{ 2,		"duplicate packet" },
464 	{ 3,		"out of sequence" },
465 	{ 4,		"exceeds window" },
466 	{ 5,		"no buffer space" },
467 	{ 6,		"ping" },
468 	{ 7,		"ping response" },
469 	{ 8,		"delay" },
470 	{ 9,		"idle" },
471 	{ 0,		NULL },
472 };
473 
474 /*
475  * Cache entries we keep around so we can figure out the RX opcode
476  * numbers for replies.  This allows us to make sense of RX reply packets.
477  */
478 
479 struct rx_cache_entry {
480 	uint32_t	callnum;	/* Call number (net order) */
481 	uint32_t	client;		/* client IP address (net order) */
482 	uint32_t	server;		/* server IP address (net order) */
483 	uint16_t	dport;		/* server UDP port (host order) */
484 	uint16_t	serviceId;	/* Service identifier (net order) */
485 	uint32_t	opcode;		/* RX opcode (host order) */
486 };
487 
488 #define RX_CACHE_SIZE	64
489 
490 static struct rx_cache_entry	rx_cache[RX_CACHE_SIZE];
491 
492 static uint32_t	rx_cache_next = 0;
493 static uint32_t	rx_cache_hint = 0;
494 static void	rx_cache_insert(netdissect_options *, const u_char *, const struct ip *, uint16_t);
495 static int	rx_cache_find(netdissect_options *, const struct rx_header *,
496 			      const struct ip *, uint16_t, uint32_t *);
497 
498 static void fs_print(netdissect_options *, const u_char *, u_int);
499 static void fs_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
500 static void acl_print(netdissect_options *, u_char *, const u_char *);
501 static void cb_print(netdissect_options *, const u_char *, u_int);
502 static void cb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
503 static void prot_print(netdissect_options *, const u_char *, u_int);
504 static void prot_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
505 static void vldb_print(netdissect_options *, const u_char *, u_int);
506 static void vldb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
507 static void kauth_print(netdissect_options *, const u_char *, u_int);
508 static void kauth_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
509 static void vol_print(netdissect_options *, const u_char *, u_int);
510 static void vol_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
511 static void bos_print(netdissect_options *, const u_char *, u_int);
512 static void bos_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
513 static void ubik_print(netdissect_options *, const u_char *);
514 static void ubik_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
515 
516 static void rx_ack_print(netdissect_options *, const u_char *, u_int);
517 
518 static int is_ubik(uint32_t);
519 
520 /*
521  * Handle the rx-level packet.  See if we know what port it's going to so
522  * we can peek at the afs call inside
523  */
524 
525 void
rx_print(netdissect_options * ndo,const u_char * bp,u_int length,uint16_t sport,uint16_t dport,const u_char * bp2)526 rx_print(netdissect_options *ndo,
527          const u_char *bp, u_int length, uint16_t sport, uint16_t dport,
528          const u_char *bp2)
529 {
530 	const struct rx_header *rxh;
531 	uint32_t i;
532 	uint8_t type, flags;
533 	uint32_t opcode;
534 
535 	ndo->ndo_protocol = "rx";
536 	if (!ND_TTEST_LEN(bp, sizeof(struct rx_header))) {
537 		ND_PRINT(" [|rx] (%u)", length);
538 		return;
539 	}
540 
541 	rxh = (const struct rx_header *) bp;
542 
543 	type = GET_U_1(rxh->type);
544 	ND_PRINT(" rx %s", tok2str(rx_types, "type %u", type));
545 
546 	flags = GET_U_1(rxh->flags);
547 	if (ndo->ndo_vflag) {
548 		int firstflag = 0;
549 
550 		if (ndo->ndo_vflag > 1)
551 			ND_PRINT(" cid %08x call# %u",
552 			       GET_BE_U_4(rxh->cid),
553 			       GET_BE_U_4(rxh->callNumber));
554 
555 		ND_PRINT(" seq %u ser %u",
556 		       GET_BE_U_4(rxh->seq),
557 		       GET_BE_U_4(rxh->serial));
558 
559 		if (ndo->ndo_vflag > 2)
560 			ND_PRINT(" secindex %u serviceid %hu",
561 				GET_U_1(rxh->securityIndex),
562 				GET_BE_U_2(rxh->serviceId));
563 
564 		if (ndo->ndo_vflag > 1)
565 			for (i = 0; i < NUM_RX_FLAGS; i++) {
566 				if (flags & rx_flags[i].flag &&
567 				    (!rx_flags[i].packetType ||
568 				     type == rx_flags[i].packetType)) {
569 					if (!firstflag) {
570 						firstflag = 1;
571 						ND_PRINT(" ");
572 					} else {
573 						ND_PRINT(",");
574 					}
575 					ND_PRINT("<%s>", rx_flags[i].s);
576 				}
577 			}
578 	}
579 
580 	/*
581 	 * Try to handle AFS calls that we know about.  Check the destination
582 	 * port and make sure it's a data packet.  Also, make sure the
583 	 * seq number is 1 (because otherwise it's a continuation packet,
584 	 * and we can't interpret that).  Also, seems that reply packets
585 	 * do not have the client-init flag set, so we check for that
586 	 * as well.
587 	 */
588 
589 	if (type == RX_PACKET_TYPE_DATA &&
590 	    GET_BE_U_4(rxh->seq) == 1 &&
591 	    flags & RX_CLIENT_INITIATED) {
592 
593 		/*
594 		 * Insert this call into the call cache table, so we
595 		 * have a chance to print out replies
596 		 */
597 
598 		rx_cache_insert(ndo, bp, (const struct ip *) bp2, dport);
599 
600 		switch (dport) {
601 			case FS_RX_PORT:	/* AFS file service */
602 				fs_print(ndo, bp, length);
603 				break;
604 			case CB_RX_PORT:	/* AFS callback service */
605 				cb_print(ndo, bp, length);
606 				break;
607 			case PROT_RX_PORT:	/* AFS protection service */
608 				prot_print(ndo, bp, length);
609 				break;
610 			case VLDB_RX_PORT:	/* AFS VLDB service */
611 				vldb_print(ndo, bp, length);
612 				break;
613 			case KAUTH_RX_PORT:	/* AFS Kerberos auth service */
614 				kauth_print(ndo, bp, length);
615 				break;
616 			case VOL_RX_PORT:	/* AFS Volume service */
617 				vol_print(ndo, bp, length);
618 				break;
619 			case BOS_RX_PORT:	/* AFS BOS service */
620 				bos_print(ndo, bp, length);
621 				break;
622 			default:
623 				;
624 		}
625 
626 	/*
627 	 * If it's a reply (client-init is _not_ set, but seq is one)
628 	 * then look it up in the cache.  If we find it, call the reply
629 	 * printing functions  Note that we handle abort packets here,
630 	 * because printing out the return code can be useful at times.
631 	 */
632 
633 	} else if (((type == RX_PACKET_TYPE_DATA &&
634 					GET_BE_U_4(rxh->seq) == 1) ||
635 		    type == RX_PACKET_TYPE_ABORT) &&
636 		   (flags & RX_CLIENT_INITIATED) == 0 &&
637 		   rx_cache_find(ndo, rxh, (const struct ip *) bp2,
638 				 sport, &opcode)) {
639 
640 		switch (sport) {
641 			case FS_RX_PORT:	/* AFS file service */
642 				fs_reply_print(ndo, bp, length, opcode);
643 				break;
644 			case CB_RX_PORT:	/* AFS callback service */
645 				cb_reply_print(ndo, bp, length, opcode);
646 				break;
647 			case PROT_RX_PORT:	/* AFS PT service */
648 				prot_reply_print(ndo, bp, length, opcode);
649 				break;
650 			case VLDB_RX_PORT:	/* AFS VLDB service */
651 				vldb_reply_print(ndo, bp, length, opcode);
652 				break;
653 			case KAUTH_RX_PORT:	/* AFS Kerberos auth service */
654 				kauth_reply_print(ndo, bp, length, opcode);
655 				break;
656 			case VOL_RX_PORT:	/* AFS Volume service */
657 				vol_reply_print(ndo, bp, length, opcode);
658 				break;
659 			case BOS_RX_PORT:	/* AFS BOS service */
660 				bos_reply_print(ndo, bp, length, opcode);
661 				break;
662 			default:
663 				;
664 		}
665 
666 	/*
667 	 * If it's an RX ack packet, then use the appropriate ack decoding
668 	 * function (there isn't any service-specific information in the
669 	 * ack packet, so we can use one for all AFS services)
670 	 */
671 
672 	} else if (type == RX_PACKET_TYPE_ACK)
673 		rx_ack_print(ndo, bp, length);
674 
675 
676 	ND_PRINT(" (%u)", length);
677 }
678 
679 /*
680  * Insert an entry into the cache.  Taken from print-nfs.c
681  */
682 
683 static void
rx_cache_insert(netdissect_options * ndo,const u_char * bp,const struct ip * ip,uint16_t dport)684 rx_cache_insert(netdissect_options *ndo,
685                 const u_char *bp, const struct ip *ip, uint16_t dport)
686 {
687 	struct rx_cache_entry *rxent;
688 	const struct rx_header *rxh = (const struct rx_header *) bp;
689 
690 	if (!ND_TTEST_4(bp + sizeof(struct rx_header)))
691 		return;
692 
693 	rxent = &rx_cache[rx_cache_next];
694 
695 	if (++rx_cache_next >= RX_CACHE_SIZE)
696 		rx_cache_next = 0;
697 
698 	rxent->callnum = GET_BE_U_4(rxh->callNumber);
699 	rxent->client = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
700 	rxent->server = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
701 	rxent->dport = dport;
702 	rxent->serviceId = GET_BE_U_2(rxh->serviceId);
703 	rxent->opcode = GET_BE_U_4(bp + sizeof(struct rx_header));
704 }
705 
706 /*
707  * Lookup an entry in the cache.  Also taken from print-nfs.c
708  *
709  * Note that because this is a reply, we're looking at the _source_
710  * port.
711  */
712 
713 static int
rx_cache_find(netdissect_options * ndo,const struct rx_header * rxh,const struct ip * ip,uint16_t sport,uint32_t * opcode)714 rx_cache_find(netdissect_options *ndo, const struct rx_header *rxh,
715 	      const struct ip *ip, uint16_t sport, uint32_t *opcode)
716 {
717 	uint32_t i;
718 	struct rx_cache_entry *rxent;
719 	uint32_t clip;
720 	uint32_t sip;
721 
722 	clip = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
723 	sip = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
724 
725 	/* Start the search where we last left off */
726 
727 	i = rx_cache_hint;
728 	do {
729 		rxent = &rx_cache[i];
730 		if (rxent->callnum == GET_BE_U_4(rxh->callNumber) &&
731 		    rxent->client == clip &&
732 		    rxent->server == sip &&
733 		    rxent->serviceId == GET_BE_U_2(rxh->serviceId) &&
734 		    rxent->dport == sport) {
735 
736 			/* We got a match! */
737 
738 			rx_cache_hint = i;
739 			*opcode = rxent->opcode;
740 			return(1);
741 		}
742 		if (++i >= RX_CACHE_SIZE)
743 			i = 0;
744 	} while (i != rx_cache_hint);
745 
746 	/* Our search failed */
747 	return(0);
748 }
749 
750 /*
751  * These extremely grody macros handle the printing of various AFS stuff.
752  */
753 
754 #define FIDOUT() { uint32_t n1, n2, n3; \
755 			ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
756 			n1 = GET_BE_U_4(bp); \
757 			bp += sizeof(uint32_t); \
758 			n2 = GET_BE_U_4(bp); \
759 			bp += sizeof(uint32_t); \
760 			n3 = GET_BE_U_4(bp); \
761 			bp += sizeof(uint32_t); \
762 			ND_PRINT(" fid %u/%u/%u", n1, n2, n3); \
763 		}
764 
765 #define STROUT(MAX) { uint32_t _i; \
766 			_i = GET_BE_U_4(bp); \
767 			if (_i > (MAX)) \
768 				goto trunc; \
769 			bp += sizeof(uint32_t); \
770 			ND_PRINT(" \""); \
771 			if (nd_printn(ndo, bp, _i, ndo->ndo_snapend)) \
772 				goto trunc; \
773 			ND_PRINT("\""); \
774 			bp += ((_i + sizeof(uint32_t) - 1) / sizeof(uint32_t)) * sizeof(uint32_t); \
775 		}
776 
777 #define INTOUT() { int32_t _i; \
778 			_i = GET_BE_S_4(bp); \
779 			bp += sizeof(int32_t); \
780 			ND_PRINT(" %d", _i); \
781 		}
782 
783 #define UINTOUT() { uint32_t _i; \
784 			_i = GET_BE_U_4(bp); \
785 			bp += sizeof(uint32_t); \
786 			ND_PRINT(" %u", _i); \
787 		}
788 
789 #define UINT64OUT() { uint64_t _i; \
790 			_i = GET_BE_U_8(bp); \
791 			bp += sizeof(uint64_t); \
792 			ND_PRINT(" %" PRIu64, _i); \
793 		}
794 
795 #define DATEOUT() { time_t _t; char str[256]; \
796 			_t = (time_t) GET_BE_S_4(bp); \
797 			bp += sizeof(int32_t); \
798 			ND_PRINT(" %s", \
799 			    nd_format_time(str, sizeof(str), \
800 			      "%Y-%m-%d %H:%M:%S", localtime(&_t))); \
801 		}
802 
803 #define STOREATTROUT() { uint32_t mask, _i; \
804 			ND_TCHECK_LEN(bp, (sizeof(uint32_t) * 6)); \
805 			mask = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
806 			if (mask) ND_PRINT(" StoreStatus"); \
807 		        if (mask & 1) { ND_PRINT(" date"); DATEOUT(); } \
808 			else bp += sizeof(uint32_t); \
809 			_i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
810 		        if (mask & 2) ND_PRINT(" owner %u", _i);  \
811 			_i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
812 		        if (mask & 4) ND_PRINT(" group %u", _i); \
813 			_i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
814 		        if (mask & 8) ND_PRINT(" mode %o", _i & 07777); \
815 			_i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
816 		        if (mask & 16) ND_PRINT(" segsize %u", _i); \
817 			/* undocumented in 3.3 docu */ \
818 		        if (mask & 1024) ND_PRINT(" fsync");  \
819 		}
820 
821 #define UBIK_VERSIONOUT() {uint32_t epoch; uint32_t counter; \
822 			ND_TCHECK_LEN(bp, sizeof(uint32_t) * 2); \
823 			epoch = GET_BE_U_4(bp); \
824 			bp += sizeof(uint32_t); \
825 			counter = GET_BE_U_4(bp); \
826 			bp += sizeof(uint32_t); \
827 			ND_PRINT(" %u.%u", epoch, counter); \
828 		}
829 
830 #define AFSUUIDOUT() {uint32_t temp; int _i; \
831 			ND_TCHECK_LEN(bp, 11 * sizeof(uint32_t)); \
832 			temp = GET_BE_U_4(bp); \
833 			bp += sizeof(uint32_t); \
834 			ND_PRINT(" %08x", temp); \
835 			temp = GET_BE_U_4(bp); \
836 			bp += sizeof(uint32_t); \
837 			ND_PRINT("%04x", temp); \
838 			temp = GET_BE_U_4(bp); \
839 			bp += sizeof(uint32_t); \
840 			ND_PRINT("%04x", temp); \
841 			for (_i = 0; _i < 8; _i++) { \
842 				temp = GET_BE_U_4(bp); \
843 				bp += sizeof(uint32_t); \
844 				ND_PRINT("%02x", (unsigned char) temp); \
845 			} \
846 		}
847 
848 /*
849  * This is the sickest one of all
850  * MAX is expected to be a constant here
851  */
852 
853 #define VECOUT(MAX) { u_char *sp; \
854 			u_char s[(MAX) + 1]; \
855 			uint32_t k; \
856 			ND_TCHECK_LEN(bp, (MAX) * sizeof(uint32_t)); \
857 			sp = s; \
858 			for (k = 0; k < (MAX); k++) { \
859 				*sp++ = (u_char) GET_BE_U_4(bp); \
860 				bp += sizeof(uint32_t); \
861 			} \
862 			s[(MAX)] = '\0'; \
863 			ND_PRINT(" \""); \
864 			fn_print_str(ndo, s); \
865 			ND_PRINT("\""); \
866 		}
867 
868 #define DESTSERVEROUT() { uint32_t n1, n2, n3; \
869 			ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
870 			n1 = GET_BE_U_4(bp); \
871 			bp += sizeof(uint32_t); \
872 			n2 = GET_BE_U_4(bp); \
873 			bp += sizeof(uint32_t); \
874 			n3 = GET_BE_U_4(bp); \
875 			bp += sizeof(uint32_t); \
876 			ND_PRINT(" server %u:%u:%u", n1, n2, n3); \
877 		}
878 
879 /*
880  * Handle calls to the AFS file service (fs)
881  */
882 
883 static void
fs_print(netdissect_options * ndo,const u_char * bp,u_int length)884 fs_print(netdissect_options *ndo,
885          const u_char *bp, u_int length)
886 {
887 	uint32_t fs_op;
888 	uint32_t i;
889 
890 	if (length <= sizeof(struct rx_header))
891 		return;
892 
893 	/*
894 	 * Print out the afs call we're invoking.  The table used here was
895 	 * gleaned from fsint/afsint.xg
896 	 */
897 
898 	fs_op = GET_BE_U_4(bp + sizeof(struct rx_header));
899 
900 	ND_PRINT(" fs call %s", tok2str(fs_req, "op#%u", fs_op));
901 
902 	/*
903 	 * Print out arguments to some of the AFS calls.  This stuff is
904 	 * all from afsint.xg
905 	 */
906 
907 	bp += sizeof(struct rx_header) + 4;
908 
909 	/*
910 	 * Sigh.  This is gross.  Ritchie forgive me.
911 	 */
912 
913 	switch (fs_op) {
914 		case 130:	/* Fetch data */
915 			FIDOUT();
916 			ND_PRINT(" offset");
917 			UINTOUT();
918 			ND_PRINT(" length");
919 			UINTOUT();
920 			break;
921 		case 131:	/* Fetch ACL */
922 		case 132:	/* Fetch Status */
923 		case 143:	/* Old set lock */
924 		case 144:	/* Old extend lock */
925 		case 145:	/* Old release lock */
926 		case 156:	/* Set lock */
927 		case 157:	/* Extend lock */
928 		case 158:	/* Release lock */
929 			FIDOUT();
930 			break;
931 		case 135:	/* Store status */
932 			FIDOUT();
933 			STOREATTROUT();
934 			break;
935 		case 133:	/* Store data */
936 			FIDOUT();
937 			STOREATTROUT();
938 			ND_PRINT(" offset");
939 			UINTOUT();
940 			ND_PRINT(" length");
941 			UINTOUT();
942 			ND_PRINT(" flen");
943 			UINTOUT();
944 			break;
945 		case 134:	/* Store ACL */
946 		{
947 			char a[AFSOPAQUEMAX+1];
948 			FIDOUT();
949 			i = GET_BE_U_4(bp);
950 			bp += sizeof(uint32_t);
951 			ND_TCHECK_LEN(bp, i);
952 			i = ND_MIN(AFSOPAQUEMAX, i);
953 			strncpy(a, (const char *) bp, i);
954 			a[i] = '\0';
955 			acl_print(ndo, (u_char *) a, (u_char *) a + i);
956 			break;
957 		}
958 		case 137:	/* Create file */
959 		case 141:	/* MakeDir */
960 			FIDOUT();
961 			STROUT(AFSNAMEMAX);
962 			STOREATTROUT();
963 			break;
964 		case 136:	/* Remove file */
965 		case 142:	/* Remove directory */
966 			FIDOUT();
967 			STROUT(AFSNAMEMAX);
968 			break;
969 		case 138:	/* Rename file */
970 			ND_PRINT(" old");
971 			FIDOUT();
972 			STROUT(AFSNAMEMAX);
973 			ND_PRINT(" new");
974 			FIDOUT();
975 			STROUT(AFSNAMEMAX);
976 			break;
977 		case 139:	/* Symlink */
978 			FIDOUT();
979 			STROUT(AFSNAMEMAX);
980 			ND_PRINT(" link to");
981 			STROUT(AFSNAMEMAX);
982 			break;
983 		case 140:	/* Link */
984 			FIDOUT();
985 			STROUT(AFSNAMEMAX);
986 			ND_PRINT(" link to");
987 			FIDOUT();
988 			break;
989 		case 148:	/* Get volume info */
990 			STROUT(AFSNAMEMAX);
991 			break;
992 		case 149:	/* Get volume stats */
993 		case 150:	/* Set volume stats */
994 			ND_PRINT(" volid");
995 			UINTOUT();
996 			break;
997 		case 154:	/* New get volume info */
998 			ND_PRINT(" volname");
999 			STROUT(AFSNAMEMAX);
1000 			break;
1001 		case 155:	/* Bulk stat */
1002 		case 65536:     /* Inline bulk stat */
1003 		{
1004 			uint32_t j;
1005 			j = GET_BE_U_4(bp);
1006 			bp += sizeof(uint32_t);
1007 
1008 			for (i = 0; i < j; i++) {
1009 				FIDOUT();
1010 				if (i != j - 1)
1011 					ND_PRINT(",");
1012 			}
1013 			if (j == 0)
1014 				ND_PRINT(" <none!>");
1015 			break;
1016 		}
1017 		case 65537:	/* Fetch data 64 */
1018 			FIDOUT();
1019 			ND_PRINT(" offset");
1020 			UINT64OUT();
1021 			ND_PRINT(" length");
1022 			UINT64OUT();
1023 			break;
1024 		case 65538:	/* Store data 64 */
1025 			FIDOUT();
1026 			STOREATTROUT();
1027 			ND_PRINT(" offset");
1028 			UINT64OUT();
1029 			ND_PRINT(" length");
1030 			UINT64OUT();
1031 			ND_PRINT(" flen");
1032 			UINT64OUT();
1033 			break;
1034 		case 65541:    /* CallBack rx conn address */
1035 			ND_PRINT(" addr");
1036 			UINTOUT();
1037 		default:
1038 			;
1039 	}
1040 
1041 	return;
1042 
1043 trunc:
1044 	ND_PRINT(" [|fs]");
1045 }
1046 
1047 /*
1048  * Handle replies to the AFS file service
1049  */
1050 
1051 static void
fs_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1052 fs_reply_print(netdissect_options *ndo,
1053                const u_char *bp, u_int length, uint32_t opcode)
1054 {
1055 	uint32_t i;
1056 	const struct rx_header *rxh;
1057 	uint8_t type;
1058 
1059 	if (length <= sizeof(struct rx_header))
1060 		return;
1061 
1062 	rxh = (const struct rx_header *) bp;
1063 
1064 	/*
1065 	 * Print out the afs call we're invoking.  The table used here was
1066 	 * gleaned from fsint/afsint.xg
1067 	 */
1068 
1069 	ND_PRINT(" fs reply %s", tok2str(fs_req, "op#%u", opcode));
1070 
1071 	type = GET_U_1(rxh->type);
1072 	bp += sizeof(struct rx_header);
1073 
1074 	/*
1075 	 * If it was a data packet, interpret the response
1076 	 */
1077 
1078 	if (type == RX_PACKET_TYPE_DATA) {
1079 		switch (opcode) {
1080 		case 131:	/* Fetch ACL */
1081 		{
1082 			char a[AFSOPAQUEMAX+1];
1083 			i = GET_BE_U_4(bp);
1084 			bp += sizeof(uint32_t);
1085 			ND_TCHECK_LEN(bp, i);
1086 			i = ND_MIN(AFSOPAQUEMAX, i);
1087 			strncpy(a, (const char *) bp, i);
1088 			a[i] = '\0';
1089 			acl_print(ndo, (u_char *) a, (u_char *) a + i);
1090 			break;
1091 		}
1092 		case 137:	/* Create file */
1093 		case 141:	/* MakeDir */
1094 			ND_PRINT(" new");
1095 			FIDOUT();
1096 			break;
1097 		case 151:	/* Get root volume */
1098 			ND_PRINT(" root volume");
1099 			STROUT(AFSNAMEMAX);
1100 			break;
1101 		case 153:	/* Get time */
1102 			DATEOUT();
1103 			break;
1104 		default:
1105 			;
1106 		}
1107 	} else if (type == RX_PACKET_TYPE_ABORT) {
1108 		/*
1109 		 * Otherwise, just print out the return code
1110 		 */
1111 		int32_t errcode;
1112 
1113 		errcode = GET_BE_S_4(bp);
1114 		bp += sizeof(int32_t);
1115 
1116 		ND_PRINT(" error %s", tok2str(afs_fs_errors, "#%d", errcode));
1117 	} else {
1118 		ND_PRINT(" strange fs reply of type %u", type);
1119 	}
1120 
1121 	return;
1122 
1123 trunc:
1124 	ND_PRINT(" [|fs]");
1125 }
1126 
1127 /*
1128  * Print out an AFS ACL string.  An AFS ACL is a string that has the
1129  * following format:
1130  *
1131  * <positive> <negative>
1132  * <uid1> <aclbits1>
1133  * ....
1134  *
1135  * "positive" and "negative" are integers which contain the number of
1136  * positive and negative ACL's in the string.  The uid/aclbits pair are
1137  * ASCII strings containing the UID/PTS record and an ASCII number
1138  * representing a logical OR of all the ACL permission bits
1139  */
1140 
1141 #define XSTRINGIFY(x) #x
1142 #define NUMSTRINGIFY(x)	XSTRINGIFY(x)
1143 
1144 static void
acl_print(netdissect_options * ndo,u_char * s,const u_char * end)1145 acl_print(netdissect_options *ndo,
1146           u_char *s, const u_char *end)
1147 {
1148 	int pos, neg, acl;
1149 	int n, i;
1150 	char user[USERNAMEMAX+1];
1151 
1152 	if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
1153 		return;
1154 
1155 	s += n;
1156 
1157 	if (s > end)
1158 		return;
1159 
1160 	/*
1161 	 * This wacky order preserves the order used by the "fs" command
1162 	 */
1163 
1164 #define ACLOUT(acl) \
1165 	ND_PRINT("%s%s%s%s%s%s%s", \
1166 	          acl & PRSFS_READ       ? "r" : "", \
1167 	          acl & PRSFS_LOOKUP     ? "l" : "", \
1168 	          acl & PRSFS_INSERT     ? "i" : "", \
1169 	          acl & PRSFS_DELETE     ? "d" : "", \
1170 	          acl & PRSFS_WRITE      ? "w" : "", \
1171 	          acl & PRSFS_LOCK       ? "k" : "", \
1172 	          acl & PRSFS_ADMINISTER ? "a" : "");
1173 
1174 	for (i = 0; i < pos; i++) {
1175 		if (sscanf((char *) s, "%" NUMSTRINGIFY(USERNAMEMAX) "s %d\n%n", user, &acl, &n) != 2)
1176 			return;
1177 		s += n;
1178 		ND_PRINT(" +{");
1179 		fn_print_str(ndo, (u_char *)user);
1180 		ND_PRINT(" ");
1181 		ACLOUT(acl);
1182 		ND_PRINT("}");
1183 		if (s > end)
1184 			return;
1185 	}
1186 
1187 	for (i = 0; i < neg; i++) {
1188 		if (sscanf((char *) s, "%" NUMSTRINGIFY(USERNAMEMAX) "s %d\n%n", user, &acl, &n) != 2)
1189 			return;
1190 		s += n;
1191 		ND_PRINT(" -{");
1192 		fn_print_str(ndo, (u_char *)user);
1193 		ND_PRINT(" ");
1194 		ACLOUT(acl);
1195 		ND_PRINT("}");
1196 		if (s > end)
1197 			return;
1198 	}
1199 }
1200 
1201 #undef ACLOUT
1202 
1203 /*
1204  * Handle calls to the AFS callback service
1205  */
1206 
1207 static void
cb_print(netdissect_options * ndo,const u_char * bp,u_int length)1208 cb_print(netdissect_options *ndo,
1209          const u_char *bp, u_int length)
1210 {
1211 	uint32_t cb_op;
1212 	uint32_t i;
1213 
1214 	if (length <= sizeof(struct rx_header))
1215 		return;
1216 
1217 	/*
1218 	 * Print out the afs call we're invoking.  The table used here was
1219 	 * gleaned from fsint/afscbint.xg
1220 	 */
1221 
1222 	cb_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1223 
1224 	ND_PRINT(" cb call %s", tok2str(cb_req, "op#%u", cb_op));
1225 
1226 	bp += sizeof(struct rx_header) + 4;
1227 
1228 	/*
1229 	 * Print out the afs call we're invoking.  The table used here was
1230 	 * gleaned from fsint/afscbint.xg
1231 	 */
1232 
1233 	switch (cb_op) {
1234 		case 204:		/* Callback */
1235 		{
1236 			uint32_t j, t;
1237 			j = GET_BE_U_4(bp);
1238 			bp += sizeof(uint32_t);
1239 
1240 			for (i = 0; i < j; i++) {
1241 				FIDOUT();
1242 				if (i != j - 1)
1243 					ND_PRINT(",");
1244 			}
1245 
1246 			if (j == 0)
1247 				ND_PRINT(" <none!>");
1248 
1249 			j = GET_BE_U_4(bp);
1250 			bp += sizeof(uint32_t);
1251 
1252 			if (j != 0)
1253 				ND_PRINT(";");
1254 
1255 			for (i = 0; i < j; i++) {
1256 				ND_PRINT(" ver");
1257 				INTOUT();
1258 				ND_PRINT(" expires");
1259 				DATEOUT();
1260 				t = GET_BE_U_4(bp);
1261 				bp += sizeof(uint32_t);
1262 				tok2str(cb_types, "type %u", t);
1263 			}
1264 			break;
1265 		}
1266 		case 214: {
1267 			ND_PRINT(" afsuuid");
1268 			AFSUUIDOUT();
1269 			break;
1270 		}
1271 		default:
1272 			;
1273 	}
1274 
1275 	return;
1276 
1277 trunc:
1278 	ND_PRINT(" [|cb]");
1279 }
1280 
1281 /*
1282  * Handle replies to the AFS Callback Service
1283  */
1284 
1285 static void
cb_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1286 cb_reply_print(netdissect_options *ndo,
1287                const u_char *bp, u_int length, uint32_t opcode)
1288 {
1289 	const struct rx_header *rxh;
1290 	uint8_t type;
1291 
1292 	if (length <= sizeof(struct rx_header))
1293 		return;
1294 
1295 	rxh = (const struct rx_header *) bp;
1296 
1297 	/*
1298 	 * Print out the afs call we're invoking.  The table used here was
1299 	 * gleaned from fsint/afscbint.xg
1300 	 */
1301 
1302 	ND_PRINT(" cb reply %s", tok2str(cb_req, "op#%u", opcode));
1303 
1304 	type = GET_U_1(rxh->type);
1305 	bp += sizeof(struct rx_header);
1306 
1307 	/*
1308 	 * If it was a data packet, interpret the response.
1309 	 */
1310 
1311 	if (type == RX_PACKET_TYPE_DATA)
1312 		switch (opcode) {
1313 		case 213:	/* InitCallBackState3 */
1314 			AFSUUIDOUT();
1315 			break;
1316 		default:
1317 		;
1318 		}
1319 	else {
1320 		/*
1321 		 * Otherwise, just print out the return code
1322 		 */
1323 		ND_PRINT(" errcode");
1324 		INTOUT();
1325 	}
1326 
1327 	return;
1328 
1329 trunc:
1330 	ND_PRINT(" [|cb]");
1331 }
1332 
1333 /*
1334  * Handle calls to the AFS protection database server
1335  */
1336 
1337 static void
prot_print(netdissect_options * ndo,const u_char * bp,u_int length)1338 prot_print(netdissect_options *ndo,
1339            const u_char *bp, u_int length)
1340 {
1341 	uint32_t i;
1342 	uint32_t pt_op;
1343 
1344 	if (length <= sizeof(struct rx_header))
1345 		return;
1346 
1347 	/*
1348 	 * Print out the afs call we're invoking.  The table used here was
1349 	 * gleaned from ptserver/ptint.xg
1350 	 */
1351 
1352 	pt_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1353 
1354 	ND_PRINT(" pt");
1355 
1356 	if (is_ubik(pt_op)) {
1357 		ubik_print(ndo, bp);
1358 		return;
1359 	}
1360 
1361 	ND_PRINT(" call %s", tok2str(pt_req, "op#%u", pt_op));
1362 
1363 	/*
1364 	 * Decode some of the arguments to the PT calls
1365 	 */
1366 
1367 	bp += sizeof(struct rx_header) + 4;
1368 
1369 	switch (pt_op) {
1370 		case 500:	/* I New User */
1371 			STROUT(PRNAMEMAX);
1372 			ND_PRINT(" id");
1373 			INTOUT();
1374 			ND_PRINT(" oldid");
1375 			INTOUT();
1376 			break;
1377 		case 501:	/* Where is it */
1378 		case 506:	/* Delete */
1379 		case 508:	/* Get CPS */
1380 		case 512:	/* List entry */
1381 		case 514:	/* List elements */
1382 		case 517:	/* List owned */
1383 		case 518:	/* Get CPS2 */
1384 		case 519:	/* Get host CPS */
1385 		case 530:	/* List super groups */
1386 			ND_PRINT(" id");
1387 			INTOUT();
1388 			break;
1389 		case 502:	/* Dump entry */
1390 			ND_PRINT(" pos");
1391 			INTOUT();
1392 			break;
1393 		case 503:	/* Add to group */
1394 		case 507:	/* Remove from group */
1395 		case 515:	/* Is a member of? */
1396 			ND_PRINT(" uid");
1397 			INTOUT();
1398 			ND_PRINT(" gid");
1399 			INTOUT();
1400 			break;
1401 		case 504:	/* Name to ID */
1402 		{
1403 			uint32_t j;
1404 			j = GET_BE_U_4(bp);
1405 			bp += sizeof(uint32_t);
1406 
1407 			/*
1408 			 * Who designed this chicken-shit protocol?
1409 			 *
1410 			 * Each character is stored as a 32-bit
1411 			 * integer!
1412 			 */
1413 
1414 			for (i = 0; i < j; i++) {
1415 				VECOUT(PRNAMEMAX);
1416 			}
1417 			if (j == 0)
1418 				ND_PRINT(" <none!>");
1419 		}
1420 			break;
1421 		case 505:	/* Id to name */
1422 		{
1423 			uint32_t j;
1424 			ND_PRINT(" ids:");
1425 			i = GET_BE_U_4(bp);
1426 			bp += sizeof(uint32_t);
1427 			for (j = 0; j < i; j++)
1428 				INTOUT();
1429 			if (j == 0)
1430 				ND_PRINT(" <none!>");
1431 		}
1432 			break;
1433 		case 509:	/* New entry */
1434 			STROUT(PRNAMEMAX);
1435 			ND_PRINT(" flag");
1436 			INTOUT();
1437 			ND_PRINT(" oid");
1438 			INTOUT();
1439 			break;
1440 		case 511:	/* Set max */
1441 			ND_PRINT(" id");
1442 			INTOUT();
1443 			ND_PRINT(" gflag");
1444 			INTOUT();
1445 			break;
1446 		case 513:	/* Change entry */
1447 			ND_PRINT(" id");
1448 			INTOUT();
1449 			STROUT(PRNAMEMAX);
1450 			ND_PRINT(" oldid");
1451 			INTOUT();
1452 			ND_PRINT(" newid");
1453 			INTOUT();
1454 			break;
1455 		case 520:	/* Update entry */
1456 			ND_PRINT(" id");
1457 			INTOUT();
1458 			STROUT(PRNAMEMAX);
1459 			break;
1460 		default:
1461 			;
1462 	}
1463 
1464 
1465 	return;
1466 
1467 trunc:
1468 	ND_PRINT(" [|pt]");
1469 }
1470 
1471 /*
1472  * Handle replies to the AFS protection service
1473  */
1474 
1475 static void
prot_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1476 prot_reply_print(netdissect_options *ndo,
1477                  const u_char *bp, u_int length, uint32_t opcode)
1478 {
1479 	const struct rx_header *rxh;
1480 	uint8_t type;
1481 	uint32_t i;
1482 
1483 	if (length < sizeof(struct rx_header))
1484 		return;
1485 
1486 	rxh = (const struct rx_header *) bp;
1487 
1488 	/*
1489 	 * Print out the afs call we're invoking.  The table used here was
1490 	 * gleaned from ptserver/ptint.xg.  Check to see if it's a
1491 	 * Ubik call, however.
1492 	 */
1493 
1494 	ND_PRINT(" pt");
1495 
1496 	if (is_ubik(opcode)) {
1497 		ubik_reply_print(ndo, bp, length, opcode);
1498 		return;
1499 	}
1500 
1501 	ND_PRINT(" reply %s", tok2str(pt_req, "op#%u", opcode));
1502 
1503 	type = GET_U_1(rxh->type);
1504 	bp += sizeof(struct rx_header);
1505 
1506 	/*
1507 	 * If it was a data packet, interpret the response
1508 	 */
1509 
1510 	if (type == RX_PACKET_TYPE_DATA)
1511 		switch (opcode) {
1512 		case 504:		/* Name to ID */
1513 		{
1514 			uint32_t j;
1515 			ND_PRINT(" ids:");
1516 			i = GET_BE_U_4(bp);
1517 			bp += sizeof(uint32_t);
1518 			for (j = 0; j < i; j++)
1519 				INTOUT();
1520 			if (j == 0)
1521 				ND_PRINT(" <none!>");
1522 		}
1523 			break;
1524 		case 505:		/* ID to name */
1525 		{
1526 			uint32_t j;
1527 			j = GET_BE_U_4(bp);
1528 			bp += sizeof(uint32_t);
1529 
1530 			/*
1531 			 * Who designed this chicken-shit protocol?
1532 			 *
1533 			 * Each character is stored as a 32-bit
1534 			 * integer!
1535 			 */
1536 
1537 			for (i = 0; i < j; i++) {
1538 				VECOUT(PRNAMEMAX);
1539 			}
1540 			if (j == 0)
1541 				ND_PRINT(" <none!>");
1542 		}
1543 			break;
1544 		case 508:		/* Get CPS */
1545 		case 514:		/* List elements */
1546 		case 517:		/* List owned */
1547 		case 518:		/* Get CPS2 */
1548 		case 519:		/* Get host CPS */
1549 		{
1550 			uint32_t j;
1551 			j = GET_BE_U_4(bp);
1552 			bp += sizeof(uint32_t);
1553 			for (i = 0; i < j; i++) {
1554 				INTOUT();
1555 			}
1556 			if (j == 0)
1557 				ND_PRINT(" <none!>");
1558 		}
1559 			break;
1560 		case 510:		/* List max */
1561 			ND_PRINT(" maxuid");
1562 			INTOUT();
1563 			ND_PRINT(" maxgid");
1564 			INTOUT();
1565 			break;
1566 		default:
1567 			;
1568 		}
1569 	else {
1570 		/*
1571 		 * Otherwise, just print out the return code
1572 		 */
1573 		ND_PRINT(" errcode");
1574 		INTOUT();
1575 	}
1576 
1577 	return;
1578 
1579 trunc:
1580 	ND_PRINT(" [|pt]");
1581 }
1582 
1583 /*
1584  * Handle calls to the AFS volume location database service
1585  */
1586 
1587 static void
vldb_print(netdissect_options * ndo,const u_char * bp,u_int length)1588 vldb_print(netdissect_options *ndo,
1589            const u_char *bp, u_int length)
1590 {
1591 	uint32_t vldb_op;
1592 	uint32_t i;
1593 
1594 	if (length <= sizeof(struct rx_header))
1595 		return;
1596 
1597 	/*
1598 	 * Print out the afs call we're invoking.  The table used here was
1599 	 * gleaned from vlserver/vldbint.xg
1600 	 */
1601 
1602 	vldb_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1603 
1604 	ND_PRINT(" vldb");
1605 
1606 	if (is_ubik(vldb_op)) {
1607 		ubik_print(ndo, bp);
1608 		return;
1609 	}
1610 	ND_PRINT(" call %s", tok2str(vldb_req, "op#%u", vldb_op));
1611 
1612 	/*
1613 	 * Decode some of the arguments to the VLDB calls
1614 	 */
1615 
1616 	bp += sizeof(struct rx_header) + 4;
1617 
1618 	switch (vldb_op) {
1619 		case 501:	/* Create new volume */
1620 		case 517:	/* Create entry N */
1621 			VECOUT(VLNAMEMAX);
1622 			break;
1623 		case 502:	/* Delete entry */
1624 		case 503:	/* Get entry by ID */
1625 		case 507:	/* Update entry */
1626 		case 508:	/* Set lock */
1627 		case 509:	/* Release lock */
1628 		case 518:	/* Get entry by ID N */
1629 			ND_PRINT(" volid");
1630 			INTOUT();
1631 			i = GET_BE_U_4(bp);
1632 			bp += sizeof(uint32_t);
1633 			if (i <= 2)
1634 				ND_PRINT(" type %s", voltype[i]);
1635 			break;
1636 		case 504:	/* Get entry by name */
1637 		case 519:	/* Get entry by name N */
1638 		case 524:	/* Update entry by name */
1639 		case 527:	/* Get entry by name U */
1640 			STROUT(VLNAMEMAX);
1641 			break;
1642 		case 505:	/* Get new vol id */
1643 			ND_PRINT(" bump");
1644 			INTOUT();
1645 			break;
1646 		case 506:	/* Replace entry */
1647 		case 520:	/* Replace entry N */
1648 			ND_PRINT(" volid");
1649 			INTOUT();
1650 			i = GET_BE_U_4(bp);
1651 			bp += sizeof(uint32_t);
1652 			if (i <= 2)
1653 				ND_PRINT(" type %s", voltype[i]);
1654 			VECOUT(VLNAMEMAX);
1655 			break;
1656 		case 510:	/* List entry */
1657 		case 521:	/* List entry N */
1658 			ND_PRINT(" index");
1659 			INTOUT();
1660 			break;
1661 		default:
1662 			;
1663 	}
1664 
1665 	return;
1666 
1667 trunc:
1668 	ND_PRINT(" [|vldb]");
1669 }
1670 
1671 /*
1672  * Handle replies to the AFS volume location database service
1673  */
1674 
1675 static void
vldb_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1676 vldb_reply_print(netdissect_options *ndo,
1677                  const u_char *bp, u_int length, uint32_t opcode)
1678 {
1679 	const struct rx_header *rxh;
1680 	uint8_t type;
1681 	uint32_t i;
1682 
1683 	if (length < sizeof(struct rx_header))
1684 		return;
1685 
1686 	rxh = (const struct rx_header *) bp;
1687 
1688 	/*
1689 	 * Print out the afs call we're invoking.  The table used here was
1690 	 * gleaned from vlserver/vldbint.xg.  Check to see if it's a
1691 	 * Ubik call, however.
1692 	 */
1693 
1694 	ND_PRINT(" vldb");
1695 
1696 	if (is_ubik(opcode)) {
1697 		ubik_reply_print(ndo, bp, length, opcode);
1698 		return;
1699 	}
1700 
1701 	ND_PRINT(" reply %s", tok2str(vldb_req, "op#%u", opcode));
1702 
1703 	type = GET_U_1(rxh->type);
1704 	bp += sizeof(struct rx_header);
1705 
1706 	/*
1707 	 * If it was a data packet, interpret the response
1708 	 */
1709 
1710 	if (type == RX_PACKET_TYPE_DATA)
1711 		switch (opcode) {
1712 		case 510:	/* List entry */
1713 			ND_PRINT(" count");
1714 			INTOUT();
1715 			ND_PRINT(" nextindex");
1716 			INTOUT();
1717 			ND_FALL_THROUGH;
1718 		case 503:	/* Get entry by id */
1719 		case 504:	/* Get entry by name */
1720 		{	uint32_t nservers, j;
1721 			VECOUT(VLNAMEMAX);
1722 			ND_TCHECK_4(bp);
1723 			bp += sizeof(uint32_t);
1724 			ND_PRINT(" numservers");
1725 			nservers = GET_BE_U_4(bp);
1726 			bp += sizeof(uint32_t);
1727 			ND_PRINT(" %u", nservers);
1728 			ND_PRINT(" servers");
1729 			for (i = 0; i < 8; i++) {
1730 				ND_TCHECK_4(bp);
1731 				if (i < nservers)
1732 					ND_PRINT(" %s",
1733 					   intoa(GET_IPV4_TO_NETWORK_ORDER(bp)));
1734 				bp += sizeof(nd_ipv4);
1735 			}
1736 			ND_PRINT(" partitions");
1737 			for (i = 0; i < 8; i++) {
1738 				j = GET_BE_U_4(bp);
1739 				if (i < nservers && j <= 26)
1740 					ND_PRINT(" %c", 'a' + j);
1741 				else if (i < nservers)
1742 					ND_PRINT(" %u", j);
1743 				bp += sizeof(uint32_t);
1744 			}
1745 			ND_TCHECK_LEN(bp, 8 * sizeof(uint32_t));
1746 			bp += 8 * sizeof(uint32_t);
1747 			ND_PRINT(" rwvol");
1748 			UINTOUT();
1749 			ND_PRINT(" rovol");
1750 			UINTOUT();
1751 			ND_PRINT(" backup");
1752 			UINTOUT();
1753 		}
1754 			break;
1755 		case 505:	/* Get new volume ID */
1756 			ND_PRINT(" newvol");
1757 			UINTOUT();
1758 			break;
1759 		case 521:	/* List entry */
1760 		case 529:	/* List entry U */
1761 			ND_PRINT(" count");
1762 			INTOUT();
1763 			ND_PRINT(" nextindex");
1764 			INTOUT();
1765 			ND_FALL_THROUGH;
1766 		case 518:	/* Get entry by ID N */
1767 		case 519:	/* Get entry by name N */
1768 		{	uint32_t nservers, j;
1769 			VECOUT(VLNAMEMAX);
1770 			ND_PRINT(" numservers");
1771 			nservers = GET_BE_U_4(bp);
1772 			bp += sizeof(uint32_t);
1773 			ND_PRINT(" %u", nservers);
1774 			ND_PRINT(" servers");
1775 			for (i = 0; i < 13; i++) {
1776 				ND_TCHECK_4(bp);
1777 				if (i < nservers)
1778 					ND_PRINT(" %s",
1779 					   intoa(GET_IPV4_TO_NETWORK_ORDER(bp)));
1780 				bp += sizeof(nd_ipv4);
1781 			}
1782 			ND_PRINT(" partitions");
1783 			for (i = 0; i < 13; i++) {
1784 				j = GET_BE_U_4(bp);
1785 				if (i < nservers && j <= 26)
1786 					ND_PRINT(" %c", 'a' + j);
1787 				else if (i < nservers)
1788 					ND_PRINT(" %u", j);
1789 				bp += sizeof(uint32_t);
1790 			}
1791 			ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
1792 			bp += 13 * sizeof(uint32_t);
1793 			ND_PRINT(" rwvol");
1794 			UINTOUT();
1795 			ND_PRINT(" rovol");
1796 			UINTOUT();
1797 			ND_PRINT(" backup");
1798 			UINTOUT();
1799 		}
1800 			break;
1801 		case 526:	/* Get entry by ID U */
1802 		case 527:	/* Get entry by name U */
1803 		{	uint32_t nservers, j;
1804 			VECOUT(VLNAMEMAX);
1805 			ND_PRINT(" numservers");
1806 			nservers = GET_BE_U_4(bp);
1807 			bp += sizeof(uint32_t);
1808 			ND_PRINT(" %u", nservers);
1809 			ND_PRINT(" servers");
1810 			for (i = 0; i < 13; i++) {
1811 				if (i < nservers) {
1812 					ND_PRINT(" afsuuid");
1813 					AFSUUIDOUT();
1814 				} else {
1815 					ND_TCHECK_LEN(bp, 44);
1816 					bp += 44;
1817 				}
1818 			}
1819 			ND_TCHECK_LEN(bp, 4 * 13);
1820 			bp += 4 * 13;
1821 			ND_PRINT(" partitions");
1822 			for (i = 0; i < 13; i++) {
1823 				j = GET_BE_U_4(bp);
1824 				if (i < nservers && j <= 26)
1825 					ND_PRINT(" %c", 'a' + j);
1826 				else if (i < nservers)
1827 					ND_PRINT(" %u", j);
1828 				bp += sizeof(uint32_t);
1829 			}
1830 			ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
1831 			bp += 13 * sizeof(uint32_t);
1832 			ND_PRINT(" rwvol");
1833 			UINTOUT();
1834 			ND_PRINT(" rovol");
1835 			UINTOUT();
1836 			ND_PRINT(" backup");
1837 			UINTOUT();
1838 		}
1839 		default:
1840 			;
1841 		}
1842 
1843 	else {
1844 		/*
1845 		 * Otherwise, just print out the return code
1846 		 */
1847 		ND_PRINT(" errcode");
1848 		INTOUT();
1849 	}
1850 
1851 	return;
1852 
1853 trunc:
1854 	ND_PRINT(" [|vldb]");
1855 }
1856 
1857 /*
1858  * Handle calls to the AFS Kerberos Authentication service
1859  */
1860 
1861 static void
kauth_print(netdissect_options * ndo,const u_char * bp,u_int length)1862 kauth_print(netdissect_options *ndo,
1863             const u_char *bp, u_int length)
1864 {
1865 	uint32_t kauth_op;
1866 
1867 	if (length <= sizeof(struct rx_header))
1868 		return;
1869 
1870 	/*
1871 	 * Print out the afs call we're invoking.  The table used here was
1872 	 * gleaned from kauth/kauth.rg
1873 	 */
1874 
1875 	kauth_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1876 
1877 	ND_PRINT(" kauth");
1878 
1879 	if (is_ubik(kauth_op)) {
1880 		ubik_print(ndo, bp);
1881 		return;
1882 	}
1883 
1884 
1885 	ND_PRINT(" call %s", tok2str(kauth_req, "op#%u", kauth_op));
1886 
1887 	/*
1888 	 * Decode some of the arguments to the KA calls
1889 	 */
1890 
1891 	bp += sizeof(struct rx_header) + 4;
1892 
1893 	switch (kauth_op) {
1894 		case 1:		/* Authenticate old */
1895 		case 21:	/* Authenticate */
1896 		case 22:	/* Authenticate-V2 */
1897 		case 2:		/* Change PW */
1898 		case 5:		/* Set fields */
1899 		case 6:		/* Create user */
1900 		case 7:		/* Delete user */
1901 		case 8:		/* Get entry */
1902 		case 14:	/* Unlock */
1903 		case 15:	/* Lock status */
1904 			ND_PRINT(" principal");
1905 			STROUT(KANAMEMAX);
1906 			STROUT(KANAMEMAX);
1907 			break;
1908 		case 3:		/* GetTicket-old */
1909 		case 23:	/* GetTicket */
1910 		{
1911 			uint32_t i;
1912 			ND_PRINT(" kvno");
1913 			INTOUT();
1914 			ND_PRINT(" domain");
1915 			STROUT(KANAMEMAX);
1916 			i = GET_BE_U_4(bp);
1917 			bp += sizeof(uint32_t);
1918 			ND_TCHECK_LEN(bp, i);
1919 			bp += i;
1920 			ND_PRINT(" principal");
1921 			STROUT(KANAMEMAX);
1922 			STROUT(KANAMEMAX);
1923 			break;
1924 		}
1925 		case 4:		/* Set Password */
1926 			ND_PRINT(" principal");
1927 			STROUT(KANAMEMAX);
1928 			STROUT(KANAMEMAX);
1929 			ND_PRINT(" kvno");
1930 			INTOUT();
1931 			break;
1932 		case 12:	/* Get password */
1933 			ND_PRINT(" name");
1934 			STROUT(KANAMEMAX);
1935 			break;
1936 		default:
1937 			;
1938 	}
1939 
1940 	return;
1941 
1942 trunc:
1943 	ND_PRINT(" [|kauth]");
1944 }
1945 
1946 /*
1947  * Handle replies to the AFS Kerberos Authentication Service
1948  */
1949 
1950 static void
kauth_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1951 kauth_reply_print(netdissect_options *ndo,
1952                   const u_char *bp, u_int length, uint32_t opcode)
1953 {
1954 	const struct rx_header *rxh;
1955 	uint8_t type;
1956 
1957 	if (length <= sizeof(struct rx_header))
1958 		return;
1959 
1960 	rxh = (const struct rx_header *) bp;
1961 
1962 	/*
1963 	 * Print out the afs call we're invoking.  The table used here was
1964 	 * gleaned from kauth/kauth.rg
1965 	 */
1966 
1967 	ND_PRINT(" kauth");
1968 
1969 	if (is_ubik(opcode)) {
1970 		ubik_reply_print(ndo, bp, length, opcode);
1971 		return;
1972 	}
1973 
1974 	ND_PRINT(" reply %s", tok2str(kauth_req, "op#%u", opcode));
1975 
1976 	type = GET_U_1(rxh->type);
1977 	bp += sizeof(struct rx_header);
1978 
1979 	/*
1980 	 * If it was a data packet, interpret the response.
1981 	 */
1982 
1983 	if (type == RX_PACKET_TYPE_DATA)
1984 		/* Well, no, not really.  Leave this for later */
1985 		;
1986 	else {
1987 		/*
1988 		 * Otherwise, just print out the return code
1989 		 */
1990 		ND_PRINT(" errcode");
1991 		INTOUT();
1992 	}
1993 }
1994 
1995 /*
1996  * Handle calls to the AFS Volume location service
1997  */
1998 
1999 static void
vol_print(netdissect_options * ndo,const u_char * bp,u_int length)2000 vol_print(netdissect_options *ndo,
2001           const u_char *bp, u_int length)
2002 {
2003 	uint32_t vol_op;
2004 
2005 	if (length <= sizeof(struct rx_header))
2006 		return;
2007 
2008 	/*
2009 	 * Print out the afs call we're invoking.  The table used here was
2010 	 * gleaned from volser/volint.xg
2011 	 */
2012 
2013 	vol_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2014 
2015 	ND_PRINT(" vol call %s", tok2str(vol_req, "op#%u", vol_op));
2016 
2017 	bp += sizeof(struct rx_header) + 4;
2018 
2019 	switch (vol_op) {
2020 		case 100:	/* Create volume */
2021 			ND_PRINT(" partition");
2022 			UINTOUT();
2023 			ND_PRINT(" name");
2024 			STROUT(AFSNAMEMAX);
2025 			ND_PRINT(" type");
2026 			UINTOUT();
2027 			ND_PRINT(" parent");
2028 			UINTOUT();
2029 			break;
2030 		case 101:	/* Delete volume */
2031 		case 107:	/* Get flags */
2032 			ND_PRINT(" trans");
2033 			UINTOUT();
2034 			break;
2035 		case 102:	/* Restore */
2036 			ND_PRINT(" totrans");
2037 			UINTOUT();
2038 			ND_PRINT(" flags");
2039 			UINTOUT();
2040 			break;
2041 		case 103:	/* Forward */
2042 			ND_PRINT(" fromtrans");
2043 			UINTOUT();
2044 			ND_PRINT(" fromdate");
2045 			DATEOUT();
2046 			DESTSERVEROUT();
2047 			ND_PRINT(" desttrans");
2048 			INTOUT();
2049 			break;
2050 		case 104:	/* End trans */
2051 			ND_PRINT(" trans");
2052 			UINTOUT();
2053 			break;
2054 		case 105:	/* Clone */
2055 			ND_PRINT(" trans");
2056 			UINTOUT();
2057 			ND_PRINT(" purgevol");
2058 			UINTOUT();
2059 			ND_PRINT(" newtype");
2060 			UINTOUT();
2061 			ND_PRINT(" newname");
2062 			STROUT(AFSNAMEMAX);
2063 			break;
2064 		case 106:	/* Set flags */
2065 			ND_PRINT(" trans");
2066 			UINTOUT();
2067 			ND_PRINT(" flags");
2068 			UINTOUT();
2069 			break;
2070 		case 108:	/* Trans create */
2071 			ND_PRINT(" vol");
2072 			UINTOUT();
2073 			ND_PRINT(" partition");
2074 			UINTOUT();
2075 			ND_PRINT(" flags");
2076 			UINTOUT();
2077 			break;
2078 		case 109:	/* Dump */
2079 		case 655537:	/* Get size */
2080 			ND_PRINT(" fromtrans");
2081 			UINTOUT();
2082 			ND_PRINT(" fromdate");
2083 			DATEOUT();
2084 			break;
2085 		case 110:	/* Get n-th volume */
2086 			ND_PRINT(" index");
2087 			UINTOUT();
2088 			break;
2089 		case 111:	/* Set forwarding */
2090 			ND_PRINT(" tid");
2091 			UINTOUT();
2092 			ND_PRINT(" newsite");
2093 			UINTOUT();
2094 			break;
2095 		case 112:	/* Get name */
2096 		case 113:	/* Get status */
2097 			ND_PRINT(" tid");
2098 			break;
2099 		case 114:	/* Signal restore */
2100 			ND_PRINT(" name");
2101 			STROUT(AFSNAMEMAX);
2102 			ND_PRINT(" type");
2103 			UINTOUT();
2104 			ND_PRINT(" pid");
2105 			UINTOUT();
2106 			ND_PRINT(" cloneid");
2107 			UINTOUT();
2108 			break;
2109 		case 116:	/* List volumes */
2110 			ND_PRINT(" partition");
2111 			UINTOUT();
2112 			ND_PRINT(" flags");
2113 			UINTOUT();
2114 			break;
2115 		case 117:	/* Set id types */
2116 			ND_PRINT(" tid");
2117 			UINTOUT();
2118 			ND_PRINT(" name");
2119 			STROUT(AFSNAMEMAX);
2120 			ND_PRINT(" type");
2121 			UINTOUT();
2122 			ND_PRINT(" pid");
2123 			UINTOUT();
2124 			ND_PRINT(" clone");
2125 			UINTOUT();
2126 			ND_PRINT(" backup");
2127 			UINTOUT();
2128 			break;
2129 		case 119:	/* Partition info */
2130 			ND_PRINT(" name");
2131 			STROUT(AFSNAMEMAX);
2132 			break;
2133 		case 120:	/* Reclone */
2134 			ND_PRINT(" tid");
2135 			UINTOUT();
2136 			break;
2137 		case 121:	/* List one volume */
2138 		case 122:	/* Nuke volume */
2139 		case 124:	/* Extended List volumes */
2140 		case 125:	/* Extended List one volume */
2141 		case 65536:	/* Convert RO to RW volume */
2142 			ND_PRINT(" partid");
2143 			UINTOUT();
2144 			ND_PRINT(" volid");
2145 			UINTOUT();
2146 			break;
2147 		case 123:	/* Set date */
2148 			ND_PRINT(" tid");
2149 			UINTOUT();
2150 			ND_PRINT(" date");
2151 			DATEOUT();
2152 			break;
2153 		case 126:	/* Set info */
2154 			ND_PRINT(" tid");
2155 			UINTOUT();
2156 			break;
2157 		case 128:	/* Forward multiple */
2158 			ND_PRINT(" fromtrans");
2159 			UINTOUT();
2160 			ND_PRINT(" fromdate");
2161 			DATEOUT();
2162 			{
2163 				uint32_t i, j;
2164 				j = GET_BE_U_4(bp);
2165 				bp += sizeof(uint32_t);
2166 				for (i = 0; i < j; i++) {
2167 					DESTSERVEROUT();
2168 					if (i != j - 1)
2169 						ND_PRINT(",");
2170 				}
2171 				if (j == 0)
2172 					ND_PRINT(" <none!>");
2173 			}
2174 			break;
2175 		case 65538:	/* Dump version 2 */
2176 			ND_PRINT(" fromtrans");
2177 			UINTOUT();
2178 			ND_PRINT(" fromdate");
2179 			DATEOUT();
2180 			ND_PRINT(" flags");
2181 			UINTOUT();
2182 			break;
2183 		default:
2184 			;
2185 	}
2186 	return;
2187 
2188 trunc:
2189 	ND_PRINT(" [|vol]");
2190 }
2191 
2192 /*
2193  * Handle replies to the AFS Volume Service
2194  */
2195 
2196 static void
vol_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)2197 vol_reply_print(netdissect_options *ndo,
2198                 const u_char *bp, u_int length, uint32_t opcode)
2199 {
2200 	const struct rx_header *rxh;
2201 	uint8_t type;
2202 
2203 	if (length <= sizeof(struct rx_header))
2204 		return;
2205 
2206 	rxh = (const struct rx_header *) bp;
2207 
2208 	/*
2209 	 * Print out the afs call we're invoking.  The table used here was
2210 	 * gleaned from volser/volint.xg
2211 	 */
2212 
2213 	ND_PRINT(" vol reply %s", tok2str(vol_req, "op#%u", opcode));
2214 
2215 	type = GET_U_1(rxh->type);
2216 	bp += sizeof(struct rx_header);
2217 
2218 	/*
2219 	 * If it was a data packet, interpret the response.
2220 	 */
2221 
2222 	if (type == RX_PACKET_TYPE_DATA) {
2223 		switch (opcode) {
2224 			case 100:	/* Create volume */
2225 				ND_PRINT(" volid");
2226 				UINTOUT();
2227 				ND_PRINT(" trans");
2228 				UINTOUT();
2229 				break;
2230 			case 104:	/* End transaction */
2231 				UINTOUT();
2232 				break;
2233 			case 105:	/* Clone */
2234 				ND_PRINT(" newvol");
2235 				UINTOUT();
2236 				break;
2237 			case 107:	/* Get flags */
2238 				UINTOUT();
2239 				break;
2240 			case 108:	/* Transaction create */
2241 				ND_PRINT(" trans");
2242 				UINTOUT();
2243 				break;
2244 			case 110:	/* Get n-th volume */
2245 				ND_PRINT(" volume");
2246 				UINTOUT();
2247 				ND_PRINT(" partition");
2248 				UINTOUT();
2249 				break;
2250 			case 112:	/* Get name */
2251 				STROUT(AFSNAMEMAX);
2252 				break;
2253 			case 113:	/* Get status */
2254 				ND_PRINT(" volid");
2255 				UINTOUT();
2256 				ND_PRINT(" nextuniq");
2257 				UINTOUT();
2258 				ND_PRINT(" type");
2259 				UINTOUT();
2260 				ND_PRINT(" parentid");
2261 				UINTOUT();
2262 				ND_PRINT(" clone");
2263 				UINTOUT();
2264 				ND_PRINT(" backup");
2265 				UINTOUT();
2266 				ND_PRINT(" restore");
2267 				UINTOUT();
2268 				ND_PRINT(" maxquota");
2269 				UINTOUT();
2270 				ND_PRINT(" minquota");
2271 				UINTOUT();
2272 				ND_PRINT(" owner");
2273 				UINTOUT();
2274 				ND_PRINT(" create");
2275 				DATEOUT();
2276 				ND_PRINT(" access");
2277 				DATEOUT();
2278 				ND_PRINT(" update");
2279 				DATEOUT();
2280 				ND_PRINT(" expire");
2281 				DATEOUT();
2282 				ND_PRINT(" backup");
2283 				DATEOUT();
2284 				ND_PRINT(" copy");
2285 				DATEOUT();
2286 				break;
2287 			case 115:	/* Old list partitions */
2288 				break;
2289 			case 116:	/* List volumes */
2290 			case 121:	/* List one volume */
2291 				{
2292 					uint32_t i, j;
2293 					j = GET_BE_U_4(bp);
2294 					bp += sizeof(uint32_t);
2295 					for (i = 0; i < j; i++) {
2296 						ND_PRINT(" name");
2297 						VECOUT(32);
2298 						ND_PRINT(" volid");
2299 						UINTOUT();
2300 						ND_PRINT(" type");
2301 						bp += sizeof(uint32_t) * 21;
2302 						if (i != j - 1)
2303 							ND_PRINT(",");
2304 					}
2305 					if (j == 0)
2306 						ND_PRINT(" <none!>");
2307 				}
2308 				break;
2309 
2310 
2311 			default:
2312 				;
2313 		}
2314 	} else {
2315 		/*
2316 		 * Otherwise, just print out the return code
2317 		 */
2318 		ND_PRINT(" errcode");
2319 		INTOUT();
2320 	}
2321 
2322 	return;
2323 
2324 trunc:
2325 	ND_PRINT(" [|vol]");
2326 }
2327 
2328 /*
2329  * Handle calls to the AFS BOS service
2330  */
2331 
2332 static void
bos_print(netdissect_options * ndo,const u_char * bp,u_int length)2333 bos_print(netdissect_options *ndo,
2334           const u_char *bp, u_int length)
2335 {
2336 	uint32_t bos_op;
2337 
2338 	if (length <= sizeof(struct rx_header))
2339 		return;
2340 
2341 	/*
2342 	 * Print out the afs call we're invoking.  The table used here was
2343 	 * gleaned from bozo/bosint.xg
2344 	 */
2345 
2346 	bos_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2347 
2348 	ND_PRINT(" bos call %s", tok2str(bos_req, "op#%u", bos_op));
2349 
2350 	/*
2351 	 * Decode some of the arguments to the BOS calls
2352 	 */
2353 
2354 	bp += sizeof(struct rx_header) + 4;
2355 
2356 	switch (bos_op) {
2357 		case 80:	/* Create B node */
2358 			ND_PRINT(" type");
2359 			STROUT(BOSNAMEMAX);
2360 			ND_PRINT(" instance");
2361 			STROUT(BOSNAMEMAX);
2362 			break;
2363 		case 81:	/* Delete B node */
2364 		case 83:	/* Get status */
2365 		case 85:	/* Get instance info */
2366 		case 87:	/* Add super user */
2367 		case 88:	/* Delete super user */
2368 		case 93:	/* Set cell name */
2369 		case 96:	/* Add cell host */
2370 		case 97:	/* Delete cell host */
2371 		case 104:	/* Restart */
2372 		case 106:	/* Uninstall */
2373 		case 108:	/* Exec */
2374 		case 112:	/* Getlog */
2375 		case 114:	/* Get instance strings */
2376 			STROUT(BOSNAMEMAX);
2377 			break;
2378 		case 82:	/* Set status */
2379 		case 98:	/* Set T status */
2380 			STROUT(BOSNAMEMAX);
2381 			ND_PRINT(" status");
2382 			INTOUT();
2383 			break;
2384 		case 86:	/* Get instance parm */
2385 			STROUT(BOSNAMEMAX);
2386 			ND_PRINT(" num");
2387 			INTOUT();
2388 			break;
2389 		case 84:	/* Enumerate instance */
2390 		case 89:	/* List super users */
2391 		case 90:	/* List keys */
2392 		case 91:	/* Add key */
2393 		case 92:	/* Delete key */
2394 		case 95:	/* Get cell host */
2395 			INTOUT();
2396 			break;
2397 		case 105:	/* Install */
2398 			STROUT(BOSNAMEMAX);
2399 			ND_PRINT(" size");
2400 			INTOUT();
2401 			ND_PRINT(" flags");
2402 			INTOUT();
2403 			ND_PRINT(" date");
2404 			INTOUT();
2405 			break;
2406 		default:
2407 			;
2408 	}
2409 
2410 	return;
2411 
2412 trunc:
2413 	ND_PRINT(" [|bos]");
2414 }
2415 
2416 /*
2417  * Handle replies to the AFS BOS Service
2418  */
2419 
2420 static void
bos_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)2421 bos_reply_print(netdissect_options *ndo,
2422                 const u_char *bp, u_int length, uint32_t opcode)
2423 {
2424 	const struct rx_header *rxh;
2425 	uint8_t type;
2426 
2427 	if (length <= sizeof(struct rx_header))
2428 		return;
2429 
2430 	rxh = (const struct rx_header *) bp;
2431 
2432 	/*
2433 	 * Print out the afs call we're invoking.  The table used here was
2434 	 * gleaned from volser/volint.xg
2435 	 */
2436 
2437 	ND_PRINT(" bos reply %s", tok2str(bos_req, "op#%u", opcode));
2438 
2439 	type = GET_U_1(rxh->type);
2440 	bp += sizeof(struct rx_header);
2441 
2442 	/*
2443 	 * If it was a data packet, interpret the response.
2444 	 */
2445 
2446 	if (type == RX_PACKET_TYPE_DATA)
2447 		/* Well, no, not really.  Leave this for later */
2448 		;
2449 	else {
2450 		/*
2451 		 * Otherwise, just print out the return code
2452 		 */
2453 		ND_PRINT(" errcode");
2454 		INTOUT();
2455 	}
2456 }
2457 
2458 /*
2459  * Check to see if this is a Ubik opcode.
2460  */
2461 
2462 static int
is_ubik(uint32_t opcode)2463 is_ubik(uint32_t opcode)
2464 {
2465 	if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) ||
2466 	    (opcode >= DISK_LOW && opcode <= DISK_HIGH))
2467 		return(1);
2468 	else
2469 		return(0);
2470 }
2471 
2472 /*
2473  * Handle Ubik opcodes to any one of the replicated database services
2474  */
2475 
2476 static void
ubik_print(netdissect_options * ndo,const u_char * bp)2477 ubik_print(netdissect_options *ndo,
2478            const u_char *bp)
2479 {
2480 	uint32_t ubik_op;
2481 	uint32_t temp;
2482 
2483 	/*
2484 	 * Print out the afs call we're invoking.  The table used here was
2485 	 * gleaned from ubik/ubik_int.xg
2486 	 */
2487 
2488 	/* Every function that calls this function first makes a bounds check
2489 	 * for (sizeof(rx_header) + 4) bytes, so long as it remains this way
2490 	 * the line below will not over-read.
2491 	 */
2492 	ubik_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2493 
2494 	ND_PRINT(" ubik call %s", tok2str(ubik_req, "op#%u", ubik_op));
2495 
2496 	/*
2497 	 * Decode some of the arguments to the Ubik calls
2498 	 */
2499 
2500 	bp += sizeof(struct rx_header) + 4;
2501 
2502 	switch (ubik_op) {
2503 		case 10000:		/* Beacon */
2504 			temp = GET_BE_U_4(bp);
2505 			bp += sizeof(uint32_t);
2506 			ND_PRINT(" syncsite %s", temp ? "yes" : "no");
2507 			ND_PRINT(" votestart");
2508 			DATEOUT();
2509 			ND_PRINT(" dbversion");
2510 			UBIK_VERSIONOUT();
2511 			ND_PRINT(" tid");
2512 			UBIK_VERSIONOUT();
2513 			break;
2514 		case 10003:		/* Get sync site */
2515 			ND_PRINT(" site");
2516 			UINTOUT();
2517 			break;
2518 		case 20000:		/* Begin */
2519 		case 20001:		/* Commit */
2520 		case 20007:		/* Abort */
2521 		case 20008:		/* Release locks */
2522 		case 20010:		/* Writev */
2523 			ND_PRINT(" tid");
2524 			UBIK_VERSIONOUT();
2525 			break;
2526 		case 20002:		/* Lock */
2527 			ND_PRINT(" tid");
2528 			UBIK_VERSIONOUT();
2529 			ND_PRINT(" file");
2530 			INTOUT();
2531 			ND_PRINT(" pos");
2532 			INTOUT();
2533 			ND_PRINT(" length");
2534 			INTOUT();
2535 			temp = GET_BE_U_4(bp);
2536 			bp += sizeof(uint32_t);
2537 			tok2str(ubik_lock_types, "type %u", temp);
2538 			break;
2539 		case 20003:		/* Write */
2540 			ND_PRINT(" tid");
2541 			UBIK_VERSIONOUT();
2542 			ND_PRINT(" file");
2543 			INTOUT();
2544 			ND_PRINT(" pos");
2545 			INTOUT();
2546 			break;
2547 		case 20005:		/* Get file */
2548 			ND_PRINT(" file");
2549 			INTOUT();
2550 			break;
2551 		case 20006:		/* Send file */
2552 			ND_PRINT(" file");
2553 			INTOUT();
2554 			ND_PRINT(" length");
2555 			INTOUT();
2556 			ND_PRINT(" dbversion");
2557 			UBIK_VERSIONOUT();
2558 			break;
2559 		case 20009:		/* Truncate */
2560 			ND_PRINT(" tid");
2561 			UBIK_VERSIONOUT();
2562 			ND_PRINT(" file");
2563 			INTOUT();
2564 			ND_PRINT(" length");
2565 			INTOUT();
2566 			break;
2567 		case 20012:		/* Set version */
2568 			ND_PRINT(" tid");
2569 			UBIK_VERSIONOUT();
2570 			ND_PRINT(" oldversion");
2571 			UBIK_VERSIONOUT();
2572 			ND_PRINT(" newversion");
2573 			UBIK_VERSIONOUT();
2574 			break;
2575 		default:
2576 			;
2577 	}
2578 
2579 	return;
2580 
2581 trunc:
2582 	ND_PRINT(" [|ubik]");
2583 }
2584 
2585 /*
2586  * Handle Ubik replies to any one of the replicated database services
2587  */
2588 
2589 static void
ubik_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)2590 ubik_reply_print(netdissect_options *ndo,
2591                  const u_char *bp, u_int length, uint32_t opcode)
2592 {
2593 	const struct rx_header *rxh;
2594 	uint8_t type;
2595 
2596 	if (length < sizeof(struct rx_header))
2597 		return;
2598 
2599 	rxh = (const struct rx_header *) bp;
2600 
2601 	/*
2602 	 * Print out the ubik call we're invoking.  This table was gleaned
2603 	 * from ubik/ubik_int.xg
2604 	 */
2605 
2606 	ND_PRINT(" ubik reply %s", tok2str(ubik_req, "op#%u", opcode));
2607 
2608 	type = GET_U_1(rxh->type);
2609 	bp += sizeof(struct rx_header);
2610 
2611 	/*
2612 	 * If it was a data packet, print out the arguments to the Ubik calls
2613 	 */
2614 
2615 	if (type == RX_PACKET_TYPE_DATA)
2616 		switch (opcode) {
2617 		case 10000:		/* Beacon */
2618 			ND_PRINT(" vote no");
2619 			break;
2620 		case 20004:		/* Get version */
2621 			ND_PRINT(" dbversion");
2622 			UBIK_VERSIONOUT();
2623 			break;
2624 		default:
2625 			;
2626 		}
2627 
2628 	/*
2629 	 * Otherwise, print out "yes" if it was a beacon packet (because
2630 	 * that's how yes votes are returned, go figure), otherwise
2631 	 * just print out the error code.
2632 	 */
2633 
2634 	else
2635 		switch (opcode) {
2636 		case 10000:		/* Beacon */
2637 			ND_PRINT(" vote yes until");
2638 			DATEOUT();
2639 			break;
2640 		default:
2641 			ND_PRINT(" errcode");
2642 			INTOUT();
2643 		}
2644 
2645 	return;
2646 
2647 trunc:
2648 	ND_PRINT(" [|ubik]");
2649 }
2650 
2651 /*
2652  * Handle RX ACK packets.
2653  */
2654 
2655 static void
rx_ack_print(netdissect_options * ndo,const u_char * bp,u_int length)2656 rx_ack_print(netdissect_options *ndo,
2657              const u_char *bp, u_int length)
2658 {
2659 	const struct rx_ackPacket *rxa;
2660 	uint8_t nAcks;
2661 	int i, start, last;
2662 	uint32_t firstPacket;
2663 
2664 	if (length < sizeof(struct rx_header))
2665 		return;
2666 
2667 	bp += sizeof(struct rx_header);
2668 
2669 	ND_TCHECK_LEN(bp, sizeof(struct rx_ackPacket));
2670 
2671 	rxa = (const struct rx_ackPacket *) bp;
2672 	bp += sizeof(struct rx_ackPacket);
2673 
2674 	/*
2675 	 * Print out a few useful things from the ack packet structure
2676 	 */
2677 
2678 	if (ndo->ndo_vflag > 2)
2679 		ND_PRINT(" bufspace %u maxskew %u",
2680 		       GET_BE_U_2(rxa->bufferSpace),
2681 		       GET_BE_U_2(rxa->maxSkew));
2682 
2683 	firstPacket = GET_BE_U_4(rxa->firstPacket);
2684 	ND_PRINT(" first %u serial %u reason %s",
2685 	       firstPacket, GET_BE_U_4(rxa->serial),
2686 	       tok2str(rx_ack_reasons, "#%u", GET_U_1(rxa->reason)));
2687 
2688 	/*
2689 	 * Okay, now we print out the ack array.  The way _this_ works
2690 	 * is that we start at "first", and step through the ack array.
2691 	 * If we have a contiguous range of acks/nacks, try to
2692 	 * collapse them into a range.
2693 	 *
2694 	 * If you're really clever, you might have noticed that this
2695 	 * doesn't seem quite correct.  Specifically, due to structure
2696 	 * padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually
2697 	 * yield the start of the ack array (because RX_MAXACKS is 255
2698 	 * and the structure will likely get padded to a 2 or 4 byte
2699 	 * boundary).  However, this is the way it's implemented inside
2700 	 * of AFS - the start of the extra fields are at
2701 	 * sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_
2702 	 * the exact start of the ack array.  Sigh.  That's why we aren't
2703 	 * using bp, but instead use rxa->acks[].  But nAcks gets added
2704 	 * to bp after this, so bp ends up at the right spot.  Go figure.
2705 	 */
2706 
2707 	nAcks = GET_U_1(rxa->nAcks);
2708 	if (nAcks != 0) {
2709 
2710 		ND_TCHECK_LEN(bp, nAcks);
2711 
2712 		/*
2713 		 * Sigh, this is gross, but it seems to work to collapse
2714 		 * ranges correctly.
2715 		 */
2716 
2717 		for (i = 0, start = last = -2; i < nAcks; i++)
2718 			if (GET_U_1(bp + i) == RX_ACK_TYPE_ACK) {
2719 
2720 				/*
2721 				 * I figured this deserved _some_ explanation.
2722 				 * First, print "acked" and the packet seq
2723 				 * number if this is the first time we've
2724 				 * seen an acked packet.
2725 				 */
2726 
2727 				if (last == -2) {
2728 					ND_PRINT(" acked %u", firstPacket + i);
2729 					start = i;
2730 				}
2731 
2732 				/*
2733 				 * Otherwise, if there is a skip in
2734 				 * the range (such as an nacked packet in
2735 				 * the middle of some acked packets),
2736 				 * then print the current packet number
2737 				 * separated from the last number by
2738 				 * a comma.
2739 				 */
2740 
2741 				else if (last != i - 1) {
2742 					ND_PRINT(",%u", firstPacket + i);
2743 					start = i;
2744 				}
2745 
2746 				/*
2747 				 * We always set last to the value of
2748 				 * the last ack we saw.  Conversely, start
2749 				 * is set to the value of the first ack
2750 				 * we saw in a range.
2751 				 */
2752 
2753 				last = i;
2754 
2755 				/*
2756 				 * Okay, this bit a code gets executed when
2757 				 * we hit a nack ... in _this_ case we
2758 				 * want to print out the range of packets
2759 				 * that were acked, so we need to print
2760 				 * the _previous_ packet number separated
2761 				 * from the first by a dash (-).  Since we
2762 				 * already printed the first packet above,
2763 				 * just print the final packet.  Don't
2764 				 * do this if there will be a single-length
2765 				 * range.
2766 				 */
2767 			} else if (last == i - 1 && start != last)
2768 				ND_PRINT("-%u", firstPacket + i - 1);
2769 
2770 		/*
2771 		 * So, what's going on here?  We ran off the end of the
2772 		 * ack list, and if we got a range we need to finish it up.
2773 		 * So we need to determine if the last packet in the list
2774 		 * was an ack (if so, then last will be set to it) and
2775 		 * we need to see if the last range didn't start with the
2776 		 * last packet (because if it _did_, then that would mean
2777 		 * that the packet number has already been printed and
2778 		 * we don't need to print it again).
2779 		 */
2780 
2781 		if (last == i - 1 && start != last)
2782 			ND_PRINT("-%u", firstPacket + i - 1);
2783 
2784 		/*
2785 		 * Same as above, just without comments
2786 		 */
2787 
2788 		for (i = 0, start = last = -2; i < nAcks; i++)
2789 			if (GET_U_1(bp + i) == RX_ACK_TYPE_NACK) {
2790 				if (last == -2) {
2791 					ND_PRINT(" nacked %u", firstPacket + i);
2792 					start = i;
2793 				} else if (last != i - 1) {
2794 					ND_PRINT(",%u", firstPacket + i);
2795 					start = i;
2796 				}
2797 				last = i;
2798 			} else if (last == i - 1 && start != last)
2799 				ND_PRINT("-%u", firstPacket + i - 1);
2800 
2801 		if (last == i - 1 && start != last)
2802 			ND_PRINT("-%u", firstPacket + i - 1);
2803 
2804 		bp += nAcks;
2805 	}
2806 
2807 	/* Padding. */
2808 	bp += 3;
2809 
2810 	/*
2811 	 * These are optional fields; depending on your version of AFS,
2812 	 * you may or may not see them
2813 	 */
2814 
2815 #define TRUNCRET(n)	if (ndo->ndo_snapend - bp + 1 <= n) return;
2816 
2817 	if (ndo->ndo_vflag > 1) {
2818 		TRUNCRET(4);
2819 		ND_PRINT(" ifmtu");
2820 		UINTOUT();
2821 
2822 		TRUNCRET(4);
2823 		ND_PRINT(" maxmtu");
2824 		UINTOUT();
2825 
2826 		TRUNCRET(4);
2827 		ND_PRINT(" rwind");
2828 		UINTOUT();
2829 
2830 		TRUNCRET(4);
2831 		ND_PRINT(" maxpackets");
2832 		UINTOUT();
2833 	}
2834 
2835 	return;
2836 
2837 trunc:
2838 	ND_PRINT(" [|ack]");
2839 }
2840 #undef TRUNCRET
2841