Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-rfid-pn532-hci.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-pn532_hci.c
2
 * Routines for NXP PN532 HCI Protocol
3
 *
4
 * http://www.nxp.com/documents/user_manual/141520.pdf
5
 *
6
 * Copyright 2013, Michal Labedzki for Tieto Corporation
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * SPDX-License-Identifier: GPL-2.0-or-later
13
 */
14
15
#include "config.h"
16
17
#include <epan/packet.h>
18
#include <epan/prefs.h>
19
#include <epan/expert.h>
20
#include "packet-usb.h"
21
22
static int proto_pn532_hci;
23
static int hf_preamble;
24
static int hf_start_code;
25
static int hf_length;
26
static int hf_length_checksum;
27
static int hf_length_checksum_status;
28
static int hf_extended_length;
29
static int hf_packet_code;
30
static int hf_postable;
31
static int hf_specific_application_level_error_code;
32
static int hf_data_checksum;
33
static int hf_data_checksum_status;
34
static int hf_ignored;
35
36
static int ett_pn532_hci;
37
38
static expert_field ei_invalid_length_checksum;
39
static expert_field ei_invalid_data_checksum;
40
41
static dissector_handle_t  pn532_handle;
42
static dissector_handle_t  pn532_hci_handle;
43
44
static const value_string packet_code_vals[] = {
45
    { 0x00FF,  "ACK Frame" },
46
    { 0x01FF,  "Error Frame" },
47
    { 0xFF00,  "NACK Frame" },
48
    { 0xFFFF,  "Extended Information Frame" },
49
    { 0, NULL }
50
};
51
52
void proto_register_pn532_hci(void);
53
void proto_reg_handoff_pn532_hci(void);
54
55
static int
56
dissect_pn532_hci(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
57
0
{
58
0
    proto_item      *main_item;
59
0
    proto_tree      *main_tree;
60
0
    int              offset = 0;
61
0
    tvbuff_t        *next_tvb;
62
0
    uint16_t         packet_code;
63
0
    uint16_t         length;
64
0
    uint8_t          checksum;
65
0
    urb_info_t      *urb;
66
67
    /* Reject the packet if data is NULL */
68
0
    if (data == NULL)
69
0
        return 0;
70
0
    urb = (urb_info_t *)data;
71
72
0
    length = tvb_captured_length_remaining(tvb, offset);
73
0
    if (length < 6) return offset;
74
75
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN532_HCI");
76
0
    col_clear(pinfo->cinfo, COL_INFO);
77
78
0
    main_item = proto_tree_add_item(tree, proto_pn532_hci, tvb, offset, -1, ENC_NA);
79
0
    main_tree = proto_item_add_subtree(main_item, ett_pn532_hci);
80
81
0
    length = 0;
82
0
    while (tvb_captured_length_remaining(tvb, length) >= 2 && tvb_get_ntohs(tvb, length) != 0x00FF) {
83
0
        length += 1;
84
0
    }
85
0
    if (length) {
86
0
        proto_tree_add_item(main_tree, hf_preamble, tvb, offset, length, ENC_NA);
87
0
        offset += length;
88
0
    }
89
90
0
    proto_tree_add_item(main_tree, hf_start_code, tvb, offset, 2, ENC_BIG_ENDIAN);
91
0
    offset += 2;
92
93
0
    packet_code = tvb_get_ntohs(tvb, offset);
94
0
    if (packet_code == 0x00FF) { /* ACK Frame */
95
0
        col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_code, packet_code_vals, "Unknown frame"));
96
97
0
        proto_tree_add_item(main_tree, hf_packet_code, tvb, offset, 2, ENC_BIG_ENDIAN);
98
0
        offset += 2;
99
0
    } else if (packet_code == 0xFF00) { /* NACK Frame */
100
0
        col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_code, packet_code_vals, "Unknown frame"));
101
102
0
        proto_tree_add_item(main_tree, hf_packet_code, tvb, offset, 2, ENC_BIG_ENDIAN);
103
0
        offset += 2;
104
0
    } else if (packet_code == 0x01FF) { /* Error Frame */
105
0
        col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_code, packet_code_vals, "Unknown frame"));
106
107
0
        proto_tree_add_item(main_tree, hf_packet_code, tvb, offset, 2, ENC_BIG_ENDIAN);
108
0
        offset += 2;
109
110
0
        proto_tree_add_item(main_tree, hf_specific_application_level_error_code, tvb, offset, 1, ENC_BIG_ENDIAN);
111
0
        offset += 1;
112
0
    } else if (packet_code == 0xFFFF) { /* Extended Information Frame */
113
0
        col_set_str(pinfo->cinfo, COL_INFO, "Extended Information Frame");
114
115
0
        proto_tree_add_item(main_tree, hf_extended_length, tvb, offset, 2, ENC_BIG_ENDIAN);
116
0
        length = tvb_get_ntohs(tvb, offset);
117
0
        offset += 2;
118
119
0
        checksum = (length >> 8) + (length & 0xFF) + tvb_get_uint8(tvb, offset);
120
0
        proto_tree_add_checksum(main_tree, tvb, offset, hf_length_checksum, hf_length_checksum_status, &ei_invalid_length_checksum,
121
0
                            pinfo, checksum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
122
0
        offset += 1;
123
124
0
        next_tvb = tvb_new_subset_length(tvb, offset, length);
125
0
        call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, urb);
126
0
        offset += length;
127
128
0
        checksum = tvb_get_uint8(tvb, offset);
129
0
        while (length) {
130
0
            checksum += tvb_get_uint8(tvb, offset - length);
131
0
            length -= 1;
132
0
        }
133
0
        proto_tree_add_checksum(main_tree, tvb, offset, hf_data_checksum, hf_data_checksum_status, &ei_invalid_data_checksum, pinfo, 0,
134
0
                            ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
135
0
        offset += 1;
136
0
    } else { /* Normal Information Frame */
137
0
        col_set_str(pinfo->cinfo, COL_INFO, "Normal Information Frame");
138
139
0
        proto_tree_add_item(main_tree, hf_length, tvb, offset, 1, ENC_BIG_ENDIAN);
140
0
        length = tvb_get_uint8(tvb, offset);
141
0
        offset += 1;
142
143
0
        checksum = length + tvb_get_uint8(tvb, offset);
144
0
        proto_tree_add_checksum(main_tree, tvb, offset, hf_length_checksum, hf_length_checksum_status, &ei_invalid_length_checksum,
145
0
                            pinfo, checksum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
146
0
        offset += 1;
147
148
0
        next_tvb = tvb_new_subset_length(tvb, offset, length);
149
0
        call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, urb);
150
0
        offset += length;
151
152
0
        proto_tree_add_item(main_tree, hf_data_checksum, tvb, offset, 1, ENC_BIG_ENDIAN);
153
0
        checksum = tvb_get_uint8(tvb, offset);
154
0
        while (length) {
155
0
            checksum += tvb_get_uint8(tvb, offset - length);
156
0
            length -= 1;
157
0
        }
158
0
        if (checksum != 0) {
159
0
            proto_tree_add_expert(main_tree, pinfo, &ei_invalid_data_checksum, tvb, offset, 1);
160
0
        }
161
0
        offset += 1;
162
0
    }
163
164
0
    length = 0;
165
0
    if (tvb_captured_length_remaining(tvb, offset) == 1) {
166
0
        length = 1;
167
0
    } else while (tvb_captured_length_remaining(tvb, offset + length) >= 2 && tvb_get_ntohs(tvb, offset + length) != 0x00FF) {
168
0
        length += 1;
169
0
    }
170
0
    if (length) {
171
0
        proto_tree_add_item(main_tree, hf_postable, tvb, offset, length, ENC_NA);
172
0
        offset += length;
173
0
    }
174
175
0
    if (tvb_captured_length_remaining(tvb, offset)) {
176
0
        proto_tree_add_item(main_tree, hf_ignored, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
177
0
        offset += tvb_captured_length_remaining(tvb, offset);
178
0
    }
179
180
0
    return offset;
181
0
}
182
183
void
184
proto_register_pn532_hci(void)
185
14
{
186
14
    module_t         *module;
187
14
    expert_module_t  *expert_module;
188
189
14
    static hf_register_info hf[] = {
190
14
        { &hf_preamble,
191
14
            { "Preamble",                        "pn532_hci.preamble",
192
14
            FT_BYTES, BASE_NONE, NULL, 0x00,
193
14
            NULL, HFILL }
194
14
        },
195
14
        { &hf_start_code,
196
14
            { "Start Code",                      "pn532_hci.start_code",
197
14
            FT_UINT16, BASE_HEX, NULL, 0x00,
198
14
            NULL, HFILL }
199
14
        },
200
14
        { &hf_packet_code,
201
14
            { "Packet Code",                     "pn532_hci.packet_code",
202
14
            FT_UINT16, BASE_HEX, VALS(packet_code_vals), 0x00,
203
14
            NULL, HFILL }
204
14
        },
205
14
        { &hf_length,
206
14
            { "Length",                          "pn532_hci.length",
207
14
            FT_UINT8, BASE_DEC, NULL, 0x00,
208
14
            NULL, HFILL }
209
14
        },
210
14
        { &hf_extended_length,
211
14
            { "Extended Length",                 "pn532_hci.extended_length",
212
14
            FT_UINT16, BASE_DEC, NULL, 0x00,
213
14
            NULL, HFILL }
214
14
        },
215
14
        { &hf_length_checksum,
216
14
            { "Length Checksum",                 "pn532_hci.length_checksum",
217
14
            FT_UINT8, BASE_HEX, NULL, 0x00,
218
14
            NULL, HFILL }
219
14
        },
220
14
        { &hf_length_checksum_status,
221
14
            { "Length Checksum Status",            "pn532_hci.length_checksum.status",
222
14
            FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x00,
223
14
            NULL, HFILL }
224
14
        },
225
14
        { &hf_data_checksum,
226
14
            { "Data Checksum",                   "pn532_hci.data_checksum",
227
14
            FT_UINT8, BASE_HEX, NULL, 0x00,
228
14
            NULL, HFILL }
229
14
        },
230
14
        { &hf_data_checksum_status,
231
14
            { "Data Checksum Status",            "pn532_hci.data_checksum.status",
232
14
            FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x00,
233
14
            NULL, HFILL }
234
14
        },
235
14
        { &hf_specific_application_level_error_code,
236
14
            { "Specific Application Level Error Code","pn532_hci.specific_application_level_error_code",
237
14
            FT_UINT8, BASE_HEX, NULL, 0x00,
238
14
            NULL, HFILL }
239
14
        },
240
14
        { &hf_postable,
241
14
            { "Postamble",                       "pn532_hci.postamble",
242
14
            FT_BYTES, BASE_NONE, NULL, 0x00,
243
14
            NULL, HFILL }
244
14
        },
245
14
        { &hf_ignored,
246
14
            { "Ignored",                         "pn532_hci.ignored",
247
14
            FT_BYTES, BASE_NONE, NULL, 0x00,
248
14
            NULL, HFILL }
249
14
        }
250
14
    };
251
252
14
    static int *ett[] = {
253
14
        &ett_pn532_hci
254
14
    };
255
256
14
    static ei_register_info ei[] = {
257
14
        { &ei_invalid_length_checksum, { "pn532_hci.expert.invalid_length_checksum", PI_PROTOCOL, PI_WARN, "Invalid Length Checksum", EXPFILL }},
258
14
        { &ei_invalid_data_checksum,   { "pn532_hci.expert.invalid_data_checksum", PI_PROTOCOL, PI_WARN, "Invalid Data Checksum", EXPFILL }},
259
14
    };
260
261
14
    proto_pn532_hci = proto_register_protocol("NXP PN532 HCI", "PN532_HCI", "pn532_hci");
262
14
    pn532_hci_handle = register_dissector("pn532_hci", dissect_pn532_hci, proto_pn532_hci);
263
264
14
    proto_register_field_array(proto_pn532_hci, hf, array_length(hf));
265
14
    proto_register_subtree_array(ett, array_length(ett));
266
14
    expert_module = expert_register_protocol(proto_pn532_hci);
267
14
    expert_register_field_array(expert_module, ei, array_length(ei));
268
269
14
    module = prefs_register_protocol(proto_pn532_hci, NULL);
270
14
    prefs_register_static_text_preference(module, "version",
271
14
            "PN532 HCI protocol version is based on: \"UM0701-02; PN532 User Manual\"",
272
14
            "Version of protocol supported by this dissector.");
273
14
}
274
275
void
276
proto_reg_handoff_pn532_hci(void)
277
14
{
278
14
    pn532_handle = find_dissector_add_dependency("pn532", proto_pn532_hci);
279
280
14
    dissector_add_uint("usb.product", (0x04e6 << 16) | 0x5591, pn532_hci_handle);
281
282
14
    dissector_add_for_decode_as("usb.device", pn532_hci_handle);
283
14
    dissector_add_for_decode_as("usb.protocol", pn532_hci_handle);
284
14
}
285
286
/*
287
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
288
 *
289
 * Local variables:
290
 * c-basic-offset: 4
291
 * tab-width: 8
292
 * indent-tabs-mode: nil
293
 * End:
294
 *
295
 * vi: set shiftwidth=4 tabstop=8 expandtab:
296
 * :indentSize=4:tabSize=8:noTabs=true:
297
 */