HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-usb-hub.c
blobc1540d98bcb08deca8a112e891903d764b8f491e
1 /* packet-usb-hub.c
2 * Routines for USB HUB dissection
3 * Copyright 2009, Marton Nemeth <nm127@freemail.hu>
5 * $Id$
7 * USB HUB Specification can be found in the Universal Serial Bus
8 * Specification 2.0, Chapter 11 Hub Specification.
9 * http://www.usb.org/developers/docs/usb_20_052709.zip
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "config.h"
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include "packet-usb.h"
36 /* protocols and header fields */
37 static int proto_usb_hub = -1;
39 /* USB 2.0, Chapter 11.24.2 Class-Specific Requests */
40 static int hf_usb_hub_request = -1;
41 static int hf_usb_hub_value = -1;
42 static int hf_usb_hub_index = -1;
43 static int hf_usb_hub_length = -1;
45 static int hf_usb_hub_hub_feature_selector = -1;
46 static int hf_usb_hub_port_feature_selector = -1;
47 static int hf_usb_hub_dev_addr = -1;
48 static int hf_usb_hub_ep_num = -1;
49 static int hf_usb_hub_descriptor_type = -1;
50 static int hf_usb_hub_descriptor_index = -1;
51 static int hf_usb_hub_zero = -1;
52 static int hf_usb_hub_tt_flags = -1;
53 static int hf_usb_hub_tt_port = -1;
54 static int hf_usb_hub_tt_state_length = -1;
55 static int hf_usb_hub_port = -1;
56 static int hf_usb_hub_port_selector = -1;
57 static int hf_usb_hub_port_status = -1;
58 static int hf_usb_hub_port_change = -1;
59 static int hf_usb_hub_port_status_connection = -1;
60 static int hf_usb_hub_port_status_enable = -1;
61 static int hf_usb_hub_port_status_suspend = -1;
62 static int hf_usb_hub_port_status_overcurrent = -1;
63 static int hf_usb_hub_port_status_reset = -1;
64 static int hf_usb_hub_port_status_power = -1;
65 static int hf_usb_hub_port_status_low_speed = -1;
66 static int hf_usb_hub_port_status_high_speed = -1;
67 static int hf_usb_hub_port_status_test = -1;
68 static int hf_usb_hub_port_status_indicator = -1;
69 static int hf_usb_hub_port_change_connection = -1;
70 static int hf_usb_hub_port_change_enable = -1;
71 static int hf_usb_hub_port_change_suspend = -1;
72 static int hf_usb_hub_port_change_overcurrent = -1;
73 static int hf_usb_hub_port_change_reset = -1;
74 static int hf_usb_hub_descriptor_length = -1;
76 static gint ett_usb_hub_wValue = -1;
77 static gint ett_usb_hub_wIndex = -1;
78 static gint ett_usb_hub_wLength = -1;
79 static gint ett_usb_hub_port_status = -1;
80 static gint ett_usb_hub_port_change = -1;
82 /* Table 11-16. Hub Class Request Codes */
83 #define USB_HUB_REQUEST_GET_STATUS 0
84 #define USB_HUB_REQUEST_CLEAR_FEATURE 1
85 #define USB_HUB_REQUEST_SET_FEATURE 3
86 #define USB_HUB_REQUEST_GET_DESCRIPTOR 6
87 #define USB_HUB_REQUEST_SET_DESCRIPTOR 7
88 #define USB_HUB_REQUEST_CLEAR_TT_BUFFER 8
89 #define USB_HUB_REQUEST_RESET_TT 9
90 #define USB_HUB_REQUEST_GET_TT_STATE 10
91 #define USB_HUB_REQUEST_STOP_TT 11
93 static const value_string setup_request_names_vals[] = {
94 { USB_HUB_REQUEST_GET_STATUS, "GET_STATUS" },
95 { USB_HUB_REQUEST_CLEAR_FEATURE, "CLEAR_FEATURE" },
96 { USB_HUB_REQUEST_SET_FEATURE, "SET_FEATURE" },
97 { USB_HUB_REQUEST_GET_DESCRIPTOR, "GET_DESCRIPTOR" },
98 { USB_HUB_REQUEST_SET_DESCRIPTOR, "SET_DESCRIPTOR" },
99 { USB_HUB_REQUEST_CLEAR_TT_BUFFER, "CLEAR_TT_BUFFER" },
100 { USB_HUB_REQUEST_GET_TT_STATE, "GET_TT_STATE" },
101 { USB_HUB_REQUEST_STOP_TT, "STOP_TT" },
102 { 0, NULL }
106 /* Table 11-17 Hub Class Feature Selectors */
107 #define USB_HUB_FEATURE_C_HUB_LOCAL_POWER 0
108 #define USB_HUB_FEATURE_C_HUB_OVER_CURRENT 1
110 #define USB_HUB_FEATURE_PORT_CONNECTION 0
111 #define USB_HUB_FEATURE_PORT_ENABLE 1
112 #define USB_HUB_FEATURE_PORT_SUSPEND 2
113 #define USB_HUB_FEATURE_PORT_OVER_CURRENT 3
114 #define USB_HUB_FEATURE_PORT_RESET 4
115 #define USB_HUB_FEATURE_PORT_POWER 8
116 #define USB_HUB_FEATURE_PORT_LOW_SPEED 9
117 #define USB_HUB_FEATURE_C_PORT_CONNECTION 16
118 #define USB_HUB_FEATURE_C_PORT_ENABLE 17
119 #define USB_HUB_FEATURE_C_PORT_SUSPEND 18
120 #define USB_HUB_FEATURE_C_PORT_OVER_CURRENT 19
121 #define USB_HUB_FEATURE_C_PORT_RESET 20
122 #define USB_HUB_FEATURE_PORT_TEST 21
123 #define USB_HUB_FEATURE_PORT_INDICATOR 22
125 static const value_string hub_class_feature_selectors_recipient_hub_vals[] = {
126 { USB_HUB_FEATURE_C_HUB_LOCAL_POWER, "C_HUB_LOCAL_POWER" },
127 { USB_HUB_FEATURE_C_HUB_OVER_CURRENT, "C_HUB_OVER_CURRENT" },
128 { 0, NULL }
131 static const value_string hub_class_feature_selectors_recipient_port_vals[] = {
132 { USB_HUB_FEATURE_PORT_CONNECTION, "PORT_CONNECTION" },
133 { USB_HUB_FEATURE_PORT_ENABLE, "PORT_ENABLE" },
134 { USB_HUB_FEATURE_PORT_SUSPEND, "PORT_SUSPEND" },
135 { USB_HUB_FEATURE_PORT_OVER_CURRENT, "PORT_OVER_CURRENT" },
136 { USB_HUB_FEATURE_PORT_RESET, "PORT_RESET" },
137 { USB_HUB_FEATURE_PORT_POWER, "PORT_POWER" },
138 { USB_HUB_FEATURE_PORT_LOW_SPEED, "PORT_LOW_SPEED" },
139 { USB_HUB_FEATURE_C_PORT_CONNECTION, "C_PORT_CONNECTION" },
140 { USB_HUB_FEATURE_C_PORT_ENABLE, "C_PORT_ENABLE" },
141 { USB_HUB_FEATURE_C_PORT_SUSPEND, "C_PORT_SUSPEND" },
142 { USB_HUB_FEATURE_C_PORT_OVER_CURRENT, "C_PORT_OVER_CURRENT" },
143 { USB_HUB_FEATURE_C_PORT_RESET, "C_PORT_RESET" },
144 { USB_HUB_FEATURE_PORT_TEST, "PORT_TEST" },
145 { USB_HUB_FEATURE_PORT_INDICATOR, "PORT_INDICATOR" },
146 { 0, NULL }
149 static const true_false_string hub_port_status_indicator_meaning = {
150 "Software-controlled color",
151 "Default colors"
154 /* Dissector for ClearHubFeature, Chapter 11.24.2.1 Clear Hub Feature */
155 static void
156 dissect_usb_hub_clear_hub_feature(packet_info *pinfo, 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_)
158 proto_item *item = NULL;
159 proto_tree *subtree = NULL;
160 const gchar* feature_name;
162 feature_name = val_to_str(usb_trans_info->setup.wValue,
163 hub_class_feature_selectors_recipient_hub_vals,
164 "UNKNOWN (0x%x)");
165 col_append_fstr(pinfo->cinfo, COL_INFO, " [Hub: %s]", feature_name);
167 if (is_request) {
168 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
169 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
170 proto_tree_add_item(subtree, hf_usb_hub_hub_feature_selector, tvb, offset, 2, ENC_LITTLE_ENDIAN);
171 offset += 2;
173 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
174 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
175 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
176 offset += 2;
178 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
179 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
180 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
181 /*offset += 2;*/
182 } else {
186 /* Dissector for ClearPortFeature, Chapter 11.24.2.2 Clear Port Feature */
187 static void
188 dissect_usb_hub_clear_port_feature(packet_info *pinfo, 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_)
190 proto_item *item = NULL;
191 proto_tree *subtree = NULL;
192 const gchar* feature_name;
194 feature_name = val_to_str(usb_trans_info->setup.wValue,
195 hub_class_feature_selectors_recipient_port_vals,
196 "UNKNOWN (0x%x)");
197 col_append_fstr(pinfo->cinfo, COL_INFO, " [Port %u: %s]", usb_trans_info->setup.wIndex, feature_name);
199 if (is_request) {
200 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
201 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
202 proto_tree_add_item(subtree, hf_usb_hub_port_feature_selector, tvb, offset, 2, ENC_LITTLE_ENDIAN);
203 offset += 2;
205 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
206 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
207 proto_tree_add_item(subtree, hf_usb_hub_port, tvb, offset, 1, ENC_LITTLE_ENDIAN);
208 offset++;
209 proto_tree_add_item(subtree, hf_usb_hub_port_selector, tvb, offset, 1, ENC_LITTLE_ENDIAN);
210 offset++;
212 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
213 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
214 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
215 /*offset += 2;*/
216 } else {
220 /* Dissector for ClearTTBuffer, Chapter 11.24.2.3 Clear TT Buffer */
221 static void
222 dissect_usb_hub_clear_tt_buffer(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_)
224 proto_item *item = NULL;
225 proto_tree *subtree = NULL;
227 if (is_request) {
228 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
229 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
230 proto_tree_add_item(subtree, hf_usb_hub_ep_num, tvb, offset, 1, ENC_LITTLE_ENDIAN);
231 offset++;
232 proto_tree_add_item(subtree, hf_usb_hub_dev_addr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
233 offset++;
235 proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
236 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
237 proto_tree_add_item(subtree, hf_usb_hub_tt_port, tvb, offset, 2, ENC_LITTLE_ENDIAN);
238 offset += 2;
240 proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
241 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
242 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
243 /*offset += 2;*/
244 } else {
248 /* Dissector for GetHubDescriptor, Chapter 11.24.2.5 Get Hub Descriptor */
249 static void
250 dissect_usb_hub_get_hub_descriptor(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_)
252 proto_item *item = NULL;
253 proto_tree *subtree = NULL;
255 if (is_request) {
256 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
257 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
258 proto_tree_add_item(subtree, hf_usb_hub_descriptor_index, tvb, offset, 1, ENC_LITTLE_ENDIAN);
259 offset++;
260 proto_tree_add_item(subtree, hf_usb_hub_descriptor_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
261 offset++;
263 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
264 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
265 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
266 offset += 2;
268 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
269 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
270 proto_tree_add_item(subtree, hf_usb_hub_descriptor_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
271 /*offset += 2;*/
272 } else {
276 /* Dissector for GetHubStatus, Chapter 11.24.2.6 Get Hub Status */
277 static void
278 dissect_usb_hub_get_hub_status(packet_info *pinfo, 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_)
280 proto_item *item = NULL;
281 proto_tree *subtree = NULL;
283 col_append_str(pinfo->cinfo, COL_INFO, " [Hub]");
285 if (is_request) {
286 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
287 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
288 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
289 offset += 2;
291 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
292 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
293 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
294 offset += 2;
296 proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
297 /* length shall always contain 4 */
298 /*offset += 2;*/
299 } else {
303 /* Dissector for GetPortStatus, Chapter 11.24.2.7 Get Port Status */
304 static void
305 dissect_usb_hub_get_port_status(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 _U_)
307 proto_item *item = NULL;
308 proto_tree *subtree = NULL;
310 col_append_fstr(pinfo->cinfo, COL_INFO, " [Port %u]", usb_trans_info->setup.wIndex);
312 if (is_request) {
313 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
314 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
315 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
316 offset += 2;
318 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
319 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
320 proto_tree_add_item(subtree, hf_usb_hub_port, tvb, offset, 2, ENC_LITTLE_ENDIAN);
321 offset += 2;
323 proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
324 /* length shall always contain 4 */
325 /*offset += 2;*/
326 } else {
327 static const int *status_fields[] = {
328 &hf_usb_hub_port_status_connection,
329 &hf_usb_hub_port_status_enable,
330 &hf_usb_hub_port_status_suspend,
331 &hf_usb_hub_port_status_overcurrent,
332 &hf_usb_hub_port_status_reset,
333 &hf_usb_hub_port_status_power,
334 &hf_usb_hub_port_status_low_speed,
335 &hf_usb_hub_port_status_high_speed,
336 &hf_usb_hub_port_status_test,
337 &hf_usb_hub_port_status_indicator,
338 NULL
341 static const int *change_fields[] = {
342 &hf_usb_hub_port_change_connection,
343 &hf_usb_hub_port_change_enable,
344 &hf_usb_hub_port_change_suspend,
345 &hf_usb_hub_port_change_overcurrent,
346 &hf_usb_hub_port_change_reset,
347 NULL
350 proto_tree_add_bitmask(tree, tvb, offset, hf_usb_hub_port_status,
351 ett_usb_hub_port_status, status_fields, ENC_LITTLE_ENDIAN);
352 offset += 2;
353 proto_tree_add_bitmask(tree, tvb, offset, hf_usb_hub_port_change,
354 ett_usb_hub_port_change, change_fields, ENC_LITTLE_ENDIAN);
355 /*offset += 2;*/
359 /* Dissector for GetTTState, Chapter 11.24.2.8 Get_TT_State */
360 static void
361 dissect_usb_hub_get_tt_state(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_)
363 proto_item *item = NULL;
364 proto_tree *subtree = NULL;
366 if (is_request) {
367 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
368 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
369 proto_tree_add_item(subtree, hf_usb_hub_tt_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
370 offset += 2;
372 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
373 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
374 proto_tree_add_item(subtree, hf_usb_hub_tt_port, tvb, offset, 1, ENC_LITTLE_ENDIAN);
375 offset += 2;
377 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
378 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
379 proto_tree_add_item(subtree, hf_usb_hub_tt_state_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
380 /*offset += 2;*/
381 } else {
385 /* Dissector for ResetTT, Chapter 11.24.2.9 Reset_TT */
386 static void
387 dissect_usb_hub_reset_tt(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_)
389 proto_item *item = NULL;
390 proto_tree *subtree = NULL;
392 if (is_request) {
393 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
394 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
395 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 1, ENC_LITTLE_ENDIAN);
396 offset += 2;
398 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
399 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
400 proto_tree_add_item(subtree, hf_usb_hub_tt_port, tvb, offset, 1, ENC_LITTLE_ENDIAN);
401 offset += 2;
403 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
404 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
405 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 1, ENC_LITTLE_ENDIAN);
406 /*offset += 2;*/
407 } else {
411 /* Dissector for SetHubDescriptor, Chapter 11.24.2.10 Set Hub Descriptor */
412 static void
413 dissect_usb_hub_set_hub_descriptor(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_)
415 proto_item *item = NULL;
416 proto_tree *subtree = NULL;
418 if (is_request) {
419 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
420 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
421 proto_tree_add_item(subtree, hf_usb_hub_descriptor_index, tvb, offset, 1, ENC_LITTLE_ENDIAN);
422 offset++;
423 proto_tree_add_item(subtree, hf_usb_hub_descriptor_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
424 offset++;
426 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
427 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
428 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
429 offset += 2;
431 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
432 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
433 proto_tree_add_item(subtree, hf_usb_hub_descriptor_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
434 /*offset += 2;*/
435 } else {
439 /* Dissector for StopTT, Chapter 11.24.2.11 Stop TT */
440 static void
441 dissect_usb_hub_stop_tt(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_)
443 proto_item *item = NULL;
444 proto_tree *subtree = NULL;
446 if (is_request) {
447 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
448 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
449 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 1, ENC_LITTLE_ENDIAN);
450 offset += 2;
452 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
453 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
454 proto_tree_add_item(subtree, hf_usb_hub_tt_port, tvb, offset, 2, ENC_LITTLE_ENDIAN);
455 offset += 2;
457 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
458 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
459 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
460 /*offset += 2;*/
461 } else {
465 /* Dissector for SetHubFeature, Chapter 11.24.2.12 Set Hub Feature */
466 static void
467 dissect_usb_hub_set_hub_feature(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 _U_)
469 proto_item *item = NULL;
470 proto_tree *subtree = NULL;
471 const gchar* feature_name;
472 feature_name = val_to_str(usb_trans_info->setup.wValue,
473 hub_class_feature_selectors_recipient_hub_vals,
474 "UNKNOWN (0x%x)");
475 col_append_fstr(pinfo->cinfo, COL_INFO, " [Hub: %s]", feature_name);
477 if (is_request) {
478 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
479 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
480 proto_tree_add_item(subtree, hf_usb_hub_hub_feature_selector, tvb, offset, 2, ENC_LITTLE_ENDIAN);
481 offset += 2;
483 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
484 subtree = proto_item_add_subtree(item, ett_usb_hub_wIndex);
485 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
486 offset += 2;
488 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
489 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
490 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
491 /*offset += 2;*/
492 } else {
496 /* Dissector for SetPortFeature, Chapter 11.24.2.13 Set Port Feature */
497 static void
498 dissect_usb_hub_set_port_feature(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 _U_)
500 proto_item *item = NULL;
501 proto_tree *subtree = NULL;
502 const gchar* feature_name;
504 feature_name = val_to_str(usb_trans_info->setup.wValue,
505 hub_class_feature_selectors_recipient_port_vals,
506 "UNKNOWN (0x%x)");
507 col_append_fstr(pinfo->cinfo, COL_INFO, " [Port %u: %s]", usb_trans_info->setup.wIndex,
508 feature_name);
510 if (is_request) {
511 item = proto_tree_add_item(tree, hf_usb_hub_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
512 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
513 proto_tree_add_item(subtree, hf_usb_hub_port_feature_selector, tvb, offset, 2, ENC_LITTLE_ENDIAN);
514 offset += 2;
516 item = proto_tree_add_item(tree, hf_usb_hub_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
517 subtree = proto_item_add_subtree(item, ett_usb_hub_wValue);
518 proto_tree_add_item(subtree, hf_usb_hub_port, tvb, offset, 1, ENC_LITTLE_ENDIAN);
519 offset++;
520 proto_tree_add_item(subtree, hf_usb_hub_port_selector, tvb, offset, 1, ENC_LITTLE_ENDIAN);
521 offset++;
523 item = proto_tree_add_item(tree, hf_usb_hub_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
524 subtree = proto_item_add_subtree(item, ett_usb_hub_wLength);
525 proto_tree_add_item(subtree, hf_usb_hub_zero, tvb, offset, 2, ENC_LITTLE_ENDIAN);
526 /*offset += 2;*/
527 } else {
532 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);
534 typedef struct _usb_setup_dissector_table_t {
535 guint8 request_type;
536 guint8 request;
537 usb_setup_dissector dissector;
538 } usb_setup_dissector_table_t;
541 /* USB 2.0, Table 11-15 Hub Class Requests */
542 static const usb_setup_dissector_table_t setup_dissectors[] = {
543 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_DEVICE,
544 USB_HUB_REQUEST_CLEAR_FEATURE,
545 dissect_usb_hub_clear_hub_feature
548 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
549 USB_HUB_REQUEST_CLEAR_FEATURE,
550 dissect_usb_hub_clear_port_feature
553 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
554 USB_HUB_REQUEST_CLEAR_TT_BUFFER,
555 dissect_usb_hub_clear_tt_buffer
558 { USB_DIR_IN | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_DEVICE,
559 USB_HUB_REQUEST_GET_DESCRIPTOR,
560 dissect_usb_hub_get_hub_descriptor
563 { USB_DIR_IN | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_DEVICE,
564 USB_HUB_REQUEST_GET_STATUS,
565 dissect_usb_hub_get_hub_status
568 { USB_DIR_IN | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
569 USB_HUB_REQUEST_GET_STATUS,
570 dissect_usb_hub_get_port_status
573 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
574 USB_HUB_REQUEST_RESET_TT,
575 dissect_usb_hub_reset_tt
578 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_DEVICE,
579 USB_HUB_REQUEST_SET_DESCRIPTOR,
580 dissect_usb_hub_set_hub_descriptor
583 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_DEVICE,
584 USB_HUB_REQUEST_SET_FEATURE,
585 dissect_usb_hub_set_hub_feature
588 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
589 USB_HUB_REQUEST_SET_FEATURE,
590 dissect_usb_hub_set_port_feature
593 { USB_DIR_IN | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
594 USB_HUB_REQUEST_GET_TT_STATE,
595 dissect_usb_hub_get_tt_state
598 { USB_DIR_OUT | (RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_OTHER,
599 USB_HUB_REQUEST_STOP_TT,
600 dissect_usb_hub_stop_tt
603 { 0, 0, NULL }
606 /* Dissector for USB HUB class-specific control request as defined in
607 * USB 2.0, Chapter 11.24.2 Class-specific Requests
608 * Returns TRUE if a class specific dissector was found
609 * and FALSE otherwise.
611 static gint
612 dissect_usb_hub_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
614 gboolean is_request;
615 usb_conv_info_t *usb_conv_info = (usb_conv_info_t *)data;
616 usb_trans_info_t *usb_trans_info = usb_conv_info->usb_trans_info;
617 int offset = 0;
618 usb_setup_dissector dissector;
619 const usb_setup_dissector_table_t *tmp;
621 is_request = (pinfo->srcport==NO_ENDPOINT);
623 /* See if we can find a class specific dissector for this request */
624 dissector = NULL;
626 /* Check valid values for bmRequestType and bRequest */
627 for (tmp = setup_dissectors; tmp->dissector; tmp++) {
628 if (tmp->request_type == usb_trans_info->setup.requesttype &&
629 tmp->request == usb_trans_info->setup.request) {
630 dissector = tmp->dissector;
631 break;
634 /* No, we could not find any class specific dissector for this request
635 * return FALSE and let USB try any of the standard requests.
637 if (!dissector) {
638 return FALSE;
641 col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBHUB");
643 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
644 val_to_str(usb_trans_info->setup.request, setup_request_names_vals, "Unknown type %x"),
645 is_request ? "Request " : "Response");
647 if (is_request) {
648 proto_tree_add_item(tree, hf_usb_hub_request, tvb, offset, 1, ENC_LITTLE_ENDIAN);
649 offset += 1;
652 dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info, usb_conv_info);
653 return TRUE;
656 void
657 proto_register_usb_hub(void)
659 static hf_register_info hf[] = {
660 /* USB HUB specific requests */
661 { &hf_usb_hub_request,
662 { "bRequest", "usbhub.setup.bRequest", FT_UINT8, BASE_HEX, VALS(setup_request_names_vals), 0x0,
663 NULL, HFILL }},
665 { &hf_usb_hub_value,
666 { "wValue", "usbhub.setup.wValue", FT_UINT16, BASE_HEX, NULL, 0x0,
667 NULL, HFILL }},
669 { &hf_usb_hub_index,
670 { "wIndex", "usbhub.setup.wIndex", FT_UINT16, BASE_DEC, NULL, 0x0,
671 NULL, HFILL }},
673 { &hf_usb_hub_length,
674 { "wLength", "usbhub.setup.wLength", FT_UINT16, BASE_DEC, NULL, 0x0,
675 NULL, HFILL }},
677 { &hf_usb_hub_hub_feature_selector,
678 { "HubFeatureSelector", "usbhub.setup.HubFeatureSelector", FT_UINT16, BASE_DEC,
679 VALS(hub_class_feature_selectors_recipient_hub_vals), 0x0,
680 NULL, HFILL }},
682 { &hf_usb_hub_port_feature_selector,
683 { "PortFeatureSelector", "usbhub.setup.PortFeatureSelector", FT_UINT16, BASE_DEC,
684 VALS(hub_class_feature_selectors_recipient_port_vals), 0x0,
685 NULL, HFILL }},
687 { &hf_usb_hub_dev_addr,
688 { "Dev_Addr", "usbhub.setup.Dev_Addr", FT_UINT8, BASE_DEC, NULL, 0x0,
689 NULL, HFILL }},
691 { &hf_usb_hub_ep_num,
692 { "EP_Num", "usbhub.setup.EP_Num", FT_UINT8, BASE_DEC, NULL, 0x0,
693 NULL, HFILL }},
695 { &hf_usb_hub_descriptor_type,
696 { "DescriptorType", "usbhub.setup.DescriptorType", FT_UINT8, BASE_DEC, NULL, 0x0,
697 NULL, HFILL }},
699 { &hf_usb_hub_descriptor_index,
700 { "DescriptorIndex", "usbhub.setup.DescriptorIndex", FT_UINT8, BASE_DEC, NULL, 0x0,
701 NULL, HFILL }},
703 { &hf_usb_hub_descriptor_length,
704 { "DescriptorLength", "usbhub.setup.DescriptorLength", FT_UINT8, BASE_DEC, NULL, 0x0,
705 NULL, HFILL }},
707 { &hf_usb_hub_zero,
708 { "(zero)", "usbhub.setup.zero", FT_UINT8, BASE_DEC, NULL, 0x0,
709 NULL, HFILL }},
711 { &hf_usb_hub_tt_flags,
712 { "TT_Flags", "usbhub.setup.TT_Flags", FT_UINT8, BASE_DEC, NULL, 0x0,
713 NULL, HFILL }},
715 { &hf_usb_hub_tt_port,
716 { "TT_Port", "usbhub.setup.TT_Port", FT_UINT16, BASE_DEC, NULL, 0x0,
717 NULL, HFILL }},
719 { &hf_usb_hub_tt_state_length,
720 { "TT State Length", "usbhub.setup.TT_StateLength", FT_UINT16, BASE_DEC, NULL, 0x0,
721 NULL, HFILL }},
723 { &hf_usb_hub_port_selector,
724 { "PortSelector", "usbhub.setup.PortSelector", FT_UINT8, BASE_DEC, NULL, 0x0,
725 NULL, HFILL }},
727 { &hf_usb_hub_port,
728 { "Port", "usbhub.setup.Port", FT_UINT8, BASE_DEC, NULL, 0x0,
729 NULL, HFILL }},
731 { &hf_usb_hub_port_status,
732 { "Port Status", "usbhub.status.port", FT_UINT16, BASE_HEX, NULL, 0,
733 NULL, HFILL }},
735 { &hf_usb_hub_port_change,
736 { "Port Change", "usbhub.change.port", FT_UINT16, BASE_HEX, NULL, 0,
737 NULL, HFILL }},
739 { &hf_usb_hub_port_status_connection,
740 { "PORT_CONNECTION", "usbhub.status.port.connection", FT_BOOLEAN, 16, NULL, (1<<0),
741 NULL, HFILL }},
743 { &hf_usb_hub_port_status_enable,
744 { "PORT_ENABLE", "usbhub.status.port.enable", FT_BOOLEAN, 16, NULL, (1<<1),
745 NULL, HFILL }},
747 { &hf_usb_hub_port_status_suspend,
748 { "PORT_SUSPEND", "usbhub.status.port.suspend", FT_BOOLEAN, 16, NULL, (1<<2),
749 NULL, HFILL }},
751 { &hf_usb_hub_port_status_overcurrent,
752 { "PORT_OVER_CURRENT", "usbhub.status.port.overcurrent", FT_BOOLEAN, 16, NULL, (1<<3),
753 NULL, HFILL }},
755 { &hf_usb_hub_port_status_reset,
756 { "PORT_RESET", "usbhub.status.port.reset", FT_BOOLEAN, 16, NULL, (1<<4),
757 NULL, HFILL }},
759 { &hf_usb_hub_port_status_power,
760 { "PORT_POWER", "usbhub.status.port.power", FT_BOOLEAN, 16, NULL, (1<<8),
761 NULL, HFILL }},
763 { &hf_usb_hub_port_status_low_speed,
764 { "PORT_LOW_SPEED", "usbhub.status.port.low_speed", FT_BOOLEAN, 16, NULL, (1<<9),
765 NULL, HFILL }},
767 { &hf_usb_hub_port_status_high_speed,
768 { "PORT_HIGH_SPEED", "usbhub.status.port.high_speed", FT_BOOLEAN, 16, NULL, (1<<10),
769 NULL, HFILL }},
771 { &hf_usb_hub_port_status_test,
772 { "PORT_TEST", "usbhub.status.port.test", FT_BOOLEAN, 16, NULL, (1<<11),
773 NULL, HFILL }},
775 { &hf_usb_hub_port_status_indicator,
776 { "PORT_INDICATOR", "usbhub.status.port.indicator", FT_BOOLEAN, 16,
777 TFS(&hub_port_status_indicator_meaning), (1<<12),
778 NULL, HFILL }},
780 { &hf_usb_hub_port_change_connection,
781 { "C_PORT_CONNECTION", "usbhub.change.port.connection", FT_BOOLEAN, 16, NULL, (1<<0),
782 NULL, HFILL }},
784 { &hf_usb_hub_port_change_enable,
785 { "C_PORT_ENABLE", "usbhub.change.port.enable", FT_BOOLEAN, 16, NULL, (1<<1),
786 NULL, HFILL }},
788 { &hf_usb_hub_port_change_suspend,
789 { "C_PORT_SUSPEND", "usbhub.status.port.suspend", FT_BOOLEAN, 16, NULL, (1<<2),
790 NULL, HFILL }},
792 { &hf_usb_hub_port_change_overcurrent,
793 { "C_PORT_OVER_CURRENT", "usbhub.status.port.overcurrent", FT_BOOLEAN, 16, NULL, (1<<3),
794 NULL, HFILL }},
796 { &hf_usb_hub_port_change_reset,
797 { "C_PORT_RESET", "usbhub.status.port.reset", FT_BOOLEAN, 16, NULL, (1<<4),
798 NULL, HFILL }}
801 static gint *usb_hub_subtrees[] = {
802 &ett_usb_hub_wValue,
803 &ett_usb_hub_wIndex,
804 &ett_usb_hub_wLength,
805 &ett_usb_hub_port_status,
806 &ett_usb_hub_port_change
809 proto_usb_hub = proto_register_protocol("USB HUB", "USBHUB", "usbhub");
810 proto_register_field_array(proto_usb_hub, hf, array_length(hf));
811 proto_register_subtree_array(usb_hub_subtrees, array_length(usb_hub_subtrees));
814 void
815 proto_reg_handoff_usb_hub(void) {
816 dissector_handle_t usb_hub_control_handle;
818 usb_hub_control_handle = new_create_dissector_handle(dissect_usb_hub_control, proto_usb_hub);
819 dissector_add_uint("usb.control", IF_CLASS_HUB, usb_hub_control_handle);
820 dissector_add_uint("usb.control", IF_CLASS_UNKNOWN, usb_hub_control_handle);