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