Coverage Report

Created: 2025-02-15 06:25

/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
 */