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