Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-aoe.c
blob28867430f4fcd7e272e918a00e784b6a16f3d0c8
1 /* packet-aoe.c
2 * Routines for dissecting the ATA over Ethernet protocol.
3 * Ronnie Sahlberg 2004
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8 #include "config.h"
11 * See
13 * http://brantleycoilecompany.com/AoEr11.pdf
15 #include <epan/packet.h>
16 #include <epan/conversation.h>
17 #include <epan/etypes.h>
18 #include <epan/tfs.h>
20 void proto_register_aoe(void);
21 void proto_reg_handoff_aoe(void);
23 static dissector_handle_t aoe_handle;
25 static int proto_aoe;
26 static int hf_aoe_version;
27 static int hf_aoe_flags_response;
28 static int hf_aoe_flags_error;
29 static int hf_aoe_error;
30 static int hf_aoe_major;
31 static int hf_aoe_minor;
32 static int hf_aoe_cmd;
33 static int hf_aoe_tag;
34 static int hf_aoe_aflags_e;
35 static int hf_aoe_aflags_d;
36 static int hf_aoe_aflags_a;
37 static int hf_aoe_aflags_w;
38 static int hf_aoe_err_feature;
39 static int hf_aoe_sector_count;
40 static int hf_aoe_acmd;
41 static int hf_aoe_astatus;
42 static int hf_aoe_lba;
43 static int hf_aoe_response_in;
44 static int hf_aoe_response_to;
45 static int hf_aoe_time;
47 static int ett_aoe;
48 static int ett_aoe_flags;
50 #define AOE_FLAGS_RESPONSE 0x08
51 #define AOE_FLAGS_ERROR 0x04
53 #define AOE_AFLAGS_E 0x40
54 #define AOE_AFLAGS_D 0x10
55 #define AOE_AFLAGS_A 0x02
56 #define AOE_AFLAGS_W 0x01
58 static const true_false_string tfs_aflags_e = {
59 "LBA48 extended command",
60 "Normal command"
63 static const true_false_string tfs_aflags_a = {
64 "ASYNCHRONOUS Write",
65 "synchronous write"
67 static const true_false_string tfs_aflags_w = {
68 "WRITE to the device",
69 "No write to device"
72 static const true_false_string tfs_error = {
73 "Error",
74 "No error"
77 static const value_string error_vals[] = {
78 { 1, "Unrecognized command code" },
79 { 2, "Bad argument parameter" },
80 { 3, "Device unavailable" },
81 { 4, "Config string present" },
82 { 5, "Unsupported version" },
83 { 0, NULL}
86 #define AOE_CMD_ISSUE_ATA_COMMAND 0
87 #define AOE_CMD_QUERY_CONFIG_INFO 1
88 static const value_string cmd_vals[] = {
89 { AOE_CMD_ISSUE_ATA_COMMAND, "Issue ATA Command" },
90 { AOE_CMD_QUERY_CONFIG_INFO, "Query Config Information" },
91 { 0, NULL}
94 static const value_string ata_cmd_vals[] = {
95 { 0x00, "NOP" },
96 { 0x08, "Atapi soft reset" },
97 { 0x10, "Recalibrate" },
98 { 0x20, "Read sectors (with retry)" },
99 { 0x21, "Read sectors (no retry)" },
100 { 0x22, "Read long (with retry)" },
101 { 0x23, "Read long (no retry)" },
102 { 0x24, "Read ext" },
103 { 0x30, "Write sectors (with retry)" },
104 { 0x31, "Write sectors (no retry)" },
105 { 0x32, "Write long (with retry)" },
106 { 0x33, "Write long (no retry)" },
107 { 0x34, "Write ext" },
108 { 0x3c, "Write verify" },
109 { 0x40, "Read verify sectors (with retry)" },
110 { 0x41, "Read verify sectors (no retry)" },
111 { 0x50, "Format track" },
112 { 0x70, "Seek" },
113 { 0x90, "Execute device diagnostics" },
114 { 0x91, "Initialize device parameters" },
115 { 0x92, "Download microcode" },
116 { 0x94, "Standby immediate" },
117 { 0x95, "Idle immediate" },
118 { 0x96, "Standby" },
119 { 0x97, "Idle" },
120 { 0x98, "Check power mode" },
121 { 0x99, "Sleep" },
122 { 0xa0, "Atapi packet" },
123 { 0xa1, "Atapi identify device" },
124 { 0xa2, "Atapi service" },
125 { 0xb0, "Smart" },
126 { 0xc4, "Read multiple" },
127 { 0xc5, "Write multiple" },
128 { 0xc6, "Set multiple mode" },
129 { 0xc8, "Read dma (with retry)" },
130 { 0xc9, "Read dma (no retry)" },
131 { 0xca, "Write dma (with retry)" },
132 { 0xcb, "Write dma (no retry)" },
133 { 0xde, "Door lock" },
134 { 0xdf, "Door unlock" },
135 { 0xe0, "Standby immediate" },
136 { 0xe1, "Idle immediate" },
137 { 0xe2, "Standby" },
138 { 0xe3, "Idle" },
139 { 0xe4, "Read buffer" },
140 { 0xe5, "Check power mode" },
141 { 0xe6, "Sleep" },
142 { 0xe8, "Write buffer" },
143 { 0xec, "Identify Device" },
144 { 0xed, "Media eject" },
145 { 0xee, "Identify device dma" },
146 { 0xef, "Set features" },
147 { 0xf1, "Security set password" },
148 { 0xf2, "Security unlock" },
149 { 0xf3, "Security erase prepare" },
150 { 0xf4, "Security erase unit" },
151 { 0xf5, "Security freeze" },
152 { 0xf6, "Security disable password" },
153 { 0, NULL}
156 typedef struct ata_info_t {
157 uint32_t tag;
158 void *conversation; /* just used to multiplex different conversations */
159 uint32_t request_frame;
160 uint32_t response_frame;
161 nstime_t req_time;
162 uint8_t cmd;
163 } ata_info_t;
164 static wmem_map_t *ata_cmd_unmatched;
165 static wmem_map_t *ata_cmd_matched;
167 static unsigned
168 ata_cmd_hash_matched(const void *k)
170 return GPOINTER_TO_UINT(k);
173 static int
174 ata_cmd_equal_matched(const void *k1, const void *k2)
176 return k1==k2;
179 static unsigned
180 ata_cmd_hash_unmatched(const void *k)
182 const ata_info_t *key = (const ata_info_t *)k;
184 return key->tag;
187 static int
188 ata_cmd_equal_unmatched(const void *k1, const void *k2)
190 const ata_info_t *key1 = (const ata_info_t *)k1;
191 const ata_info_t *key2 = (const ata_info_t *)k2;
193 return (key1->tag==key2->tag)&&(key1->conversation==key2->conversation);
196 static void
197 dissect_ata_pdu(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, bool response, uint32_t tag)
199 proto_item *tmp_item;
200 uint8_t aflags;
201 uint64_t lba;
202 ata_info_t *ata_info=NULL;
203 conversation_t *conversation;
205 /* only create a conversation for ATA commands */
206 conversation = find_or_create_conversation(pinfo);
208 if( !(pinfo->fd->visited) ){
209 if(!response){
210 ata_info_t *tmp_ata_info;
211 /* first time we see this request so add a struct for request/response
212 matching */
213 ata_info=wmem_new(wmem_file_scope(), ata_info_t);
214 ata_info->tag=tag;
215 ata_info->conversation=conversation;
216 ata_info->request_frame=pinfo->num;
217 ata_info->response_frame=0;
218 ata_info->cmd=tvb_get_uint8(tvb, offset+3);
219 ata_info->req_time=pinfo->abs_ts;
221 tmp_ata_info=(ata_info_t *)wmem_map_lookup(ata_cmd_unmatched, ata_info);
222 if(tmp_ata_info){
223 wmem_map_remove(ata_cmd_unmatched, tmp_ata_info);
225 wmem_map_insert(ata_cmd_unmatched, ata_info, ata_info);
226 } else {
227 ata_info_t tmp_ata_info;
228 /* first time we see this response so see if we can match it with
229 a request */
230 tmp_ata_info.tag=tag;
231 tmp_ata_info.conversation=conversation;
232 ata_info=(ata_info_t *)wmem_map_lookup(ata_cmd_unmatched, &tmp_ata_info);
233 /* woo hoo we could, so no need to store this in unmatched any more,
234 move both request and response to the matched table */
235 if(ata_info){
236 ata_info->response_frame=pinfo->num;
237 wmem_map_remove(ata_cmd_unmatched, ata_info);
238 wmem_map_insert(ata_cmd_matched, GUINT_TO_POINTER(ata_info->request_frame), ata_info);
239 wmem_map_insert(ata_cmd_matched, GUINT_TO_POINTER(ata_info->response_frame), ata_info);
242 } else {
243 ata_info=(ata_info_t *)wmem_map_lookup(ata_cmd_matched, GUINT_TO_POINTER(pinfo->num));
246 if(ata_info){
247 if(response){
248 if(ata_info->request_frame){
249 nstime_t delta_ts;
250 tmp_item=proto_tree_add_uint(tree, hf_aoe_response_to, tvb, 0, 0, ata_info->request_frame);
251 proto_item_set_generated(tmp_item);
252 nstime_delta(&delta_ts, &pinfo->abs_ts, &ata_info->req_time);
253 tmp_item=proto_tree_add_time(tree, hf_aoe_time, tvb, offset, 0, &delta_ts);
254 proto_item_set_generated(tmp_item);
256 } else {
257 if(ata_info->response_frame){
258 tmp_item=proto_tree_add_uint(tree, hf_aoe_response_in, tvb, 0, 0, ata_info->response_frame);
259 proto_item_set_generated(tmp_item);
264 /* aflags */
265 aflags=tvb_get_uint8(tvb, offset);
266 proto_tree_add_item(tree, hf_aoe_aflags_e, tvb, offset, 1, ENC_BIG_ENDIAN);
267 if(aflags&AOE_AFLAGS_E){
268 proto_tree_add_item(tree, hf_aoe_aflags_d, tvb, offset, 1, ENC_BIG_ENDIAN);
270 if(aflags&AOE_AFLAGS_W){
271 proto_tree_add_item(tree, hf_aoe_aflags_a, tvb, offset, 1, ENC_BIG_ENDIAN);
273 proto_tree_add_item(tree, hf_aoe_aflags_w, tvb, offset, 1, ENC_BIG_ENDIAN);
274 offset++;
276 /* err/feature */
277 proto_tree_add_item(tree, hf_aoe_err_feature, tvb, offset, 1, ENC_BIG_ENDIAN);
278 offset++;
280 /* sector count */
281 proto_tree_add_item(tree, hf_aoe_sector_count, tvb, offset, 1, ENC_BIG_ENDIAN);
282 offset++;
284 /* ata command/status */
285 if(!response){
286 proto_tree_add_item(tree, hf_aoe_acmd, tvb, offset, 1, ENC_BIG_ENDIAN);
287 col_append_fstr(pinfo->cinfo, COL_INFO, " ATA:%s", val_to_str(tvb_get_uint8(tvb, offset), ata_cmd_vals, " Unknown ATA<0x%02x>"));
288 } else {
289 proto_tree_add_item(tree, hf_aoe_astatus, tvb, offset, 1, ENC_BIG_ENDIAN);
290 if(ata_info != NULL && ata_info->request_frame){
291 /* we don't know what command it was unless we saw the request_frame */
292 tmp_item=proto_tree_add_uint(tree, hf_aoe_acmd, tvb, 0, 0, ata_info->cmd);
293 proto_item_set_generated(tmp_item);
294 col_append_fstr(pinfo->cinfo, COL_INFO, " ATA:%s", val_to_str(ata_info->cmd, ata_cmd_vals, " Unknown ATA<0x%02x>"));
297 offset++;
299 /*lba probably complete wrong */
300 lba=tvb_get_letohs(tvb, offset+4);
301 lba=(lba<<32)|tvb_get_letohl(tvb, offset);
302 offset+=8;
303 proto_tree_add_uint64(tree, hf_aoe_lba, tvb, offset-8, 6, lba);
307 static void
308 dissect_aoe_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
310 uint8_t flags, cmd;
311 uint32_t tag;
312 proto_item *flags_item;
313 proto_tree *flags_tree;
315 /* read and dissect the flags */
316 flags=tvb_get_uint8(tvb, 0)&0x0f;
318 flags_tree=proto_tree_add_subtree(tree, tvb, 0, 1, ett_aoe_flags, &flags_item, "Flags:");
320 proto_tree_add_item(flags_tree, hf_aoe_flags_response, tvb, 0, 1, ENC_BIG_ENDIAN);
321 proto_tree_add_item(flags_tree, hf_aoe_flags_error, tvb, 0, 1, ENC_BIG_ENDIAN);
323 proto_item_append_text(flags_item,(flags&AOE_FLAGS_RESPONSE)?" Response":" Request");
325 /* error */
326 if(flags&AOE_FLAGS_ERROR){
327 proto_item_append_text(flags_item, " Error");
328 proto_tree_add_item(tree, hf_aoe_error, tvb, 1, 1, ENC_BIG_ENDIAN);
329 col_append_fstr(pinfo->cinfo, COL_INFO, "Error:%s ", val_to_str(tvb_get_uint8(tvb, 1), error_vals, "Unknown error<%d>"));
332 /* major/minor address */
333 proto_tree_add_item(tree, hf_aoe_major, tvb, 2, 2, ENC_BIG_ENDIAN);
334 proto_tree_add_item(tree, hf_aoe_minor, tvb, 4, 1, ENC_BIG_ENDIAN);
336 /* command */
337 cmd=tvb_get_uint8(tvb, 5);
338 proto_tree_add_item(tree, hf_aoe_cmd, tvb, 5, 1, ENC_BIG_ENDIAN);
339 col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", val_to_str(cmd, cmd_vals, "Unknown command<%d>"), (flags&AOE_FLAGS_RESPONSE)?"Response":"Request");
342 /* tag */
343 tag=tvb_get_letohl(tvb, 6);
344 proto_tree_add_item(tree, hf_aoe_tag, tvb, 6, 4, ENC_BIG_ENDIAN);
347 switch(cmd){
348 case AOE_CMD_ISSUE_ATA_COMMAND:
349 dissect_ata_pdu(pinfo, tree, tvb, 10, flags&AOE_FLAGS_RESPONSE, tag);
350 break;
351 case AOE_CMD_QUERY_CONFIG_INFO:
352 break;
357 static int
358 dissect_aoe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
360 proto_item *item;
361 proto_tree *tree;
362 uint8_t version;
364 col_set_str(pinfo->cinfo, COL_PROTOCOL, "AoE");
365 col_clear(pinfo->cinfo, COL_INFO);
367 item = proto_tree_add_item(parent_tree, proto_aoe, tvb, 0, -1, ENC_NA);
368 tree = proto_item_add_subtree(item, ett_aoe);
370 version=tvb_get_uint8(tvb, 0)>>4;
371 proto_tree_add_uint(tree, hf_aoe_version, tvb, 0, 1, version);
372 switch(version){
373 case 1:
374 dissect_aoe_v1(tvb, pinfo, tree);
375 break;
378 return tvb_captured_length(tvb);
381 void
382 proto_register_aoe(void)
385 static hf_register_info hf[] = {
386 { &hf_aoe_cmd,
387 { "Command", "aoe.cmd", FT_UINT8, BASE_DEC, VALS(cmd_vals), 0x0,
388 "AOE Command", HFILL}},
389 { &hf_aoe_version,
390 { "Version", "aoe.version", FT_UINT8, BASE_DEC, NULL, 0x0,
391 "Version of the AOE protocol", HFILL}},
392 { &hf_aoe_error,
393 { "Error", "aoe.error", FT_UINT8, BASE_DEC, VALS(error_vals), 0x0,
394 "Error code", HFILL}},
395 { &hf_aoe_err_feature,
396 { "Err/Feature", "aoe.err_feature", FT_UINT8, BASE_HEX, NULL, 0x0,
397 NULL, HFILL}},
398 { &hf_aoe_sector_count,
399 { "Sector Count", "aoe.sector_count", FT_UINT8, BASE_DEC, NULL, 0x0,
400 NULL, HFILL}},
401 { &hf_aoe_flags_response,
402 { "Response flag", "aoe.response", FT_BOOLEAN, 8, TFS(&tfs_response_request), AOE_FLAGS_RESPONSE, "Whether this is a response PDU or not", HFILL}},
403 { &hf_aoe_flags_error,
404 { "Error flag", "aoe.flags_error", FT_BOOLEAN, 8, TFS(&tfs_error), AOE_FLAGS_ERROR, "Whether this is an error PDU or not", HFILL}},
405 { &hf_aoe_major,
406 { "Major", "aoe.major", FT_UINT16, BASE_HEX, NULL, 0x0,
407 "Major address", HFILL}},
408 { &hf_aoe_minor,
409 { "Minor", "aoe.minor", FT_UINT8, BASE_HEX, NULL, 0x0,
410 "Minor address", HFILL}},
411 { &hf_aoe_acmd,
412 { "ATA Cmd", "aoe.ata.cmd", FT_UINT8, BASE_HEX, VALS(ata_cmd_vals), 0x0,
413 "ATA command opcode", HFILL}},
414 { &hf_aoe_astatus,
415 { "ATA Status", "aoe.ata.status", FT_UINT8, BASE_HEX, NULL, 0x0,
416 "ATA status bits", HFILL}},
417 { &hf_aoe_tag,
418 { "Tag", "aoe.tag", FT_UINT32, BASE_HEX, NULL, 0x0,
419 "Command Tag", HFILL}},
420 { &hf_aoe_aflags_e,
421 { "E", "aoe.aflags.e", FT_BOOLEAN, 8, TFS(&tfs_aflags_e), AOE_AFLAGS_E, "Whether this is a normal or LBA48 command", HFILL}},
422 { &hf_aoe_aflags_d,
423 { "D", "aoe.aflags.d", FT_BOOLEAN, 8, NULL, AOE_AFLAGS_D, "Device/head register flag", HFILL}},
424 { &hf_aoe_aflags_a,
425 { "A", "aoe.aflags.a", FT_BOOLEAN, 8, TFS(&tfs_aflags_a), AOE_AFLAGS_A, "Whether this is an asynchronous write or not", HFILL}},
426 { &hf_aoe_aflags_w,
427 { "W", "aoe.aflags.w", FT_BOOLEAN, 8, TFS(&tfs_aflags_w), AOE_AFLAGS_W, "Is this a command writing data to the device or not", HFILL}},
428 { &hf_aoe_lba,
429 { "Lba", "aoe.lba", FT_UINT64, BASE_HEX, NULL, 0x00, "Lba address", HFILL}},
430 { &hf_aoe_response_in,
431 { "Response In", "aoe.response_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, "The response to this packet is in this frame", HFILL }},
432 { &hf_aoe_response_to,
433 { "Response To", "aoe.response_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, "This is a response to the ATA command in this frame", HFILL }},
434 { &hf_aoe_time,
435 { "Time from request", "aoe.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for ATA calls", HFILL }},
438 static int *ett[] = {
439 &ett_aoe,
440 &ett_aoe_flags,
443 proto_aoe = proto_register_protocol("ATAoverEthernet", "AOE", "aoe");
444 proto_register_field_array(proto_aoe, hf, array_length(hf));
445 proto_register_subtree_array(ett, array_length(ett));
447 aoe_handle = register_dissector("aoe", dissect_aoe, proto_aoe);
449 ata_cmd_unmatched=wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), ata_cmd_hash_unmatched, ata_cmd_equal_unmatched);
450 ata_cmd_matched=wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), ata_cmd_hash_matched, ata_cmd_equal_matched);
453 void
454 proto_reg_handoff_aoe(void)
456 dissector_add_uint("ethertype", ETHERTYPE_AOE, aoe_handle);
460 * Editor modelines - https://www.wireshark.org/tools/modelines.html
462 * Local Variables:
463 * c-basic-offset: 2
464 * tab-width: 8
465 * indent-tabs-mode: nil
466 * End:
468 * ex: set shiftwidth=2 tabstop=8 expandtab:
469 * :indentSize=2:tabSize=8:noTabs=true: