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