Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-usbms-bot.c
blobccd4c3ef1b9745bab82690cf664953319cc9099c
1 /* packet-usbms-bot.c
3 * usb mass storage (bulk-only transport) dissector
4 * Ronnie Sahlberg 2006
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
10 #include "config.h"
12 #include <epan/packet.h>
13 #include "packet-usb.h"
14 #include "packet-scsi.h"
16 void proto_register_usbms_bot(void);
17 void proto_reg_handoff_usbms_bot(void);
19 #define IF_PROTOCOL_BULK_ONLY 0x50
21 /* protocols and header fields */
22 static int proto_usbms_bot;
23 static int hf_usbms_bot_dCBWSignature;
24 static int hf_usbms_bot_dCBWTag;
25 static int hf_usbms_bot_dCBWDataTransferLength;
26 static int hf_usbms_bot_dCBWFlags;
27 static int hf_usbms_bot_dCBWTarget;
28 static int hf_usbms_bot_dCBWLUN;
29 static int hf_usbms_bot_dCBWCBLength;
30 static int hf_usbms_bot_dCSWSignature;
31 static int hf_usbms_bot_dCSWDataResidue;
32 static int hf_usbms_bot_dCSWStatus;
33 static int hf_usbms_bot_request;
34 static int hf_usbms_bot_value;
35 static int hf_usbms_bot_index;
36 static int hf_usbms_bot_length;
37 static int hf_usbms_bot_maxlun;
39 static int ett_usbms_bot;
41 static dissector_handle_t usbms_bot_bulk_handle;
42 static dissector_handle_t usbms_bot_control_handle;
44 /* there is one such structure for each masstorage conversation */
45 typedef struct _usbms_bot_conv_info_t {
46 wmem_tree_t *itl; /* indexed by LUN */
47 wmem_tree_t *itlq; /* pinfo->num */
48 } usbms_bot_conv_info_t;
51 static const value_string status_vals[] = {
52 {0x00, "Command Passed"},
53 {0x01, "Command Failed"},
54 {0x02, "Phase Error"},
55 {0, NULL}
58 static void
59 dissect_usbms_bot_reset(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, bool is_request, usb_trans_info_t *usb_trans_info _U_, urb_info_t *urb _U_)
61 if(is_request){
62 proto_tree_add_item(tree, hf_usbms_bot_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
63 offset += 2;
65 proto_tree_add_item(tree, hf_usbms_bot_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
66 offset += 2;
68 proto_tree_add_item(tree, hf_usbms_bot_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
69 /*offset += 2;*/
70 } else {
71 /* no data in reset response */
75 static void
76 dissect_usbms_bot_get_max_lun(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, bool is_request, usb_trans_info_t *usb_trans_info _U_, urb_info_t *urb _U_)
78 if(is_request){
79 proto_tree_add_item(tree, hf_usbms_bot_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
80 offset += 2;
82 proto_tree_add_item(tree, hf_usbms_bot_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
83 offset += 2;
85 proto_tree_add_item(tree, hf_usbms_bot_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
86 /*offset += 2;*/
87 } else {
88 proto_tree_add_item(tree, hf_usbms_bot_maxlun, tvb, offset, 1, ENC_LITTLE_ENDIAN);
89 /*offset++;*/
94 typedef void (*usb_setup_dissector)(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, bool is_request, usb_trans_info_t *usb_trans_info, urb_info_t *urb);
96 typedef struct _usb_setup_dissector_table_t {
97 uint8_t request;
98 usb_setup_dissector dissector;
99 } usb_setup_dissector_table_t;
100 #define USB_SETUP_RESET 0xff
101 #define USB_SETUP_GET_MAX_LUN 0xfe
102 static const usb_setup_dissector_table_t setup_dissectors[] = {
103 {USB_SETUP_RESET, dissect_usbms_bot_reset},
104 {USB_SETUP_GET_MAX_LUN, dissect_usbms_bot_get_max_lun},
105 {0, NULL}
107 static const value_string setup_request_names_vals[] = {
108 {USB_SETUP_RESET, "RESET"},
109 {USB_SETUP_GET_MAX_LUN, "GET MAX LUN"},
110 {0, NULL}
113 /* Dissector for mass storage control .
114 * Returns tvb_captured_length(tvb) if a class specific dissector was found
115 * and 0 othervise.
117 static int
118 dissect_usbms_bot_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data)
120 bool is_request;
121 urb_info_t *urb;
122 usb_trans_info_t *usb_trans_info;
123 int offset=0;
124 usb_setup_dissector dissector = NULL;
125 const usb_setup_dissector_table_t *tmp;
126 proto_tree *tree;
127 proto_item *ti;
129 /* Reject the packet if data or usb_trans_info are NULL */
130 if (data == NULL || ((urb_info_t *)data)->usb_trans_info == NULL)
131 return 0;
132 urb = (urb_info_t *)data;
133 usb_trans_info = urb->usb_trans_info;
135 is_request=(pinfo->srcport==NO_ENDPOINT);
137 /* See if we can find a class specific dissector for this request */
138 for(tmp=setup_dissectors;tmp->dissector;tmp++){
139 if (tmp->request == usb_trans_info->setup.request){
140 dissector=tmp->dissector;
141 break;
144 /* No we could not find any class specific dissector for this request
145 * return 0 and let USB try any of the standard requests.
147 if(!dissector){
148 return 0;
151 col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBMS");
152 ti = proto_tree_add_protocol_format(parent_tree, proto_usbms_bot, tvb, 0, -1, "USB Mass Storage");
153 tree = proto_item_add_subtree(ti, ett_usbms_bot);
155 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
156 val_to_str(usb_trans_info->setup.request, setup_request_names_vals, "Unknown type %x"),
157 is_request?"Request":"Response");
159 if(is_request){
160 proto_tree_add_item(tree, hf_usbms_bot_request, tvb, offset, 1, ENC_LITTLE_ENDIAN);
161 offset += 1;
164 dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info, urb);
165 return tvb_captured_length(tvb);
168 static proto_tree *
169 create_usbms_bot_protocol_tree(tvbuff_t *tvb, proto_tree *parent_tree)
171 proto_tree *tree;
172 proto_item *ti;
174 ti = proto_tree_add_protocol_format(parent_tree, proto_usbms_bot, tvb, 0, -1, "USB Mass Storage");
175 tree = proto_item_add_subtree(ti, ett_usbms_bot);
177 return tree;
180 static int
181 dissect_usbms_bot_cbw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, usbms_bot_conv_info_t *usbms_bot_conv_info)
183 proto_tree *tree = create_usbms_bot_protocol_tree(tvb, parent_tree);
184 tvbuff_t *cdb_tvb;
185 int offset=0;
186 int cdbrlen, cdblen;
187 uint8_t lun, flags;
188 uint32_t datalen;
189 itl_nexus_t *itl;
190 itlq_nexus_t *itlq;
192 /* dCBWSignature */
193 proto_tree_add_item(tree, hf_usbms_bot_dCBWSignature, tvb, offset, 4, ENC_LITTLE_ENDIAN);
194 offset+=4;
196 /* dCBWTag */
197 proto_tree_add_item(tree, hf_usbms_bot_dCBWTag, tvb, offset, 4, ENC_LITTLE_ENDIAN);
198 offset+=4;
200 /* dCBWDataTransferLength */
201 proto_tree_add_item(tree, hf_usbms_bot_dCBWDataTransferLength, tvb, offset, 4, ENC_LITTLE_ENDIAN);
202 datalen=tvb_get_letohl(tvb, offset);
203 offset+=4;
205 /* dCBWFlags */
206 proto_tree_add_item(tree, hf_usbms_bot_dCBWFlags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
207 flags=tvb_get_uint8(tvb, offset);
208 offset+=1;
210 /* dCBWLUN */
211 proto_tree_add_item(tree, hf_usbms_bot_dCBWTarget, tvb, offset, 1, ENC_LITTLE_ENDIAN);
212 proto_tree_add_item(tree, hf_usbms_bot_dCBWLUN, tvb, offset, 1, ENC_LITTLE_ENDIAN);
213 lun=tvb_get_uint8(tvb, offset)&0x0f;
214 offset+=1;
216 /* make sure we have a ITL structure for this LUN */
217 itl=(itl_nexus_t *)wmem_tree_lookup32(usbms_bot_conv_info->itl, lun);
218 if(!itl){
219 itl=wmem_new(wmem_file_scope(), itl_nexus_t);
220 itl->cmdset=0xff;
221 itl->conversation=NULL;
222 wmem_tree_insert32(usbms_bot_conv_info->itl, lun, itl);
225 /* make sure we have an ITLQ structure for this LUN/transaction */
226 itlq=(itlq_nexus_t *)wmem_tree_lookup32(usbms_bot_conv_info->itlq, pinfo->num);
227 if(!itlq){
228 itlq=wmem_new(wmem_file_scope(), itlq_nexus_t);
229 itlq->lun=lun;
230 itlq->scsi_opcode=0xffff;
231 itlq->task_flags=0;
232 if(datalen){
233 if(flags&0x80){
234 itlq->task_flags|=SCSI_DATA_READ;
235 } else {
236 itlq->task_flags|=SCSI_DATA_WRITE;
239 itlq->data_length=datalen;
240 itlq->bidir_data_length=0;
241 itlq->fc_time=pinfo->abs_ts;
242 itlq->first_exchange_frame=pinfo->num;
243 itlq->last_exchange_frame=0;
244 itlq->flags=0;
245 itlq->alloc_len=0;
246 itlq->extra_data=NULL;
247 wmem_tree_insert32(usbms_bot_conv_info->itlq, pinfo->num, itlq);
250 /* dCBWCBLength */
251 proto_tree_add_item(tree, hf_usbms_bot_dCBWCBLength, tvb, offset, 1, ENC_LITTLE_ENDIAN);
252 cdbrlen=tvb_get_uint8(tvb, offset)&0x1f;
253 offset+=1;
255 cdblen=cdbrlen;
256 if(cdblen>tvb_captured_length_remaining(tvb, offset)){
257 cdblen=tvb_captured_length_remaining(tvb, offset);
259 if(cdblen){
260 cdb_tvb=tvb_new_subset_length_caplen(tvb, offset, cdblen, cdbrlen);
261 dissect_scsi_cdb(cdb_tvb, pinfo, parent_tree, SCSI_DEV_UNKNOWN, itlq, itl);
263 return tvb_captured_length(tvb);
266 static int
267 dissect_usbms_bot_csw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, usbms_bot_conv_info_t *usbms_bot_conv_info)
269 proto_tree *tree = create_usbms_bot_protocol_tree(tvb, parent_tree);
270 int offset=0;
271 uint8_t status;
272 itl_nexus_t *itl;
273 itlq_nexus_t *itlq;
275 /* dCSWSignature */
276 proto_tree_add_item(tree, hf_usbms_bot_dCSWSignature, tvb, offset, 4, ENC_LITTLE_ENDIAN);
277 offset+=4;
279 /* dCSWTag */
280 proto_tree_add_item(tree, hf_usbms_bot_dCBWTag, tvb, offset, 4, ENC_LITTLE_ENDIAN);
281 offset+=4;
283 /* dCSWDataResidue */
284 proto_tree_add_item(tree, hf_usbms_bot_dCSWDataResidue, tvb, offset, 4, ENC_LITTLE_ENDIAN);
285 offset+=4;
287 /* dCSWStatus */
288 proto_tree_add_item(tree, hf_usbms_bot_dCSWStatus, tvb, offset, 1, ENC_LITTLE_ENDIAN);
289 status=tvb_get_uint8(tvb, offset);
290 /*offset+=1;*/
292 itlq=(itlq_nexus_t *)wmem_tree_lookup32_le(usbms_bot_conv_info->itlq, pinfo->num);
293 if(!itlq){
294 return tvb_captured_length(tvb);
296 itlq->last_exchange_frame=pinfo->num;
298 itl=(itl_nexus_t *)wmem_tree_lookup32(usbms_bot_conv_info->itl, itlq->lun);
299 if(!itl){
300 return tvb_captured_length(tvb);
303 if(!status){
304 dissect_scsi_rsp(tvb, pinfo, parent_tree, itlq, itl, 0);
305 } else {
306 /* just send "check condition" */
307 dissect_scsi_rsp(tvb, pinfo, parent_tree, itlq, itl, 0x02);
309 return tvb_captured_length(tvb);
312 static bool
313 usbms_bot_bulk_is_cbw(tvbuff_t *tvb, int offset, bool is_request)
315 return is_request && (tvb_reported_length(tvb)==(unsigned)offset+31) &&
316 tvb_get_letohl(tvb, offset) == 0x43425355;
319 static bool
320 usbms_bot_bulk_is_csw(tvbuff_t *tvb, int offset, bool is_request)
322 return !is_request && (tvb_reported_length(tvb)==(unsigned)offset+13) &&
323 tvb_get_letohl(tvb, offset) == 0x53425355;
326 /* dissector for mass storage bulk data */
327 static int
328 dissect_usbms_bot_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
330 urb_info_t *urb;
331 usbms_bot_conv_info_t *usbms_bot_conv_info;
332 int offset=0;
333 bool is_request;
334 itl_nexus_t *itl;
335 itlq_nexus_t *itlq;
336 tvbuff_t *payload_tvb;
338 /* Reject the packet if data is NULL */
339 if (data == NULL)
340 return 0;
341 urb = (urb_info_t *)data;
342 if (urb->conv == NULL)
343 return 0;
345 /* verify that we do have a usbms_bot_conv_info */
346 usbms_bot_conv_info=(usbms_bot_conv_info_t *)urb->conv->class_data;
347 if(!usbms_bot_conv_info){
348 usbms_bot_conv_info=wmem_new(wmem_file_scope(), usbms_bot_conv_info_t);
349 usbms_bot_conv_info->itl=wmem_tree_new(wmem_file_scope());
350 usbms_bot_conv_info->itlq=wmem_tree_new(wmem_file_scope());
351 urb->conv->class_data=usbms_bot_conv_info;
352 urb->conv->class_data_type = USB_CONV_MASS_STORAGE_BOT;
353 } else if (urb->conv->class_data_type != USB_CONV_MASS_STORAGE_BOT) {
354 /* Don't dissect if another USB type is in the conversation */
355 return 0;
358 is_request=(pinfo->srcport==NO_ENDPOINT);
360 col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBMS");
362 col_clear(pinfo->cinfo, COL_INFO);
366 * SCSI CDB inside CBW
368 if (usbms_bot_bulk_is_cbw(tvb, offset, is_request)) {
369 return dissect_usbms_bot_cbw(tvb, pinfo, parent_tree, usbms_bot_conv_info);
374 * SCSI RESPONSE inside CSW
376 if (usbms_bot_bulk_is_csw(tvb, offset, is_request)) {
377 return dissect_usbms_bot_csw(tvb, pinfo, parent_tree, usbms_bot_conv_info);
381 * Ok it was neither CDB not STATUS so just assume it is either data in/out
383 itlq=(itlq_nexus_t *)wmem_tree_lookup32_le(usbms_bot_conv_info->itlq, pinfo->num-1);
384 if(!itlq){
385 create_usbms_bot_protocol_tree(tvb, parent_tree);
386 return tvb_captured_length(tvb);
389 itl=(itl_nexus_t *)wmem_tree_lookup32(usbms_bot_conv_info->itl, itlq->lun);
390 if(!itl){
391 create_usbms_bot_protocol_tree(tvb, parent_tree);
392 return tvb_captured_length(tvb);
396 * Workaround USBLL reassembly limitations by anticipating concatenated
397 * SCSI Data IN with CSW and SCSI Data OUT with next CBW. Proper would
398 * involve implementing a framework to allow USB class dissectors to signal
399 * expected transfer length on Bulk IN or Bulk OUT endpoint whenever CBW is
400 * encountered.
402 payload_tvb = tvb_new_subset_length(tvb, 0, itlq->data_length);
403 if (usbms_bot_bulk_is_cbw(tvb, itlq->data_length, is_request)) {
404 tvbuff_t *cbw_tvb = tvb_new_subset_length(tvb, itlq->data_length, 31);
406 dissect_scsi_payload(payload_tvb, pinfo, parent_tree, is_request, itlq, itl, 0);
407 dissect_usbms_bot_cbw(cbw_tvb, pinfo, parent_tree, usbms_bot_conv_info);
408 return tvb_captured_length(tvb);
409 } else if (usbms_bot_bulk_is_csw(tvb, itlq->data_length, is_request)) {
410 tvbuff_t *csw_tvb = tvb_new_subset_length(tvb, itlq->data_length, 13);
412 dissect_scsi_payload(payload_tvb, pinfo, parent_tree, is_request, itlq, itl, 0);
413 dissect_usbms_bot_csw(csw_tvb, pinfo, parent_tree, usbms_bot_conv_info);
414 return tvb_captured_length(tvb);
417 /* Create empty protocol tree so "usbms" filter displays this packet */
418 create_usbms_bot_protocol_tree(tvb, parent_tree);
419 dissect_scsi_payload(payload_tvb, pinfo, parent_tree, is_request, itlq, itl, 0);
420 return tvb_captured_length(payload_tvb);
423 static bool
424 dissect_usbms_bot_bulk_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
426 static const unsigned char usbc[] = {0x55, 0x53, 0x42, 0x43};
427 static const unsigned char usbs[] = {0x55, 0x53, 0x42, 0x53};
428 if (tvb_reported_length(tvb) < 4)
429 return false;
431 if (tvb_memeql(tvb, 0, usbc, sizeof(usbc)) == 0 ||
432 tvb_memeql(tvb, 0, usbs, sizeof(usbs)) == 0) {
433 dissect_usbms_bot_bulk(tvb, pinfo, tree, data);
434 return true;
437 return false;
440 void
441 proto_register_usbms_bot(void)
443 static hf_register_info hf[] = {
444 { &hf_usbms_bot_dCBWSignature,
445 { "Signature", "usbms.dCBWSignature", FT_UINT32, BASE_HEX,
446 NULL, 0x0, NULL, HFILL }},
448 { &hf_usbms_bot_dCBWTag,
449 { "Tag", "usbms.dCBWTag", FT_UINT32, BASE_HEX,
450 NULL, 0x0, NULL, HFILL }},
452 { &hf_usbms_bot_dCBWDataTransferLength,
453 { "DataTransferLength", "usbms.dCBWDataTransferLength", FT_UINT32, BASE_DEC,
454 NULL, 0x0, NULL, HFILL }},
456 { &hf_usbms_bot_dCBWFlags,
457 { "Flags", "usbms.dCBWFlags", FT_UINT8, BASE_HEX,
458 NULL, 0x0, NULL, HFILL }},
460 { &hf_usbms_bot_dCBWTarget,
461 { "Target", "usbms.dCBWTarget", FT_UINT8, BASE_HEX_DEC,
462 NULL, 0x70, "Target Number when enabling multi-target mode", HFILL }},
464 { &hf_usbms_bot_dCBWLUN,
465 { "LUN", "usbms.dCBWLUN", FT_UINT8, BASE_HEX,
466 NULL, 0x0f, NULL, HFILL }},
468 { &hf_usbms_bot_dCBWCBLength,
469 { "CDB Length", "usbms.dCBWCBLength", FT_UINT8, BASE_HEX,
470 NULL, 0x1f, NULL, HFILL }},
472 { &hf_usbms_bot_dCSWSignature,
473 { "Signature", "usbms.dCSWSignature", FT_UINT32, BASE_HEX,
474 NULL, 0x0, NULL, HFILL }},
476 { &hf_usbms_bot_dCSWDataResidue,
477 { "DataResidue", "usbms.dCSWDataResidue", FT_UINT32, BASE_DEC,
478 NULL, 0x0, NULL, HFILL }},
480 { &hf_usbms_bot_dCSWStatus,
481 { "Status", "usbms.dCSWStatus", FT_UINT8, BASE_HEX,
482 VALS(status_vals), 0x0, NULL, HFILL }},
484 { &hf_usbms_bot_request,
485 { "bRequest", "usbms.setup.bRequest", FT_UINT8, BASE_HEX, VALS(setup_request_names_vals), 0x0,
486 NULL, HFILL }},
488 { &hf_usbms_bot_value,
489 { "wValue", "usbms.setup.wValue", FT_UINT16, BASE_HEX, NULL, 0x0,
490 NULL, HFILL }},
492 { &hf_usbms_bot_index,
493 { "wIndex", "usbms.setup.wIndex", FT_UINT16, BASE_DEC, NULL, 0x0,
494 NULL, HFILL }},
496 { &hf_usbms_bot_length,
497 { "wLength", "usbms.setup.wLength", FT_UINT16, BASE_DEC, NULL, 0x0,
498 NULL, HFILL }},
500 { &hf_usbms_bot_maxlun,
501 { "Max LUN", "usbms.setup.maxlun", FT_UINT8, BASE_DEC, NULL, 0x0,
502 NULL, HFILL }},
506 static int *usbms_bot_ett[] = {
507 &ett_usbms_bot,
511 proto_usbms_bot = proto_register_protocol("USB Mass Storage", "USBMS", "usbms");
512 proto_register_field_array(proto_usbms_bot, hf, array_length(hf));
513 proto_register_subtree_array(usbms_bot_ett, array_length(usbms_bot_ett));
515 usbms_bot_bulk_handle = register_dissector("usbms", dissect_usbms_bot_bulk, proto_usbms_bot);
516 usbms_bot_control_handle = register_dissector("usbms.control", dissect_usbms_bot_control, proto_usbms_bot);
519 void
520 proto_reg_handoff_usbms_bot(void)
522 dissector_add_uint("usbms.bulk", IF_PROTOCOL_BULK_ONLY, usbms_bot_bulk_handle);
523 dissector_add_uint("usbms.control", IF_PROTOCOL_BULK_ONLY, usbms_bot_control_handle);
525 heur_dissector_add("usb.bulk", dissect_usbms_bot_bulk_heur,
526 "Mass Storage USB Bulk-Only Transport bulk endpoint",
527 "ms_usb_bulk", proto_usbms_bot, HEURISTIC_ENABLE);
531 * Editor modelines - https://www.wireshark.org/tools/modelines.html
533 * Local variables:
534 * c-basic-offset: 4
535 * tab-width: 8
536 * indent-tabs-mode: nil
537 * End:
539 * vi: set shiftwidth=4 tabstop=8 expandtab:
540 * :indentSize=4:tabSize=8:noTabs=true: