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
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
;
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"},
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"},
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"},
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 */
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 */
117 /* UASP ITLQ nexus per command; multi part key
119 * [1] = pinfo->num */
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
) {
145 return uasp_conv_info
;
149 get_scsi_lun(tvbuff_t
* tvb
, int offset
)
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;
158 lun
|= tvb_get_uint8(tvb
,offset
+ 1);
160 lun
= tvb_get_uint8(tvb
, offset
+ 1);
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
;
172 uasp_itlq_nexus_t
*uitlq
;
174 /* ensure ITL nexus exists */
175 itl
= (itl_nexus_t
*)wmem_tree_lookup32(uasp_conv_info
->itl
, lun
);
177 itl
= wmem_new(wmem_file_scope(), itl_nexus_t
);
179 itl
->conversation
= NULL
;
180 wmem_tree_insert32(uasp_conv_info
->itl
, lun
, itl
);
183 /* ensure ITLQ nexus exists */
187 key
[1].key
= &pinfo
->num
;
190 uitlq
= (uasp_itlq_nexus_t
*)wmem_tree_lookup32_array(uasp_conv_info
->itlq
, key
);
192 uitlq
= wmem_new(wmem_file_scope(), uasp_itlq_nexus_t
);
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;
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
);
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
;
229 key
[1].key
= &pinfo
->num
;
232 uitlq
= (uasp_itlq_nexus_t
*)wmem_tree_lookup32_array_le(uasp_conv_info
->itlq
, key
);
233 if(!uitlq
|| uitlq
->tag
!= tag
)
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
));
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)
255 add_uasp_tag_links(tvbuff_t
*tvb
, proto_tree
*uasp_tree
, uasp_itlq_nexus_t
*uitlq
, int kind
)
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
);
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
)
302 uasp_itlq_nexus_t
*uitlq
= NULL
;
306 /* an IU header is 4 bytes */
307 if (tvb_reported_length(tvb
) < 4)
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
);
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);
332 if (len
> tvb_captured_length_remaining(tvb
, 16))
333 len
= tvb_captured_length_remaining(tvb
, 16);
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
);
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
);
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);
359 dissect_scsi_snsinfo(tvb
, pinfo
, parent_tree
, 16, rlen
, &uitlq
->itlq
, uitlq
->itl
);
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
);
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);
376 case READ_READY_IU_ID
:
377 uitlq
= get_itlq_nexus(pinfo
, uasp_conv_info
, tag
);
379 uitlq
->read_ready_frame
= pinfo
->num
;
381 create_ready_iu(uasp_conv_info
->read_ready
, pinfo
, tag
);
384 case WRITE_READY_IU_ID
:
385 uitlq
= get_itlq_nexus(pinfo
, uasp_conv_info
, tag
);
387 uitlq
->write_ready_frame
= pinfo
->num
;
389 create_ready_iu(uasp_conv_info
->write_ready
, pinfo
, tag
);
393 add_uasp_tag_links(tvb
, uasp_tree
, uitlq
, iu_id
);
395 return tvb_captured_length(tvb
);
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
)
405 uasp_itlq_nexus_t
*uitlq
;
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...)
418 tag
= get_ready_iu(uasp_conv_info
->write_ready
, pinfo
);
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
);
429 uitlq
->data_sent_frame
= pinfo
->num
;
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
);
441 dissect_uasp_bulk(tvbuff_t
*tvb
,
443 proto_tree
*parent_tree
,
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
;
451 uasp_dissector_t dissector
= NULL
;
453 urb_info_t
*urb
= (urb_info_t
*)data
;
454 uasp_conv_info_t
*uasp_conv_info
= get_uasp_conv_info(urb
->conv
);
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
;
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
);
480 dissect_uasp_descriptor(tvbuff_t
*tvb
,
481 packet_info
*pinfo _U_
,
482 proto_tree
*parent_tree
,
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
;
494 usb_trans_info
= urb
->usb_trans_info
;
496 /* Descriptor must have a length and type field. */
497 if (tvb_reported_length(tvb
) < 2)
500 desc_len
= tvb_get_uint8(tvb
, 0);
501 desc_type
= tvb_get_uint8(tvb
, 1);
503 if (desc_type
!= DT_PIPE_USAGE
)
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
,
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
) {
526 case COMMAND_PIPE_ID
:
527 uasp_conv_info
->command_endpoint
= endpoint
;
530 uasp_conv_info
->status_endpoint
= endpoint
;
532 case DATA_IN_PIPE_ID
:
533 uasp_conv_info
->data_in_endpoint
= endpoint
;
535 case DATA_OUT_PIPE_ID
:
536 uasp_conv_info
->data_out_endpoint
= endpoint
;
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
} },
554 { "IU ID", "uasp.iu_id",
555 FT_UINT8
, BASE_HEX
, VALS(uasp_iu_id_vals
), 0x00, NULL
, HFILL
} },
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
[] = {
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
);
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
);