print-aoe.c 11 KB

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