]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-rx.c
ping: use the monotonic clock to measure durations
[FreeBSD/FreeBSD.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_32BITS(&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_32BITS(&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                 }
1023                 case 65537:     /* Fetch data 64 */
1024                         FIDOUT();
1025                         ND_PRINT((ndo, " offset"));
1026                         UINT64OUT();
1027                         ND_PRINT((ndo, " length"));
1028                         UINT64OUT();
1029                         break;
1030                 case 65538:     /* Store data 64 */
1031                         FIDOUT();
1032                         STOREATTROUT();
1033                         ND_PRINT((ndo, " offset"));
1034                         UINT64OUT();
1035                         ND_PRINT((ndo, " length"));
1036                         UINT64OUT();
1037                         ND_PRINT((ndo, " flen"));
1038                         UINT64OUT();
1039                         break;
1040                 case 65541:    /* CallBack rx conn address */
1041                         ND_PRINT((ndo, " addr"));
1042                         UINTOUT();
1043                 default:
1044                         ;
1045         }
1046
1047         return;
1048
1049 trunc:
1050         ND_PRINT((ndo, " [|fs]"));
1051 }
1052
1053 /*
1054  * Handle replies to the AFS file service
1055  */
1056
1057 static void
1058 fs_reply_print(netdissect_options *ndo,
1059                register const u_char *bp, int length, int32_t opcode)
1060 {
1061         unsigned long i;
1062         const struct rx_header *rxh;
1063
1064         if (length <= (int)sizeof(struct rx_header))
1065                 return;
1066
1067         rxh = (const struct rx_header *) bp;
1068
1069         /*
1070          * Print out the afs call we're invoking.  The table used here was
1071          * gleaned from fsint/afsint.xg
1072          */
1073
1074         ND_PRINT((ndo, " fs reply %s", tok2str(fs_req, "op#%d", opcode)));
1075
1076         bp += sizeof(struct rx_header);
1077
1078         /*
1079          * If it was a data packet, interpret the response
1080          */
1081
1082         if (rxh->type == RX_PACKET_TYPE_DATA) {
1083                 switch (opcode) {
1084                 case 131:       /* Fetch ACL */
1085                 {
1086                         char a[AFSOPAQUEMAX+1];
1087                         ND_TCHECK2(bp[0], 4);
1088                         i = EXTRACT_32BITS(bp);
1089                         bp += sizeof(int32_t);
1090                         ND_TCHECK2(bp[0], i);
1091                         i = min(AFSOPAQUEMAX, i);
1092                         strncpy(a, (const char *) bp, i);
1093                         a[i] = '\0';
1094                         acl_print(ndo, (u_char *) a, sizeof(a), (u_char *) a + i);
1095                         break;
1096                 }
1097                 case 137:       /* Create file */
1098                 case 141:       /* MakeDir */
1099                         ND_PRINT((ndo, " new"));
1100                         FIDOUT();
1101                         break;
1102                 case 151:       /* Get root volume */
1103                         ND_PRINT((ndo, " root volume"));
1104                         STROUT(AFSNAMEMAX);
1105                         break;
1106                 case 153:       /* Get time */
1107                         DATEOUT();
1108                         break;
1109                 default:
1110                         ;
1111                 }
1112         } else if (rxh->type == RX_PACKET_TYPE_ABORT) {
1113                 /*
1114                  * Otherwise, just print out the return code
1115                  */
1116                 ND_TCHECK2(bp[0], sizeof(int32_t));
1117                 i = (int) EXTRACT_32BITS(bp);
1118                 bp += sizeof(int32_t);
1119
1120                 ND_PRINT((ndo, " error %s", tok2str(afs_fs_errors, "#%d", i)));
1121         } else {
1122                 ND_PRINT((ndo, " strange fs reply of type %d", rxh->type));
1123         }
1124
1125         return;
1126
1127 trunc:
1128         ND_PRINT((ndo, " [|fs]"));
1129 }
1130
1131 /*
1132  * Print out an AFS ACL string.  An AFS ACL is a string that has the
1133  * following format:
1134  *
1135  * <positive> <negative>
1136  * <uid1> <aclbits1>
1137  * ....
1138  *
1139  * "positive" and "negative" are integers which contain the number of
1140  * positive and negative ACL's in the string.  The uid/aclbits pair are
1141  * ASCII strings containing the UID/PTS record and and a ascii number
1142  * representing a logical OR of all the ACL permission bits
1143  */
1144
1145 static void
1146 acl_print(netdissect_options *ndo,
1147           u_char *s, int maxsize, u_char *end)
1148 {
1149         int pos, neg, acl;
1150         int n, i;
1151         char *user;
1152         char fmt[1024];
1153
1154         if ((user = (char *)malloc(maxsize)) == NULL)
1155                 return;
1156
1157         if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
1158                 goto finish;
1159
1160         s += n;
1161
1162         if (s > end)
1163                 goto finish;
1164
1165         /*
1166          * This wacky order preserves the order used by the "fs" command
1167          */
1168
1169 #define ACLOUT(acl) \
1170         ND_PRINT((ndo, "%s%s%s%s%s%s%s", \
1171                   acl & PRSFS_READ       ? "r" : "", \
1172                   acl & PRSFS_LOOKUP     ? "l" : "", \
1173                   acl & PRSFS_INSERT     ? "i" : "", \
1174                   acl & PRSFS_DELETE     ? "d" : "", \
1175                   acl & PRSFS_WRITE      ? "w" : "", \
1176                   acl & PRSFS_LOCK       ? "k" : "", \
1177                   acl & PRSFS_ADMINISTER ? "a" : ""));
1178
1179         for (i = 0; i < pos; i++) {
1180                 snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
1181                 if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
1182                         goto finish;
1183                 s += n;
1184                 ND_PRINT((ndo, " +{"));
1185                 fn_print(ndo, (u_char *)user, NULL);
1186                 ND_PRINT((ndo, " "));
1187                 ACLOUT(acl);
1188                 ND_PRINT((ndo, "}"));
1189                 if (s > end)
1190                         goto finish;
1191         }
1192
1193         for (i = 0; i < neg; i++) {
1194                 snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
1195                 if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
1196                         goto finish;
1197                 s += n;
1198                 ND_PRINT((ndo, " -{"));
1199                 fn_print(ndo, (u_char *)user, NULL);
1200                 ND_PRINT((ndo, " "));
1201                 ACLOUT(acl);
1202                 ND_PRINT((ndo, "}"));
1203                 if (s > end)
1204                         goto finish;
1205         }
1206
1207 finish:
1208         free(user);
1209         return;
1210 }
1211
1212 #undef ACLOUT
1213
1214 /*
1215  * Handle calls to the AFS callback service
1216  */
1217
1218 static void
1219 cb_print(netdissect_options *ndo,
1220          register const u_char *bp, int length)
1221 {
1222         int cb_op;
1223         unsigned long i;
1224
1225         if (length <= (int)sizeof(struct rx_header))
1226                 return;
1227
1228         if (ndo->ndo_snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1229                 goto trunc;
1230         }
1231
1232         /*
1233          * Print out the afs call we're invoking.  The table used here was
1234          * gleaned from fsint/afscbint.xg
1235          */
1236
1237         cb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1238
1239         ND_PRINT((ndo, " cb call %s", tok2str(cb_req, "op#%d", cb_op)));
1240
1241         bp += sizeof(struct rx_header) + 4;
1242
1243         /*
1244          * Print out the afs call we're invoking.  The table used here was
1245          * gleaned from fsint/afscbint.xg
1246          */
1247
1248         switch (cb_op) {
1249                 case 204:               /* Callback */
1250                 {
1251                         unsigned long j, t;
1252                         ND_TCHECK2(bp[0], 4);
1253                         j = EXTRACT_32BITS(bp);
1254                         bp += sizeof(int32_t);
1255
1256                         for (i = 0; i < j; i++) {
1257                                 FIDOUT();
1258                                 if (i != j - 1)
1259                                         ND_PRINT((ndo, ","));
1260                         }
1261
1262                         if (j == 0)
1263                                 ND_PRINT((ndo, " <none!>"));
1264
1265                         ND_TCHECK_32BITS(bp);
1266                         j = EXTRACT_32BITS(bp);
1267                         bp += sizeof(int32_t);
1268
1269                         if (j != 0)
1270                                 ND_PRINT((ndo, ";"));
1271
1272                         for (i = 0; i < j; i++) {
1273                                 ND_PRINT((ndo, " ver"));
1274                                 INTOUT();
1275                                 ND_PRINT((ndo, " expires"));
1276                                 DATEOUT();
1277                                 ND_TCHECK2(bp[0], 4);
1278                                 t = EXTRACT_32BITS(bp);
1279                                 bp += sizeof(int32_t);
1280                                 tok2str(cb_types, "type %d", t);
1281                         }
1282                 }
1283                 case 214: {
1284                         ND_PRINT((ndo, " afsuuid"));
1285                         AFSUUIDOUT();
1286                         break;
1287                 }
1288                 default:
1289                         ;
1290         }
1291
1292         return;
1293
1294 trunc:
1295         ND_PRINT((ndo, " [|cb]"));
1296 }
1297
1298 /*
1299  * Handle replies to the AFS Callback Service
1300  */
1301
1302 static void
1303 cb_reply_print(netdissect_options *ndo,
1304                register const u_char *bp, int length, int32_t opcode)
1305 {
1306         const struct rx_header *rxh;
1307
1308         if (length <= (int)sizeof(struct rx_header))
1309                 return;
1310
1311         rxh = (const struct rx_header *) bp;
1312
1313         /*
1314          * Print out the afs call we're invoking.  The table used here was
1315          * gleaned from fsint/afscbint.xg
1316          */
1317
1318         ND_PRINT((ndo, " cb reply %s", tok2str(cb_req, "op#%d", opcode)));
1319
1320         bp += sizeof(struct rx_header);
1321
1322         /*
1323          * If it was a data packet, interpret the response.
1324          */
1325
1326         if (rxh->type == RX_PACKET_TYPE_DATA)
1327                 switch (opcode) {
1328                 case 213:       /* InitCallBackState3 */
1329                         AFSUUIDOUT();
1330                         break;
1331                 default:
1332                 ;
1333                 }
1334         else {
1335                 /*
1336                  * Otherwise, just print out the return code
1337                  */
1338                 ND_PRINT((ndo, " errcode"));
1339                 INTOUT();
1340         }
1341
1342         return;
1343
1344 trunc:
1345         ND_PRINT((ndo, " [|cb]"));
1346 }
1347
1348 /*
1349  * Handle calls to the AFS protection database server
1350  */
1351
1352 static void
1353 prot_print(netdissect_options *ndo,
1354            register const u_char *bp, int length)
1355 {
1356         unsigned long i;
1357         int pt_op;
1358
1359         if (length <= (int)sizeof(struct rx_header))
1360                 return;
1361
1362         if (ndo->ndo_snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1363                 goto trunc;
1364         }
1365
1366         /*
1367          * Print out the afs call we're invoking.  The table used here was
1368          * gleaned from ptserver/ptint.xg
1369          */
1370
1371         pt_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1372
1373         ND_PRINT((ndo, " pt"));
1374
1375         if (is_ubik(pt_op)) {
1376                 ubik_print(ndo, bp);
1377                 return;
1378         }
1379
1380         ND_PRINT((ndo, " call %s", tok2str(pt_req, "op#%d", pt_op)));
1381
1382         /*
1383          * Decode some of the arguments to the PT calls
1384          */
1385
1386         bp += sizeof(struct rx_header) + 4;
1387
1388         switch (pt_op) {
1389                 case 500:       /* I New User */
1390                         STROUT(PRNAMEMAX);
1391                         ND_PRINT((ndo, " id"));
1392                         INTOUT();
1393                         ND_PRINT((ndo, " oldid"));
1394                         INTOUT();
1395                         break;
1396                 case 501:       /* Where is it */
1397                 case 506:       /* Delete */
1398                 case 508:       /* Get CPS */
1399                 case 512:       /* List entry */
1400                 case 514:       /* List elements */
1401                 case 517:       /* List owned */
1402                 case 518:       /* Get CPS2 */
1403                 case 519:       /* Get host CPS */
1404                 case 530:       /* List super groups */
1405                         ND_PRINT((ndo, " id"));
1406                         INTOUT();
1407                         break;
1408                 case 502:       /* Dump entry */
1409                         ND_PRINT((ndo, " pos"));
1410                         INTOUT();
1411                         break;
1412                 case 503:       /* Add to group */
1413                 case 507:       /* Remove from group */
1414                 case 515:       /* Is a member of? */
1415                         ND_PRINT((ndo, " uid"));
1416                         INTOUT();
1417                         ND_PRINT((ndo, " gid"));
1418                         INTOUT();
1419                         break;
1420                 case 504:       /* Name to ID */
1421                 {
1422                         unsigned long j;
1423                         ND_TCHECK2(bp[0], 4);
1424                         j = EXTRACT_32BITS(bp);
1425                         bp += sizeof(int32_t);
1426
1427                         /*
1428                          * Who designed this chicken-shit protocol?
1429                          *
1430                          * Each character is stored as a 32-bit
1431                          * integer!
1432                          */
1433
1434                         for (i = 0; i < j; i++) {
1435                                 VECOUT(PRNAMEMAX);
1436                         }
1437                         if (j == 0)
1438                                 ND_PRINT((ndo, " <none!>"));
1439                 }
1440                         break;
1441                 case 505:       /* Id to name */
1442                 {
1443                         unsigned long j;
1444                         ND_PRINT((ndo, " ids:"));
1445                         ND_TCHECK2(bp[0], 4);
1446                         i = EXTRACT_32BITS(bp);
1447                         bp += sizeof(int32_t);
1448                         for (j = 0; j < i; j++)
1449                                 INTOUT();
1450                         if (j == 0)
1451                                 ND_PRINT((ndo, " <none!>"));
1452                 }
1453                         break;
1454                 case 509:       /* New entry */
1455                         STROUT(PRNAMEMAX);
1456                         ND_PRINT((ndo, " flag"));
1457                         INTOUT();
1458                         ND_PRINT((ndo, " oid"));
1459                         INTOUT();
1460                         break;
1461                 case 511:       /* Set max */
1462                         ND_PRINT((ndo, " id"));
1463                         INTOUT();
1464                         ND_PRINT((ndo, " gflag"));
1465                         INTOUT();
1466                         break;
1467                 case 513:       /* Change entry */
1468                         ND_PRINT((ndo, " id"));
1469                         INTOUT();
1470                         STROUT(PRNAMEMAX);
1471                         ND_PRINT((ndo, " oldid"));
1472                         INTOUT();
1473                         ND_PRINT((ndo, " newid"));
1474                         INTOUT();
1475                         break;
1476                 case 520:       /* Update entry */
1477                         ND_PRINT((ndo, " id"));
1478                         INTOUT();
1479                         STROUT(PRNAMEMAX);
1480                         break;
1481                 default:
1482                         ;
1483         }
1484
1485
1486         return;
1487
1488 trunc:
1489         ND_PRINT((ndo, " [|pt]"));
1490 }
1491
1492 /*
1493  * Handle replies to the AFS protection service
1494  */
1495
1496 static void
1497 prot_reply_print(netdissect_options *ndo,
1498                  register const u_char *bp, int length, int32_t opcode)
1499 {
1500         const struct rx_header *rxh;
1501         unsigned long i;
1502
1503         if (length < (int)sizeof(struct rx_header))
1504                 return;
1505
1506         rxh = (const struct rx_header *) bp;
1507
1508         /*
1509          * Print out the afs call we're invoking.  The table used here was
1510          * gleaned from ptserver/ptint.xg.  Check to see if it's a
1511          * Ubik call, however.
1512          */
1513
1514         ND_PRINT((ndo, " pt"));
1515
1516         if (is_ubik(opcode)) {
1517                 ubik_reply_print(ndo, bp, length, opcode);
1518                 return;
1519         }
1520
1521         ND_PRINT((ndo, " reply %s", tok2str(pt_req, "op#%d", opcode)));
1522
1523         bp += sizeof(struct rx_header);
1524
1525         /*
1526          * If it was a data packet, interpret the response
1527          */
1528
1529         if (rxh->type == RX_PACKET_TYPE_DATA)
1530                 switch (opcode) {
1531                 case 504:               /* Name to ID */
1532                 {
1533                         unsigned long j;
1534                         ND_PRINT((ndo, " ids:"));
1535                         ND_TCHECK2(bp[0], 4);
1536                         i = EXTRACT_32BITS(bp);
1537                         bp += sizeof(int32_t);
1538                         for (j = 0; j < i; j++)
1539                                 INTOUT();
1540                         if (j == 0)
1541                                 ND_PRINT((ndo, " <none!>"));
1542                 }
1543                         break;
1544                 case 505:               /* ID to name */
1545                 {
1546                         unsigned long j;
1547                         ND_TCHECK2(bp[0], 4);
1548                         j = EXTRACT_32BITS(bp);
1549                         bp += sizeof(int32_t);
1550
1551                         /*
1552                          * Who designed this chicken-shit protocol?
1553                          *
1554                          * Each character is stored as a 32-bit
1555                          * integer!
1556                          */
1557
1558                         for (i = 0; i < j; i++) {
1559                                 VECOUT(PRNAMEMAX);
1560                         }
1561                         if (j == 0)
1562                                 ND_PRINT((ndo, " <none!>"));
1563                 }
1564                         break;
1565                 case 508:               /* Get CPS */
1566                 case 514:               /* List elements */
1567                 case 517:               /* List owned */
1568                 case 518:               /* Get CPS2 */
1569                 case 519:               /* Get host CPS */
1570                 {
1571                         unsigned long j;
1572                         ND_TCHECK2(bp[0], 4);
1573                         j = EXTRACT_32BITS(bp);
1574                         bp += sizeof(int32_t);
1575                         for (i = 0; i < j; i++) {
1576                                 INTOUT();
1577                         }
1578                         if (j == 0)
1579                                 ND_PRINT((ndo, " <none!>"));
1580                 }
1581                         break;
1582                 case 510:               /* List max */
1583                         ND_PRINT((ndo, " maxuid"));
1584                         INTOUT();
1585                         ND_PRINT((ndo, " maxgid"));
1586                         INTOUT();
1587                         break;
1588                 default:
1589                         ;
1590                 }
1591         else {
1592                 /*
1593                  * Otherwise, just print out the return code
1594                  */
1595                 ND_PRINT((ndo, " errcode"));
1596                 INTOUT();
1597         }
1598
1599         return;
1600
1601 trunc:
1602         ND_PRINT((ndo, " [|pt]"));
1603 }
1604
1605 /*
1606  * Handle calls to the AFS volume location database service
1607  */
1608
1609 static void
1610 vldb_print(netdissect_options *ndo,
1611            register const u_char *bp, int length)
1612 {
1613         int vldb_op;
1614         unsigned long i;
1615
1616         if (length <= (int)sizeof(struct rx_header))
1617                 return;
1618
1619         if (ndo->ndo_snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1620                 goto trunc;
1621         }
1622
1623         /*
1624          * Print out the afs call we're invoking.  The table used here was
1625          * gleaned from vlserver/vldbint.xg
1626          */
1627
1628         vldb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1629
1630         ND_PRINT((ndo, " vldb"));
1631
1632         if (is_ubik(vldb_op)) {
1633                 ubik_print(ndo, bp);
1634                 return;
1635         }
1636         ND_PRINT((ndo, " call %s", tok2str(vldb_req, "op#%d", vldb_op)));
1637
1638         /*
1639          * Decode some of the arguments to the VLDB calls
1640          */
1641
1642         bp += sizeof(struct rx_header) + 4;
1643
1644         switch (vldb_op) {
1645                 case 501:       /* Create new volume */
1646                 case 517:       /* Create entry N */
1647                         VECOUT(VLNAMEMAX);
1648                         break;
1649                 case 502:       /* Delete entry */
1650                 case 503:       /* Get entry by ID */
1651                 case 507:       /* Update entry */
1652                 case 508:       /* Set lock */
1653                 case 509:       /* Release lock */
1654                 case 518:       /* Get entry by ID N */
1655                         ND_PRINT((ndo, " volid"));
1656                         INTOUT();
1657                         ND_TCHECK2(bp[0], sizeof(int32_t));
1658                         i = EXTRACT_32BITS(bp);
1659                         bp += sizeof(int32_t);
1660                         if (i <= 2)
1661                                 ND_PRINT((ndo, " type %s", voltype[i]));
1662                         break;
1663                 case 504:       /* Get entry by name */
1664                 case 519:       /* Get entry by name N */
1665                 case 524:       /* Update entry by name */
1666                 case 527:       /* Get entry by name U */
1667                         STROUT(VLNAMEMAX);
1668                         break;
1669                 case 505:       /* Get new vol id */
1670                         ND_PRINT((ndo, " bump"));
1671                         INTOUT();
1672                         break;
1673                 case 506:       /* Replace entry */
1674                 case 520:       /* Replace entry N */
1675                         ND_PRINT((ndo, " volid"));
1676                         INTOUT();
1677                         ND_TCHECK2(bp[0], sizeof(int32_t));
1678                         i = EXTRACT_32BITS(bp);
1679                         bp += sizeof(int32_t);
1680                         if (i <= 2)
1681                                 ND_PRINT((ndo, " type %s", voltype[i]));
1682                         VECOUT(VLNAMEMAX);
1683                         break;
1684                 case 510:       /* List entry */
1685                 case 521:       /* List entry N */
1686                         ND_PRINT((ndo, " index"));
1687                         INTOUT();
1688                         break;
1689                 default:
1690                         ;
1691         }
1692
1693         return;
1694
1695 trunc:
1696         ND_PRINT((ndo, " [|vldb]"));
1697 }
1698
1699 /*
1700  * Handle replies to the AFS volume location database service
1701  */
1702
1703 static void
1704 vldb_reply_print(netdissect_options *ndo,
1705                  register const u_char *bp, int length, int32_t opcode)
1706 {
1707         const struct rx_header *rxh;
1708         unsigned long i;
1709
1710         if (length < (int)sizeof(struct rx_header))
1711                 return;
1712
1713         rxh = (const struct rx_header *) bp;
1714
1715         /*
1716          * Print out the afs call we're invoking.  The table used here was
1717          * gleaned from vlserver/vldbint.xg.  Check to see if it's a
1718          * Ubik call, however.
1719          */
1720
1721         ND_PRINT((ndo, " vldb"));
1722
1723         if (is_ubik(opcode)) {
1724                 ubik_reply_print(ndo, bp, length, opcode);
1725                 return;
1726         }
1727
1728         ND_PRINT((ndo, " reply %s", tok2str(vldb_req, "op#%d", opcode)));
1729
1730         bp += sizeof(struct rx_header);
1731
1732         /*
1733          * If it was a data packet, interpret the response
1734          */
1735
1736         if (rxh->type == RX_PACKET_TYPE_DATA)
1737                 switch (opcode) {
1738                 case 510:       /* List entry */
1739                         ND_PRINT((ndo, " count"));
1740                         INTOUT();
1741                         ND_PRINT((ndo, " nextindex"));
1742                         INTOUT();
1743                 case 503:       /* Get entry by id */
1744                 case 504:       /* Get entry by name */
1745                 {       unsigned long nservers, j;
1746                         VECOUT(VLNAMEMAX);
1747                         ND_TCHECK2(bp[0], sizeof(int32_t));
1748                         bp += sizeof(int32_t);
1749                         ND_PRINT((ndo, " numservers"));
1750                         ND_TCHECK2(bp[0], sizeof(int32_t));
1751                         nservers = EXTRACT_32BITS(bp);
1752                         bp += sizeof(int32_t);
1753                         ND_PRINT((ndo, " %lu", nservers));
1754                         ND_PRINT((ndo, " servers"));
1755                         for (i = 0; i < 8; i++) {
1756                                 ND_TCHECK2(bp[0], sizeof(int32_t));
1757                                 if (i < nservers)
1758                                         ND_PRINT((ndo, " %s",
1759                                            intoa(((const struct in_addr *) bp)->s_addr)));
1760                                 bp += sizeof(int32_t);
1761                         }
1762                         ND_PRINT((ndo, " partitions"));
1763                         for (i = 0; i < 8; i++) {
1764                                 ND_TCHECK2(bp[0], sizeof(int32_t));
1765                                 j = EXTRACT_32BITS(bp);
1766                                 if (i < nservers && j <= 26)
1767                                         ND_PRINT((ndo, " %c", 'a' + (int)j));
1768                                 else if (i < nservers)
1769                                         ND_PRINT((ndo, " %lu", j));
1770                                 bp += sizeof(int32_t);
1771                         }
1772                         ND_TCHECK2(bp[0], 8 * sizeof(int32_t));
1773                         bp += 8 * sizeof(int32_t);
1774                         ND_PRINT((ndo, " rwvol"));
1775                         UINTOUT();
1776                         ND_PRINT((ndo, " rovol"));
1777                         UINTOUT();
1778                         ND_PRINT((ndo, " backup"));
1779                         UINTOUT();
1780                 }
1781                         break;
1782                 case 505:       /* Get new volume ID */
1783                         ND_PRINT((ndo, " newvol"));
1784                         UINTOUT();
1785                         break;
1786                 case 521:       /* List entry */
1787                 case 529:       /* List entry U */
1788                         ND_PRINT((ndo, " count"));
1789                         INTOUT();
1790                         ND_PRINT((ndo, " nextindex"));
1791                         INTOUT();
1792                 case 518:       /* Get entry by ID N */
1793                 case 519:       /* Get entry by name N */
1794                 {       unsigned long nservers, j;
1795                         VECOUT(VLNAMEMAX);
1796                         ND_PRINT((ndo, " numservers"));
1797                         ND_TCHECK2(bp[0], sizeof(int32_t));
1798                         nservers = EXTRACT_32BITS(bp);
1799                         bp += sizeof(int32_t);
1800                         ND_PRINT((ndo, " %lu", nservers));
1801                         ND_PRINT((ndo, " servers"));
1802                         for (i = 0; i < 13; i++) {
1803                                 ND_TCHECK2(bp[0], sizeof(int32_t));
1804                                 if (i < nservers)
1805                                         ND_PRINT((ndo, " %s",
1806                                            intoa(((const struct in_addr *) bp)->s_addr)));
1807                                 bp += sizeof(int32_t);
1808                         }
1809                         ND_PRINT((ndo, " partitions"));
1810                         for (i = 0; i < 13; i++) {
1811                                 ND_TCHECK2(bp[0], sizeof(int32_t));
1812                                 j = EXTRACT_32BITS(bp);
1813                                 if (i < nservers && j <= 26)
1814                                         ND_PRINT((ndo, " %c", 'a' + (int)j));
1815                                 else if (i < nservers)
1816                                         ND_PRINT((ndo, " %lu", j));
1817                                 bp += sizeof(int32_t);
1818                         }
1819                         ND_TCHECK2(bp[0], 13 * sizeof(int32_t));
1820                         bp += 13 * sizeof(int32_t);
1821                         ND_PRINT((ndo, " rwvol"));
1822                         UINTOUT();
1823                         ND_PRINT((ndo, " rovol"));
1824                         UINTOUT();
1825                         ND_PRINT((ndo, " backup"));
1826                         UINTOUT();
1827                 }
1828                         break;
1829                 case 526:       /* Get entry by ID U */
1830                 case 527:       /* Get entry by name U */
1831                 {       unsigned long nservers, j;
1832                         VECOUT(VLNAMEMAX);
1833                         ND_PRINT((ndo, " numservers"));
1834                         ND_TCHECK2(bp[0], sizeof(int32_t));
1835                         nservers = EXTRACT_32BITS(bp);
1836                         bp += sizeof(int32_t);
1837                         ND_PRINT((ndo, " %lu", nservers));
1838                         ND_PRINT((ndo, " servers"));
1839                         for (i = 0; i < 13; i++) {
1840                                 if (i < nservers) {
1841                                         ND_PRINT((ndo, " afsuuid"));
1842                                         AFSUUIDOUT();
1843                                 } else {
1844                                         ND_TCHECK2(bp[0], 44);
1845                                         bp += 44;
1846                                 }
1847                         }
1848                         ND_TCHECK2(bp[0], 4 * 13);
1849                         bp += 4 * 13;
1850                         ND_PRINT((ndo, " partitions"));
1851                         for (i = 0; i < 13; i++) {
1852                                 ND_TCHECK2(bp[0], sizeof(int32_t));
1853                                 j = EXTRACT_32BITS(bp);
1854                                 if (i < nservers && j <= 26)
1855                                         ND_PRINT((ndo, " %c", 'a' + (int)j));
1856                                 else if (i < nservers)
1857                                         ND_PRINT((ndo, " %lu", j));
1858                                 bp += sizeof(int32_t);
1859                         }
1860                         ND_TCHECK2(bp[0], 13 * sizeof(int32_t));
1861                         bp += 13 * sizeof(int32_t);
1862                         ND_PRINT((ndo, " rwvol"));
1863                         UINTOUT();
1864                         ND_PRINT((ndo, " rovol"));
1865                         UINTOUT();
1866                         ND_PRINT((ndo, " backup"));
1867                         UINTOUT();
1868                 }
1869                 default:
1870                         ;
1871                 }
1872
1873         else {
1874                 /*
1875                  * Otherwise, just print out the return code
1876                  */
1877                 ND_PRINT((ndo, " errcode"));
1878                 INTOUT();
1879         }
1880
1881         return;
1882
1883 trunc:
1884         ND_PRINT((ndo, " [|vldb]"));
1885 }
1886
1887 /*
1888  * Handle calls to the AFS Kerberos Authentication service
1889  */
1890
1891 static void
1892 kauth_print(netdissect_options *ndo,
1893             register const u_char *bp, int length)
1894 {
1895         int kauth_op;
1896
1897         if (length <= (int)sizeof(struct rx_header))
1898                 return;
1899
1900         if (ndo->ndo_snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1901                 goto trunc;
1902         }
1903
1904         /*
1905          * Print out the afs call we're invoking.  The table used here was
1906          * gleaned from kauth/kauth.rg
1907          */
1908
1909         kauth_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1910
1911         ND_PRINT((ndo, " kauth"));
1912
1913         if (is_ubik(kauth_op)) {
1914                 ubik_print(ndo, bp);
1915                 return;
1916         }
1917
1918
1919         ND_PRINT((ndo, " call %s", tok2str(kauth_req, "op#%d", kauth_op)));
1920
1921         /*
1922          * Decode some of the arguments to the KA calls
1923          */
1924
1925         bp += sizeof(struct rx_header) + 4;
1926
1927         switch (kauth_op) {
1928                 case 1:         /* Authenticate old */
1929                 case 21:        /* Authenticate */
1930                 case 22:        /* Authenticate-V2 */
1931                 case 2:         /* Change PW */
1932                 case 5:         /* Set fields */
1933                 case 6:         /* Create user */
1934                 case 7:         /* Delete user */
1935                 case 8:         /* Get entry */
1936                 case 14:        /* Unlock */
1937                 case 15:        /* Lock status */
1938                         ND_PRINT((ndo, " principal"));
1939                         STROUT(KANAMEMAX);
1940                         STROUT(KANAMEMAX);
1941                         break;
1942                 case 3:         /* GetTicket-old */
1943                 case 23:        /* GetTicket */
1944                 {
1945                         int i;
1946                         ND_PRINT((ndo, " kvno"));
1947                         INTOUT();
1948                         ND_PRINT((ndo, " domain"));
1949                         STROUT(KANAMEMAX);
1950                         ND_TCHECK2(bp[0], sizeof(int32_t));
1951                         i = (int) EXTRACT_32BITS(bp);
1952                         bp += sizeof(int32_t);
1953                         ND_TCHECK2(bp[0], i);
1954                         bp += i;
1955                         ND_PRINT((ndo, " principal"));
1956                         STROUT(KANAMEMAX);
1957                         STROUT(KANAMEMAX);
1958                         break;
1959                 }
1960                 case 4:         /* Set Password */
1961                         ND_PRINT((ndo, " principal"));
1962                         STROUT(KANAMEMAX);
1963                         STROUT(KANAMEMAX);
1964                         ND_PRINT((ndo, " kvno"));
1965                         INTOUT();
1966                         break;
1967                 case 12:        /* Get password */
1968                         ND_PRINT((ndo, " name"));
1969                         STROUT(KANAMEMAX);
1970                         break;
1971                 default:
1972                         ;
1973         }
1974
1975         return;
1976
1977 trunc:
1978         ND_PRINT((ndo, " [|kauth]"));
1979 }
1980
1981 /*
1982  * Handle replies to the AFS Kerberos Authentication Service
1983  */
1984
1985 static void
1986 kauth_reply_print(netdissect_options *ndo,
1987                   register const u_char *bp, int length, int32_t opcode)
1988 {
1989         const struct rx_header *rxh;
1990
1991         if (length <= (int)sizeof(struct rx_header))
1992                 return;
1993
1994         rxh = (const struct rx_header *) bp;
1995
1996         /*
1997          * Print out the afs call we're invoking.  The table used here was
1998          * gleaned from kauth/kauth.rg
1999          */
2000
2001         ND_PRINT((ndo, " kauth"));
2002
2003         if (is_ubik(opcode)) {
2004                 ubik_reply_print(ndo, bp, length, opcode);
2005                 return;
2006         }
2007
2008         ND_PRINT((ndo, " reply %s", tok2str(kauth_req, "op#%d", opcode)));
2009
2010         bp += sizeof(struct rx_header);
2011
2012         /*
2013          * If it was a data packet, interpret the response.
2014          */
2015
2016         if (rxh->type == RX_PACKET_TYPE_DATA)
2017                 /* Well, no, not really.  Leave this for later */
2018                 ;
2019         else {
2020                 /*
2021                  * Otherwise, just print out the return code
2022                  */
2023                 ND_PRINT((ndo, " errcode"));
2024                 INTOUT();
2025         }
2026
2027         return;
2028
2029 trunc:
2030         ND_PRINT((ndo, " [|kauth]"));
2031 }
2032
2033 /*
2034  * Handle calls to the AFS Volume location service
2035  */
2036
2037 static void
2038 vol_print(netdissect_options *ndo,
2039           register const u_char *bp, int length)
2040 {
2041         int vol_op;
2042
2043         if (length <= (int)sizeof(struct rx_header))
2044                 return;
2045
2046         if (ndo->ndo_snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
2047                 goto trunc;
2048         }
2049
2050         /*
2051          * Print out the afs call we're invoking.  The table used here was
2052          * gleaned from volser/volint.xg
2053          */
2054
2055         vol_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
2056
2057         ND_PRINT((ndo, " vol call %s", tok2str(vol_req, "op#%d", vol_op)));
2058
2059         bp += sizeof(struct rx_header) + 4;
2060
2061         switch (vol_op) {
2062                 case 100:       /* Create volume */
2063                         ND_PRINT((ndo, " partition"));
2064                         UINTOUT();
2065                         ND_PRINT((ndo, " name"));
2066                         STROUT(AFSNAMEMAX);
2067                         ND_PRINT((ndo, " type"));
2068                         UINTOUT();
2069                         ND_PRINT((ndo, " parent"));
2070                         UINTOUT();
2071                         break;
2072                 case 101:       /* Delete volume */
2073                 case 107:       /* Get flags */
2074                         ND_PRINT((ndo, " trans"));
2075                         UINTOUT();
2076                         break;
2077                 case 102:       /* Restore */
2078                         ND_PRINT((ndo, " totrans"));
2079                         UINTOUT();
2080                         ND_PRINT((ndo, " flags"));
2081                         UINTOUT();
2082                         break;
2083                 case 103:       /* Forward */
2084                         ND_PRINT((ndo, " fromtrans"));
2085                         UINTOUT();
2086                         ND_PRINT((ndo, " fromdate"));
2087                         DATEOUT();
2088                         DESTSERVEROUT();
2089                         ND_PRINT((ndo, " desttrans"));
2090                         INTOUT();
2091                         break;
2092                 case 104:       /* End trans */
2093                         ND_PRINT((ndo, " trans"));
2094                         UINTOUT();
2095                         break;
2096                 case 105:       /* Clone */
2097                         ND_PRINT((ndo, " trans"));
2098                         UINTOUT();
2099                         ND_PRINT((ndo, " purgevol"));
2100                         UINTOUT();
2101                         ND_PRINT((ndo, " newtype"));
2102                         UINTOUT();
2103                         ND_PRINT((ndo, " newname"));
2104                         STROUT(AFSNAMEMAX);
2105                         break;
2106                 case 106:       /* Set flags */
2107                         ND_PRINT((ndo, " trans"));
2108                         UINTOUT();
2109                         ND_PRINT((ndo, " flags"));
2110                         UINTOUT();
2111                         break;
2112                 case 108:       /* Trans create */
2113                         ND_PRINT((ndo, " vol"));
2114                         UINTOUT();
2115                         ND_PRINT((ndo, " partition"));
2116                         UINTOUT();
2117                         ND_PRINT((ndo, " flags"));
2118                         UINTOUT();
2119                         break;
2120                 case 109:       /* Dump */
2121                 case 655537:    /* Get size */
2122                         ND_PRINT((ndo, " fromtrans"));
2123                         UINTOUT();
2124                         ND_PRINT((ndo, " fromdate"));
2125                         DATEOUT();
2126                         break;
2127                 case 110:       /* Get n-th volume */
2128                         ND_PRINT((ndo, " index"));
2129                         UINTOUT();
2130                         break;
2131                 case 111:       /* Set forwarding */
2132                         ND_PRINT((ndo, " tid"));
2133                         UINTOUT();
2134                         ND_PRINT((ndo, " newsite"));
2135                         UINTOUT();
2136                         break;
2137                 case 112:       /* Get name */
2138                 case 113:       /* Get status */
2139                         ND_PRINT((ndo, " tid"));
2140                         break;
2141                 case 114:       /* Signal restore */
2142                         ND_PRINT((ndo, " name"));
2143                         STROUT(AFSNAMEMAX);
2144                         ND_PRINT((ndo, " type"));
2145                         UINTOUT();
2146                         ND_PRINT((ndo, " pid"));
2147                         UINTOUT();
2148                         ND_PRINT((ndo, " cloneid"));
2149                         UINTOUT();
2150                         break;
2151                 case 116:       /* List volumes */
2152                         ND_PRINT((ndo, " partition"));
2153                         UINTOUT();
2154                         ND_PRINT((ndo, " flags"));
2155                         UINTOUT();
2156                         break;
2157                 case 117:       /* Set id types */
2158                         ND_PRINT((ndo, " tid"));
2159                         UINTOUT();
2160                         ND_PRINT((ndo, " name"));
2161                         STROUT(AFSNAMEMAX);
2162                         ND_PRINT((ndo, " type"));
2163                         UINTOUT();
2164                         ND_PRINT((ndo, " pid"));
2165                         UINTOUT();
2166                         ND_PRINT((ndo, " clone"));
2167                         UINTOUT();
2168                         ND_PRINT((ndo, " backup"));
2169                         UINTOUT();
2170                         break;
2171                 case 119:       /* Partition info */
2172                         ND_PRINT((ndo, " name"));
2173                         STROUT(AFSNAMEMAX);
2174                         break;
2175                 case 120:       /* Reclone */
2176                         ND_PRINT((ndo, " tid"));
2177                         UINTOUT();
2178                         break;
2179                 case 121:       /* List one volume */
2180                 case 122:       /* Nuke volume */
2181                 case 124:       /* Extended List volumes */
2182                 case 125:       /* Extended List one volume */
2183                 case 65536:     /* Convert RO to RW volume */
2184                         ND_PRINT((ndo, " partid"));
2185                         UINTOUT();
2186                         ND_PRINT((ndo, " volid"));
2187                         UINTOUT();
2188                         break;
2189                 case 123:       /* Set date */
2190                         ND_PRINT((ndo, " tid"));
2191                         UINTOUT();
2192                         ND_PRINT((ndo, " date"));
2193                         DATEOUT();
2194                         break;
2195                 case 126:       /* Set info */
2196                         ND_PRINT((ndo, " tid"));
2197                         UINTOUT();
2198                         break;
2199                 case 128:       /* Forward multiple */
2200                         ND_PRINT((ndo, " fromtrans"));
2201                         UINTOUT();
2202                         ND_PRINT((ndo, " fromdate"));
2203                         DATEOUT();
2204                         {
2205                                 unsigned long i, j;
2206                                 ND_TCHECK2(bp[0], 4);
2207                                 j = EXTRACT_32BITS(bp);
2208                                 bp += sizeof(int32_t);
2209                                 for (i = 0; i < j; i++) {
2210                                         DESTSERVEROUT();
2211                                         if (i != j - 1)
2212                                                 ND_PRINT((ndo, ","));
2213                                 }
2214                                 if (j == 0)
2215                                         ND_PRINT((ndo, " <none!>"));
2216                         }
2217                         break;
2218                 case 65538:     /* Dump version 2 */
2219                         ND_PRINT((ndo, " fromtrans"));
2220                         UINTOUT();
2221                         ND_PRINT((ndo, " fromdate"));
2222                         DATEOUT();
2223                         ND_PRINT((ndo, " flags"));
2224                         UINTOUT();
2225                         break;
2226                 default:
2227                         ;
2228         }
2229         return;
2230
2231 trunc:
2232         ND_PRINT((ndo, " [|vol]"));
2233 }
2234
2235 /*
2236  * Handle replies to the AFS Volume Service
2237  */
2238
2239 static void
2240 vol_reply_print(netdissect_options *ndo,
2241                 register const u_char *bp, int length, int32_t opcode)
2242 {
2243         const struct rx_header *rxh;
2244
2245         if (length <= (int)sizeof(struct rx_header))
2246                 return;
2247
2248         rxh = (const struct rx_header *) bp;
2249
2250         /*
2251          * Print out the afs call we're invoking.  The table used here was
2252          * gleaned from volser/volint.xg
2253          */
2254
2255         ND_PRINT((ndo, " vol reply %s", tok2str(vol_req, "op#%d", opcode)));
2256
2257         bp += sizeof(struct rx_header);
2258
2259         /*
2260          * If it was a data packet, interpret the response.
2261          */
2262
2263         if (rxh->type == RX_PACKET_TYPE_DATA) {
2264                 switch (opcode) {
2265                         case 100:       /* Create volume */
2266                                 ND_PRINT((ndo, " volid"));
2267                                 UINTOUT();
2268                                 ND_PRINT((ndo, " trans"));
2269                                 UINTOUT();
2270                                 break;
2271                         case 104:       /* End transaction */
2272                                 UINTOUT();
2273                                 break;
2274                         case 105:       /* Clone */
2275                                 ND_PRINT((ndo, " newvol"));
2276                                 UINTOUT();
2277                                 break;
2278                         case 107:       /* Get flags */
2279                                 UINTOUT();
2280                                 break;
2281                         case 108:       /* Transaction create */
2282                                 ND_PRINT((ndo, " trans"));
2283                                 UINTOUT();
2284                                 break;
2285                         case 110:       /* Get n-th volume */
2286                                 ND_PRINT((ndo, " volume"));
2287                                 UINTOUT();
2288                                 ND_PRINT((ndo, " partition"));
2289                                 UINTOUT();
2290                                 break;
2291                         case 112:       /* Get name */
2292                                 STROUT(AFSNAMEMAX);
2293                                 break;
2294                         case 113:       /* Get status */
2295                                 ND_PRINT((ndo, " volid"));
2296                                 UINTOUT();
2297                                 ND_PRINT((ndo, " nextuniq"));
2298                                 UINTOUT();
2299                                 ND_PRINT((ndo, " type"));
2300                                 UINTOUT();
2301                                 ND_PRINT((ndo, " parentid"));
2302                                 UINTOUT();
2303                                 ND_PRINT((ndo, " clone"));
2304                                 UINTOUT();
2305                                 ND_PRINT((ndo, " backup"));
2306                                 UINTOUT();
2307                                 ND_PRINT((ndo, " restore"));
2308                                 UINTOUT();
2309                                 ND_PRINT((ndo, " maxquota"));
2310                                 UINTOUT();
2311                                 ND_PRINT((ndo, " minquota"));
2312                                 UINTOUT();
2313                                 ND_PRINT((ndo, " owner"));
2314                                 UINTOUT();
2315                                 ND_PRINT((ndo, " create"));
2316                                 DATEOUT();
2317                                 ND_PRINT((ndo, " access"));
2318                                 DATEOUT();
2319                                 ND_PRINT((ndo, " update"));
2320                                 DATEOUT();
2321                                 ND_PRINT((ndo, " expire"));
2322                                 DATEOUT();
2323                                 ND_PRINT((ndo, " backup"));
2324                                 DATEOUT();
2325                                 ND_PRINT((ndo, " copy"));
2326                                 DATEOUT();
2327                                 break;
2328                         case 115:       /* Old list partitions */
2329                                 break;
2330                         case 116:       /* List volumes */
2331                         case 121:       /* List one volume */
2332                                 {
2333                                         unsigned long i, j;
2334                                         ND_TCHECK2(bp[0], 4);
2335                                         j = EXTRACT_32BITS(bp);
2336                                         bp += sizeof(int32_t);
2337                                         for (i = 0; i < j; i++) {
2338                                                 ND_PRINT((ndo, " name"));
2339                                                 VECOUT(32);
2340                                                 ND_PRINT((ndo, " volid"));
2341                                                 UINTOUT();
2342                                                 ND_PRINT((ndo, " type"));
2343                                                 bp += sizeof(int32_t) * 21;
2344                                                 if (i != j - 1)
2345                                                         ND_PRINT((ndo, ","));
2346                                         }
2347                                         if (j == 0)
2348                                                 ND_PRINT((ndo, " <none!>"));
2349                                 }
2350                                 break;
2351
2352
2353                         default:
2354                                 ;
2355                 }
2356         } else {
2357                 /*
2358                  * Otherwise, just print out the return code
2359                  */
2360                 ND_PRINT((ndo, " errcode"));
2361                 INTOUT();
2362         }
2363
2364         return;
2365
2366 trunc:
2367         ND_PRINT((ndo, " [|vol]"));
2368 }
2369
2370 /*
2371  * Handle calls to the AFS BOS service
2372  */
2373
2374 static void
2375 bos_print(netdissect_options *ndo,
2376           register const u_char *bp, int length)
2377 {
2378         int bos_op;
2379
2380         if (length <= (int)sizeof(struct rx_header))
2381                 return;
2382
2383         if (ndo->ndo_snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
2384                 goto trunc;
2385         }
2386
2387         /*
2388          * Print out the afs call we're invoking.  The table used here was
2389          * gleaned from bozo/bosint.xg
2390          */
2391
2392         bos_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
2393
2394         ND_PRINT((ndo, " bos call %s", tok2str(bos_req, "op#%d", bos_op)));
2395
2396         /*
2397          * Decode some of the arguments to the BOS calls
2398          */
2399
2400         bp += sizeof(struct rx_header) + 4;
2401
2402         switch (bos_op) {
2403                 case 80:        /* Create B node */
2404                         ND_PRINT((ndo, " type"));
2405                         STROUT(BOSNAMEMAX);
2406                         ND_PRINT((ndo, " instance"));
2407                         STROUT(BOSNAMEMAX);
2408                         break;
2409                 case 81:        /* Delete B node */
2410                 case 83:        /* Get status */
2411                 case 85:        /* Get instance info */
2412                 case 87:        /* Add super user */
2413                 case 88:        /* Delete super user */
2414                 case 93:        /* Set cell name */
2415                 case 96:        /* Add cell host */
2416                 case 97:        /* Delete cell host */
2417                 case 104:       /* Restart */
2418                 case 106:       /* Uninstall */
2419                 case 108:       /* Exec */
2420                 case 112:       /* Getlog */
2421                 case 114:       /* Get instance strings */
2422                         STROUT(BOSNAMEMAX);
2423                         break;
2424                 case 82:        /* Set status */
2425                 case 98:        /* Set T status */
2426                         STROUT(BOSNAMEMAX);
2427                         ND_PRINT((ndo, " status"));
2428                         INTOUT();
2429                         break;
2430                 case 86:        /* Get instance parm */
2431                         STROUT(BOSNAMEMAX);
2432                         ND_PRINT((ndo, " num"));
2433                         INTOUT();
2434                         break;
2435                 case 84:        /* Enumerate instance */
2436                 case 89:        /* List super users */
2437                 case 90:        /* List keys */
2438                 case 91:        /* Add key */
2439                 case 92:        /* Delete key */
2440                 case 95:        /* Get cell host */
2441                         INTOUT();
2442                         break;
2443                 case 105:       /* Install */
2444                         STROUT(BOSNAMEMAX);
2445                         ND_PRINT((ndo, " size"));
2446                         INTOUT();
2447                         ND_PRINT((ndo, " flags"));
2448                         INTOUT();
2449                         ND_PRINT((ndo, " date"));
2450                         INTOUT();
2451                         break;
2452                 default:
2453                         ;
2454         }
2455
2456         return;
2457
2458 trunc:
2459         ND_PRINT((ndo, " [|bos]"));
2460 }
2461
2462 /*
2463  * Handle replies to the AFS BOS Service
2464  */
2465
2466 static void
2467 bos_reply_print(netdissect_options *ndo,
2468                 register const u_char *bp, int length, int32_t opcode)
2469 {
2470         const struct rx_header *rxh;
2471
2472         if (length <= (int)sizeof(struct rx_header))
2473                 return;
2474
2475         rxh = (const struct rx_header *) bp;
2476
2477         /*
2478          * Print out the afs call we're invoking.  The table used here was
2479          * gleaned from volser/volint.xg
2480          */
2481
2482         ND_PRINT((ndo, " bos reply %s", tok2str(bos_req, "op#%d", opcode)));
2483
2484         bp += sizeof(struct rx_header);
2485
2486         /*
2487          * If it was a data packet, interpret the response.
2488          */
2489
2490         if (rxh->type == RX_PACKET_TYPE_DATA)
2491                 /* Well, no, not really.  Leave this for later */
2492                 ;
2493         else {
2494                 /*
2495                  * Otherwise, just print out the return code
2496                  */
2497                 ND_PRINT((ndo, " errcode"));
2498                 INTOUT();
2499         }
2500
2501         return;
2502
2503 trunc:
2504         ND_PRINT((ndo, " [|bos]"));
2505 }
2506
2507 /*
2508  * Check to see if this is a Ubik opcode.
2509  */
2510
2511 static int
2512 is_ubik(uint32_t opcode)
2513 {
2514         if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) ||
2515             (opcode >= DISK_LOW && opcode <= DISK_HIGH))
2516                 return(1);
2517         else
2518                 return(0);
2519 }
2520
2521 /*
2522  * Handle Ubik opcodes to any one of the replicated database services
2523  */
2524
2525 static void
2526 ubik_print(netdissect_options *ndo,
2527            register const u_char *bp)
2528 {
2529         int ubik_op;
2530         int32_t temp;
2531
2532         /*
2533          * Print out the afs call we're invoking.  The table used here was
2534          * gleaned from ubik/ubik_int.xg
2535          */
2536
2537         /* Every function that calls this function first makes a bounds check
2538          * for (sizeof(rx_header) + 4) bytes, so long as it remains this way
2539          * the line below will not over-read.
2540          */
2541         ubik_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
2542
2543         ND_PRINT((ndo, " ubik call %s", tok2str(ubik_req, "op#%d", ubik_op)));
2544
2545         /*
2546          * Decode some of the arguments to the Ubik calls
2547          */
2548
2549         bp += sizeof(struct rx_header) + 4;
2550
2551         switch (ubik_op) {
2552                 case 10000:             /* Beacon */
2553                         ND_TCHECK2(bp[0], 4);
2554                         temp = EXTRACT_32BITS(bp);
2555                         bp += sizeof(int32_t);
2556                         ND_PRINT((ndo, " syncsite %s", temp ? "yes" : "no"));
2557                         ND_PRINT((ndo, " votestart"));
2558                         DATEOUT();
2559                         ND_PRINT((ndo, " dbversion"));
2560                         UBIK_VERSIONOUT();
2561                         ND_PRINT((ndo, " tid"));
2562                         UBIK_VERSIONOUT();
2563                         break;
2564                 case 10003:             /* Get sync site */
2565                         ND_PRINT((ndo, " site"));
2566                         UINTOUT();
2567                         break;
2568                 case 20000:             /* Begin */
2569                 case 20001:             /* Commit */
2570                 case 20007:             /* Abort */
2571                 case 20008:             /* Release locks */
2572                 case 20010:             /* Writev */
2573                         ND_PRINT((ndo, " tid"));
2574                         UBIK_VERSIONOUT();
2575                         break;
2576                 case 20002:             /* Lock */
2577                         ND_PRINT((ndo, " tid"));
2578                         UBIK_VERSIONOUT();
2579                         ND_PRINT((ndo, " file"));
2580                         INTOUT();
2581                         ND_PRINT((ndo, " pos"));
2582                         INTOUT();
2583                         ND_PRINT((ndo, " length"));
2584                         INTOUT();
2585                         ND_TCHECK_32BITS(bp);
2586                         temp = EXTRACT_32BITS(bp);
2587                         bp += sizeof(int32_t);
2588                         tok2str(ubik_lock_types, "type %d", temp);
2589                         break;
2590                 case 20003:             /* Write */
2591                         ND_PRINT((ndo, " tid"));
2592                         UBIK_VERSIONOUT();
2593                         ND_PRINT((ndo, " file"));
2594                         INTOUT();
2595                         ND_PRINT((ndo, " pos"));
2596                         INTOUT();
2597                         break;
2598                 case 20005:             /* Get file */
2599                         ND_PRINT((ndo, " file"));
2600                         INTOUT();
2601                         break;
2602                 case 20006:             /* Send file */
2603                         ND_PRINT((ndo, " file"));
2604                         INTOUT();
2605                         ND_PRINT((ndo, " length"));
2606                         INTOUT();
2607                         ND_PRINT((ndo, " dbversion"));
2608                         UBIK_VERSIONOUT();
2609                         break;
2610                 case 20009:             /* Truncate */
2611                         ND_PRINT((ndo, " tid"));
2612                         UBIK_VERSIONOUT();
2613                         ND_PRINT((ndo, " file"));
2614                         INTOUT();
2615                         ND_PRINT((ndo, " length"));
2616                         INTOUT();
2617                         break;
2618                 case 20012:             /* Set version */
2619                         ND_PRINT((ndo, " tid"));
2620                         UBIK_VERSIONOUT();
2621                         ND_PRINT((ndo, " oldversion"));
2622                         UBIK_VERSIONOUT();
2623                         ND_PRINT((ndo, " newversion"));
2624                         UBIK_VERSIONOUT();
2625                         break;
2626                 default:
2627                         ;
2628         }
2629
2630         return;
2631
2632 trunc:
2633         ND_PRINT((ndo, " [|ubik]"));
2634 }
2635
2636 /*
2637  * Handle Ubik replies to any one of the replicated database services
2638  */
2639
2640 static void
2641 ubik_reply_print(netdissect_options *ndo,
2642                  register const u_char *bp, int length, int32_t opcode)
2643 {
2644         const struct rx_header *rxh;
2645
2646         if (length < (int)sizeof(struct rx_header))
2647                 return;
2648
2649         rxh = (const struct rx_header *) bp;
2650
2651         /*
2652          * Print out the ubik call we're invoking.  This table was gleaned
2653          * from ubik/ubik_int.xg
2654          */
2655
2656         ND_PRINT((ndo, " ubik reply %s", tok2str(ubik_req, "op#%d", opcode)));
2657
2658         bp += sizeof(struct rx_header);
2659
2660         /*
2661          * If it was a data packet, print out the arguments to the Ubik calls
2662          */
2663
2664         if (rxh->type == RX_PACKET_TYPE_DATA)
2665                 switch (opcode) {
2666                 case 10000:             /* Beacon */
2667                         ND_PRINT((ndo, " vote no"));
2668                         break;
2669                 case 20004:             /* Get version */
2670                         ND_PRINT((ndo, " dbversion"));
2671                         UBIK_VERSIONOUT();
2672                         break;
2673                 default:
2674                         ;
2675                 }
2676
2677         /*
2678          * Otherwise, print out "yes" it it was a beacon packet (because
2679          * that's how yes votes are returned, go figure), otherwise
2680          * just print out the error code.
2681          */
2682
2683         else
2684                 switch (opcode) {
2685                 case 10000:             /* Beacon */
2686                         ND_PRINT((ndo, " vote yes until"));
2687                         DATEOUT();
2688                         break;
2689                 default:
2690                         ND_PRINT((ndo, " errcode"));
2691                         INTOUT();
2692                 }
2693
2694         return;
2695
2696 trunc:
2697         ND_PRINT((ndo, " [|ubik]"));
2698 }
2699
2700 /*
2701  * Handle RX ACK packets.
2702  */
2703
2704 static void
2705 rx_ack_print(netdissect_options *ndo,
2706              register const u_char *bp, int length)
2707 {
2708         const struct rx_ackPacket *rxa;
2709         int i, start, last;
2710         uint32_t firstPacket;
2711
2712         if (length < (int)sizeof(struct rx_header))
2713                 return;
2714
2715         bp += sizeof(struct rx_header);
2716
2717         /*
2718          * This may seem a little odd .... the rx_ackPacket structure
2719          * contains an array of individual packet acknowledgements
2720          * (used for selective ack/nack), but since it's variable in size,
2721          * we don't want to truncate based on the size of the whole
2722          * rx_ackPacket structure.
2723          */
2724
2725         ND_TCHECK2(bp[0], sizeof(struct rx_ackPacket) - RX_MAXACKS);
2726
2727         rxa = (const struct rx_ackPacket *) bp;
2728         bp += (sizeof(struct rx_ackPacket) - RX_MAXACKS);
2729
2730         /*
2731          * Print out a few useful things from the ack packet structure
2732          */
2733
2734         if (ndo->ndo_vflag > 2)
2735                 ND_PRINT((ndo, " bufspace %d maxskew %d",
2736                        (int) EXTRACT_16BITS(&rxa->bufferSpace),
2737                        (int) EXTRACT_16BITS(&rxa->maxSkew)));
2738
2739         firstPacket = EXTRACT_32BITS(&rxa->firstPacket);
2740         ND_PRINT((ndo, " first %d serial %d reason %s",
2741                firstPacket, EXTRACT_32BITS(&rxa->serial),
2742                tok2str(rx_ack_reasons, "#%d", (int) rxa->reason)));
2743
2744         /*
2745          * Okay, now we print out the ack array.  The way _this_ works
2746          * is that we start at "first", and step through the ack array.
2747          * If we have a contiguous range of acks/nacks, try to
2748          * collapse them into a range.
2749          *
2750          * If you're really clever, you might have noticed that this
2751          * doesn't seem quite correct.  Specifically, due to structure
2752          * padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually
2753          * yield the start of the ack array (because RX_MAXACKS is 255
2754          * and the structure will likely get padded to a 2 or 4 byte
2755          * boundary).  However, this is the way it's implemented inside
2756          * of AFS - the start of the extra fields are at
2757          * sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_
2758          * the exact start of the ack array.  Sigh.  That's why we aren't
2759          * using bp, but instead use rxa->acks[].  But nAcks gets added
2760          * to bp after this, so bp ends up at the right spot.  Go figure.
2761          */
2762
2763         if (rxa->nAcks != 0) {
2764
2765                 ND_TCHECK2(bp[0], rxa->nAcks);
2766
2767                 /*
2768                  * Sigh, this is gross, but it seems to work to collapse
2769                  * ranges correctly.
2770                  */
2771
2772                 for (i = 0, start = last = -2; i < rxa->nAcks; i++)
2773                         if (rxa->acks[i] == RX_ACK_TYPE_ACK) {
2774
2775                                 /*
2776                                  * I figured this deserved _some_ explanation.
2777                                  * First, print "acked" and the packet seq
2778                                  * number if this is the first time we've
2779                                  * seen an acked packet.
2780                                  */
2781
2782                                 if (last == -2) {
2783                                         ND_PRINT((ndo, " acked %d", firstPacket + i));
2784                                         start = i;
2785                                 }
2786
2787                                 /*
2788                                  * Otherwise, if there is a skip in
2789                                  * the range (such as an nacked packet in
2790                                  * the middle of some acked packets),
2791                                  * then print the current packet number
2792                                  * seperated from the last number by
2793                                  * a comma.
2794                                  */
2795
2796                                 else if (last != i - 1) {
2797                                         ND_PRINT((ndo, ",%d", firstPacket + i));
2798                                         start = i;
2799                                 }
2800
2801                                 /*
2802                                  * We always set last to the value of
2803                                  * the last ack we saw.  Conversely, start
2804                                  * is set to the value of the first ack
2805                                  * we saw in a range.
2806                                  */
2807
2808                                 last = i;
2809
2810                                 /*
2811                                  * Okay, this bit a code gets executed when
2812                                  * we hit a nack ... in _this_ case we
2813                                  * want to print out the range of packets
2814                                  * that were acked, so we need to print
2815                                  * the _previous_ packet number seperated
2816                                  * from the first by a dash (-).  Since we
2817                                  * already printed the first packet above,
2818                                  * just print the final packet.  Don't
2819                                  * do this if there will be a single-length
2820                                  * range.
2821                                  */
2822                         } else if (last == i - 1 && start != last)
2823                                 ND_PRINT((ndo, "-%d", firstPacket + i - 1));
2824
2825                 /*
2826                  * So, what's going on here?  We ran off the end of the
2827                  * ack list, and if we got a range we need to finish it up.
2828                  * So we need to determine if the last packet in the list
2829                  * was an ack (if so, then last will be set to it) and
2830                  * we need to see if the last range didn't start with the
2831                  * last packet (because if it _did_, then that would mean
2832                  * that the packet number has already been printed and
2833                  * we don't need to print it again).
2834                  */
2835
2836                 if (last == i - 1 && start != last)
2837                         ND_PRINT((ndo, "-%d", firstPacket + i - 1));
2838
2839                 /*
2840                  * Same as above, just without comments
2841                  */
2842
2843                 for (i = 0, start = last = -2; i < rxa->nAcks; i++)
2844                         if (rxa->acks[i] == RX_ACK_TYPE_NACK) {
2845                                 if (last == -2) {
2846                                         ND_PRINT((ndo, " nacked %d", firstPacket + i));
2847                                         start = i;
2848                                 } else if (last != i - 1) {
2849                                         ND_PRINT((ndo, ",%d", firstPacket + i));
2850                                         start = i;
2851                                 }
2852                                 last = i;
2853                         } else if (last == i - 1 && start != last)
2854                                 ND_PRINT((ndo, "-%d", firstPacket + i - 1));
2855
2856                 if (last == i - 1 && start != last)
2857                         ND_PRINT((ndo, "-%d", firstPacket + i - 1));
2858
2859                 bp += rxa->nAcks;
2860         }
2861
2862
2863         /*
2864          * These are optional fields; depending on your version of AFS,
2865          * you may or may not see them
2866          */
2867
2868 #define TRUNCRET(n)     if (ndo->ndo_snapend - bp + 1 <= n) return;
2869
2870         if (ndo->ndo_vflag > 1) {
2871                 TRUNCRET(4);
2872                 ND_PRINT((ndo, " ifmtu"));
2873                 INTOUT();
2874
2875                 TRUNCRET(4);
2876                 ND_PRINT((ndo, " maxmtu"));
2877                 INTOUT();
2878
2879                 TRUNCRET(4);
2880                 ND_PRINT((ndo, " rwind"));
2881                 INTOUT();
2882
2883                 TRUNCRET(4);
2884                 ND_PRINT((ndo, " maxpackets"));
2885                 INTOUT();
2886         }
2887
2888         return;
2889
2890 trunc:
2891         ND_PRINT((ndo, " [|ack]"));
2892 }
2893 #undef TRUNCRET