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