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