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