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