USBLL: Initial USB 2.0 Link Layer dissector

Dissect raw USB Packets. The actual USB packets to transaction conversion
(which is needed to pass the data to existing USB URB dissector) is not
implemented yet.

Ping-Bug: 15908
Change-Id: Ia75d58882d770fdd8650622d318241743069ad8f
Reviewed-on: https://code.wireshark.org/review/34006
Reviewed-by: Tomasz Moń <desowin@gmail.com>
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Tomasz Moń 2019-07-23 15:54:36 +02:00 committed by Anders Broman
parent d55cf134eb
commit 53fdec477d
5 changed files with 364 additions and 0 deletions

View File

@ -1830,6 +1830,7 @@ set(DISSECTOR_SRC
${CMAKE_CURRENT_SOURCE_DIR}/packet-usb-video.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-usb.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-usbip.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-usbll.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-user_encap.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-userlog.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-uts.c

View File

@ -0,0 +1,357 @@
/* packet-usbll.c
*
* 2019 Tomasz Mon <desowin@gmail.com>
*
* USB link layer dissector
*
* This code is separated from packet-usb.c on purpose.
* It is important to note that packet-usb.c operates on the USB URB level.
* The idea behind this file is to transform low level link layer data
* (captured by hardware sniffers) into structures that resemble URB and pass
* such URB to the URB common dissection code.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/expert.h>
static int proto_usbll = -1;
/* Fields defined by USB 2.0 standard */
static int hf_usbll_pid = -1;
static int hf_usbll_addr = -1;
static int hf_usbll_endp = -1;
static int hf_usbll_crc5 = -1;
static int hf_usbll_data = -1;
static int hf_usbll_data_crc = -1;
static int hf_usbll_sof_framenum = -1;
static int hf_usbll_split_hub_addr = -1;
static int hf_usbll_split_sc = -1;
static int hf_usbll_split_port = -1;
static int hf_usbll_split_s = -1;
static int hf_usbll_split_e = -1;
static int hf_usbll_split_iso_se = -1;
static int hf_usbll_split_et = -1;
static int hf_usbll_split_crc5 = -1;
static int ett_usbll = -1;
static expert_field ei_invalid_pid = EI_INIT;
static expert_field ei_undecoded = EI_INIT;
static dissector_handle_t usbll_handle;
/* USB packet ID is 4-bit. It is send in octet alongside complemented form.
* The list of PIDs is available in Universal Serial Bus Specification Revision 2.0,
* Table 8-1. PID Types
* Packets here are sorted by the complemented form (high nibble).
*/
#define USB_PID_DATA_MDATA 0x0F
#define USB_PID_HANDSHAKE_STALL 0x1E
#define USB_PID_TOKEN_SETUP 0x2D
#define USB_PID_SPECIAL_PRE_OR_ERR 0x3C
#define USB_PID_DATA_DATA1 0x4B
#define USB_PID_HANDSHAKE_NAK 0x5A
#define USB_PID_TOKEN_IN 0x69
#define USB_PID_SPECIAL_SPLIT 0x78
#define USB_PID_DATA_DATA2 0x87
#define USB_PID_HANDSHAKE_NYET 0x96
#define USB_PID_TOKEN_SOF 0xA5
#define USB_PID_SPECIAL_PING 0xB4
#define USB_PID_DATA_DATA0 0xC3
#define USB_PID_HANDSHAKE_ACK 0xD2
#define USB_PID_TOKEN_OUT 0xE1
#define USB_PID_SPECIAL_RESERVED 0xF0
static const value_string usb_packetid_vals[] = {
{USB_PID_DATA_MDATA, "MDATA"},
{USB_PID_HANDSHAKE_STALL, "STALL"},
{USB_PID_TOKEN_SETUP, "SETUP"},
{USB_PID_SPECIAL_PRE_OR_ERR, "PRE/ERR"},
{USB_PID_DATA_DATA1, "DATA1"},
{USB_PID_HANDSHAKE_NAK, "NAK"},
{USB_PID_TOKEN_IN, "IN"},
{USB_PID_SPECIAL_SPLIT, "SPLIT"},
{USB_PID_DATA_DATA2, "DATA2"},
{USB_PID_HANDSHAKE_NYET, "NYET"},
{USB_PID_TOKEN_SOF, "SOF"},
{USB_PID_SPECIAL_PING, "PING"},
{USB_PID_DATA_DATA0, "DATA0"},
{USB_PID_HANDSHAKE_ACK, "ACK"},
{USB_PID_TOKEN_OUT, "OUT"},
{USB_PID_SPECIAL_RESERVED, "Reserved"},
{0, NULL}
};
static value_string_ext usb_packetid_vals_ext =
VALUE_STRING_EXT_INIT(usb_packetid_vals);
static const value_string usb_start_complete_vals[] = {
{0, "Start"},
{1, "Complete"},
{0, NULL}
};
static const value_string usb_split_speed_vals[] = {
{0, "Full"},
{1, "Low"},
{0, NULL}
};
static const value_string usb_split_iso_se_vals[] = {
{0, "High-speed data is the middle of the fullspeed data payload"},
{1, "High-speed data is the beginning of the full-speed data payload"},
{2, "High-speed data is the end of the full-speed data payload"},
{3, "High-speed data is all of the full-speed data payload"},
{0, NULL}
};
#define USB_EP_TYPE_CONTROL 0
#define USB_EP_TYPE_ISOCHRONOUS 1
#define USB_EP_TYPE_BULK 2
#define USB_EP_TYPE_INTERRUPT 3
static const value_string usb_endpoint_type_vals[] = {
{USB_EP_TYPE_CONTROL, "Control"},
{USB_EP_TYPE_ISOCHRONOUS, "Isochronous"},
{USB_EP_TYPE_BULK, "Bulk"},
{USB_EP_TYPE_INTERRUPT, "Interrupt"},
{0, NULL}
};
static int
dissect_usbll_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
{
proto_item *item;
proto_tree *tree;
gint offset = 0;
guint32 pid;
const gchar *str;
tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_usbll, &item, "USB Packet");
item = proto_tree_add_item_ret_uint(tree, hf_usbll_pid, tvb, offset, 1, ENC_LITTLE_ENDIAN, &pid);
offset++;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBLL");
str = try_val_to_str(pid, usb_packetid_vals);
if (str)
{
col_set_str(pinfo->cinfo, COL_INFO, str);
}
else
{
col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid Packet ID (0x%02x)", pid);
expert_add_info(pinfo, item, &ei_invalid_pid);
}
switch (pid)
{
case USB_PID_TOKEN_SETUP:
case USB_PID_TOKEN_OUT:
case USB_PID_TOKEN_IN:
case USB_PID_SPECIAL_PING:
{
static const int *address_fields[] = {
&hf_usbll_addr,
&hf_usbll_endp,
&hf_usbll_crc5,
NULL
};
proto_tree_add_bitmask_list(tree, tvb, offset, 2, address_fields, ENC_LITTLE_ENDIAN);
offset += 2;
break;
}
case USB_PID_DATA_DATA0:
case USB_PID_DATA_DATA1:
case USB_PID_DATA_DATA2:
case USB_PID_DATA_MDATA:
{
/* TODO: How to determine the expected DATA size? */
gint data_size = tvb_reported_length_remaining(tvb, offset) - 2;
if (data_size > 0)
{
proto_tree_add_item(tree, hf_usbll_data, tvb, offset, data_size, ENC_NA);
offset += data_size;
}
proto_tree_add_item(tree, hf_usbll_data_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
}
case USB_PID_HANDSHAKE_ACK:
case USB_PID_HANDSHAKE_NAK:
case USB_PID_HANDSHAKE_NYET:
case USB_PID_HANDSHAKE_STALL:
break;
case USB_PID_TOKEN_SOF:
{
static const int *sof_fields[] = {
&hf_usbll_sof_framenum,
&hf_usbll_crc5,
NULL
};
proto_tree_add_bitmask_list(tree, tvb, offset, 2, sof_fields, ENC_LITTLE_ENDIAN);
offset += 2;
break;
}
case USB_PID_SPECIAL_SPLIT:
{
/* S/E fields have special meaning for Isochronous transfers */
gint32 tmp = tvb_get_gint24(tvb, offset, ENC_LITTLE_ENDIAN);
static const int *split_fields[] = {
&hf_usbll_split_hub_addr,
&hf_usbll_split_sc,
&hf_usbll_split_port,
&hf_usbll_split_s,
&hf_usbll_split_e,
&hf_usbll_split_et,
&hf_usbll_split_crc5,
NULL
};
static const int *split_iso_fields[] = {
&hf_usbll_split_hub_addr,
&hf_usbll_split_sc,
&hf_usbll_split_port,
&hf_usbll_split_iso_se,
&hf_usbll_split_et,
&hf_usbll_split_crc5,
NULL
};
if (((tmp & 0x060000) >> 17) == USB_EP_TYPE_ISOCHRONOUS)
{
proto_tree_add_bitmask_list(tree, tvb, offset, 3, split_iso_fields, ENC_LITTLE_ENDIAN);
}
else
{
proto_tree_add_bitmask_list(tree, tvb, offset, 3, split_fields, ENC_LITTLE_ENDIAN);
}
offset += 3;
break;
}
case USB_PID_SPECIAL_PRE_OR_ERR:
break;
case USB_PID_SPECIAL_RESERVED:
break;
default:
break;
}
if (tvb_reported_length_remaining(tvb, offset) > 0)
{
proto_tree_add_expert(tree, pinfo, &ei_undecoded, tvb, offset, -1);
offset += tvb_captured_length_remaining(tvb, offset);
}
return offset;
}
void
proto_register_usbll(void)
{
expert_module_t *expert_module;
static hf_register_info hf[] = {
{ &hf_usbll_pid,
{ "PID", "usbll.pid",
FT_UINT8, BASE_HEX|BASE_EXT_STRING, &usb_packetid_vals_ext, 0x00,
"USB Packet ID", HFILL }},
{ &hf_usbll_addr,
{ "Address", "usbll.addr",
FT_UINT16, BASE_DEC, NULL, 0x007F,
NULL, HFILL }},
{ &hf_usbll_endp,
{ "Endpoint", "usbll.endp",
FT_UINT16, BASE_DEC, NULL, 0x0780,
NULL, HFILL }},
{ &hf_usbll_crc5,
{ "CRC5", "usbll.crc5",
FT_UINT16, BASE_HEX, NULL, 0xF800,
NULL, HFILL }},
{ &hf_usbll_data,
{ "Data", "usbll.data",
FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_usbll_data_crc,
{ "CRC", "usbll.crc16",
FT_UINT16, BASE_HEX, NULL, 0x0000,
NULL, HFILL }},
{ &hf_usbll_sof_framenum,
{ "Frame Number", "usbll.frame_num",
FT_UINT16, BASE_DEC, NULL, 0x07FF,
NULL, HFILL }},
{ &hf_usbll_split_hub_addr,
{ "Hub Address", "usbll.split_hub_addr",
FT_UINT24, BASE_DEC, NULL, 0x00007F,
NULL, HFILL }},
{ &hf_usbll_split_sc,
{ "SC", "usbll.split_sc",
FT_UINT24, BASE_DEC, VALS(usb_start_complete_vals), 0x000080,
NULL, HFILL }},
{ &hf_usbll_split_port,
{ "Port", "usbll.split_port",
FT_UINT24, BASE_DEC, NULL, 0x007F00,
NULL, HFILL }},
{ &hf_usbll_split_s,
{ "Speed", "usbll.split_s",
FT_UINT24, BASE_DEC, VALS(usb_split_speed_vals), 0x008000,
NULL, HFILL }},
{ &hf_usbll_split_e,
{ "E", "usbll.split_e",
FT_UINT24, BASE_DEC, NULL, 0x010000,
"Unused. Must be 0.", HFILL }},
{ &hf_usbll_split_iso_se,
{ "Start and End", "usbll.split_se",
FT_UINT24, BASE_DEC, VALS(usb_split_iso_se_vals), 0x018000,
NULL, HFILL }},
{ &hf_usbll_split_et,
{ "Endpoint Type", "usbll.split_et",
FT_UINT24, BASE_DEC, VALS(usb_endpoint_type_vals), 0x060000,
NULL, HFILL }},
{ &hf_usbll_split_crc5,
{ "CRC5", "usbll.split_crc5",
FT_UINT24, BASE_HEX, NULL, 0xF80000,
NULL, HFILL }},
};
static ei_register_info ei[] = {
{ &ei_invalid_pid, { "usbll.invalid_pid", PI_MALFORMED, PI_ERROR, "Invalid USB Packet ID", EXPFILL }},
{ &ei_undecoded, { "usbll.undecoded", PI_UNDECODED, PI_WARN, "Not dissected yet (report to wireshark.org)", EXPFILL }},
};
static gint *ett[] = {
&ett_usbll,
};
proto_usbll = proto_register_protocol("USB Link Layer", "USBLL", "usbll");
proto_register_field_array(proto_usbll, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_module = expert_register_protocol(proto_usbll);
expert_register_field_array(expert_module, ei, array_length(ei));
register_dissector("usbll", dissect_usbll_packet, proto_usbll);
}
void
proto_reg_handoff_usbll(void)
{
usbll_handle = create_dissector_handle(dissect_usbll_packet, proto_usbll);
dissector_add_uint("wtap_encap", WTAP_ENCAP_USB_2_0, usbll_handle);
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -472,6 +472,9 @@ static const struct {
/* IEEE 802.15.4 TAP */
{ 283, WTAP_ENCAP_IEEE802_15_4_TAP },
/* USB 2.0/1.1/1.0 packets as transmitted over the cable */
{ 288, WTAP_ENCAP_USB_2_0 },
/*
* To repeat:
*

View File

@ -975,6 +975,8 @@ static struct encap_type_info encap_table_base[] = {
/* WTAP_ENCAP_LOG_3GPP */
{ "log_3GPP", "3GPP Phone Log" },
/* WTAP_ENCAP_USB_2_0 */
{ "usb-20", "USB 2.0/1.1/1.0 packets" },
};
WS_DLL_LOCAL

View File

@ -288,6 +288,7 @@ extern "C" {
#define WTAP_ENCAP_VPP 205
#define WTAP_ENCAP_IEEE802_15_4_TAP 206
#define WTAP_ENCAP_LOG_3GPP 207
#define WTAP_ENCAP_USB_2_0 208
/* After adding new item here, please also add new item to encap_table_base array */