Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-usbms-uasp.c
blob7f2951ccebec23bd6ab8b7410c80a0ebc315e94e
1 /* packet-usbms-uasp.c
2 * Routines for USB Attached SCSI dissection
3 * Copyright 2021, Aidan MacDonald <amachronic@protonmail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include <config.h>
14 #include <epan/packet.h>
15 #include "packet-usb.h"
16 #include "packet-scsi.h"
18 void proto_register_uasp(void);
19 void proto_reg_handoff_uasp(void);
21 #define IF_PROTOCOL_UAS 0x62
23 static dissector_handle_t uasp_descriptor_handle;
24 static dissector_handle_t uasp_bulk_handle;
26 static int proto_uasp;
28 static int hf_pipe_usage_descr_pipe_id;
29 static int hf_uas_iu_id;
30 static int hf_uas_tag;
31 static int hf_uas_cmd_command_priority;
32 static int hf_uas_cmd_task_attribute;
33 static int hf_uas_cmd_additional_cdb_length;
34 static int hf_uas_sense_status_qualifier;
35 static int hf_uas_sense_status;
36 static int hf_uas_sense_length;
37 static int hf_uas_response_additional_info;
38 static int hf_uas_response_code;
39 static int hf_uas_taskmgmt_function;
40 static int hf_uas_taskmgmt_tag_of_managed_task;
41 static int hf_uas_tag_started_frame;
42 static int hf_uas_tag_completed_frame;
43 static int hf_uas_tag_read_ready_frame;
44 static int hf_uas_tag_write_ready_frame;
45 static int hf_uas_tag_data_recv_frame;
46 static int hf_uas_tag_data_sent_frame;
48 static int ett_uasp;
49 static int ett_uasp_desc;
51 #define DT_PIPE_USAGE 0x24
53 static const value_string uasp_descriptor_type_vals[] = {
54 {DT_PIPE_USAGE, "Pipe Usage"},
55 {0, NULL}
58 static value_string_ext uasp_descriptor_type_vals_ext =
59 VALUE_STRING_EXT_INIT(uasp_descriptor_type_vals);
61 #define COMMAND_PIPE_ID 0x01
62 #define STATUS_PIPE_ID 0x02
63 #define DATA_IN_PIPE_ID 0x03
64 #define DATA_OUT_PIPE_ID 0x04
66 static const value_string uasp_pipe_id_vals[] = {
67 {COMMAND_PIPE_ID, "Command"},
68 {STATUS_PIPE_ID, "Status"},
69 {DATA_IN_PIPE_ID, "Data-In"},
70 {DATA_OUT_PIPE_ID, "Data-Out"},
71 {0, NULL}
74 #define COMMAND_IU_ID 0x01
75 #define SENSE_IU_ID 0x03
76 #define RESPONSE_IU_ID 0x04
77 #define TASK_MGMT_IU_ID 0x05
78 #define READ_READY_IU_ID 0x06
79 #define WRITE_READY_IU_ID 0x07
81 static const value_string uasp_iu_id_vals[] = {
82 {COMMAND_IU_ID, "Command IU"},
83 {SENSE_IU_ID, "Sense IU"},
84 {RESPONSE_IU_ID, "Response IU"},
85 {TASK_MGMT_IU_ID, "Task Management IU"},
86 {READ_READY_IU_ID, "Read Ready IU"},
87 {WRITE_READY_IU_ID, "Write Ready IU"},
88 {0, NULL},
91 typedef struct _uasp_itlq_nexus_t {
92 uint16_t tag; /* tag for this ITLQ nexus */
93 uint32_t started_frame; /* when tag was first seen */
94 uint32_t completed_frame; /* when tag was completed */
95 uint32_t read_ready_frame; /* when read ready was issued for tag */
96 uint32_t write_ready_frame; /* when write ready was issued for tag */
97 uint32_t data_recv_frame; /* when read data was received for tag */
98 uint32_t data_sent_frame; /* when write data was sent for tag */
99 itl_nexus_t* itl;
100 itlq_nexus_t itlq;
101 } uasp_itlq_nexus_t;
103 typedef struct _uasp_conv_info_t {
104 /* for keeping track of what endpoint is used for what */
105 uint8_t command_endpoint;
106 uint8_t status_endpoint;
107 uint8_t data_in_endpoint;
108 uint8_t data_out_endpoint;
110 /* tag of each read/write ready IU; indexed by pinfo->num */
111 wmem_tree_t* read_ready;
112 wmem_tree_t* write_ready;
114 /* ITL nexus; indexed by LUN */
115 wmem_tree_t* itl;
117 /* UASP ITLQ nexus per command; multi part key
118 * [0] = UAS tag
119 * [1] = pinfo->num */
120 wmem_tree_t* itlq;
121 } uasp_conv_info_t;
123 static uasp_conv_info_t*
124 get_uasp_conv_info(usb_conv_info_t *usb_conv_info)
126 uasp_conv_info_t *uasp_conv_info = (uasp_conv_info_t *)usb_conv_info->class_data;
128 if (!uasp_conv_info) {
129 uasp_conv_info = wmem_new(wmem_file_scope(), uasp_conv_info_t);
130 uasp_conv_info->command_endpoint = 0;
131 uasp_conv_info->status_endpoint = 0;
132 uasp_conv_info->data_in_endpoint = 0;
133 uasp_conv_info->data_out_endpoint = 0;
134 uasp_conv_info->read_ready = wmem_tree_new(wmem_file_scope());
135 uasp_conv_info->write_ready = wmem_tree_new(wmem_file_scope());
136 uasp_conv_info->itl = wmem_tree_new(wmem_file_scope());
137 uasp_conv_info->itlq = wmem_tree_new(wmem_file_scope());
139 usb_conv_info->class_data = uasp_conv_info;
140 usb_conv_info->class_data_type = USB_CONV_MASS_STORAGE_UASP;
141 } else if (usb_conv_info->class_data_type != USB_CONV_MASS_STORAGE_UASP) {
142 return NULL;
145 return uasp_conv_info;
148 static uint16_t
149 get_scsi_lun(tvbuff_t* tvb, int offset)
151 uint16_t lun;
153 /* Copied from packet-iscsi.c - not really correct but good enough... */
154 if (tvb_get_uint8(tvb, offset) & 0x40) {
155 /* volume set addressing */
156 lun = tvb_get_uint8(tvb, offset) & 0x3f;
157 lun <<= 8;
158 lun |= tvb_get_uint8(tvb,offset + 1);
159 } else {
160 lun = tvb_get_uint8(tvb, offset + 1);
163 return lun;
166 static uasp_itlq_nexus_t*
167 create_itlq_nexus(packet_info *pinfo, uasp_conv_info_t *uasp_conv_info, uint16_t lun, uint16_t tag)
169 wmem_tree_key_t key[3];
170 uint32_t tag32 = tag;
171 itl_nexus_t *itl;
172 uasp_itlq_nexus_t *uitlq;
174 /* ensure ITL nexus exists */
175 itl = (itl_nexus_t *)wmem_tree_lookup32(uasp_conv_info->itl, lun);
176 if(!itl) {
177 itl = wmem_new(wmem_file_scope(), itl_nexus_t);
178 itl->cmdset = 0xff;
179 itl->conversation = NULL;
180 wmem_tree_insert32(uasp_conv_info->itl, lun, itl);
183 /* ensure ITLQ nexus exists */
184 key[0].length = 1;
185 key[0].key = &tag32;
186 key[1].length = 1;
187 key[1].key = &pinfo->num;
188 key[2].length = 0;
190 uitlq = (uasp_itlq_nexus_t *)wmem_tree_lookup32_array(uasp_conv_info->itlq, key);
191 if(!uitlq) {
192 uitlq = wmem_new(wmem_file_scope(), uasp_itlq_nexus_t);
193 uitlq->tag = tag;
194 uitlq->started_frame = pinfo->num;
195 uitlq->completed_frame = 0;
196 uitlq->read_ready_frame = 0;
197 uitlq->write_ready_frame = 0;
198 uitlq->data_sent_frame = 0;
199 uitlq->data_recv_frame = 0;
200 uitlq->itl = itl;
201 uitlq->itlq.lun = lun;
202 uitlq->itlq.scsi_opcode = 0xffff;
203 uitlq->itlq.task_flags = 0;
204 uitlq->itlq.data_length = 0;
205 uitlq->itlq.bidir_data_length = 0;
206 uitlq->itlq.fc_time = pinfo->abs_ts;
207 uitlq->itlq.first_exchange_frame = pinfo->num;
208 uitlq->itlq.last_exchange_frame = 0;
209 uitlq->itlq.flags = 0;
210 uitlq->itlq.alloc_len = 0;
211 uitlq->itlq.extra_data = NULL;
213 wmem_tree_insert32_array(uasp_conv_info->itlq, key, uitlq);
216 return uitlq;
219 static uasp_itlq_nexus_t*
220 get_itlq_nexus(packet_info* pinfo, uasp_conv_info_t *uasp_conv_info, uint16_t tag)
222 uint32_t tag32 = tag;
223 wmem_tree_key_t key[3];
224 uasp_itlq_nexus_t *uitlq;
226 key[0].length = 1;
227 key[0].key = &tag32;
228 key[1].length = 1;
229 key[1].key = &pinfo->num;
230 key[2].length = 0;
232 uitlq = (uasp_itlq_nexus_t *)wmem_tree_lookup32_array_le(uasp_conv_info->itlq, key);
233 if(!uitlq || uitlq->tag != tag)
234 return NULL;
236 return uitlq;
239 static void
240 create_ready_iu(wmem_tree_t* tree, packet_info* pinfo, uint16_t tag)
242 wmem_tree_insert32(tree, pinfo->num, GUINT_TO_POINTER(tag));
245 static uint16_t
246 get_ready_iu(wmem_tree_t* tree, packet_info* pinfo)
248 return GPOINTER_TO_UINT(wmem_tree_lookup32_le(tree, pinfo->num));
251 #define DATA_WRITE (-1)
252 #define DATA_READ (-2)
254 static void
255 add_uasp_tag_links(tvbuff_t *tvb, proto_tree *uasp_tree, uasp_itlq_nexus_t *uitlq, int kind)
257 proto_item *ti;
259 if (!uitlq)
260 return;
262 if (uitlq->started_frame && kind != COMMAND_IU_ID && kind != TASK_MGMT_IU_ID) {
263 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag_started_frame, tvb, 0, 0, uitlq->started_frame);
264 proto_item_set_generated(ti);
267 if (uitlq->read_ready_frame && kind != READ_READY_IU_ID) {
268 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag_read_ready_frame, tvb, 0, 0, uitlq->read_ready_frame);
269 proto_item_set_generated(ti);
272 if (uitlq->write_ready_frame && kind != WRITE_READY_IU_ID) {
273 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag_write_ready_frame, tvb, 0, 0, uitlq->write_ready_frame);
274 proto_item_set_generated(ti);
277 if (uitlq->data_recv_frame && kind != DATA_READ) {
278 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag_data_recv_frame, tvb, 0, 0, uitlq->data_recv_frame);
279 proto_item_set_generated(ti);
282 if (uitlq->data_sent_frame && kind != DATA_WRITE) {
283 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag_data_sent_frame, tvb, 0, 0, uitlq->data_sent_frame);
284 proto_item_set_generated(ti);
287 if (uitlq->completed_frame && kind != SENSE_IU_ID && kind != RESPONSE_IU_ID) {
288 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag_completed_frame, tvb, 0, 0, uitlq->completed_frame);
289 proto_item_set_generated(ti);
293 static int
294 dissect_uasp_iu(tvbuff_t *tvb, packet_info *pinfo,
295 proto_tree *parent_tree, proto_tree *uasp_tree,
296 urb_info_t *urb _U_, uasp_conv_info_t *uasp_conv_info)
298 uint8_t iu_id;
299 uint8_t status;
300 uint16_t tag;
301 uint16_t lun;
302 uasp_itlq_nexus_t *uitlq = NULL;
303 int rlen, len;
304 tvbuff_t *cdb_tvb;
306 /* an IU header is 4 bytes */
307 if (tvb_reported_length(tvb) < 4)
308 return 0;
310 iu_id = tvb_get_uint8(tvb, 0);
311 tag = tvb_get_ntohs(tvb, 2);
313 col_add_str(pinfo->cinfo, COL_INFO,
314 val_to_str(iu_id, uasp_iu_id_vals, "Unknown IU [0x%02x]"));
316 proto_tree_add_item(uasp_tree, hf_uas_iu_id, tvb, 0, 1, ENC_NA);
317 proto_tree_add_item(uasp_tree, hf_uas_tag, tvb, 2, 2, ENC_BIG_ENDIAN);
319 switch(iu_id) {
320 case COMMAND_IU_ID:
321 proto_tree_add_item(uasp_tree, hf_uas_cmd_command_priority, tvb, 4, 1, ENC_NA);
322 proto_tree_add_item(uasp_tree, hf_uas_cmd_task_attribute, tvb, 4, 1, ENC_NA);
323 proto_tree_add_item(uasp_tree, hf_uas_cmd_additional_cdb_length, tvb, 6, 1, ENC_NA);
324 dissect_scsi_lun(uasp_tree, tvb, 8);
326 lun = get_scsi_lun(tvb, 8);
327 uitlq = create_itlq_nexus(pinfo, uasp_conv_info, lun, tag);
329 rlen = 16 + tvb_get_uint8(tvb, 6);
330 len = rlen;
332 if (len > tvb_captured_length_remaining(tvb, 16))
333 len = tvb_captured_length_remaining(tvb, 16);
335 if (len) {
336 cdb_tvb = tvb_new_subset_length_caplen(tvb, 16, len, rlen);
337 dissect_scsi_cdb(cdb_tvb, pinfo, parent_tree, SCSI_DEV_UNKNOWN,
338 &uitlq->itlq, uitlq->itl);
341 break;
343 case SENSE_IU_ID:
344 proto_tree_add_item(uasp_tree, hf_uas_sense_status_qualifier, tvb, 4, 2, ENC_BIG_ENDIAN);
345 proto_tree_add_item(uasp_tree, hf_uas_sense_status, tvb, 6, 1, ENC_NA);
346 proto_tree_add_item(uasp_tree, hf_uas_sense_length, tvb, 14, 2, ENC_BIG_ENDIAN);
348 uitlq = get_itlq_nexus(pinfo, uasp_conv_info, tag);
349 if (uitlq) {
350 uitlq->completed_frame = pinfo->num;
351 uitlq->itlq.last_exchange_frame = pinfo->num;
353 status = tvb_get_uint8(tvb, 6);
354 dissect_scsi_rsp(tvb, pinfo, parent_tree, &uitlq->itlq, uitlq->itl, status);
356 /* dissect sense info, if any */
357 rlen = tvb_get_ntohs(tvb, 14);
358 if (rlen) {
359 dissect_scsi_snsinfo(tvb, pinfo, parent_tree, 16, rlen, &uitlq->itlq, uitlq->itl);
363 break;
365 case RESPONSE_IU_ID:
366 proto_tree_add_item(uasp_tree, hf_uas_response_additional_info, tvb, 4, 3, ENC_BIG_ENDIAN);
367 proto_tree_add_item(uasp_tree, hf_uas_response_code, tvb, 7, 1, ENC_NA);
368 break;
370 case TASK_MGMT_IU_ID:
371 proto_tree_add_item(uasp_tree, hf_uas_taskmgmt_function, tvb, 4, 1, ENC_NA);
372 proto_tree_add_item(uasp_tree, hf_uas_taskmgmt_tag_of_managed_task, tvb, 6, 2, ENC_BIG_ENDIAN);
373 dissect_scsi_lun(uasp_tree, tvb, 8);
374 break;
376 case READ_READY_IU_ID:
377 uitlq = get_itlq_nexus(pinfo, uasp_conv_info, tag);
378 if (uitlq)
379 uitlq->read_ready_frame = pinfo->num;
381 create_ready_iu(uasp_conv_info->read_ready, pinfo, tag);
382 break;
384 case WRITE_READY_IU_ID:
385 uitlq = get_itlq_nexus(pinfo, uasp_conv_info, tag);
386 if (uitlq)
387 uitlq->write_ready_frame = pinfo->num;
389 create_ready_iu(uasp_conv_info->write_ready, pinfo, tag);
390 break;
393 add_uasp_tag_links(tvb, uasp_tree, uitlq, iu_id);
395 return tvb_captured_length(tvb);
398 static int
399 dissect_uasp_data(tvbuff_t *tvb, packet_info *pinfo,
400 proto_tree *parent_tree, proto_tree *uasp_tree,
401 urb_info_t *urb, uasp_conv_info_t *uasp_conv_info)
403 proto_item *ti;
404 uint16_t tag;
405 uasp_itlq_nexus_t *uitlq;
406 bool is_request;
408 is_request = (urb->direction == P2P_DIR_SENT) ? true : false;
410 /* TODO - fetch tag from USB 3.0 Bulk Streams.
412 * It seems Wireshark doesn't track the stream ID so we can't yet
413 * dissect UASP over USB 3.0 traffic. (The Linux kernel doesn't even
414 * export an URB's stream ID, so OS support for this might be spotty
415 * or even non-existent...)
417 if (is_request)
418 tag = get_ready_iu(uasp_conv_info->write_ready, pinfo);
419 else
420 tag = get_ready_iu(uasp_conv_info->read_ready, pinfo);
422 /* add tag to tree */
423 ti = proto_tree_add_uint(uasp_tree, hf_uas_tag, tvb, 0, 0, tag);
424 proto_item_set_generated(ti);
426 uitlq = get_itlq_nexus(pinfo, uasp_conv_info, tag);
427 if (uitlq) {
428 if (is_request)
429 uitlq->data_sent_frame = pinfo->num;
430 else
431 uitlq->data_recv_frame = pinfo->num;
433 add_uasp_tag_links(tvb, uasp_tree, uitlq, is_request ? DATA_WRITE : DATA_READ);
434 dissect_scsi_payload(tvb, pinfo, parent_tree, is_request, &uitlq->itlq, uitlq->itl, 0);
437 return tvb_captured_length(tvb);
440 static int
441 dissect_uasp_bulk(tvbuff_t *tvb,
442 packet_info *pinfo,
443 proto_tree *parent_tree,
444 void *data)
446 typedef int(*uasp_dissector_t)(tvbuff_t *, packet_info *, proto_tree *,
447 proto_tree *, urb_info_t *, uasp_conv_info_t *);
449 proto_tree *uasp_tree;
450 proto_item *ti;
451 uasp_dissector_t dissector = NULL;
452 uint8_t endpoint;
453 urb_info_t *urb = (urb_info_t *)data;
454 uasp_conv_info_t *uasp_conv_info = get_uasp_conv_info(urb->conv);
456 if (!uasp_conv_info)
457 return 0;
459 endpoint = urb->endpoint;
460 if (endpoint == uasp_conv_info->command_endpoint ||
461 endpoint == uasp_conv_info->status_endpoint)
462 dissector = dissect_uasp_iu;
463 else if (endpoint == uasp_conv_info->data_in_endpoint ||
464 endpoint == uasp_conv_info->data_out_endpoint)
465 dissector = dissect_uasp_data;
466 else
467 return 0;
469 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UASP");
470 col_clear(pinfo->cinfo, COL_INFO);
472 ti = proto_tree_add_protocol_format(parent_tree, proto_uasp, tvb, 0, -1,
473 "USB Attached SCSI");
474 uasp_tree = proto_item_add_subtree(ti, ett_uasp);
476 return dissector(tvb, pinfo, parent_tree, uasp_tree, urb, uasp_conv_info);
479 static int
480 dissect_uasp_descriptor(tvbuff_t *tvb,
481 packet_info *pinfo _U_,
482 proto_tree *parent_tree,
483 void *data _U_)
485 uint8_t desc_type;
486 uint8_t desc_len;
487 proto_tree *desc_tree;
488 proto_tree *desc_tree_item;
489 urb_info_t *urb = (urb_info_t *)data;
490 usb_trans_info_t *usb_trans_info = NULL;
491 uasp_conv_info_t *uasp_conv_info;
493 if (urb)
494 usb_trans_info = urb->usb_trans_info;
496 /* Descriptor must have a length and type field. */
497 if (tvb_reported_length(tvb) < 2)
498 return 0;
500 desc_len = tvb_get_uint8(tvb, 0);
501 desc_type = tvb_get_uint8(tvb, 1);
503 if (desc_type != DT_PIPE_USAGE)
504 return 0;
506 desc_tree = proto_tree_add_subtree(parent_tree, tvb, 0, desc_len,
507 ett_uasp_desc, &desc_tree_item,
508 "UAS PIPE USAGE DESCRIPTOR");
510 dissect_usb_descriptor_header(desc_tree, tvb, 0,
511 &uasp_descriptor_type_vals_ext);
512 proto_tree_add_item(desc_tree, hf_pipe_usage_descr_pipe_id,
513 tvb, 2, 1, ENC_NA);
515 /* The pipe usage descriptor should follow the endpoint descriptor
516 * of the endpoint it applies to. Keep track of the pipe ID for the
517 * endpoint so the bulk dissector can distinguish between commands
518 * and data reliably */
519 if (!pinfo->fd->visited && usb_trans_info && usb_trans_info->interface_info) {
520 uint8_t endpoint = usb_trans_info->interface_endpoint;
521 uint8_t pipe_id = tvb_get_uint8(tvb, 2);
523 uasp_conv_info = get_uasp_conv_info(usb_trans_info->interface_info);
524 if (uasp_conv_info) {
525 switch (pipe_id) {
526 case COMMAND_PIPE_ID:
527 uasp_conv_info->command_endpoint = endpoint;
528 break;
529 case STATUS_PIPE_ID:
530 uasp_conv_info->status_endpoint = endpoint;
531 break;
532 case DATA_IN_PIPE_ID:
533 uasp_conv_info->data_in_endpoint = endpoint;
534 break;
535 case DATA_OUT_PIPE_ID:
536 uasp_conv_info->data_out_endpoint = endpoint;
537 break;
542 return desc_len;
545 void
546 proto_register_uasp(void)
548 static hf_register_info hf[] = {
549 { &hf_pipe_usage_descr_pipe_id,
550 { "bPipeID", "uasp.pipe_usage.bPipeID",
551 FT_UINT8, BASE_HEX, VALS(uasp_pipe_id_vals), 0x00, NULL, HFILL } },
553 { &hf_uas_iu_id,
554 { "IU ID", "uasp.iu_id",
555 FT_UINT8, BASE_HEX, VALS(uasp_iu_id_vals), 0x00, NULL, HFILL } },
556 { &hf_uas_tag,
557 { "Tag", "uasp.tag",
558 FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL } },
560 { &hf_uas_cmd_command_priority,
561 { "Command Priority", "uasp.command.priority",
562 FT_UINT8, BASE_DEC, NULL, 0x78, NULL, HFILL } },
563 { &hf_uas_cmd_task_attribute,
564 { "Task Attribute", "uasp.command.task_attr",
565 FT_UINT8, BASE_HEX, NULL, 0x07, NULL, HFILL } },
566 { &hf_uas_cmd_additional_cdb_length,
567 { "Additional CDB Length", "uasp.command.add_cdb_length",
568 FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
570 { &hf_uas_sense_status_qualifier,
571 { "Status Qualifier", "uasp.sense.status_qualifier",
572 FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL } },
573 { &hf_uas_sense_status,
574 { "Status", "uasp.sense.status",
575 FT_UINT8, BASE_DEC, VALS(scsi_status_val), 0x00, NULL, HFILL } },
576 { &hf_uas_sense_length,
577 { "Length", "uasp.sense.length",
578 FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL } },
580 { &hf_uas_response_additional_info,
581 { "Additional Response Info", "uasp.response.add_info",
582 FT_UINT24, BASE_HEX, NULL, 0x00, NULL, HFILL } },
583 { &hf_uas_response_code,
584 { "Response Code", "uasp.response.code",
585 FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
587 { &hf_uas_taskmgmt_function,
588 { "Task Management Function", "uasp.task_mgmt.function",
589 FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
590 { &hf_uas_taskmgmt_tag_of_managed_task,
591 { "Tag of Managed Task", "uasp.task_mgmt.managed_tag",
592 FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL } },
594 { &hf_uas_tag_started_frame,
595 { "Tag started in", "uasp.tag_started_frame", FT_FRAMENUM, BASE_NONE, NULL, 0,
596 "The command with this tag was started in this frame", HFILL } },
597 { &hf_uas_tag_completed_frame,
598 { "Tag completed in", "uasp.tag_completed_frame", FT_FRAMENUM, BASE_NONE, NULL, 0,
599 "The command with this tag was completed in this frame", HFILL } },
600 { &hf_uas_tag_read_ready_frame,
601 { "Tag read ready in", "uasp.tag_read_ready_frame", FT_FRAMENUM, BASE_NONE, NULL, 0,
602 "The request data for the tag became ready in this frame", HFILL } },
603 { &hf_uas_tag_write_ready_frame,
604 { "Tag write ready in", "uasp.tag_write_ready_frame", FT_FRAMENUM, BASE_NONE, NULL, 0,
605 "The request data for the tag became ready in this frame", HFILL } },
606 { &hf_uas_tag_data_recv_frame,
607 { "Tag data received in", "uasp.tag_data_recv_frame", FT_FRAMENUM, BASE_NONE, NULL, 0,
608 "The response data for the tag was transmitted in this frame", HFILL } },
609 { &hf_uas_tag_data_sent_frame,
610 { "Tag data sent in", "uasp.tag_data_sent_frame", FT_FRAMENUM, BASE_NONE, NULL, 0,
611 "The request data for the tag was transmitted in this frame", HFILL } },
614 static int *uasp_ett[] = {
615 &ett_uasp,
616 &ett_uasp_desc,
619 proto_uasp = proto_register_protocol("USB Attached SCSI", "UASP", "uasp");
620 proto_register_field_array(proto_uasp, hf, array_length(hf));
621 proto_register_subtree_array(uasp_ett, array_length(uasp_ett));
623 uasp_descriptor_handle = register_dissector("uasp", dissect_uasp_descriptor, proto_uasp);
624 uasp_bulk_handle = register_dissector("uasp.bulk", dissect_uasp_bulk, proto_uasp);
627 void
628 proto_reg_handoff_uasp(void)
630 dissector_add_uint("usbms.descriptor", IF_PROTOCOL_UAS, uasp_descriptor_handle);
631 dissector_add_uint("usbms.bulk", IF_PROTOCOL_UAS, uasp_bulk_handle);