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.37.2.2 2007/06/15 19:43:15 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 char fmt[1024]; 1017 1018 if ((user = (char *)malloc(maxsize)) == NULL) 1019 return; 1020 1021 if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2) 1022 goto finish; 1023 1024 s += n; 1025 1026 if (s > end) 1027 goto finish; 1028 1029 /* 1030 * This wacky order preserves the order used by the "fs" command 1031 */ 1032 1033 #define ACLOUT(acl) \ 1034 if (acl & PRSFS_READ) \ 1035 printf("r"); \ 1036 if (acl & PRSFS_LOOKUP) \ 1037 printf("l"); \ 1038 if (acl & PRSFS_INSERT) \ 1039 printf("i"); \ 1040 if (acl & PRSFS_DELETE) \ 1041 printf("d"); \ 1042 if (acl & PRSFS_WRITE) \ 1043 printf("w"); \ 1044 if (acl & PRSFS_LOCK) \ 1045 printf("k"); \ 1046 if (acl & PRSFS_ADMINISTER) \ 1047 printf("a"); 1048 1049 for (i = 0; i < pos; i++) { 1050 snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1); 1051 if (sscanf((char *) s, fmt, user, &acl, &n) != 2) 1052 goto finish; 1053 s += n; 1054 printf(" +{"); 1055 fn_print((u_char *)user, NULL); 1056 printf(" "); 1057 ACLOUT(acl); 1058 printf("}"); 1059 if (s > end) 1060 goto finish; 1061 } 1062 1063 for (i = 0; i < neg; i++) { 1064 snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1); 1065 if (sscanf((char *) s, fmt, user, &acl, &n) != 2) 1066 goto finish; 1067 s += n; 1068 printf(" -{"); 1069 fn_print((u_char *)user, NULL); 1070 printf(" "); 1071 ACLOUT(acl); 1072 printf("}"); 1073 if (s > end) 1074 goto finish; 1075 } 1076 1077 finish: 1078 free(user); 1079 return; 1080 } 1081 1082 #undef ACLOUT 1083 1084 /* 1085 * Handle calls to the AFS callback service 1086 */ 1087 1088 static void 1089 cb_print(register const u_char *bp, int length) 1090 { 1091 int cb_op; 1092 unsigned long i; 1093 1094 if (length <= (int)sizeof(struct rx_header)) 1095 return; 1096 1097 if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) { 1098 goto trunc; 1099 } 1100 1101 /* 1102 * Print out the afs call we're invoking. The table used here was 1103 * gleaned from fsint/afscbint.xg 1104 */ 1105 1106 cb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 1107 1108 printf(" cb call %s", tok2str(cb_req, "op#%d", cb_op)); 1109 1110 bp += sizeof(struct rx_header) + 4; 1111 1112 /* 1113 * Print out the afs call we're invoking. The table used here was 1114 * gleaned from fsint/afscbint.xg 1115 */ 1116 1117 switch (cb_op) { 1118 case 204: /* Callback */ 1119 { 1120 unsigned long j, t; 1121 TCHECK2(bp[0], 4); 1122 j = EXTRACT_32BITS(bp); 1123 bp += sizeof(int32_t); 1124 1125 for (i = 0; i < j; i++) { 1126 FIDOUT(); 1127 if (i != j - 1) 1128 printf(","); 1129 } 1130 1131 if (j == 0) 1132 printf(" <none!>"); 1133 1134 j = EXTRACT_32BITS(bp); 1135 bp += sizeof(int32_t); 1136 1137 if (j != 0) 1138 printf(";"); 1139 1140 for (i = 0; i < j; i++) { 1141 printf(" ver"); 1142 INTOUT(); 1143 printf(" expires"); 1144 DATEOUT(); 1145 TCHECK2(bp[0], 4); 1146 t = EXTRACT_32BITS(bp); 1147 bp += sizeof(int32_t); 1148 tok2str(cb_types, "type %d", t); 1149 } 1150 } 1151 case 214: { 1152 printf(" afsuuid"); 1153 AFSUUIDOUT(); 1154 break; 1155 } 1156 default: 1157 ; 1158 } 1159 1160 return; 1161 1162 trunc: 1163 printf(" [|cb]"); 1164 } 1165 1166 /* 1167 * Handle replies to the AFS Callback Service 1168 */ 1169 1170 static void 1171 cb_reply_print(register const u_char *bp, int length, int32_t opcode) 1172 { 1173 struct rx_header *rxh; 1174 1175 if (length <= (int)sizeof(struct rx_header)) 1176 return; 1177 1178 rxh = (struct rx_header *) bp; 1179 1180 /* 1181 * Print out the afs call we're invoking. The table used here was 1182 * gleaned from fsint/afscbint.xg 1183 */ 1184 1185 printf(" cb reply %s", tok2str(cb_req, "op#%d", opcode)); 1186 1187 bp += sizeof(struct rx_header); 1188 1189 /* 1190 * If it was a data packet, interpret the response. 1191 */ 1192 1193 if (rxh->type == RX_PACKET_TYPE_DATA) 1194 switch (opcode) { 1195 case 213: /* InitCallBackState3 */ 1196 AFSUUIDOUT(); 1197 break; 1198 default: 1199 ; 1200 } 1201 else { 1202 /* 1203 * Otherwise, just print out the return code 1204 */ 1205 printf(" errcode"); 1206 INTOUT(); 1207 } 1208 1209 return; 1210 1211 trunc: 1212 printf(" [|cb]"); 1213 } 1214 1215 /* 1216 * Handle calls to the AFS protection database server 1217 */ 1218 1219 static void 1220 prot_print(register const u_char *bp, int length) 1221 { 1222 unsigned long i; 1223 int pt_op; 1224 1225 if (length <= (int)sizeof(struct rx_header)) 1226 return; 1227 1228 if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) { 1229 goto trunc; 1230 } 1231 1232 /* 1233 * Print out the afs call we're invoking. The table used here was 1234 * gleaned from ptserver/ptint.xg 1235 */ 1236 1237 pt_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 1238 1239 printf(" pt"); 1240 1241 if (is_ubik(pt_op)) { 1242 ubik_print(bp); 1243 return; 1244 } 1245 1246 printf(" call %s", tok2str(pt_req, "op#%d", pt_op)); 1247 1248 /* 1249 * Decode some of the arguments to the PT calls 1250 */ 1251 1252 bp += sizeof(struct rx_header) + 4; 1253 1254 switch (pt_op) { 1255 case 500: /* I New User */ 1256 STROUT(PRNAMEMAX); 1257 printf(" id"); 1258 INTOUT(); 1259 printf(" oldid"); 1260 INTOUT(); 1261 break; 1262 case 501: /* Where is it */ 1263 case 506: /* Delete */ 1264 case 508: /* Get CPS */ 1265 case 512: /* List entry */ 1266 case 514: /* List elements */ 1267 case 517: /* List owned */ 1268 case 518: /* Get CPS2 */ 1269 case 519: /* Get host CPS */ 1270 printf(" id"); 1271 INTOUT(); 1272 break; 1273 case 502: /* Dump entry */ 1274 printf(" pos"); 1275 INTOUT(); 1276 break; 1277 case 503: /* Add to group */ 1278 case 507: /* Remove from group */ 1279 case 515: /* Is a member of? */ 1280 printf(" uid"); 1281 INTOUT(); 1282 printf(" gid"); 1283 INTOUT(); 1284 break; 1285 case 504: /* Name to ID */ 1286 { 1287 unsigned long j; 1288 TCHECK2(bp[0], 4); 1289 j = EXTRACT_32BITS(bp); 1290 bp += sizeof(int32_t); 1291 1292 /* 1293 * Who designed this chicken-shit protocol? 1294 * 1295 * Each character is stored as a 32-bit 1296 * integer! 1297 */ 1298 1299 for (i = 0; i < j; i++) { 1300 VECOUT(PRNAMEMAX); 1301 } 1302 if (j == 0) 1303 printf(" <none!>"); 1304 } 1305 break; 1306 case 505: /* Id to name */ 1307 { 1308 unsigned long j; 1309 printf(" ids:"); 1310 TCHECK2(bp[0], 4); 1311 i = EXTRACT_32BITS(bp); 1312 bp += sizeof(int32_t); 1313 for (j = 0; j < i; j++) 1314 INTOUT(); 1315 if (j == 0) 1316 printf(" <none!>"); 1317 } 1318 break; 1319 case 509: /* New entry */ 1320 STROUT(PRNAMEMAX); 1321 printf(" flag"); 1322 INTOUT(); 1323 printf(" oid"); 1324 INTOUT(); 1325 break; 1326 case 511: /* Set max */ 1327 printf(" id"); 1328 INTOUT(); 1329 printf(" gflag"); 1330 INTOUT(); 1331 break; 1332 case 513: /* Change entry */ 1333 printf(" id"); 1334 INTOUT(); 1335 STROUT(PRNAMEMAX); 1336 printf(" oldid"); 1337 INTOUT(); 1338 printf(" newid"); 1339 INTOUT(); 1340 break; 1341 case 520: /* Update entry */ 1342 printf(" id"); 1343 INTOUT(); 1344 STROUT(PRNAMEMAX); 1345 break; 1346 default: 1347 ; 1348 } 1349 1350 1351 return; 1352 1353 trunc: 1354 printf(" [|pt]"); 1355 } 1356 1357 /* 1358 * Handle replies to the AFS protection service 1359 */ 1360 1361 static void 1362 prot_reply_print(register const u_char *bp, int length, int32_t opcode) 1363 { 1364 struct rx_header *rxh; 1365 unsigned long i; 1366 1367 if (length < (int)sizeof(struct rx_header)) 1368 return; 1369 1370 rxh = (struct rx_header *) bp; 1371 1372 /* 1373 * Print out the afs call we're invoking. The table used here was 1374 * gleaned from ptserver/ptint.xg. Check to see if it's a 1375 * Ubik call, however. 1376 */ 1377 1378 printf(" pt"); 1379 1380 if (is_ubik(opcode)) { 1381 ubik_reply_print(bp, length, opcode); 1382 return; 1383 } 1384 1385 printf(" reply %s", tok2str(pt_req, "op#%d", opcode)); 1386 1387 bp += sizeof(struct rx_header); 1388 1389 /* 1390 * If it was a data packet, interpret the response 1391 */ 1392 1393 if (rxh->type == RX_PACKET_TYPE_DATA) 1394 switch (opcode) { 1395 case 504: /* Name to ID */ 1396 { 1397 unsigned long j; 1398 printf(" ids:"); 1399 TCHECK2(bp[0], 4); 1400 i = EXTRACT_32BITS(bp); 1401 bp += sizeof(int32_t); 1402 for (j = 0; j < i; j++) 1403 INTOUT(); 1404 if (j == 0) 1405 printf(" <none!>"); 1406 } 1407 break; 1408 case 505: /* ID to name */ 1409 { 1410 unsigned long j; 1411 TCHECK2(bp[0], 4); 1412 j = EXTRACT_32BITS(bp); 1413 bp += sizeof(int32_t); 1414 1415 /* 1416 * Who designed this chicken-shit protocol? 1417 * 1418 * Each character is stored as a 32-bit 1419 * integer! 1420 */ 1421 1422 for (i = 0; i < j; i++) { 1423 VECOUT(PRNAMEMAX); 1424 } 1425 if (j == 0) 1426 printf(" <none!>"); 1427 } 1428 break; 1429 case 508: /* Get CPS */ 1430 case 514: /* List elements */ 1431 case 517: /* List owned */ 1432 case 518: /* Get CPS2 */ 1433 case 519: /* Get host CPS */ 1434 { 1435 unsigned long j; 1436 TCHECK2(bp[0], 4); 1437 j = EXTRACT_32BITS(bp); 1438 bp += sizeof(int32_t); 1439 for (i = 0; i < j; i++) { 1440 INTOUT(); 1441 } 1442 if (j == 0) 1443 printf(" <none!>"); 1444 } 1445 break; 1446 case 510: /* List max */ 1447 printf(" maxuid"); 1448 INTOUT(); 1449 printf(" maxgid"); 1450 INTOUT(); 1451 break; 1452 default: 1453 ; 1454 } 1455 else { 1456 /* 1457 * Otherwise, just print out the return code 1458 */ 1459 printf(" errcode"); 1460 INTOUT(); 1461 } 1462 1463 return; 1464 1465 trunc: 1466 printf(" [|pt]"); 1467 } 1468 1469 /* 1470 * Handle calls to the AFS volume location database service 1471 */ 1472 1473 static void 1474 vldb_print(register const u_char *bp, int length) 1475 { 1476 int vldb_op; 1477 unsigned long i; 1478 1479 if (length <= (int)sizeof(struct rx_header)) 1480 return; 1481 1482 if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) { 1483 goto trunc; 1484 } 1485 1486 /* 1487 * Print out the afs call we're invoking. The table used here was 1488 * gleaned from vlserver/vldbint.xg 1489 */ 1490 1491 vldb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 1492 1493 printf(" vldb"); 1494 1495 if (is_ubik(vldb_op)) { 1496 ubik_print(bp); 1497 return; 1498 } 1499 printf(" call %s", tok2str(vldb_req, "op#%d", vldb_op)); 1500 1501 /* 1502 * Decode some of the arguments to the VLDB calls 1503 */ 1504 1505 bp += sizeof(struct rx_header) + 4; 1506 1507 switch (vldb_op) { 1508 case 501: /* Create new volume */ 1509 case 517: /* Create entry N */ 1510 VECOUT(VLNAMEMAX); 1511 break; 1512 case 502: /* Delete entry */ 1513 case 503: /* Get entry by ID */ 1514 case 507: /* Update entry */ 1515 case 508: /* Set lock */ 1516 case 509: /* Release lock */ 1517 case 518: /* Get entry by ID N */ 1518 printf(" volid"); 1519 INTOUT(); 1520 TCHECK2(bp[0], sizeof(int32_t)); 1521 i = EXTRACT_32BITS(bp); 1522 bp += sizeof(int32_t); 1523 if (i <= 2) 1524 printf(" type %s", voltype[i]); 1525 break; 1526 case 504: /* Get entry by name */ 1527 case 519: /* Get entry by name N */ 1528 case 524: /* Update entry by name */ 1529 case 527: /* Get entry by name U */ 1530 STROUT(VLNAMEMAX); 1531 break; 1532 case 505: /* Get new vol id */ 1533 printf(" bump"); 1534 INTOUT(); 1535 break; 1536 case 506: /* Replace entry */ 1537 case 520: /* Replace entry N */ 1538 printf(" volid"); 1539 INTOUT(); 1540 TCHECK2(bp[0], sizeof(int32_t)); 1541 i = EXTRACT_32BITS(bp); 1542 bp += sizeof(int32_t); 1543 if (i <= 2) 1544 printf(" type %s", voltype[i]); 1545 VECOUT(VLNAMEMAX); 1546 break; 1547 case 510: /* List entry */ 1548 case 521: /* List entry N */ 1549 printf(" index"); 1550 INTOUT(); 1551 break; 1552 default: 1553 ; 1554 } 1555 1556 return; 1557 1558 trunc: 1559 printf(" [|vldb]"); 1560 } 1561 1562 /* 1563 * Handle replies to the AFS volume location database service 1564 */ 1565 1566 static void 1567 vldb_reply_print(register const u_char *bp, int length, int32_t opcode) 1568 { 1569 struct rx_header *rxh; 1570 unsigned long i; 1571 1572 if (length < (int)sizeof(struct rx_header)) 1573 return; 1574 1575 rxh = (struct rx_header *) bp; 1576 1577 /* 1578 * Print out the afs call we're invoking. The table used here was 1579 * gleaned from vlserver/vldbint.xg. Check to see if it's a 1580 * Ubik call, however. 1581 */ 1582 1583 printf(" vldb"); 1584 1585 if (is_ubik(opcode)) { 1586 ubik_reply_print(bp, length, opcode); 1587 return; 1588 } 1589 1590 printf(" reply %s", tok2str(vldb_req, "op#%d", opcode)); 1591 1592 bp += sizeof(struct rx_header); 1593 1594 /* 1595 * If it was a data packet, interpret the response 1596 */ 1597 1598 if (rxh->type == RX_PACKET_TYPE_DATA) 1599 switch (opcode) { 1600 case 510: /* List entry */ 1601 printf(" count"); 1602 INTOUT(); 1603 printf(" nextindex"); 1604 INTOUT(); 1605 case 503: /* Get entry by id */ 1606 case 504: /* Get entry by name */ 1607 { unsigned long nservers, j; 1608 VECOUT(VLNAMEMAX); 1609 TCHECK2(bp[0], sizeof(int32_t)); 1610 bp += sizeof(int32_t); 1611 printf(" numservers"); 1612 TCHECK2(bp[0], sizeof(int32_t)); 1613 nservers = EXTRACT_32BITS(bp); 1614 bp += sizeof(int32_t); 1615 printf(" %lu", nservers); 1616 printf(" servers"); 1617 for (i = 0; i < 8; i++) { 1618 TCHECK2(bp[0], sizeof(int32_t)); 1619 if (i < nservers) 1620 printf(" %s", 1621 intoa(((struct in_addr *) bp)->s_addr)); 1622 bp += sizeof(int32_t); 1623 } 1624 printf(" partitions"); 1625 for (i = 0; i < 8; i++) { 1626 TCHECK2(bp[0], sizeof(int32_t)); 1627 j = EXTRACT_32BITS(bp); 1628 if (i < nservers && j <= 26) 1629 printf(" %c", 'a' + (int)j); 1630 else if (i < nservers) 1631 printf(" %lu", j); 1632 bp += sizeof(int32_t); 1633 } 1634 TCHECK2(bp[0], 8 * sizeof(int32_t)); 1635 bp += 8 * sizeof(int32_t); 1636 printf(" rwvol"); 1637 UINTOUT(); 1638 printf(" rovol"); 1639 UINTOUT(); 1640 printf(" backup"); 1641 UINTOUT(); 1642 } 1643 break; 1644 case 505: /* Get new volume ID */ 1645 printf(" newvol"); 1646 UINTOUT(); 1647 break; 1648 case 521: /* List entry */ 1649 case 529: /* List entry U */ 1650 printf(" count"); 1651 INTOUT(); 1652 printf(" nextindex"); 1653 INTOUT(); 1654 case 518: /* Get entry by ID N */ 1655 case 519: /* Get entry by name N */ 1656 { unsigned long nservers, j; 1657 VECOUT(VLNAMEMAX); 1658 printf(" numservers"); 1659 TCHECK2(bp[0], sizeof(int32_t)); 1660 nservers = EXTRACT_32BITS(bp); 1661 bp += sizeof(int32_t); 1662 printf(" %lu", nservers); 1663 printf(" servers"); 1664 for (i = 0; i < 13; i++) { 1665 TCHECK2(bp[0], sizeof(int32_t)); 1666 if (i < nservers) 1667 printf(" %s", 1668 intoa(((struct in_addr *) bp)->s_addr)); 1669 bp += sizeof(int32_t); 1670 } 1671 printf(" partitions"); 1672 for (i = 0; i < 13; i++) { 1673 TCHECK2(bp[0], sizeof(int32_t)); 1674 j = EXTRACT_32BITS(bp); 1675 if (i < nservers && j <= 26) 1676 printf(" %c", 'a' + (int)j); 1677 else if (i < nservers) 1678 printf(" %lu", j); 1679 bp += sizeof(int32_t); 1680 } 1681 TCHECK2(bp[0], 13 * sizeof(int32_t)); 1682 bp += 13 * sizeof(int32_t); 1683 printf(" rwvol"); 1684 UINTOUT(); 1685 printf(" rovol"); 1686 UINTOUT(); 1687 printf(" backup"); 1688 UINTOUT(); 1689 } 1690 break; 1691 case 526: /* Get entry by ID U */ 1692 case 527: /* Get entry by name U */ 1693 { unsigned long nservers, j; 1694 VECOUT(VLNAMEMAX); 1695 printf(" numservers"); 1696 TCHECK2(bp[0], sizeof(int32_t)); 1697 nservers = EXTRACT_32BITS(bp); 1698 bp += sizeof(int32_t); 1699 printf(" %lu", nservers); 1700 printf(" servers"); 1701 for (i = 0; i < 13; i++) { 1702 if (i < nservers) { 1703 printf(" afsuuid"); 1704 AFSUUIDOUT(); 1705 } else { 1706 TCHECK2(bp[0], 44); 1707 bp += 44; 1708 } 1709 } 1710 TCHECK2(bp[0], 4 * 13); 1711 bp += 4 * 13; 1712 printf(" partitions"); 1713 for (i = 0; i < 13; i++) { 1714 TCHECK2(bp[0], sizeof(int32_t)); 1715 j = EXTRACT_32BITS(bp); 1716 if (i < nservers && j <= 26) 1717 printf(" %c", 'a' + (int)j); 1718 else if (i < nservers) 1719 printf(" %lu", j); 1720 bp += sizeof(int32_t); 1721 } 1722 TCHECK2(bp[0], 13 * sizeof(int32_t)); 1723 bp += 13 * sizeof(int32_t); 1724 printf(" rwvol"); 1725 UINTOUT(); 1726 printf(" rovol"); 1727 UINTOUT(); 1728 printf(" backup"); 1729 UINTOUT(); 1730 } 1731 default: 1732 ; 1733 } 1734 1735 else { 1736 /* 1737 * Otherwise, just print out the return code 1738 */ 1739 printf(" errcode"); 1740 INTOUT(); 1741 } 1742 1743 return; 1744 1745 trunc: 1746 printf(" [|vldb]"); 1747 } 1748 1749 /* 1750 * Handle calls to the AFS Kerberos Authentication service 1751 */ 1752 1753 static void 1754 kauth_print(register const u_char *bp, int length) 1755 { 1756 int kauth_op; 1757 1758 if (length <= (int)sizeof(struct rx_header)) 1759 return; 1760 1761 if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) { 1762 goto trunc; 1763 } 1764 1765 /* 1766 * Print out the afs call we're invoking. The table used here was 1767 * gleaned from kauth/kauth.rg 1768 */ 1769 1770 kauth_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 1771 1772 printf(" kauth"); 1773 1774 if (is_ubik(kauth_op)) { 1775 ubik_print(bp); 1776 return; 1777 } 1778 1779 1780 printf(" call %s", tok2str(kauth_req, "op#%d", kauth_op)); 1781 1782 /* 1783 * Decode some of the arguments to the KA calls 1784 */ 1785 1786 bp += sizeof(struct rx_header) + 4; 1787 1788 switch (kauth_op) { 1789 case 1: /* Authenticate old */; 1790 case 21: /* Authenticate */ 1791 case 22: /* Authenticate-V2 */ 1792 case 2: /* Change PW */ 1793 case 5: /* Set fields */ 1794 case 6: /* Create user */ 1795 case 7: /* Delete user */ 1796 case 8: /* Get entry */ 1797 case 14: /* Unlock */ 1798 case 15: /* Lock status */ 1799 printf(" principal"); 1800 STROUT(KANAMEMAX); 1801 STROUT(KANAMEMAX); 1802 break; 1803 case 3: /* GetTicket-old */ 1804 case 23: /* GetTicket */ 1805 { 1806 int i; 1807 printf(" kvno"); 1808 INTOUT(); 1809 printf(" domain"); 1810 STROUT(KANAMEMAX); 1811 TCHECK2(bp[0], sizeof(int32_t)); 1812 i = (int) EXTRACT_32BITS(bp); 1813 bp += sizeof(int32_t); 1814 TCHECK2(bp[0], i); 1815 bp += i; 1816 printf(" principal"); 1817 STROUT(KANAMEMAX); 1818 STROUT(KANAMEMAX); 1819 break; 1820 } 1821 case 4: /* Set Password */ 1822 printf(" principal"); 1823 STROUT(KANAMEMAX); 1824 STROUT(KANAMEMAX); 1825 printf(" kvno"); 1826 INTOUT(); 1827 break; 1828 case 12: /* Get password */ 1829 printf(" name"); 1830 STROUT(KANAMEMAX); 1831 break; 1832 default: 1833 ; 1834 } 1835 1836 return; 1837 1838 trunc: 1839 printf(" [|kauth]"); 1840 } 1841 1842 /* 1843 * Handle replies to the AFS Kerberos Authentication Service 1844 */ 1845 1846 static void 1847 kauth_reply_print(register const u_char *bp, int length, int32_t opcode) 1848 { 1849 struct rx_header *rxh; 1850 1851 if (length <= (int)sizeof(struct rx_header)) 1852 return; 1853 1854 rxh = (struct rx_header *) bp; 1855 1856 /* 1857 * Print out the afs call we're invoking. The table used here was 1858 * gleaned from kauth/kauth.rg 1859 */ 1860 1861 printf(" kauth"); 1862 1863 if (is_ubik(opcode)) { 1864 ubik_reply_print(bp, length, opcode); 1865 return; 1866 } 1867 1868 printf(" reply %s", tok2str(kauth_req, "op#%d", opcode)); 1869 1870 bp += sizeof(struct rx_header); 1871 1872 /* 1873 * If it was a data packet, interpret the response. 1874 */ 1875 1876 if (rxh->type == RX_PACKET_TYPE_DATA) 1877 /* Well, no, not really. Leave this for later */ 1878 ; 1879 else { 1880 /* 1881 * Otherwise, just print out the return code 1882 */ 1883 printf(" errcode"); 1884 INTOUT(); 1885 } 1886 1887 return; 1888 1889 trunc: 1890 printf(" [|kauth]"); 1891 } 1892 1893 /* 1894 * Handle calls to the AFS Volume location service 1895 */ 1896 1897 static void 1898 vol_print(register const u_char *bp, int length) 1899 { 1900 int vol_op; 1901 1902 if (length <= (int)sizeof(struct rx_header)) 1903 return; 1904 1905 if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) { 1906 goto trunc; 1907 } 1908 1909 /* 1910 * Print out the afs call we're invoking. The table used here was 1911 * gleaned from volser/volint.xg 1912 */ 1913 1914 vol_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 1915 1916 printf(" vol call %s", tok2str(vol_req, "op#%d", vol_op)); 1917 1918 /* 1919 * Normally there would be a switch statement here to decode the 1920 * arguments to the AFS call, but since I don't have access to 1921 * an AFS server (yet) and I'm not an AFS admin, I can't 1922 * test any of these calls. Leave this blank for now. 1923 */ 1924 1925 return; 1926 1927 trunc: 1928 printf(" [|vol]"); 1929 } 1930 1931 /* 1932 * Handle replies to the AFS Volume Service 1933 */ 1934 1935 static void 1936 vol_reply_print(register const u_char *bp, int length, int32_t opcode) 1937 { 1938 struct rx_header *rxh; 1939 1940 if (length <= (int)sizeof(struct rx_header)) 1941 return; 1942 1943 rxh = (struct rx_header *) bp; 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 printf(" vol reply %s", tok2str(vol_req, "op#%d", opcode)); 1951 1952 bp += sizeof(struct rx_header); 1953 1954 /* 1955 * If it was a data packet, interpret the response. 1956 */ 1957 1958 if (rxh->type == RX_PACKET_TYPE_DATA) 1959 /* Well, no, not really. Leave this for later */ 1960 ; 1961 else { 1962 /* 1963 * Otherwise, just print out the return code 1964 */ 1965 printf(" errcode"); 1966 INTOUT(); 1967 } 1968 1969 return; 1970 1971 trunc: 1972 printf(" [|vol]"); 1973 } 1974 1975 /* 1976 * Handle calls to the AFS BOS service 1977 */ 1978 1979 static void 1980 bos_print(register const u_char *bp, int length) 1981 { 1982 int bos_op; 1983 1984 if (length <= (int)sizeof(struct rx_header)) 1985 return; 1986 1987 if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) { 1988 goto trunc; 1989 } 1990 1991 /* 1992 * Print out the afs call we're invoking. The table used here was 1993 * gleaned from bozo/bosint.xg 1994 */ 1995 1996 bos_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 1997 1998 printf(" bos call %s", tok2str(bos_req, "op#%d", bos_op)); 1999 2000 /* 2001 * Decode some of the arguments to the BOS calls 2002 */ 2003 2004 bp += sizeof(struct rx_header) + 4; 2005 2006 switch (bos_op) { 2007 case 80: /* Create B node */ 2008 printf(" type"); 2009 STROUT(BOSNAMEMAX); 2010 printf(" instance"); 2011 STROUT(BOSNAMEMAX); 2012 break; 2013 case 81: /* Delete B node */ 2014 case 83: /* Get status */ 2015 case 85: /* Get instance info */ 2016 case 87: /* Add super user */ 2017 case 88: /* Delete super user */ 2018 case 93: /* Set cell name */ 2019 case 96: /* Add cell host */ 2020 case 97: /* Delete cell host */ 2021 case 104: /* Restart */ 2022 case 106: /* Uninstall */ 2023 case 108: /* Exec */ 2024 case 112: /* Getlog */ 2025 case 114: /* Get instance strings */ 2026 STROUT(BOSNAMEMAX); 2027 break; 2028 case 82: /* Set status */ 2029 case 98: /* Set T status */ 2030 STROUT(BOSNAMEMAX); 2031 printf(" status"); 2032 INTOUT(); 2033 break; 2034 case 86: /* Get instance parm */ 2035 STROUT(BOSNAMEMAX); 2036 printf(" num"); 2037 INTOUT(); 2038 break; 2039 case 84: /* Enumerate instance */ 2040 case 89: /* List super users */ 2041 case 90: /* List keys */ 2042 case 91: /* Add key */ 2043 case 92: /* Delete key */ 2044 case 95: /* Get cell host */ 2045 INTOUT(); 2046 break; 2047 case 105: /* Install */ 2048 STROUT(BOSNAMEMAX); 2049 printf(" size"); 2050 INTOUT(); 2051 printf(" flags"); 2052 INTOUT(); 2053 printf(" date"); 2054 INTOUT(); 2055 break; 2056 default: 2057 ; 2058 } 2059 2060 return; 2061 2062 trunc: 2063 printf(" [|bos]"); 2064 } 2065 2066 /* 2067 * Handle replies to the AFS BOS Service 2068 */ 2069 2070 static void 2071 bos_reply_print(register const u_char *bp, int length, int32_t opcode) 2072 { 2073 struct rx_header *rxh; 2074 2075 if (length <= (int)sizeof(struct rx_header)) 2076 return; 2077 2078 rxh = (struct rx_header *) bp; 2079 2080 /* 2081 * Print out the afs call we're invoking. The table used here was 2082 * gleaned from volser/volint.xg 2083 */ 2084 2085 printf(" bos reply %s", tok2str(bos_req, "op#%d", opcode)); 2086 2087 bp += sizeof(struct rx_header); 2088 2089 /* 2090 * If it was a data packet, interpret the response. 2091 */ 2092 2093 if (rxh->type == RX_PACKET_TYPE_DATA) 2094 /* Well, no, not really. Leave this for later */ 2095 ; 2096 else { 2097 /* 2098 * Otherwise, just print out the return code 2099 */ 2100 printf(" errcode"); 2101 INTOUT(); 2102 } 2103 2104 return; 2105 2106 trunc: 2107 printf(" [|bos]"); 2108 } 2109 2110 /* 2111 * Check to see if this is a Ubik opcode. 2112 */ 2113 2114 static int 2115 is_ubik(u_int32_t opcode) 2116 { 2117 if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) || 2118 (opcode >= DISK_LOW && opcode <= DISK_HIGH)) 2119 return(1); 2120 else 2121 return(0); 2122 } 2123 2124 /* 2125 * Handle Ubik opcodes to any one of the replicated database services 2126 */ 2127 2128 static void 2129 ubik_print(register const u_char *bp) 2130 { 2131 int ubik_op; 2132 int32_t temp; 2133 2134 /* 2135 * Print out the afs call we're invoking. The table used here was 2136 * gleaned from ubik/ubik_int.xg 2137 */ 2138 2139 ubik_op = EXTRACT_32BITS(bp + sizeof(struct rx_header)); 2140 2141 printf(" ubik call %s", tok2str(ubik_req, "op#%d", ubik_op)); 2142 2143 /* 2144 * Decode some of the arguments to the Ubik calls 2145 */ 2146 2147 bp += sizeof(struct rx_header) + 4; 2148 2149 switch (ubik_op) { 2150 case 10000: /* Beacon */ 2151 TCHECK2(bp[0], 4); 2152 temp = EXTRACT_32BITS(bp); 2153 bp += sizeof(int32_t); 2154 printf(" syncsite %s", temp ? "yes" : "no"); 2155 printf(" votestart"); 2156 DATEOUT(); 2157 printf(" dbversion"); 2158 UBIK_VERSIONOUT(); 2159 printf(" tid"); 2160 UBIK_VERSIONOUT(); 2161 break; 2162 case 10003: /* Get sync site */ 2163 printf(" site"); 2164 UINTOUT(); 2165 break; 2166 case 20000: /* Begin */ 2167 case 20001: /* Commit */ 2168 case 20007: /* Abort */ 2169 case 20008: /* Release locks */ 2170 case 20010: /* Writev */ 2171 printf(" tid"); 2172 UBIK_VERSIONOUT(); 2173 break; 2174 case 20002: /* Lock */ 2175 printf(" tid"); 2176 UBIK_VERSIONOUT(); 2177 printf(" file"); 2178 INTOUT(); 2179 printf(" pos"); 2180 INTOUT(); 2181 printf(" length"); 2182 INTOUT(); 2183 temp = EXTRACT_32BITS(bp); 2184 bp += sizeof(int32_t); 2185 tok2str(ubik_lock_types, "type %d", temp); 2186 break; 2187 case 20003: /* Write */ 2188 printf(" tid"); 2189 UBIK_VERSIONOUT(); 2190 printf(" file"); 2191 INTOUT(); 2192 printf(" pos"); 2193 INTOUT(); 2194 break; 2195 case 20005: /* Get file */ 2196 printf(" file"); 2197 INTOUT(); 2198 break; 2199 case 20006: /* Send file */ 2200 printf(" file"); 2201 INTOUT(); 2202 printf(" length"); 2203 INTOUT(); 2204 printf(" dbversion"); 2205 UBIK_VERSIONOUT(); 2206 break; 2207 case 20009: /* Truncate */ 2208 printf(" tid"); 2209 UBIK_VERSIONOUT(); 2210 printf(" file"); 2211 INTOUT(); 2212 printf(" length"); 2213 INTOUT(); 2214 break; 2215 case 20012: /* Set version */ 2216 printf(" tid"); 2217 UBIK_VERSIONOUT(); 2218 printf(" oldversion"); 2219 UBIK_VERSIONOUT(); 2220 printf(" newversion"); 2221 UBIK_VERSIONOUT(); 2222 break; 2223 default: 2224 ; 2225 } 2226 2227 return; 2228 2229 trunc: 2230 printf(" [|ubik]"); 2231 } 2232 2233 /* 2234 * Handle Ubik replies to any one of the replicated database services 2235 */ 2236 2237 static void 2238 ubik_reply_print(register const u_char *bp, int length, int32_t opcode) 2239 { 2240 struct rx_header *rxh; 2241 2242 if (length < (int)sizeof(struct rx_header)) 2243 return; 2244 2245 rxh = (struct rx_header *) bp; 2246 2247 /* 2248 * Print out the ubik call we're invoking. This table was gleaned 2249 * from ubik/ubik_int.xg 2250 */ 2251 2252 printf(" ubik reply %s", tok2str(ubik_req, "op#%d", opcode)); 2253 2254 bp += sizeof(struct rx_header); 2255 2256 /* 2257 * If it was a data packet, print out the arguments to the Ubik calls 2258 */ 2259 2260 if (rxh->type == RX_PACKET_TYPE_DATA) 2261 switch (opcode) { 2262 case 10000: /* Beacon */ 2263 printf(" vote no"); 2264 break; 2265 case 20004: /* Get version */ 2266 printf(" dbversion"); 2267 UBIK_VERSIONOUT(); 2268 break; 2269 default: 2270 ; 2271 } 2272 2273 /* 2274 * Otherwise, print out "yes" it it was a beacon packet (because 2275 * that's how yes votes are returned, go figure), otherwise 2276 * just print out the error code. 2277 */ 2278 2279 else 2280 switch (opcode) { 2281 case 10000: /* Beacon */ 2282 printf(" vote yes until"); 2283 DATEOUT(); 2284 break; 2285 default: 2286 printf(" errcode"); 2287 INTOUT(); 2288 } 2289 2290 return; 2291 2292 trunc: 2293 printf(" [|ubik]"); 2294 } 2295 2296 /* 2297 * Handle RX ACK packets. 2298 */ 2299 2300 static void 2301 rx_ack_print(register const u_char *bp, int length) 2302 { 2303 struct rx_ackPacket *rxa; 2304 int i, start, last; 2305 u_int32_t firstPacket; 2306 2307 if (length < (int)sizeof(struct rx_header)) 2308 return; 2309 2310 bp += sizeof(struct rx_header); 2311 2312 /* 2313 * This may seem a little odd .... the rx_ackPacket structure 2314 * contains an array of individual packet acknowledgements 2315 * (used for selective ack/nack), but since it's variable in size, 2316 * we don't want to truncate based on the size of the whole 2317 * rx_ackPacket structure. 2318 */ 2319 2320 TCHECK2(bp[0], sizeof(struct rx_ackPacket) - RX_MAXACKS); 2321 2322 rxa = (struct rx_ackPacket *) bp; 2323 bp += (sizeof(struct rx_ackPacket) - RX_MAXACKS); 2324 2325 /* 2326 * Print out a few useful things from the ack packet structure 2327 */ 2328 2329 if (vflag > 2) 2330 printf(" bufspace %d maxskew %d", 2331 (int) EXTRACT_16BITS(&rxa->bufferSpace), 2332 (int) EXTRACT_16BITS(&rxa->maxSkew)); 2333 2334 firstPacket = EXTRACT_32BITS(&rxa->firstPacket); 2335 printf(" first %d serial %d reason %s", 2336 firstPacket, EXTRACT_32BITS(&rxa->serial), 2337 tok2str(rx_ack_reasons, "#%d", (int) rxa->reason)); 2338 2339 /* 2340 * Okay, now we print out the ack array. The way _this_ works 2341 * is that we start at "first", and step through the ack array. 2342 * If we have a contiguous range of acks/nacks, try to 2343 * collapse them into a range. 2344 * 2345 * If you're really clever, you might have noticed that this 2346 * doesn't seem quite correct. Specifically, due to structure 2347 * padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually 2348 * yield the start of the ack array (because RX_MAXACKS is 255 2349 * and the structure will likely get padded to a 2 or 4 byte 2350 * boundary). However, this is the way it's implemented inside 2351 * of AFS - the start of the extra fields are at 2352 * sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_ 2353 * the exact start of the ack array. Sigh. That's why we aren't 2354 * using bp, but instead use rxa->acks[]. But nAcks gets added 2355 * to bp after this, so bp ends up at the right spot. Go figure. 2356 */ 2357 2358 if (rxa->nAcks != 0) { 2359 2360 TCHECK2(bp[0], rxa->nAcks); 2361 2362 /* 2363 * Sigh, this is gross, but it seems to work to collapse 2364 * ranges correctly. 2365 */ 2366 2367 for (i = 0, start = last = -2; i < rxa->nAcks; i++) 2368 if (rxa->acks[i] == RX_ACK_TYPE_ACK) { 2369 2370 /* 2371 * I figured this deserved _some_ explanation. 2372 * First, print "acked" and the packet seq 2373 * number if this is the first time we've 2374 * seen an acked packet. 2375 */ 2376 2377 if (last == -2) { 2378 printf(" acked %d", 2379 firstPacket + i); 2380 start = i; 2381 } 2382 2383 /* 2384 * Otherwise, if the there is a skip in 2385 * the range (such as an nacked packet in 2386 * the middle of some acked packets), 2387 * then print the current packet number 2388 * seperated from the last number by 2389 * a comma. 2390 */ 2391 2392 else if (last != i - 1) { 2393 printf(",%d", firstPacket + i); 2394 start = i; 2395 } 2396 2397 /* 2398 * We always set last to the value of 2399 * the last ack we saw. Conversely, start 2400 * is set to the value of the first ack 2401 * we saw in a range. 2402 */ 2403 2404 last = i; 2405 2406 /* 2407 * Okay, this bit a code gets executed when 2408 * we hit a nack ... in _this_ case we 2409 * want to print out the range of packets 2410 * that were acked, so we need to print 2411 * the _previous_ packet number seperated 2412 * from the first by a dash (-). Since we 2413 * already printed the first packet above, 2414 * just print the final packet. Don't 2415 * do this if there will be a single-length 2416 * range. 2417 */ 2418 } else if (last == i - 1 && start != last) 2419 printf("-%d", firstPacket + i - 1); 2420 2421 /* 2422 * So, what's going on here? We ran off the end of the 2423 * ack list, and if we got a range we need to finish it up. 2424 * So we need to determine if the last packet in the list 2425 * was an ack (if so, then last will be set to it) and 2426 * we need to see if the last range didn't start with the 2427 * last packet (because if it _did_, then that would mean 2428 * that the packet number has already been printed and 2429 * we don't need to print it again). 2430 */ 2431 2432 if (last == i - 1 && start != last) 2433 printf("-%d", firstPacket + i - 1); 2434 2435 /* 2436 * Same as above, just without comments 2437 */ 2438 2439 for (i = 0, start = last = -2; i < rxa->nAcks; i++) 2440 if (rxa->acks[i] == RX_ACK_TYPE_NACK) { 2441 if (last == -2) { 2442 printf(" nacked %d", 2443 firstPacket + i); 2444 start = i; 2445 } else if (last != i - 1) { 2446 printf(",%d", firstPacket + i); 2447 start = i; 2448 } 2449 last = i; 2450 } else if (last == i - 1 && start != last) 2451 printf("-%d", firstPacket + i - 1); 2452 2453 if (last == i - 1 && start != last) 2454 printf("-%d", firstPacket + i - 1); 2455 2456 bp += rxa->nAcks; 2457 } 2458 2459 2460 /* 2461 * These are optional fields; depending on your version of AFS, 2462 * you may or may not see them 2463 */ 2464 2465 #define TRUNCRET(n) if (snapend - bp + 1 <= n) return; 2466 2467 if (vflag > 1) { 2468 TRUNCRET(4); 2469 printf(" ifmtu"); 2470 INTOUT(); 2471 2472 TRUNCRET(4); 2473 printf(" maxmtu"); 2474 INTOUT(); 2475 2476 TRUNCRET(4); 2477 printf(" rwind"); 2478 INTOUT(); 2479 2480 TRUNCRET(4); 2481 printf(" maxpackets"); 2482 INTOUT(); 2483 } 2484 2485 return; 2486 2487 trunc: 2488 printf(" [|ack]"); 2489 } 2490 #undef TRUNCRET 2491