/src/wireshark/epan/dissectors/packet-usb-dfu.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-usbdfu.c |
2 | | * Routines for USB DFU dissection |
3 | | * |
4 | | * Copyright 2014, Michal Labedzki for Tieto Corporation |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <epan/prefs.h> |
17 | | #include <epan/expert.h> |
18 | | #include "packet-usb.h" |
19 | | |
20 | | static int proto_usb_dfu; |
21 | | |
22 | | static int hf_setup_command; |
23 | | static int hf_setup_unused; |
24 | | static int hf_setup_interface; |
25 | | static int hf_setup_length; |
26 | | static int hf_setup_timeout; |
27 | | static int hf_setup_block_number; |
28 | | static int hf_response; |
29 | | static int hf_command_in_frame; |
30 | | static int hf_state; |
31 | | static int hf_status; |
32 | | static int hf_poll_timeout; |
33 | | static int hf_iString; |
34 | | static int hf_data; |
35 | | static int hf_usb_dfu_descriptor; |
36 | | static int hf_usb_dfu_descriptor_bmAttributes_reserved; |
37 | | static int hf_usb_dfu_descriptor_bmAttributes_WillDetach; |
38 | | static int hf_usb_dfu_descriptor_bmAttributes_ManifestationTolerant; |
39 | | static int hf_usb_dfu_descriptor_bmAttributes_CanUpload; |
40 | | static int hf_usb_dfu_descriptor_bmAttributes_CanDownload; |
41 | | static int hf_usb_dfu_descriptor_wDetachTimeOut; |
42 | | static int hf_usb_dfu_descriptor_wTransferSize; |
43 | | static int hf_usb_dfu_descriptor_bcdDFUVersion; |
44 | | |
45 | | static int ett_usb_dfu; |
46 | | static int ett_usb_dfu_descriptor; |
47 | | static int ett_command; |
48 | | |
49 | | static expert_field ei_unexpected_response; |
50 | | static expert_field ei_unknown_data; |
51 | | static expert_field ei_unexpected_data; |
52 | | static expert_field ei_descriptor_invalid_length; |
53 | | static expert_field ei_invalid_command_for_request_type; |
54 | | |
55 | | static dissector_handle_t usb_dfu_handle; |
56 | | static dissector_handle_t usf_dfu_descriptor_handle; |
57 | | |
58 | | |
59 | | static wmem_tree_t *command_info; |
60 | | |
61 | | typedef struct _command_data { |
62 | | uint32_t bus_id; |
63 | | uint32_t device_address; |
64 | | |
65 | | uint16_t interface; |
66 | | uint8_t command; |
67 | | uint32_t command_frame_number; |
68 | | int32_t block_number; |
69 | | } command_data_t; |
70 | | |
71 | | |
72 | | static const value_string command_vals[] = { |
73 | | { 0x00, "Detach" }, |
74 | | { 0x01, "Download" }, |
75 | | { 0x02, "Upload" }, |
76 | | { 0x03, "Get Status" }, |
77 | | { 0x04, "Clear Status" }, |
78 | | { 0x05, "Get State" }, |
79 | | { 0x06, "Abort" }, |
80 | | { 0x00, NULL } |
81 | | }; |
82 | | static value_string_ext(command_vals_ext) = VALUE_STRING_EXT_INIT(command_vals); |
83 | | |
84 | | static const value_string state_vals[] = { |
85 | | { 0, "appIdle" }, |
86 | | { 1, "appDetach" }, |
87 | | { 2, "dfuIdle" }, |
88 | | { 3, "dfuDownloadSync" }, |
89 | | { 4, "dfuDownloadBusy" }, |
90 | | { 5, "dfuDownloadIdle" }, |
91 | | { 6, "dfuManifestSync" }, |
92 | | { 7, "dfuManifest" }, |
93 | | { 8, "dfuManifestWaitReset" }, |
94 | | { 9, "dfuUploadIdle" }, |
95 | | { 10, "dfuError" }, |
96 | | { 0x00, NULL } |
97 | | }; |
98 | | static value_string_ext(state_vals_ext) = VALUE_STRING_EXT_INIT(state_vals); |
99 | | |
100 | | static const value_string status_vals[] = { |
101 | | { 0x00, "OK" }, |
102 | | { 0x01, "errTarget" }, |
103 | | { 0x02, "errFile" }, |
104 | | { 0x03, "errWrite" }, |
105 | | { 0x04, "errErase" }, |
106 | | { 0x05, "errCheckErased" }, |
107 | | { 0x06, "errProg" }, |
108 | | { 0x07, "errVerify" }, |
109 | | { 0x08, "errAddress" }, |
110 | | { 0x09, "errNotDone" }, |
111 | | { 0x0A, "errFirmware" }, |
112 | | { 0x0B, "errVendor" }, |
113 | | { 0x0C, "errUsbReset" }, |
114 | | { 0x0D, "errPowerOnReset" }, |
115 | | { 0x0E, "errUnknown" }, |
116 | | { 0x0F, "errStalledPkt" }, |
117 | | { 0x00, NULL } |
118 | | }; |
119 | | static value_string_ext(status_vals_ext) = VALUE_STRING_EXT_INIT(status_vals); |
120 | | |
121 | | static const value_string descriptor_type_vals[] = { |
122 | | { 0x21, "DFU FUNCTIONAL" }, |
123 | | { 0x00, NULL } |
124 | | }; |
125 | | static value_string_ext(descriptor_type_vals_ext) = VALUE_STRING_EXT_INIT(descriptor_type_vals); |
126 | | |
127 | | void proto_register_usb_dfu(void); |
128 | | void proto_reg_handoff_usb_dfu(void); |
129 | | |
130 | | |
131 | | static int |
132 | | dissect_usb_dfu_descriptor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
133 | 0 | { |
134 | 0 | proto_item *main_item; |
135 | 0 | proto_tree *main_tree; |
136 | 0 | proto_item *length_item; |
137 | 0 | int offset = 0; |
138 | 0 | uint8_t descriptor_length; |
139 | 0 | uint8_t descriptor_type; |
140 | 0 | urb_info_t *urb = (urb_info_t *) data; |
141 | |
|
142 | 0 | if (!urb || !urb->conv) return offset; |
143 | | |
144 | 0 | if (!(urb->conv->interfaceClass == IF_CLASS_APPLICATION_SPECIFIC && |
145 | 0 | urb->conv->interfaceSubclass == 0x01)) return offset; |
146 | | |
147 | 0 | descriptor_length = tvb_get_uint8(tvb, offset); |
148 | 0 | descriptor_type = tvb_get_uint8(tvb, offset + 1); |
149 | |
|
150 | 0 | switch (descriptor_type) { |
151 | 0 | case 0x21: |
152 | 0 | main_item = proto_tree_add_item(tree, hf_usb_dfu_descriptor, tvb, offset, -1, ENC_NA); |
153 | 0 | main_tree = proto_item_add_subtree(main_item, ett_usb_dfu_descriptor); |
154 | |
|
155 | 0 | proto_item_append_text(main_item, ": %s", val_to_str_ext_const(descriptor_type, &descriptor_type_vals_ext, "Unknown")); |
156 | |
|
157 | 0 | length_item = dissect_usb_descriptor_header(main_tree, tvb, offset, &descriptor_type_vals_ext); |
158 | 0 | if (descriptor_length != 7 && descriptor_length != 9) |
159 | 0 | expert_add_info(pinfo, length_item, &ei_descriptor_invalid_length); |
160 | 0 | offset += 2; |
161 | |
|
162 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_bmAttributes_reserved, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
163 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_bmAttributes_WillDetach, tvb, offset, 1, ENC_NA); |
164 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_bmAttributes_ManifestationTolerant, tvb, offset, 1, ENC_NA); |
165 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_bmAttributes_CanUpload, tvb, offset, 1, ENC_NA); |
166 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_bmAttributes_CanDownload, tvb, offset, 1, ENC_NA); |
167 | 0 | offset += 1; |
168 | |
|
169 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_wDetachTimeOut, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
170 | 0 | offset += 2; |
171 | |
|
172 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_wTransferSize, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
173 | 0 | offset += 2; |
174 | |
|
175 | 0 | if (descriptor_length > 7) { |
176 | 0 | proto_tree_add_item(main_tree, hf_usb_dfu_descriptor_bcdDFUVersion, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
177 | 0 | offset += 2; |
178 | 0 | } |
179 | |
|
180 | 0 | break; |
181 | 0 | } |
182 | | |
183 | 0 | return offset; |
184 | 0 | } |
185 | | |
186 | | static int |
187 | | dissect_usb_dfu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
188 | 0 | { |
189 | 0 | proto_item *main_item; |
190 | 0 | proto_tree *main_tree; |
191 | 0 | proto_item *command_item; |
192 | 0 | proto_item *sub_item; |
193 | 0 | proto_tree *command_tree; |
194 | 0 | int offset = 0; |
195 | 0 | int p2p_dir_save; |
196 | 0 | uint8_t command; |
197 | 0 | int16_t command_response = -1; |
198 | 0 | command_data_t *command_data = NULL; |
199 | 0 | wmem_tree_t *wmem_tree; |
200 | 0 | wmem_tree_key_t key[5]; |
201 | 0 | uint32_t bus_id; |
202 | 0 | uint32_t device_address; |
203 | 0 | uint32_t k_bus_id; |
204 | 0 | uint32_t k_device_address; |
205 | 0 | uint32_t k_frame_number; |
206 | 0 | int32_t block_number = -1; |
207 | 0 | urb_info_t *urb = (urb_info_t *)data; |
208 | |
|
209 | 0 | if (!urb) return offset; |
210 | | |
211 | 0 | bus_id = urb->bus_id; |
212 | 0 | device_address = urb->device_address; |
213 | |
|
214 | 0 | k_bus_id = bus_id; |
215 | 0 | k_device_address = device_address; |
216 | 0 | k_frame_number = pinfo->num; |
217 | |
|
218 | 0 | key[0].length = 1; |
219 | 0 | key[0].key = &k_bus_id; |
220 | 0 | key[1].length = 1; |
221 | 0 | key[1].key = &k_device_address; |
222 | |
|
223 | 0 | main_item = proto_tree_add_item(tree, proto_usb_dfu, tvb, offset, -1, ENC_NA); |
224 | 0 | main_tree = proto_item_add_subtree(main_item, ett_usb_dfu); |
225 | |
|
226 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "USB DFU"); |
227 | |
|
228 | 0 | p2p_dir_save = pinfo->p2p_dir; |
229 | 0 | pinfo->p2p_dir = (urb->is_request) ? P2P_DIR_SENT : P2P_DIR_RECV; |
230 | |
|
231 | 0 | switch (pinfo->p2p_dir) { |
232 | | |
233 | 0 | case P2P_DIR_SENT: |
234 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Sent "); |
235 | 0 | break; |
236 | | |
237 | 0 | case P2P_DIR_RECV: |
238 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Rcvd "); |
239 | 0 | break; |
240 | | |
241 | 0 | default: |
242 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Unknown direction "); |
243 | 0 | break; |
244 | 0 | } |
245 | | |
246 | 0 | if (urb->is_setup) { |
247 | 0 | uint16_t interface; |
248 | 0 | uint32_t length; |
249 | |
|
250 | 0 | command_item = proto_tree_add_item(main_tree, hf_setup_command, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
251 | 0 | command = tvb_get_uint8(tvb, offset); |
252 | |
|
253 | 0 | if (!((urb->setup_requesttype == 0x21 && (command == 0x00 || command == 0x01 || command == 0x04 || command == 0x06)) || |
254 | 0 | (urb->setup_requesttype == 0xa1 && (command == 0x02 || command == 0x03 || command == 0x05)))) |
255 | 0 | expert_add_info(pinfo, command_item, &ei_invalid_command_for_request_type); |
256 | 0 | offset += 1; |
257 | |
|
258 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "Command: %s", |
259 | 0 | val_to_str_ext_const(command, &command_vals_ext, "Unknown")); |
260 | |
|
261 | 0 | if (command == 0x00) { /* Detach */ |
262 | 0 | proto_tree_add_item(main_tree, hf_setup_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
263 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Timeout=%u", tvb_get_letohs(tvb, offset)); |
264 | 0 | } else if (command == 0x01 || command == 0x02) { /* Download || Upload */ |
265 | 0 | proto_tree_add_item(main_tree, hf_setup_block_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
266 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Block Number=%u", tvb_get_letohs(tvb, offset)); |
267 | 0 | block_number = tvb_get_letohs(tvb, offset); |
268 | 0 | } else { |
269 | 0 | proto_tree_add_item(main_tree, hf_setup_unused, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
270 | 0 | } |
271 | 0 | offset += 2; |
272 | |
|
273 | 0 | proto_tree_add_item(main_tree, hf_setup_interface, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
274 | 0 | interface = tvb_get_letohs(tvb, offset); |
275 | 0 | offset += 2; |
276 | |
|
277 | 0 | proto_tree_add_item_ret_uint(main_tree, hf_setup_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &length); |
278 | 0 | offset += 2; |
279 | |
|
280 | 0 | if (command == 0x01) { /* Download */ |
281 | | /* length == 0 implies there's no more data to download */ |
282 | 0 | if (length > 0) { |
283 | 0 | proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); |
284 | 0 | offset = tvb_captured_length(tvb); |
285 | 0 | } |
286 | 0 | } |
287 | |
|
288 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 0) { |
289 | 0 | proto_tree_add_expert(main_tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_captured_length_remaining(tvb, offset)); |
290 | 0 | offset = tvb_captured_length(tvb); |
291 | 0 | } |
292 | | |
293 | | /* Save request info (command_data) */ |
294 | 0 | if (!pinfo->fd->visited && command != 21) { |
295 | 0 | key[2].length = 1; |
296 | 0 | key[2].key = &k_frame_number; |
297 | 0 | key[3].length = 0; |
298 | 0 | key[3].key = NULL; |
299 | |
|
300 | 0 | command_data = wmem_new(wmem_file_scope(), command_data_t); |
301 | 0 | command_data->bus_id = bus_id; |
302 | 0 | command_data->device_address = device_address; |
303 | |
|
304 | 0 | command_data->command = command; |
305 | 0 | command_data->interface = interface; |
306 | 0 | command_data->command_frame_number = pinfo->num; |
307 | 0 | command_data->block_number = block_number; |
308 | |
|
309 | 0 | wmem_tree_insert32_array(command_info, key, command_data); |
310 | 0 | } |
311 | |
|
312 | 0 | pinfo->p2p_dir = p2p_dir_save; |
313 | |
|
314 | 0 | return offset; |
315 | 0 | } |
316 | | |
317 | | /* Get request info (command_data) */ |
318 | 0 | key[2].length = 0; |
319 | 0 | key[2].key = NULL; |
320 | |
|
321 | 0 | wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key); |
322 | 0 | if (wmem_tree) { |
323 | 0 | command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); |
324 | 0 | if (command_data) { |
325 | 0 | command_response = command_data->command; |
326 | 0 | block_number = command_data->block_number; |
327 | 0 | } |
328 | 0 | } |
329 | |
|
330 | 0 | if (!command_data) { |
331 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "Response: Unknown"); |
332 | |
|
333 | 0 | proto_tree_add_expert(main_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_captured_length_remaining(tvb, offset)); |
334 | |
|
335 | 0 | pinfo->p2p_dir = p2p_dir_save; |
336 | |
|
337 | 0 | return tvb_captured_length(tvb); |
338 | 0 | } |
339 | | |
340 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "Response: %s", |
341 | 0 | val_to_str_ext_const(command_response, &command_vals_ext, "Unknown")); |
342 | |
|
343 | 0 | command_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, 0, command_response); |
344 | 0 | command_tree = proto_item_add_subtree(command_item, ett_command); |
345 | 0 | proto_item_set_generated(command_item); |
346 | |
|
347 | 0 | command_item = proto_tree_add_uint(main_tree, hf_setup_interface, tvb, offset, 0, command_data->interface); |
348 | 0 | proto_item_set_generated(command_item); |
349 | |
|
350 | 0 | command_item = proto_tree_add_uint(main_tree, hf_command_in_frame, tvb, offset, 0, command_data->command_frame_number); |
351 | 0 | proto_item_set_generated(command_item); |
352 | |
|
353 | 0 | switch (command_response) { |
354 | 0 | case 0x02: /* Upload */ |
355 | 0 | if (block_number != -1) { |
356 | 0 | sub_item = proto_tree_add_uint(main_tree, hf_setup_block_number, tvb, offset, 0, block_number); |
357 | 0 | proto_item_set_generated(sub_item); |
358 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Block Number=%u", block_number); |
359 | 0 | } |
360 | |
|
361 | 0 | proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); |
362 | 0 | offset = tvb_captured_length(tvb); |
363 | |
|
364 | 0 | break; |
365 | 0 | case 0x03: /* Get Status */ |
366 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " = Status: %s, PollTimeout: %u ms, State: %s", |
367 | 0 | val_to_str_ext_const(tvb_get_uint8(tvb, offset), &status_vals_ext, "Unknown"), |
368 | 0 | tvb_get_letoh24(tvb, offset + 1), |
369 | 0 | val_to_str_ext_const(tvb_get_uint8(tvb, offset + 4), &state_vals_ext, "Unknown")); |
370 | |
|
371 | 0 | proto_tree_add_item(main_tree, hf_status, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
372 | 0 | offset += 1; |
373 | |
|
374 | 0 | proto_tree_add_item(main_tree, hf_poll_timeout, tvb, offset, 3, ENC_LITTLE_ENDIAN); |
375 | 0 | offset += 3; |
376 | |
|
377 | 0 | proto_tree_add_item(main_tree, hf_state, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
378 | 0 | offset += 1; |
379 | |
|
380 | 0 | proto_tree_add_item(main_tree, hf_iString, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
381 | 0 | offset += 1; |
382 | |
|
383 | 0 | break; |
384 | 0 | case 0x05: /* Get State */ |
385 | 0 | proto_tree_add_item(main_tree, hf_state, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
386 | |
|
387 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " = %s", |
388 | 0 | val_to_str_ext_const(tvb_get_uint8(tvb, offset), &state_vals_ext, "Unknown")); |
389 | |
|
390 | 0 | offset += 1; |
391 | |
|
392 | 0 | break; |
393 | 0 | case 0x00: /* Detach */ |
394 | 0 | case 0x01: /* Download */ |
395 | 0 | case 0x04: /* Clear Status */ |
396 | 0 | case 0x06: /* Abort */ |
397 | 0 | default: |
398 | 0 | proto_tree_add_expert(command_tree, pinfo, &ei_unexpected_response, tvb, offset, 0); |
399 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 0) { |
400 | 0 | proto_tree_add_expert(main_tree, pinfo, &ei_unknown_data, tvb, offset, -1); |
401 | 0 | offset = tvb_captured_length(tvb); |
402 | 0 | } |
403 | 0 | } |
404 | | |
405 | 0 | pinfo->p2p_dir = p2p_dir_save; |
406 | |
|
407 | 0 | return offset; |
408 | 0 | } |
409 | | |
410 | | void |
411 | | proto_register_usb_dfu(void) |
412 | 14 | { |
413 | 14 | module_t *module; |
414 | 14 | expert_module_t *expert_module; |
415 | | |
416 | 14 | static hf_register_info hf[] = { |
417 | | |
418 | 14 | { &hf_setup_command, |
419 | 14 | { "Command", "usbdfu.command", |
420 | 14 | FT_UINT8, BASE_DEC | BASE_EXT_STRING, &command_vals_ext, 0x0, |
421 | 14 | NULL, HFILL } |
422 | 14 | }, |
423 | 14 | { &hf_response, |
424 | 14 | { "Response", "usbdfu.response", |
425 | 14 | FT_UINT8, BASE_DEC | BASE_EXT_STRING, &command_vals_ext, 0x0, |
426 | 14 | NULL, HFILL } |
427 | 14 | }, |
428 | 14 | { &hf_command_in_frame, |
429 | 14 | { "Command Frame", "usbdfu.command_frame", |
430 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
431 | 14 | NULL, HFILL } |
432 | 14 | }, |
433 | 14 | { &hf_setup_unused, |
434 | 14 | { "Unused", "usbdfu.unused", |
435 | 14 | FT_UINT16, BASE_HEX, NULL, 0x0, |
436 | 14 | NULL, HFILL } |
437 | 14 | }, |
438 | 14 | { &hf_setup_interface, |
439 | 14 | { "Interface", "usbdfu.interface", |
440 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
441 | 14 | NULL, HFILL } |
442 | 14 | }, |
443 | 14 | { &hf_setup_length, |
444 | 14 | { "Length", "usbdfu.length", |
445 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
446 | 14 | NULL, HFILL } |
447 | 14 | }, |
448 | 14 | { &hf_setup_block_number, |
449 | 14 | { "Block Number", "usbdfu.block_number", |
450 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
451 | 14 | NULL, HFILL } |
452 | 14 | }, |
453 | 14 | { &hf_setup_timeout, |
454 | 14 | { "Timeout", "usbdfu.timeout", |
455 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
456 | 14 | NULL, HFILL } |
457 | 14 | }, |
458 | 14 | { &hf_state, |
459 | 14 | { "State", "usbdfu.state", |
460 | 14 | FT_UINT8, BASE_DEC | BASE_EXT_STRING, &state_vals_ext, 0x0, |
461 | 14 | NULL, HFILL } |
462 | 14 | }, |
463 | 14 | { &hf_status, |
464 | 14 | { "Status", "usbdfu.status", |
465 | 14 | FT_UINT8, BASE_HEX | BASE_EXT_STRING, &status_vals_ext, 0x0, |
466 | 14 | NULL, HFILL } |
467 | 14 | }, |
468 | 14 | { &hf_iString, |
469 | 14 | { "iString", "usbdfu.iString", |
470 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
471 | 14 | NULL, HFILL } |
472 | 14 | }, |
473 | 14 | { &hf_poll_timeout, |
474 | 14 | { "Poll Timeout", "usbdfu.poll_timeout", |
475 | 14 | FT_UINT24, BASE_DEC, NULL, 0x0, |
476 | 14 | NULL, HFILL } |
477 | 14 | }, |
478 | 14 | { &hf_data, |
479 | 14 | { "Data", "usbdfu.data", |
480 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
481 | 14 | NULL, HFILL } |
482 | 14 | }, |
483 | 14 | { &hf_usb_dfu_descriptor, |
484 | 14 | { "DFU Descriptor", "usbdfu.descriptor", |
485 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
486 | 14 | NULL, HFILL } |
487 | 14 | }, |
488 | 14 | { &hf_usb_dfu_descriptor_bmAttributes_reserved, |
489 | 14 | { "Reserved", "usbdfu.descriptor.bmAttributes.reserved", |
490 | 14 | FT_UINT8, BASE_HEX, NULL, 0xF0, |
491 | 14 | NULL, HFILL } |
492 | 14 | }, |
493 | 14 | { &hf_usb_dfu_descriptor_bmAttributes_WillDetach, |
494 | 14 | { "Will Detach", "usbdfu.descriptor.bmAttributes.WillDetach", |
495 | 14 | FT_BOOLEAN, 8, NULL, 0x08, |
496 | 14 | NULL, HFILL } |
497 | 14 | }, |
498 | 14 | { &hf_usb_dfu_descriptor_bmAttributes_ManifestationTolerant, |
499 | 14 | { "Manifestation Tolerant", "usbdfu.descriptor.bmAttributes.ManifestationTolerant", |
500 | 14 | FT_BOOLEAN, 8, NULL, 0x04, |
501 | 14 | NULL, HFILL } |
502 | 14 | }, |
503 | 14 | { &hf_usb_dfu_descriptor_bmAttributes_CanUpload, |
504 | 14 | { "Can Upload", "usbdfu.descriptor.bmAttributes.CanUpload", |
505 | 14 | FT_BOOLEAN, 8, NULL, 0x02, |
506 | 14 | NULL, HFILL } |
507 | 14 | }, |
508 | 14 | { &hf_usb_dfu_descriptor_bmAttributes_CanDownload, |
509 | 14 | { "Can Download", "usbdfu.descriptor.bmAttributes.CanDownload", |
510 | 14 | FT_BOOLEAN, 8, NULL, 0x01, |
511 | 14 | NULL, HFILL } |
512 | 14 | }, |
513 | 14 | { &hf_usb_dfu_descriptor_wDetachTimeOut, |
514 | 14 | { "wDetachTimeOut", "usbdfu.descriptor.wDetachTimeOut", |
515 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
516 | 14 | NULL, HFILL } |
517 | 14 | }, |
518 | 14 | { &hf_usb_dfu_descriptor_wTransferSize, |
519 | 14 | { "wTransferSize", "usbdfu.descriptor.wTransferSize", |
520 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
521 | 14 | NULL, HFILL } |
522 | 14 | }, |
523 | 14 | { &hf_usb_dfu_descriptor_bcdDFUVersion, |
524 | 14 | { "bcdDFUVersion", "usbdfu.descriptor.bcdDFUVersion", |
525 | 14 | FT_UINT16, BASE_HEX, NULL, 0x0, |
526 | 14 | NULL, HFILL } |
527 | 14 | } |
528 | 14 | }; |
529 | | |
530 | 14 | static ei_register_info ei[] = { |
531 | 14 | { &ei_unexpected_response, { "usb_dfu.unexpected_response", PI_PROTOCOL, PI_ERROR, "Unexpected response for this command", EXPFILL }}, |
532 | 14 | { &ei_unknown_data, { "usb_dfu.unknown_data", PI_PROTOCOL, PI_NOTE, "Unknown data", EXPFILL }}, |
533 | 14 | { &ei_unexpected_data, { "usb_dfu.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected data", EXPFILL }}, |
534 | 14 | { &ei_invalid_command_for_request_type, { "usb_dfu.invalid_command_for_request_type", PI_PROTOCOL, PI_WARN, "Invalid command for this Request Type", EXPFILL }}, |
535 | 14 | { &ei_descriptor_invalid_length, { "usb_dfu.descriptor.invalid_length", PI_PROTOCOL, PI_WARN, "Invalid Length", EXPFILL }}, |
536 | 14 | }; |
537 | | |
538 | 14 | static int *ett[] = { |
539 | 14 | &ett_usb_dfu, |
540 | 14 | &ett_usb_dfu_descriptor, |
541 | 14 | &ett_command |
542 | 14 | }; |
543 | | |
544 | 14 | command_info = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); |
545 | | |
546 | 14 | proto_usb_dfu = proto_register_protocol("USB Device Firmware Upgrade ", "USB DFU", "usbdfu"); |
547 | 14 | proto_register_field_array(proto_usb_dfu, hf, array_length(hf)); |
548 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
549 | 14 | usb_dfu_handle = register_dissector("usb_dfu", dissect_usb_dfu, proto_usb_dfu); |
550 | 14 | usf_dfu_descriptor_handle = register_dissector("usb_dfu.descriptor", dissect_usb_dfu_descriptor, proto_usb_dfu); |
551 | | |
552 | 14 | expert_module = expert_register_protocol(proto_usb_dfu); |
553 | 14 | expert_register_field_array(expert_module, ei, array_length(ei)); |
554 | | |
555 | 14 | module = prefs_register_protocol(proto_usb_dfu, NULL); |
556 | 14 | prefs_register_static_text_preference(module, "version", |
557 | 14 | "USB DFU Specification 1.1", |
558 | 14 | "Version of protocol supported by this dissector."); |
559 | 14 | } |
560 | | |
561 | 14 | #define RUNTIME_KEY USB_PROTOCOL_KEY(IF_CLASS_APPLICATION_SPECIFIC, IF_SUBCLASS_APP_DFU, IF_PROTOCOL_DFU_RUNTIME) |
562 | 14 | #define DFU_MODE_KEY USB_PROTOCOL_KEY(IF_CLASS_APPLICATION_SPECIFIC, IF_SUBCLASS_APP_DFU, IF_PROTOCOL_DFU_MODE) |
563 | | |
564 | | void |
565 | | proto_reg_handoff_usb_dfu(void) |
566 | 14 | { |
567 | 14 | dissector_add_uint("usb.descriptor", IF_CLASS_APPLICATION_SPECIFIC, usf_dfu_descriptor_handle); |
568 | | |
569 | 14 | dissector_add_uint("usb.control", RUNTIME_KEY, usb_dfu_handle); |
570 | 14 | dissector_add_uint("usb.control", DFU_MODE_KEY, usb_dfu_handle); |
571 | | |
572 | 14 | dissector_add_uint("usb.product", (0x05ac << 16) | 0x1227, usb_dfu_handle); /* Apple Inc. Mobile Device (DFU Mode) */ |
573 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x1db5, usb_dfu_handle); /* IDBG in DFU mode */ |
574 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6001, usb_dfu_handle); /* Ubertooth Zero DFU */ |
575 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6003, usb_dfu_handle); /* Ubertooth One DFU */ |
576 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x600f, usb_dfu_handle); /* Paparazzi Lisa/M (DFU) */ |
577 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6011, usb_dfu_handle); /* LeoLipo (DFU) */ |
578 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6017, usb_dfu_handle); /* Black Magic Debug Probe (DFU) */ |
579 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6044, usb_dfu_handle); /* Open Source USB CANBUS converter (DFU Mode) */ |
580 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6064, usb_dfu_handle); /* CPC FPGA (DFU) */ |
581 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6069, usb_dfu_handle); /* xser (DFU mode) */ |
582 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6082, usb_dfu_handle); /* Facecandy *USB DFU loader */ |
583 | 14 | dissector_add_uint("usb.product", (0x1d50 << 16) | 0x6084, usb_dfu_handle); /* arcin arcade controller (USB DFU loader) */ |
584 | | |
585 | 14 | dissector_add_for_decode_as("usb.device", usb_dfu_handle); |
586 | 14 | dissector_add_for_decode_as("usb.protocol", usb_dfu_handle); |
587 | 14 | } |
588 | | |
589 | | /* |
590 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
591 | | * |
592 | | * Local variables: |
593 | | * c-basic-offset: 4 |
594 | | * tab-width: 8 |
595 | | * indent-tabs-mode: nil |
596 | | * End: |
597 | | * |
598 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
599 | | * :indentSize=4:tabSize=8:noTabs=true: |
600 | | */ |