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