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