xref: /minix3/external/bsd/tcpdump/dist/print-aoe.c (revision b636d99d91c3d54204248f643c14627405d4afd1)
1*b636d99dSDavid van Moolenbroek /*
2*b636d99dSDavid van Moolenbroek  * This module implements decoding of the ATA over Ethernet (AoE) protocol
3*b636d99dSDavid van Moolenbroek  * according to the following specification:
4*b636d99dSDavid van Moolenbroek  * http://support.coraid.com/documents/AoEr11.txt
5*b636d99dSDavid van Moolenbroek  *
6*b636d99dSDavid van Moolenbroek  * Copyright (c) 2014 The TCPDUMP project
7*b636d99dSDavid van Moolenbroek  * All rights reserved.
8*b636d99dSDavid van Moolenbroek  *
9*b636d99dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*b636d99dSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*b636d99dSDavid van Moolenbroek  * are met:
12*b636d99dSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*b636d99dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*b636d99dSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*b636d99dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
16*b636d99dSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
17*b636d99dSDavid van Moolenbroek  *
18*b636d99dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*b636d99dSDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*b636d99dSDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21*b636d99dSDavid van Moolenbroek  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22*b636d99dSDavid van Moolenbroek  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23*b636d99dSDavid van Moolenbroek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*b636d99dSDavid van Moolenbroek  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*b636d99dSDavid van Moolenbroek  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26*b636d99dSDavid van Moolenbroek  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*b636d99dSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28*b636d99dSDavid van Moolenbroek  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*b636d99dSDavid van Moolenbroek  * POSSIBILITY OF SUCH DAMAGE.
30*b636d99dSDavid van Moolenbroek  */
31*b636d99dSDavid van Moolenbroek 
32*b636d99dSDavid van Moolenbroek #include <sys/cdefs.h>
33*b636d99dSDavid van Moolenbroek #ifndef lint
34*b636d99dSDavid van Moolenbroek __RCSID("$NetBSD: print-aoe.c,v 1.2 2014/11/20 03:05:03 christos Exp $");
35*b636d99dSDavid van Moolenbroek #endif
36*b636d99dSDavid van Moolenbroek 
37*b636d99dSDavid van Moolenbroek #define NETDISSECT_REWORKED
38*b636d99dSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
39*b636d99dSDavid van Moolenbroek #include "config.h"
40*b636d99dSDavid van Moolenbroek #endif
41*b636d99dSDavid van Moolenbroek 
42*b636d99dSDavid van Moolenbroek #include <tcpdump-stdinc.h>
43*b636d99dSDavid van Moolenbroek 
44*b636d99dSDavid van Moolenbroek #include "interface.h"
45*b636d99dSDavid van Moolenbroek #include "extract.h"
46*b636d99dSDavid van Moolenbroek #include "addrtoname.h"
47*b636d99dSDavid van Moolenbroek #include "ether.h"
48*b636d99dSDavid van Moolenbroek 
49*b636d99dSDavid van Moolenbroek static const char tstr[] = " [|aoe]";
50*b636d99dSDavid van Moolenbroek static const char cstr[] = " (corrupt)";
51*b636d99dSDavid van Moolenbroek 
52*b636d99dSDavid van Moolenbroek #define AOE_V1 1
53*b636d99dSDavid van Moolenbroek #define ATA_SECTOR_SIZE 512
54*b636d99dSDavid van Moolenbroek 
55*b636d99dSDavid van Moolenbroek #define AOEV1_CMD_ISSUE_ATA_COMMAND        0
56*b636d99dSDavid van Moolenbroek #define AOEV1_CMD_QUERY_CONFIG_INFORMATION 1
57*b636d99dSDavid van Moolenbroek #define AOEV1_CMD_MAC_MASK_LIST            2
58*b636d99dSDavid van Moolenbroek #define AOEV1_CMD_RESERVE_RELEASE          3
59*b636d99dSDavid van Moolenbroek 
60*b636d99dSDavid van Moolenbroek static const struct tok cmdcode_str[] = {
61*b636d99dSDavid van Moolenbroek 	{ AOEV1_CMD_ISSUE_ATA_COMMAND,        "Issue ATA Command"        },
62*b636d99dSDavid van Moolenbroek 	{ AOEV1_CMD_QUERY_CONFIG_INFORMATION, "Query Config Information" },
63*b636d99dSDavid van Moolenbroek 	{ AOEV1_CMD_MAC_MASK_LIST,            "MAC Mask List"            },
64*b636d99dSDavid van Moolenbroek 	{ AOEV1_CMD_RESERVE_RELEASE,          "Reserve/Release"          },
65*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
66*b636d99dSDavid van Moolenbroek };
67*b636d99dSDavid van Moolenbroek 
68*b636d99dSDavid van Moolenbroek #define AOEV1_COMMON_HDR_LEN    10U /* up to but w/o Arg                */
69*b636d99dSDavid van Moolenbroek #define AOEV1_ISSUE_ARG_LEN     12U /* up to but w/o Data               */
70*b636d99dSDavid van Moolenbroek #define AOEV1_QUERY_ARG_LEN      8U /* up to but w/o Config String      */
71*b636d99dSDavid van Moolenbroek #define AOEV1_MAC_ARG_LEN        4U /* up to but w/o Directive 0        */
72*b636d99dSDavid van Moolenbroek #define AOEV1_RESERVE_ARG_LEN    2U /* up to but w/o Ethernet address 0 */
73*b636d99dSDavid van Moolenbroek #define AOEV1_MAX_CONFSTR_LEN 1024U
74*b636d99dSDavid van Moolenbroek 
75*b636d99dSDavid van Moolenbroek #define AOEV1_FLAG_R 0x08
76*b636d99dSDavid van Moolenbroek #define AOEV1_FLAG_E 0x04
77*b636d99dSDavid van Moolenbroek 
78*b636d99dSDavid van Moolenbroek static const struct tok aoev1_flag_str[] = {
79*b636d99dSDavid van Moolenbroek 	{ AOEV1_FLAG_R, "Response" },
80*b636d99dSDavid van Moolenbroek 	{ AOEV1_FLAG_E, "Error"    },
81*b636d99dSDavid van Moolenbroek 	{ 0x02,         "MBZ-0x02" },
82*b636d99dSDavid van Moolenbroek 	{ 0x01,         "MBZ-0x01" },
83*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
84*b636d99dSDavid van Moolenbroek };
85*b636d99dSDavid van Moolenbroek 
86*b636d99dSDavid van Moolenbroek static const struct tok aoev1_errcode_str[] = {
87*b636d99dSDavid van Moolenbroek 	{ 1, "Unrecognized command code" },
88*b636d99dSDavid van Moolenbroek 	{ 2, "Bad argument parameter"    },
89*b636d99dSDavid van Moolenbroek 	{ 3, "Device unavailable"        },
90*b636d99dSDavid van Moolenbroek 	{ 4, "Config string present"     },
91*b636d99dSDavid van Moolenbroek 	{ 5, "Unsupported version"       },
92*b636d99dSDavid van Moolenbroek 	{ 6, "Target is reserved"        },
93*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
94*b636d99dSDavid van Moolenbroek };
95*b636d99dSDavid van Moolenbroek 
96*b636d99dSDavid van Moolenbroek #define AOEV1_AFLAG_E 0x40
97*b636d99dSDavid van Moolenbroek #define AOEV1_AFLAG_D 0x10
98*b636d99dSDavid van Moolenbroek #define AOEV1_AFLAG_A 0x02
99*b636d99dSDavid van Moolenbroek #define AOEV1_AFLAG_W 0x01
100*b636d99dSDavid van Moolenbroek 
101*b636d99dSDavid van Moolenbroek static const struct tok aoev1_aflag_str[] = {
102*b636d99dSDavid van Moolenbroek 	{ 0x08,          "MBZ-0x08" },
103*b636d99dSDavid van Moolenbroek 	{ AOEV1_AFLAG_E, "Ext48"    },
104*b636d99dSDavid van Moolenbroek 	{ 0x06,          "MBZ-0x06" },
105*b636d99dSDavid van Moolenbroek 	{ AOEV1_AFLAG_D, "Device"   },
106*b636d99dSDavid van Moolenbroek 	{ 0x04,          "MBZ-0x04" },
107*b636d99dSDavid van Moolenbroek 	{ 0x03,          "MBZ-0x03" },
108*b636d99dSDavid van Moolenbroek 	{ AOEV1_AFLAG_A, "Async"    },
109*b636d99dSDavid van Moolenbroek 	{ AOEV1_AFLAG_W, "Write"    },
110*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
111*b636d99dSDavid van Moolenbroek };
112*b636d99dSDavid van Moolenbroek 
113*b636d99dSDavid van Moolenbroek static const struct tok aoev1_ccmd_str[] = {
114*b636d99dSDavid van Moolenbroek 	{ 0, "read config string"        },
115*b636d99dSDavid van Moolenbroek 	{ 1, "test config string"        },
116*b636d99dSDavid van Moolenbroek 	{ 2, "test config string prefix" },
117*b636d99dSDavid van Moolenbroek 	{ 3, "set config string"         },
118*b636d99dSDavid van Moolenbroek 	{ 4, "force set config string"   },
119*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
120*b636d99dSDavid van Moolenbroek };
121*b636d99dSDavid van Moolenbroek 
122*b636d99dSDavid van Moolenbroek static const struct tok aoev1_mcmd_str[] = {
123*b636d99dSDavid van Moolenbroek 	{ 0, "Read Mac Mask List" },
124*b636d99dSDavid van Moolenbroek 	{ 1, "Edit Mac Mask List" },
125*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
126*b636d99dSDavid van Moolenbroek };
127*b636d99dSDavid van Moolenbroek 
128*b636d99dSDavid van Moolenbroek static const struct tok aoev1_merror_str[] = {
129*b636d99dSDavid van Moolenbroek 	{ 1, "Unspecified Error"  },
130*b636d99dSDavid van Moolenbroek 	{ 2, "Bad DCmd directive" },
131*b636d99dSDavid van Moolenbroek 	{ 3, "Mask list full"     },
132*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
133*b636d99dSDavid van Moolenbroek };
134*b636d99dSDavid van Moolenbroek 
135*b636d99dSDavid van Moolenbroek static const struct tok aoev1_dcmd_str[] = {
136*b636d99dSDavid van Moolenbroek 	{ 0, "No Directive"                      },
137*b636d99dSDavid van Moolenbroek 	{ 1, "Add mac address to mask list"      },
138*b636d99dSDavid van Moolenbroek 	{ 2, "Delete mac address from mask list" },
139*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
140*b636d99dSDavid van Moolenbroek };
141*b636d99dSDavid van Moolenbroek 
142*b636d99dSDavid van Moolenbroek static const struct tok aoev1_rcmd_str[] = {
143*b636d99dSDavid van Moolenbroek 	{ 0, "Read reserve list"      },
144*b636d99dSDavid van Moolenbroek 	{ 1, "Set reserve list"       },
145*b636d99dSDavid van Moolenbroek 	{ 2, "Force set reserve list" },
146*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
147*b636d99dSDavid van Moolenbroek };
148*b636d99dSDavid van Moolenbroek 
149*b636d99dSDavid van Moolenbroek static void
aoev1_issue_print(netdissect_options * ndo,const u_char * cp,const u_int len)150*b636d99dSDavid van Moolenbroek aoev1_issue_print(netdissect_options *ndo,
151*b636d99dSDavid van Moolenbroek                   const u_char *cp, const u_int len)
152*b636d99dSDavid van Moolenbroek {
153*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
154*b636d99dSDavid van Moolenbroek 
155*b636d99dSDavid van Moolenbroek 	if (len < AOEV1_ISSUE_ARG_LEN)
156*b636d99dSDavid van Moolenbroek 		goto corrupt;
157*b636d99dSDavid van Moolenbroek 	/* AFlags */
158*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
159*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "\n\tAFlags: [%s]", bittok2str(aoev1_aflag_str, "none", *cp)));
160*b636d99dSDavid van Moolenbroek 	cp += 1;
161*b636d99dSDavid van Moolenbroek 	/* Err/Feature */
162*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
163*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Err/Feature: %u", *cp));
164*b636d99dSDavid van Moolenbroek 	cp += 1;
165*b636d99dSDavid van Moolenbroek 	/* Sector Count (not correlated with the length) */
166*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
167*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Sector Count: %u", *cp));
168*b636d99dSDavid van Moolenbroek 	cp += 1;
169*b636d99dSDavid van Moolenbroek 	/* Cmd/Status */
170*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
171*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Cmd/Status: %u", *cp));
172*b636d99dSDavid van Moolenbroek 	cp += 1;
173*b636d99dSDavid van Moolenbroek 	/* lba0 */
174*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
175*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "\n\tlba0: %u", *cp));
176*b636d99dSDavid van Moolenbroek 	cp += 1;
177*b636d99dSDavid van Moolenbroek 	/* lba1 */
178*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
179*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", lba1: %u", *cp));
180*b636d99dSDavid van Moolenbroek 	cp += 1;
181*b636d99dSDavid van Moolenbroek 	/* lba2 */
182*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
183*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", lba2: %u", *cp));
184*b636d99dSDavid van Moolenbroek 	cp += 1;
185*b636d99dSDavid van Moolenbroek 	/* lba3 */
186*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
187*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", lba3: %u", *cp));
188*b636d99dSDavid van Moolenbroek 	cp += 1;
189*b636d99dSDavid van Moolenbroek 	/* lba4 */
190*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
191*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", lba4: %u", *cp));
192*b636d99dSDavid van Moolenbroek 	cp += 1;
193*b636d99dSDavid van Moolenbroek 	/* lba5 */
194*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
195*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", lba5: %u", *cp));
196*b636d99dSDavid van Moolenbroek 	cp += 1;
197*b636d99dSDavid van Moolenbroek 	/* Reserved */
198*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 2);
199*b636d99dSDavid van Moolenbroek 	cp += 2;
200*b636d99dSDavid van Moolenbroek 	/* Data */
201*b636d99dSDavid van Moolenbroek 	if (len > AOEV1_ISSUE_ARG_LEN)
202*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\tData: %u bytes", len - AOEV1_ISSUE_ARG_LEN));
203*b636d99dSDavid van Moolenbroek 	return;
204*b636d99dSDavid van Moolenbroek 
205*b636d99dSDavid van Moolenbroek corrupt:
206*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", cstr));
207*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
208*b636d99dSDavid van Moolenbroek 	return;
209*b636d99dSDavid van Moolenbroek trunc:
210*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
211*b636d99dSDavid van Moolenbroek }
212*b636d99dSDavid van Moolenbroek 
213*b636d99dSDavid van Moolenbroek static void
aoev1_query_print(netdissect_options * ndo,const u_char * cp,const u_int len)214*b636d99dSDavid van Moolenbroek aoev1_query_print(netdissect_options *ndo,
215*b636d99dSDavid van Moolenbroek                   const u_char *cp, const u_int len)
216*b636d99dSDavid van Moolenbroek {
217*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
218*b636d99dSDavid van Moolenbroek 	uint16_t cslen;
219*b636d99dSDavid van Moolenbroek 
220*b636d99dSDavid van Moolenbroek 	if (len < AOEV1_QUERY_ARG_LEN)
221*b636d99dSDavid van Moolenbroek 		goto corrupt;
222*b636d99dSDavid van Moolenbroek 	/* Buffer Count */
223*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 2);
224*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "\n\tBuffer Count: %u", EXTRACT_16BITS(cp)));
225*b636d99dSDavid van Moolenbroek 	cp += 2;
226*b636d99dSDavid van Moolenbroek 	/* Firmware Version */
227*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 2);
228*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Firmware Version: %u", EXTRACT_16BITS(cp)));
229*b636d99dSDavid van Moolenbroek 	cp += 2;
230*b636d99dSDavid van Moolenbroek 	/* Sector Count */
231*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
232*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Sector Count: %u", *cp));
233*b636d99dSDavid van Moolenbroek 	cp += 1;
234*b636d99dSDavid van Moolenbroek 	/* AoE/CCmd */
235*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
236*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", AoE: %u, CCmd: %s", (*cp & 0xF0) >> 4,
237*b636d99dSDavid van Moolenbroek 	          tok2str(aoev1_ccmd_str, "Unknown (0x02x)", *cp & 0x0F)));
238*b636d99dSDavid van Moolenbroek 	cp += 1;
239*b636d99dSDavid van Moolenbroek 	/* Config String Length */
240*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 2);
241*b636d99dSDavid van Moolenbroek 	cslen = EXTRACT_16BITS(cp);
242*b636d99dSDavid van Moolenbroek 	cp += 2;
243*b636d99dSDavid van Moolenbroek 	if (cslen > AOEV1_MAX_CONFSTR_LEN || AOEV1_QUERY_ARG_LEN + cslen > len)
244*b636d99dSDavid van Moolenbroek 		goto corrupt;
245*b636d99dSDavid van Moolenbroek 	/* Config String */
246*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, cslen);
247*b636d99dSDavid van Moolenbroek 	if (cslen) {
248*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\tConfig String (length %u): ", cslen));
249*b636d99dSDavid van Moolenbroek 		if (fn_printn(ndo, cp, cslen, ndo->ndo_snapend))
250*b636d99dSDavid van Moolenbroek 			goto trunc;
251*b636d99dSDavid van Moolenbroek 	}
252*b636d99dSDavid van Moolenbroek 	return;
253*b636d99dSDavid van Moolenbroek 
254*b636d99dSDavid van Moolenbroek corrupt:
255*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", cstr));
256*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
257*b636d99dSDavid van Moolenbroek 	return;
258*b636d99dSDavid van Moolenbroek trunc:
259*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
260*b636d99dSDavid van Moolenbroek }
261*b636d99dSDavid van Moolenbroek 
262*b636d99dSDavid van Moolenbroek static void
aoev1_mac_print(netdissect_options * ndo,const u_char * cp,const u_int len)263*b636d99dSDavid van Moolenbroek aoev1_mac_print(netdissect_options *ndo,
264*b636d99dSDavid van Moolenbroek                 const u_char *cp, const u_int len)
265*b636d99dSDavid van Moolenbroek {
266*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
267*b636d99dSDavid van Moolenbroek 	uint8_t dircount, i;
268*b636d99dSDavid van Moolenbroek 
269*b636d99dSDavid van Moolenbroek 	if (len < AOEV1_MAC_ARG_LEN)
270*b636d99dSDavid van Moolenbroek 		goto corrupt;
271*b636d99dSDavid van Moolenbroek 	/* Reserved */
272*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
273*b636d99dSDavid van Moolenbroek 	cp += 1;
274*b636d99dSDavid van Moolenbroek 	/* MCmd */
275*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
276*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "\n\tMCmd: %s", tok2str(aoev1_mcmd_str, "Unknown (0x%02x)", *cp)));
277*b636d99dSDavid van Moolenbroek 	cp += 1;
278*b636d99dSDavid van Moolenbroek 	/* MError */
279*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
280*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", MError: %s", tok2str(aoev1_merror_str, "Unknown (0x%02x)", *cp)));
281*b636d99dSDavid van Moolenbroek 	cp += 1;
282*b636d99dSDavid van Moolenbroek 	/* Dir Count */
283*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
284*b636d99dSDavid van Moolenbroek 	dircount = *cp;
285*b636d99dSDavid van Moolenbroek 	cp += 1;
286*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Dir Count: %u", dircount));
287*b636d99dSDavid van Moolenbroek 	if (AOEV1_MAC_ARG_LEN + dircount * 8 > len)
288*b636d99dSDavid van Moolenbroek 		goto corrupt;
289*b636d99dSDavid van Moolenbroek 	/* directives */
290*b636d99dSDavid van Moolenbroek 	for (i = 0; i < dircount; i++) {
291*b636d99dSDavid van Moolenbroek 		/* Reserved */
292*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 1);
293*b636d99dSDavid van Moolenbroek 		cp += 1;
294*b636d99dSDavid van Moolenbroek 		/* DCmd */
295*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 1);
296*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\t DCmd: %s", tok2str(aoev1_dcmd_str, "Unknown (0x%02x)", *cp)));
297*b636d99dSDavid van Moolenbroek 		cp += 1;
298*b636d99dSDavid van Moolenbroek 		/* Ethernet Address */
299*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, ETHER_ADDR_LEN);
300*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, ", Ethernet Address: %s", etheraddr_string(ndo, cp)));
301*b636d99dSDavid van Moolenbroek 		cp += ETHER_ADDR_LEN;
302*b636d99dSDavid van Moolenbroek 	}
303*b636d99dSDavid van Moolenbroek 	return;
304*b636d99dSDavid van Moolenbroek 
305*b636d99dSDavid van Moolenbroek corrupt:
306*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", cstr));
307*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
308*b636d99dSDavid van Moolenbroek 	return;
309*b636d99dSDavid van Moolenbroek trunc:
310*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
311*b636d99dSDavid van Moolenbroek }
312*b636d99dSDavid van Moolenbroek 
313*b636d99dSDavid van Moolenbroek static void
aoev1_reserve_print(netdissect_options * ndo,const u_char * cp,const u_int len)314*b636d99dSDavid van Moolenbroek aoev1_reserve_print(netdissect_options *ndo,
315*b636d99dSDavid van Moolenbroek                     const u_char *cp, const u_int len)
316*b636d99dSDavid van Moolenbroek {
317*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
318*b636d99dSDavid van Moolenbroek 	uint8_t nmacs, i;
319*b636d99dSDavid van Moolenbroek 
320*b636d99dSDavid van Moolenbroek 	if (len < AOEV1_RESERVE_ARG_LEN || (len - AOEV1_RESERVE_ARG_LEN) % ETHER_ADDR_LEN)
321*b636d99dSDavid van Moolenbroek 		goto corrupt;
322*b636d99dSDavid van Moolenbroek 	/* RCmd */
323*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
324*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "\n\tRCmd: %s", tok2str(aoev1_rcmd_str, "Unknown (0x%02x)", *cp)));
325*b636d99dSDavid van Moolenbroek 	cp += 1;
326*b636d99dSDavid van Moolenbroek 	/* NMacs (correlated with the length) */
327*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
328*b636d99dSDavid van Moolenbroek 	nmacs = *cp;
329*b636d99dSDavid van Moolenbroek 	cp += 1;
330*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", NMacs: %u", nmacs));
331*b636d99dSDavid van Moolenbroek 	if (AOEV1_RESERVE_ARG_LEN + nmacs * ETHER_ADDR_LEN != len)
332*b636d99dSDavid van Moolenbroek 		goto corrupt;
333*b636d99dSDavid van Moolenbroek 	/* addresses */
334*b636d99dSDavid van Moolenbroek 	for (i = 0; i < nmacs; i++) {
335*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\tEthernet Address %u: %s", i, etheraddr_string(ndo, cp)));
336*b636d99dSDavid van Moolenbroek 		cp += ETHER_ADDR_LEN;
337*b636d99dSDavid van Moolenbroek 	}
338*b636d99dSDavid van Moolenbroek 	return;
339*b636d99dSDavid van Moolenbroek 
340*b636d99dSDavid van Moolenbroek corrupt:
341*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", cstr));
342*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
343*b636d99dSDavid van Moolenbroek 	return;
344*b636d99dSDavid van Moolenbroek trunc:
345*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
346*b636d99dSDavid van Moolenbroek }
347*b636d99dSDavid van Moolenbroek 
348*b636d99dSDavid van Moolenbroek /* cp points to the Ver/Flags octet */
349*b636d99dSDavid van Moolenbroek static void
aoev1_print(netdissect_options * ndo,const u_char * cp,const u_int len)350*b636d99dSDavid van Moolenbroek aoev1_print(netdissect_options *ndo,
351*b636d99dSDavid van Moolenbroek             const u_char *cp, const u_int len)
352*b636d99dSDavid van Moolenbroek {
353*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
354*b636d99dSDavid van Moolenbroek 	uint8_t flags, command;
355*b636d99dSDavid van Moolenbroek 	void (*cmd_decoder)(netdissect_options *, const u_char *, const u_int);
356*b636d99dSDavid van Moolenbroek 
357*b636d99dSDavid van Moolenbroek 	if (len < AOEV1_COMMON_HDR_LEN)
358*b636d99dSDavid van Moolenbroek 		goto corrupt;
359*b636d99dSDavid van Moolenbroek 	/* Flags */
360*b636d99dSDavid van Moolenbroek 	flags = *cp & 0x0F;
361*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Flags: [%s]", bittok2str(aoev1_flag_str, "none", flags)));
362*b636d99dSDavid van Moolenbroek 	cp += 1;
363*b636d99dSDavid van Moolenbroek 	if (! ndo->ndo_vflag)
364*b636d99dSDavid van Moolenbroek 		return;
365*b636d99dSDavid van Moolenbroek 	/* Error */
366*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
367*b636d99dSDavid van Moolenbroek 	if (flags & AOEV1_FLAG_E)
368*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\tError: %s", tok2str(aoev1_errcode_str, "Invalid (%u)", *cp)));
369*b636d99dSDavid van Moolenbroek 	cp += 1;
370*b636d99dSDavid van Moolenbroek 	/* Major */
371*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 2);
372*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "\n\tMajor: 0x%04x", EXTRACT_16BITS(cp)));
373*b636d99dSDavid van Moolenbroek 	cp += 2;
374*b636d99dSDavid van Moolenbroek 	/* Minor */
375*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
376*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Minor: 0x%02x", *cp));
377*b636d99dSDavid van Moolenbroek 	cp += 1;
378*b636d99dSDavid van Moolenbroek 	/* Command */
379*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
380*b636d99dSDavid van Moolenbroek 	command = *cp;
381*b636d99dSDavid van Moolenbroek 	cp += 1;
382*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Command: %s", tok2str(cmdcode_str, "Unknown (0x%02x)", command)));
383*b636d99dSDavid van Moolenbroek 	/* Tag */
384*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 4);
385*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Tag: 0x%08x", EXTRACT_32BITS(cp)));
386*b636d99dSDavid van Moolenbroek 	cp += 4;
387*b636d99dSDavid van Moolenbroek 	/* Arg */
388*b636d99dSDavid van Moolenbroek 	cmd_decoder =
389*b636d99dSDavid van Moolenbroek 		command == AOEV1_CMD_ISSUE_ATA_COMMAND        ? aoev1_issue_print :
390*b636d99dSDavid van Moolenbroek 		command == AOEV1_CMD_QUERY_CONFIG_INFORMATION ? aoev1_query_print :
391*b636d99dSDavid van Moolenbroek 		command == AOEV1_CMD_MAC_MASK_LIST            ? aoev1_mac_print :
392*b636d99dSDavid van Moolenbroek 		command == AOEV1_CMD_RESERVE_RELEASE          ? aoev1_reserve_print :
393*b636d99dSDavid van Moolenbroek 		NULL;
394*b636d99dSDavid van Moolenbroek 	if (cmd_decoder != NULL)
395*b636d99dSDavid van Moolenbroek 		cmd_decoder(ndo, cp, len - AOEV1_COMMON_HDR_LEN);
396*b636d99dSDavid van Moolenbroek 	return;
397*b636d99dSDavid van Moolenbroek 
398*b636d99dSDavid van Moolenbroek corrupt:
399*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", cstr));
400*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
401*b636d99dSDavid van Moolenbroek 	return;
402*b636d99dSDavid van Moolenbroek trunc:
403*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
404*b636d99dSDavid van Moolenbroek }
405*b636d99dSDavid van Moolenbroek 
406*b636d99dSDavid van Moolenbroek void
aoe_print(netdissect_options * ndo,const u_char * cp,const u_int len)407*b636d99dSDavid van Moolenbroek aoe_print(netdissect_options *ndo,
408*b636d99dSDavid van Moolenbroek           const u_char *cp, const u_int len)
409*b636d99dSDavid van Moolenbroek {
410*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
411*b636d99dSDavid van Moolenbroek 	uint8_t ver;
412*b636d99dSDavid van Moolenbroek 
413*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "AoE length %u", len));
414*b636d99dSDavid van Moolenbroek 
415*b636d99dSDavid van Moolenbroek 	if (len < 1)
416*b636d99dSDavid van Moolenbroek 		goto corrupt;
417*b636d99dSDavid van Moolenbroek 	/* Ver/Flags */
418*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
419*b636d99dSDavid van Moolenbroek 	ver = (*cp & 0xF0) >> 4;
420*b636d99dSDavid van Moolenbroek 	/* Don't advance cp yet: low order 4 bits are version-specific. */
421*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ", Ver %u", ver));
422*b636d99dSDavid van Moolenbroek 
423*b636d99dSDavid van Moolenbroek 	switch (ver) {
424*b636d99dSDavid van Moolenbroek 		case AOE_V1:
425*b636d99dSDavid van Moolenbroek 			aoev1_print(ndo, cp, len);
426*b636d99dSDavid van Moolenbroek 			break;
427*b636d99dSDavid van Moolenbroek 	}
428*b636d99dSDavid van Moolenbroek 	return;
429*b636d99dSDavid van Moolenbroek 
430*b636d99dSDavid van Moolenbroek corrupt:
431*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", cstr));
432*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
433*b636d99dSDavid van Moolenbroek 	return;
434*b636d99dSDavid van Moolenbroek trunc:
435*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
436*b636d99dSDavid van Moolenbroek }
437*b636d99dSDavid van Moolenbroek 
438