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