add a dissector table for class specific control input/output pdus
authorsahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 22 Oct 2006 11:49:23 +0000 (11:49 +0000)
committersahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 22 Oct 2006 11:49:23 +0000 (11:49 +0000)
implement class specific control commands : reset and getmaxlun for mass storage

now with a better understanding of the problem space for usb and device classes we can start cleaning the code up and make it nice

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@19659 f5534014-38df-0310-8fa8-9805f1628bb7

epan/dissectors/packet-usb-masstorage.c
epan/dissectors/packet-usb.c
epan/dissectors/packet-usb.h

index 81669d1dc24fdeb6125ada0cf10a557521117426..78a31dbffafa848624867d5f5e56d0d91e9956b3 100644 (file)
@@ -44,6 +44,11 @@ static int hf_usb_ms_dCBWCBLength = -1;
 static int hf_usb_ms_dCSWSignature = -1;
 static int hf_usb_ms_dCSWDataResidue = -1;
 static int hf_usb_ms_dCSWStatus = -1;
+static int hf_usb_ms_request = -1;
+static int hf_usb_ms_value = -1;
+static int hf_usb_ms_index = -1;
+static int hf_usb_ms_length = -1;
+static int hf_usb_ms_maxlun = -1;
 
 static gint ett_usb_ms = -1;
 
@@ -62,8 +67,124 @@ static const value_string status_vals[] = {
     {0, NULL}
 };
 
+
+
+
+static void
+dissect_usb_ms_reset(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){
+        proto_tree_add_item(tree, hf_usb_ms_value, tvb, offset, 2, FALSE);
+        offset += 2;
+
+        proto_tree_add_item(tree, hf_usb_ms_index, tvb, offset, 2, FALSE);
+        offset += 2;
+
+        proto_tree_add_item(tree, hf_usb_ms_length, tvb, offset, 2, FALSE);
+        offset += 2;
+    } else {
+        /* no data in reset response */
+    }
+}
+
+static void
+dissect_usb_ms_get_max_lun(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){
+        proto_tree_add_item(tree, hf_usb_ms_value, tvb, offset, 2, FALSE);
+        offset += 2;
+
+        proto_tree_add_item(tree, hf_usb_ms_index, tvb, offset, 2, FALSE);
+        offset += 2;
+
+        proto_tree_add_item(tree, hf_usb_ms_length, tvb, offset, 2, FALSE);
+        offset += 2;
+    } else {
+        proto_tree_add_item(tree, hf_usb_ms_maxlun, tvb, offset, 1, FALSE);
+        offset++;
+    }
+}
+
+
+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;
+#define USB_SETUP_RESET               0xff
+#define USB_SETUP_GET_MAX_LUN         0xfe
+static const usb_setup_dissector_table_t setup_dissectors[] = {
+    {USB_SETUP_RESET,          dissect_usb_ms_reset},
+    {USB_SETUP_GET_MAX_LUN,    dissect_usb_ms_get_max_lun},
+    {0, NULL}
+};  
+static const value_string setup_request_names_vals[] = {
+    {USB_SETUP_RESET,          "RESET"},
+    {USB_SETUP_GET_MAX_LUN,    "GET MAX LUN"},
+    {0, NULL}
+};  
+
+/* Dissector for mass storage control .
+ * Returns TRUE if a class specific dissector was found
+ * and FALSE othervise.
+ */
+static gint
+dissect_usb_ms_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;
+    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;
+    }
+
+
+    if(check_col(pinfo->cinfo, COL_PROTOCOL))
+        col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBMS");
+
+    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_ms_request, tvb, offset, 1, TRUE);
+        offset += 1;
+    }
+
+    dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info, usb_conv_info);
+    return TRUE;
+}
+
+
+/* dissector for mass storage bulk data */
 static void
-dissect_usb_ms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+dissect_usb_ms_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 {
     usb_conv_info_t *usb_conv_info;
     usb_ms_conv_info_t *usb_ms_conv_info;
@@ -287,6 +408,26 @@ proto_register_usb_ms(void)
         { "Status", "usbms.dCSWStatus", FT_UINT8, BASE_HEX, 
           VALS(status_vals), 0x0, "", HFILL }},
 
+        { &hf_usb_ms_request,
+        { "bRequest", "usbms.setup.bRequest", FT_UINT8, BASE_HEX, VALS(setup_request_names_vals), 0x0,
+                "", HFILL }},
+
+        { &hf_usb_ms_value,
+        { "wValue", "usbms.setup.wValue", FT_UINT16, BASE_HEX, NULL, 0x0,
+                "", HFILL }},
+
+        { &hf_usb_ms_index,
+        { "wIndex", "usbms.setup.wIndex", FT_UINT16, BASE_DEC, NULL, 0x0,
+                "", HFILL }},
+
+        { &hf_usb_ms_length,
+        { "wLength", "usbms.setup.wLength", FT_UINT16, BASE_DEC, NULL, 0x0,
+                "", HFILL }},
+                
+        { &hf_usb_ms_maxlun,
+        { "Max LUN", "usbms.setup.maxlun", FT_UINT8, BASE_DEC, NULL, 0x0,
+                "", HFILL }},
+                
     };
     
     static gint *usb_ms_subtrees[] = {
@@ -298,14 +439,18 @@ proto_register_usb_ms(void)
     proto_register_field_array(proto_usb_ms, hf, array_length(hf));
     proto_register_subtree_array(usb_ms_subtrees, array_length(usb_ms_subtrees));
 
-    register_dissector("usbms", dissect_usb_ms, proto_usb_ms);
+    register_dissector("usbms", dissect_usb_ms_bulk, proto_usb_ms);
 }
 
 void
 proto_reg_handoff_usb_ms(void)
 {
-    dissector_handle_t usb_ms_handle;
-    usb_ms_handle = create_dissector_handle(dissect_usb_ms, proto_usb_ms);
+    dissector_handle_t usb_ms_bulk_handle;
+    dissector_handle_t usb_ms_control_handle;
+
+    usb_ms_bulk_handle = create_dissector_handle(dissect_usb_ms_bulk, proto_usb_ms);
+    dissector_add("usb.bulk", IF_CLASS_MASSTORAGE, usb_ms_bulk_handle);
 
-    dissector_add("usb.bulk", IF_CLASS_MASSTORAGE, usb_ms_handle);
+    usb_ms_control_handle = new_create_dissector_handle(dissect_usb_ms_control, proto_usb_ms);
+    dissector_add("usb.control", IF_CLASS_MASSTORAGE, usb_ms_control_handle);
 }
index d11eb6beb7de7d8955d12e99c479c135b3f49abd..fdc65e69ff44295dee1c146b8c8aa2287312cc14 100644 (file)
@@ -107,6 +107,7 @@ static gint ett_configuration_bEndpointAddress = -1;
 
 
 static dissector_table_t usb_bulk_dissector_table;
+static dissector_table_t usb_control_dissector_table;
 
 
 typedef enum { 
@@ -975,16 +976,19 @@ dissect_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent)
         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));
@@ -994,6 +998,20 @@ dissect_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent)
                 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);
@@ -1021,6 +1039,8 @@ dissect_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent)
                 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);
@@ -1032,6 +1052,7 @@ dissect_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent)
                 }
             }
             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){
@@ -1039,7 +1060,15 @@ dissect_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent)
                         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",
@@ -1334,6 +1363,9 @@ proto_register_usb(void)
     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
index 972a1fcb95408d3d6e9b83998b56fdabffb6ed19..2c55681d1d255b3b1aff75bdf360bbc419458a1a 100644 (file)
 #ifndef __PACKET_USB_H__
 #define __PACKET_USB_H__
 
-/* there is one such structure for each device/endpoint conversation */
-typedef struct _usb_conv_info_t {
-    guint16 class;             /* class for this conversation */
-    emem_tree_t *transactions;
-    void *masstorage;           /* mass storage data */
-} usb_conv_info_t;
+typedef struct _usb_conv_info_t usb_conv_info_t;
 
 /* there is one such structure for each request/response */
 typedef struct _usb_trans_info_t {
@@ -54,6 +49,14 @@ typedef struct _usb_trans_info_t {
     usb_conv_info_t *interface_info;
 } usb_trans_info_t;
 
+/* there is one such structure for each device/endpoint conversation */
+struct _usb_conv_info_t {
+    guint16 class;             /* class for this conversation */
+    emem_tree_t *transactions;
+    void *masstorage;           /* mass storage data */
+    usb_trans_info_t *usb_trans_info; /* pointer to the current transaction */
+};
+
 
 /* This is the endpoint number user for "no endpoint" or the fake endpoint 
  * for the host side since we need two endpoints to manage conversations