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