/* Man this is suboptimal.
- * The USB Header and the setup data are LITTLE ENDIAN
- * but all the real usb data is BIG ENDIAN.
+ * The USB Header and the setup data are BIG ENDIAN
+ * but all the real usb data is LITTLE ENDIAN.
*/
/* packet-usb.c
*
* usb basic dissector
* By Paolo Abeni <paolo.abeni@email.com>
+ * Ronnie Sahlberg 2006
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <epan/emem.h>
#include <epan/conversation.h>
#include <string.h>
+#include "packet-usb.h"
/* protocols and header fields */
static int proto_usb = -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_bInterfaceProtocol = -1;
+static int hf_usb_iInterface = -1;
+static int hf_usb_bEndpointAddress = -1;
+static int hf_usb_bmAttributes = -1;
+static int hf_usb_wMaxPacketSize = -1;
+static int hf_usb_bInterval = -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_selfpowered = -1;
+static int hf_usb_configuration_remotewakeup = -1;
+static int hf_usb_bEndpointAddress_direction = -1;
+static int hf_usb_bEndpointAddress_number = -1;
static gint usb_hdr = -1;
static gint usb_setup_hdr = -1;
static gint ett_usb_setup_bmrequesttype = -1;
static gint ett_descriptor_device = -1;
+static gint ett_configuration_bmAttributes = -1;
+static gint ett_configuration_bEndpointAddress = -1;
-/* there is one such structure for each device/endpoint conversation */
-typedef struct _usb_conv_info_t {
- emem_tree_t *transactions;
-} usb_conv_info_t;
+static dissector_table_t usb_bulk_dissector_table;
+static dissector_table_t usb_control_dissector_table;
-/* there is one such structure for each request/response */
-typedef struct _usb_trans_info_t {
- guint32 request_in;
- guint32 response_in;
- guint8 requesttype;
- guint8 request;
- union {
- struct {
- guint8 type;
- guint8 index;
- } get_descriptor;
- };
-} usb_trans_info_t;
typedef enum {
URB_CONTROL_INPUT,
{0, NULL}
};
+static const value_string usb_interfaceclass_vals[] = {
+ {IF_CLASS_MASSTORAGE, "Mass Storage Class"},
+ {0, NULL}
+};
+
+
static const value_string usb_urb_type_vals[] = {
{URB_CONTROL_INPUT, "URB_CONTROL_INPUT"},
{URB_CONTROL_OUTPUT,"URB_CONTROL_OUTPUT"},
};
+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 = conversation_get_proto_data(conversation, proto_usb);
+ if(!usb_conv_info){
+ /* no not yet so create some */
+ usb_conv_info = se_alloc(sizeof(usb_conv_info_t));
+ usb_conv_info->class=IF_CLASS_UNKNOWN;
+ usb_conv_info->transactions=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "usb transactions");
+ usb_conv_info->masstorage=NULL;
+
+ conversation_add_proto_data(conversation, proto_usb, usb_conv_info);
+ }
+
+ return usb_conv_info;
+}
+
static conversation_t *
-get_usb_conversation(packet_info *pinfo)
+get_usb_conversation(packet_info *pinfo, guint32 src_endpoint, guint32 dst_endpoint)
{
conversation_t *conversation;
conversation = find_conversation(pinfo->fd->num,
&pinfo->src, &pinfo->dst,
pinfo->ptype,
- pinfo->srcport, pinfo->destport, 0);
+ src_endpoint, dst_endpoint, 0);
if(conversation){
return conversation;
}
conversation = conversation_new(pinfo->fd->num,
&pinfo->src, &pinfo->dst,
pinfo->ptype,
- pinfo->srcport, pinfo->destport, 0);
+ src_endpoint, dst_endpoint, 0);
return conversation;
}
/* 9.6.2 */
static int
-dissect_usb_device_qualifier_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_)
+dissect_usb_device_qualifier_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
{
proto_item *item=NULL;
proto_tree *tree=NULL;
/* 9.6.1 */
static int
-dissect_usb_device_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_)
+dissect_usb_device_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
{
proto_item *item=NULL;
proto_tree *tree=NULL;
/* 9.6.7 */
static int
-dissect_usb_string_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info)
+dissect_usb_string_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info, usb_conv_info_t *usb_conv_info _U_)
{
proto_item *item=NULL;
proto_tree *tree=NULL;
tree=proto_item_add_subtree(item, ett_descriptor_device);
}
-
/* bLength */
proto_tree_add_item(tree, hf_usb_bLength, tvb, offset, 1, TRUE);
len=tvb_get_guint8(tvb, offset);
offset++;
-
/* bDescriptorType */
proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset, 1, TRUE);
offset++;
}
+
+/* 9.6.5 */
+static int
+dissect_usb_interface_descriptor(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info, usb_conv_info_t *usb_conv_info)
+{
+ proto_item *item=NULL;
+ proto_tree *tree=NULL;
+ int old_offset=offset;
+
+ if(parent_tree){
+ item=proto_tree_add_text(parent_tree, tvb, offset, 0, "INTERFACE DESCRIPTOR");
+ tree=proto_item_add_subtree(item, ett_descriptor_device);
+ }
+
+ /* bLength */
+ proto_tree_add_item(tree, hf_usb_bLength, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bDescriptorType */
+ proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bInterfaceNumber */
+ proto_tree_add_item(tree, hf_usb_bInterfaceNumber, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bAlternateSetting */
+ proto_tree_add_item(tree, hf_usb_bAlternateSetting, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bNumEndpoints */
+ proto_tree_add_item(tree, hf_usb_bNumEndpoints, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bInterfaceClass */
+ proto_tree_add_item(tree, hf_usb_bInterfaceClass, tvb, offset, 1, TRUE);
+ /* save the class so we can access it later in the endpoint descriptor */
+ usb_conv_info->class=tvb_get_guint8(tvb, offset);
+ if(!pinfo->fd->flags.visited){
+ usb_trans_info->interface_info=se_alloc(sizeof(usb_conv_info_t));
+ usb_trans_info->interface_info->class=tvb_get_guint8(tvb, offset);
+ usb_trans_info->interface_info->transactions=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "usb transactions");
+ usb_trans_info->interface_info->masstorage=NULL;
+ }
+ offset++;
+
+ /* bInterfaceSubClass */
+ proto_tree_add_item(tree, hf_usb_bInterfaceSubClass, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bInterfaceProtocol */
+ proto_tree_add_item(tree, hf_usb_bInterfaceProtocol, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* iInterface */
+ proto_tree_add_item(tree, hf_usb_iInterface, tvb, offset, 1, TRUE);
+ offset++;
+
+ if(item){
+ proto_item_set_len(item, offset-old_offset);
+ }
+
+ return offset;
+}
+
+/* 9.6.6 */
+static const true_false_string tfs_endpoint_direction = {
+ "IN Endpoint",
+ "OUT Endpoint"
+};
+static int
+dissect_usb_endpoint_descriptor(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ proto_item *item=NULL;
+ proto_tree *tree=NULL;
+ proto_item *endpoint_item=NULL;
+ proto_tree *endpoint_tree=NULL;
+ int old_offset=offset;
+ guint8 endpoint;
+
+ if(parent_tree){
+ item=proto_tree_add_text(parent_tree, tvb, offset, 0, "ENDPOINT DESCRIPTOR");
+ tree=proto_item_add_subtree(item, ett_descriptor_device);
+ }
+
+ /* bLength */
+ proto_tree_add_item(tree, hf_usb_bLength, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bDescriptorType */
+ proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bEndpointAddress */
+ if(tree){
+ endpoint_item=proto_tree_add_item(tree, hf_usb_bEndpointAddress, tvb, offset, 1, TRUE);
+ 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, TRUE);
+ 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, TRUE);
+ proto_item_append_text(endpoint_item, " Endpoint:%d", endpoint);
+ offset++;
+
+ /* 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->flags.visited)&&usb_trans_info->interface_info){
+ conversation_t *conversation;
+
+ if(pinfo->destport==NO_ENDPOINT){
+ conversation=get_usb_conversation(pinfo, endpoint, pinfo->destport);
+ } else {
+ conversation=get_usb_conversation(pinfo, pinfo->srcport, endpoint);
+ }
+
+ conversation_add_proto_data(conversation, proto_usb, usb_trans_info->interface_info);
+ }
+
+ /* bmAttributes */
+ proto_tree_add_item(tree, hf_usb_bmAttributes, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* wMaxPacketSize */
+ proto_tree_add_item(tree, hf_usb_wMaxPacketSize, tvb, offset, 2, TRUE);
+ offset+=2;
+
+ /* bInterval */
+ proto_tree_add_item(tree, hf_usb_bInterval, tvb, offset, 1, TRUE);
+ offset++;
+
+ if(item){
+ proto_item_set_len(item, offset-old_offset);
+ }
+
+ return offset;
+}
+
+/* 9.6.3 */
+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_trans_info_t *usb_trans_info, usb_conv_info_t *usb_conv_info)
+{
+ proto_item *item=NULL;
+ proto_tree *tree=NULL;
+ int old_offset=offset;
+ guint16 len;
+ proto_item *flags_item=NULL;
+ proto_tree *flags_tree=NULL;
+ guint8 flags;
+ proto_item *power_item=NULL;
+ guint8 power;
+
+ if(parent_tree){
+ item=proto_tree_add_text(parent_tree, tvb, offset, 0, "CONFIGURATION DESCRIPTOR");
+ tree=proto_item_add_subtree(item, ett_descriptor_device);
+ }
+
+ /* bLength */
+ proto_tree_add_item(tree, hf_usb_bLength, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bDescriptorType */
+ proto_tree_add_item(tree, hf_usb_bDescriptorType, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* wTotalLength */
+ proto_tree_add_item(tree, hf_usb_wTotalLength, tvb, offset, 2, TRUE);
+ len=tvb_get_letohs(tvb, offset);
+ offset+=2;
+
+ /* bNumInterfaces */
+ proto_tree_add_item(tree, hf_usb_bNumInterfaces, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bConfigurationValue */
+ proto_tree_add_item(tree, hf_usb_bConfigurationValue, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* iConfiguration */
+ proto_tree_add_item(tree, hf_usb_iConfiguration, tvb, offset, 1, TRUE);
+ offset++;
+
+ /* bmAttributes */
+ if(tree){
+ flags_item=proto_tree_add_item(tree, hf_usb_configuration_bmAttributes, tvb, offset, 1, TRUE);
+ 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_selfpowered, tvb, offset, 1, TRUE);
+ proto_item_append_text(flags_item, " %sSELF-POWERED", (flags&0x40)?"":"NOT ");
+ flags&=~0x40;
+ proto_tree_add_item(flags_tree, hf_usb_configuration_remotewakeup, tvb, offset, 1, TRUE);
+ proto_item_append_text(flags_item, " %sREMOTE-WAKEUP", (flags&0x20)?"":"NO ");
+ flags&=~0x20;
+ offset++;
+
+ /* bMaxPower */
+ power_item=proto_tree_add_item(tree, hf_usb_bMaxPower, tvb, offset, 1, TRUE);
+ power=tvb_get_guint8(tvb, offset);
+ proto_item_append_text(power_item, " (%dmA)", power*2);
+ offset++;
+
+ /* initialize interface_info to NULL */
+ usb_trans_info->interface_info=NULL;
+
+ /* decode any additional interface and endpoint descriptors */
+ while(len>(old_offset-offset)){
+ guint8 next_type;
+
+ if(tvb_length_remaining(tvb, offset)<2){
+ 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_trans_info, usb_conv_info);
+ break;
+ case USB_DT_ENDPOINT:
+ offset=dissect_usb_endpoint_descriptor(pinfo, parent_tree, tvb, offset, usb_trans_info, usb_conv_info);
+ break;
+ default:
+ return offset;
+ }
+ }
+
+ if(item){
+ proto_item_set_len(item, offset-old_offset);
+ }
+
+ return offset;
+}
+
+
static void
-dissect_usb_setup_get_descriptor(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info)
+dissect_usb_setup_get_descriptor(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info, usb_conv_info_t *usb_conv_info)
{
if(is_request){
/* descriptor type */
}
switch(usb_trans_info->get_descriptor.type){
case USB_DT_DEVICE:
- offset=dissect_usb_device_descriptor(pinfo, tree, tvb, offset, usb_trans_info);
+ offset=dissect_usb_device_descriptor(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info);
+ break;
+ case USB_DT_CONFIGURATION:
+ offset=dissect_usb_configuration_descriptor(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info);
break;
case USB_DT_STRING:
- offset=dissect_usb_string_descriptor(pinfo, tree, tvb, offset, usb_trans_info);
+ offset=dissect_usb_string_descriptor(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info);
+ break;
+ case USB_DT_INTERFACE:
+ offset=dissect_usb_interface_descriptor(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info);
+ break;
+ case USB_DT_ENDPOINT:
+ offset=dissect_usb_endpoint_descriptor(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info);
break;
case USB_DT_DEVICE_QUALIFIER:
- offset=dissect_usb_device_qualifier_descriptor(pinfo, tree, tvb, offset, usb_trans_info);
+ offset=dissect_usb_device_qualifier_descriptor(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info);
break;
default:
/* XXX dissect the descriptor coming back from the device */
-typedef void (*usb_setup_dissector)(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info);
+typedef void (*usb_setup_dissector)(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info, usb_conv_info_t *usb_conv_info);
typedef struct _usb_setup_dissector_table_t {
guint8 request;
/* set up addresses and ports */
switch(type){
+ case URB_BULK_INPUT:
+ /* Bulk input are responses if they contain payload data and
+ * requests otherwise.
+ */
+ if(tvb_length_remaining(tvb, offset)>0){
+ src_addr=tmp_addr;
+ src_port=endpoint;
+ dst_addr=0xffffffff;
+ dst_port=NO_ENDPOINT;
+ is_request=FALSE;
+ } else {
+ src_addr=0xffffffff;
+ src_port=NO_ENDPOINT;
+ dst_addr=tmp_addr;
+ dst_port=endpoint;
+ is_request=TRUE;
+ }
+ break;
+ case URB_BULK_OUTPUT:
+ /* Bulk output are requests if they contain payload data and
+ * responses otherwise.
+ */
+ if(tvb_length_remaining(tvb, offset)>0){
+ src_addr=0xffffffff;
+ src_port=NO_ENDPOINT;
+ dst_addr=tmp_addr;
+ dst_port=endpoint;
+ is_request=TRUE;
+ } else {
+ src_addr=tmp_addr;
+ src_port=endpoint;
+ dst_addr=0xffffffff;
+ dst_port=NO_ENDPOINT;
+ is_request=FALSE;
+ }
+ break;
case URB_CONTROL_INPUT:
/* CONTROL INPUT packets are requests if they contain a "setup"
* blob and responses othervise
*/
if(setup){
src_addr=0xffffffff;
+ src_port=NO_ENDPOINT;
dst_addr=tmp_addr;
- src_port=0xffff;
dst_port=endpoint;
is_request=TRUE;
} else {
src_addr=tmp_addr;
- dst_addr=0xffffffff;
src_port=endpoint;
- dst_port=0xffff;
+ dst_addr=0xffffffff;
+ dst_port=NO_ENDPOINT;
is_request=FALSE;
}
break;
/* dont know */
src_addr=0xffffffff;
dst_addr=0xffffffff;
- src_port=0xffff;
- dst_port=0xffff;
+ src_port=NO_ENDPOINT;
+ dst_port=NO_ENDPOINT;
is_request=FALSE;
}
SET_ADDRESS(&pinfo->net_src, AT_USB, USB_ADDR_LEN, (char *)&src_addr);
pinfo->destport=dst_port;
- conversation=get_usb_conversation(pinfo);
+ conversation=get_usb_conversation(pinfo, pinfo->srcport, pinfo->destport);
+
+ usb_conv_info=get_usb_conv_info(conversation);
/* do we have conversation specific data ? */
usb_conv_info = conversation_get_proto_data(conversation, proto_usb);
if(!usb_conv_info){
/* no not yet so create some */
usb_conv_info = se_alloc(sizeof(usb_conv_info_t));
+ usb_conv_info->class=IF_CLASS_UNKNOWN;
usb_conv_info->transactions=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "usb transactions");
+ usb_conv_info->masstorage=NULL;
conversation_add_proto_data(conversation, proto_usb, usb_conv_info);
}
switch(type){
+ case URB_BULK_INPUT:
+ {
+ proto_item *item;
+
+ item=proto_tree_add_uint(tree, hf_usb_bInterfaceClass, tvb, offset, 0, usb_conv_info->class);
+ PROTO_ITEM_SET_GENERATED(item);
+ if(tvb_length_remaining(tvb, offset)){
+ tvbuff_t *next_tvb;
+
+ pinfo->usb_conv_info=usb_conv_info;
+ next_tvb=tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), tvb_reported_length_remaining(tvb, offset));
+ if(dissector_try_port(usb_bulk_dissector_table, usb_conv_info->class, next_tvb, pinfo, parent)){
+ return;
+ }
+ }
+ }
+ break;
+ case URB_BULK_OUTPUT:
+ {
+ proto_item *item;
+
+ item=proto_tree_add_uint(tree, hf_usb_bInterfaceClass, tvb, offset, 0, usb_conv_info->class);
+ PROTO_ITEM_SET_GENERATED(item);
+ if(tvb_length_remaining(tvb, offset)){
+ tvbuff_t *next_tvb;
+
+ pinfo->usb_conv_info=usb_conv_info;
+ next_tvb=tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), tvb_reported_length_remaining(tvb, offset));
+ if(dissector_try_port(usb_bulk_dissector_table, usb_conv_info->class, next_tvb, pinfo, parent)){
+ return;
+ }
+ }
+ }
+ break;
case URB_CONTROL_INPUT:
{
const usb_setup_dissector_table_t *tmp;
guint8 requesttype, request;
usb_trans_info_t *usb_trans_info;
+ ti=proto_tree_add_uint(tree, hf_usb_bInterfaceClass, tvb, offset, 0, usb_conv_info->class);
+ PROTO_ITEM_SET_GENERATED(ti);
+
if(is_request){
+ tvbuff_t *next_tvb;
+
/* this is a request */
ti = proto_tree_add_protocol_format(tree, proto_usb, tvb, offset, sizeof(usb_setup_t), "URB setup");
setup_tree = proto_item_add_subtree(ti, usb_setup_hdr);
requesttype=tvb_get_guint8(tvb, offset);
offset=dissect_usb_setup_bmrequesttype(setup_tree, tvb, offset);
- request=tvb_get_guint8(tvb, offset);
- proto_tree_add_item(setup_tree, hf_usb_request, tvb, offset, 1, TRUE);
- offset += 1;
+ /* read the request code and spawn off to a class specific
+ * dissector if found
+ */
+ request=tvb_get_guint8(tvb, offset);
usb_trans_info=se_tree_lookup32(usb_conv_info->transactions, pinfo->fd->num);
if(!usb_trans_info){
usb_trans_info=se_alloc(sizeof(usb_trans_info_t));
usb_trans_info->request=request;
se_tree_insert32(usb_conv_info->transactions, pinfo->fd->num, usb_trans_info);
}
+ usb_conv_info->usb_trans_info=usb_trans_info;
+ pinfo->usb_conv_info=usb_conv_info;
+
+ /* Try to find a class specific dissector */
+ next_tvb=tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), tvb_reported_length_remaining(tvb, offset));
+ if(dissector_try_port(usb_control_dissector_table, usb_conv_info->class, next_tvb, pinfo, tree)){
+ return;
+ }
+
+ /*
+ * This was a standard request which is managed by this dissector
+ */
+ proto_tree_add_item(setup_tree, hf_usb_request, tvb, offset, 1, TRUE);
+ offset += 1;
if (check_col(pinfo->cinfo, COL_INFO)) {
col_clear(pinfo->cinfo, COL_INFO);
}
if(dissector){
- dissector(pinfo, setup_tree, tvb, offset, is_request, usb_trans_info);
+ dissector(pinfo, setup_tree, tvb, offset, is_request, usb_trans_info, usb_conv_info);
offset+=6;
} else {
- proto_tree_add_item(setup_tree, hf_usb_value, tvb, offset, 2, TRUE);
+ proto_tree_add_item(setup_tree, hf_usb_value, tvb, offset, 2, FALSE);
offset += 2;
- proto_tree_add_item(setup_tree, hf_usb_index, tvb, offset, 2, TRUE);
+ proto_tree_add_item(setup_tree, hf_usb_index, tvb, offset, 2, FALSE);
offset += 2;
- proto_tree_add_item(setup_tree, hf_usb_length, tvb, offset, 2, TRUE);
+ proto_tree_add_item(setup_tree, hf_usb_length, tvb, offset, 2, FALSE);
offset += 2;
}
} else {
+ tvbuff_t *next_tvb;
+
/* this is a response */
if(pinfo->fd->flags.visited){
usb_trans_info=se_tree_lookup32(usb_conv_info->transactions, pinfo->fd->num);
}
}
if(usb_trans_info){
+ usb_conv_info->usb_trans_info=usb_trans_info;
dissector=NULL;
for(tmp=setup_dissectors;tmp->dissector;tmp++){
if(tmp->request==usb_trans_info->request){
break;
}
}
-
+
+ /* Try to find a class specific dissector */
+ usb_conv_info->usb_trans_info=usb_trans_info;
+ pinfo->usb_conv_info=usb_conv_info;
+ next_tvb=tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), tvb_reported_length_remaining(tvb, offset));
+ if(dissector_try_port(usb_control_dissector_table, usb_conv_info->class, next_tvb, pinfo, tree)){
+ return;
+ }
+
if (check_col(pinfo->cinfo, COL_INFO)) {
col_clear(pinfo->cinfo, COL_INFO);
col_append_fstr(pinfo->cinfo, COL_INFO, "%s Response",
}
if(dissector){
- dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info);
+ dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info, usb_conv_info);
}
} else {
/* could not find a matching request */
offset=dissect_usb_setup_bmrequesttype(setup_tree, tvb, offset);
request=tvb_get_guint8(tvb, offset);
- proto_tree_add_item(setup_tree, hf_usb_request, tvb, offset, 1, TRUE);
+ proto_tree_add_item(setup_tree, hf_usb_request, tvb, offset, 1, FALSE);
offset += 1;
- proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, TRUE);
+ proto_tree_add_item(tree, hf_usb_value, tvb, offset, 2, FALSE);
offset += 2;
- proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, TRUE);
+ proto_tree_add_item(tree, hf_usb_index, tvb, offset, 2, FALSE);
offset += 2;
- proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, TRUE);
+ proto_tree_add_item(tree, hf_usb_length, tvb, offset, 2, FALSE);
offset += 2;
}
proto_tree_add_item(tree, hf_usb_data, tvb,
- offset, tvb_length_remaining(tvb, offset), TRUE);
+ offset, tvb_length_remaining(tvb, offset), FALSE);
}
void
{ &hf_usb_setup,
{ "Setup", "usb.setup", FT_UINT32, BASE_DEC, NULL, 0x0,
- "USB setup", HFILL }},
+ "USB setup", HFILL }},
{ &hf_usb_endpoint_number,
{ "Endpoint", "usb.endpoint_number", FT_UINT32, BASE_HEX, NULL, 0x0,
{ "bString", "usb.bString", FT_STRING, BASE_NONE,
NULL, 0x0, "", HFILL }},
+ { &hf_usb_bInterfaceNumber,
+ { "bInterfaceNumber", "usb.bInterfaceNumber", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bAlternateSetting,
+ { "bAlternateSetting","usb.bAlternateSetting", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bNumEndpoints,
+ { "bNumEndpoints","usb.bNumEndpoints", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bInterfaceClass,
+ { "bInterfaceClass", "usb.bInterfaceClass", FT_UINT8, BASE_HEX,
+ VALS(usb_interfaceclass_vals), 0x0, "", HFILL }},
+
+ { &hf_usb_bInterfaceSubClass,
+ { "bInterfaceSubClass", "usb.bInterfaceSubClass", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bInterfaceProtocol,
+ { "bInterfaceProtocol", "usb.bInterfaceProtocol", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_iInterface,
+ { "iInterface", "usb.iInterface", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bEndpointAddress,
+ { "bEndpointAddress", "usb.bEndpointAddress", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_configuration_bmAttributes,
+ { "Configuration bmAttributes", "usb.configuration.bmAttributes", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bmAttributes,
+ { "bmAttributes", "usb.bmAttributes", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_wMaxPacketSize,
+ { "wMaxPacketSize", "usb.wMaxPacketSize", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bInterval,
+ { "bInterval", "usb.bInterval", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_wTotalLength,
+ { "wTotalLength", "usb.wTotalLength", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bNumInterfaces,
+ { "bNumInterfaces", "usb.bNumInterfaces", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bConfigurationValue,
+ { "bConfigurationValue", "usb.bConfigurationValue", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_iConfiguration,
+ { "iConfiguration", "usb.iConfiguration", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_bMaxPower,
+ { "bMaxPower", "usb.bMaxPower", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+ { &hf_usb_configuration_selfpowered,
+ { "Self-Powered", "usb.configuration.selfpowered", FT_BOOLEAN, 8,
+ TFS(&tfs_selfpowered), 0x40, "", HFILL }},
+
+ { &hf_usb_configuration_remotewakeup,
+ { "Remote Wakeup", "usb.configuration.remotewakeup", FT_BOOLEAN, 8,
+ TFS(&tfs_remotewakeup), 0x20, "", HFILL }},
+
+ { &hf_usb_bEndpointAddress_number,
+ { "Endpoint Number", "usb.bEndpointAddress.number", FT_UINT8, BASE_HEX,
+ NULL, 0x0f, "", HFILL }},
+
+ { &hf_usb_bEndpointAddress_direction,
+ { "Direction", "usb.bEndpointAddress.direction", FT_BOOLEAN, 8,
+ TFS(&tfs_endpoint_direction), 0x80, "", HFILL }},
+
};
static gint *usb_subtrees[] = {
&usb_hdr,
&usb_setup_hdr,
&ett_usb_setup_bmrequesttype,
- &ett_descriptor_device
+ &ett_descriptor_device,
+ &ett_configuration_bmAttributes,
+ &ett_configuration_bEndpointAddress
};
proto_register_subtree_array(usb_subtrees, array_length(usb_subtrees));
register_dissector("usb", dissect_usb, proto_usb);
+
+ usb_bulk_dissector_table = register_dissector_table("usb.bulk",
+ "USB bulk endpoint", FT_UINT8, BASE_DEC);
+
+ usb_control_dissector_table = register_dissector_table("usb.control",
+ "USB control endpoint", FT_UINT8, BASE_DEC);
+
}
void