xref: /dflybsd-src/contrib/tcpdump/print-aoe.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
1411677aeSAaron LI /*
2411677aeSAaron LI  * Copyright (c) 2014 The TCPDUMP project
3411677aeSAaron LI  * All rights reserved.
4411677aeSAaron LI  *
5411677aeSAaron LI  * Redistribution and use in source and binary forms, with or without
6411677aeSAaron LI  * modification, are permitted provided that the following conditions
7411677aeSAaron LI  * are met:
8411677aeSAaron LI  * 1. Redistributions of source code must retain the above copyright
9411677aeSAaron LI  *    notice, this list of conditions and the following disclaimer.
10411677aeSAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
11411677aeSAaron LI  *    notice, this list of conditions and the following disclaimer in the
12411677aeSAaron LI  *    documentation and/or other materials provided with the distribution.
13411677aeSAaron LI  *
14411677aeSAaron LI  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15411677aeSAaron LI  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16411677aeSAaron LI  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17411677aeSAaron LI  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18411677aeSAaron LI  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19411677aeSAaron LI  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20411677aeSAaron LI  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21411677aeSAaron LI  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22411677aeSAaron LI  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23411677aeSAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24411677aeSAaron LI  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25411677aeSAaron LI  * POSSIBILITY OF SUCH DAMAGE.
26411677aeSAaron LI  */
27411677aeSAaron LI 
28411677aeSAaron LI /* \summary: ATA over Ethernet (AoE) protocol printer */
29411677aeSAaron LI 
30*ed775ee7SAntonio Huete Jimenez /* specification:
31*ed775ee7SAntonio Huete Jimenez  * https://web.archive.org/web/20161025044402/http://brantleycoilecompany.com/AoEr11.pdf
32*ed775ee7SAntonio Huete Jimenez  */
33411677aeSAaron LI 
34411677aeSAaron LI #ifdef HAVE_CONFIG_H
35*ed775ee7SAntonio Huete Jimenez #include <config.h>
36411677aeSAaron LI #endif
37411677aeSAaron LI 
38*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
39411677aeSAaron LI 
40*ed775ee7SAntonio Huete Jimenez #define ND_LONGJMP_FROM_TCHECK
41411677aeSAaron LI #include "netdissect.h"
42411677aeSAaron LI #include "extract.h"
43411677aeSAaron LI #include "addrtoname.h"
44411677aeSAaron LI 
45411677aeSAaron LI 
46411677aeSAaron LI #define AOE_V1 1
47411677aeSAaron LI #define ATA_SECTOR_SIZE 512
48411677aeSAaron LI 
49411677aeSAaron LI #define AOEV1_CMD_ISSUE_ATA_COMMAND        0
50411677aeSAaron LI #define AOEV1_CMD_QUERY_CONFIG_INFORMATION 1
51411677aeSAaron LI #define AOEV1_CMD_MAC_MASK_LIST            2
52411677aeSAaron LI #define AOEV1_CMD_RESERVE_RELEASE          3
53411677aeSAaron LI 
54411677aeSAaron LI static const struct tok cmdcode_str[] = {
55411677aeSAaron LI 	{ AOEV1_CMD_ISSUE_ATA_COMMAND,        "Issue ATA Command"        },
56411677aeSAaron LI 	{ AOEV1_CMD_QUERY_CONFIG_INFORMATION, "Query Config Information" },
57411677aeSAaron LI 	{ AOEV1_CMD_MAC_MASK_LIST,            "MAC Mask List"            },
58411677aeSAaron LI 	{ AOEV1_CMD_RESERVE_RELEASE,          "Reserve/Release"          },
59411677aeSAaron LI 	{ 0, NULL }
60411677aeSAaron LI };
61411677aeSAaron LI 
62411677aeSAaron LI #define AOEV1_COMMON_HDR_LEN    10U /* up to but w/o Arg                */
63411677aeSAaron LI #define AOEV1_ISSUE_ARG_LEN     12U /* up to but w/o Data               */
64411677aeSAaron LI #define AOEV1_QUERY_ARG_LEN      8U /* up to but w/o Config String      */
65411677aeSAaron LI #define AOEV1_MAC_ARG_LEN        4U /* up to but w/o Directive 0        */
66411677aeSAaron LI #define AOEV1_RESERVE_ARG_LEN    2U /* up to but w/o Ethernet address 0 */
67411677aeSAaron LI #define AOEV1_MAX_CONFSTR_LEN 1024U
68411677aeSAaron LI 
69411677aeSAaron LI #define AOEV1_FLAG_R 0x08
70411677aeSAaron LI #define AOEV1_FLAG_E 0x04
71411677aeSAaron LI 
72411677aeSAaron LI static const struct tok aoev1_flag_str[] = {
73411677aeSAaron LI 	{ AOEV1_FLAG_R, "Response" },
74411677aeSAaron LI 	{ AOEV1_FLAG_E, "Error"    },
75*ed775ee7SAntonio Huete Jimenez 	{ 0x02,         "MBZ-1"    },
76*ed775ee7SAntonio Huete Jimenez 	{ 0x01,         "MBZ-0"    },
77411677aeSAaron LI 	{ 0, NULL }
78411677aeSAaron LI };
79411677aeSAaron LI 
80411677aeSAaron LI static const struct tok aoev1_errcode_str[] = {
81411677aeSAaron LI 	{ 1, "Unrecognized command code" },
82411677aeSAaron LI 	{ 2, "Bad argument parameter"    },
83411677aeSAaron LI 	{ 3, "Device unavailable"        },
84411677aeSAaron LI 	{ 4, "Config string present"     },
85411677aeSAaron LI 	{ 5, "Unsupported version"       },
86411677aeSAaron LI 	{ 6, "Target is reserved"        },
87411677aeSAaron LI 	{ 0, NULL }
88411677aeSAaron LI };
89411677aeSAaron LI 
90411677aeSAaron LI #define AOEV1_AFLAG_E 0x40
91411677aeSAaron LI #define AOEV1_AFLAG_D 0x10
92411677aeSAaron LI #define AOEV1_AFLAG_A 0x02
93411677aeSAaron LI #define AOEV1_AFLAG_W 0x01
94411677aeSAaron LI 
95*ed775ee7SAntonio Huete Jimenez static const struct tok aoev1_aflag_bitmap_str[] = {
96*ed775ee7SAntonio Huete Jimenez 	{ 0x80,          "MBZ-7"    },
97411677aeSAaron LI 	{ AOEV1_AFLAG_E, "Ext48"    },
98*ed775ee7SAntonio Huete Jimenez 	{ 0x20,          "MBZ-5"    },
99411677aeSAaron LI 	{ AOEV1_AFLAG_D, "Device"   },
100*ed775ee7SAntonio Huete Jimenez 	{ 0x08,          "MBZ-3"    },
101*ed775ee7SAntonio Huete Jimenez 	{ 0x04,          "MBZ-2"    },
102411677aeSAaron LI 	{ AOEV1_AFLAG_A, "Async"    },
103411677aeSAaron LI 	{ AOEV1_AFLAG_W, "Write"    },
104411677aeSAaron LI 	{ 0, NULL }
105411677aeSAaron LI };
106411677aeSAaron LI 
107411677aeSAaron LI static const struct tok aoev1_ccmd_str[] = {
108411677aeSAaron LI 	{ 0, "read config string"        },
109411677aeSAaron LI 	{ 1, "test config string"        },
110411677aeSAaron LI 	{ 2, "test config string prefix" },
111411677aeSAaron LI 	{ 3, "set config string"         },
112411677aeSAaron LI 	{ 4, "force set config string"   },
113411677aeSAaron LI 	{ 0, NULL }
114411677aeSAaron LI };
115411677aeSAaron LI 
116411677aeSAaron LI static const struct tok aoev1_mcmd_str[] = {
117411677aeSAaron LI 	{ 0, "Read Mac Mask List" },
118411677aeSAaron LI 	{ 1, "Edit Mac Mask List" },
119411677aeSAaron LI 	{ 0, NULL }
120411677aeSAaron LI };
121411677aeSAaron LI 
122411677aeSAaron LI static const struct tok aoev1_merror_str[] = {
123411677aeSAaron LI 	{ 1, "Unspecified Error"  },
124411677aeSAaron LI 	{ 2, "Bad DCmd directive" },
125411677aeSAaron LI 	{ 3, "Mask list full"     },
126411677aeSAaron LI 	{ 0, NULL }
127411677aeSAaron LI };
128411677aeSAaron LI 
129411677aeSAaron LI static const struct tok aoev1_dcmd_str[] = {
130411677aeSAaron LI 	{ 0, "No Directive"                      },
131411677aeSAaron LI 	{ 1, "Add mac address to mask list"      },
132411677aeSAaron LI 	{ 2, "Delete mac address from mask list" },
133411677aeSAaron LI 	{ 0, NULL }
134411677aeSAaron LI };
135411677aeSAaron LI 
136411677aeSAaron LI static const struct tok aoev1_rcmd_str[] = {
137411677aeSAaron LI 	{ 0, "Read reserve list"      },
138411677aeSAaron LI 	{ 1, "Set reserve list"       },
139411677aeSAaron LI 	{ 2, "Force set reserve list" },
140411677aeSAaron LI 	{ 0, NULL }
141411677aeSAaron LI };
142411677aeSAaron LI 
143411677aeSAaron LI static void
aoev1_issue_print(netdissect_options * ndo,const u_char * cp,u_int len)144411677aeSAaron LI aoev1_issue_print(netdissect_options *ndo,
145*ed775ee7SAntonio Huete Jimenez                   const u_char *cp, u_int len)
146411677aeSAaron LI {
147411677aeSAaron LI 	if (len < AOEV1_ISSUE_ARG_LEN)
148411677aeSAaron LI 		goto invalid;
149411677aeSAaron LI 	/* AFlags */
150*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("\n\tAFlags: [%s]",
151*ed775ee7SAntonio Huete Jimenez 		 bittok2str(aoev1_aflag_bitmap_str, "none", GET_U_1(cp)));
152411677aeSAaron LI 	cp += 1;
153*ed775ee7SAntonio Huete Jimenez 	len -= 1;
154411677aeSAaron LI 	/* Err/Feature */
155*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Err/Feature: %u", GET_U_1(cp));
156411677aeSAaron LI 	cp += 1;
157*ed775ee7SAntonio Huete Jimenez 	len -= 1;
158411677aeSAaron LI 	/* Sector Count (not correlated with the length) */
159*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Sector Count: %u", GET_U_1(cp));
160411677aeSAaron LI 	cp += 1;
161*ed775ee7SAntonio Huete Jimenez 	len -= 1;
162411677aeSAaron LI 	/* Cmd/Status */
163*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Cmd/Status: %u", GET_U_1(cp));
164411677aeSAaron LI 	cp += 1;
165*ed775ee7SAntonio Huete Jimenez 	len -= 1;
166411677aeSAaron LI 	/* lba0 */
167*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("\n\tlba0: %u", GET_U_1(cp));
168411677aeSAaron LI 	cp += 1;
169*ed775ee7SAntonio Huete Jimenez 	len -= 1;
170411677aeSAaron LI 	/* lba1 */
171*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", lba1: %u", GET_U_1(cp));
172411677aeSAaron LI 	cp += 1;
173*ed775ee7SAntonio Huete Jimenez 	len -= 1;
174411677aeSAaron LI 	/* lba2 */
175*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", lba2: %u", GET_U_1(cp));
176411677aeSAaron LI 	cp += 1;
177*ed775ee7SAntonio Huete Jimenez 	len -= 1;
178411677aeSAaron LI 	/* lba3 */
179*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", lba3: %u", GET_U_1(cp));
180411677aeSAaron LI 	cp += 1;
181*ed775ee7SAntonio Huete Jimenez 	len -= 1;
182411677aeSAaron LI 	/* lba4 */
183*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", lba4: %u", GET_U_1(cp));
184411677aeSAaron LI 	cp += 1;
185*ed775ee7SAntonio Huete Jimenez 	len -= 1;
186411677aeSAaron LI 	/* lba5 */
187*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", lba5: %u", GET_U_1(cp));
188411677aeSAaron LI 	cp += 1;
189*ed775ee7SAntonio Huete Jimenez 	len -= 1;
190411677aeSAaron LI 	/* Reserved */
191*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_2(cp);
192411677aeSAaron LI 	cp += 2;
193*ed775ee7SAntonio Huete Jimenez 	len -= 2;
194411677aeSAaron LI 	/* Data */
195*ed775ee7SAntonio Huete Jimenez 	if (len)
196*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("\n\tData: %u bytes", len);
197411677aeSAaron LI 	return;
198411677aeSAaron LI 
199411677aeSAaron LI invalid:
200*ed775ee7SAntonio Huete Jimenez 	nd_print_invalid(ndo);
201*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(cp, len);
202411677aeSAaron LI }
203411677aeSAaron LI 
204411677aeSAaron LI static void
aoev1_query_print(netdissect_options * ndo,const u_char * cp,u_int len)205411677aeSAaron LI aoev1_query_print(netdissect_options *ndo,
206*ed775ee7SAntonio Huete Jimenez                   const u_char *cp, u_int len)
207411677aeSAaron LI {
208411677aeSAaron LI 	uint16_t cslen;
209411677aeSAaron LI 
210411677aeSAaron LI 	if (len < AOEV1_QUERY_ARG_LEN)
211411677aeSAaron LI 		goto invalid;
212411677aeSAaron LI 	/* Buffer Count */
213*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("\n\tBuffer Count: %u", GET_BE_U_2(cp));
214411677aeSAaron LI 	cp += 2;
215*ed775ee7SAntonio Huete Jimenez 	len -= 2;
216411677aeSAaron LI 	/* Firmware Version */
217*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Firmware Version: %u", GET_BE_U_2(cp));
218411677aeSAaron LI 	cp += 2;
219*ed775ee7SAntonio Huete Jimenez 	len -= 2;
220411677aeSAaron LI 	/* Sector Count */
221*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Sector Count: %u", GET_U_1(cp));
222411677aeSAaron LI 	cp += 1;
223*ed775ee7SAntonio Huete Jimenez 	len -= 1;
224411677aeSAaron LI 	/* AoE/CCmd */
225*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", AoE: %u, CCmd: %s", (GET_U_1(cp) & 0xF0) >> 4,
226*ed775ee7SAntonio Huete Jimenez 	          tok2str(aoev1_ccmd_str, "Unknown (0x02x)", GET_U_1(cp) & 0x0F));
227411677aeSAaron LI 	cp += 1;
228*ed775ee7SAntonio Huete Jimenez 	len -= 1;
229411677aeSAaron LI 	/* Config String Length */
230*ed775ee7SAntonio Huete Jimenez 	cslen = GET_BE_U_2(cp);
231411677aeSAaron LI 	cp += 2;
232*ed775ee7SAntonio Huete Jimenez 	len -= 2;
233*ed775ee7SAntonio Huete Jimenez 	if (cslen > AOEV1_MAX_CONFSTR_LEN || cslen > len)
234411677aeSAaron LI 		goto invalid;
235411677aeSAaron LI 	/* Config String */
236411677aeSAaron LI 	if (cslen) {
237*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("\n\tConfig String (length %u): ", cslen);
238*ed775ee7SAntonio Huete Jimenez 		(void)nd_printn(ndo, cp, cslen, NULL);
239411677aeSAaron LI 	}
240411677aeSAaron LI 	return;
241411677aeSAaron LI 
242411677aeSAaron LI invalid:
243*ed775ee7SAntonio Huete Jimenez 	nd_print_invalid(ndo);
244*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(cp, len);
245411677aeSAaron LI }
246411677aeSAaron LI 
247411677aeSAaron LI static void
aoev1_mac_print(netdissect_options * ndo,const u_char * cp,u_int len)248411677aeSAaron LI aoev1_mac_print(netdissect_options *ndo,
249*ed775ee7SAntonio Huete Jimenez                 const u_char *cp, u_int len)
250411677aeSAaron LI {
251411677aeSAaron LI 	uint8_t dircount, i;
252411677aeSAaron LI 
253411677aeSAaron LI 	if (len < AOEV1_MAC_ARG_LEN)
254411677aeSAaron LI 		goto invalid;
255411677aeSAaron LI 	/* Reserved */
256411677aeSAaron LI 	cp += 1;
257*ed775ee7SAntonio Huete Jimenez 	len -= 1;
258411677aeSAaron LI 	/* MCmd */
259*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("\n\tMCmd: %s",
260*ed775ee7SAntonio Huete Jimenez 		 tok2str(aoev1_mcmd_str, "Unknown (0x%02x)", GET_U_1(cp)));
261411677aeSAaron LI 	cp += 1;
262*ed775ee7SAntonio Huete Jimenez 	len -= 1;
263411677aeSAaron LI 	/* MError */
264*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", MError: %s",
265*ed775ee7SAntonio Huete Jimenez 		 tok2str(aoev1_merror_str, "Unknown (0x%02x)", GET_U_1(cp)));
266411677aeSAaron LI 	cp += 1;
267*ed775ee7SAntonio Huete Jimenez 	len -= 1;
268411677aeSAaron LI 	/* Dir Count */
269*ed775ee7SAntonio Huete Jimenez 	dircount = GET_U_1(cp);
270411677aeSAaron LI 	cp += 1;
271*ed775ee7SAntonio Huete Jimenez 	len -= 1;
272*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Dir Count: %u", dircount);
273*ed775ee7SAntonio Huete Jimenez 	if (dircount * 8U > len)
274411677aeSAaron LI 		goto invalid;
275411677aeSAaron LI 	/* directives */
276411677aeSAaron LI 	for (i = 0; i < dircount; i++) {
277411677aeSAaron LI 		/* Reserved */
278411677aeSAaron LI 		cp += 1;
279*ed775ee7SAntonio Huete Jimenez 		len -= 1;
280411677aeSAaron LI 		/* DCmd */
281*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("\n\t DCmd: %s",
282*ed775ee7SAntonio Huete Jimenez 			 tok2str(aoev1_dcmd_str, "Unknown (0x%02x)", GET_U_1(cp)));
283411677aeSAaron LI 		cp += 1;
284*ed775ee7SAntonio Huete Jimenez 		len -= 1;
285411677aeSAaron LI 		/* Ethernet Address */
286*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(", Ethernet Address: %s", GET_ETHERADDR_STRING(cp));
287*ed775ee7SAntonio Huete Jimenez 		cp += MAC_ADDR_LEN;
288*ed775ee7SAntonio Huete Jimenez 		len -= MAC_ADDR_LEN;
289411677aeSAaron LI 	}
290411677aeSAaron LI 	return;
291411677aeSAaron LI 
292411677aeSAaron LI invalid:
293*ed775ee7SAntonio Huete Jimenez 	nd_print_invalid(ndo);
294*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(cp, len);
295411677aeSAaron LI }
296411677aeSAaron LI 
297411677aeSAaron LI static void
aoev1_reserve_print(netdissect_options * ndo,const u_char * cp,u_int len)298411677aeSAaron LI aoev1_reserve_print(netdissect_options *ndo,
299*ed775ee7SAntonio Huete Jimenez                     const u_char *cp, u_int len)
300411677aeSAaron LI {
301411677aeSAaron LI 	uint8_t nmacs, i;
302411677aeSAaron LI 
303*ed775ee7SAntonio Huete Jimenez 	if (len < AOEV1_RESERVE_ARG_LEN || (len - AOEV1_RESERVE_ARG_LEN) % MAC_ADDR_LEN)
304411677aeSAaron LI 		goto invalid;
305411677aeSAaron LI 	/* RCmd */
306*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("\n\tRCmd: %s",
307*ed775ee7SAntonio Huete Jimenez 		 tok2str(aoev1_rcmd_str, "Unknown (0x%02x)", GET_U_1(cp)));
308411677aeSAaron LI 	cp += 1;
309*ed775ee7SAntonio Huete Jimenez 	len -= 1;
310411677aeSAaron LI 	/* NMacs (correlated with the length) */
311*ed775ee7SAntonio Huete Jimenez 	nmacs = GET_U_1(cp);
312411677aeSAaron LI 	cp += 1;
313*ed775ee7SAntonio Huete Jimenez 	len -= 1;
314*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", NMacs: %u", nmacs);
315*ed775ee7SAntonio Huete Jimenez 	if (nmacs * MAC_ADDR_LEN != len)
316411677aeSAaron LI 		goto invalid;
317411677aeSAaron LI 	/* addresses */
318411677aeSAaron LI 	for (i = 0; i < nmacs; i++) {
319*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("\n\tEthernet Address %u: %s", i, GET_ETHERADDR_STRING(cp));
320*ed775ee7SAntonio Huete Jimenez 		cp += MAC_ADDR_LEN;
321*ed775ee7SAntonio Huete Jimenez 		len -= MAC_ADDR_LEN;
322411677aeSAaron LI 	}
323411677aeSAaron LI 	return;
324411677aeSAaron LI 
325411677aeSAaron LI invalid:
326*ed775ee7SAntonio Huete Jimenez 	nd_print_invalid(ndo);
327*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(cp, len);
328411677aeSAaron LI }
329411677aeSAaron LI 
330411677aeSAaron LI /* cp points to the Ver/Flags octet */
331411677aeSAaron LI static void
aoev1_print(netdissect_options * ndo,const u_char * cp,u_int len)332411677aeSAaron LI aoev1_print(netdissect_options *ndo,
333*ed775ee7SAntonio Huete Jimenez             const u_char *cp, u_int len)
334411677aeSAaron LI {
335411677aeSAaron LI 	uint8_t flags, command;
336*ed775ee7SAntonio Huete Jimenez 	void (*cmd_decoder)(netdissect_options *, const u_char *, u_int);
337411677aeSAaron LI 
338411677aeSAaron LI 	if (len < AOEV1_COMMON_HDR_LEN)
339411677aeSAaron LI 		goto invalid;
340411677aeSAaron LI 	/* Flags */
341*ed775ee7SAntonio Huete Jimenez 	flags = GET_U_1(cp) & 0x0F;
342*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Flags: [%s]", bittok2str(aoev1_flag_str, "none", flags));
343411677aeSAaron LI 	cp += 1;
344*ed775ee7SAntonio Huete Jimenez 	len -= 1;
345411677aeSAaron LI 	if (! ndo->ndo_vflag)
346411677aeSAaron LI 		return;
347411677aeSAaron LI 	/* Error */
348411677aeSAaron LI 	if (flags & AOEV1_FLAG_E)
349*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("\n\tError: %s",
350*ed775ee7SAntonio Huete Jimenez 			 tok2str(aoev1_errcode_str, "Invalid (%u)", GET_U_1(cp)));
351411677aeSAaron LI 	cp += 1;
352*ed775ee7SAntonio Huete Jimenez 	len -= 1;
353411677aeSAaron LI 	/* Major */
354*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("\n\tMajor: 0x%04x", GET_BE_U_2(cp));
355411677aeSAaron LI 	cp += 2;
356*ed775ee7SAntonio Huete Jimenez 	len -= 2;
357411677aeSAaron LI 	/* Minor */
358*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Minor: 0x%02x", GET_U_1(cp));
359411677aeSAaron LI 	cp += 1;
360*ed775ee7SAntonio Huete Jimenez 	len -= 1;
361411677aeSAaron LI 	/* Command */
362*ed775ee7SAntonio Huete Jimenez 	command = GET_U_1(cp);
363411677aeSAaron LI 	cp += 1;
364*ed775ee7SAntonio Huete Jimenez 	len -= 1;
365*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Command: %s", tok2str(cmdcode_str, "Unknown (0x%02x)", command));
366411677aeSAaron LI 	/* Tag */
367*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Tag: 0x%08x", GET_BE_U_4(cp));
368411677aeSAaron LI 	cp += 4;
369*ed775ee7SAntonio Huete Jimenez 	len -= 4;
370411677aeSAaron LI 	/* Arg */
371411677aeSAaron LI 	cmd_decoder =
372411677aeSAaron LI 		command == AOEV1_CMD_ISSUE_ATA_COMMAND        ? aoev1_issue_print :
373411677aeSAaron LI 		command == AOEV1_CMD_QUERY_CONFIG_INFORMATION ? aoev1_query_print :
374411677aeSAaron LI 		command == AOEV1_CMD_MAC_MASK_LIST            ? aoev1_mac_print :
375411677aeSAaron LI 		command == AOEV1_CMD_RESERVE_RELEASE          ? aoev1_reserve_print :
376411677aeSAaron LI 		NULL;
377411677aeSAaron LI 	if (cmd_decoder != NULL)
378*ed775ee7SAntonio Huete Jimenez 		cmd_decoder(ndo, cp, len);
379411677aeSAaron LI 	return;
380411677aeSAaron LI 
381411677aeSAaron LI invalid:
382*ed775ee7SAntonio Huete Jimenez 	nd_print_invalid(ndo);
383*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(cp, len);
384411677aeSAaron LI }
385411677aeSAaron LI 
386411677aeSAaron LI void
aoe_print(netdissect_options * ndo,const u_char * cp,const u_int len)387411677aeSAaron LI aoe_print(netdissect_options *ndo,
388411677aeSAaron LI           const u_char *cp, const u_int len)
389411677aeSAaron LI {
390411677aeSAaron LI 	uint8_t ver;
391411677aeSAaron LI 
392*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "aoe";
393*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("AoE length %u", len);
394411677aeSAaron LI 
395411677aeSAaron LI 	if (len < 1)
396411677aeSAaron LI 		goto invalid;
397411677aeSAaron LI 	/* Ver/Flags */
398*ed775ee7SAntonio Huete Jimenez 	ver = (GET_U_1(cp) & 0xF0) >> 4;
399411677aeSAaron LI 	/* Don't advance cp yet: low order 4 bits are version-specific. */
400*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(", Ver %u", ver);
401411677aeSAaron LI 
402411677aeSAaron LI 	switch (ver) {
403411677aeSAaron LI 		case AOE_V1:
404411677aeSAaron LI 			aoev1_print(ndo, cp, len);
405411677aeSAaron LI 			break;
406411677aeSAaron LI 	}
407411677aeSAaron LI 	return;
408411677aeSAaron LI 
409411677aeSAaron LI invalid:
410*ed775ee7SAntonio Huete Jimenez 	nd_print_invalid(ndo);
411*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(cp, len);
412411677aeSAaron LI }
413411677aeSAaron LI 
414