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