aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-usb-hid.c
diff options
context:
space:
mode:
authorStig Bjørlykke <stig@bjorlykke.org>2009-10-29 21:42:16 +0000
committerStig Bjørlykke <stig@bjorlykke.org>2009-10-29 21:42:16 +0000
commit6a2aae878d6fae03f67f447246aaff856543aab7 (patch)
tree1cacdc5b08ef705586a64c4f380b2405cb24d1c4 /epan/dissectors/packet-usb-hid.c
parent373fff9846dfad061c97d88043955e1998acd4cb (diff)
From Marton Nemeth via bug 4173:
Parse USB HID class-specific requests. svn path=/trunk/; revision=30762
Diffstat (limited to 'epan/dissectors/packet-usb-hid.c')
-rw-r--r--epan/dissectors/packet-usb-hid.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/epan/dissectors/packet-usb-hid.c b/epan/dissectors/packet-usb-hid.c
index 8cca7ddd00..5d9a104378 100644
--- a/epan/dissectors/packet-usb-hid.c
+++ b/epan/dissectors/packet-usb-hid.c
@@ -87,6 +87,16 @@ static int hf_usb_hid_localitem_delimiter = -1;
static gint ett_usb_hid_report = -1;
static gint ett_usb_hid_item_header = -1;
+static gint ett_usb_hid_wValue = -1;
+
+static int hf_usb_hid_request = -1;
+static int hf_usb_hid_value = -1;
+static int hf_usb_hid_index = -1;
+static int hf_usb_hid_length = -1;
+static int hf_usb_hid_report_type = -1;
+static int hf_usb_hid_report_id = -1;
+static int hf_usb_hid_duration = -1;
+static int hf_usb_hid_zero = -1;
static const true_false_string tfs_mainitem_bit0 = {"Data", "Constant"};
static const true_false_string tfs_mainitem_bit1 = {"Array", "Variable"};
@@ -552,6 +562,246 @@ dissect_usb_hid_get_report_descriptor(packet_info *pinfo _U_, proto_tree *parent
return offset;
}
+/* Dissector for HID GET_REPORT request. See USBHID 1.11, Chapter 7.2.1 Get_Report Request */
+static void
+dissect_usb_hid_get_report(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+
+ if (is_request) {
+ item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, TRUE);
+ subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
+
+ /* Report Type in the high byte, Report ID in the low byte */
+ proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, TRUE);
+ offset++;
+ proto_tree_add_item(subtree, hf_usb_hid_report_type, tvb, offset, 1, TRUE);
+ offset++;
+
+ proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, TRUE);
+ offset += 2;
+ } else {
+ }
+}
+
+/* Dissector for HID SET_REPORT request. See USBHID 1.11, Chapter 7.2.2 Set_Report Request */
+static void
+dissect_usb_hid_set_report(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+
+ if (is_request) {
+ item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, TRUE);
+ subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
+
+ proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, TRUE);
+ offset++;
+ proto_tree_add_item(subtree, hf_usb_hid_report_type, tvb, offset, 1, TRUE);
+ offset++;
+
+ proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, TRUE);
+ offset += 2;
+ } else {
+ }
+}
+
+
+/* Dissector for HID GET_IDLE request. See USBHID 1.11, Chapter 7.2.3 Get_Idle Request */
+static void
+dissect_usb_hid_get_idle(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+
+ if (is_request) {
+ item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, TRUE);
+ subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
+
+ proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, TRUE);
+ offset++;
+ proto_tree_add_item(subtree, hf_usb_hid_zero, tvb, offset, 1, TRUE);
+ offset++;
+
+ proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, TRUE);
+ offset += 2;
+ } else {
+ }
+}
+
+/* Dissector for HID SET_IDLE request. See USBHID 1.11, Chapter 7.2.4 Set_Idle Request */
+static void
+dissect_usb_hid_set_idle(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+
+ if (is_request) {
+ item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, TRUE);
+ subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
+
+ /* Duration in the high byte, Report ID in the low byte */
+ proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, TRUE);
+ offset++;
+ proto_tree_add_item(subtree, hf_usb_hid_duration, tvb, offset, 1, TRUE);
+ offset++;
+
+ proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, TRUE);
+ offset += 2;
+ } else {
+ }
+}
+
+/* Dissector for HID GET_PROTOCOL request. See USBHID 1.11, Chapter 7.2.5 Get_Protocol Request */
+static void
+dissect_usb_hid_get_protocol(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ if (is_request) {
+ proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, TRUE);
+ offset += 2;
+ } else {
+ }
+}
+
+/* Dissector for HID SET_PROTOCOL request. See USBHID 1.11, Chapter 7.2.6 Set_Protocol Request */
+static void
+dissect_usb_hid_set_protocol(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
+{
+ if (is_request) {
+ proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, TRUE);
+ offset += 2;
+ } else {
+ }
+}
+
+
+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;
+ usb_setup_dissector dissector;
+} usb_setup_dissector_table_t;
+
+
+/* USBHID 1.11, Chapter 7.2 Class-Specific Requests */
+#define USB_HID_SETUP_GET_REPORT 0x01
+#define USB_HID_SETUP_GET_IDLE 0x02
+#define USB_HID_SETUP_GET_PROTOCOL 0x03
+/* 0x04..0x08: Reserved */
+#define USB_HID_SETUP_SET_REPORT 0x09
+#define USB_HID_SETUP_SET_IDLE 0x0A
+#define USB_HID_SETUP_SET_PROTOCOL 0x0B
+
+static const usb_setup_dissector_table_t setup_dissectors[] = {
+ { USB_HID_SETUP_GET_REPORT, dissect_usb_hid_get_report },
+ { USB_HID_SETUP_GET_IDLE, dissect_usb_hid_get_idle },
+ { USB_HID_SETUP_GET_PROTOCOL, dissect_usb_hid_get_protocol },
+ { USB_HID_SETUP_SET_REPORT, dissect_usb_hid_set_report },
+ { USB_HID_SETUP_SET_IDLE, dissect_usb_hid_set_idle },
+ { USB_HID_SETUP_SET_PROTOCOL, dissect_usb_hid_set_protocol },
+ { 0, NULL }
+};
+
+static const value_string setup_request_names_vals[] = {
+ { USB_HID_SETUP_GET_REPORT, "GET_REPORT" },
+ { USB_HID_SETUP_GET_IDLE, "GET_IDLE" },
+ { USB_HID_SETUP_GET_PROTOCOL, "GET_PROTOCOL" },
+ { USB_HID_SETUP_SET_REPORT, "SET_REPORT" },
+ { USB_HID_SETUP_SET_IDLE, "SET_IDLE" },
+ { USB_HID_SETUP_SET_PROTOCOL, "SET_PROTOCOL" },
+ { 0, NULL }
+};
+
+static const value_string usb_hid_report_type_vals[] = {
+ { 1, "Input" },
+ { 2, "Output" },
+ { 3, "Feature" },
+ { 0, NULL }
+};
+
+/* Dissector for HID class-specific control request as defined in
+ * USBHID 1.11, Chapter 7.2.
+ * Returns TRUE if a class specific dissector was found
+ * and FALSE otherwise.
+ */
+static gint
+dissect_usb_hid_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ gboolean is_request;
+ usb_conv_info_t *usb_conv_info;
+ usb_trans_info_t *usb_trans_info;
+ int offset = 0;
+ usb_setup_dissector dissector;
+ const usb_setup_dissector_table_t *tmp;
+
+ is_request = (pinfo->srcport==NO_ENDPOINT);
+
+ usb_conv_info = pinfo->usb_conv_info;
+ usb_trans_info = usb_conv_info->usb_trans_info;
+
+ /* See if we can find a class specific dissector for this request */
+ dissector = NULL;
+
+ /* Check valid values for bmRequestType. See Chapter 7.2 in USBHID 1.11 */
+ if ((usb_trans_info->requesttype & 0x7F) ==
+ ((RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_INTERFACE)) {
+ for (tmp = setup_dissectors; tmp->dissector; tmp++) {
+ if (tmp->request == usb_trans_info->request) {
+ dissector = tmp->dissector;
+ break;
+ }
+ }
+ }
+ /* No, we could not find any class specific dissector for this request
+ * return FALSE and let USB try any of the standard requests.
+ */
+ if (!dissector) {
+ return FALSE;
+ }
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBHID");
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_clear(pinfo->cinfo, COL_INFO);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+ val_to_str(usb_trans_info->request, setup_request_names_vals, "Unknown type %x"),
+ is_request ? "Request" : "Response");
+ }
+
+ if (is_request) {
+ proto_tree_add_item(tree, hf_usb_hid_request, tvb, offset, 1, TRUE);
+ offset += 1;
+ }
+
+ dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info, usb_conv_info);
+ return TRUE;
+}
+
void
proto_register_usb_hid(void)
{
@@ -755,14 +1005,55 @@ proto_register_usb_hid(void)
{ "Item data", "usbhid.item.data", FT_BYTES, BASE_NONE,
NULL, 0, NULL, HFILL }},
+ /* USB HID specific requests */
+ { &hf_usb_hid_request,
+ { "bRequest", "usbhid.setup.bRequest", FT_UINT8, BASE_HEX, VALS(setup_request_names_vals), 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_value,
+ { "wValue", "usbhid.setup.wValue", FT_UINT16, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_index,
+ { "wIndex", "usbhid.setup.wIndex", FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_length,
+ { "wLength", "usbhid.setup.wLength", FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_report_type,
+ { "ReportType", "usbhid.setup.ReportType", FT_UINT8, BASE_DEC,
+ VALS(usb_hid_report_type_vals), 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_report_id,
+ { "ReportID", "usbhid.setup.ReportID", FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_duration,
+ { "Duration", "usbhid.setup.Duration", FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_usb_hid_zero,
+ { "(zero)", "usbhid.setup.zero", FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }}
+
};
static gint *usb_hid_subtrees[] = {
&ett_usb_hid_report,
&ett_usb_hid_item_header,
+ &ett_usb_hid_wValue
};
+ dissector_handle_t usb_hid_control_handle;
+
proto_usb_hid = proto_register_protocol("USB HID", "USBHID", "usbhid");
proto_register_field_array(proto_usb_hid, hf, array_length(hf));
proto_register_subtree_array(usb_hid_subtrees, array_length(usb_hid_subtrees));
+
+ usb_hid_control_handle = new_create_dissector_handle(dissect_usb_hid_control, proto_usb_hid);
+ dissector_add("usb.control", IF_CLASS_HID, usb_hid_control_handle);
+
}