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