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