diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-usb.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-usb.c')
-rw-r--r-- | epan/dissectors/packet-usb.c | 7414 |
1 files changed, 7414 insertions, 0 deletions
diff --git a/epan/dissectors/packet-usb.c b/epan/dissectors/packet-usb.c new file mode 100644 index 00000000..a8899da5 --- /dev/null +++ b/epan/dissectors/packet-usb.c @@ -0,0 +1,7414 @@ +/* packet-usb.c + * + * USB basic dissector + * By Paolo Abeni <paolo.abeni@email.it> + * Ronnie Sahlberg 2006 + * + * http://www.usb.org/developers/docs/usb_20_122909-2.zip + * + * https://github.com/torvalds/linux/blob/master/Documentation/usb/usbmon.rst + * + * http://desowin.org/usbpcap/captureformat.html + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#include "config.h" + +#include <epan/packet.h> +#include <epan/exceptions.h> +#include <epan/addr_resolv.h> +#include <epan/address_types.h> +#include <epan/conversation_table.h> +#include <epan/expert.h> +#include <epan/prefs.h> +#include <epan/decode_as.h> +#include <epan/proto_data.h> +#include <wsutil/pint.h> +#include <wsutil/ws_roundup.h> + +#include "packet-usb.h" +#include "packet-mausb.h" +#include "packet-usbip.h" +#include "packet-netmon.h" + +/* dissector handles */ +static dissector_handle_t linux_usb_handle; +static dissector_handle_t linux_usb_mmapped_handle; +static dissector_handle_t win32_usb_handle; +static dissector_handle_t freebsd_usb_handle; +static dissector_handle_t darwin_usb_handle; +static dissector_handle_t netmon_usb_port_handle; + +/* protocols and header fields */ +static int proto_usb = -1; +static int proto_usbport = -1; + +/* USB pseudoheader fields, both FreeBSD and Linux */ +static int hf_usb_totlen = -1; +static int hf_usb_busunit = -1; +static int hf_usb_address = -1; +static int hf_usb_mode = -1; +static int hf_usb_freebsd_urb_type = -1; +static int hf_usb_freebsd_transfer_type = -1; +static int hf_usb_xferflags = -1; +static int hf_usb_xferflags_force_short_xfer = -1; +static int hf_usb_xferflags_short_xfer_ok = -1; +static int hf_usb_xferflags_short_frames_ok = -1; +static int hf_usb_xferflags_pipe_bof = -1; +static int hf_usb_xferflags_proxy_buffer = -1; +static int hf_usb_xferflags_ext_buffer = -1; +static int hf_usb_xferflags_manual_status = -1; +static int hf_usb_xferflags_no_pipe_ok = -1; +static int hf_usb_xferflags_stall_pipe = -1; +static int hf_usb_xferstatus = -1; +static int hf_usb_xferstatus_open = -1; +static int hf_usb_xferstatus_transferring = -1; +static int hf_usb_xferstatus_did_dma_delay = -1; +static int hf_usb_xferstatus_did_close = -1; +static int hf_usb_xferstatus_draining = -1; +static int hf_usb_xferstatus_started = -1; +static int hf_usb_xferstatus_bw_reclaimed = -1; +static int hf_usb_xferstatus_control_xfr = -1; +static int hf_usb_xferstatus_control_hdr = -1; +static int hf_usb_xferstatus_control_act = -1; +static int hf_usb_xferstatus_control_stall = -1; +static int hf_usb_xferstatus_short_frames_ok = -1; +static int hf_usb_xferstatus_short_xfer_ok = -1; +static int hf_usb_xferstatus_bdma_enable = -1; +static int hf_usb_xferstatus_bdma_no_post_sync = -1; +static int hf_usb_xferstatus_bdma_setup = -1; +static int hf_usb_xferstatus_isochronous_xfr = -1; +static int hf_usb_xferstatus_curr_dma_set = -1; +static int hf_usb_xferstatus_can_cancel_immed = -1; +static int hf_usb_xferstatus_doing_callback = -1; +static int hf_usb_error = -1; +static int hf_usb_interval = -1; +static int hf_usb_nframes = -1; +static int hf_usb_packet_size = -1; +static int hf_usb_packet_count = -1; +static int hf_usb_speed = -1; +static int hf_usb_frame_length = -1; +static int hf_usb_frame_flags = -1; +static int hf_usb_frame_flags_read = -1; +static int hf_usb_frame_flags_data_follows = -1; +static int hf_usb_frame_data = -1; +static int hf_usb_urb_id = -1; +static int hf_usb_linux_urb_type = -1; +static int hf_usb_linux_transfer_type = -1; +static int hf_usb_endpoint_address = -1; +static int hf_usb_endpoint_direction = -1; +static int hf_usb_endpoint_number = -1; +static int hf_usb_device_address = -1; +static int hf_usb_bus_id = -1; +static int hf_usb_setup_flag = -1; +static int hf_usb_data_flag = -1; +static int hf_usb_urb_ts_sec = -1; +static int hf_usb_urb_ts_usec = -1; +static int hf_usb_urb_status = -1; +static int hf_usb_urb_len = -1; +static int hf_usb_urb_data_len = -1; +static int hf_usb_urb_unused_setup_header = -1; +static int hf_usb_urb_interval = -1; +static int hf_usb_urb_start_frame = -1; +static int hf_usb_urb_copy_of_transfer_flags = -1; + +/* transfer_flags */ +static int hf_short_not_ok = -1; +static int hf_iso_asap = -1; +static int hf_no_transfer_dma_map = -1; +static int hf_no_fsbr = -1; +static int hf_zero_packet = -1; +static int hf_no_interrupt = -1; +static int hf_free_buffer = -1; +static int hf_dir_in = -1; +static int hf_dma_map_single = -1; +static int hf_dma_map_page = -1; +static int hf_dma_map_sg = -1; +static int hf_map_local = -1; +static int hf_setup_map_single = -1; +static int hf_setup_map_local = -1; +static int hf_dma_sg_combined = -1; +static int hf_aligned_temp_buffer = -1; + +static int * const transfer_flags_fields[] = { + &hf_short_not_ok, + &hf_iso_asap, + &hf_no_transfer_dma_map, + &hf_no_fsbr, + &hf_zero_packet, + &hf_no_interrupt, + &hf_free_buffer, + &hf_dir_in, + &hf_dma_map_single, + &hf_dma_map_page, + &hf_dma_map_sg, + &hf_map_local, + &hf_setup_map_single, + &hf_setup_map_local, + &hf_dma_sg_combined, + &hf_aligned_temp_buffer, + NULL +}; + +/* Win32 USBPcap pseudoheader fields */ +static int hf_usb_win32_header_len = -1; +static int hf_usb_irp_id = -1; +static int hf_usb_usbd_status = -1; +static int hf_usb_function = -1; +static int hf_usb_info = -1; +static int hf_usb_usbpcap_info_reserved = -1; +static int hf_usb_usbpcap_info_direction = -1; +static int hf_usb_win32_device_address = -1; +static int hf_usb_win32_transfer_type = -1; +/* hf_usb_bus_id, hf_usb_endpoint_address, hf_usb_endpoint_direction, + * hf_usb_endpoint_number are common with + * FreeBSD and Linux pseudoheaders */ +static int hf_usb_win32_data_len = -1; +static int hf_usb_win32_control_stage = -1; +static int hf_usb_win32_iso_start_frame = -1; +static int hf_usb_win32_iso_num_packets = -1; +static int hf_usb_win32_iso_error_count = -1; +static int hf_usb_win32_iso_offset = -1; +static int hf_usb_win32_iso_length = -1; +static int hf_usb_win32_iso_status = -1; + +static int hf_usb_request = -1; +static int hf_usb_request_unknown_class = -1; +static int hf_usb_value = -1; +static int hf_usb_index = -1; +static int hf_usb_length = -1; +/* static int hf_usb_data_len = -1; */ +static int hf_usb_capdata = -1; +static int hf_usb_device_wFeatureSelector = -1; +static int hf_usb_interface_wFeatureSelector = -1; +static int hf_usb_endpoint_wFeatureSelector = -1; +static int hf_usb_wInterface = -1; +static int hf_usb_wEndpoint = -1; +static int hf_usb_wStatus = -1; +static int hf_usb_wFrameNumber = -1; + +static int hf_usb_iso_error_count = -1; +static int hf_usb_iso_numdesc = -1; +static int hf_usb_iso_status = -1; +static int hf_usb_iso_off = -1; +static int hf_usb_iso_len = -1; +static int hf_usb_iso_actual_len = -1; +static int hf_usb_iso_pad = -1; +static int hf_usb_iso_data = -1; + +static int hf_usb_bmRequestType = -1; +static int hf_usb_control_response_generic = -1; +static int hf_usb_bmRequestType_direction = -1; +static int hf_usb_bmRequestType_type = -1; +static int hf_usb_bmRequestType_recipient = -1; +static int hf_usb_bDescriptorType = -1; +static int hf_usb_get_descriptor_resp_generic = -1; +static int hf_usb_descriptor_index = -1; +static int hf_usb_language_id = -1; +static int hf_usb_bLength = -1; +static int hf_usb_bcdUSB = -1; +static int hf_usb_bDeviceClass = -1; +static int hf_usb_bDeviceSubClass = -1; +static int hf_usb_bDeviceProtocol = -1; +static int hf_usb_bMaxPacketSize0 = -1; +static int hf_usb_idVendor = -1; +static int hf_usb_idProduct = -1; +static int hf_usb_bcdDevice = -1; +static int hf_usb_iManufacturer = -1; +static int hf_usb_iProduct = -1; +static int hf_usb_iSerialNumber = -1; +static int hf_usb_bNumConfigurations = -1; +static int hf_usb_wLANGID = -1; +static int hf_usb_bString = -1; +static int hf_usb_bInterfaceNumber = -1; +static int hf_usb_bAlternateSetting = -1; +static int hf_usb_bNumEndpoints = -1; +static int hf_usb_bInterfaceClass = -1; +static int hf_usb_bInterfaceSubClass = -1; +static int hf_usb_bInterfaceSubClass_audio = -1; +static int hf_usb_bInterfaceSubClass_cdc = -1; +static int hf_usb_bInterfaceSubClass_massstorage = -1; +static int hf_usb_bInterfaceSubClass_hid = -1; +static int hf_usb_bInterfaceSubClass_misc = -1; +static int hf_usb_bInterfaceSubClass_app = -1; +static int hf_usb_bInterfaceProtocol = -1; +static int hf_usb_bInterfaceProtocol_cdc = -1; +static int hf_usb_bInterfaceProtocol_massstorage = -1; +static int hf_usb_bInterfaceProtocol_cdc_data = -1; +static int hf_usb_bInterfaceProtocol_hid_boot = -1; +static int hf_usb_bInterfaceProtocol_app_dfu = -1; +static int hf_usb_bInterfaceProtocol_app_irda = -1; +static int hf_usb_bInterfaceProtocol_app_usb_test_and_measurement = -1; +static int hf_usb_iInterface = -1; +static int hf_usb_bEndpointAddress = -1; +static int hf_usb_bmAttributes = -1; +static int hf_usb_bEndpointAttributeTransfer = -1; +static int hf_usb_bEndpointAttributeSynchonisation = -1; +static int hf_usb_bEndpointAttributeBehaviour = -1; +static int hf_usb_wMaxPacketSize = -1; +static int hf_usb_wMaxPacketSize_size = -1; +static int hf_usb_wMaxPacketSize_slots = -1; +static int hf_usb_bInterval = -1; +static int hf_usb_bMaxBurst = -1; +static int hf_usb_audio_bRefresh = -1; +static int hf_usb_audio_bSynchAddress = -1; +static int hf_usb_bSSEndpointAttributeBulkMaxStreams = -1; +static int hf_usb_bSSEndpointAttributeIsoMult = -1; +static int hf_usb_wBytesPerInterval = -1; +static int hf_usb_wTotalLength = -1; +static int hf_usb_bNumInterfaces = -1; +static int hf_usb_bConfigurationValue = -1; +static int hf_usb_iConfiguration = -1; +static int hf_usb_bMaxPower = -1; +static int hf_usb_configuration_bmAttributes = -1; +static int hf_usb_configuration_legacy10buspowered = -1; +static int hf_usb_configuration_selfpowered = -1; +static int hf_usb_configuration_remotewakeup = -1; +static int hf_usb_bEndpointAddress_direction = -1; +static int hf_usb_bEndpointAddress_number = -1; +static int hf_usb_response_in = -1; +static int hf_usb_time = -1; +static int hf_usb_request_in = -1; +static int hf_usb_bFirstInterface = -1; +static int hf_usb_bInterfaceCount = -1; +static int hf_usb_bFunctionClass = -1; +static int hf_usb_bFunctionSubClass = -1; +static int hf_usb_bFunctionProtocol = -1; +static int hf_usb_iFunction = -1; +static int hf_usb_bNumDeviceCaps = -1; +static int hf_usb_bDevCapabilityType = -1; +static int hf_usb_usb20ext_bmAttributes = -1; +static int hf_usb_usb20ext_LPM = -1; +static int hf_usb_usb20ext_BESL_HIRD = -1; +static int hf_usb_usb20ext_baseline_BESL_valid = -1; +static int hf_usb_usb20ext_deep_BESL_valid = -1; +static int hf_usb_usb20ext_baseline_BESL = -1; +static int hf_usb_usb20ext_deep_BESL = -1; +static int hf_usb_bReserved = -1; +static int hf_usb_PlatformCapabilityUUID = -1; +static int hf_usb_webusb_bcdVersion = -1; +static int hf_usb_webusb_bVendorCode = -1; +static int hf_usb_webusb_iLandingPage = -1; +static int hf_usb_msos20_dwWindowsVersion = -1; +static int hf_usb_msos20_wMSOSDescriptorSetTotalLength = -1; +static int hf_usb_msos20_bMS_VendorCode = -1; +static int hf_usb_msos20_bAltEnumCode = -1; +static int hf_usb_data_fragment = -1; +static int hf_usb_src = -1; +static int hf_usb_dst = -1; +static int hf_usb_addr = -1; + +/* macOS */ +static int hf_usb_darwin_bcd_version = -1; +static int hf_usb_darwin_header_len = -1; +static int hf_usb_darwin_request_type = -1; +static int hf_usb_darwin_io_len = -1; +static int hf_usb_darwin_io_status = -1; +static int hf_usb_darwin_iso_num_packets = -1; +static int hf_usb_darwin_io_id = -1; +static int hf_usb_darwin_device_location = -1; +static int hf_usb_darwin_speed = -1; +static int hf_usb_darwin_device_address = -1; +static int hf_usb_darwin_endpoint_address = -1; +static int hf_usb_darwin_endpoint_type = -1; +static int hf_usb_darwin_iso_status = -1; +static int hf_usb_darwin_iso_frame_number = -1; +static int hf_usb_darwin_iso_timestamp = -1; + +/* NetMon */ +static int hf_usbport_event_id = -1; +static int hf_usbport_device_object = -1; +static int hf_usbport_pci_bus = -1; +static int hf_usbport_pci_device = -1; +static int hf_usbport_pci_function = -1; +static int hf_usbport_pci_vendor_id = -1; +static int hf_usbport_pci_device_id = -1; +static int hf_usbport_port_path_depth = -1; +static int hf_usbport_port_path0 = -1; +static int hf_usbport_port_path1 = -1; +static int hf_usbport_port_path2 = -1; +static int hf_usbport_port_path3 = -1; +static int hf_usbport_port_path4 = -1; +static int hf_usbport_port_path5 = -1; +static int hf_usbport_device_handle = -1; +static int hf_usbport_device_speed = -1; +static int hf_usbport_endpoint = -1; +static int hf_usbport_pipehandle = -1; +static int hf_usbport_endpoint_desc_length = -1; +static int hf_usbport_endpoint_desc_type = -1; +static int hf_usbport_endpoint_address = -1; +static int hf_usbport_bm_attributes = -1; +static int hf_usbport_max_packet_size = -1; +static int hf_usbport_interval = -1; +static int hf_usbport_irp = -1; +static int hf_usbport_urb = -1; +static int hf_usbport_urb_transfer_data = -1; +static int hf_usbport_urb_header_length = -1; +static int hf_usbport_urb_header_function = -1; +static int hf_usbport_urb_header_status = -1; +static int hf_usbport_urb_header_usbddevice_handle = -1; +static int hf_usbport_urb_header_usbdflags = -1; +static int hf_usbport_urb_configuration_desc = -1; +static int hf_usbport_urb_configuration_handle = -1; +static int hf_usbport_urb_pipe_handle = -1; +static int hf_usbport_urb_xferflags = -1; +static int hf_usbport_urb_transfer_buffer_length = -1; +static int hf_usbport_urb_transfer_buffer = -1; +static int hf_usbport_urb_transfer_buffer_mdl = -1; +static int hf_usbport_urb_reserved_mbz = -1; +static int hf_usbport_urb_reserved_hcd = -1; +static int hf_usbport_urb_reserved = -1; +static int hf_usbport_keyword = -1; +static int hf_usbport_keyword_diagnostic = -1; +static int hf_usbport_keyword_power_diagnostics = -1; +static int hf_usbport_keyword_perf_diagnostics = -1; +static int hf_usbport_keyword_reserved1 = -1; + +static gint ett_usb_hdr = -1; +static gint ett_usb_setup_hdr = -1; +static gint ett_usb_isodesc = -1; +static gint ett_usb_win32_iso_packet = -1; +static gint ett_usb_endpoint = -1; +static gint ett_usb_setup_bmrequesttype = -1; +static gint ett_usb_usbpcap_info = -1; +static gint ett_descriptor_device = -1; +static gint ett_configuration_bmAttributes = -1; +static gint ett_configuration_bEndpointAddress = -1; +static gint ett_endpoint_bmAttributes = -1; +static gint ett_endpoint_wMaxPacketSize = -1; +static gint ett_usb_xferflags = -1; +static gint ett_usb_xferstatus = -1; +static gint ett_usb_frame = -1; +static gint ett_usb_frame_flags = -1; +static gint ett_usbport = -1; +static gint ett_usbport_host_controller = -1; +static gint ett_usbport_path = -1; +static gint ett_usbport_device = -1; +static gint ett_usbport_endpoint = -1; +static gint ett_usbport_endpoint_desc = -1; +static gint ett_usbport_urb = -1; +static gint ett_usbport_keyword = -1; +static gint ett_transfer_flags = -1; +static gint ett_usb20ext_bmAttributes = -1; + +static expert_field ei_usb_undecoded = EI_INIT; +static expert_field ei_usb_bLength_even = EI_INIT; +static expert_field ei_usb_bLength_too_short = EI_INIT; +static expert_field ei_usb_desc_length_invalid = EI_INIT; +static expert_field ei_usb_invalid_setup = EI_INIT; +static expert_field ei_usb_ss_ep_companion_before_ep = EI_INIT; +static expert_field ei_usb_usbpcap_unknown_urb = EI_INIT; +static expert_field ei_usb_bad_length = EI_INIT; +static expert_field ei_usb_invalid_max_packet_size = EI_INIT; +static expert_field ei_usb_invalid_max_packet_size0 = EI_INIT; +static expert_field ei_usb_invalid_endpoint_type = EI_INIT; +static expert_field ei_usb_unexpected_desc_type = EI_INIT; + +static expert_field ei_usbport_invalid_path_depth = EI_INIT; + +static int usb_address_type = -1; + +static int * const usb_endpoint_fields[] = { + &hf_usb_endpoint_direction, + &hf_usb_endpoint_number, + NULL +}; + +static int * const usb_usbpcap_info_fields[] = { + &hf_usb_usbpcap_info_reserved, + &hf_usb_usbpcap_info_direction, + NULL +}; + +static int usb_tap = -1; +static gboolean try_heuristics = TRUE; + +static dissector_table_t usb_bulk_dissector_table; +static dissector_table_t usb_control_dissector_table; +static dissector_table_t usb_interrupt_dissector_table; +static dissector_table_t usb_descriptor_dissector_table; + +static heur_dissector_list_t heur_bulk_subdissector_list; +static heur_dissector_list_t heur_control_subdissector_list; +static heur_dissector_list_t heur_interrupt_subdissector_list; + +static wmem_tree_t *device_to_protocol_table = NULL; +static wmem_tree_t *device_to_product_table = NULL; +static wmem_tree_t *usbpcap_setup_data = NULL; + +static dissector_table_t device_to_dissector; +static dissector_table_t protocol_to_dissector; +static dissector_table_t product_to_dissector; + +typedef struct _device_product_data_t { + guint16 vendor; + guint16 product; + guint16 device; + guint bus_id; + guint device_address; +} device_product_data_t; + +typedef struct _device_protocol_data_t { + guint32 protocol; + guint bus_id; + guint device_address; +} device_protocol_data_t; + +typedef struct _usb_alt_setting_t { + guint8 altSetting; + guint8 interfaceClass; + guint8 interfaceSubclass; + guint8 interfaceProtocol; + guint8 interfaceNum; +} usb_alt_setting_t; + +typedef struct { + guint64 usb_id; + guint8 setup_data[8]; +} usbpcap_setup_data_t; + +static const value_string usb_speed_vals[] = { + {USB_SPEED_UNKNOWN, "Unknown Speed"}, + {USB_SPEED_LOW, "Low-Speed"}, + {USB_SPEED_FULL, "Full-Speed"}, + {USB_SPEED_HIGH, "High-Speed"}, + {0, NULL} +}; + +/* http://www.usb.org/developers/docs/USB_LANGIDs.pdf */ +static const value_string usb_langid_vals[] = { + {0x0000, "no language specified"}, + {0x0401, "Arabic (Saudi Arabia)"}, + {0x0402, "Bulgarian"}, + {0x0403, "Catalan"}, + {0x0404, "Chinese (Taiwan)"}, + {0x0405, "Czech"}, + {0x0406, "Danish"}, + {0x0407, "German (Standard)"}, + {0x0408, "Greek"}, + {0x0409, "English (United States)"}, + {0x040a, "Spanish (Traditional Sort)"}, + {0x040b, "Finnish"}, + {0x040c, "French (Standard)"}, + {0x040d, "Hebrew"}, + {0x040e, "Hungarian"}, + {0x040f, "Icelandic"}, + {0x0410, "Italian (Standard)"}, + {0x0411, "Japanese"}, + {0x0412, "Korean"}, + {0x0413, "Dutch (Netherlands)"}, + {0x0414, "Norwegian (Bokmal)"}, + {0x0415, "Polish"}, + {0x0416, "Portuguese (Brazil)"}, + {0x0418, "Romanian"}, + {0x0419, "Russian"}, + {0x041a, "Croatian"}, + {0x041b, "Slovak"}, + {0x041c, "Albanian"}, + {0x041d, "Swedish"}, + {0x041e, "Thai"}, + {0x041f, "Turkish"}, + {0x0420, "Urdu (Pakistan)"}, + {0x0421, "Indonesian"}, + {0x0422, "Ukrainian"}, + {0x0423, "Belarussian"}, + {0x0424, "Slovenian"}, + {0x0425, "Estonian"}, + {0x0426, "Latvian"}, + {0x0427, "Lithuanian"}, + {0x0429, "Farsi"}, + {0x042a, "Vietnamese"}, + {0x042b, "Armenian"}, + {0x042c, "Azeri (Latin)"}, + {0x042d, "Basque"}, + {0x042f, "Macedonian"}, + {0x0430, "Sutu"}, + {0x0436, "Afrikaans"}, + {0x0437, "Georgian"}, + {0x0438, "Faeroese"}, + {0x0439, "Hindi"}, + {0x043e, "Malay (Malaysian)"}, + {0x043f, "Kazakh"}, + {0x0441, "Swahili (Kenya)"}, + {0x0443, "Uzbek (Latin)"}, + {0x0444, "Tatar (Tatarstan)"}, + {0x0445, "Bengali"}, + {0x0446, "Punjabi"}, + {0x0447, "Gujarati"}, + {0x0448, "Oriya"}, + {0x0449, "Tamil"}, + {0x044a, "Telugu"}, + {0x044b, "Kannada"}, + {0x044c, "Malayalam"}, + {0x044d, "Assamese"}, + {0x044e, "Marathi"}, + {0x044f, "Sanskrit"}, + {0x0455, "Burmese"}, + {0x0457, "Konkani"}, + {0x0458, "Manipuri"}, + {0x0459, "Sindhi"}, + {0x04ff, "HID (Usage Data Descriptor)"}, + {0x0801, "Arabic (Iraq)"}, + {0x0804, "Chinese (PRC)"}, + {0x0807, "German (Switzerland)"}, + {0x0809, "English (United Kingdom)"}, + {0x080a, "Spanish (Mexican)"}, + {0x080c, "French (Belgian)"}, + {0x0810, "Italian (Switzerland)"}, + {0x0812, "Korean (Johab)"}, + {0x0813, "Dutch (Belgium)"}, + {0x0814, "Norwegian (Nynorsk)"}, + {0x0816, "Portuguese (Standard)"}, + {0x081a, "Serbian (Latin)"}, + {0x081d, "Swedish (Finland)"}, + {0x0820, "Urdu (India)"}, + {0x0827, "Lithuanian (Classic)"}, + {0x082c, "Azeri (Cyrillic)"}, + {0x083e, "Malay (Brunei Darussalam)"}, + {0x0843, "Uzbek (Cyrillic)"}, + {0x0860, "Kashmiri (India)"}, + {0x0861, "Nepali (India)"}, + {0x0c01, "Arabic (Egypt)"}, + {0x0c04, "Chinese (Hong Kong SAR, PRC)"}, + {0x0c07, "German (Austria)"}, + {0x0c09, "English (Australian)"}, + {0x0c0a, "Spanish (Modern Sort)"}, + {0x0c0c, "French (Canadian)"}, + {0x0c1a, "Serbian (Cyrillic)"}, + {0x1001, "Arabic (Libya)"}, + {0x1004, "Chinese (Singapore)"}, + {0x1007, "German (Luxembourg)"}, + {0x1009, "English (Canadian)"}, + {0x100a, "Spanish (Guatemala)"}, + {0x100c, "French (Switzerland)"}, + {0x1401, "Arabic (Algeria)"}, + {0x1404, "Chinese (Macau SAR)"}, + {0x1407, "German (Liechtenstein)"}, + {0x1409, "English (New Zealand)"}, + {0x140a, "Spanish (Costa Rica)"}, + {0x140c, "French (Luxembourg)"}, + {0x1801, "Arabic (Morocco)"}, + {0x1809, "English (Ireland)"}, + {0x180a, "Spanish (Panama)"}, + {0x180c, "French (Monaco)"}, + {0x1c01, "Arabic (Tunisia)"}, + {0x1c09, "English (South Africa)"}, + {0x1c0a, "Spanish (Dominican Republic)"}, + {0x2001, "Arabic (Oman)"}, + {0x2009, "English (Jamaica)"}, + {0x200a, "Spanish (Venezuela)"}, + {0x2401, "Arabic (Yemen)"}, + {0x2409, "English (Caribbean)"}, + {0x240a, "Spanish (Colombia)"}, + {0x2801, "Arabic (Syria)"}, + {0x2809, "English (Belize)"}, + {0x280a, "Spanish (Peru)"}, + {0x2c01, "Arabic (Jordan)"}, + {0x2c09, "English (Trinidad)"}, + {0x2c0a, "Spanish (Argentina)"}, + {0x3001, "Arabic (Lebanon)"}, + {0x3009, "English (Zimbabwe)"}, + {0x300a, "Spanish (Ecuador)"}, + {0x3401, "Arabic (Kuwait)"}, + {0x3409, "English (Philippines)"}, + {0x340a, "Spanish (Chile)"}, + {0x3801, "Arabic (U.A.E.)"}, + {0x380a, "Spanish (Uruguay)"}, + {0x3c01, "Arabic (Bahrain)"}, + {0x3c0a, "Spanish (Paraguay)"}, + {0x4001, "Arabic (Qatar)"}, + {0x400a, "Spanish (Bolivia)"}, + {0x440a, "Spanish (El Salvador)"}, + {0x480a, "Spanish (Honduras)"}, + {0x4c0a, "Spanish (Nicaragua)"}, + {0x500a, "Spanish (Puerto Rico)"}, + {0xf0ff, "HID (Vendor Defined 1)"}, + {0xf4ff, "HID (Vendor Defined 2)"}, + {0xf8ff, "HID (Vendor Defined 3)"}, + {0xfcff, "HID (Vendor Defined 4)"}, + {0, NULL} +}; +value_string_ext usb_langid_vals_ext = VALUE_STRING_EXT_INIT(usb_langid_vals); + +static const value_string usb_class_vals[] = { + {IF_CLASS_DEVICE, "Device"}, + {IF_CLASS_AUDIO, "Audio"}, + {IF_CLASS_COMMUNICATIONS, "Communications and CDC Control"}, + {IF_CLASS_HID, "HID"}, + {IF_CLASS_PHYSICAL, "Physical"}, + {IF_CLASS_IMAGE, "Imaging"}, + {IF_CLASS_PRINTER, "Printer"}, + {IF_CLASS_MASS_STORAGE, "Mass Storage"}, + {IF_CLASS_HUB, "Hub"}, + {IF_CLASS_CDC_DATA, "CDC-Data"}, + {IF_CLASS_SMART_CARD, "Smart Card"}, + {IF_CLASS_CONTENT_SECURITY, "Content Security"}, + {IF_CLASS_VIDEO, "Video"}, + {IF_CLASS_PERSONAL_HEALTHCARE, "Personal Healthcare"}, + {IF_CLASS_AUDIO_VIDEO, "Audio/Video Devices"}, + {IF_CLASS_DIAGNOSTIC_DEVICE, "Diagnostic Device"}, + {IF_CLASS_WIRELESS_CONTROLLER, "Wireless Controller"}, + {IF_CLASS_MISCELLANEOUS, "Miscellaneous"}, + {IF_CLASS_APPLICATION_SPECIFIC, "Application Specific"}, + {IF_CLASS_VENDOR_SPECIFIC, "Vendor Specific"}, + {0, NULL} +}; +value_string_ext usb_class_vals_ext = VALUE_STRING_EXT_INIT(usb_class_vals); + +/* use usb class, subclass and protocol id together + http://www.usb.org/developers/defined_class + USB Class Definitions for Communications Devices, Revision 1.2 December 6, 2012 +*/ +static const value_string usb_protocols[] = { + {0x000000, "Use class code info from Interface Descriptors"}, + {0x060101, "Still Imaging"}, + {0x090000, "Full speed Hub"}, + {0x090001, "Hi-speed hub with single TT"}, + {0x090002, "Hi-speed hub with multiple TTs"}, + {0x0D0000, "Content Security"}, + {0x100100, "AVControl Interface"}, + {0x100200, "AVData Video Streaming Interface"}, + {0x100300, "AVData Audio Streaming Interface"}, + {0xDC0101, "USB2 Compliance Device"}, + {0xE00101, "Bluetooth Programming Interface"}, + {0xE00102, "UWB Radio Control Interface"}, + {0xE00103, "Remote NDIS"}, + {0xE00104, "Bluetooth AMP Controller"}, + {0xE00201, "Host Wire Adapter Control/Data interface"}, + {0xE00202, "Device Wire Adapter Control/Data interface"}, + {0xE00203, "Device Wire Adapter Isochronous interface"}, + {0xEF0101, "Active Sync device"}, + {0xEF0102, "Palm Sync"}, + {0xEF0201, "Interface Association Descriptor"}, + {0xEF0202, "Wire Adapter Multifunction Peripheral programming interface"}, + {0xEF0301, "Cable Based Association Framework"}, + {0xFE0101, "Device Firmware Upgrade"}, + {0xFE0200, "IRDA Bridge device"}, + {0xFE0300, "USB Test and Measurement Device"}, + {0xFE0301, "USB Test and Measurement Device conforming to the USBTMC USB488"}, + {0, NULL} +}; +static value_string_ext usb_protocols_ext = VALUE_STRING_EXT_INIT(usb_protocols); + +/* BOS Descriptor Device Capability Type Codes + https://www.usb.org/bos-descriptor-types +*/ +#define BOS_CAP_WIRELESS_USB 0x01 +#define BOS_CAP_USB_20_EXTENSION 0x02 +#define BOS_CAP_SUPERSPEED_USB 0x03 +#define BOS_CAP_CONTAINER_ID 0x04 +#define BOS_CAP_PLATFORM 0x05 +#define BOS_CAP_POWER_DELIVERY 0x06 +#define BOS_CAP_BATTERY_INFO 0x07 +#define BOS_CAP_PD_CONSUMER_PORT 0x08 +#define BOS_CAP_PD_PROVIDER_PORT 0x09 +#define BOS_CAP_SUPERSPEED_PLUS 0x0A +#define BOS_CAP_PRECISION_TIME_MEAS 0x0B +#define BOS_CAP_WIRELESS_USB_EXT 0x0C +#define BOS_CAP_BILLBOARD 0x0D +#define BOS_CAP_AUTHENTICATION 0x0E +#define BOS_CAP_BILLBOARD_EX 0x0F +#define BOS_CAP_CONFIGURATION_SUMMARY 0x10 +#define BOS_CAP_FWSTATUS 0x11 +#define BOS_CAP_USB3_GEN_T 0x13 +static const value_string usb_capability_vals[] = { + {BOS_CAP_WIRELESS_USB, "Wireless USB"}, + {BOS_CAP_USB_20_EXTENSION, "USB 2.0 Extension Descriptor"}, + {BOS_CAP_SUPERSPEED_USB, "SuperSpeed USB"}, + {BOS_CAP_CONTAINER_ID, "Container ID"}, + {BOS_CAP_PLATFORM, "Platform"}, + {BOS_CAP_POWER_DELIVERY, "Power Delivery Capability"}, + {BOS_CAP_BATTERY_INFO, "Battery Info Capability"}, + {BOS_CAP_PD_CONSUMER_PORT, "PD Consumer Port Capability"}, + {BOS_CAP_PD_PROVIDER_PORT, "PD Provider Port Capability"}, + {BOS_CAP_SUPERSPEED_PLUS, "SuperSpeed Plus"}, + {BOS_CAP_PRECISION_TIME_MEAS, "Precision Time Measurement"}, + {BOS_CAP_WIRELESS_USB_EXT, "Wireless USB Ext"}, + {BOS_CAP_BILLBOARD, "Billboard Capability"}, + {BOS_CAP_AUTHENTICATION, "Authentication Capability Descriptor"}, + {BOS_CAP_BILLBOARD_EX, "Billboard Ex capability"}, + {BOS_CAP_CONFIGURATION_SUMMARY, "Configuration Summary"}, + {BOS_CAP_FWSTATUS, "Firmware Status"}, + {0x12, "TBD (reserved for USB Audio 4.0)"}, + {BOS_CAP_USB3_GEN_T, "USB 3 Gen T Capability"}, + {0x14, "TBD (reserved for USB PD)"}, + {0, NULL} +}; +static value_string_ext usb_capability_vals_ext = VALUE_STRING_EXT_INIT(usb_capability_vals); + +/* FreeBSD header */ + +/* Transfer mode */ +#define FREEBSD_MODE_HOST 0 +#define FREEBSD_MODE_DEVICE 1 +static const value_string usb_freebsd_transfer_mode_vals[] = { + {FREEBSD_MODE_HOST, "Host"}, + {FREEBSD_MODE_DEVICE, "Device"}, + {0, NULL} +}; + +/* Type */ +#define FREEBSD_URB_SUBMIT 0 +#define FREEBSD_URB_COMPLETE 1 +static const value_string usb_freebsd_urb_type_vals[] = { + {FREEBSD_URB_SUBMIT, "URB_SUBMIT"}, + {FREEBSD_URB_COMPLETE, "URB_COMPLETE"}, + {0, NULL} +}; + +/* Transfer type */ +#define FREEBSD_URB_CONTROL 0 +#define FREEBSD_URB_ISOCHRONOUS 1 +#define FREEBSD_URB_BULK 2 +#define FREEBSD_URB_INTERRUPT 3 + +static const value_string usb_freebsd_transfer_type_vals[] = { + {FREEBSD_URB_CONTROL, "URB_CONTROL"}, + {FREEBSD_URB_ISOCHRONOUS, "URB_ISOCHRONOUS"}, + {FREEBSD_URB_BULK, "URB_BULK"}, + {FREEBSD_URB_INTERRUPT, "URB_INTERRUPT"}, + {0, NULL} +}; + +/* Transfer flags */ +#define FREEBSD_FLAG_FORCE_SHORT_XFER 0x00000001 +#define FREEBSD_FLAG_SHORT_XFER_OK 0x00000002 +#define FREEBSD_FLAG_SHORT_FRAMES_OK 0x00000004 +#define FREEBSD_FLAG_PIPE_BOF 0x00000008 +#define FREEBSD_FLAG_PROXY_BUFFER 0x00000010 +#define FREEBSD_FLAG_EXT_BUFFER 0x00000020 +#define FREEBSD_FLAG_MANUAL_STATUS 0x00000040 +#define FREEBSD_FLAG_NO_PIPE_OK 0x00000080 +#define FREEBSD_FLAG_STALL_PIPE 0x00000100 + +static int * const usb_xferflags_fields[] = { + &hf_usb_xferflags_force_short_xfer, + &hf_usb_xferflags_short_xfer_ok, + &hf_usb_xferflags_short_frames_ok, + &hf_usb_xferflags_pipe_bof, + &hf_usb_xferflags_proxy_buffer, + &hf_usb_xferflags_ext_buffer, + &hf_usb_xferflags_manual_status, + &hf_usb_xferflags_no_pipe_ok, + &hf_usb_xferflags_stall_pipe, + NULL +}; + +/* Transfer status */ +#define FREEBSD_STATUS_OPEN 0x00000001 +#define FREEBSD_STATUS_TRANSFERRING 0x00000002 +#define FREEBSD_STATUS_DID_DMA_DELAY 0x00000004 +#define FREEBSD_STATUS_DID_CLOSE 0x00000008 +#define FREEBSD_STATUS_DRAINING 0x00000010 +#define FREEBSD_STATUS_STARTED 0x00000020 +#define FREEBSD_STATUS_BW_RECLAIMED 0x00000040 +#define FREEBSD_STATUS_CONTROL_XFR 0x00000080 +#define FREEBSD_STATUS_CONTROL_HDR 0x00000100 +#define FREEBSD_STATUS_CONTROL_ACT 0x00000200 +#define FREEBSD_STATUS_CONTROL_STALL 0x00000400 +#define FREEBSD_STATUS_SHORT_FRAMES_OK 0x00000800 +#define FREEBSD_STATUS_SHORT_XFER_OK 0x00001000 +#define FREEBSD_STATUS_BDMA_ENABLE 0x00002000 +#define FREEBSD_STATUS_BDMA_NO_POST_SYNC 0x00004000 +#define FREEBSD_STATUS_BDMA_SETUP 0x00008000 +#define FREEBSD_STATUS_ISOCHRONOUS_XFR 0x00010000 +#define FREEBSD_STATUS_CURR_DMA_SET 0x00020000 +#define FREEBSD_STATUS_CAN_CANCEL_IMMED 0x00040000 +#define FREEBSD_STATUS_DOING_CALLBACK 0x00080000 + +static int * const usb_xferstatus_fields[] = { + &hf_usb_xferstatus_open, + &hf_usb_xferstatus_transferring, + &hf_usb_xferstatus_did_dma_delay, + &hf_usb_xferstatus_did_close, + &hf_usb_xferstatus_draining, + &hf_usb_xferstatus_started, + &hf_usb_xferstatus_bw_reclaimed, + &hf_usb_xferstatus_control_xfr, + &hf_usb_xferstatus_control_hdr, + &hf_usb_xferstatus_control_act, + &hf_usb_xferstatus_control_stall, + &hf_usb_xferstatus_short_frames_ok, + &hf_usb_xferstatus_short_xfer_ok, + &hf_usb_xferstatus_bdma_enable, + &hf_usb_xferstatus_bdma_no_post_sync, + &hf_usb_xferstatus_bdma_setup, + &hf_usb_xferstatus_isochronous_xfr, + &hf_usb_xferstatus_curr_dma_set, + &hf_usb_xferstatus_can_cancel_immed, + &hf_usb_xferstatus_doing_callback, + NULL +}; + +/* USB errors */ +#define FREEBSD_ERR_NORMAL_COMPLETION 0 +#define FREEBSD_ERR_PENDING_REQUESTS 1 +#define FREEBSD_ERR_NOT_STARTED 2 +#define FREEBSD_ERR_INVAL 3 +#define FREEBSD_ERR_NOMEM 4 +#define FREEBSD_ERR_CANCELLED 5 +#define FREEBSD_ERR_BAD_ADDRESS 6 +#define FREEBSD_ERR_BAD_BUFSIZE 7 +#define FREEBSD_ERR_BAD_FLAG 8 +#define FREEBSD_ERR_NO_CALLBACK 9 +#define FREEBSD_ERR_IN_USE 10 +#define FREEBSD_ERR_NO_ADDR 11 +#define FREEBSD_ERR_NO_PIPE 12 +#define FREEBSD_ERR_ZERO_NFRAMES 13 +#define FREEBSD_ERR_ZERO_MAXP 14 +#define FREEBSD_ERR_SET_ADDR_FAILED 15 +#define FREEBSD_ERR_NO_POWER 16 +#define FREEBSD_ERR_TOO_DEEP 17 +#define FREEBSD_ERR_IOERROR 18 +#define FREEBSD_ERR_NOT_CONFIGURED 19 +#define FREEBSD_ERR_TIMEOUT 20 +#define FREEBSD_ERR_SHORT_XFER 21 +#define FREEBSD_ERR_STALLED 22 +#define FREEBSD_ERR_INTERRUPTED 23 +#define FREEBSD_ERR_DMA_LOAD_FAILED 24 +#define FREEBSD_ERR_BAD_CONTEXT 25 +#define FREEBSD_ERR_NO_ROOT_HUB 26 +#define FREEBSD_ERR_NO_INTR_THREAD 27 +#define FREEBSD_ERR_NOT_LOCKED 28 + +static const value_string usb_freebsd_err_vals[] = { + {FREEBSD_ERR_NORMAL_COMPLETION, "Normal completion"}, + {FREEBSD_ERR_PENDING_REQUESTS, "Pending requests"}, + {FREEBSD_ERR_NOT_STARTED, "Not started"}, + {FREEBSD_ERR_INVAL, "Invalid"}, + {FREEBSD_ERR_NOMEM, "No memory"}, + {FREEBSD_ERR_CANCELLED, "Cancelled"}, + {FREEBSD_ERR_BAD_ADDRESS, "Bad address"}, + {FREEBSD_ERR_BAD_BUFSIZE, "Bad buffer size"}, + {FREEBSD_ERR_BAD_FLAG, "Bad flag"}, + {FREEBSD_ERR_NO_CALLBACK, "No callback"}, + {FREEBSD_ERR_IN_USE, "In use"}, + {FREEBSD_ERR_NO_ADDR, "No address"}, + {FREEBSD_ERR_NO_PIPE, "No pipe"}, + {FREEBSD_ERR_ZERO_NFRAMES, "Number of frames is zero"}, + {FREEBSD_ERR_ZERO_MAXP, "MAXP is zero"}, + {FREEBSD_ERR_SET_ADDR_FAILED, "Set address failed"}, + {FREEBSD_ERR_NO_POWER, "No power"}, + {FREEBSD_ERR_TOO_DEEP, "Too deep"}, + {FREEBSD_ERR_IOERROR, "I/O error"}, + {FREEBSD_ERR_NOT_CONFIGURED, "Not configured"}, + {FREEBSD_ERR_TIMEOUT, "Timeout"}, + {FREEBSD_ERR_SHORT_XFER, "Short transfer"}, + {FREEBSD_ERR_STALLED, "Stalled"}, + {FREEBSD_ERR_INTERRUPTED, "Interrupted"}, + {FREEBSD_ERR_DMA_LOAD_FAILED, "DMA load failed"}, + {FREEBSD_ERR_BAD_CONTEXT, "Bad context"}, + {FREEBSD_ERR_NO_ROOT_HUB, "No root hub"}, + {FREEBSD_ERR_NO_INTR_THREAD, "No interrupt thread"}, + {FREEBSD_ERR_NOT_LOCKED, "Not locked"}, + {0, NULL} +}; + +/* USB speeds */ +#define FREEBSD_SPEED_VARIABLE 0 +#define FREEBSD_SPEED_LOW 1 +#define FREEBSD_SPEED_FULL 2 +#define FREEBSD_SPEED_HIGH 3 +#define FREEBSD_SPEED_SUPER 4 + +static const value_string usb_freebsd_speed_vals[] = { + {FREEBSD_SPEED_VARIABLE, "Variable"}, + {FREEBSD_SPEED_LOW, "Low"}, + {FREEBSD_SPEED_FULL, "Full"}, + {FREEBSD_SPEED_HIGH, "High"}, + {FREEBSD_SPEED_SUPER, "Super"}, + {0, NULL} +}; + +/* Frame flags */ +#define FREEBSD_FRAMEFLAG_READ 0x00000001 +#define FREEBSD_FRAMEFLAG_DATA_FOLLOWS 0x00000002 + +static int * const usb_frame_flags_fields[] = { + &hf_usb_frame_flags_read, + &hf_usb_frame_flags_data_follows, + NULL +}; + +static const value_string usb_linux_urb_type_vals[] = { + {URB_SUBMIT, "URB_SUBMIT"}, + {URB_COMPLETE, "URB_COMPLETE"}, + {URB_ERROR, "URB_ERROR"}, + {0, NULL} +}; + +static const value_string usb_linux_transfer_type_vals[] = { + {URB_CONTROL, "URB_CONTROL"}, + {URB_ISOCHRONOUS, "URB_ISOCHRONOUS"}, + {URB_INTERRUPT, "URB_INTERRUPT"}, + {URB_BULK, "URB_BULK"}, + {0, NULL} +}; + +static const value_string usb_transfer_type_and_direction_vals[] = { + {URB_CONTROL, "URB_CONTROL out"}, + {URB_ISOCHRONOUS, "URB_ISOCHRONOUS out"}, + {URB_INTERRUPT, "URB_INTERRUPT out"}, + {URB_BULK, "URB_BULK out"}, + {URB_CONTROL | URB_TRANSFER_IN, "URB_CONTROL in"}, + {URB_ISOCHRONOUS | URB_TRANSFER_IN, "URB_ISOCHRONOUS in"}, + {URB_INTERRUPT | URB_TRANSFER_IN, "URB_INTERRUPT in"}, + {URB_BULK | URB_TRANSFER_IN, "URB_BULK in"}, + {0, NULL} +}; + +static const value_string usb_endpoint_direction_vals[] = { + {0, "OUT"}, + {1, "IN"}, + {0, NULL} +}; + +static const range_string usb_setup_flag_rvals[] = { + {0, 0, "relevant"}, + {1, 255, "not relevant"}, + {0, 0, NULL} +}; + +static const range_string usb_data_flag_rvals[] = { + {0, 0, "present"}, + {1, 255, "not present"}, + {0, 0, NULL} +}; + +extern value_string_ext ext_usb_vendors_vals; +extern value_string_ext ext_usb_products_vals; +extern value_string_ext ext_usb_audio_subclass_vals; +extern value_string_ext ext_usb_com_subclass_vals; +extern value_string_ext ext_usb_massstorage_subclass_vals; +extern value_string_ext linux_negative_errno_vals_ext; + +/* + * Standard descriptor types. + * + * all class specific descriptor types were removed from this list + * a descriptor type is not globally unique + * dissectors for the USB classes should provide their own value string + * and pass it to dissect_usb_descriptor_header() + * + */ +#define USB_DT_DEVICE 1 +#define USB_DT_CONFIG 2 +#define USB_DT_STRING 3 +#define USB_DT_INTERFACE 4 +#define USB_DT_ENDPOINT 5 +#define USB_DT_DEVICE_QUALIFIER 6 +#define USB_DT_OTHER_SPEED_CONFIG 7 +#define USB_DT_INTERFACE_POWER 8 +/* these are from a minor usb 2.0 revision (ECN) */ +#define USB_DT_OTG 9 +#define USB_DT_DEBUG 10 +#define USB_DT_INTERFACE_ASSOCIATION 11 +/* these are from usb 3.0 specification */ +#define USB_DT_BOS 0x0F +#define USB_DT_DEVICE_CAPABILITY 0x10 +#define USB_DT_SUPERSPEED_EP_COMPANION 0x30 +/* these are from usb 3.1 specification */ +#define USB_DT_SUPERSPEED_ISO_EP_COMPANION 0x31 + +/* There are only Standard Descriptor Types, Class-specific types are + provided by "usb.descriptor" descriptors table*/ +static const value_string std_descriptor_type_vals[] = { + {USB_DT_DEVICE, "DEVICE"}, + {USB_DT_CONFIG, "CONFIGURATION"}, + {USB_DT_STRING, "STRING"}, + {USB_DT_INTERFACE, "INTERFACE"}, + {USB_DT_ENDPOINT, "ENDPOINT"}, + {USB_DT_DEVICE_QUALIFIER, "DEVICE QUALIFIER"}, + {USB_DT_OTHER_SPEED_CONFIG, "OTHER SPEED CONFIG"}, + {USB_DT_INTERFACE_POWER, "INTERFACE POWER"}, + {USB_DT_OTG, "OTG"}, + {USB_DT_DEBUG, "DEBUG"}, + {USB_DT_INTERFACE_ASSOCIATION, "INTERFACE ASSOCIATION"}, + {USB_DT_BOS, "BOS"}, + {USB_DT_DEVICE_CAPABILITY, "DEVICE CAPABILITY"}, + {USB_DT_SUPERSPEED_EP_COMPANION, "SUPERSPEED USB ENDPOINT COMPANION"}, + {USB_DT_SUPERSPEED_ISO_EP_COMPANION, "SUPERSPEED PLUS ISOCHRONOUS ENDPOINT COMPANION"}, + {0,NULL} +}; +static value_string_ext std_descriptor_type_vals_ext = + VALUE_STRING_EXT_INIT(std_descriptor_type_vals); + +/* + * Feature selectors. + * Per USB 3.1 spec, Table 9-7 + */ +#define USB_FS_ENDPOINT_HALT 0 +#define USB_FS_FUNCTION_SUSPEND 0 /* same as ENDPOINT_HALT */ +#define USB_FS_DEVICE_REMOTE_WAKEUP 1 +#define USB_FS_TEST_MODE 2 +#define USB_FS_B_HNP_ENABLE 3 +#define USB_FS_A_HNP_SUPPORT 4 +#define USB_FS_A_ALT_HNP_SUPPORT 5 +#define USB_FS_WUSB_DEVICE 6 +#define USB_FS_U1_ENABLE 48 +#define USB_FS_U2_ENABLE 49 +#define USB_FS_LTM_ENABLE 50 +#define USB_FS_B3_NTF_HOST_REL 51 +#define USB_FS_B3_RSP_ENABLE 52 +#define USB_FS_LDM_ENABLE 53 + +static const value_string usb_endpoint_feature_selector_vals[] = { + {USB_FS_ENDPOINT_HALT, "ENDPOINT HALT"}, + {0, NULL} +}; + +static const value_string usb_interface_feature_selector_vals[] = { + {USB_FS_FUNCTION_SUSPEND, "FUNCTION SUSPEND"}, + {0, NULL} +}; + +static const value_string usb_device_feature_selector_vals[] = { + {USB_FS_DEVICE_REMOTE_WAKEUP, "DEVICE REMOTE WAKEUP"}, + {USB_FS_TEST_MODE, "TEST MODE"}, + {USB_FS_B_HNP_ENABLE, "B HNP ENABLE"}, + {USB_FS_A_HNP_SUPPORT, "A HNP SUPPORT"}, + {USB_FS_A_ALT_HNP_SUPPORT, "A ALT HNP SUPPORT"}, + {USB_FS_WUSB_DEVICE, "WUSB DEVICE"}, + {USB_FS_U1_ENABLE, "U1 ENABLE"}, + {USB_FS_U2_ENABLE, "U2 ENABLE"}, + {USB_FS_LTM_ENABLE, "LTM ENABLE"}, + {USB_FS_B3_NTF_HOST_REL, "B3 NTF HOST REL"}, + {USB_FS_B3_RSP_ENABLE, "B3 RSP ENABLE"}, + {USB_FS_LDM_ENABLE, "LDM ENABLE"}, + {0, NULL} +}; + + +/* the transfer type in the endpoint descriptor, i.e. the type of the endpoint + (this is not the same as the URB transfer type) */ +#define USB_EP_CONTROL 0x00 +#define USB_EP_ISOCHRONOUS 0x01 +#define USB_EP_BULK 0x02 +#define USB_EP_INTERRUPT 0x03 + +static const value_string usb_bmAttributes_transfer_vals[] = { + {USB_EP_CONTROL, "Control-Transfer"}, + {USB_EP_ISOCHRONOUS, "Isochronous-Transfer"}, + {USB_EP_BULK, "Bulk-Transfer"}, + {USB_EP_INTERRUPT, "Interrupt-Transfer"}, + {0, NULL} +}; + +static const value_string usb_bmAttributes_sync_vals[] = { + {0x00, "No Sync"}, + {0x01, "Asynchronous"}, + {0x02, "Adaptive"}, + {0x03, "Synchronous"}, + {0, NULL} +}; + +static const value_string usb_bmAttributes_behaviour_vals[] = { + {0x00, "Data-Endpoint"}, + {0x01, "Explicit Feedback-Endpoint"}, + {0x02, "Implicit Feedback-Data-Endpoint"}, + {0x03, "Reserved"}, + {0, NULL} +}; + +static const value_string usb_wMaxPacketSize_slots_vals[] = { + {0x00, "1"}, + {0x01, "2"}, + {0x02, "3"}, + {0x03, "Reserved"}, + {0, NULL} +}; + +/* USBPcap versions up to 1.4.1.0 captures USB control as 2 or 3 packets: + * * SETUP with 8 bytes of Setup data + * * DATA with optional data (either OUT or IN) + * * STATUS without any USB payload, only the pseudoheader + * + * USBPcap versions 1.5.0.0 and up captures USB control as 2 packets: + * * SETUP with 8 bytes of Setup data and optional DATA OUT + * * COMPLETE with optional DATA IN + * + * The SETUP/COMPLETE matches the way control transfers are captured by + * usbmon on Linux. + */ +#define USB_CONTROL_STAGE_SETUP 0x00 +#define USB_CONTROL_STAGE_DATA 0x01 +#define USB_CONTROL_STAGE_STATUS 0x02 +#define USB_CONTROL_STAGE_COMPLETE 0x03 + +static const value_string usb_control_stage_vals[] = { + {USB_CONTROL_STAGE_SETUP, "Setup"}, + {USB_CONTROL_STAGE_DATA, "Data"}, + {USB_CONTROL_STAGE_STATUS, "Status"}, + {USB_CONTROL_STAGE_COMPLETE, "Complete"}, + {0, NULL} +}; + +/* Extra URB code to indicate relevant USB IRPs that don't directly + * have any matching USB transfer. + */ +#define USBPCAP_URB_IRP_INFO 0xFE + +static const value_string win32_usb_transfer_type_vals[] = { + {URB_CONTROL, "URB_CONTROL"}, + {URB_ISOCHRONOUS, "URB_ISOCHRONOUS"}, + {URB_INTERRUPT, "URB_INTERRUPT"}, + {URB_BULK, "URB_BULK"}, + {USBPCAP_URB_IRP_INFO, "USB IRP Info"}, + {0, NULL} +}; + +static const value_string win32_urb_function_vals[] = { + {0x0000, "URB_FUNCTION_SELECT_CONFIGURATION"}, + {0x0001, "URB_FUNCTION_SELECT_INTERFACE"}, + {0x0002, "URB_FUNCTION_ABORT_PIPE"}, + {0x0003, "URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL"}, + {0x0004, "URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL"}, + {0x0005, "URB_FUNCTION_GET_FRAME_LENGTH"}, + {0x0006, "URB_FUNCTION_SET_FRAME_LENGTH"}, + {0x0007, "URB_FUNCTION_GET_CURRENT_FRAME_NUMBER"}, + {0x0008, "URB_FUNCTION_CONTROL_TRANSFER"}, + {0x0009, "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"}, + {0x000A, "URB_FUNCTION_ISOCH_TRANSFER"}, + {0x000B, "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"}, + {0x000C, "URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE"}, + {0x000D, "URB_FUNCTION_SET_FEATURE_TO_DEVICE"}, + {0x000E, "URB_FUNCTION_SET_FEATURE_TO_INTERFACE"}, + {0x000F, "URB_FUNCTION_SET_FEATURE_TO_ENDPOINT"}, + {0x0010, "URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE"}, + {0x0011, "URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE"}, + {0x0012, "URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT"}, + {0x0013, "URB_FUNCTION_GET_STATUS_FROM_DEVICE"}, + {0x0014, "URB_FUNCTION_GET_STATUS_FROM_INTERFACE"}, + {0x0015, "URB_FUNCTION_GET_STATUS_FROM_ENDPOINT"}, + {0x0016, "URB_FUNCTION_RESERVED_0X0016"}, + {0x0017, "URB_FUNCTION_VENDOR_DEVICE"}, + {0x0018, "URB_FUNCTION_VENDOR_INTERFACE"}, + {0x0019, "URB_FUNCTION_VENDOR_ENDPOINT"}, + {0x001A, "URB_FUNCTION_CLASS_DEVICE"}, + {0x001B, "URB_FUNCTION_CLASS_INTERFACE"}, + {0x001C, "URB_FUNCTION_CLASS_ENDPOINT"}, + {0x001D, "URB_FUNCTION_RESERVE_0X001D"}, + {0x001E, "URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL"}, + {0x001F, "URB_FUNCTION_CLASS_OTHER"}, + {0x0020, "URB_FUNCTION_VENDOR_OTHER"}, + {0x0021, "URB_FUNCTION_GET_STATUS_FROM_OTHER"}, + {0x0022, "URB_FUNCTION_CLEAR_FEATURE_TO_OTHER"}, + {0x0023, "URB_FUNCTION_SET_FEATURE_TO_OTHER"}, + {0x0024, "URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT"}, + {0x0025, "URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT"}, + {0x0026, "URB_FUNCTION_GET_CONFIGURATION"}, + {0x0027, "URB_FUNCTION_GET_INTERFACE"}, + {0x0028, "URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"}, + {0x0029, "URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE"}, + {0x002A, "URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR"}, + {0x002B, "URB_FUNCTION_RESERVE_0X002B"}, + {0x002C, "URB_FUNCTION_RESERVE_0X002C"}, + {0x002D, "URB_FUNCTION_RESERVE_0X002D"}, + {0x002E, "URB_FUNCTION_RESERVE_0X002E"}, + {0x002F, "URB_FUNCTION_RESERVE_0X002F"}, + {0x0030, "URB_FUNCTION_SYNC_RESET_PIPE"}, + {0x0031, "URB_FUNCTION_SYNC_CLEAR_STALL"}, + {0x0032, "URB_FUNCTION_CONTROL_TRANSFER_EX"}, + {0x0033, "URB_FUNCTION_RESERVE_0X0033"}, + {0x0034, "URB_FUNCTION_RESERVE_0X0034"}, + {0, NULL} +}; +static value_string_ext win32_urb_function_vals_ext = VALUE_STRING_EXT_INIT(win32_urb_function_vals); + +static const value_string win32_usbd_status_vals[] = { + {0x00000000, "USBD_STATUS_SUCCESS"}, + {0x40000000, "USBD_STATUS_PENDING"}, + + {0x80000200, "USBD_STATUS_INVALID_URB_FUNCTION"}, + {0x80000300, "USBD_STATUS_INVALID_PARAMETER"}, + {0x80000400, "USBD_STATUS_ERROR_BUSY"}, + {0x80000600, "USBD_STATUS_INVALID_PIPE_HANDLE"}, + {0x80000700, "USBD_STATUS_NO_BANDWIDTH"}, + {0x80000800, "USBD_STATUS_INTERNAL_HC_ERROR"}, + {0x80000900, "USBD_STATUS_ERROR_SHORT_TRANSFER"}, + + {0xC0000001, "USBD_STATUS_CRC"}, + {0xC0000002, "USBD_STATUS_BTSTUFF"}, + {0xC0000003, "USBD_STATUS_DATA_TOGGLE_MISMATCH"}, + {0xC0000004, "USBD_STATUS_STALL_PID"}, + {0xC0000005, "USBD_STATUS_DEV_NOT_RESPONDING"}, + {0xC0000006, "USBD_STATUS_PID_CHECK_FAILURE"}, + {0xC0000007, "USBD_STATUS_UNEXPECTED_PID"}, + {0xC0000008, "USBD_STATUS_DATA_OVERRUN"}, + {0xC0000009, "USBD_STATUS_DATA_UNDERRUN"}, + {0xC000000A, "USBD_STATUS_RESERVED1"}, + {0xC000000B, "USBD_STATUS_RESERVED2"}, + {0xC000000C, "USBD_STATUS_BUFFER_OVERRUN"}, + {0xC000000D, "USBD_STATUS_BUFFER_UNDERRUN"}, + {0xC000000F, "USBD_STATUS_NOT_ACCESSED"}, + {0xC0000010, "USBD_STATUS_FIFO"}, + {0xC0000011, "USBD_STATUS_XACT_ERROR"}, + {0xC0000012, "USBD_STATUS_BABBLE_DETECTED"}, + {0xC0000013, "USBD_STATUS_DATA_BUFFER_ERROR"}, + {0xC0000030, "USBD_STATUS_ENDPOINT_HALTED"}, + + {0xC0000A00, "USBD_STATUS_BAD_START_FRAME"}, + {0xC0000B00, "USBD_STATUS_ISOCH_REQUEST_FAILED"}, + {0xC0000C00, "USBD_STATUS_FRAME_CONTROL_OWNED"}, + {0xC0000D00, "USBD_STATUS_FRAME_CONTROL_NOT_OWNED"}, + {0xC0000E00, "USBD_STATUS_NOT_SUPPORTED"}, + {0xC0000F00, "USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR"}, + {0xC0001000, "USBD_STATUS_INSUFFICIENT_RESOURCES"}, + {0xC0002000, "USBD_STATUS_SET_CONFIG_FAILED"}, + {0xC0003000, "USBD_STATUS_BUFFER_TOO_SMALL"}, + {0xC0004000, "USBD_STATUS_INTERFACE_NOT_FOUND"}, + {0xC0005000, "USBD_STATUS_INVALID_PIPE_FLAGS"}, + {0xC0006000, "USBD_STATUS_TIMEOUT"}, + {0xC0007000, "USBD_STATUS_DEVICE_GONE"}, + {0xC0008000, "USBD_STATUS_STATUS_NOT_MAPPED"}, + {0xC0009000, "USBD_STATUS_HUB_INTERNAL_ERROR"}, + {0xC0010000, "USBD_STATUS_CANCELED"}, + {0xC0020000, "USBD_STATUS_ISO_NOT_ACCESSED_BY_HW"}, + {0xC0030000, "USBD_STATUS_ISO_TD_ERROR"}, + {0xC0040000, "USBD_STATUS_ISO_NA_LATE_USBPORT"}, + {0xC0050000, "USBD_STATUS_ISO_NOT_ACCESSED_LATE"}, + {0xC0100000, "USBD_STATUS_BAD_DESCRIPTOR"}, + {0xC0100001, "USBD_STATUS_BAD_DESCRIPTOR_BLEN"}, + {0xC0100002, "USBD_STATUS_BAD_DESCRIPTOR_TYPE"}, + {0xC0100003, "USBD_STATUS_BAD_INTERFACE_DESCRIPTOR"}, + {0xC0100004, "USBD_STATUS_BAD_ENDPOINT_DESCRIPTOR"}, + {0xC0100005, "USBD_STATUS_BAD_INTERFACE_ASSOC_DESCRIPTOR"}, + {0xC0100006, "USBD_STATUS_BAD_CONFIG_DESC_LENGTH"}, + {0xC0100007, "USBD_STATUS_BAD_NUMBER_OF_INTERFACES"}, + {0xC0100008, "USBD_STATUS_BAD_NUMBER_OF_ENDPOINTS"}, + {0xC0100009, "USBD_STATUS_BAD_ENDPOINT_ADDRESS"}, + {0, NULL} +}; +static value_string_ext win32_usbd_status_vals_ext = VALUE_STRING_EXT_INIT(win32_usbd_status_vals); + +static const value_string win32_usb_info_direction_vals[] = { + {0, "FDO -> PDO"}, + {1, "PDO -> FDO"}, + {0, NULL} +}; + +static const value_string usb_cdc_protocol_vals[] = { + {0x00, "No class specific protocol required"}, + {0x01, "AT Commands: V.250 etc"}, + {0x02, "AT Commands defined by PCCA-101"}, + {0x03, "AT Commands defined by PCCA-101 & Annex O"}, + {0x04, "AT Commands defined by GSM 07.07"}, + {0x05, "AT Commands defined by 3GPP 27.007"}, + {0x06, "AT Commands defined by TIA for CDMA"}, + {0x07, "Ethernet Emulation Model"}, + {0xFE, "External Protocol: Commands defined by Command Set Functional Descriptor"}, + {0xFF, "Vendor-specific"}, + {0, NULL} +}; +static value_string_ext usb_cdc_protocol_vals_ext = VALUE_STRING_EXT_INIT(usb_cdc_protocol_vals); + +extern value_string_ext usb_massstorage_protocol_vals_ext; + +static const value_string usb_cdc_data_protocol_vals[] = { + {0x00, "No class specific protocol required"}, + {0x01, "Network Transfer Block"}, + {0x02, "Network Transfer Block (IP + DSS)"}, + {0x30, "Physical interface protocol for ISDN BRI"}, + {0x31, "HDLC"}, + {0x32, "Transparent"}, + {0x50, "Management protocol for Q.921 data link protocol"}, + {0x51, "Data link protocol for Q.931"}, + {0x52, "TEI-multiplexor for Q.921 data link protocol"}, + {0x90, "Data compression procedures"}, + {0x91, "Euro-ISDN protocol control"}, + {0x92, "V.24 rate adaptation to ISDN"}, + {0x93, "CAPI Commands"}, + {0xFE, "The protocol(s) are described using a Protocol Unit Functional Descriptors on Communications Class Interface"}, + {0xFF, "Vendor-specific"}, + {0, NULL} +}; +static value_string_ext usb_cdc_data_protocol_vals_ext = VALUE_STRING_EXT_INIT(usb_cdc_data_protocol_vals); + +static const value_string usb_hid_subclass_vals[] = { + {0, "No Subclass"}, + {1, "Boot Interface"}, + {0, NULL} +}; +static value_string_ext usb_hid_subclass_vals_ext = VALUE_STRING_EXT_INIT(usb_hid_subclass_vals); + +static const value_string usb_hid_boot_protocol_vals[] = { + {0, "None"}, + {1, "Keyboard"}, + {2, "Mouse"}, + {0, NULL} +}; +static value_string_ext usb_hid_boot_protocol_vals_ext = VALUE_STRING_EXT_INIT(usb_hid_boot_protocol_vals); + +static const value_string usb_misc_subclass_vals[] = { + {0x03, "Cable Based Association Framework"}, + {0x04, "RNDIS"}, + {IF_SUBCLASS_MISC_U3V, "USB3 Vision"}, + {0x06, "Stream Transport Efficient Protocol"}, + {0, NULL} +}; +static value_string_ext usb_misc_subclass_vals_ext = VALUE_STRING_EXT_INIT(usb_misc_subclass_vals); + + +static const value_string usb_app_subclass_vals[] = { + {0x01, "Device Firmware Upgrade"}, + {0x02, "IRDA Bridge"}, + {0x03, "USB Test and Measurement Device"}, + {0, NULL} +}; +static value_string_ext usb_app_subclass_vals_ext = VALUE_STRING_EXT_INIT(usb_app_subclass_vals); + + +static const value_string usb_app_dfu_protocol_vals[] = { + {0x01, "Runtime protocol"}, + {0x02, "DFU mode protocol"}, + {0, NULL} +}; +static value_string_ext usb_app_dfu_protocol_vals_ext = VALUE_STRING_EXT_INIT(usb_app_dfu_protocol_vals); + +static const value_string usb_app_irda_protocol_vals[] = { + {0x00, "IRDA Bridge device"}, + {0, NULL} +}; +static value_string_ext usb_app_irda_protocol_vals_ext = VALUE_STRING_EXT_INIT(usb_app_irda_protocol_vals); + +static const value_string usb_app_usb_test_and_measurement_protocol_vals[] = { + {0x00, "USB Test and Measurement Device"}, + {0x01, "USB Test and Measurement Device conforming to the USBTMC USB488 Subclass Specification"}, + {0, NULL} +}; +static value_string_ext usb_app_usb_test_and_measurement_protocol_vals_ext = VALUE_STRING_EXT_INIT(usb_app_usb_test_and_measurement_protocol_vals); + +/* macOS */ + +/* Request Type */ +#define DARWIN_IO_SUBMIT 0 +#define DARWIN_IO_COMPLETE 1 + + +static const value_string usb_darwin_request_type_vals[] = { + {DARWIN_IO_SUBMIT, "SUBMIT"}, + {DARWIN_IO_COMPLETE, "COMPLETE"}, + {0, NULL} +}; + +/* Transfer type */ +static const value_string usb_darwin_endpoint_type_vals[] = { + {USB_EP_CONTROL, "Control"}, + {USB_EP_ISOCHRONOUS, "Isochronous"}, + {USB_EP_BULK, "Bulk"}, + {USB_EP_INTERRUPT, "Interrupt"}, + {0, NULL} +}; + +/* USB speeds */ +#define DARWIN_SPEED_LOW 0 +#define DARWIN_SPEED_FULL 1 +#define DARWIN_SPEED_HIGH 2 +#define DARWIN_SPEED_SUPER 3 +#define DARWIN_SPEED_SUPERPLUS 4 + +static const value_string usb_darwin_speed_vals[] = { + {DARWIN_SPEED_LOW, "Low"}, + {DARWIN_SPEED_FULL, "Full"}, + {DARWIN_SPEED_HIGH, "High"}, + {DARWIN_SPEED_SUPER, "Super"}, + {DARWIN_SPEED_SUPERPLUS, "Super+"}, + {0, NULL} +}; + +static const value_string darwin_usb_status_vals[] = { + {0x00000000, "kIOReturnSuccess"}, + {0xe00002bc, "kIOReturnError"}, + {0xe00002bd, "kIOReturnNoMemory"}, + {0xe00002be, "kIOReturnNoResources"}, + {0xe00002bf, "kIOReturnIPCError"}, + {0xe00002c0, "kIOReturnNoDevice"}, + {0xe00002c1, "kIOReturnNotPrivileged"}, + {0xe00002c2, "kIOReturnBadArgument"}, + {0xe00002c3, "kIOReturnLockedRead"}, + {0xe00002c4, "kIOReturnLockedWrite"}, + {0xe00002c5, "kIOReturnExclusiveAccess"}, + {0xe00002c6, "kIOReturnBadMessageID"}, + {0xe00002c7, "kIOReturnUnsupported"}, + {0xe00002c8, "kIOReturnVMError"}, + {0xe00002c9, "kIOReturnInternalError"}, + {0xe00002ca, "kIOReturnIOError"}, + + {0xe00002cc, "kIOReturnCannotLock"}, + {0xe00002cd, "kIOReturnNotOpen"}, + {0xe00002ce, "kIOReturnNotReadable"}, + {0xe00002cf, "kIOReturnNotWritable"}, + {0xe00002d0, "kIOReturnNotAligned"}, + {0xe00002d1, "kIOReturnBadMedia"}, + {0xe00002d2, "kIOReturnStillOpen"}, + {0xe00002d3, "kIOReturnRLDError"}, + {0xe00002d4, "kIOReturnDMAError"}, + {0xe00002d5, "kIOReturnBusy"}, + {0xe00002d6, "kIOReturnTimeout"}, + {0xe00002d7, "kIOReturnOffline"}, + {0xe00002d8, "kIOReturnNotReady"}, + {0xe00002d9, "kIOReturnNotAttached"}, + {0xe00002da, "kIOReturnNoChannels"}, + {0xe00002db, "kIOReturnNoSpace"}, + + {0xe00002dd, "kIOReturnPortExists"}, + {0xe00002de, "kIOReturnCannotWire"}, + {0xe00002df, "kIOReturnNoInterrupt"}, + {0xe00002e0, "kIOReturnNoFrames"}, + {0xe00002e1, "kIOReturnMessageTooLarge"}, + {0xe00002e2, "kIOReturnNotPermitted"}, + {0xe00002e3, "kIOReturnNoPower"}, + {0xe00002e4, "kIOReturnNoMedia"}, + {0xe00002e5, "kIOReturnUnformattedMedia"}, + {0xe00002e6, "kIOReturnUnsupportedMode"}, + {0xe00002e7, "kIOReturnUnderrun"}, + {0xe00002e8, "kIOReturnOverrun"}, + {0xe00002e9, "kIOReturnDeviceError"}, + {0xe00002ea, "kIOReturnNoCompletion"}, + {0xe00002eb, "kIOReturnAborted"}, + {0xe00002ec, "kIOReturnNoBandwidth"}, + {0xe00002ed, "kIOReturnNotResponding"}, + {0xe00002ee, "kIOReturnIsoTooOld"}, + {0xe00002ef, "kIOReturnIsoTooNew"}, + {0xe00002f0, "kIOReturnNotFound"}, + {0, NULL} +}; + +static const guint32 darwin_endpoint_to_linux[] = +{ + URB_CONTROL, + URB_ISOCHRONOUS, + URB_BULK, + URB_INTERRUPT, + URB_UNKNOWN +}; + +static value_string_ext usb_darwin_status_vals_ext = VALUE_STRING_EXT_INIT(darwin_usb_status_vals); + + +static const value_string netmon_event_id_vals[] = { + {1, "USBPORT_ETW_EVENT_HC_ADD USBPORT_ETW_EVENT_HC_ADD"}, + {2, "USBPORT_ETW_EVENT_HC_REMOVAL USBPORT_ETW_EVENT_HC_REMOVAL"}, + {3, "USBPORT_ETW_EVENT_HC_INFORMATION USBPORT_ETW_EVENT_HC_INFORMATION"}, + {4, "USBPORT_ETW_EVENT_HC_START USBPORT_ETW_EVENT_HC_START"}, + {5, "USBPORT_ETW_EVENT_HC_STOP USBPORT_ETW_EVENT_HC_STOP"}, + {6, "USBPORT_ETW_EVENT_HC_SUSPEND USBPORT_ETW_EVENT_HC_SUSPEND"}, + {7, "USBPORT_ETW_EVENT_HC_RESUME USBPORT_ETW_EVENT_HC_RESUME"}, + {8, "USBPORT_ETW_EVENT_HC_ASYNC_SCHEDULE_ENABLE"}, + {9, "USBPORT_ETW_EVENT_HC_ASYNC_SCHEDULE_DISABLE"}, + {10, "USBPORT_ETW_EVENT_HC_PERIODIC_SCHEDULE_ENABLE"}, + {11, "USBPORT_ETW_EVENT_HC_PERIODIC_SCHEDULE_DISABLE"}, + {12, "USBPORT_ETW_EVENT_DEVICE_CREATE"}, + {13, "USBPORT_ETW_EVENT_DEVICE_INITIALIZE"}, + {14, "USBPORT_ETW_EVENT_DEVICE_REMOVAL"}, + {15, "USBPORT_ETW_EVENT_DEVICE_INFORMATION"}, + {16, "USBPORT_ETW_EVENT_DEVICE_IDLE_STATE_SET"}, + {17, "USBPORT_ETW_EVENT_DEVICE_IDLE_STATE_CLEAR"}, + {18, "USBPORT_ETW_EVENT_ENDPOINT_OPEN"}, + {19, "USBPORT_ETW_EVENT_ENDPOINT_CLOSE USBPORT_ETW_EVENT_ENDPOINT_CLOSE"}, + {20, "USBPORT_ETW_EVENT_ENDPOINT_INFORMATION"}, + {21, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SELECT_CONFIGURATION"}, + {22, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SELECT_INTERFACE"}, + {23, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_CURRENT_FRAME_NUMBER"}, + {24, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CONTROL_TRANSFER"}, + {25, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CONTROL_TRANSFER_EX"}, + {26, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"}, + {27, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_ISOCH_TRANSFER"}, + {28, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"}, + {29, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE"}, + {30, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT"}, + {31, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT"}, + {32, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"}, + {33, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE"}, + {34, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_FEATURE_TO_DEVICE"}, + {35, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_FEATURE_TO_INTERFACE"}, + {36, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_FEATURE_TO_ENDPOINT"}, + {37, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE"}, + {38, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE"}, + {39, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT"}, + {40, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLEAR_FEATURE_TO_OTHER"}, + {41, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_FEATURE_TO_OTHER"}, + {42, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_STATUS_FROM_DEVICE"}, + {43, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_STATUS_FROM_INTERFACE"}, + {44, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_STATUS_FROM_ENDPOINT"}, + {45, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_STATUS_FROM_OTHER"}, + {46, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_VENDOR_DEVICE"}, + {47, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_VENDOR_INTERFACE"}, + {48, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_VENDOR_ENDPOINT"}, + {49, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLASS_DEVICE"}, + {50, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLASS_INTERFACE"}, + {51, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLASS_ENDPOINT"}, + {52, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_CLASS_OTHER"}, + {53, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_VENDOR_OTHER"}, + {54, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_ABORT_PIPE"}, + {55, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL"}, + {56, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SYNC_RESET_PIPE"}, + {57, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SYNC_CLEAR_STALL"}, + {58, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_CONFIGURATION"}, + {59, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_INTERFACE"}, + {60, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR"}, + {61, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL"}, + {62, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL"}, + {63, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_GET_FRAME_LENGTH"}, + {64, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_SET_FRAME_LENGTH"}, + {65, "USBPORT_ETW_EVENT_DISPATCH_URB_FUNCTION_RESERVED"}, + {66, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_CONTROL_TRANSFER"}, + {67, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_CONTROL_TRANSFER_EX"}, + {68, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_CONTROL_TRANSFER_DATA"}, + {69, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_CONTROL_TRANSFER_EX_DATA"}, + {70, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"}, + {71, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER_DATA"}, + {72, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_ISOCH_TRANSFER"}, + {73, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_ISOCH_TRANSFER_DATA"}, + {74, "USBPORT_ETW_EVENT_INTERNAL_URB_FUNCTION_CONTROL_TRANSFER"}, + {75, "USBPORT_ETW_EVENT_COMPLETE_INTERNAL_URB_FUNCTION_CONTROL_TRANSFER"}, + {76, "USBPORT_ETW_EVENT_COMPLETE_INTERNAL_URB_FUNCTION_CONTROL_TRANSFER_DATA"}, + {77, "USBPORT_ETW_EVENT_COMPLETE_URB_FUNCTION_ABORT_PIPE"}, + {78, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_HEADER_LENGTH_WARNING"}, + {79, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_FUNCTION"}, + {80, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_HEADER_LENGTH"}, + {81, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_DEVICE_HANDLE"}, + {82, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_FUNCTION_NOT_SUPPORTED"}, + {83, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_FUNCTION_RESERVED"}, + {84, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_DUE_TO_HC_SUSPEND"}, + {85, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_URB_LINK"}, + {86, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_PIPE_HANDLE"}, + {87, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_ZERO_BW_PIPE_HANDLE"}, + {88, "USBPORT_ETW_EVENT_DISPATCH_URB_NOP_ZERO_BW_PIPE_HANDLE_REQUEST"}, + {89, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_CONTROL_TRANSFER_ENDPOINT"}, + {90, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_CONTROL_TRANSFER_BUFFER_LENGTH"}, + {91, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_BULK_OR_INTERRUPT_TRANSFER_ENDPOINT"}, + {92, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_BULK_OR_INTERRUPT_TRANSFER_BUFFER_LENGTH"}, + {93, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_ISOCHRONOUS_TRANSFER_ENDPOINT"}, + {94, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_NULL_TRANSFER_BUFFER_AND_MDL"}, + {95, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_NON_NULL_TRANSFER_BUFFER_MDL"}, + {96, "USBPORT_ETW_EVENT_DISPATCH_URB_ALLOCATE_MDL_FAILURE"}, + {97, "USBPORT_ETW_EVENT_DISPATCH_URB_ALLOCATE_TRANSFER_CONTEXT_FAILURE"}, + {98, "USBPORT_ETW_EVENT_DISPATCH_URB_NOP_ROOTHUB_PIPE_HANDLE_REQUEST"}, + {99, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_ISOCHRONOUS_ZERO_LENGTH"}, + {100, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_ISOCHRONOUS_NUM_PACKETS"}, + {101, "USBPORT_ETW_EVENT_DISPATCH_URB_INVALID_ISOCHRONOUS_START_FRAME"}, + {102, "USBPORT_ETW_EVENT_IRP_CANCEL"}, + {103, "USBPORT_ETW_EVENT_USBUSER_OP_RAW_RESET_PORT_DISPATCH"}, + {104, "USBPORT_ETW_EVENT_USBUSER_OP_RAW_RESET_PORT_STATUS1"}, + {105, "USBPORT_ETW_EVENT_USBUSER_OP_RAW_RESET_PORT_STATUS2"}, + {106, "USBPORT_ETW_EVENT_USBUSER_OP_RAW_RESET_PORT_STATUS3"}, + {107, "USBPORT_ETW_EVENT_USBUSER_OP_RAW_RESET_PORT_COMPLETE"}, + {108, "USBPORT_ETW_EVENT_USBUSER_OP_SEND_ONE_PACKET_DISPATCH"}, + {109, "USBPORT_ETW_EVENT_USBUSER_OP_SEND_ONE_PACKET_DISPATCH_DATA"}, + {110, "USBPORT_ETW_EVENT_USBUSER_OP_SEND_ONE_PACKET_TIMEOUT"}, + {111, "USBPORT_ETW_EVENT_USBUSER_OP_SEND_ONE_PACKET_COMPLETE"}, + {112, "USBPORT_ETW_EVENT_USBUSER_OP_SEND_ONE_PACKET_COMPLETE_DATA"}, + {113, "USBPORT_ETW_EVENT_CODE_EXECUTION_TIME"}, + {114, "USBPORT_ETW_EVENT_PUT_SGLIST_EXECUTION_TIME"}, + {115, "USBPORT_ETW_EVENT_BUILD_SGLIST_EXECUTION_TIME"}, + {1024, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_DISPATCH"}, + {1025, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_COMPLETE"}, + {1026, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_COMPLETE_ERROR_1"}, + {1027, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_COMPLETE_ERROR_2"}, + {1028, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_COMPLETE_ERROR_3"}, + {1029, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_COMPLETE_ERROR_4"}, + {1030, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_START_COMPLETE_ERROR_5"}, + {1031, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_STOP_DISPATCH"}, + {1032, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_STOP_COMPLETE"}, + {1033, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_SUSPEND_DISPATCH"}, + {1034, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_SUSPEND_COMPLETE"}, + {1035, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_DISPATCH"}, + {1036, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE"}, + {1037, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE_ERROR_1"}, + {1038, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE_ERROR_2"}, + {1039, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE_ERROR_3"}, + {1040, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE_ERROR_4"}, + {1041, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE_ERROR_5"}, + {1042, "USBPORT_ETW_EVENT_HC_EHCI_MINIPORT_RESUME_COMPLETE_ERROR_6"}, + {2048, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_DISPATCH"}, + {2049, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_COMPLETE"}, + {2050, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_COMPLETE_ERROR_1"}, + {2051, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_COMPLETE_ERROR_2"}, + {2052, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_COMPLETE_ERROR_3"}, + {2053, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_COMPLETE_ERROR_4"}, + {2054, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_START_COMPLETE_ERROR_5"}, + {2055, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_STOP_DISPATCH"}, + {2056, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_STOP_COMPLETE"}, + {2057, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_SUSPEND_DISPATCH"}, + {2058, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_SUSPEND_COMPLETE"}, + {2059, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_DISPATCH"}, + {2060, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_COMPLETE"}, + {2061, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_COMPLETE_ERROR_1"}, + {2062, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_COMPLETE_ERROR_2"}, + {2063, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_COMPLETE_ERROR_3"}, + {2064, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_COMPLETE_ERROR_4"}, + {2065, "USBPORT_ETW_EVENT_HC_OHCI_MINIPORT_RESUME_COMPLETE_ERROR_5"}, + {3072, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_START_DISPATCH"}, + {3073, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_START_COMPLETE"}, + {3074, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_START_COMPLETE_ERROR_1"}, + {3075, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_START_COMPLETE_ERROR_2"}, + {3076, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_START_COMPLETE_ERROR_3"}, + {3077, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_START_COMPLETE_ERROR_4"}, + {3078, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_STOP_DISPATCH"}, + {3079, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_STOP_COMPLETE"}, + {3080, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_SUSPEND_DISPATCH"}, + {3081, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_SUSPEND_COMPLETE"}, + {3082, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_DISPATCH"}, + {3083, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_COMPLETE"}, + {3084, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_COMPLETE_ERROR_1"}, + {3085, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_COMPLETE_ERROR_2"}, + {3086, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_COMPLETE_ERROR_3"}, + {3087, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_COMPLETE_ERROR_4"}, + {3088, "USBPORT_ETW_EVENT_HC_UHCI_MINIPORT_RESUME_COMPLETE_ERROR_5"}, + {3089, "USBPORT_ETW_EVENT_RTPM_TRANSITION"}, + {3090, "USBPORT_ETW_EVENT_DISPATCH_WAIT_WAKE"}, + {3091, "USBPORT_ETW_EVENT_COMPLETE_WAIT_WAKE"}, + {0, NULL} +}; +static value_string_ext netmon_event_id_vals_ext = VALUE_STRING_EXT_INIT(netmon_event_id_vals); + +static const value_string netmon_urb_function_vals[] = { + {0x0000, "SELECT_CONFIGURATION"}, + {0x0001, "SELECT_INTERFACE"}, + {0x0002, "ABORT_PIPE"}, + {0x0003, "TAKE_FRAME_LENGTH_CONTROL"}, + {0x0004, "RELEASE_FRAME_LENGTH_CONTROL"}, + {0x0005, "GET_FRAME_LENGTH"}, + {0x0006, "SET_FRAME_LENGTH"}, + {0x0007, "GET_CURRENT_FRAME_NUMBER"}, + {0x0008, "CONTROL_TRANSFER"}, + {0x0009, "BULK_OR_INTERRUPT_TRANSFER"}, + {0x000A, "ISOCH_TRANSFER"}, + {0x000B, "GET_DESCRIPTOR_FROM_DEVICE"}, + {0x000C, "SET_DESCRIPTOR_TO_DEVICE"}, + {0x000D, "SET_FEATURE_TO_DEVICE"}, + {0x000E, "SET_FEATURE_TO_INTERFACE"}, + {0x000F, "SET_FEATURE_TO_ENDPOINT"}, + {0x0010, "CLEAR_FEATURE_TO_DEVICE"}, + {0x0011, "CLEAR_FEATURE_TO_INTERFACE"}, + {0x0012, "CLEAR_FEATURE_TO_ENDPOINT"}, + {0x0013, "GET_STATUS_FROM_DEVICE"}, + {0x0014, "GET_STATUS_FROM_INTERFACE"}, + {0x0015, "GET_STATUS_FROM_ENDPOINT"}, + {0x0016, "RESERVED"}, + {0x0017, "VENDOR_DEVICE"}, + {0x0018, "VENDOR_INTERFACE"}, + {0x0019, "VENDOR_ENDPOINT"}, + {0x001A, "CLASS_DEVICE"}, + {0x001B, "CLASS_INTERFACE"}, + {0x001C, "CLASS_ENDPOINT"}, + {0x001D, "RESERVE_0X001D"}, + {0x001E, "SYNC_RESET_PIPE_AND_CLEAR_STALL"}, + {0x001F, "CLASS_OTHER"}, + {0x0020, "VENDOR_OTHER"}, + {0x0021, "GET_STATUS_FROM_OTHER"}, + {0x0022, "CLEAR_FEATURE_TO_OTHER"}, + {0x0023, "SET_FEATURE_TO_OTHER"}, + {0x0024, "GET_DESCRIPTOR_FROM_ENDPOINT"}, + {0x0025, "SET_DESCRIPTOR_TO_ENDPOINT"}, + {0x0026, "GET_CONFIGURATION"}, + {0x0027, "GET_INTERFACE"}, + {0x0028, "GET_DESCRIPTOR_FROM_INTERFACE"}, + {0x0029, "SET_DESCRIPTOR_TO_INTERFACE"}, + {0x002A, "GET_MS_FEATURE_DESCRIPTOR"}, + {0x0030, "SYNC_RESET_PIPE"}, + {0x0031, "SYNC_CLEAR_STALL"}, + {0x0032, "CONTROL_TRANSFER_EX"}, + {0x0035, "OPEN_STATIC_STREAMS"}, + {0x0036, "CLOSE_STATIC_STREAMS"}, + {0x0037, "BULK_OR_INTERRUPT_TRANSFER_USING_CHAINED_MDL"}, + {0x0038, "ISOCH_TRANSFER_USING_CHAINED_MDL"}, + {0, NULL} +}; +static value_string_ext netmon_urb_function_vals_ext = VALUE_STRING_EXT_INIT(netmon_urb_function_vals); + + +void proto_register_usb(void); +void proto_reg_handoff_usb(void); + +/* USB address handling */ +static int usb_addr_to_str(const address* addr, gchar *buf, int buf_len _U_) +{ + const guint8 *addrp = (const guint8 *)addr->data; + + if(pletoh32(&addrp[0])==0xffffffff){ + (void) g_strlcpy(buf, "host", buf_len); + } else { + snprintf(buf, buf_len, "%d.%d.%d", pletoh16(&addrp[8]), + pletoh32(&addrp[0]), pletoh32(&addrp[4])); + } + + return (int)(strlen(buf)+1); +} + +static int usb_addr_str_len(const address* addr _U_) +{ + return 50; +} + + +/* This keys provide information for DecodeBy and other dissector via + per packet data: p_get_proto_data()/p_add_proto_data() */ +#define USB_BUS_ID 0 +#define USB_DEVICE_ADDRESS 1 +#define USB_VENDOR_ID 2 +#define USB_PRODUCT_ID 3 +#define USB_DEVICE_CLASS 4 +#define USB_DEVICE_SUBCLASS 5 +#define USB_DEVICE_PROTOCOL 6 + +static void +usb_device_prompt(packet_info *pinfo, gchar* result) +{ + snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Bus ID %u \nDevice Address %u\nas ", + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_BUS_ID)), + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_ADDRESS))); +} + +static gpointer +usb_device_value(packet_info *pinfo) +{ + guint32 value = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_BUS_ID)) << 16; + value |= GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_ADDRESS)); + return GUINT_TO_POINTER(value); +} + +static void +usb_product_prompt(packet_info *pinfo, gchar* result) +{ + snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Vendor ID 0x%04x \nProduct ID 0x%04x\nas ", + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_VENDOR_ID)), + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_PRODUCT_ID))); +} + +static gpointer +usb_product_value(packet_info *pinfo) +{ + guint32 value = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_VENDOR_ID)) << 16; + value |= GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_PRODUCT_ID)); + return GUINT_TO_POINTER(value); +} + +static void +usb_protocol_prompt(packet_info *pinfo, gchar* result) +{ + snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Class ID 0x%04x \nSubclass ID 0x%04x\nProtocol 0x%04x\nas ", + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_CLASS)), + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_SUBCLASS)), + GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_PROTOCOL))); +} + +static gpointer +usb_protocol_value(packet_info *pinfo) +{ + guint32 value = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_CLASS)) << 16; + value |= GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_SUBCLASS)) << 8; + value |= GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_PROTOCOL)); + return GUINT_TO_POINTER(value); +} + +static build_valid_func usb_product_da_build_value[1] = {usb_product_value}; +static decode_as_value_t usb_product_da_values = {usb_product_prompt, 1, usb_product_da_build_value}; +static decode_as_t usb_product_da = { + "usb", "usb.product", + 1, 0, &usb_product_da_values, NULL, NULL, + decode_as_default_populate_list, decode_as_default_reset, + decode_as_default_change, NULL}; + +static build_valid_func usb_device_da_build_value[1] = {usb_device_value}; +static decode_as_value_t usb_device_da_values = {usb_device_prompt, 1, usb_device_da_build_value}; +static decode_as_t usb_device_da = { + "usb", "usb.device", + 1, 0, &usb_device_da_values, NULL, NULL, + decode_as_default_populate_list, decode_as_default_reset, + decode_as_default_change, NULL}; + +static build_valid_func usb_protocol_da_build_value[1] = {usb_protocol_value}; +static decode_as_value_t usb_protocol_da_values = {usb_protocol_prompt, 1, usb_protocol_da_build_value}; +static decode_as_t usb_protocol_da = { + "usb", "usb.protocol", + 1, 0, &usb_protocol_da_values, NULL, NULL, + decode_as_default_populate_list, decode_as_default_reset, + decode_as_default_change, NULL}; + + +static usb_conv_info_t * +get_usb_conv_info(conversation_t *conversation) +{ + usb_conv_info_t *usb_conv_info; + + /* do we have conversation specific data ? */ + usb_conv_info = (usb_conv_info_t *)conversation_get_proto_data(conversation, proto_usb); + if (!usb_conv_info) { + /* no not yet so create some */ + usb_conv_info = wmem_new0(wmem_file_scope(), usb_conv_info_t); + usb_conv_info->interfaceClass = IF_CLASS_UNKNOWN; + usb_conv_info->interfaceSubclass = IF_SUBCLASS_UNKNOWN; + usb_conv_info->interfaceProtocol = IF_PROTOCOL_UNKNOWN; + usb_conv_info->deviceVendor = DEV_VENDOR_UNKNOWN; + usb_conv_info->deviceProduct = DEV_PRODUCT_UNKNOWN; + usb_conv_info->deviceVersion = DEV_VERSION_UNKNOWN; + usb_conv_info->alt_settings = wmem_array_new(wmem_file_scope(), sizeof(usb_alt_setting_t)); + usb_conv_info->transactions = wmem_tree_new(wmem_file_scope()); + usb_conv_info->descriptor_transfer_type = URB_UNKNOWN; + usb_conv_info->max_packet_size = 0; + + conversation_add_proto_data(conversation, proto_usb, usb_conv_info); + } + + return usb_conv_info; +} + + +/* usb_conv_info_t contains some components that are valid only for one specific packet + clear_usb_conv_tmp_data() clears these components, it should be called + before we dissect a new packet */ +static void clear_usb_conv_tmp_data(usb_conv_info_t *usb_conv_info) +{ + /* caller must have checked that usb_conv_info!= NULL */ + + usb_conv_info->direction = P2P_DIR_UNKNOWN; + usb_conv_info->transfer_type = URB_UNKNOWN; + usb_conv_info->is_request = FALSE; + usb_conv_info->is_setup = FALSE; + usb_conv_info->setup_requesttype = 0; + usb_conv_info->speed = USB_SPEED_UNKNOWN; + + /* when we parse the configuration, interface and endpoint + descriptors, we store the current interface class in endpoint 0's + conversation + + this must be cleared since endpoint 0 does not belong to any + interface class + + we used to clear these info in dissect_usb_configuration_descriptor() + this doesn't work when the descriptor parsing throws an exception */ + + if (usb_conv_info->endpoint==0) { + usb_conv_info->interfaceClass = IF_CLASS_UNKNOWN; + usb_conv_info->interfaceSubclass = IF_SUBCLASS_UNKNOWN; + usb_conv_info->interfaceProtocol = IF_PROTOCOL_UNKNOWN; + } +} + +static conversation_t * +get_usb_conversation(packet_info *pinfo, + address *src_addr, address *dst_addr, + guint32 src_endpoint, guint32 dst_endpoint) +{ + conversation_t *conversation; + + /* + * Do we have a conversation for this connection? + */ + conversation = find_conversation(pinfo->num, + src_addr, dst_addr, + conversation_pt_to_conversation_type(pinfo->ptype), + src_endpoint, dst_endpoint, 0); + if (conversation) { + return conversation; + } + + /* We don't yet have a conversation, so create one. */ + conversation = conversation_new(pinfo->num, + src_addr, dst_addr, + conversation_pt_to_conversation_type(pinfo->ptype), + src_endpoint, dst_endpoint, 0); + return conversation; +} + +/* Fetch or create usb_conv_info for a specified interface. */ +usb_conv_info_t * +get_usb_iface_conv_info(packet_info *pinfo, guint8 interface_num) +{ + conversation_t *conversation; + guint32 if_port; + + if_port = GUINT32_TO_LE(INTERFACE_PORT | interface_num); + + if (pinfo->srcport == NO_ENDPOINT) { + conversation = get_usb_conversation(pinfo, &pinfo->src, &pinfo->dst, pinfo->srcport, if_port); + } else { + conversation = get_usb_conversation(pinfo, &pinfo->src, &pinfo->dst, if_port, pinfo->destport); + } + + return get_usb_conv_info(conversation); +} + +/* Fetch usb_conv_info for specified endpoint, return NULL if not found */ +usb_conv_info_t * +get_existing_usb_ep_conv_info(packet_info* pinfo, guint16 bus_id, guint16 device_address, int endpoint) +{ + usb_address_t *src_addr = wmem_new0(pinfo->pool, usb_address_t), + *dst_addr = wmem_new0(pinfo->pool, usb_address_t); + address src, dst; + conversation_t *conversation; + usb_conv_info_t *usb_conv_info = NULL; + + src_addr->bus_id = GUINT16_TO_LE(bus_id); + src_addr->device = GUINT16_TO_LE(device_address); + src_addr->endpoint = GUINT32_TO_LE(endpoint); + + dst_addr->bus_id = GUINT16_TO_LE(bus_id); + dst_addr->device = 0xffffffff; + dst_addr->endpoint = NO_ENDPOINT; + + set_address(&src, usb_address_type, USB_ADDR_LEN, (char *)src_addr); + set_address(&dst, usb_address_type, USB_ADDR_LEN, (char *)dst_addr); + + conversation = find_conversation(pinfo->num, &src, &dst, + conversation_pt_to_conversation_type(PT_USB), + src_addr->endpoint, dst_addr->endpoint, 0); + if (conversation) { + usb_conv_info = (usb_conv_info_t *)conversation_get_proto_data(conversation, proto_usb); + } + return usb_conv_info; +} + +static const char* usb_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == usb_address_type)) + return "usb.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == usb_address_type)) + return "usb.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == usb_address_type)) + return "usb.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t usb_ct_dissector_info = {&usb_conv_get_filter_type}; + +static tap_packet_status +usb_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip _U_, tap_flags_t flags) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + hash->flags = flags; + + add_conversation_table_data(hash, &pinfo->src, &pinfo->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &usb_ct_dissector_info, CONVERSATION_NONE); + + return TAP_PACKET_REDRAW; +} + +static const char* usb_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_ANY_ADDRESS) && (endpoint->myaddress.type == usb_address_type)) + return "usb.addr"; + + return CONV_FILTER_INVALID; +} + +static const char* +usb_col_filter_str(const address* addr _U_, gboolean is_src) +{ + return is_src ? "usb.src" : "usb.dst"; +} + +static et_dissector_info_t usb_endpoint_dissector_info = {&usb_endpoint_get_filter_type}; + +static tap_packet_status +usb_endpoint_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip _U_, tap_flags_t flags) +{ + conv_hash_t *hash = (conv_hash_t*) pit; + hash->flags = flags; + + /* Take two "add" passes per packet, adding for each direction, ensures that all + packets are counted properly (even if address is sending to itself) + XXX - this could probably be done more efficiently inside endpoint_table */ + add_endpoint_table_data(hash, &pinfo->src, 0, TRUE, 1, pinfo->fd->pkt_len, &usb_endpoint_dissector_info, ENDPOINT_NONE); + add_endpoint_table_data(hash, &pinfo->dst, 0, FALSE, 1, pinfo->fd->pkt_len, &usb_endpoint_dissector_info, ENDPOINT_NONE); + + return TAP_PACKET_REDRAW; +} + +/* SETUP dissectors */ + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / CLEAR FEATURE + */ + + +/* 9.4.1 */ +static int +dissect_usb_setup_clear_feature_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + guint8 recip; + + if (usb_conv_info) { + recip = USB_RECIPIENT(usb_conv_info->usb_trans_info->setup.requesttype); + + /* feature selector, zero/interface/endpoint */ + switch (recip) { + case RQT_SETUP_RECIPIENT_DEVICE: + proto_tree_add_item(tree, hf_usb_device_wFeatureSelector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_INTERFACE: + proto_tree_add_item(tree, hf_usb_interface_wFeatureSelector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_wInterface, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_ENDPOINT: + proto_tree_add_item(tree, hf_usb_endpoint_wFeatureSelector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_wEndpoint, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_OTHER: + default: + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + } + } else { + /* No conversation information, so recipient type is unknown */ + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + offset += 2; + + /* length */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_clear_feature_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / GET CONFIGURATION + */ + + +/* 9.4.2 */ +static int +dissect_usb_setup_get_configuration_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + proto_tree_add_item(tree, hf_usb_bConfigurationValue, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / GET DESCRIPTOR + */ + +proto_item * dissect_usb_descriptor_header(proto_tree *tree, + tvbuff_t *tvb, int offset, + value_string_ext *type_val_str) +{ + guint8 desc_type; + proto_item *length_item; + + + length_item = proto_tree_add_item(tree, hf_usb_bLength, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + desc_type = tvb_get_guint8(tvb, offset); + /* if the caller provided no class specific value string, we're + * using the standard descriptor types */ + if (!type_val_str) + type_val_str = &std_descriptor_type_vals_ext; + + proto_tree_add_uint_format_value(tree, hf_usb_bDescriptorType, + tvb, offset, 1, desc_type, "0x%02x (%s)", desc_type, + val_to_str_ext_const(desc_type, type_val_str, "unknown")); + + return length_item; +} + +static void +dissect_max_packet_size0(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info, gboolean other_speed) +{ + proto_item *item; + guint32 max_packet_size; + unsigned int sanitized_max_packet_size; + usb_speed_t speed = usb_conv_info->speed; + + item = proto_tree_add_item_ret_uint(tree, hf_usb_bMaxPacketSize0, tvb, offset, 1, ENC_LITTLE_ENDIAN, &max_packet_size); + if (other_speed) { + if (speed == USB_SPEED_FULL) + speed = USB_SPEED_HIGH; + else if (speed == USB_SPEED_HIGH) + speed = USB_SPEED_FULL; + } + sanitized_max_packet_size = sanitize_usb_max_packet_size(ENDPOINT_TYPE_CONTROL, speed, max_packet_size); + if (sanitized_max_packet_size != max_packet_size) { + expert_add_info_format(pinfo, item, &ei_usb_invalid_max_packet_size0, + "%s endpoint zero max packet size cannot be %u, using %d instead.", + try_val_to_str(speed, usb_speed_vals), max_packet_size, sanitized_max_packet_size); + } +} + +/* 9.6.2 */ +static int +dissect_usb_device_qualifier_descriptor(packet_info *pinfo, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + proto_item *item; + proto_tree *tree; + proto_item *nitem; + int old_offset = offset; + guint32 protocol; + const gchar *description; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "DEVICE QUALIFIER DESCRIPTOR"); + + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* bcdUSB */ + proto_tree_add_item(tree, hf_usb_bcdUSB, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + protocol = tvb_get_ntoh24(tvb, offset); + description = val_to_str_ext_const(protocol, &usb_protocols_ext, ""); + + /* bDeviceClass */ + proto_tree_add_item(tree, hf_usb_bDeviceClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bDeviceSubClass */ + proto_tree_add_item(tree, hf_usb_bDeviceSubClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bDeviceProtocol */ + nitem = proto_tree_add_item(tree, hf_usb_bDeviceProtocol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + if (*description) + proto_item_append_text(nitem, " (%s)", description); + offset += 1; + + if (!pinfo->fd->visited) { + guint k_bus_id; + guint k_device_address; + guint k_frame_number; + wmem_tree_key_t key[4]; + device_protocol_data_t *device_protocol_data; + + k_frame_number = pinfo->num; + k_device_address = usb_conv_info->device_address; + k_bus_id = usb_conv_info->bus_id; + + key[0].length = 1; + key[0].key = &k_device_address; + key[1].length = 1; + key[1].key = &k_bus_id; + key[2].length = 1; + key[2].key = &k_frame_number; + key[3].length = 0; + key[3].key = NULL; + + device_protocol_data = wmem_new(wmem_file_scope(), device_protocol_data_t); + device_protocol_data->protocol = protocol; + device_protocol_data->bus_id = usb_conv_info->bus_id; + device_protocol_data->device_address = usb_conv_info->device_address; + wmem_tree_insert32_array(device_to_protocol_table, key, device_protocol_data); + } + + /* bMaxPacketSize0 */ + dissect_max_packet_size0(pinfo, tree, tvb, offset, usb_conv_info, TRUE); + offset += 1; + + /* bNumConfigurations */ + proto_tree_add_item(tree, hf_usb_bNumConfigurations, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* one reserved byte */ + offset += 1; + + proto_item_set_len(item, offset-old_offset); + + return offset; +} + +/* 9.6.1 */ +static int +dissect_usb_device_descriptor(packet_info *pinfo, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + proto_item *item; + proto_tree *tree; + proto_item *nitem; + int old_offset = offset; + guint32 protocol; + const gchar *description; + guint32 vendor_id; + guint32 product; + guint16 product_id; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "DEVICE DESCRIPTOR"); + + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* bcdUSB */ + proto_tree_add_item(tree, hf_usb_bcdUSB, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + protocol = tvb_get_ntoh24(tvb, offset); + description = val_to_str_ext_const(protocol, &usb_protocols_ext, ""); + + /* bDeviceClass */ + proto_tree_add_item(tree, hf_usb_bDeviceClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bDeviceSubClass */ + proto_tree_add_item(tree, hf_usb_bDeviceSubClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bDeviceProtocol */ + nitem = proto_tree_add_item(tree, hf_usb_bDeviceProtocol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + if (*description) + proto_item_append_text(nitem, " (%s)", description); + offset += 1; + + /* bMaxPacketSize0 */ + dissect_max_packet_size0(pinfo, tree, tvb, offset, usb_conv_info, FALSE); + offset += 1; + + /* if request was only for the first 8 bytes */ + /* per 5.5.3 of USB2.0 Spec */ + if (8 == usb_conv_info->usb_trans_info->setup.wLength) { + proto_item_set_len(item, offset-old_offset); + return offset; + } + + /* idVendor */ + proto_tree_add_item_ret_uint(tree, hf_usb_idVendor, tvb, offset, 2, ENC_LITTLE_ENDIAN, &vendor_id); + usb_conv_info->deviceVendor = (guint16)vendor_id; + offset += 2; + + /* idProduct */ + product_id = tvb_get_letohs(tvb, offset); + usb_conv_info->deviceProduct = product_id; + product = (guint16)vendor_id << 16 | product_id; + + proto_tree_add_uint_format_value(tree, hf_usb_idProduct, tvb, offset, 2, product_id, "%s (0x%04x)", + val_to_str_ext_const(product, &ext_usb_products_vals, "Unknown"), + product_id); + offset += 2; + + /* bcdDevice */ + usb_conv_info->deviceVersion = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_usb_bcdDevice, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + if (!pinfo->fd->visited) { + guint k_bus_id; + guint k_device_address; + guint k_frame_number; + wmem_tree_key_t key[4]; + device_product_data_t *device_product_data; + device_protocol_data_t *device_protocol_data; + + k_frame_number = pinfo->num; + k_device_address = usb_conv_info->device_address; + k_bus_id = usb_conv_info->bus_id; + + key[0].length = 1; + key[0].key = &k_device_address; + key[1].length = 1; + key[1].key = &k_bus_id; + key[2].length = 1; + key[2].key = &k_frame_number; + key[3].length = 0; + key[3].key = NULL; + + device_product_data = wmem_new(wmem_file_scope(), device_product_data_t); + device_product_data->vendor = vendor_id; + device_product_data->product = product_id; + device_product_data->device = usb_conv_info->deviceVersion; + device_product_data->bus_id = usb_conv_info->bus_id; + device_product_data->device_address = usb_conv_info->device_address; + wmem_tree_insert32_array(device_to_product_table, key, device_product_data); + + device_protocol_data = wmem_new(wmem_file_scope(), device_protocol_data_t); + device_protocol_data->protocol = protocol; + device_protocol_data->bus_id = usb_conv_info->bus_id; + device_protocol_data->device_address = usb_conv_info->device_address; + + wmem_tree_insert32_array(device_to_protocol_table, key, device_protocol_data); + } + + /* iManufacturer */ + proto_tree_add_item(tree, hf_usb_iManufacturer, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* iProduct */ + proto_tree_add_item(tree, hf_usb_iProduct, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* iSerialNumber */ + usb_conv_info->iSerialNumber = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_usb_iSerialNumber, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bNumConfigurations */ + proto_tree_add_item(tree, hf_usb_bNumConfigurations, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_item_set_len(item, offset-old_offset); + + return offset; +} + +/* 9.6.7 */ +static int +dissect_usb_string_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + proto_item *item; + proto_tree *tree; + int old_offset = offset; + guint8 len; + proto_item *len_item; + usb_trans_info_t *usb_trans_info; + + usb_trans_info = usb_conv_info->usb_trans_info; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "STRING DESCRIPTOR"); + + len = tvb_get_guint8(tvb, offset); + /* The USB spec says that the languages / the string are UTF16 and not + 0-terminated, i.e. the length field must contain an even number */ + if (len & 0x1) { + /* bLength */ + len_item = proto_tree_add_item(tree, hf_usb_bLength, tvb, offset, 1, ENC_LITTLE_ENDIAN); + expert_add_info(pinfo, len_item, &ei_usb_bLength_even); + + /* bDescriptorType */ + proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); + } + else + len_item = dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* Report an error, and give up, if the length is < 2 */ + if (len < 2) { + expert_add_info(pinfo, len_item, &ei_usb_bLength_too_short); + return offset; + } + + if (!usb_trans_info->u.get_descriptor.usb_index) { + /* list of languanges */ + while (offset >= old_offset && len > (offset - old_offset)) { + /* wLANGID */ + proto_tree_add_item(tree, hf_usb_wLANGID, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset+=2; + } + } else { + /* UTF-16 string */ + /* handle case of host requesting only substring */ + guint8 len_str = MIN(len-2, usb_trans_info->setup.wLength -2); + proto_tree_add_item(tree, hf_usb_bString, tvb, offset, len_str, ENC_UTF_16 | ENC_LITTLE_ENDIAN); + offset += len_str; + } + + proto_item_set_len(item, offset-old_offset); + + return offset; +} + + + +/* 9.6.5 */ +static int +dissect_usb_interface_descriptor(packet_info *pinfo, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + proto_item *item; + proto_tree *tree; + const char *class_str = NULL; + int old_offset = offset; + guint8 len; + guint8 interface_num; + guint8 alt_setting; + usb_trans_info_t *usb_trans_info; + + usb_trans_info = usb_conv_info->usb_trans_info; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "INTERFACE DESCRIPTOR"); + + len = tvb_get_guint8(tvb, offset); + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* bInterfaceNumber */ + interface_num = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_usb_bInterfaceNumber, tvb, offset, 1, ENC_LITTLE_ENDIAN); + usb_conv_info->interfaceNum = interface_num; + offset += 1; + + /* bAlternateSetting */ + alt_setting = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_usb_bAlternateSetting, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bNumEndpoints */ + proto_tree_add_item(tree, hf_usb_bNumEndpoints, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bInterfaceClass */ + proto_tree_add_item(tree, hf_usb_bInterfaceClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + /* save the class so we can access it later in the endpoint descriptor */ + usb_conv_info->interfaceClass = tvb_get_guint8(tvb, offset); + + class_str = val_to_str_ext(usb_conv_info->interfaceClass, &usb_class_vals_ext, "unknown (0x%X)"); + proto_item_append_text(item, " (%u.%u): class %s", interface_num, alt_setting, class_str); + + if (!pinfo->fd->visited) { + usb_alt_setting_t alternate_setting; + + /* Register conversation for this interface in case CONTROL messages are sent to it */ + usb_trans_info->interface_info = get_usb_iface_conv_info(pinfo, interface_num); + usb_trans_info->interface_info->bus_id = usb_conv_info->bus_id; + usb_trans_info->interface_info->device_address = usb_conv_info->device_address; + + alternate_setting.altSetting = alt_setting; + alternate_setting.interfaceClass = tvb_get_guint8(tvb, offset); + alternate_setting.interfaceSubclass = tvb_get_guint8(tvb, offset+1); + alternate_setting.interfaceProtocol = tvb_get_guint8(tvb, offset+2); + alternate_setting.interfaceNum = interface_num; + wmem_array_append_one(usb_trans_info->interface_info->alt_settings, alternate_setting); + + if (alt_setting == 0) { + /* By default let's assume alternate setting 0 will be used */ + + /* in interface conversations, endpoint has no meaning */ + usb_trans_info->interface_info->endpoint = NO_ENDPOINT8; + + usb_trans_info->interface_info->interfaceClass = alternate_setting.interfaceClass; + usb_trans_info->interface_info->interfaceSubclass = alternate_setting.interfaceSubclass; + usb_trans_info->interface_info->interfaceProtocol = alternate_setting.interfaceProtocol; + usb_trans_info->interface_info->interfaceNum = alternate_setting.interfaceNum; + usb_trans_info->interface_info->deviceVendor = usb_conv_info->deviceVendor; + usb_trans_info->interface_info->deviceProduct = usb_conv_info->deviceProduct; + usb_trans_info->interface_info->deviceVersion = usb_conv_info->deviceVersion; + } + } + offset += 1; + + /* bInterfaceSubClass */ + switch (usb_conv_info->interfaceClass) { + case IF_CLASS_AUDIO: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass_audio, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_COMMUNICATIONS: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass_cdc, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_MASS_STORAGE: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass_massstorage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_HID: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass_hid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_MISCELLANEOUS: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass_misc, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_APPLICATION_SPECIFIC: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass_app, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + default: + proto_tree_add_item(tree, hf_usb_bInterfaceSubClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + + /* save the subclass so we can access it later in class-specific descriptors */ + usb_conv_info->interfaceSubclass = tvb_get_guint8(tvb, offset); + offset += 1; + + /* bInterfaceProtocol */ + switch (usb_conv_info->interfaceClass) { + case IF_CLASS_COMMUNICATIONS: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_cdc, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_MASS_STORAGE: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_massstorage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_CDC_DATA: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_cdc_data, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case IF_CLASS_APPLICATION_SPECIFIC: + switch (usb_conv_info->interfaceSubclass) { + case 0x01: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_app_dfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case 0x02: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_app_irda, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case 0x03: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_app_usb_test_and_measurement, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + default: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + break; + case IF_CLASS_HID: + if (usb_conv_info->interfaceSubclass == 1) { + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol_hid_boot, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + } + + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + + break; + default: + proto_tree_add_item(tree, hf_usb_bInterfaceProtocol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + + usb_conv_info->interfaceProtocol = tvb_get_guint8(tvb, offset); + offset += 1; + + /* iInterface */ + proto_tree_add_item(tree, hf_usb_iInterface, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_item_set_len(item, len); + + if (offset < old_offset+len) { + /* skip unknown records */ + offset = old_offset + len; + } + + return offset; +} + +/* 9.6.6 */ +const true_false_string tfs_endpoint_direction = { + "IN Endpoint", + "OUT Endpoint" +}; + +void dissect_usb_endpoint_address(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_item *endpoint_item; + proto_tree *endpoint_tree; + guint8 endpoint; + + endpoint_item = proto_tree_add_item(tree, hf_usb_bEndpointAddress, tvb, offset, 1, ENC_LITTLE_ENDIAN); + endpoint_tree = proto_item_add_subtree(endpoint_item, ett_configuration_bEndpointAddress); + + endpoint = tvb_get_guint8(tvb, offset)&0x0f; + proto_tree_add_item(endpoint_tree, hf_usb_bEndpointAddress_direction, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(endpoint_item, " %s", (tvb_get_guint8(tvb, offset)&0x80)?"IN":"OUT"); + proto_tree_add_item(endpoint_tree, hf_usb_bEndpointAddress_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(endpoint_item, " Endpoint:%d", endpoint); +} + +unsigned int +sanitize_usb_max_packet_size(guint8 ep_type, usb_speed_t speed, + unsigned int max_packet_size) +{ + unsigned int sanitized = max_packet_size; + switch (speed) { + case USB_SPEED_LOW: + switch (ep_type) { + case ENDPOINT_TYPE_CONTROL: + /* 8 is the only allowed value */ + sanitized = 8; + break; + case ENDPOINT_TYPE_INTERRUPT: + if (max_packet_size > 8) + sanitized = 8; + break; + default: + /* Not allowed */ + break; + } + break; + case USB_SPEED_FULL: + switch (ep_type) { + case ENDPOINT_TYPE_CONTROL: + case ENDPOINT_TYPE_BULK: + /* Allowed values are: 8, 16, 32 and 64 */ + if (max_packet_size > 32) + sanitized = 64; + else if (max_packet_size > 16) + sanitized = 32; + else if (max_packet_size > 8) + sanitized = 16; + else + sanitized = 8; + break; + case ENDPOINT_TYPE_INTERRUPT: + if (max_packet_size > 64) + sanitized = 64; + break; + case ENDPOINT_TYPE_ISOCHRONOUS: + if (max_packet_size > 1023) + sanitized = 1023; + break; + default: + break; + } + break; + case USB_SPEED_HIGH: + switch (ep_type) { + case ENDPOINT_TYPE_CONTROL: + /* 64 is the only allowed value */ + sanitized = 64; + break; + case ENDPOINT_TYPE_BULK: + /* 512 is the only allowed value */ + sanitized = 512; + break; + case ENDPOINT_TYPE_INTERRUPT: + case ENDPOINT_TYPE_ISOCHRONOUS: + if (max_packet_size > 1024) + sanitized = 1024; + break; + default: + break; + } + break; + case USB_SPEED_UNKNOWN: + default: + break; + } + + return sanitized; +} + +int +dissect_usb_endpoint_descriptor(packet_info *pinfo, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info, + guint8 *out_ep_type, usb_speed_t speed) +{ + proto_item *item; + proto_tree *tree; + proto_item *ep_attrib_item; + proto_tree *ep_attrib_tree; + proto_item *ep_type_item; + proto_item *ep_pktsize_item; + proto_tree *ep_pktsize_tree; + int old_offset = offset; + guint8 endpoint; + guint8 ep_type; + guint8 len; + guint32 max_packet_size; + unsigned int sanitized_max_packet_size; + usb_trans_info_t *usb_trans_info = NULL; + conversation_t *conversation = NULL; + + if (usb_conv_info) + usb_trans_info = usb_conv_info->usb_trans_info; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "ENDPOINT DESCRIPTOR"); + + len = tvb_get_guint8(tvb, offset); + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + endpoint = tvb_get_guint8(tvb, offset)&0x0f; + dissect_usb_endpoint_address(tree, tvb, offset); + offset += 1; + + /* Together with class from the interface descriptor we know what kind + * of class the device at endpoint is. + * Make sure a conversation exists for this endpoint and attach a + * usb_conv_into_t structure to it. + * + * All endpoints for the same interface descriptor share the same + * usb_conv_info structure. + */ + if ((!pinfo->fd->visited) && usb_trans_info && usb_trans_info->interface_info) { + if (pinfo->destport == NO_ENDPOINT) { + address tmp_addr; + usb_address_t *usb_addr = wmem_new0(pinfo->pool, usb_address_t); + + /* packet is sent from a USB device's endpoint 0 to the host + * replace endpoint 0 with the endpoint of this descriptor + * and find the corresponding conversation + */ + usb_addr->bus_id = ((const usb_address_t *)(pinfo->src.data))->bus_id; + usb_addr->device = ((const usb_address_t *)(pinfo->src.data))->device; + usb_addr->endpoint = GUINT32_TO_LE(endpoint); + set_address(&tmp_addr, usb_address_type, USB_ADDR_LEN, (char *)usb_addr); + conversation = get_usb_conversation(pinfo, &tmp_addr, &pinfo->dst, usb_addr->endpoint, pinfo->destport); + } + + if (conversation) { + usb_trans_info->interface_info->endpoint = endpoint; + conversation_add_proto_data(conversation, proto_usb, usb_trans_info->interface_info); + } + } + + /* bmAttributes */ + ep_type = ENDPOINT_TYPE(tvb_get_guint8(tvb, offset)); + if (out_ep_type) { + *out_ep_type = ep_type; + } + + ep_attrib_item = proto_tree_add_item(tree, hf_usb_bmAttributes, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ep_attrib_tree = proto_item_add_subtree(ep_attrib_item, ett_endpoint_bmAttributes); + + ep_type_item = proto_tree_add_item(ep_attrib_tree, hf_usb_bEndpointAttributeTransfer, tvb, offset, 1, ENC_LITTLE_ENDIAN); + if (ep_type==USB_EP_ISOCHRONOUS) { + proto_tree_add_item(ep_attrib_tree, hf_usb_bEndpointAttributeSynchonisation, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ep_attrib_tree, hf_usb_bEndpointAttributeBehaviour, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + + /* At Low-Speed, only control and interrupt transfers are allowed */ + if ((speed == USB_SPEED_LOW) && !((ep_type == USB_EP_CONTROL) || (ep_type == USB_EP_INTERRUPT))) { + expert_add_info(pinfo, ep_type_item, &ei_usb_invalid_endpoint_type); + } + offset += 1; + + /* wMaxPacketSize */ + ep_pktsize_item = proto_tree_add_item(tree, hf_usb_wMaxPacketSize, tvb, offset, 2, ENC_LITTLE_ENDIAN); + ep_pktsize_tree = proto_item_add_subtree(ep_pktsize_item, ett_endpoint_wMaxPacketSize); + if ((ep_type == ENDPOINT_TYPE_INTERRUPT) || (ep_type == ENDPOINT_TYPE_ISOCHRONOUS)) { + proto_tree_add_item(ep_pktsize_tree, hf_usb_wMaxPacketSize_slots, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + proto_tree_add_item_ret_uint(ep_pktsize_tree, hf_usb_wMaxPacketSize_size, tvb, offset, 2, ENC_LITTLE_ENDIAN, &max_packet_size); + sanitized_max_packet_size = sanitize_usb_max_packet_size(ep_type, speed, max_packet_size); + if (sanitized_max_packet_size != max_packet_size) { + expert_add_info_format(pinfo, ep_pktsize_item, &ei_usb_invalid_max_packet_size, + "%s %s endpoint max packet size cannot be %u, using %d instead.", + try_val_to_str(speed, usb_speed_vals), try_val_to_str(ep_type, usb_bmAttributes_transfer_vals), + max_packet_size, sanitized_max_packet_size); + max_packet_size = sanitized_max_packet_size; + } + offset+=2; + + if (conversation) { + usb_conv_info_t* endpoint_conv_info = get_usb_conv_info(conversation); + guint8 transfer_type; + + switch(ep_type) { + case ENDPOINT_TYPE_CONTROL: + transfer_type = URB_CONTROL; + break; + case ENDPOINT_TYPE_ISOCHRONOUS: + transfer_type = URB_ISOCHRONOUS; + break; + case ENDPOINT_TYPE_BULK: + transfer_type = URB_BULK; + break; + case ENDPOINT_TYPE_INTERRUPT: + transfer_type = URB_INTERRUPT; + break; + default: + transfer_type = URB_UNKNOWN; + break; + } + endpoint_conv_info->descriptor_transfer_type = transfer_type; + endpoint_conv_info->max_packet_size = max_packet_size; + } + + /* bInterval */ + proto_tree_add_item(tree, hf_usb_bInterval, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bRefresh and bSynchAddress are present only in the Audio 1.0 + * Endpoint Descriptors, so observe the descriptor size */ + if (usb_conv_info && (usb_conv_info->interfaceClass == IF_CLASS_AUDIO) + && (len >= 9)) { + proto_tree_add_item(tree, hf_usb_audio_bRefresh, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_usb_audio_bSynchAddress, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + } + + proto_item_set_len(item, len); + + if (offset < old_offset+len) { + /* mark unknown records as undecoded */ + proto_tree_add_expert(tree, pinfo, &ei_usb_undecoded, tvb, offset, old_offset + len - offset); + offset = old_offset + len; + } + + return offset; +} + +static int +dissect_usb_endpoint_companion_descriptor(packet_info *pinfo, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_, + guint8 ep_type) +{ + proto_item *item; + proto_tree *tree; + proto_item *ep_attrib_item; + proto_tree *ep_attrib_tree; + int old_offset = offset; + guint8 len; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "SUPERSPEED ENDPOINT COMPANION DESCRIPTOR"); + + len = tvb_get_guint8(tvb, offset); + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* bMaxBurst */ + proto_tree_add_item(tree, hf_usb_bMaxBurst, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bmAttributes */ + ep_attrib_item = proto_tree_add_item(tree, hf_usb_bmAttributes, tvb, offset, 1, ENC_LITTLE_ENDIAN); + switch (ep_type) { + case ENDPOINT_TYPE_CONTROL: + break; + case ENDPOINT_TYPE_ISOCHRONOUS: + ep_attrib_tree = proto_item_add_subtree(ep_attrib_item, ett_endpoint_bmAttributes); + proto_tree_add_item(ep_attrib_tree, hf_usb_bSSEndpointAttributeIsoMult, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case ENDPOINT_TYPE_BULK: + ep_attrib_tree = proto_item_add_subtree(ep_attrib_item, ett_endpoint_bmAttributes); + proto_tree_add_item(ep_attrib_tree, hf_usb_bSSEndpointAttributeBulkMaxStreams, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case ENDPOINT_TYPE_INTERRUPT: + break; + default: + expert_add_info(pinfo, ep_attrib_item, &ei_usb_ss_ep_companion_before_ep); + break; + } + offset += 1; + + /* wBytesPerInterval */ + proto_tree_add_item(tree, hf_usb_wBytesPerInterval, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_item_set_len(item, len); + + if (offset < old_offset + len) { + /* mark unknown records as undecoded */ + proto_tree_add_expert(tree, pinfo, &ei_usb_undecoded, tvb, offset, old_offset + len - offset); + offset = old_offset + len; + } + + return offset; +} + +/* ECN */ +static int +dissect_usb_interface_assn_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + proto_item *item; + proto_tree *tree; + int old_offset = offset; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "INTERFACE ASSOCIATION DESCRIPTOR"); + + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* bFirstInterface */ + proto_tree_add_item(tree, hf_usb_bFirstInterface, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bInterfaceCount */ + proto_tree_add_item(tree, hf_usb_bInterfaceCount, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bFunctionClass */ + proto_tree_add_item(tree, hf_usb_bFunctionClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bFunctionSubclass */ + proto_tree_add_item(tree, hf_usb_bFunctionSubClass, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bFunctionProtocol */ + proto_tree_add_item(tree, hf_usb_bFunctionProtocol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* iFunction */ + proto_tree_add_item(tree, hf_usb_iFunction, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_item_set_len(item, offset-old_offset); + + return offset; +} + +int +dissect_usb_unknown_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + proto_item *item; + proto_tree *tree; + guint8 bLength; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "UNKNOWN DESCRIPTOR"); + + bLength = tvb_get_guint8(tvb, offset); + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += bLength; + + proto_item_set_len(item, bLength); + + return offset; +} + +/* 9.6.3 */ +static const true_false_string tfs_mustbeone = { + "Must be 1 for USB 1.1 and higher", + "FIXME: Is this a USB 1.0 device" +}; +static const true_false_string tfs_selfpowered = { + "This device is SELF-POWERED", + "This device is powered from the USB bus" +}; +static const true_false_string tfs_remotewakeup = { + "This device supports REMOTE WAKEUP", + "This device does NOT support remote wakeup" +}; +static int +dissect_usb_configuration_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info, usb_speed_t speed) +{ + proto_item *item; + proto_tree *tree; + int old_offset = offset; + guint16 len; + proto_item *flags_item; + proto_tree *flags_tree; + guint8 flags; + guint8 last_ep_type = ENDPOINT_TYPE_NOT_SET; + proto_item *power_item; + guint8 power; + gboolean truncation_expected; + usb_trans_info_t *usb_trans_info; + + usb_trans_info = usb_conv_info->usb_trans_info; + + usb_conv_info->interfaceClass = IF_CLASS_UNKNOWN; + usb_conv_info->interfaceSubclass = IF_SUBCLASS_UNKNOWN; + usb_conv_info->interfaceProtocol = IF_PROTOCOL_UNKNOWN; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "CONFIGURATION DESCRIPTOR"); + + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* wTotalLength */ + proto_tree_add_item(tree, hf_usb_wTotalLength, tvb, offset, 2, ENC_LITTLE_ENDIAN); + len = tvb_get_letohs(tvb, offset); + offset+=2; + + /* bNumInterfaces */ + proto_tree_add_item(tree, hf_usb_bNumInterfaces, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bConfigurationValue */ + proto_tree_add_item(tree, hf_usb_bConfigurationValue, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* iConfiguration */ + proto_tree_add_item(tree, hf_usb_iConfiguration, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* bmAttributes */ + flags_item = proto_tree_add_item(tree, hf_usb_configuration_bmAttributes, tvb, offset, 1, ENC_LITTLE_ENDIAN); + flags_tree = proto_item_add_subtree(flags_item, ett_configuration_bmAttributes); + + flags = tvb_get_guint8(tvb, offset); + proto_tree_add_item(flags_tree, hf_usb_configuration_legacy10buspowered, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(flags_tree, hf_usb_configuration_selfpowered, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(flags_item, " %sSELF-POWERED", (flags&0x40)?"":"NOT "); + proto_tree_add_item(flags_tree, hf_usb_configuration_remotewakeup, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(flags_item, " %sREMOTE-WAKEUP", (flags&0x20)?"":"NO "); + offset += 1; + + /* bMaxPower */ + power_item = proto_tree_add_item(tree, hf_usb_bMaxPower, tvb, offset, 1, ENC_LITTLE_ENDIAN); + power = tvb_get_guint8(tvb, offset); + proto_item_append_text(power_item, " (%dmA)", power*2); + offset += 1; + + /* initialize interface_info to NULL */ + usb_trans_info->interface_info = NULL; + + truncation_expected = (usb_trans_info->setup.wLength < len); + + /* decode any additional interface and endpoint descriptors */ + while(len>(offset-old_offset)) { + guint8 next_type; + guint8 next_len = 0; + gint remaining_tvb, remaining_len; + tvbuff_t *next_tvb = NULL; + + /* Handle truncated descriptors appropriately */ + remaining_tvb = tvb_reported_length_remaining(tvb, offset); + if (remaining_tvb > 0) { + next_len = tvb_get_guint8(tvb, offset); + remaining_len = len - (offset - old_offset); + if ((next_len < 3) || (next_len > remaining_len)) { + proto_tree_add_expert_format(parent_tree, pinfo, &ei_usb_desc_length_invalid, + tvb, offset, 1, "Invalid descriptor length: %u", next_len); + item = NULL; + break; + } + } + + if ((remaining_tvb == 0) || (next_len > remaining_tvb)) { + if (truncation_expected) + break; + } + + next_type = tvb_get_guint8(tvb, offset+1); + switch(next_type) { + case USB_DT_INTERFACE: + offset = dissect_usb_interface_descriptor(pinfo, parent_tree, tvb, offset, usb_conv_info); + break; + case USB_DT_ENDPOINT: + offset = dissect_usb_endpoint_descriptor(pinfo, parent_tree, tvb, offset, usb_conv_info, &last_ep_type, speed); + break; + case USB_DT_INTERFACE_ASSOCIATION: + offset = dissect_usb_interface_assn_descriptor(pinfo, parent_tree, tvb, offset, usb_conv_info); + break; + case USB_DT_SUPERSPEED_EP_COMPANION: + offset = dissect_usb_endpoint_companion_descriptor(pinfo, parent_tree, tvb, offset, usb_conv_info, last_ep_type); + break; + default: + next_tvb = tvb_new_subset_length(tvb, offset, next_len); + if (dissector_try_uint_new(usb_descriptor_dissector_table, usb_conv_info->interfaceClass, next_tvb, pinfo, parent_tree, TRUE, usb_conv_info)) { + offset += next_len; + } else { + offset = dissect_usb_unknown_descriptor(pinfo, parent_tree, tvb, offset, usb_conv_info); + } + break; + /* was: return offset; */ + } + } + + proto_item_set_len(item, offset-old_offset); + + return offset; +} + +/* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor */ +static int +dissect_webusb_platform_descriptor(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + proto_tree_add_item(tree, hf_usb_webusb_bcdVersion, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_usb_webusb_bVendorCode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_usb_webusb_iLandingPage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + return offset; +} + +/* Microsoft OS 2.0 Descriptors Specification */ +static int +dissect_msos20_platform_descriptor(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + proto_tree_add_item(tree, hf_usb_msos20_dwWindowsVersion, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_usb_msos20_wMSOSDescriptorSetTotalLength, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_usb_msos20_bMS_VendorCode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_usb_msos20_bAltEnumCode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + return offset; +} + +static struct { + e_guid_t uuid; + const gchar *text; + int (*dissect)(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info); +} bos_platform_uuids[] = { + { {0x3408b638, 0x09a9, 0x47a0, {0x8b, 0xfd, 0xa0, 0x76, 0x88, 0x15, 0xb6, 0x65}}, + "WebUSB Platform Capability descriptor", + dissect_webusb_platform_descriptor }, + + { {0xd8dd60df, 0x4589, 0x4cc7, {0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, 0x9f}}, + "Microsoft OS 2.0 Platform Capability descriptor", + dissect_msos20_platform_descriptor }, +}; + +/* USB 3.2 Specification Table 9-13. Format of a Device Capability Descriptor */ +static int +dissect_usb_device_capability_descriptor(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + guint8 cap_type; + const gchar *cap_text; + e_guid_t uuid; + unsigned int i; + + proto_tree_add_item(tree, hf_usb_bDevCapabilityType, tvb, offset, 1, ENC_LITTLE_ENDIAN); + cap_type = tvb_get_guint8(tvb, offset); + offset += 1; + + cap_text = try_val_to_str_ext(cap_type, &usb_capability_vals_ext); + + if (cap_type == BOS_CAP_USB_20_EXTENSION) { + /* USB 2.0 ECN Errata for Link Power Management */ + static int * const usb20ext_fields[] = { + &hf_usb_usb20ext_LPM, + &hf_usb_usb20ext_BESL_HIRD, + &hf_usb_usb20ext_baseline_BESL_valid, + &hf_usb_usb20ext_deep_BESL_valid, + &hf_usb_usb20ext_baseline_BESL, + &hf_usb_usb20ext_deep_BESL, + NULL + }; + + proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_usb_usb20ext_bmAttributes, + ett_usb20ext_bmAttributes, usb20ext_fields, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); + offset += 4; + } else if (cap_type == BOS_CAP_PLATFORM) { + proto_tree_add_item(tree, hf_usb_bReserved, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + tvb_get_letohguid(tvb, offset, &uuid); + proto_tree_add_guid(tree, hf_usb_PlatformCapabilityUUID, tvb, offset, 16, &uuid); + offset += 16; + + for (i = 0; i < array_length(bos_platform_uuids); i++) { + if (guid_cmp(&bos_platform_uuids[i].uuid, &uuid) == 0) { + offset = bos_platform_uuids[i].dissect(pinfo, tree, tvb, offset, usb_conv_info); + cap_text = bos_platform_uuids[i].text; + break; + } + } + } + + if (cap_text) { + proto_item_append_text(tree, ": %s", cap_text); + } + + return offset; +} + +/* USB 3.2 Specification 9.6.2 Binary Device Object Store (BOS) */ +static int +dissect_usb_bos_descriptor(packet_info *pinfo, proto_tree *parent_tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + proto_item *item; + proto_tree *tree; + int old_offset = offset; + guint16 total_len; + usb_trans_info_t *usb_trans_info; + + usb_trans_info = usb_conv_info->usb_trans_info; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &item, "BOS DESCRIPTOR"); + + dissect_usb_descriptor_header(tree, tvb, offset, NULL); + offset += 2; + + /* wTotalLength */ + proto_tree_add_item(tree, hf_usb_wTotalLength, tvb, offset, 2, ENC_LITTLE_ENDIAN); + total_len = tvb_get_letohs(tvb, offset); + offset += 2; + + proto_tree_add_item(tree, hf_usb_bNumDeviceCaps, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + if (offset - old_offset >= usb_trans_info->setup.wLength) { + /* Do not report the most common case where host finds out about + * wTotalLength by requesting just BOS descriptor as Malformed Packet. + * TODO: Generic handling of "host requested too few bytes" (which is + * perfectly fine, but complicates dissection) because host is allowed + * to request any number of bytes. + */ + return offset; + } + + /* Dissect capabilities */ + while (total_len > (offset - old_offset)) { + proto_item *desc_item; + int prev_offset = offset; + guint8 desc_len, desc_type; + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_descriptor_device, &desc_item, "DEVICE CAPABILITY DESCRIPTOR"); + + item = proto_tree_add_item(tree, hf_usb_bLength, tvb, offset, 1, ENC_LITTLE_ENDIAN); + desc_len = tvb_get_guint8(tvb, offset); + offset += 1; + if (desc_len < 3) { + expert_add_info_format(pinfo, item, &ei_usb_bLength_too_short, "Invalid Length (must be 3 or larger)"); + break; + } + + item = proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset, 1, ENC_LITTLE_ENDIAN); + desc_type = tvb_get_guint8(tvb, offset); + offset += 1; + if (desc_type == USB_DT_DEVICE_CAPABILITY) { + tvbuff_t *desc_tvb = tvb_new_subset_length(tvb, offset, desc_len - 2); + offset += dissect_usb_device_capability_descriptor(pinfo, tree, desc_tvb, 0, usb_conv_info); + } else { + expert_add_info(pinfo, item, &ei_usb_unexpected_desc_type); + /* Already reported unexpected type, do not mark rest as undecoded */ + offset = prev_offset + desc_len; + } + + if (offset < prev_offset + desc_len) { + proto_tree_add_expert(tree, pinfo, &ei_usb_undecoded, tvb, offset, prev_offset + desc_len - offset); + offset = prev_offset + desc_len; + } + proto_item_set_len(item, offset - prev_offset); + } + + proto_item_set_len(item, offset - old_offset); + + return offset; +} + +/* 9.4.3 */ +static int +dissect_usb_setup_get_descriptor_request(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + usb_trans_info_t *usb_trans_info, trans_info; + + if (usb_conv_info) + usb_trans_info = usb_conv_info->usb_trans_info; + else + usb_trans_info = &trans_info; + + /* descriptor index */ + proto_tree_add_item(tree, hf_usb_descriptor_index, tvb, offset, 1, ENC_LITTLE_ENDIAN); + usb_trans_info->u.get_descriptor.usb_index = tvb_get_guint8(tvb, offset); + offset += 1; + + /* descriptor type */ + proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset, 1, ENC_LITTLE_ENDIAN); + usb_trans_info->u.get_descriptor.type = tvb_get_guint8(tvb, offset); + offset += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + val_to_str_ext(usb_trans_info->u.get_descriptor.type, &std_descriptor_type_vals_ext, "Unknown type %u")); + + /* language id */ + proto_tree_add_item(tree, hf_usb_language_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset+=2; + + /* length */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_get_descriptor_response(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + usb_trans_info_t *usb_trans_info; + usb_speed_t speed; + + usb_trans_info = usb_conv_info->usb_trans_info; + speed = usb_conv_info->speed; + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + val_to_str_ext(usb_trans_info->u.get_descriptor.type, &std_descriptor_type_vals_ext, "Unknown type %u")); + + switch(usb_trans_info->u.get_descriptor.type) { + case USB_DT_INTERFACE: + case USB_DT_ENDPOINT: + /* an interface or an endpoint descriptor can only be accessed + as part of a configuration descriptor */ + break; + case USB_DT_DEVICE: + offset = dissect_usb_device_descriptor(pinfo, tree, tvb, offset, usb_conv_info); + break; + case USB_DT_OTHER_SPEED_CONFIG: + /* USB 2.0 Specification: 9.2.6.6 Speed Dependent Descriptors */ + if (speed == USB_SPEED_FULL) + speed = USB_SPEED_HIGH; + else if (speed == USB_SPEED_HIGH) + speed = USB_SPEED_FULL; + /* fall-through */ + case USB_DT_CONFIG: + offset = dissect_usb_configuration_descriptor(pinfo, tree, tvb, offset, usb_conv_info, speed); + break; + case USB_DT_STRING: + offset = dissect_usb_string_descriptor(pinfo, tree, tvb, offset, usb_conv_info); + break; + case USB_DT_DEVICE_QUALIFIER: + offset = dissect_usb_device_qualifier_descriptor(pinfo, tree, tvb, offset, usb_conv_info); + break; + case USB_DT_BOS: + offset = dissect_usb_bos_descriptor(pinfo, tree, tvb, offset, usb_conv_info); + break; + default: + /* XXX dissect the descriptor coming back from the device */ + { + guint len = tvb_reported_length_remaining(tvb, offset); + proto_tree_add_bytes_format(tree, hf_usb_get_descriptor_resp_generic, tvb, offset, len, NULL, + "GET DESCRIPTOR Response data (unknown descriptor type %u): %s", + usb_trans_info->u.get_descriptor.type, + tvb_bytes_to_str(pinfo->pool, tvb, offset, len)); + offset = offset + len; + } + break; + } + + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / GET INTERFACE + */ + + +/* 9.4.4 */ +static int +dissect_usb_setup_get_interface_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* zero */ + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* interface */ + proto_tree_add_item(tree, hf_usb_wInterface, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* length */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_get_interface_response(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* alternate setting */ + proto_tree_add_item(tree, hf_usb_bAlternateSetting, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / GET STATUS + */ + + +/* 9.4.5 */ +static int +dissect_usb_setup_get_status_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* zero */ + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* zero/interface/endpoint */ + if (usb_conv_info) { + guint8 recip; + + recip = USB_RECIPIENT(usb_conv_info->usb_trans_info->setup.requesttype); + + switch (recip) { + case RQT_SETUP_RECIPIENT_INTERFACE: + proto_tree_add_item(tree, hf_usb_wInterface, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_ENDPOINT: + proto_tree_add_item(tree, hf_usb_wEndpoint, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_DEVICE: + case RQT_SETUP_RECIPIENT_OTHER: + default: + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + } + } else { + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + offset += 2; + + /* length */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_get_status_response(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* status */ + /* XXX - show bits */ + proto_tree_add_item(tree, hf_usb_wStatus, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / SET ADDRESS + */ + + +/* 9.4.6 */ +static int +dissect_usb_setup_set_address_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* device address */ + proto_tree_add_item(tree, hf_usb_device_address, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* zero */ + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* zero */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_set_address_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / SET CONFIGURATION + */ + + +/* 9.4.7 */ +static int +dissect_usb_setup_set_configuration_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* configuration value */ + proto_tree_add_item(tree, hf_usb_bConfigurationValue, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 2; + + /* zero */ + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* zero */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_set_configuration_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / SET FEATURE + */ + + +/* 9.4.9 */ +static int +dissect_usb_setup_set_feature_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + guint8 recip; + + if (usb_conv_info) { + recip = USB_RECIPIENT(usb_conv_info->usb_trans_info->setup.requesttype); + + /* feature selector, zero/interface/endpoint */ + switch (recip) { + case RQT_SETUP_RECIPIENT_DEVICE: + proto_tree_add_item(tree, hf_usb_device_wFeatureSelector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_INTERFACE: + proto_tree_add_item(tree, hf_usb_interface_wFeatureSelector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_wInterface, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_ENDPOINT: + proto_tree_add_item(tree, hf_usb_endpoint_wFeatureSelector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_wEndpoint, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + + case RQT_SETUP_RECIPIENT_OTHER: + default: + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + } + } else { + /* No conversation information, so recipient type is unknown */ + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + offset += 2; + + /* zero */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_set_feature_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / SET INTERFACE + */ + + +/* 9.4.10 */ +static int +dissect_usb_setup_set_interface_request(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + guint8 alt_setting, interface_num; + + /* alternate setting */ + alt_setting = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_usb_bAlternateSetting, tvb, offset, 2, alt_setting); + offset += 2; + + /* interface */ + interface_num = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_usb_wInterface, tvb, offset, 2, interface_num); + offset += 2; + + /* zero */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + if (!PINFO_FD_VISITED(pinfo)) { + guint i, count; + usb_conv_info_t *iface_conv_info = get_usb_iface_conv_info(pinfo, interface_num); + + /* update the conversation info with the selected alternate setting */ + count = wmem_array_get_count(iface_conv_info->alt_settings); + for (i = 0; i < count; i++) { + usb_alt_setting_t *alternate_setting = (usb_alt_setting_t *)wmem_array_index(iface_conv_info->alt_settings, i); + + if (alternate_setting->altSetting == alt_setting) { + iface_conv_info->interfaceClass = alternate_setting->interfaceClass; + iface_conv_info->interfaceSubclass = alternate_setting->interfaceSubclass; + iface_conv_info->interfaceProtocol = alternate_setting->interfaceProtocol; + iface_conv_info->interfaceNum = alternate_setting->interfaceNum; + break; + } + } + } + + return offset; +} + +static int +dissect_usb_setup_set_interface_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + return offset; +} + + +/* + * These dissectors are used to dissect the setup part and the data + * for URB_CONTROL_INPUT / SYNCH FRAME + */ + + +/* 9.4.11 */ +static int +dissect_usb_setup_synch_frame_request(packet_info *pinfo _U_, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* zero */ + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* endpoint */ + proto_tree_add_item(tree, hf_usb_wEndpoint, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* two */ + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_usb_setup_synch_frame_response(packet_info *pinfo _U_, proto_tree *tree _U_, + tvbuff_t *tvb _U_, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + /* frame number */ + proto_tree_add_item(tree, hf_usb_wFrameNumber, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +/* Dissector used for unknown USB setup request/responses */ +static int +dissect_usb_setup_generic(packet_info *pinfo _U_, proto_tree *tree , + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info _U_) +{ + + proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + + + +typedef int (*usb_setup_dissector)(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info); + +typedef struct _usb_setup_dissector_table_t { + guint8 request; + usb_setup_dissector dissector; + +} usb_setup_dissector_table_t; +static const usb_setup_dissector_table_t setup_request_dissectors[] = { + {USB_SETUP_GET_STATUS, dissect_usb_setup_get_status_request}, + {USB_SETUP_CLEAR_FEATURE, dissect_usb_setup_clear_feature_request}, + {USB_SETUP_SET_FEATURE, dissect_usb_setup_set_feature_request}, + {USB_SETUP_SET_ADDRESS, dissect_usb_setup_set_address_request}, + {USB_SETUP_GET_DESCRIPTOR, dissect_usb_setup_get_descriptor_request}, + {USB_SETUP_SET_CONFIGURATION, dissect_usb_setup_set_configuration_request}, + {USB_SETUP_GET_INTERFACE, dissect_usb_setup_get_interface_request}, + {USB_SETUP_SET_INTERFACE, dissect_usb_setup_set_interface_request}, + {USB_SETUP_SYNCH_FRAME, dissect_usb_setup_synch_frame_request}, + {0, NULL} +}; + +static const usb_setup_dissector_table_t setup_response_dissectors[] = { + {USB_SETUP_GET_STATUS, dissect_usb_setup_get_status_response}, + {USB_SETUP_CLEAR_FEATURE, dissect_usb_setup_clear_feature_response}, + {USB_SETUP_SET_FEATURE, dissect_usb_setup_set_feature_response}, + {USB_SETUP_SET_ADDRESS, dissect_usb_setup_set_address_response}, + {USB_SETUP_GET_DESCRIPTOR, dissect_usb_setup_get_descriptor_response}, + {USB_SETUP_GET_CONFIGURATION, dissect_usb_setup_get_configuration_response}, + {USB_SETUP_SET_CONFIGURATION, dissect_usb_setup_set_configuration_response}, + {USB_SETUP_GET_INTERFACE, dissect_usb_setup_get_interface_response}, + {USB_SETUP_SET_INTERFACE, dissect_usb_setup_set_interface_response}, + {USB_SETUP_SYNCH_FRAME, dissect_usb_setup_synch_frame_response}, + {0, NULL} +}; + +static const value_string setup_request_names_vals[] = { + {USB_SETUP_GET_STATUS, "GET STATUS"}, + {USB_SETUP_CLEAR_FEATURE, "CLEAR FEATURE"}, + {USB_SETUP_SET_FEATURE, "SET FEATURE"}, + {USB_SETUP_SET_ADDRESS, "SET ADDRESS"}, + {USB_SETUP_GET_DESCRIPTOR, "GET DESCRIPTOR"}, + {USB_SETUP_SET_DESCRIPTOR, "SET DESCRIPTOR"}, + {USB_SETUP_GET_CONFIGURATION, "GET CONFIGURATION"}, + {USB_SETUP_SET_CONFIGURATION, "SET CONFIGURATION"}, + {USB_SETUP_GET_INTERFACE, "GET INTERFACE"}, + {USB_SETUP_SET_INTERFACE, "SET INTERFACE"}, + {USB_SETUP_SYNCH_FRAME, "SYNCH FRAME"}, + {USB_SETUP_SET_SEL, "SET SEL"}, + {USB_SETUP_SET_ISOCH_DELAY, "SET ISOCH DELAY"}, + {0, NULL} +}; +static value_string_ext setup_request_names_vals_ext = VALUE_STRING_EXT_INIT(setup_request_names_vals); + + +static const true_false_string tfs_bmrequesttype_direction = { + "Device-to-host", + "Host-to-device" +}; + +static const value_string bmrequesttype_type_vals[] = { + {RQT_SETUP_TYPE_STANDARD, "Standard"}, + {RQT_SETUP_TYPE_CLASS, "Class"}, + {RQT_SETUP_TYPE_VENDOR, "Vendor"}, + {0, NULL} +}; + +static const value_string bmrequesttype_recipient_vals[] = { + {RQT_SETUP_RECIPIENT_DEVICE, "Device" }, + {RQT_SETUP_RECIPIENT_INTERFACE, "Interface" }, + {RQT_SETUP_RECIPIENT_ENDPOINT, "Endpoint" }, + {RQT_SETUP_RECIPIENT_OTHER, "Other" }, + {0, NULL } +}; + +/* Dissector used for standard usb setup requests */ +static int +dissect_usb_standard_setup_request(packet_info *pinfo, proto_tree *tree , + tvbuff_t *tvb, usb_conv_info_t *usb_conv_info, + usb_trans_info_t *usb_trans_info) +{ + gint offset = 0; + const usb_setup_dissector_table_t *tmp; + usb_setup_dissector dissector; + + proto_tree_add_item(tree, hf_usb_request, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request", + val_to_str_ext(usb_trans_info->setup.request, &setup_request_names_vals_ext, "Unknown type %x")); + + dissector = NULL; + for(tmp = setup_request_dissectors;tmp->dissector;tmp++) { + if (tmp->request == usb_trans_info->setup.request) { + dissector = tmp->dissector; + break; + } + } + + if (!dissector) { + dissector = &dissect_usb_setup_generic; + } + + offset = dissector(pinfo, tree, tvb, offset, usb_conv_info); + + return offset; + +} + +/* Dissector used for standard usb setup responses */ +static int +dissect_usb_standard_setup_response(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + usb_conv_info_t *usb_conv_info) +{ + const usb_setup_dissector_table_t *tmp; + usb_setup_dissector dissector; + gint length_remaining; + + + col_add_fstr(pinfo->cinfo, COL_INFO, "%s Response", + val_to_str_ext(usb_conv_info->usb_trans_info->setup.request, + &setup_request_names_vals_ext, "Unknown type %x")); + + dissector = NULL; + for(tmp = setup_response_dissectors;tmp->dissector;tmp++) { + if (tmp->request == usb_conv_info->usb_trans_info->setup.request) { + dissector = tmp->dissector; + break; + } + } + + length_remaining = tvb_reported_length_remaining(tvb, offset); + + if (length_remaining <= 0) + return offset; + + if (dissector) { + offset = dissector(pinfo, tree, tvb, offset, usb_conv_info); + } else { + proto_tree_add_item(tree, hf_usb_control_response_generic, + tvb, offset, length_remaining, ENC_NA); + offset += length_remaining; + } + + return offset; +} + + +static void +usb_tap_queue_packet(packet_info *pinfo, guint8 urb_type, + usb_conv_info_t *usb_conv_info) +{ + usb_tap_data_t *tap_data; + + tap_data = wmem_new(pinfo->pool, usb_tap_data_t); + tap_data->urb_type = urb_type; + tap_data->transfer_type = (guint8)(usb_conv_info->transfer_type); + tap_data->conv_info = usb_conv_info; + tap_data->trans_info = usb_conv_info->usb_trans_info; + + tap_queue_packet(usb_tap, pinfo, tap_data); +} + + +static gboolean +is_usb_standard_setup_request(usb_trans_info_t *usb_trans_info) +{ + guint8 type, recip; + + type = USB_TYPE(usb_trans_info->setup.requesttype); + recip = USB_RECIPIENT(usb_trans_info->setup.requesttype); + + if (type != RQT_SETUP_TYPE_STANDARD) + return FALSE; + + /* the USB standards defines the GET_DESCRIPTOR request only as a + request to a device + if it's not aimed at a device, it's a non-standard request that + should be handled by a class-specific dissector */ + if (usb_trans_info->setup.request == USB_SETUP_GET_DESCRIPTOR && + recip != RQT_SETUP_RECIPIENT_DEVICE) { + return FALSE; + } + + return TRUE; +} + + +static gint +try_dissect_next_protocol(proto_tree *tree, tvbuff_t *next_tvb, packet_info *pinfo, + usb_conv_info_t *usb_conv_info, guint8 urb_type, proto_tree *urb_tree, + proto_tree *setup_tree) +{ + int ret; + wmem_tree_key_t key[4]; + guint32 k_frame_number; + guint32 k_device_address; + guint32 k_bus_id; + usb_conv_info_t *old_conv_info = usb_conv_info; + usb_trans_info_t *usb_trans_info; + heur_dtbl_entry_t *hdtbl_entry; + heur_dissector_list_t heur_subdissector_list = NULL; + dissector_table_t usb_dissector_table = NULL; + proto_item *sub_item; + device_product_data_t *device_product_data; + device_protocol_data_t *device_protocol_data; + guint8 ctrl_recip; + /* if we select the next dissector based on a class, + this is the (device or interface) class we're using */ + guint32 usb_class; + guint8 transfer_type; + gboolean use_setup_tree = FALSE; + + if (!usb_conv_info) { + /* + * Not enough information to choose the next protocol. + * XXX - is there something we can still do here? + */ + if (tvb_reported_length(next_tvb) > 0) + call_data_dissector(next_tvb, pinfo, tree); + + return tvb_captured_length(next_tvb); + } + + /* try dissect by "usb.device" */ + ret = dissector_try_uint_new(device_to_dissector, + (guint32)(usb_conv_info->bus_id<<16 | usb_conv_info->device_address), + next_tvb, pinfo, tree, TRUE, usb_conv_info); + if (ret) + return tvb_captured_length(next_tvb); + + k_frame_number = pinfo->num; + k_device_address = usb_conv_info->device_address; + k_bus_id = usb_conv_info->bus_id; + + key[0].length = 1; + key[0].key = &k_device_address; + key[1].length = 1; + key[1].key = &k_bus_id; + key[2].length = 1; + key[2].key = &k_frame_number; + key[3].length = 0; + key[3].key = NULL; + + /* try dissect by "usb.protocol" */ + device_protocol_data = (device_protocol_data_t *)wmem_tree_lookup32_array_le(device_to_protocol_table, key); + + if (device_protocol_data && + device_protocol_data->bus_id == usb_conv_info->bus_id && + device_protocol_data->device_address == usb_conv_info->device_address) { + ret = dissector_try_uint_new(protocol_to_dissector, + (guint32)device_protocol_data->protocol, + next_tvb, pinfo, tree, TRUE, usb_conv_info); + if (ret) + return tvb_captured_length(next_tvb); + } + + device_product_data = (device_product_data_t *)wmem_tree_lookup32_array_le(device_to_product_table, key); + + if (device_product_data && device_product_data->bus_id == usb_conv_info->bus_id && + device_product_data->device_address == usb_conv_info->device_address) { + ret = dissector_try_uint_new(product_to_dissector, + (guint32)(device_product_data->vendor<<16 | device_product_data->product), + next_tvb, pinfo, tree, TRUE, usb_conv_info); + if (ret) + return tvb_captured_length(next_tvb); + } + + transfer_type = usb_conv_info->transfer_type; + if (transfer_type == URB_UNKNOWN) + transfer_type = usb_conv_info->descriptor_transfer_type; + + switch(transfer_type) { + case URB_BULK: + heur_subdissector_list = heur_bulk_subdissector_list; + usb_dissector_table = usb_bulk_dissector_table; + break; + + case URB_INTERRUPT: + heur_subdissector_list = heur_interrupt_subdissector_list; + usb_dissector_table = usb_interrupt_dissector_table; + break; + + case URB_CONTROL: + usb_trans_info = usb_conv_info->usb_trans_info; + if (!usb_trans_info) + break; + + /* for standard control requests and responses, there's no + need to query dissector tables */ + if (is_usb_standard_setup_request(usb_trans_info)) + break; + + /* When dissecting requests, and Setup Data tree is created, + pass it to next dissector instead of parent. */ + if (usb_conv_info->is_request && setup_tree) + use_setup_tree = TRUE; + + ctrl_recip = USB_RECIPIENT(usb_trans_info->setup.requesttype); + + if (ctrl_recip == RQT_SETUP_RECIPIENT_INTERFACE) { + guint8 interface_num = usb_trans_info->setup.wIndex & 0xff; + + heur_subdissector_list = heur_control_subdissector_list; + usb_dissector_table = usb_control_dissector_table; + + usb_conv_info = get_usb_iface_conv_info(pinfo, interface_num); + usb_conv_info->usb_trans_info = usb_trans_info; + } + else if (ctrl_recip == RQT_SETUP_RECIPIENT_ENDPOINT) { + address endpoint_addr; + gint endpoint; + guint32 src_endpoint, dst_endpoint; + conversation_t *conversation; + + heur_subdissector_list = heur_control_subdissector_list; + usb_dissector_table = usb_control_dissector_table; + + endpoint = usb_trans_info->setup.wIndex & 0x0f; + + if (usb_conv_info->is_request) { + usb_address_t *dst_addr = wmem_new0(pinfo->pool, usb_address_t); + dst_addr->bus_id = usb_conv_info->bus_id; + dst_addr->device = usb_conv_info->device_address; + dst_addr->endpoint = dst_endpoint = GUINT32_TO_LE(endpoint); + set_address(&endpoint_addr, usb_address_type, USB_ADDR_LEN, (char *)dst_addr); + + conversation = get_usb_conversation(pinfo, &pinfo->src, &endpoint_addr, pinfo->srcport, dst_endpoint); + } + else { + usb_address_t *src_addr = wmem_new0(pinfo->pool, usb_address_t); + src_addr->bus_id = usb_conv_info->bus_id; + src_addr->device = usb_conv_info->device_address; + src_addr->endpoint = src_endpoint = GUINT32_TO_LE(endpoint); + set_address(&endpoint_addr, usb_address_type, USB_ADDR_LEN, (char *)src_addr); + + conversation = get_usb_conversation(pinfo, &endpoint_addr, &pinfo->dst, src_endpoint, pinfo->destport); + } + + usb_conv_info = get_usb_conv_info(conversation); + usb_conv_info->usb_trans_info = usb_trans_info; + } + else { + /* the recipient is "device" or "other" or "reserved" + there's no way for us to determine the interfaceClass + we set the usb_dissector_table anyhow as some + dissectors register for control messages to + IF_CLASS_UNKNOWN (this should be fixed) */ + heur_subdissector_list = heur_control_subdissector_list; + usb_dissector_table = usb_control_dissector_table; + } + + if (old_conv_info != usb_conv_info) { + /* Preserve URB specific information */ + usb_conv_info->is_setup = old_conv_info->is_setup; + usb_conv_info->is_request = old_conv_info->is_request; + usb_conv_info->setup_requesttype = old_conv_info->setup_requesttype; + usb_conv_info->speed = old_conv_info->speed; + } + + usb_tap_queue_packet(pinfo, urb_type, usb_conv_info); + sub_item = proto_tree_add_uint(urb_tree, hf_usb_bInterfaceClass, next_tvb, 0, 0, usb_conv_info->interfaceClass); + proto_item_set_generated(sub_item); + break; + + default: + break; + } + + if (try_heuristics && heur_subdissector_list) { + ret = dissector_try_heuristic(heur_subdissector_list, + next_tvb, pinfo, use_setup_tree ? setup_tree : tree, &hdtbl_entry, usb_conv_info); + if (ret) + return tvb_captured_length(next_tvb); + } + + if (usb_dissector_table) { + /* we prefer the interface class unless it says we should refer + to the device class + XXX - use the device class if the interface class is unknown */ + if (usb_conv_info->interfaceClass == IF_CLASS_DEVICE) { + usb_class = (usb_conv_info->device_protocol>>16) & 0xFF; + } + else { + usb_class = usb_conv_info->interfaceClass; + } + + ret = dissector_try_uint_new(usb_dissector_table, usb_class, + next_tvb, pinfo, use_setup_tree ? setup_tree : tree, TRUE, usb_conv_info); + if (ret) + return tvb_captured_length(next_tvb); + + /* try protocol specific dissector if there is one */ + usb_class = USB_PROTOCOL_KEY(usb_conv_info->interfaceClass, + usb_conv_info->interfaceSubclass, + usb_conv_info->interfaceProtocol); + ret = dissector_try_uint_new(usb_dissector_table, usb_class, + next_tvb, pinfo, use_setup_tree ? setup_tree : tree, TRUE, usb_conv_info); + if (ret) + return tvb_captured_length(next_tvb); + } + + return 0; +} + + +static int +dissect_usb_setup_response(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + guint8 urb_type, usb_conv_info_t *usb_conv_info) +{ + proto_tree *parent; + tvbuff_t *next_tvb = NULL; + gint length_remaining; + + parent = proto_tree_get_parent_tree(tree); + + if (usb_conv_info) { + if (usb_conv_info->usb_trans_info && is_usb_standard_setup_request(usb_conv_info->usb_trans_info)) { + offset = dissect_usb_standard_setup_response(pinfo, parent, tvb, offset, usb_conv_info); + } + else { + next_tvb = tvb_new_subset_remaining(tvb, offset); + offset += try_dissect_next_protocol(parent, next_tvb, pinfo, usb_conv_info, urb_type, tree, NULL); + + length_remaining = tvb_reported_length_remaining(tvb, offset); + if (length_remaining > 0) { + proto_tree_add_item(parent, hf_usb_control_response_generic, + tvb, offset, length_remaining, ENC_NA); + offset += length_remaining; + } + } + } + else { + /* no matching request available */ + length_remaining = tvb_reported_length_remaining(tvb, offset); + if (length_remaining > 0) { + proto_tree_add_item(parent, hf_usb_control_response_generic, tvb, + offset, length_remaining, ENC_NA); + offset += length_remaining; + } + } + + return offset; +} + + +static int +dissect_usb_bmrequesttype(proto_tree *parent_tree, tvbuff_t *tvb, int offset, guint8 *byte) +{ + guint64 val; + + static int * const bmRequestType_bits[] = { + &hf_usb_bmRequestType_direction, + &hf_usb_bmRequestType_type, + &hf_usb_bmRequestType_recipient, + NULL + }; + + proto_tree_add_bitmask_with_flags_ret_uint64(parent_tree, tvb, offset, hf_usb_bmRequestType, ett_usb_setup_bmrequesttype, + bmRequestType_bits, ENC_LITTLE_ENDIAN, BMT_NO_APPEND, &val); + *byte = (guint8) val; + + return ++offset; +} + +int +dissect_urb_transfer_flags(tvbuff_t *tvb, int offset, proto_tree* tree, int hf, int endian) +{ + proto_tree_add_bitmask(tree, tvb, offset, hf, ett_transfer_flags, transfer_flags_fields, endian); + return 4; +} + +static int +dissect_linux_usb_pseudo_header_ext(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, + proto_tree *tree) +{ + proto_tree_add_item(tree, hf_usb_urb_interval, tvb, offset, 4, ENC_HOST_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_usb_urb_start_frame, tvb, offset, 4, ENC_HOST_ENDIAN); + offset += 4; + dissect_urb_transfer_flags(tvb, offset, tree, hf_usb_urb_copy_of_transfer_flags, ENC_HOST_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_usb_iso_numdesc, tvb, offset, 4, ENC_HOST_ENDIAN); + offset += 4; + + return offset; +} + + +/* Dissector used for usb setup requests */ +static int +dissect_usb_setup_request(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, + guint8 urb_type, usb_conv_info_t *usb_conv_info, + usb_header_t header_type, guint64 usb_id) +{ + gint setup_offset; + gint req_type; + gint ret; + proto_tree *parent, *setup_tree; + usb_trans_info_t *usb_trans_info, trans_info; + tvbuff_t *next_tvb, *data_tvb = NULL; + guint8 bm_request_type; + + /* we should do the NULL check in all non-static functions */ + if (usb_conv_info) + usb_trans_info = usb_conv_info->usb_trans_info; + else + usb_trans_info = &trans_info; + + parent = proto_tree_get_parent_tree(tree); + + setup_tree = proto_tree_add_subtree(parent, tvb, offset, 8, ett_usb_setup_hdr, NULL, "Setup Data"); + + req_type = USB_TYPE(tvb_get_guint8(tvb, offset)); + usb_trans_info->setup.requesttype = tvb_get_guint8(tvb, offset); + if (usb_conv_info) { + usb_conv_info->setup_requesttype = tvb_get_guint8(tvb, offset); + if (req_type != RQT_SETUP_TYPE_CLASS) + usb_tap_queue_packet(pinfo, urb_type, usb_conv_info); + } + + offset = dissect_usb_bmrequesttype(setup_tree, tvb, offset, &bm_request_type); + + /* as we're going through the data, we build a next_tvb that + contains the the setup packet without the request type + and request-specific data + all subsequent dissection routines work on this tvb */ + + setup_offset = offset; + usb_trans_info->setup.request = tvb_get_guint8(tvb, offset); + offset++; + usb_trans_info->setup.wValue = tvb_get_letohs(tvb, offset); + offset += 2; + usb_trans_info->setup.wIndex = tvb_get_letohs(tvb, offset); + offset += 2; + usb_trans_info->setup.wLength = tvb_get_letohs(tvb, offset); + offset += 2; + + if (header_type == USB_HEADER_LINUX_64_BYTES) { + offset = dissect_linux_usb_pseudo_header_ext(tvb, offset, pinfo, tree); + } else if (header_type == USB_HEADER_USBPCAP) { + if ((bm_request_type & 0x80) == 0 && + usb_trans_info->setup.wLength > 0 && + tvb_reported_length_remaining(tvb, offset) == 0) { + /* UPBPcap older than 1.5.0.0 packet, save setup data + and do not call subdissector */ + if (!PINFO_FD_VISITED(pinfo)) { + wmem_tree_key_t key[3]; + usbpcap_setup_data_t *setup_data = wmem_new(wmem_file_scope(), usbpcap_setup_data_t); + setup_data->usb_id = usb_id; + tvb_memcpy(tvb, setup_data->setup_data, setup_offset-1, 8); + key[0].length = 2; + key[0].key = (guint32 *)&usb_id; + key[1].length = 1; + key[1].key = &pinfo->num; + key[2].length = 0; + key[2].key = NULL; + wmem_tree_insert32_array(usbpcap_setup_data, key, setup_data); + } + proto_tree_add_item(setup_tree, hf_usb_request_unknown_class, tvb, setup_offset, 1, ENC_LITTLE_ENDIAN); + dissect_usb_setup_generic(pinfo, setup_tree, tvb, setup_offset+1, usb_conv_info); + return offset; + } + } + + + if (tvb_captured_length_remaining(tvb, offset) > 0) { + next_tvb = tvb_new_composite(); + tvb_composite_append(next_tvb, tvb_new_subset_length(tvb, setup_offset, 7)); + + data_tvb = tvb_new_subset_remaining(tvb, offset); + tvb_composite_append(next_tvb, data_tvb); + offset += tvb_captured_length(data_tvb); + tvb_composite_finalize(next_tvb); + next_tvb = tvb_new_child_real_data(tvb, + (const guint8 *) tvb_memdup(pinfo->pool, next_tvb, 0, tvb_captured_length(next_tvb)), + tvb_captured_length(next_tvb), + tvb_captured_length(next_tvb)); + add_new_data_source(pinfo, next_tvb, "USB Control"); + } else { + next_tvb = tvb_new_subset_length(tvb, setup_offset, 7); + } + + /* at this point, offset contains the number of bytes that we + dissected */ + + if (is_usb_standard_setup_request(usb_trans_info)) { + /* there's no point in checking the return value as there's no + fallback for standard setup requests */ + dissect_usb_standard_setup_request(pinfo, setup_tree, + next_tvb, usb_conv_info, usb_trans_info); + } + else { + /* no standard request - pass it on to class-specific dissectors */ + ret = try_dissect_next_protocol( + parent, next_tvb, pinfo, usb_conv_info, urb_type, tree, setup_tree); + if (ret <= 0) { + /* no class-specific dissector could handle it, + dissect it as generic setup request */ + proto_tree_add_item(setup_tree, hf_usb_request_unknown_class, + next_tvb, 0, 1, ENC_LITTLE_ENDIAN); + dissect_usb_setup_generic(pinfo, setup_tree, + next_tvb, 1, usb_conv_info); + } + /* at this point, non-standard request has been dissectored */ + } + + if (data_tvb) + proto_tree_add_item(setup_tree, hf_usb_data_fragment, data_tvb, 0, -1, ENC_NA); + + return offset; +} + + +/* dissect the linux-specific USB pseudo header and fill the conversation struct + return the number of dissected bytes */ +static gint +dissect_linux_usb_pseudo_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + usb_conv_info_t *usb_conv_info, guint64 *urb_id) +{ + guint8 transfer_type; + guint8 endpoint_byte; + guint8 transfer_type_and_direction; + guint8 urb_type; + guint32 flag; + guint32 bus_id; + + *urb_id = tvb_get_guint64(tvb, 0, ENC_HOST_ENDIAN); + proto_tree_add_uint64(tree, hf_usb_urb_id, tvb, 0, 8, *urb_id); + + /* show the urb type of this URB as string and as a character */ + urb_type = tvb_get_guint8(tvb, 8); + usb_conv_info->is_request = (urb_type==URB_SUBMIT); + proto_tree_add_uint(tree, hf_usb_linux_urb_type, tvb, 8, 1, urb_type); + proto_tree_add_item(tree, hf_usb_linux_transfer_type, tvb, 9, 1, ENC_LITTLE_ENDIAN); + + transfer_type = tvb_get_guint8(tvb, 9); + usb_conv_info->transfer_type = transfer_type; + + endpoint_byte = tvb_get_guint8(tvb, 10); /* direction bit | endpoint */ + usb_conv_info->endpoint = endpoint_byte & 0x7F; + if (endpoint_byte & URB_TRANSFER_IN) + usb_conv_info->direction = P2P_DIR_RECV; + else + usb_conv_info->direction = P2P_DIR_SENT; + + transfer_type_and_direction = (transfer_type & 0x7F) | (endpoint_byte & 0x80); + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str(transfer_type_and_direction, usb_transfer_type_and_direction_vals, "Unknown type %x")); + + proto_tree_add_bitmask(tree, tvb, 10, hf_usb_endpoint_address, ett_usb_endpoint, usb_endpoint_fields, ENC_NA); + proto_tree_add_item(tree, hf_usb_device_address, tvb, 11, 1, ENC_LITTLE_ENDIAN); + usb_conv_info->device_address = (guint16)tvb_get_guint8(tvb, 11); + + proto_tree_add_item_ret_uint(tree, hf_usb_bus_id, tvb, 12, 2, ENC_HOST_ENDIAN, &bus_id); + usb_conv_info->bus_id = (guint16) bus_id; + + /* Right after the pseudo header we always have + * sizeof(struct usb_device_setup_hdr) bytes. The content of these + * bytes only have meaning in case setup_flag == 0. + */ + proto_tree_add_item_ret_uint(tree, hf_usb_setup_flag, tvb, 14, 1, ENC_NA, &flag); + if (flag == 0) { + usb_conv_info->is_setup = TRUE; + if (usb_conv_info->transfer_type!=URB_CONTROL) + proto_tree_add_expert(tree, pinfo, &ei_usb_invalid_setup, tvb, 14, 1); + } else { + usb_conv_info->is_setup = FALSE; + } + + proto_tree_add_item(tree, hf_usb_data_flag, tvb, 15, 1, ENC_NA); + + proto_tree_add_item(tree, hf_usb_urb_ts_sec, tvb, 16, 8, ENC_HOST_ENDIAN); + proto_tree_add_item(tree, hf_usb_urb_ts_usec, tvb, 24, 4, ENC_HOST_ENDIAN); + proto_tree_add_item(tree, hf_usb_urb_status, tvb, 28, 4, ENC_HOST_ENDIAN); + proto_tree_add_item(tree, hf_usb_urb_len, tvb, 32, 4, ENC_HOST_ENDIAN); + proto_tree_add_item(tree, hf_usb_urb_data_len, tvb, 36, 4, ENC_HOST_ENDIAN); + + return 40; +} + +/* dissect the usbpcap_buffer_packet_header and fill the conversation struct + this function does not handle the transfer-specific headers + return the number of bytes processed */ +static gint +dissect_usbpcap_buffer_packet_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + usb_conv_info_t *usb_conv_info, guint32 *win32_data_len, guint64 *irp_id) +{ + proto_item *item; + guint32 function_code; + guint8 transfer_type; + guint8 endpoint_byte; + guint8 transfer_type_and_direction; + guint8 tmp_val8; + + proto_tree_add_item(tree, hf_usb_win32_header_len, tvb, 0, 2, ENC_LITTLE_ENDIAN); + *irp_id = tvb_get_guint64(tvb, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_uint64(tree, hf_usb_irp_id, tvb, 2, 8, *irp_id); + proto_tree_add_item(tree, hf_usb_usbd_status, tvb, 10, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item_ret_uint(tree, hf_usb_function, tvb, 14, 2, ENC_LITTLE_ENDIAN, &function_code); + + proto_tree_add_bitmask(tree, tvb, 16, hf_usb_info, ett_usb_usbpcap_info, usb_usbpcap_info_fields, ENC_LITTLE_ENDIAN); + tmp_val8 = tvb_get_guint8(tvb, 16); + /* TODO: Handle errors */ + if (tmp_val8 & 0x01) { + usb_conv_info->is_request = FALSE; + } else { + usb_conv_info->is_request = TRUE; + } + + proto_tree_add_item(tree, hf_usb_bus_id, tvb, 17, 2, ENC_LITTLE_ENDIAN); + usb_conv_info->bus_id = tvb_get_letohs(tvb, 17); + + proto_tree_add_item(tree, hf_usb_win32_device_address, tvb, 19, 2, ENC_LITTLE_ENDIAN); + usb_conv_info->device_address = tvb_get_letohs(tvb, 19); + + endpoint_byte = tvb_get_guint8(tvb, 21); + usb_conv_info->direction = endpoint_byte&URB_TRANSFER_IN ? P2P_DIR_RECV : P2P_DIR_SENT; + usb_conv_info->endpoint = endpoint_byte&0x7F; + proto_tree_add_bitmask(tree, tvb, 21, hf_usb_endpoint_address, ett_usb_endpoint, usb_endpoint_fields, ENC_LITTLE_ENDIAN); + + transfer_type = tvb_get_guint8(tvb, 22); + usb_conv_info->transfer_type = transfer_type; + item = proto_tree_add_item(tree, hf_usb_win32_transfer_type, tvb, 22, 1, ENC_LITTLE_ENDIAN); + if (transfer_type == URB_UNKNOWN) { + expert_add_info(pinfo, item, &ei_usb_usbpcap_unknown_urb); + } + + /* Workaround bug in captures created with USBPcap earlier than 1.3.0.0 */ + if ((endpoint_byte == 0x00) && (transfer_type == URB_CONTROL) && (tvb_get_guint8(tvb, 27) == USB_CONTROL_STAGE_DATA)) { + usb_conv_info->is_request = TRUE; + } + + if (transfer_type != USBPCAP_URB_IRP_INFO) { + transfer_type_and_direction = (transfer_type & 0x7F) | (endpoint_byte & 0x80); + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str(transfer_type_and_direction, usb_transfer_type_and_direction_vals, "Unknown type %x")); + } else { + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str_ext(function_code, &win32_urb_function_vals_ext, "Unknown function %x")); + } + + *win32_data_len = tvb_get_letohl(tvb, 23); + proto_tree_add_item(tree, hf_usb_win32_data_len, tvb, 23, 4, ENC_LITTLE_ENDIAN); + + /* by default, we assume it's no setup packet + the correct values will be set when we parse the control header */ + usb_conv_info->is_setup = FALSE; + usb_conv_info->setup_requesttype = 0; + + /* we don't handle the transfer-specific headers here */ + return 27; +} + + +static gint +dissect_darwin_buffer_packet_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + usb_conv_info_t *usb_conv_info, guint64 *id) +{ + guint8 transfer_type; + guint8 request_type; + guint8 endpoint_byte; + guint8 transfer_type_and_direction; + guint8 header_length; + + proto_tree_add_item(tree, hf_usb_darwin_bcd_version, tvb, 0, 2, ENC_LITTLE_ENDIAN); + + header_length = tvb_get_guint8(tvb, 2); + proto_tree_add_item(tree, hf_usb_darwin_header_len, tvb, 2, 1, ENC_LITTLE_ENDIAN); + + request_type = tvb_get_guint8(tvb, 3); + usb_conv_info->is_request = (request_type == DARWIN_IO_SUBMIT); + proto_tree_add_uint(tree, hf_usb_darwin_request_type, tvb, 3, 1, request_type); + + proto_tree_add_item(tree, hf_usb_darwin_io_len, tvb, 4, 4, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(tree, hf_usb_darwin_io_status, tvb, 8, 4, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(tree, hf_usb_darwin_iso_num_packets, tvb, 12, 4, ENC_LITTLE_ENDIAN); + + *id = tvb_get_guint64(tvb, 16, ENC_LITTLE_ENDIAN); + proto_tree_add_uint64(tree, hf_usb_darwin_io_id, tvb, 16, 8, *id); + + proto_tree_add_item(tree, hf_usb_darwin_device_location, tvb, 24, 4, ENC_LITTLE_ENDIAN); + usb_conv_info->bus_id = tvb_get_letohl(tvb, 24) >> 24; + + proto_tree_add_item(tree, hf_usb_darwin_speed, tvb, 28, 1, ENC_LITTLE_ENDIAN); + + usb_conv_info->device_address = (guint16)tvb_get_guint8(tvb, 29); + proto_tree_add_uint(tree, hf_usb_darwin_device_address, tvb, 29, 1, usb_conv_info->device_address); + + endpoint_byte = tvb_get_guint8(tvb, 30); /* direction bit | endpoint */ + usb_conv_info->endpoint = endpoint_byte & 0x7F; + if (endpoint_byte & URB_TRANSFER_IN) { + usb_conv_info->direction = P2P_DIR_RECV; + } + else { + usb_conv_info->direction = P2P_DIR_SENT; + } + proto_tree_add_uint(tree, hf_usb_darwin_endpoint_address, tvb, 30, 1, endpoint_byte); + proto_tree_add_bitmask(tree, tvb, 30, hf_usb_endpoint_number, ett_usb_endpoint, usb_endpoint_fields, ENC_LITTLE_ENDIAN); + + transfer_type = MIN(tvb_get_guint8(tvb, 31), G_N_ELEMENTS(darwin_endpoint_to_linux) - 1); + usb_conv_info->transfer_type = darwin_endpoint_to_linux[transfer_type]; + proto_tree_add_uint(tree, hf_usb_darwin_endpoint_type, tvb, 31, 1, transfer_type); + + transfer_type_and_direction = (darwin_endpoint_to_linux[transfer_type] & 0x7F) | (endpoint_byte & 0x80); + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str(transfer_type_and_direction, usb_transfer_type_and_direction_vals, "Unknown type %x")); + col_append_str(pinfo->cinfo, COL_INFO, usb_conv_info->is_request == TRUE ? " (submitted)" : " (completed)"); + + usb_conv_info->is_setup = FALSE; + if ((usb_conv_info->is_request == TRUE) && (usb_conv_info->transfer_type == URB_CONTROL)) { + usb_conv_info->is_setup = TRUE; + } + + usb_conv_info->setup_requesttype = 0; + + /* we don't handle the transfer-specific headers here */ + return header_length; +} + +/* Set the usb_address_t fields based on the direction of the urb */ +static void +usb_set_addr(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, guint16 bus_id, guint16 device_address, + int endpoint, gboolean req) +{ + proto_item *sub_item; + usb_address_t *src_addr = wmem_new0(pinfo->pool, usb_address_t), + *dst_addr = wmem_new0(pinfo->pool, usb_address_t); + guint8 *str_src_addr; + guint8 *str_dst_addr; + + if (req) { + /* request */ + src_addr->device = 0xffffffff; + src_addr->endpoint = NO_ENDPOINT; + dst_addr->device = GUINT16_TO_LE(device_address); + dst_addr->endpoint = GUINT32_TO_LE(endpoint); + } else { + /* response */ + src_addr->device = GUINT16_TO_LE(device_address); + src_addr->endpoint = GUINT32_TO_LE(endpoint); + dst_addr->device = 0xffffffff; + dst_addr->endpoint = NO_ENDPOINT; + } + src_addr->bus_id = GUINT16_TO_LE(bus_id); + dst_addr->bus_id = GUINT16_TO_LE(bus_id); + + set_address(&pinfo->net_src, usb_address_type, USB_ADDR_LEN, (char *)src_addr); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + set_address(&pinfo->net_dst, usb_address_type, USB_ADDR_LEN, (char *)dst_addr); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + + pinfo->ptype = PT_USB; + pinfo->srcport = src_addr->endpoint; + pinfo->destport = dst_addr->endpoint; + /* sent/received is from the perspective of the USB host */ + pinfo->p2p_dir = req ? P2P_DIR_SENT : P2P_DIR_RECV; + + str_src_addr = address_to_str(pinfo->pool, &pinfo->src); + str_dst_addr = address_to_str(pinfo->pool, &pinfo->dst); + + sub_item = proto_tree_add_string(tree, hf_usb_src, tvb, 0, 0, str_src_addr); + proto_item_set_generated(sub_item); + + sub_item = proto_tree_add_string(tree, hf_usb_addr, tvb, 0, 0, str_src_addr); + proto_item_set_hidden(sub_item); + + sub_item = proto_tree_add_string(tree, hf_usb_dst, tvb, 0, 0, str_dst_addr); + proto_item_set_generated(sub_item); + + sub_item = proto_tree_add_string(tree, hf_usb_addr, tvb, 0, 0, str_dst_addr); + proto_item_set_hidden(sub_item); +} + + +/* Gets the transfer info for a given packet + * Generates transfer info if none exists yet + * Also adds request/response info to the tree for the given packet */ +static usb_trans_info_t +*usb_get_trans_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + usb_header_t header_type, usb_conv_info_t *usb_conv_info, guint64 usb_id) +{ + usb_trans_info_t *usb_trans_info; + proto_item *ti; + nstime_t t, deltat; + wmem_tree_key_t key[3]; + + /* request/response matching so we can keep track of transaction specific + * data. + */ + key[0].length = 2; + key[0].key = (guint32 *)&usb_id; + key[1].length = 1; + key[1].key = &pinfo->num; + key[2].length = 0; + key[2].key = NULL; + + if (usb_conv_info->is_request) { + /* this is a request */ + usb_trans_info = (usb_trans_info_t *)wmem_tree_lookup32_array(usb_conv_info->transactions, key); + if (!usb_trans_info) { + usb_trans_info = wmem_new0(wmem_file_scope(), usb_trans_info_t); + usb_trans_info->request_in = pinfo->num; + usb_trans_info->req_time = pinfo->abs_ts; + usb_trans_info->header_type = header_type; + usb_trans_info->usb_id = usb_id; + + wmem_tree_insert32_array(usb_conv_info->transactions, key, usb_trans_info); + } + + if (usb_trans_info->response_in) { + ti = proto_tree_add_uint(tree, hf_usb_response_in, tvb, 0, 0, usb_trans_info->response_in); + proto_item_set_generated(ti); + } + + } else { + /* this is a response */ + if (pinfo->fd->visited) { + usb_trans_info = (usb_trans_info_t *)wmem_tree_lookup32_array(usb_conv_info->transactions, key); + + } else { + usb_trans_info = (usb_trans_info_t *)wmem_tree_lookup32_array_le(usb_conv_info->transactions, key); + if (usb_trans_info) { + if (usb_trans_info->usb_id == usb_id) { + if (usb_trans_info->response_in == 0) { + /* USBPcap generates 2 frames for response; store the first one */ + usb_trans_info->response_in = pinfo->num; + } + wmem_tree_insert32_array(usb_conv_info->transactions, key, usb_trans_info); + } else { + usb_trans_info = NULL; + } + } + } + + if (usb_trans_info && usb_trans_info->request_in) { + + ti = proto_tree_add_uint(tree, hf_usb_request_in, tvb, 0, 0, usb_trans_info->request_in); + proto_item_set_generated(ti); + + t = pinfo->abs_ts; + nstime_delta(&deltat, &t, &usb_trans_info->req_time); + ti = proto_tree_add_time(tree, hf_usb_time, tvb, 0, 0, &deltat); + proto_item_set_generated(ti); + } + } + + return usb_trans_info; +} + + +/* dissect a group of isochronous packets inside an usb packet in + usbpcap format */ +#define MAX_ISO_PACKETS 100000 // Arbitrary +static gint +dissect_usbpcap_iso_packets(packet_info *pinfo _U_, proto_tree *urb_tree, guint8 urb_type, + tvbuff_t *tvb, gint offset, guint32 win32_data_len, usb_conv_info_t *usb_conv_info) +{ + guint32 i; + guint32 num_packets; + int data_start_offset; + proto_item *num_packets_ti, *urb_tree_ti; + + proto_tree_add_item(urb_tree, hf_usb_win32_iso_start_frame, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + num_packets = tvb_get_letohl(tvb, offset); + num_packets_ti = proto_tree_add_item(urb_tree, hf_usb_win32_iso_num_packets, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(urb_tree, hf_usb_win32_iso_error_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + if (num_packets > MAX_ISO_PACKETS) { + expert_add_info_format(pinfo, num_packets_ti, &ei_usb_bad_length, "Too many isochronous transfer packets (%u)", num_packets); + return tvb_captured_length(tvb); + } + + data_start_offset = offset + 12 * num_packets; + urb_tree_ti = proto_tree_get_parent(urb_tree); + proto_item_set_len(urb_tree_ti, data_start_offset); + + for (i = 0; i < num_packets; i++) { + guint32 this_offset; + guint32 next_offset; + guint32 iso_len; + proto_item *iso_packet_ti, *ti; + proto_tree *iso_packet_tree; + + iso_packet_ti = proto_tree_add_protocol_format( + proto_tree_get_root(urb_tree), proto_usb, + tvb, offset, 12, "USB isochronous packet"); + iso_packet_tree = proto_item_add_subtree(iso_packet_ti, ett_usb_win32_iso_packet); + + this_offset = tvb_get_letohl(tvb, offset); + if (num_packets - i == 1) { + /* this is the last packet */ + next_offset = win32_data_len; + } else { + /* there is next packet */ + next_offset = tvb_get_letohl(tvb, offset + 12); + } + + if (next_offset > this_offset) { + iso_len = next_offset - this_offset; + } else { + iso_len = 0; + } + + /* If this packet does not contain isochrounous data, do not try to display it */ + if (!((usb_conv_info->is_request && usb_conv_info->direction==P2P_DIR_SENT) || + (!usb_conv_info->is_request && usb_conv_info->direction==P2P_DIR_RECV))) { + iso_len = 0; + } + + proto_tree_add_item(iso_packet_tree, hf_usb_win32_iso_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + ti = proto_tree_add_item(iso_packet_tree, hf_usb_win32_iso_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + if (usb_conv_info->direction==P2P_DIR_SENT) { + /* Isochronous OUT transfer */ + proto_item_append_text(ti, " (not used)"); + } else { + /* Isochronous IN transfer. + * Length field is being set by host controller. + */ + if (usb_conv_info->is_request) { + /* Length was not yet set */ + proto_item_append_text(ti, " (irrelevant)"); + } else { + /* Length was set and (should be) valid */ + proto_item_append_text(ti, " (relevant)"); + iso_len = tvb_get_letohl(tvb, offset); + } + } + offset += 4; + + ti = proto_tree_add_item(iso_packet_tree, hf_usb_win32_iso_status, tvb, offset, 4, ENC_LITTLE_ENDIAN); + if (urb_type == URB_SUBMIT) { + proto_item_append_text(ti, " (irrelevant)"); + } else { + proto_item_append_text(ti, " (relevant)"); + } + offset += 4; + + if (iso_len && data_start_offset + this_offset + iso_len <= tvb_captured_length(tvb)) { + proto_tree_add_item(iso_packet_tree, hf_usb_iso_data, tvb, (gint)(data_start_offset + this_offset), (gint)iso_len, ENC_NA); + proto_tree_set_appendix(iso_packet_tree, tvb, (gint)(data_start_offset + this_offset), (gint)iso_len); + } + } + + if ((usb_conv_info->is_request && usb_conv_info->direction==P2P_DIR_SENT) || + (!usb_conv_info->is_request && usb_conv_info->direction==P2P_DIR_RECV)) { + /* We have dissected all the isochronous data */ + offset += win32_data_len; + } + + return offset; +} + + +static gint +dissect_linux_usb_iso_transfer(packet_info *pinfo _U_, proto_tree *urb_tree, + usb_header_t header_type, tvbuff_t *tvb, gint offset, + usb_conv_info_t *usb_conv_info) +{ + guint32 iso_numdesc = 0; + proto_item *tii; + guint32 i; + guint data_base; + guint32 iso_status; + guint32 iso_off = 0; + guint32 iso_len = 0; + + tii = proto_tree_add_uint(urb_tree, hf_usb_bInterfaceClass, tvb, offset, 0, usb_conv_info->interfaceClass); + proto_item_set_generated(tii); + + /* All fields which belong to Linux usbmon headers are in host-endian + * byte order. The fields coming from the USB communication are in little + * endian format (see usb_20.pdf, chapter 8.1 Byte/Bit ordering). + * + * When a capture file is transferred to a host with different endianness + * than packet was captured then the necessary swapping happens in + * wiretap/pcap-common.c, pcap_byteswap_linux_usb_pseudoheader(). + */ + + /* iso urbs on linux can't possibly contain a setup packet + see mon_bin_event() in the linux kernel */ + + proto_tree_add_item(urb_tree, hf_usb_iso_error_count, tvb, offset, 4, ENC_HOST_ENDIAN); + offset += 4; + + proto_tree_add_item_ret_uint(urb_tree, hf_usb_iso_numdesc, tvb, offset, 4, ENC_HOST_ENDIAN, &iso_numdesc); + offset += 4; + + if (header_type == USB_HEADER_LINUX_64_BYTES) { + offset = dissect_linux_usb_pseudo_header_ext(tvb, offset, pinfo, urb_tree); + } + + data_base = offset + iso_numdesc*16; + for (i = 0; i<iso_numdesc; i++) { + proto_item *iso_desc_ti; + proto_tree *iso_desc_tree; + + iso_desc_ti = proto_tree_add_protocol_format(urb_tree, proto_usb, tvb, offset, + 16, "USB isodesc %u", i); + iso_desc_tree = proto_item_add_subtree(iso_desc_ti, ett_usb_isodesc); + + proto_tree_add_item_ret_int(iso_desc_tree, hf_usb_iso_status, tvb, offset, 4, ENC_HOST_ENDIAN, &iso_status); + proto_item_append_text(iso_desc_ti, " [%s]", val_to_str_ext(iso_status, &linux_negative_errno_vals_ext, "Error %d")); + offset += 4; + + proto_tree_add_item_ret_uint(iso_desc_tree, hf_usb_iso_off, tvb, offset, 4, ENC_HOST_ENDIAN, &iso_off); + offset += 4; + + proto_tree_add_item_ret_uint(iso_desc_tree, hf_usb_iso_len, tvb, offset, 4, ENC_HOST_ENDIAN, &iso_len); + if (iso_len != 0) + proto_item_append_text(iso_desc_ti, " (%u bytes)", iso_len); + offset += 4; + + /* Show the ISO data if we captured them and either the status + is OK or the packet is sent from host to device. + The Linux kernel sets the status field in outgoing isochronous + URBs to -EXDEV and fills the data part with valid data. + */ + if ((pinfo->p2p_dir==P2P_DIR_SENT || !iso_status) && + iso_len && data_base + iso_off + iso_len <= tvb_captured_length(tvb)) { + proto_tree_add_item(iso_desc_tree, hf_usb_iso_data, tvb, data_base + iso_off, iso_len, ENC_NA); + proto_tree_set_appendix(iso_desc_tree, tvb, (gint)(data_base+iso_off), (gint)iso_len); + } + + proto_tree_add_item(iso_desc_tree, hf_usb_iso_pad, tvb, offset, 4, ENC_HOST_ENDIAN); + offset += 4; + } + + /* we jump to the end of the last iso data chunk + this assumes that the iso data starts immediately after the + iso descriptors + we have to use the offsets from the last iso descriptor, we can't keep + track of the offset ourselves as there may be gaps + between data packets in the transfer buffer */ + return data_base+iso_off+iso_len; +} + +static gint +dissect_usbip_iso_transfer(packet_info *pinfo _U_, proto_tree *urb_tree, + tvbuff_t *tvb, gint offset, guint32 iso_numdesc, guint32 desc_offset, + usb_conv_info_t *usb_conv_info) +{ + proto_item *tii; + guint32 i; + guint data_base; + guint32 iso_off = 0; + guint32 iso_len = 0; + + tii = proto_tree_add_uint(urb_tree, hf_usb_bInterfaceClass, tvb, offset, 0, usb_conv_info->interfaceClass); + proto_item_set_generated(tii); + + /* All fields which belong to usbip are in big-endian byte order. + * unlike the linux kernel, the usb isoc descriptor is appended at + * the end of the isoc data. We have to reassemble the pdus and jump + * to the end (actual_length) and the remaining data is the isoc + * descriptor. + */ + + data_base = offset; + for (i = 0; i<iso_numdesc; i++) { + proto_item *iso_desc_ti; + proto_tree *iso_desc_tree; + gint32 iso_status; + + iso_desc_ti = proto_tree_add_protocol_format(urb_tree, proto_usb, tvb, desc_offset, + 16, "USB isodesc %u", i); + iso_desc_tree = proto_item_add_subtree(iso_desc_ti, ett_usb_isodesc); + + proto_tree_add_item_ret_uint(iso_desc_tree, hf_usb_iso_off, tvb, desc_offset, 4, ENC_BIG_ENDIAN, &iso_off); + desc_offset += 4; + + proto_tree_add_item(iso_desc_tree, hf_usb_iso_len, tvb, desc_offset, 4, ENC_BIG_ENDIAN); + desc_offset += 4; + + proto_tree_add_item_ret_uint(iso_desc_tree, hf_usb_iso_actual_len, tvb, desc_offset, 4, ENC_BIG_ENDIAN, &iso_len); + desc_offset += 4; + + proto_tree_add_item_ret_int(iso_desc_tree, hf_usb_iso_status, tvb, desc_offset, 4, ENC_BIG_ENDIAN, &iso_status); + proto_item_append_text(iso_desc_ti, " [%s]", val_to_str_ext(iso_status, &linux_negative_errno_vals_ext, "Error %d")); + desc_offset += 4; + + if (iso_len > 0) + proto_item_append_text(iso_desc_ti, " (%u bytes)", iso_len); + + /* Show the ISO data if we captured them and either the status + is OK or the packet is sent from host to device. + The Linux kernel sets the status field in outgoing isochronous + URBs to -EXDEV and fills the data part with valid data. + */ + if ((pinfo->p2p_dir==P2P_DIR_SENT || !iso_status) && + iso_len && data_base + iso_off + iso_len <= tvb_reported_length(tvb)) { + proto_tree_add_item(iso_desc_tree, hf_usb_iso_data, tvb, (guint) data_base + iso_off, iso_len, ENC_NA); + proto_tree_set_appendix(iso_desc_tree, tvb, (guint) data_base + iso_off, (gint)iso_len); + } + } + return desc_offset; +} + +static gint +dissect_darwin_usb_iso_transfer(packet_info *pinfo _U_, proto_tree *tree, usb_header_t header_type _U_, + guint8 urb_type _U_, tvbuff_t *tvb, gint32 offset, usb_conv_info_t *usb_conv_info) +{ + guint32 frame_length; + guint32 frame_header_length; + guint32 status; + guint32 iso_tree_start; + guint32 i; + guint32 iso_numdesc; + guint32 len; + proto_item *tii; + + len = (gint32)tvb_captured_length(tvb); + len -= offset; + + tii = proto_tree_add_uint(tree, hf_usb_bInterfaceClass, tvb, offset, 0, usb_conv_info->interfaceClass); + proto_item_set_generated(tii); + + status = tvb_get_guint32(tvb, 8, ENC_LITTLE_ENDIAN); + iso_numdesc = tvb_get_guint32(tvb, 12, ENC_LITTLE_ENDIAN); + + iso_tree_start = offset; + for (i = 0; (i < iso_numdesc) && (len > 8 /* header len + frame len */); i++) { + proto_item *iso_desc_ti; + proto_tree *iso_desc_tree; + + /* Fetch ISO descriptor fields stored in little-endian byte order. */ + frame_header_length = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN); + frame_length = tvb_get_guint32(tvb, offset + 4, ENC_LITTLE_ENDIAN); + + if ((len < frame_header_length) || (frame_header_length < 20)) { + break; + } + + iso_desc_ti = proto_tree_add_protocol_format(tree, proto_usb, tvb, offset, + 20, "Frame %u", i); + + iso_desc_tree = proto_item_add_subtree(iso_desc_ti, ett_usb_isodesc); + + proto_tree_add_item(iso_desc_tree, hf_usb_darwin_iso_frame_number, tvb, offset + 12, 8, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(iso_desc_tree, hf_usb_iso_len, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN); + + if (usb_conv_info->is_request == FALSE) { + proto_tree_add_item(iso_desc_tree, hf_usb_darwin_iso_timestamp, tvb, offset + 20, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item_ret_uint(iso_desc_tree, hf_usb_darwin_iso_status, tvb, offset + 8, 4, ENC_LITTLE_ENDIAN, &status); + + proto_item_append_text(iso_desc_ti, " [%s]", val_to_str_ext(status, &usb_darwin_status_vals_ext, "Error %d")); + + /* Data */ + if (frame_length > len) { + frame_length = len; + } + + proto_tree_add_item(iso_desc_tree, hf_usb_iso_data, tvb, offset + frame_header_length, frame_length, ENC_NA); + proto_tree_set_appendix(iso_desc_tree, tvb, (gint)iso_tree_start, (gint)(offset - iso_tree_start)); + + len -= frame_length; + offset += frame_length; + } + + /* Padding to align the next header */ + offset += frame_header_length; + offset = WS_ROUNDUP_4(offset); + iso_tree_start = offset; + + len -= frame_header_length; + } + + return offset; +} + +static gint +dissect_usb_payload(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *parent, proto_tree *tree, + usb_conv_info_t *usb_conv_info, guint8 urb_type, + gint offset, guint16 device_address) +{ + wmem_tree_key_t key[4]; + guint32 k_frame_number; + guint32 k_device_address; + guint32 k_bus_id; + device_product_data_t *device_product_data = NULL; + device_protocol_data_t *device_protocol_data = NULL; + tvbuff_t *next_tvb = NULL; + + k_frame_number = pinfo->num; + k_device_address = device_address; + k_bus_id = usb_conv_info->bus_id; + + key[0].length = 1; + key[0].key = &k_device_address; + key[1].length = 1; + key[1].key = &k_bus_id; + key[2].length = 1; + key[2].key = &k_frame_number; + key[3].length = 0; + key[3].key = NULL; + + device_product_data = (device_product_data_t *) wmem_tree_lookup32_array_le(device_to_product_table, key); + if (device_product_data && device_product_data->bus_id == usb_conv_info->bus_id && + device_product_data->device_address == device_address) { + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_VENDOR_ID, GUINT_TO_POINTER((guint)device_product_data->vendor)); + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_PRODUCT_ID, GUINT_TO_POINTER((guint)device_product_data->product)); + usb_conv_info->deviceVendor = device_product_data->vendor; + usb_conv_info->deviceProduct = device_product_data->product; + usb_conv_info->deviceVersion = device_product_data->device; + } + + device_protocol_data = (device_protocol_data_t *) wmem_tree_lookup32_array_le(device_to_protocol_table, key); + if (device_protocol_data && device_protocol_data->bus_id == usb_conv_info->bus_id && + device_protocol_data->device_address == device_address) { + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_CLASS, GUINT_TO_POINTER(device_protocol_data->protocol >> 16)); + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_SUBCLASS, GUINT_TO_POINTER((device_protocol_data->protocol >> 8) & 0xFF)); + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_PROTOCOL, GUINT_TO_POINTER(device_protocol_data->protocol & 0xFF)); + usb_conv_info->device_protocol = device_protocol_data->protocol; + } + + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_BUS_ID, GUINT_TO_POINTER((guint)usb_conv_info->bus_id)); + p_add_proto_data(pinfo->pool, pinfo, proto_usb, USB_DEVICE_ADDRESS, GUINT_TO_POINTER((guint)device_address)); + + if (tvb_captured_length_remaining(tvb, offset) > 0) { + next_tvb = tvb_new_subset_remaining(tvb, offset); + offset += try_dissect_next_protocol(parent, next_tvb, pinfo, usb_conv_info, urb_type, tree, NULL); + } + + if (tvb_captured_length_remaining(tvb, offset) > 0) { + /* There is still leftover capture data to add (padding?) */ + proto_tree_add_item(parent, hf_usb_capdata, tvb, offset, -1, ENC_NA); + } + + return offset; +} + +static int +dissect_freebsd_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, void *data _U_) +{ + int offset = 0; + proto_item *ti; + proto_tree *tree = NULL, *frame_tree = NULL; + guint32 nframes; + guint32 i; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "USB"); + + /* add usb hdr*/ + if (parent) { + ti = proto_tree_add_protocol_format(parent, proto_usb, tvb, 0, 128, + "USB URB"); + tree = proto_item_add_subtree(ti, ett_usb_hdr); + } + + proto_tree_add_item(tree, hf_usb_totlen, tvb, 0, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_busunit, tvb, 4, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_address, tvb, 8, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_mode, tvb, 9, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_freebsd_urb_type, tvb, 10, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_freebsd_transfer_type, tvb, 11, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_bitmask(tree, tvb, 12, hf_usb_xferflags, ett_usb_xferflags, + usb_xferflags_fields, ENC_LITTLE_ENDIAN); + proto_tree_add_bitmask(tree, tvb, 16, hf_usb_xferstatus, ett_usb_xferstatus, + usb_xferstatus_fields, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_error, tvb, 20, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_interval, tvb, 24, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item_ret_uint(tree, hf_usb_nframes, tvb, 28, 4, ENC_LITTLE_ENDIAN, &nframes); + proto_tree_add_item(tree, hf_usb_packet_size, tvb, 32, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_usb_packet_count, tvb, 36, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_bitmask(tree, tvb, 40, hf_usb_endpoint_address, ett_usb_endpoint, usb_endpoint_fields, ENC_NA); + proto_tree_add_item(tree, hf_usb_speed, tvb, 44, 1, ENC_LITTLE_ENDIAN); + + offset += 128; + for (i = 0; i < nframes; i++) { + guint32 framelen; + guint64 frameflags; + + frame_tree = proto_tree_add_subtree_format(tree, tvb, offset, -1, + ett_usb_frame, &ti, + "Frame %u", i); + proto_tree_add_item_ret_uint(frame_tree, hf_usb_frame_length, + tvb, offset, 4, ENC_LITTLE_ENDIAN, + &framelen); + offset += 4; + proto_tree_add_bitmask_ret_uint64(frame_tree, tvb, offset, + hf_usb_frame_flags, + ett_usb_frame_flags, + usb_frame_flags_fields, + ENC_LITTLE_ENDIAN, &frameflags); + offset += 4; + if (frameflags & FREEBSD_FRAMEFLAG_DATA_FOLLOWS) { + /* + * XXX - ultimately, we should dissect this data. + */ + proto_tree_add_item(frame_tree, hf_usb_frame_data, tvb, offset, + framelen, ENC_NA); + offset += WS_ROUNDUP_4(framelen); + } + proto_item_set_end(ti, tvb, offset); + } + + return tvb_captured_length(tvb); +} + +static int +netmon_HostController2(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 flags) +{ + proto_tree *host_tree; + + host_tree = proto_tree_add_subtree(tree, tvb, offset, (flags & EVENT_HEADER_FLAG_64_BIT_HEADER) ? 20 : 16, ett_usbport_host_controller, NULL, "HostController"); + netmon_etl_field(host_tree, tvb, &offset, hf_usbport_device_object, flags); + + proto_tree_add_item(host_tree, hf_usbport_pci_bus, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(host_tree, hf_usbport_pci_device, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(host_tree, hf_usbport_pci_function, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(host_tree, hf_usbport_pci_vendor_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(host_tree, hf_usbport_pci_device_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +netmon_UsbPortPath(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo) +{ + proto_item *path_item, *depth_item; + proto_tree *path_tree; + guint32 path_depth, path0, path1, path2, path3, path4, path5; + + path_tree = proto_tree_add_subtree(tree, tvb, offset, 28, ett_usbport_path, &path_item, "PortPath: "); + depth_item = proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path_depth); + offset += 4; + proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path0, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path0); + offset += 4; + proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path1, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path1); + offset += 4; + proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path2, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path2); + offset += 4; + proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path3, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path3); + offset += 4; + proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path4, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path4); + offset += 4; + proto_tree_add_item_ret_uint(path_tree, hf_usbport_port_path5, tvb, offset, 4, ENC_LITTLE_ENDIAN, &path5); + offset += 4; + if (path_depth == 0) { + proto_item_append_text(path_item, "-"); + } + if (path_depth > 0) { + proto_item_append_text(path_item, "%d", path0); + } + if (path_depth > 1) { + proto_item_append_text(path_item, ",%d", path1); + } + if (path_depth > 2) { + proto_item_append_text(path_item, ",%d", path2); + } + if (path_depth > 3) { + proto_item_append_text(path_item, ",%d", path3); + } + if (path_depth > 4) { + proto_item_append_text(path_item, ",%d", path4); + } + if (path_depth > 5) { + proto_item_append_text(path_item, ",%d", path5); + } + if (path_depth > 6) { + expert_add_info(pinfo, depth_item, &ei_usbport_invalid_path_depth); + } + + return offset; +} + +static int +netmon_fid_USBPORT_Device(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 flags, packet_info *pinfo) +{ + proto_item *device_item; + proto_tree *device_tree; + + device_tree = proto_tree_add_subtree(tree, tvb, offset, 4, ett_usbport_device, &device_item, "Device"); + netmon_etl_field(device_tree, tvb, &offset, hf_usbport_device_handle, flags); + proto_tree_add_item(device_tree, hf_usb_idVendor, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(device_tree, hf_usb_idProduct, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + offset = netmon_UsbPortPath(device_tree, tvb, offset, pinfo); + proto_tree_add_item(device_tree, hf_usbport_device_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(device_tree, hf_usb_device_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + return offset; +} + +static int +netmon_fid_USBPORT_Endpoint(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 flags) +{ + proto_tree *endpoint_tree; + + endpoint_tree = proto_tree_add_subtree(tree, tvb, offset, (flags & EVENT_HEADER_FLAG_64_BIT_HEADER) ? 24 : 12, ett_usbport_endpoint, NULL, "Endpoint"); + netmon_etl_field(endpoint_tree, tvb, &offset, hf_usbport_endpoint, flags); + netmon_etl_field(endpoint_tree, tvb, &offset, hf_usbport_pipehandle, flags); + netmon_etl_field(endpoint_tree, tvb, &offset, hf_usbport_device_handle, flags); + + return offset; +} + +static int +netmon_fid_USBPORT_Endpoint_Descriptor(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_tree *endpoint_desc_tree; + + endpoint_desc_tree = proto_tree_add_subtree(tree, tvb, offset, 7, ett_usbport_endpoint_desc, NULL, "Endpoint Descriptor"); + proto_tree_add_item(endpoint_desc_tree, hf_usbport_endpoint_desc_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(endpoint_desc_tree, hf_usbport_endpoint_desc_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(endpoint_desc_tree, hf_usbport_endpoint_address, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(endpoint_desc_tree, hf_usbport_bm_attributes, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(endpoint_desc_tree, hf_usbport_max_packet_size, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(endpoint_desc_tree, hf_usbport_interval, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + return offset; +} + +static int +netmon_URB(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 flags) +{ + proto_item *urb_item; + proto_tree *urb_tree; + guint32 func; + int i, start_offset = offset; + + urb_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_usbport_urb, &urb_item, "URB"); + proto_tree_add_item(urb_tree, hf_usbport_urb_header_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item_ret_uint(urb_tree, hf_usbport_urb_header_function, tvb, offset, 2, ENC_LITTLE_ENDIAN, &func); + proto_item_append_text(urb_item, ": %s", val_to_str_ext_const(func, &netmon_urb_function_vals_ext, "Unknown")); + offset += 2; + proto_tree_add_item(urb_tree, hf_usbport_urb_header_status, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_header_usbddevice_handle, flags); + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_header_usbdflags, flags); + + switch (func) + { + case 0x0000: + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_configuration_desc, flags); + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_configuration_handle, flags); + break; + case 0x0008: //URB_FUNCTION_CONTROL_TRANSFER + case 0x0009: //URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER + case 0x000A: //URB_FUNCTION_ISOCH_TRANSFER + case 0x000B: //URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE + case 0x000C: //URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE + case 0x000D: //URB_FUNCTION_SET_FEATURE_TO_DEVICE + case 0x000E: //URB_FUNCTION_SET_FEATURE_TO_INTERFACE + case 0x000F: //URB_FUNCTION_SET_FEATURE_TO_ENDPOINT + case 0x0010: //URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE + case 0x0011: //URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE + case 0x0012: //URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT + case 0x0013: //URB_FUNCTION_GET_STATUS_FROM_DEVICE + case 0x0014: //URB_FUNCTION_GET_STATUS_FROM_INTERFACE + case 0x0015: //URB_FUNCTION_GET_STATUS_FROM_ENDPOINT + case 0x0017: //URB_FUNCTION_VENDOR_DEVICE + case 0x0018: //URB_FUNCTION_VENDOR_INTERFACE + case 0x0019: //URB_FUNCTION_VENDOR_ENDPOINT + case 0x001A: //URB_FUNCTION_CLASS_DEVICE + case 0x001B: //URB_FUNCTION_CLASS_INTERFACE + case 0x001C: //URB_FUNCTION_CLASS_ENDPOINT + case 0x001F: //URB_FUNCTION_CLASS_OTHER + case 0x0020: //URB_FUNCTION_VENDOR_OTHER + case 0x0021: //URB_FUNCTION_GET_STATUS_FROM_OTHER + case 0x0022: //URB_FUNCTION_CLEAR_FEATURE_TO_OTHER + case 0x0023: //URB_FUNCTION_SET_FEATURE_TO_OTHER + case 0x0024: //URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT + case 0x0025: //URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT + case 0x0026: //URB_FUNCTION_GET_CONFIGURATION + case 0x0027: //URB_FUNCTION_GET_INTERFACE + case 0x0028: //URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE + case 0x0029: //URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE + case 0x002A: //URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR + case 0x0032: //URB_FUNCTION_CONTROL_TRANSFER_EX + case 0x0037: //URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER_USING_CHAINED_MDL + case 0x0038: //URB_FUNCTION_ISOCH_TRANSFER_USING_CHAINED_MDL + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_pipe_handle, flags); + proto_tree_add_bitmask(urb_tree, tvb, offset, hf_usbport_urb_xferflags, ett_usb_xferflags, + usb_xferflags_fields, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(urb_tree, hf_usbport_urb_transfer_buffer_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_transfer_buffer, flags); + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_transfer_buffer_mdl, flags); + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_reserved_mbz, flags); + for (i = 0; i < 8; i++) + { + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_reserved_hcd, flags); + } + break; + + case 0x0002: //URB_FUNCTION_ABORT_PIPE + case 0x001E: //URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL + case 0x0030: //URB_FUNCTION_SYNC_RESET_PIPE + case 0x0031: //URB_FUNCTION_SYNC_CLEAR_STALL + case 0x0036: //URB_FUNCTION_CLOSE_STATIC_STREAMS + netmon_etl_field(urb_tree, tvb, &offset, hf_usbport_urb_pipe_handle, flags); + proto_tree_add_item(urb_tree, hf_usbport_urb_reserved, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + } + + proto_item_set_len(urb_item, offset-start_offset); + return offset; +} + +#define USBPORT_KEYWORD_DIAGNOSTIC G_GUINT64_CONSTANT(0x0000000000000001) +#define USBPORT_KEYWORD_POWER_DIAGNOSTICS G_GUINT64_CONSTANT(0x0000000000000002) +#define USBPORT_KEYWORD_PERF_DIAGNOSTICS G_GUINT64_CONSTANT(0x0000000000000004) +#define USBPORT_KEYWORD_RESERVED1 G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFF8) + +static int +dissect_netmon_usb_port(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, void* data) +{ + proto_item *ti, *generated; + proto_tree *usb_port_tree; + int offset = 0; + struct netmon_provider_id_data *provider_id_data = (struct netmon_provider_id_data*)data; + static int * const keyword_fields[] = { + &hf_usbport_keyword_diagnostic, + &hf_usbport_keyword_power_diagnostics, + &hf_usbport_keyword_perf_diagnostics, + &hf_usbport_keyword_reserved1, + NULL + }; + + DISSECTOR_ASSERT(provider_id_data != NULL); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBPort"); + col_clear(pinfo->cinfo, COL_INFO); + + ti = proto_tree_add_item(parent, proto_usbport, tvb, 0, -1, ENC_NA); + usb_port_tree = proto_item_add_subtree(ti, ett_usbport); + + generated = proto_tree_add_uint(usb_port_tree, hf_usbport_event_id, tvb, 0, 0, provider_id_data->event_id); + proto_item_set_generated(generated); + generated = proto_tree_add_bitmask_value(usb_port_tree, tvb, 0, hf_usbport_keyword, ett_usbport_keyword, keyword_fields, provider_id_data->keyword); + proto_item_set_generated(generated); + + switch (provider_id_data->event_id) + { + case 71: + offset = netmon_HostController2(usb_port_tree, tvb, offset, provider_id_data->event_flags); + offset = netmon_fid_USBPORT_Device(usb_port_tree, tvb, offset, provider_id_data->event_flags, pinfo); + offset = netmon_fid_USBPORT_Endpoint(usb_port_tree, tvb, offset, provider_id_data->event_flags); + offset = netmon_fid_USBPORT_Endpoint_Descriptor(usb_port_tree, tvb, offset); + netmon_etl_field(usb_port_tree, tvb, &offset, hf_usbport_irp, provider_id_data->event_flags); + netmon_etl_field(usb_port_tree, tvb, &offset, hf_usbport_urb, provider_id_data->event_flags); + offset = netmon_URB(usb_port_tree, tvb, offset, provider_id_data->event_flags); + proto_tree_add_item(usb_port_tree, hf_usbport_urb_transfer_data, tvb, offset, 2, ENC_LITTLE_ENDIAN); + break; + } + + return tvb_captured_length(tvb); +} + +void +dissect_usb_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, + usb_header_t header_type, void *extra_data) +{ + gint offset = 0; + int endpoint; + guint8 urb_type; + guint32 win32_data_len = 0; + guint32 iso_numdesc = 0; + guint32 desc_offset = 0; + guint32 location = 0; + proto_item *urb_tree_ti; + proto_tree *tree; + proto_item *item; + usb_conv_info_t *usb_conv_info; + conversation_t *conversation; + guint16 device_address; + guint16 bus_id; + guint8 usbpcap_control_stage = 0; + guint64 usb_id; + struct mausb_header *ma_header = NULL; + struct usbip_header *ip_header = NULL; + usb_pseudo_urb_t *pseudo_urb = NULL; + + /* the goal is to get the conversation struct as early as possible + and store all status values in this struct + at first, we read the fields required to create/identify + the right conversation struct */ + switch (header_type) { + + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + urb_type = tvb_get_guint8(tvb, 8); + endpoint = tvb_get_guint8(tvb, 10) & 0x7F; + device_address = (guint16)tvb_get_guint8(tvb, 11); + bus_id = tvb_get_letohs(tvb, 12); + break; + + case USB_HEADER_USBPCAP: + urb_type = tvb_get_guint8(tvb, 16) & 0x01 ? URB_COMPLETE : URB_SUBMIT; + device_address = tvb_get_letohs(tvb, 19); + endpoint = tvb_get_guint8(tvb, 21); + if ((endpoint == 0x00) && (tvb_get_guint8(tvb, 22) == URB_CONTROL) && + (tvb_get_guint8(tvb, 27) == USB_CONTROL_STAGE_DATA)) { + /* USBPcap before 1.3.0.0 DATA OUT packet (the info at offset 16 is wrong) */ + urb_type = URB_SUBMIT; + } + endpoint &= 0x7F; /* Clear the direction flag */ + bus_id = tvb_get_letohs(tvb, 17); + break; + + case USB_HEADER_MAUSB: + ma_header = (struct mausb_header *) extra_data; + urb_type = mausb_is_from_host(ma_header) ? URB_SUBMIT : URB_COMPLETE; + device_address = mausb_ep_handle_dev_addr(ma_header->handle); + endpoint = mausb_ep_handle_ep_num(ma_header->handle); + bus_id = mausb_ep_handle_bus_num(ma_header->handle); + break; + + case USB_HEADER_USBIP: + ip_header = (struct usbip_header *) extra_data; + urb_type = tvb_get_ntohl(tvb, 0) == 1 ? URB_SUBMIT : URB_COMPLETE; + device_address = ip_header->devid; + bus_id = ip_header->busid; + endpoint = ip_header->ep; + break; + + case USB_HEADER_DARWIN: + urb_type = tvb_get_guint8(tvb, 3) ? URB_COMPLETE : URB_SUBMIT; + endpoint = tvb_get_guint8(tvb, 30) & 0x7F; + device_address = (guint16)tvb_get_guint8(tvb, 29); + location = tvb_get_letohl(tvb, 24); + bus_id = location >> 24; + break; + + case USB_HEADER_PSEUDO_URB: + pseudo_urb = (usb_pseudo_urb_t *) extra_data; + urb_type = pseudo_urb->from_host ? URB_SUBMIT : URB_COMPLETE; + device_address = pseudo_urb->device_address; + endpoint = pseudo_urb->endpoint; + bus_id = pseudo_urb->bus_id; + break; + + default: + return; /* invalid USB pseudo header */ + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "USB"); + urb_tree_ti = proto_tree_add_protocol_format(parent, proto_usb, tvb, 0, -1, "USB URB"); + tree = proto_item_add_subtree(urb_tree_ti, ett_usb_hdr); + + usb_set_addr(tree, tvb, pinfo, bus_id, device_address, endpoint, + (urb_type == URB_SUBMIT)); + + conversation = get_usb_conversation(pinfo, &pinfo->src, &pinfo->dst, pinfo->srcport, pinfo->destport); + usb_conv_info = get_usb_conv_info(conversation); + clear_usb_conv_tmp_data(usb_conv_info); + + + switch (header_type) { + + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + proto_item_set_len(urb_tree_ti, (header_type == USB_HEADER_LINUX_64_BYTES) ? 64 : 48); + offset = dissect_linux_usb_pseudo_header(tvb, pinfo, tree, usb_conv_info, &usb_id); + break; + + case USB_HEADER_USBPCAP: + offset = dissect_usbpcap_buffer_packet_header(tvb, pinfo, tree, usb_conv_info, &win32_data_len, &usb_id); + /* the length that we're setting here might have to be corrected + if there's a transfer-specific pseudo-header following */ + proto_item_set_len(urb_tree_ti, offset); + break; + + case USB_HEADER_MAUSB: + /* MA USB header gets dissected earlier, just set conversation variables */ + offset = MAUSB_DPH_LENGTH; + mausb_set_usb_conv_info(usb_conv_info, ma_header); + usb_id = 0; + break; + + case USB_HEADER_USBIP: + iso_numdesc = tvb_get_ntohl(tvb, 0x20); + usb_conv_info->transfer_type = endpoint == 0 ? URB_CONTROL : (iso_numdesc != 0xffffffff ? URB_ISOCHRONOUS : URB_UNKNOWN); + usb_conv_info->direction = ip_header->dir == USBIP_DIR_OUT ? P2P_DIR_SENT : P2P_DIR_RECV; + usb_conv_info->is_setup = endpoint == 0 ? (tvb_get_ntoh64(tvb, 0x28) != G_GUINT64_CONSTANT(0)) : FALSE; + usb_conv_info->is_request = (urb_type==URB_SUBMIT); + offset = usb_conv_info->is_setup ? USBIP_HEADER_WITH_SETUP_LEN : USBIP_HEADER_LEN; + + /* The ISOC descriptor is located at the end of the isoc frame behind the isoc data. */ + if ((usb_conv_info->is_request && usb_conv_info->direction == USBIP_DIR_OUT) || + (!usb_conv_info->is_request && usb_conv_info->direction == USBIP_DIR_IN)) { + desc_offset += tvb_get_ntohl(tvb, 0x18); + } + + desc_offset += offset; + usb_id = 0; + break; + + case USB_HEADER_DARWIN: + offset = dissect_darwin_buffer_packet_header(tvb, pinfo, tree, usb_conv_info, &usb_id); + proto_item_set_len(urb_tree_ti, offset); + break; + + case USB_HEADER_PSEUDO_URB: + usb_conv_info->transfer_type = pseudo_urb->transfer_type; + usb_conv_info->direction = pseudo_urb->from_host ? P2P_DIR_SENT : P2P_DIR_RECV; + usb_conv_info->is_setup = pseudo_urb->from_host && (pseudo_urb->transfer_type == URB_CONTROL); + usb_conv_info->is_request = pseudo_urb->from_host; + usb_conv_info->speed = pseudo_urb->speed; + usb_id = 0; + break; + + default: + usb_id = 0; + break; + } + + usb_conv_info->usb_trans_info = usb_get_trans_info(tvb, pinfo, tree, header_type, usb_conv_info, usb_id); + + if (usb_conv_info->transfer_type != URB_CONTROL) { + usb_tap_queue_packet(pinfo, urb_type, usb_conv_info); + } + + switch(usb_conv_info->transfer_type) { + case URB_BULK: + case URB_INTERRUPT: + item = proto_tree_add_uint(tree, hf_usb_bInterfaceClass, tvb, 0, 0, usb_conv_info->interfaceClass); + proto_item_set_generated(item); + + switch (header_type) { + + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + /* bulk and interrupt transfers never contain a setup packet */ + proto_tree_add_item(tree, hf_usb_urb_unused_setup_header, tvb, offset, 8, ENC_NA); + offset += 8; + if (header_type == USB_HEADER_LINUX_64_BYTES) { + offset = dissect_linux_usb_pseudo_header_ext(tvb, offset, pinfo, tree); + } + break; + + case USB_HEADER_USBPCAP: + break; + + case USB_HEADER_MAUSB: + break; + + case USB_HEADER_USBIP: + break; + + case USB_HEADER_DARWIN: + break; + + case USB_HEADER_PSEUDO_URB: + break; + } + break; + + case URB_CONTROL: + if (header_type == USB_HEADER_USBPCAP) { + proto_tree_add_item(tree, hf_usb_win32_control_stage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + usbpcap_control_stage = tvb_get_guint8(tvb, offset); + offset++; + proto_item_set_len(urb_tree_ti, offset); + if (usbpcap_control_stage == USB_CONTROL_STAGE_SETUP) { + usb_conv_info->is_setup = TRUE; + } else if (usbpcap_control_stage == USB_CONTROL_STAGE_DATA && urb_type == URB_SUBMIT) { + /* USBPcap before 1.5.0.0 */ + wmem_tree_key_t key[3]; + key[0].length = 2; + key[0].key = (guint32 *)&usb_id; + key[1].length = 1; + key[1].key = &pinfo->num; + key[2].length = 0; + key[2].key = NULL; + usbpcap_setup_data_t *setup_data = (usbpcap_setup_data_t *)wmem_tree_lookup32_array_le(usbpcap_setup_data, key); + if (setup_data && setup_data->usb_id == usb_id) { + tvbuff_t *reassembled_tvb = tvb_new_composite(); + tvb_composite_append(reassembled_tvb, tvb_new_child_real_data(tvb, setup_data->setup_data, 8, 8)); + tvb_composite_append(reassembled_tvb, tvb_new_subset_remaining(tvb, offset)); + tvb_composite_finalize(reassembled_tvb); + add_new_data_source(pinfo, reassembled_tvb, "USBPcap reassembled setup"); + usb_conv_info->is_setup = TRUE; + tvb = reassembled_tvb; + offset = 0; + } + } + } + + if (usb_conv_info->is_request) { + if (usb_conv_info->is_setup) { + offset = dissect_usb_setup_request(pinfo, tree, tvb, offset, urb_type, + usb_conv_info, header_type, usb_id); + + } else { + switch (header_type) { + + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + proto_tree_add_item(tree, hf_usb_urb_unused_setup_header, tvb, offset, 8, ENC_NA); + offset += 8; + if (header_type == USB_HEADER_LINUX_64_BYTES) { + offset = dissect_linux_usb_pseudo_header_ext(tvb, offset, pinfo, tree); + } + break; + + case USB_HEADER_USBPCAP: + break; + + case USB_HEADER_MAUSB: + break; + + case USB_HEADER_USBIP: + break; + + case USB_HEADER_DARWIN: + break; + + case USB_HEADER_PSEUDO_URB: + break; + } + } + } else { + /* this is a response */ + + switch (header_type) { + + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + /* Skip setup header - it's never applicable for responses */ + proto_tree_add_item(tree, hf_usb_urb_unused_setup_header, tvb, offset, 8, ENC_NA); + offset += 8; + if (header_type == USB_HEADER_LINUX_64_BYTES) { + offset = dissect_linux_usb_pseudo_header_ext(tvb, offset, pinfo, tree); + } + break; + + case USB_HEADER_USBPCAP: + /* Check if this is status stage */ + if ((usb_conv_info->usb_trans_info) && + (usbpcap_control_stage == USB_CONTROL_STAGE_STATUS)) { + const gchar *description; + if (USB_TYPE(usb_conv_info->usb_trans_info->setup.requesttype) == RQT_SETUP_TYPE_STANDARD) { + description = val_to_str_ext(usb_conv_info->usb_trans_info->setup.request, + &setup_request_names_vals_ext, "Unknown type %x") ; + } else { + description = "URB_CONTROL"; + } + col_add_fstr(pinfo->cinfo, COL_INFO, "%s status", description); + /* There is no data to dissect */ + return; + } + break; + + case USB_HEADER_MAUSB: + break; + + case USB_HEADER_USBIP: + break; + + case USB_HEADER_DARWIN: + break; + + case USB_HEADER_PSEUDO_URB: + break; + } + + offset = dissect_usb_setup_response(pinfo, tree, tvb, offset, + urb_type, usb_conv_info); + } + break; + case URB_ISOCHRONOUS: + switch (header_type) { + + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + offset = dissect_linux_usb_iso_transfer(pinfo, tree, header_type, + tvb, offset, usb_conv_info); + break; + + case USB_HEADER_USBPCAP: + offset = dissect_usbpcap_iso_packets(pinfo, tree, + urb_type, tvb, offset, win32_data_len, usb_conv_info); + break; + + case USB_HEADER_MAUSB: + break; + + case USB_HEADER_USBIP: + offset = dissect_usbip_iso_transfer(pinfo, tree, + tvb, offset, iso_numdesc, desc_offset, usb_conv_info); + break; + + case USB_HEADER_DARWIN: + offset = dissect_darwin_usb_iso_transfer(pinfo, tree, header_type, + urb_type, tvb, offset, usb_conv_info); + break; + + case USB_HEADER_PSEUDO_URB: + break; + } + break; + + default: + /* unknown transfer type */ + switch (header_type) { + case USB_HEADER_LINUX_48_BYTES: + case USB_HEADER_LINUX_64_BYTES: + proto_tree_add_item(tree, hf_usb_urb_unused_setup_header, tvb, offset, 8, ENC_NA); + offset += 8; + if (header_type == USB_HEADER_LINUX_64_BYTES) { + offset = dissect_linux_usb_pseudo_header_ext(tvb, offset, pinfo, tree); + } + break; + + case USB_HEADER_USBPCAP: + break; + + case USB_HEADER_MAUSB: + break; + + case USB_HEADER_USBIP: + break; + + case USB_HEADER_DARWIN: + break; + + case USB_HEADER_PSEUDO_URB: + break; + } + break; + } + + dissect_usb_payload(tvb, pinfo, parent, tree, usb_conv_info, urb_type, + offset, device_address); +} + +static int +dissect_linux_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, void* data _U_) +{ + dissect_usb_common(tvb, pinfo, parent, USB_HEADER_LINUX_48_BYTES, NULL); + return tvb_captured_length(tvb); +} + +static int +dissect_linux_usb_mmapped(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, void* data _U_) +{ + dissect_usb_common(tvb, pinfo, parent, USB_HEADER_LINUX_64_BYTES, NULL); + return tvb_captured_length(tvb); +} + + +static int +dissect_win32_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, void* data _U_) +{ + dissect_usb_common(tvb, pinfo, parent, USB_HEADER_USBPCAP, NULL); + return tvb_captured_length(tvb); +} + +static int +dissect_darwin_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent, void* data _U_) +{ + dissect_usb_common(tvb, pinfo, parent, USB_HEADER_DARWIN, NULL); + return tvb_captured_length(tvb); +} + +void +proto_register_usb(void) +{ + module_t *usb_module; + static hf_register_info hf[] = { + + /* USB packet pseudoheader members */ + + { &hf_usb_totlen, + { "Total length", "usb.totlen", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_busunit, + { "Host controller unit number", "usb.busunit", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_address, + { "USB device index", "usb.address", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_mode, + { "Mode of transfer", "usb.transfer_mode", + FT_UINT8, BASE_DEC, VALS(usb_freebsd_transfer_mode_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_freebsd_urb_type, + { "URB type", "usb.freebsd_type", + FT_UINT8, BASE_DEC, VALS(usb_freebsd_urb_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_freebsd_transfer_type, + { "URB transfer type", "usb.freebsd_transfer_type", + FT_UINT8, BASE_HEX, VALS(usb_freebsd_transfer_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_xferflags, + { "Transfer flags", "usb.xferflags", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_xferflags_force_short_xfer, + { "Force short transfer", "usb.xferflags.force_short_xfer", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_FORCE_SHORT_XFER, + NULL, HFILL }}, + + { &hf_usb_xferflags_short_xfer_ok, + { "Short transfer OK", "usb.xferflags.short_xfer_ok", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_SHORT_XFER_OK, + NULL, HFILL }}, + + { &hf_usb_xferflags_short_frames_ok, + { "Short frames OK", "usb.xferflags.short_frames_ok", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_SHORT_FRAMES_OK, + NULL, HFILL }}, + + { &hf_usb_xferflags_pipe_bof, + { "Pipe BOF", "usb.xferflags.pipe_bof", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_PIPE_BOF, + NULL, HFILL }}, + + { &hf_usb_xferflags_proxy_buffer, + { "Proxy buffer", "usb.xferflags.proxy_buffer", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_PROXY_BUFFER, + NULL, HFILL }}, + + { &hf_usb_xferflags_ext_buffer, + { "External buffer", "usb.xferflags.ext_buffer", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_EXT_BUFFER, + NULL, HFILL }}, + + { &hf_usb_xferflags_manual_status, + { "Manual status", "usb.xferflags.manual_status", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_MANUAL_STATUS, + NULL, HFILL }}, + + { &hf_usb_xferflags_no_pipe_ok, + { "No pipe OK", "usb.xferflags.no_pipe_ok", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_NO_PIPE_OK, + NULL, HFILL }}, + + { &hf_usb_xferflags_stall_pipe, + { "Stall pipe", "usb.xferflags.stall_pipe", + FT_BOOLEAN, 32, NULL, FREEBSD_FLAG_STALL_PIPE, + NULL, HFILL }}, + + { &hf_usb_xferstatus, + { "Transfer status", "usb.xferstatus", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_xferstatus_open, + { "Pipe has been opened", "usb.xferstatus.open", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_OPEN, + NULL, HFILL }}, + + { &hf_usb_xferstatus_transferring, + { "Transfer in progress", "usb.xferstatus.transferring", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_TRANSFERRING, + NULL, HFILL }}, + + { &hf_usb_xferstatus_did_dma_delay, + { "Waited for hardware DMA", "usb.xferstatus.did_dma_delay", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_DID_DMA_DELAY, + NULL, HFILL }}, + + { &hf_usb_xferstatus_did_close, + { "Transfer closed", "usb.xferstatus.did_close", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_DID_CLOSE, + NULL, HFILL }}, + + { &hf_usb_xferstatus_draining, + { "Draining transfer", "usb.xferstatus.draining", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_DRAINING, + NULL, HFILL }}, + + { &hf_usb_xferstatus_started, + { "Transfer started", "usb.xferstatus.started", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_STARTED, + "Whether the transfer is started or stopped", HFILL }}, + + { &hf_usb_xferstatus_bw_reclaimed, + { "Bandwidth reclaimed", "usb.xferstatus.bw_reclaimed", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_BW_RECLAIMED, + NULL, HFILL }}, + + { &hf_usb_xferstatus_control_xfr, + { "Control transfer", "usb.xferstatus.control_xfr", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_CONTROL_XFR, + NULL, HFILL }}, + + { &hf_usb_xferstatus_control_hdr, + { "Control header being sent", "usb.xferstatus.control_hdr", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_CONTROL_HDR, + NULL, HFILL }}, + + { &hf_usb_xferstatus_control_act, + { "Control transfer active", "usb.xferstatus.control_act", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_CONTROL_ACT, + NULL, HFILL }}, + + { &hf_usb_xferstatus_control_stall, + { "Control transfer should be stalled", "usb.xferstatus.control_stall", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_CONTROL_STALL, + NULL, HFILL }}, + + { &hf_usb_xferstatus_short_frames_ok, + { "Short frames OK", "usb.xferstatus.short_frames_ok", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_SHORT_FRAMES_OK, + NULL, HFILL }}, + + { &hf_usb_xferstatus_short_xfer_ok, + { "Short transfer OK", "usb.xferstatus.short_xfer_ok", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_SHORT_XFER_OK, + NULL, HFILL }}, + + { &hf_usb_xferstatus_bdma_enable, + { "BUS-DMA enabled", "usb.xferstatus.bdma_enable", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_BDMA_ENABLE, + NULL, HFILL }}, + + { &hf_usb_xferstatus_bdma_no_post_sync, + { "BUS-DMA post sync op not done", "usb.xferstatus.bdma_no_post_sync", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_BDMA_NO_POST_SYNC, + NULL, HFILL }}, + + { &hf_usb_xferstatus_bdma_setup, + { "BUS-DMA set up", "usb.xferstatus.bdma_setup", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_BDMA_SETUP, + NULL, HFILL }}, + + { &hf_usb_xferstatus_isochronous_xfr, + { "Isochronous transfer", "usb.xferstatus.isochronous_xfr", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_ISOCHRONOUS_XFR, + NULL, HFILL }}, + + { &hf_usb_xferstatus_curr_dma_set, + { "Current DMA set", "usb.xferstatus.curr_dma_set", + FT_UINT32, BASE_DEC, NULL, FREEBSD_STATUS_CURR_DMA_SET, + NULL, HFILL }}, + + { &hf_usb_xferstatus_can_cancel_immed, + { "Transfer can be cancelled immediately", "usb.xferstatus.can_cancel_immed", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_CAN_CANCEL_IMMED, + NULL, HFILL }}, + + { &hf_usb_xferstatus_doing_callback, + { "Executing the callback", "usb.xferstatus.doing_callback", + FT_BOOLEAN, 32, NULL, FREEBSD_STATUS_DOING_CALLBACK, + NULL, HFILL }}, + + { &hf_usb_error, + { "Error", "usb.error", + FT_UINT32, BASE_DEC, VALS(usb_freebsd_err_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_interval, + { "Interval", "usb.interval", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Interval (ms)", HFILL }}, + + { &hf_usb_nframes, + { "Number of following frames", "usb.nframes", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_packet_size, + { "Packet size used", "usb.packet_size", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_packet_count, + { "Packet count used", "usb.packet_count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_speed, + { "Speed", "usb.speed", + FT_UINT8, BASE_DEC, VALS(usb_freebsd_speed_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_frame_length, + { "Frame length", "usb.frame.length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_frame_flags, + { "Frame flags", "usb.frame.flags", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_frame_flags_read, + { "Data direction is read", "usb.frame.read", + FT_BOOLEAN, 32, NULL, FREEBSD_FRAMEFLAG_READ, + NULL, HFILL }}, + + { &hf_usb_frame_flags_data_follows, + { "Frame contains data", "usb.frame.data_follows", + FT_BOOLEAN, 32, NULL, FREEBSD_FRAMEFLAG_DATA_FOLLOWS, + NULL, HFILL }}, + + { &hf_usb_frame_data, + { "Frame data", "usb.frame.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_urb_id, + { "URB id", "usb.urb_id", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_linux_urb_type, + { "URB type", "usb.urb_type", + FT_CHAR, BASE_HEX, VALS(usb_linux_urb_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_linux_transfer_type, + { "URB transfer type", "usb.transfer_type", + FT_UINT8, BASE_HEX, VALS(usb_linux_transfer_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_endpoint_address, + { "Endpoint", "usb.endpoint_address", + FT_UINT8, BASE_HEX, NULL, 0x0, + "USB endpoint address", HFILL }}, + + { &hf_usb_endpoint_direction, + { "Direction", "usb.endpoint_address.direction", + FT_UINT8, BASE_DEC, VALS(usb_endpoint_direction_vals), 0x80, + "USB endpoint direction", HFILL }}, + + { &hf_usb_endpoint_number, + { "Endpoint number", "usb.endpoint_address.number", + FT_UINT8, BASE_DEC, NULL, 0x0F, + "USB endpoint number", HFILL }}, + + { &hf_usb_device_address, + { "Device", "usb.device_address", + FT_UINT32, BASE_DEC, NULL, 0x0, + "USB device address", HFILL }}, + + { &hf_usb_bus_id, + { "URB bus id", "usb.bus_id", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_setup_flag, + { "Device setup request", "usb.setup_flag", + FT_CHAR, BASE_HEX|BASE_RANGE_STRING, RVALS(usb_setup_flag_rvals), 0x0, + "USB device setup request is relevant (0) or not", HFILL }}, + + { &hf_usb_data_flag, + { "Data", "usb.data_flag", + FT_CHAR, BASE_HEX|BASE_RANGE_STRING, RVALS(usb_data_flag_rvals), 0x0, + "USB data is present (0) or not", HFILL }}, + + { &hf_usb_urb_ts_sec, + { "URB sec", "usb.urb_ts_sec", + FT_UINT64, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_urb_ts_usec, + { "URB usec", "usb.urb_ts_usec", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_urb_status, + { "URB status", "usb.urb_status", + FT_INT32, BASE_DEC|BASE_EXT_STRING, &linux_negative_errno_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_urb_len, + { "URB length [bytes]", "usb.urb_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "URB length in bytes", HFILL }}, + + { &hf_usb_urb_data_len, + { "Data length [bytes]", "usb.data_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "URB data length in bytes", HFILL }}, + + { &hf_usb_urb_unused_setup_header, + { "Unused Setup Header", + "usb.unused_setup_header", FT_NONE, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_urb_interval, + { "Interval", + "usb.interval", FT_UINT32, BASE_DEC, + NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_urb_start_frame, + { "Start frame", + "usb.start_frame", FT_UINT32, BASE_DEC, + NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_urb_copy_of_transfer_flags, + { "Copy of Transfer Flags", + "usb.copy_of_transfer_flags", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_short_not_ok, + { "Short not OK", + "usb.transfer_flags.short_not_ok", FT_BOOLEAN, 32, + NULL, URB_SHORT_NOT_OK, NULL, HFILL }}, + + { &hf_iso_asap, + { "ISO ASAP", + "usb.transfer_flags.iso_asap", FT_BOOLEAN, 32, + NULL, URB_ISO_ASAP, NULL, HFILL }}, + + { &hf_no_transfer_dma_map, + { "No transfer DMA map", + "usb.transfer_flags.no_transfer_dma_map", FT_BOOLEAN, 32, + NULL, URB_NO_TRANSFER_DMA_MAP, NULL, HFILL }}, + + { &hf_no_fsbr, + { "No FSBR", + "usb.transfer_flags.no_fsbr", FT_BOOLEAN, 32, + NULL, URB_NO_FSBR, NULL, HFILL }}, + + { &hf_zero_packet, + { "Zero Packet", "usb.transfer_flags.zero_packet", FT_BOOLEAN, 32, + NULL, URB_ZERO_PACKET, NULL, HFILL }}, + + { &hf_no_interrupt, + { "No Interrupt", "usb.transfer_flags.no_interrupt", FT_BOOLEAN, 32, + NULL, URB_NO_INTERRUPT, NULL, HFILL }}, + + { &hf_free_buffer, + { "Free Buffer", "usb.transfer_flags.free_buffer", FT_BOOLEAN, 32, + NULL, URB_FREE_BUFFER, NULL, HFILL }}, + + { &hf_dir_in, + { "Dir IN", "usb.transfer_flags.dir_in", FT_BOOLEAN, 32, + NULL, URB_DIR_IN, NULL, HFILL }}, + + { &hf_dma_map_single, + { "DMA Map Single", "usb.transfer_flags.dma_map_single", FT_BOOLEAN, 32, + NULL, URB_DMA_MAP_SINGLE, NULL, HFILL }}, + + { &hf_dma_map_page, + { "DMA Map Page", "usb.transfer_flags.dma_map_page", FT_BOOLEAN, 32, + NULL, URB_DMA_MAP_PAGE, NULL, HFILL }}, + + { &hf_dma_map_sg, + { "DMA Map SG", "usb.transfer_flags.dma_map_sg", FT_BOOLEAN, 32, + NULL, URB_DMA_MAP_SG, NULL, HFILL }}, + + { &hf_map_local, + { "Map Local", "usb.transfer_flags.map_local", FT_BOOLEAN, 32, + NULL, URB_MAP_LOCAL, NULL, HFILL }}, + + { &hf_setup_map_single, + { "Setup Map Single", "usb.transfer_flags.setup_map_single", FT_BOOLEAN, 32, + NULL, URB_SETUP_MAP_SINGLE, NULL, HFILL }}, + + { &hf_setup_map_local, + { "Setup Map Local", "usb.transfer_flags.setup_map_local", FT_BOOLEAN, 32, + NULL, URB_SETUP_MAP_LOCAL, NULL, HFILL }}, + + { &hf_dma_sg_combined, + { "DMA S-G Combined", "usb.transfer_flags.dma_sg_combined", FT_BOOLEAN, 32, + NULL, URB_DMA_SG_COMBINED, NULL, HFILL }}, + + { &hf_aligned_temp_buffer, + { "Aligned Temp Buffer", "usb.transfer_flags.aligned_temp_buffer", FT_BOOLEAN, 32, + NULL, URB_ALIGNED_TEMP_BUFFER, NULL, HFILL }}, + + /* Win32 USBPcap pseudoheader */ + { &hf_usb_win32_header_len, + { "USBPcap pseudoheader length", "usb.usbpcap_header_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_irp_id, + { "IRP ID", "usb.irp_id", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_usbd_status, + { "IRP USBD_STATUS", "usb.usbd_status", + FT_UINT32, BASE_HEX | BASE_EXT_STRING, &win32_usbd_status_vals_ext, 0x0, + "USB request status value", HFILL }}, + + { &hf_usb_function, + { "URB Function", "usb.function", + FT_UINT16, BASE_HEX|BASE_EXT_STRING, &win32_urb_function_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_info, + { "IRP information", "usb.irp_info", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_usbpcap_info_reserved, + { "Reserved", "usb.irp_info.reserved", + FT_UINT8, BASE_HEX, NULL, 0xFE, + NULL, HFILL }}, + + { &hf_usb_usbpcap_info_direction, + { "Direction", "usb.irp_info.direction", + FT_UINT8, BASE_HEX, VALS(win32_usb_info_direction_vals), 0x01, + NULL, HFILL }}, + + { &hf_usb_win32_device_address, + { "Device address", "usb.device_address", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Windows USB device address", HFILL }}, + + { &hf_usb_win32_transfer_type, + { "URB transfer type", "usb.transfer_type", + FT_UINT8, BASE_HEX, VALS(win32_usb_transfer_type_vals), 0x0, + NULL, HFILL } }, + + { &hf_usb_win32_data_len, + { "Packet Data Length", "usb.data_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_control_stage, + { "Control transfer stage", "usb.control_stage", + FT_UINT8, BASE_DEC, VALS(usb_control_stage_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_iso_start_frame, + { "Isochronous transfer start frame", "usb.win32.iso_frame", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_iso_num_packets, + { "Isochronous transfer number of packets", "usb.win32.iso_num_packets", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_iso_error_count, + { "Isochronous transfer error count", "usb.win32.iso_error_count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_iso_offset, + { "ISO Data offset", "usb.win32.iso_offset", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_iso_length, + { "ISO Data length", "usb.win32.iso_data_len", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_win32_iso_status, + { "ISO USBD status", "usb.win32.iso_status", + FT_UINT32, BASE_HEX | BASE_EXT_STRING, &win32_usbd_status_vals_ext, 0x0, + NULL, HFILL }}, + + /* macOS usbdump pseudoheader */ + { &hf_usb_darwin_bcd_version, + { "Darwin header bcdVersion", "usb.darwin.bcdVersion", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_header_len, + { "Darwin header length", "usb.darwin.header_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_request_type, + { "Request type", "usb.darwin.request_type", + FT_UINT8, BASE_DEC, VALS(usb_darwin_request_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_io_len, + { "I/O length [bytes]", "usb.darwin.io_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Request length in bytes", HFILL }}, + + { &hf_usb_darwin_io_status, + { "Request status", "usb.darwin.io_status", + FT_UINT32, BASE_HEX | BASE_EXT_STRING, &usb_darwin_status_vals_ext, 0x0, + "USB request status", HFILL }}, + + { &hf_usb_darwin_iso_num_packets, + { "Isochronous transfer number of frames", "usb.darwin.io_frame_count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_io_id, + { "I/O ID", "usb.darwin.io_id", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_device_location, + { "Device location ID", "usb.darwin.location_id", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_speed, + { "Device speed", "usb.darwin_device_speed", + FT_UINT8, BASE_DEC, VALS(usb_darwin_speed_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_device_address, + { "USB device index", "usb.darwin.device_address", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_endpoint_address, + { "Endpoint address", "usb.darwin.endpoint_address", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Endpoint address and direction", HFILL }}, + + { &hf_usb_darwin_endpoint_type, + { "Endpoint transfer type", "usb.darwin.endpoint_type", + FT_UINT8, BASE_DEC, VALS(usb_darwin_endpoint_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_iso_status, + { "Frame status", "usb.darwin.iso.status", + FT_UINT32, BASE_HEX | BASE_EXT_STRING, &usb_darwin_status_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_iso_timestamp, + { "Frame timestamp", "usb.darwin.iso.timestamp", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_darwin_iso_frame_number, + { "Frame number", "usb.darwin.iso.frame_number", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bmRequestType, + { "bmRequestType", "usb.bmRequestType", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + /* Only used when response type cannot be determined */ + { &hf_usb_control_response_generic, + { "CONTROL response data", "usb.control.Response", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_request, + { "bRequest", "usb.setup.bRequest", + FT_UINT8, BASE_DEC | BASE_EXT_STRING, &setup_request_names_vals_ext, 0x0, + NULL, HFILL }}, + + /* Same as hf_usb_request but no descriptive text */ + { &hf_usb_request_unknown_class, + { "bRequest", "usb.setup.bRequest", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_value, + { "wValue", "usb.setup.wValue", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_index, + { "wIndex", "usb.setup.wIndex", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_length, + { "wLength", "usb.setup.wLength", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_device_wFeatureSelector, + { "wFeatureSelector", "usb.setup.wFeatureSelector", + FT_UINT16, BASE_DEC, VALS(usb_device_feature_selector_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_interface_wFeatureSelector, + { "wFeatureSelector", "usb.setup.wFeatureSelector", + FT_UINT16, BASE_DEC, VALS(usb_interface_feature_selector_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_endpoint_wFeatureSelector, + { "wFeatureSelector", "usb.setup.wFeatureSelector", + FT_UINT16, BASE_DEC, VALS(usb_endpoint_feature_selector_vals), 0x0, + NULL, HFILL }}, + + { &hf_usb_wInterface, + { "wInterface", "usb.setup.wInterface", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_wEndpoint, + { "wEndpoint", "usb.setup.wEndpoint", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_wStatus, + { "wStatus", "usb.setup.wStatus", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_wFrameNumber, + { "wFrameNumber", "usb.setup.wFrameNumber", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + /* --------------------------------- */ + { &hf_usb_iso_error_count, /* host endian byte order */ + { "ISO error count", "usb.iso.error_count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_iso_numdesc, + { "Number of ISO descriptors", "usb.iso.numdesc", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + /* fields of struct mon_bin_isodesc from linux/drivers/usb/mon/mon_bin.c */ + { &hf_usb_iso_status, + { "Status", "usb.iso.iso_status", + FT_INT32, BASE_DEC|BASE_EXT_STRING, &linux_negative_errno_vals_ext, 0x0, + "ISO descriptor status", HFILL }}, + + { &hf_usb_iso_off, + { "Offset [bytes]", "usb.iso.iso_off", + FT_UINT32, BASE_DEC, NULL, 0x0, + "ISO data offset in bytes starting from the end of the last ISO descriptor", HFILL }}, + + { &hf_usb_iso_len, + { "Length [bytes]", "usb.iso.iso_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "ISO data length in bytes", HFILL }}, + + { &hf_usb_iso_actual_len, + { "Actual Length [bytes]", "usb.iso.iso_actual_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "ISO data actual length in bytes", HFILL }}, + + { &hf_usb_iso_pad, /* host endian byte order */ + { "Padding", "usb.iso.pad", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Padding field of ISO descriptor structure", HFILL }}, + + { &hf_usb_iso_data, + {"ISO Data", "usb.iso.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + /* --------------------------------- */ +#if 0 + { &hf_usb_data_len, + {"Application Data Length", "usb.data.length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, +#endif + + { &hf_usb_capdata, + {"Leftover Capture Data", "usb.capdata", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Padding added by the USB capture system", HFILL }}, + + { &hf_usb_bmRequestType_direction, + { "Direction", "usb.bmRequestType.direction", + FT_BOOLEAN, 8, TFS(&tfs_bmrequesttype_direction), USB_DIR_IN, + NULL, HFILL }}, + + { &hf_usb_bmRequestType_type, + { "Type", "usb.bmRequestType.type", + FT_UINT8, BASE_HEX, VALS(bmrequesttype_type_vals), USB_TYPE_MASK, + NULL, HFILL }}, + + { &hf_usb_bmRequestType_recipient, + { "Recipient", "usb.bmRequestType.recipient", + FT_UINT8, BASE_HEX, VALS(bmrequesttype_recipient_vals), 0x1f, + NULL, HFILL }}, + + { &hf_usb_bDescriptorType, + { "bDescriptorType", "usb.bDescriptorType", + FT_UINT8, BASE_HEX|BASE_EXT_STRING, &std_descriptor_type_vals_ext, 0x0, + NULL, HFILL }}, + + /* Only used when descriptor type cannot be determined */ + { &hf_usb_get_descriptor_resp_generic, + { "GET DESCRIPTOR Response data", "usb.getDescriptor.Response", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_descriptor_index, + { "Descriptor Index", "usb.DescriptorIndex", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_language_id, + { "Language Id", "usb.LanguageId", + FT_UINT16, BASE_HEX|BASE_EXT_STRING,&usb_langid_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bLength, + { "bLength", "usb.bLength", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bcdUSB, + { "bcdUSB", "usb.bcdUSB", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bDeviceClass, + { "bDeviceClass", "usb.bDeviceClass", + FT_UINT8, BASE_HEX|BASE_EXT_STRING, &usb_class_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bDeviceSubClass, + { "bDeviceSubClass", "usb.bDeviceSubClass", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bDeviceProtocol, + { "bDeviceProtocol", "usb.bDeviceProtocol", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bMaxPacketSize0, + { "bMaxPacketSize0", "usb.bMaxPacketSize0", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_idVendor, + { "idVendor", "usb.idVendor", + FT_UINT16, BASE_HEX | BASE_EXT_STRING, &ext_usb_vendors_vals, 0x0, + NULL, HFILL }}, + + { &hf_usb_idProduct, + { "idProduct", "usb.idProduct", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bcdDevice, + { "bcdDevice", "usb.bcdDevice", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_iManufacturer, + { "iManufacturer", "usb.iManufacturer", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_iProduct, + { "iProduct", "usb.iProduct", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_iSerialNumber, + { "iSerialNumber", "usb.iSerialNumber", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bNumConfigurations, + { "bNumConfigurations", "usb.bNumConfigurations", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_wLANGID, + { "wLANGID", "usb.wLANGID", + FT_UINT16, BASE_HEX|BASE_EXT_STRING,&usb_langid_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bString, + { "bString", "usb.bString", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceNumber, + { "bInterfaceNumber", "usb.bInterfaceNumber", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bAlternateSetting, + { "bAlternateSetting", "usb.bAlternateSetting", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bNumEndpoints, + { "bNumEndpoints", "usb.bNumEndpoints", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceClass, + { "bInterfaceClass", "usb.bInterfaceClass", + FT_UINT8, BASE_HEX|BASE_EXT_STRING, &usb_class_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass, + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass_audio, + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &ext_usb_audio_subclass_vals, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass_cdc, + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &ext_usb_com_subclass_vals, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass_massstorage , + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &ext_usb_massstorage_subclass_vals, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass_hid, + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_hid_subclass_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass_misc, + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_misc_subclass_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceSubClass_app, + { "bInterfaceSubClass", "usb.bInterfaceSubClass", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_app_subclass_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_cdc, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_cdc_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_massstorage, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_massstorage_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_cdc_data, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_cdc_data_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_hid_boot, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_hid_boot_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_app_dfu, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_app_dfu_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_app_irda, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_app_irda_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_bInterfaceProtocol_app_usb_test_and_measurement, + { "bInterfaceProtocol", "usb.bInterfaceProtocol", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &usb_app_usb_test_and_measurement_protocol_vals_ext, 0x0, + NULL, HFILL }}, + + + { &hf_usb_iInterface, + { "iInterface", "usb.iInterface", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bEndpointAddress, + { "bEndpointAddress", "usb.bEndpointAddress", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_configuration_bmAttributes, + { "Configuration bmAttributes", "usb.configuration.bmAttributes", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bmAttributes, + { "bmAttributes", "usb.bmAttributes", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bEndpointAttributeTransfer, + { "Transfertype", "usb.bmAttributes.transfer", + FT_UINT8, BASE_HEX, VALS(usb_bmAttributes_transfer_vals), 0x03, + NULL, HFILL }}, + + { &hf_usb_bEndpointAttributeSynchonisation, + { "Synchronisationtype", "usb.bmAttributes.sync", + FT_UINT8, BASE_HEX, VALS(usb_bmAttributes_sync_vals), 0x0c, + NULL, HFILL }}, + + { &hf_usb_bEndpointAttributeBehaviour, + { "Behaviourtype", "usb.bmAttributes.behaviour", + FT_UINT8, BASE_HEX, VALS(usb_bmAttributes_behaviour_vals), 0x30, + NULL, HFILL }}, + + { &hf_usb_wMaxPacketSize, + { "wMaxPacketSize", "usb.wMaxPacketSize", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_wMaxPacketSize_size, + { "Maximum Packet Size", "usb.wMaxPacketSize.size", + FT_UINT16, BASE_DEC, NULL, 0x03FF, + NULL, HFILL }}, + + { &hf_usb_wMaxPacketSize_slots, + { "Transactions per microframe", "usb.wMaxPacketSize.slots", + FT_UINT16, BASE_DEC, VALS(usb_wMaxPacketSize_slots_vals), (3<<11), + NULL, HFILL }}, + + { &hf_usb_bInterval, + { "bInterval", "usb.bInterval", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bMaxBurst, + { "bMaxBurst", "usb.bMaxBurst", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Valid values are from 0 to 15. For control endpoints this value shall be 0.", HFILL }}, + + { &hf_usb_audio_bRefresh, + { "bRefresh", "usb.audio.bRefresh", + FT_UINT8, BASE_DEC, NULL, 0x00, + NULL, HFILL }}, + + { &hf_usb_audio_bSynchAddress, + { "bSynchAddress", "usb.audio.bSynchAddress", + FT_UINT8, BASE_DEC, NULL, 0x00, + NULL, HFILL }}, + + { &hf_usb_bSSEndpointAttributeBulkMaxStreams, + { "MaxStreams", "usb.bmAttributes.MaxStreams", + FT_UINT8, BASE_DEC, NULL, 0x0F, + "Number of streams = 2 to the power MaxStreams", HFILL }}, + + { &hf_usb_bSSEndpointAttributeIsoMult, + { "Mult", "usb.bmAttributes.Mult", + FT_UINT8, BASE_DEC, NULL, 0x03, + "Maximum number of packets = bMaxBurst * (Mult + 1)", HFILL } }, + + { &hf_usb_wBytesPerInterval, + { "wBytesPerInterval", "usb.wBytesPerInterval", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } }, + + { &hf_usb_wTotalLength, + { "wTotalLength", "usb.wTotalLength", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bNumInterfaces, + { "bNumInterfaces", "usb.bNumInterfaces", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bConfigurationValue, + { "bConfigurationValue", "usb.bConfigurationValue", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_iConfiguration, + { "iConfiguration", "usb.iConfiguration", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bMaxPower, + { "bMaxPower", "usb.bMaxPower", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_configuration_legacy10buspowered, + { "Must be 1", "usb.configuration.legacy10buspowered", + FT_BOOLEAN, 8, TFS(&tfs_mustbeone), 0x80, + "Legacy USB 1.0 bus powered", HFILL }}, + + { &hf_usb_configuration_selfpowered, + { "Self-Powered", "usb.configuration.selfpowered", + FT_BOOLEAN, 8, TFS(&tfs_selfpowered), 0x40, + NULL, HFILL }}, + + { &hf_usb_configuration_remotewakeup, + { "Remote Wakeup", "usb.configuration.remotewakeup", + FT_BOOLEAN, 8, TFS(&tfs_remotewakeup), 0x20, + NULL, HFILL }}, + + { &hf_usb_bEndpointAddress_number, + { "Endpoint Number", "usb.bEndpointAddress.number", + FT_UINT8, BASE_HEX, NULL, 0x0f, + NULL, HFILL }}, + + { &hf_usb_bEndpointAddress_direction, + { "Direction", "usb.bEndpointAddress.direction", + FT_BOOLEAN, 8, TFS(&tfs_endpoint_direction), 0x80, + NULL, HFILL }}, + + { &hf_usb_request_in, + { "Request in", "usb.request_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "The request to this packet is in this packet", HFILL }}, + + { &hf_usb_time, + { "Time from request", "usb.time", + FT_RELATIVE_TIME, BASE_NONE, NULL, 0, + "Time between Request and Response for USB cmds", HFILL }}, + + { &hf_usb_response_in, + { "Response in", "usb.response_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "The response to this packet is in this packet", HFILL }}, + + { &hf_usb_bFirstInterface, + { "bFirstInterface", "usb.bFirstInterface", + FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_bInterfaceCount, + { "bInterfaceCount", + "usb.bInterfaceCount", FT_UINT8, BASE_DEC, + NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_bFunctionClass, + { "bFunctionClass", "usb.bFunctionClass", + FT_UINT8, BASE_HEX|BASE_EXT_STRING, &usb_class_vals_ext, 0x0, NULL, HFILL }}, + + { &hf_usb_bFunctionSubClass, + { "bFunctionSubClass", + "usb.bFunctionSubClass", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_bFunctionProtocol, + { "bFunctionProtocol", "usb.bFunctionProtocol", + FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_iFunction, + { "iFunction", + "usb.iFunction", FT_UINT8, BASE_DEC, + NULL, 0x0, NULL, HFILL }}, + + { &hf_usb_bNumDeviceCaps, + { "bNumDeviceCaps", "usb.bNumDeviceCaps", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_bDevCapabilityType, + { "bDevCapabilityType", "usb.bDevCapabilityType", + FT_UINT8, BASE_HEX|BASE_EXT_STRING, &usb_capability_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_usb_usb20ext_bmAttributes, + { "bmAttributes", "usb.usb20ext.bmAttributes", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_usb20ext_LPM, + { "LPM", "usb.usb20ext.bmAttributes.LPM", + FT_BOOLEAN, 32, NULL, 0x00000002, + NULL, HFILL }}, + + { &hf_usb_usb20ext_BESL_HIRD, + { "BESL & Alternate HIRD", "usb.usb20ext.bmAttributes.BESL", + FT_BOOLEAN, 32, NULL, 0x00000004, + NULL, HFILL }}, + + { &hf_usb_usb20ext_baseline_BESL_valid, + { "Baseline BESL valid", "usb.usb20ext.bmAttributes.baseline_BESL_valid", + FT_BOOLEAN, 32, NULL, 0x00000008, + NULL, HFILL }}, + + { &hf_usb_usb20ext_deep_BESL_valid, + { "Deep BESL valid", "usb.usb20ext.bmAttributes.deep_BESL_valid", + FT_BOOLEAN, 32, NULL, 0x00000010, + NULL, HFILL }}, + + { &hf_usb_usb20ext_baseline_BESL, + { "Recommended Baseline BESL", "usb.usb20ext.bmAttributes.baseline_BESL", + FT_UINT32, BASE_CUSTOM, CF_FUNC(usb_lpm_besl_str), 0x00000F00, + NULL, HFILL }}, + + { &hf_usb_usb20ext_deep_BESL, + { "Recommended Deep BESL", "usb.usb20ext.bmAttributes.deep_BESL", + FT_UINT32, BASE_CUSTOM, CF_FUNC(usb_lpm_besl_str), 0x0000F000, + NULL, HFILL }}, + + { &hf_usb_bReserved, + { "bReserved", "usb.bReserved", + FT_UINT8, BASE_DEC, NULL, 0x0, + "This field is reserved and shall be set to zero", HFILL }}, + + { &hf_usb_PlatformCapabilityUUID, + { "PlatformCapabilityUUID", "usb.PlatformCapabilityUUID", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_webusb_bcdVersion, + { "bcdVersion", "usb.webusb.bcdVersion", + FT_UINT16, BASE_HEX, NULL, 0x0, + "WebUSB descriptor version", HFILL }}, + + { &hf_usb_webusb_bVendorCode, + { "bVendorCode", "usb.webusb.bVendorCode", + FT_UINT8, BASE_DEC, NULL, 0x0, + "bRequest value for WebUSB", HFILL }}, + + { &hf_usb_webusb_iLandingPage, + { "iLandingPage", "usb.webusb.iLandingPage", + FT_UINT8, BASE_DEC, NULL, 0x0, + "URL for landing page", HFILL }}, + + { &hf_usb_msos20_dwWindowsVersion, + { "dwWindowsVersion", "usb.msos20.dwWindowsVersion", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_msos20_wMSOSDescriptorSetTotalLength, + { "wMSOSDescriptorSetTotalLength", "usb.msos20.wMSOSDescriptorSetTotalLength", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_msos20_bMS_VendorCode, + { "bMS_VendorCode", "usb.msos20.bMS_VendorCode", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_msos20_bAltEnumCode, + { "bAltEnumCode", "usb.msos20.bAltEnumCode", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_usb_data_fragment, + { "Data Fragment", + "usb.data_fragment", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + { &hf_usb_src, + { "Source", "usb.src", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usb_dst, + { "Destination", "usb.dst", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usb_addr, + { "Source or Destination", "usb.addr", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + } + }; + + static hf_register_info hf_usbport[] = { + { &hf_usbport_event_id, + { "Event ID", "usbport.event_id", + FT_UINT32, BASE_DEC_HEX|BASE_EXT_STRING, &netmon_event_id_vals_ext, 0x0, + NULL, HFILL } + }, + { &hf_usbport_device_object, + { "Device Object", "usbport.device_object", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_pci_bus, + { "PCI Bus", "usbport.pci_bus", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_pci_device, + { "PCI Bus", "usbport.pci_device", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_pci_function, + { "PCI Function", "usbport.pci_function", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_pci_vendor_id, + { "PCI Vendor ID", "usbport.pci_vendor_id", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_pci_device_id, + { "PCI Device ID", "usbport.pci_device_id", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path_depth, + { "Path Depth", "usbport.port_path_depth", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path0, + { "Path0", "usbport.port_path0", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path1, + { "Path1", "usbport.port_path1", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path2, + { "Path2", "usbport.port_path2", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path3, + { "Path3", "usbport.port_path3", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path4, + { "Path4", "usbport.port_path4", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_port_path5, + { "Path5", "usbport.port_path5", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_device_handle, + { "Device Handle", "usbport.device_handle", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_device_speed, + { "Device Speed", "usbport.device_speed", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_endpoint, + { "Endpoint", "usbport.endpoint", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_pipehandle, + { "Pipe Handle", "usbport.pipehandle", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_endpoint_desc_length, + { "Length", "usbport.endpoint_desc_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_endpoint_desc_type, + { "Description Type", "usbport.endpoint_desc_type", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_endpoint_address, + { "Endpoint Address", "usbport.endpoint_address", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_bm_attributes, + { "bmAttributes", "usbport.bm_attributes", + FT_UINT8, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_max_packet_size, + { "Max Packet Size", "usbport.max_packet_size", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_interval, + { "Interval", "usbport.interval", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_irp, + { "IRP", "usbport.irp", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb, + { "URB", "usbport.urb", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_transfer_data, + { "URB Transfer data", "usbport.urb_transfer_data", + FT_UINT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_header_length, + { "URB Header Length", "usbport.urb_header_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_header_function, + { "URB Header Function", "usbport.urb_header_function", + FT_UINT16, BASE_DEC|BASE_EXT_STRING, &netmon_urb_function_vals_ext, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_header_status, + { "URB Header Status", "usbport.urb_header_status", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_header_usbddevice_handle, + { "URB Header Device Handle", "usbport.urb_header_usbddevice_handle", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_header_usbdflags, + { "URB Header Flags", "usbport.urb_header_usbdflags", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_configuration_desc, + { "URB Configuration Description", "usbport.urb_configuration_desc", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_configuration_handle, + { "URB Configuration Handle", "usbport.urb_configuration_handle", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_pipe_handle, + { "URB Pipe Handle", "usbport.urb_pipe_handle", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_xferflags, + { "URB Transfer Flags", "usbport.urb_xferflags", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_transfer_buffer_length, + { "URB Transfer Buffer Length", "usbport.urb_transfer_buffer_length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_transfer_buffer, + { "URB Transfer Buffer", "usbport.urb_transfer_buffer", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_transfer_buffer_mdl, + { "URB Transfer Buffer MDL", "usbport.urb_transfer_buffer_mdl", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_reserved_mbz, + { "URB Reserved MBZ", "usbport.urb_reserved_mbz", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_reserved_hcd, + { "URB Reserved HCD", "usbport.urb_reserved_hcd", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_urb_reserved, + { "URB Reserved", "usbport.urb_reserved", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_keyword, + { "Keyword", "usbport.keyword", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_usbport_keyword_diagnostic, + { "USBPORT_ETW_KEYWORD_DIAGNOSTIC", "usbport.keyword.diagnostic", + FT_BOOLEAN, 64, NULL, USBPORT_KEYWORD_DIAGNOSTIC, + NULL, HFILL } + }, + { &hf_usbport_keyword_power_diagnostics, + { "USBPORT_ETW_KEYWORD_POWER_DIAGNOSTICS", "usbport.keyword.power_diagnostics", + FT_BOOLEAN, 64, NULL, USBPORT_KEYWORD_POWER_DIAGNOSTICS, + NULL, HFILL } + }, + { &hf_usbport_keyword_perf_diagnostics, + { "USBPORT_ETW_KEYWORD_PERF_DIAGNOSTICS", "usbport.keyword.perf_diagnostics", + FT_BOOLEAN, 64, NULL, USBPORT_KEYWORD_PERF_DIAGNOSTICS, + NULL, HFILL } + }, + { &hf_usbport_keyword_reserved1, + { "Reserved1", "usbport.keyword.reserved1", + FT_UINT64, BASE_HEX, NULL, USBPORT_KEYWORD_RESERVED1, + NULL, HFILL } + }, + }; + + static gint *usb_subtrees[] = { + &ett_usb_hdr, + &ett_usb_setup_hdr, + &ett_usb_isodesc, + &ett_usb_win32_iso_packet, + &ett_usb_endpoint, + &ett_usb_xferflags, + &ett_usb_xferstatus, + &ett_usb_frame, + &ett_usb_frame_flags, + &ett_usb_setup_bmrequesttype, + &ett_usb_usbpcap_info, + &ett_descriptor_device, + &ett_configuration_bmAttributes, + &ett_configuration_bEndpointAddress, + &ett_endpoint_bmAttributes, + &ett_endpoint_wMaxPacketSize, + &ett_transfer_flags, + &ett_usb20ext_bmAttributes, + }; + + static gint *usbport_subtrees[] = { + &ett_usbport, + &ett_usbport_host_controller, + &ett_usbport_path, + &ett_usbport_device, + &ett_usbport_endpoint, + &ett_usbport_endpoint_desc, + &ett_usbport_urb, + &ett_usbport_keyword, + }; + + static ei_register_info ei[] = { + { &ei_usb_undecoded, { "usb.undecoded", PI_UNDECODED, PI_WARN, "Not dissected yet (report to wireshark.org)", EXPFILL }}, + { &ei_usb_bLength_even, { "usb.bLength.even", PI_PROTOCOL, PI_WARN, "Invalid STRING DESCRIPTOR Length (must be even)", EXPFILL }}, + { &ei_usb_bLength_too_short, { "usb.bLength.too_short", PI_MALFORMED, PI_ERROR, "Invalid STRING DESCRIPTOR Length (must be 2 or larger)", EXPFILL }}, + { &ei_usb_desc_length_invalid, { "usb.desc_length.invalid", PI_MALFORMED, PI_ERROR, "Invalid descriptor length", EXPFILL }}, + { &ei_usb_invalid_setup, { "usb.setup.invalid", PI_MALFORMED, PI_ERROR, "Only control URBs may contain a setup packet", EXPFILL }}, + { &ei_usb_ss_ep_companion_before_ep, { "usb.bmAttributes.invalid_order", PI_MALFORMED, PI_ERROR, "SuperSpeed Endpoint Companion must come after Endpoint Descriptor", EXPFILL }}, + { &ei_usb_usbpcap_unknown_urb, { "usb.usbpcap.unknown_urb", PI_MALFORMED, PI_ERROR, "USBPcap did not recognize URB Function code (report to desowin.org/USBPcap)", EXPFILL }}, + { &ei_usb_bad_length, { "usb.bad_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }}, + { &ei_usb_invalid_max_packet_size, { "usb.wMaxPacketSize.invalid", PI_PROTOCOL, PI_WARN, "Invalid Max Packet Size", EXPFILL }}, + { &ei_usb_invalid_max_packet_size0, { "usb.bMaxPacketSize0.invalid", PI_PROTOCOL, PI_WARN, "Invalid Max Packet Size", EXPFILL }}, + { &ei_usb_invalid_endpoint_type, { "usb.bmAttributes.transfer.invalid", PI_PROTOCOL, PI_WARN, "Transfer type not allowed at Low-Speed", EXPFILL }}, + { &ei_usb_unexpected_desc_type, { "usb.bDescriptorType.unexpected", PI_MALFORMED, PI_ERROR, "Unexpected descriptor type", EXPFILL }}, + }; + static ei_register_info ei_usbport[] = { + { &ei_usbport_invalid_path_depth, { "usbport.path_depth.invalid", PI_PROTOCOL, PI_WARN, "Invalid path depth", EXPFILL }}, + }; + + expert_module_t *expert_usb, *expert_usbport; + + proto_usb = proto_register_protocol("USB", "USB", "usb"); + proto_usbport = proto_register_protocol("USBPort", "USBPort", "usbport"); + + proto_register_field_array(proto_usb, hf, array_length(hf)); + proto_register_field_array(proto_usbport, hf_usbport, array_length(hf_usbport)); + proto_register_subtree_array(usb_subtrees, array_length(usb_subtrees)); + proto_register_subtree_array(usbport_subtrees, array_length(usbport_subtrees)); + + expert_usb = expert_register_protocol(proto_usb); + expert_register_field_array(expert_usb, ei, array_length(ei)); + expert_usbport = expert_register_protocol(proto_usbport); + expert_register_field_array(expert_usbport, ei_usbport, array_length(ei_usbport)); + + device_to_product_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + device_to_protocol_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + usbpcap_setup_data = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + device_to_dissector = register_dissector_table("usb.device", "USB device", proto_usb, FT_UINT32, BASE_HEX); + protocol_to_dissector = register_dissector_table("usb.protocol", "USB protocol", proto_usb, FT_UINT32, BASE_HEX); + product_to_dissector = register_dissector_table("usb.product", "USB product", proto_usb, FT_UINT32, BASE_HEX); + + usb_bulk_dissector_table = register_dissector_table("usb.bulk", + "USB bulk endpoint", proto_usb, FT_UINT32, BASE_HEX); + heur_bulk_subdissector_list = register_heur_dissector_list("usb.bulk", proto_usb); + usb_control_dissector_table = register_dissector_table("usb.control", + "USB control endpoint", proto_usb, FT_UINT32, BASE_HEX); + heur_control_subdissector_list = register_heur_dissector_list("usb.control", proto_usb); + usb_interrupt_dissector_table = register_dissector_table("usb.interrupt", + "USB interrupt endpoint", proto_usb, FT_UINT32, BASE_HEX); + heur_interrupt_subdissector_list = register_heur_dissector_list("usb.interrupt", proto_usb); + usb_descriptor_dissector_table = register_dissector_table("usb.descriptor", + "USB descriptor", proto_usb, FT_UINT8, BASE_DEC); + + usb_module = prefs_register_protocol(proto_usb, NULL); + prefs_register_bool_preference(usb_module, "try_heuristics", + "Try heuristic sub-dissectors", + "Try to decode a packet using a heuristic sub-dissector before " + "attempting to dissect the packet using the \"usb.bulk\", \"usb.interrupt\" or " + "\"usb.control\" dissector tables.", &try_heuristics); + + usb_tap = register_tap("usb"); + + register_decode_as(&usb_protocol_da); + register_decode_as(&usb_product_da); + register_decode_as(&usb_device_da); + + linux_usb_handle = register_dissector("usb_linux", dissect_linux_usb, proto_usb); + linux_usb_mmapped_handle = register_dissector("usb_linux_mmapped", dissect_linux_usb_mmapped, proto_usb); + win32_usb_handle = register_dissector("usb_win32", dissect_win32_usb, proto_usb); + freebsd_usb_handle = register_dissector("usb_freebsd", dissect_freebsd_usb, proto_usb); + darwin_usb_handle = register_dissector("usb_darwin", dissect_darwin_usb, proto_usb); + netmon_usb_port_handle = register_dissector("usb_netmon", dissect_netmon_usb_port, proto_usbport); + + usb_address_type = address_type_dissector_register("AT_USB", "USB Address", usb_addr_to_str, usb_addr_str_len, NULL, usb_col_filter_str, NULL, NULL, NULL); + + register_conversation_table(proto_usb, TRUE, usb_conversation_packet, usb_endpoint_packet); +} + +void +proto_reg_handoff_usb(void) +{ + static guid_key usb_port_key = {{ 0xc88a4ef5, 0xd048, 0x4013, { 0x94, 0x08, 0xe0, 0x4b, 0x7d, 0xb2, 0x81, 0x4a }}, 0 }; + + dissector_add_uint("wtap_encap", WTAP_ENCAP_USB_LINUX, linux_usb_handle); + dissector_add_uint("wtap_encap", WTAP_ENCAP_USB_LINUX_MMAPPED, linux_usb_mmapped_handle); + dissector_add_uint("wtap_encap", WTAP_ENCAP_USBPCAP, win32_usb_handle); + dissector_add_uint("wtap_encap", WTAP_ENCAP_USB_FREEBSD, freebsd_usb_handle); + dissector_add_uint("wtap_encap", WTAP_ENCAP_USB_DARWIN, darwin_usb_handle); + + dissector_add_guid( "netmon.provider_id", &usb_port_key, netmon_usb_port_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |