86031b7e03829e68bf6a78d1d090162a7f9590a3
[metze/wireshark/wip.git] / epan / dissectors / packet-acr122.c
1 /* packet-acr122.c
2  * Routines for ACR122 USB NFC dongle
3  *
4  * Copyright 2013, 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  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See thehf_class
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <epan/packet.h>
28 #include <epan/prefs.h>
29 #include <epan/expert.h>
30 #include "packet-usb.h"
31
32 static int proto_acr122                                                    = -1;
33
34 static int hf_class                                                        = -1;
35 static int hf_ins                                                          = -1;
36 static int hf_p1                                                           = -1;
37 static int hf_p2                                                           = -1;
38 static int hf_length                                                       = -1;
39 static int hf_status_word                                                  = -1;
40 static int hf_status_word_sw1                                              = -1;
41 static int hf_status_word_sw2                                              = -1;
42 static int hf_status_word_led_reserved                                     = -1;
43 static int hf_status_word_led_green                                        = -1;
44 static int hf_status_word_led_red                                          = -1;
45 static int hf_command                                                      = -1;
46 static int hf_response                                                     = -1;
47 static int hf_response_for                                                 = -1;
48 static int hf_picc_operating_auto_picc_polling                             = -1;
49 static int hf_picc_operating_auto_ats_generation                           = -1;
50 static int hf_picc_operating_polling_interval                              = -1;
51 static int hf_picc_operating_felica_424k                                   = -1;
52 static int hf_picc_operating_felica_212k                                   = -1;
53 static int hf_picc_operating_topaz                                         = -1;
54 static int hf_picc_operating_iso_14443_type_b                              = -1;
55 static int hf_picc_operating_iso_14443_type_a                              = -1;
56 static int hf_firmware_version                                             = -1;
57 static int hf_led_green_blinking_state                                     = -1;
58 static int hf_led_red_blinking_state                                       = -1;
59 static int hf_led_green_mask                                               = -1;
60 static int hf_led_red_mask                                                 = -1;
61 static int hf_led_initial_green_blinking_state                             = -1;
62 static int hf_led_initial_red_blinking_state                               = -1;
63 static int hf_led_final_green_state                                        = -1;
64 static int hf_led_final_red_state                                          = -1;
65 static int hf_led_t1_duration                                              = -1;
66 static int hf_led_t2_duration                                              = -1;
67 static int hf_led_number_of_repetition                                     = -1;
68 static int hf_led_link_to_buzzer                                           = -1;
69 static int hf_timeout                                                      = -1;
70 static int hf_poll_buzzer_status                                           = -1;
71 static int hf_key                                                          = -1;
72 static int hf_key_structure                                                = -1;
73 static int hf_key_number                                                   = -1;
74 static int hf_key_type                                                     = -1;
75 static int hf_block_number                                                 = -1;
76 static int hf_source_block_number                                          = -1;
77 static int hf_target_block_number                                          = -1;
78 static int hf_vb_op                                                        = -1;
79 static int hf_static_byte                                                  = -1;
80 static int hf_version                                                      = -1;
81 static int hf_value                                                        = -1;
82 static int hf_uid                                                          = -1;
83 static int hf_ats                                                          = -1;
84 static int hf_data                                                         = -1;
85
86 static gint ett_acr122                                                 = -1;
87 static gint ett_p1_item                                                    = -1;
88 static gint ett_p2_item                                                    = -1;
89 static gint ett_status_word                                                = -1;
90 static gint ett_status_word_sw2                                            = -1;
91
92 static expert_field ei_unknown_command_or_invalid_parameters          = EI_INIT;
93
94 static dissector_handle_t  acr122_handle;
95 static dissector_handle_t  pn532_handle;
96
97 static wmem_tree_t *command_info = NULL;
98
99 typedef struct command_data_t {
100     guint32  bus_id;
101     guint32  device_address;
102     guint32  endpoint;
103
104     guint8   command;
105     guint32  command_frame_number;
106     guint32  response_frame_number;
107 } command_data_t;
108
109 /* Not part of protocol, generated values */
110 #define CMD_UNKNOWN                                 0x00
111 #define CMD_GET_DATA_UID                            0x01
112 #define CMD_GET_DATA_ATS                            0x02
113 #define CMD_LOAD_AUTHENTICATION_KEYS                0x03
114 #define CMD_AUTHENTICATION_OBSOLETE                 0x04
115 #define CMD_AUTHENTICATION                          0x05
116 #define CMD_READ_BINARY_BLOCKS                      0x06
117 #define CMD_UPDATE_BINARY_BLOCKS                    0x07
118 #define CMD_VALUE_BLOCK_OPERATION                   0x08
119 #define CMD_READ_VALUE_BLOCK                        0x09
120 #define CMD_RESTORE_VALUE_BLOCK                     0x0A
121 #define CMD_DIRECT_TRANSMIT                         0x0B
122 #define CMD_BI_COLOR_AND_BUZZER_LED_CONTROL         0x0C
123 #define CMD_GET_FIRMWARE_VERSION                    0x0D
124 #define CMD_GET_PICC_OPERATING_PARAMETER            0x0E
125 #define CMD_SET_PICC_OPERATING_PARAMETER            0x0F
126 #define CMD_SET_TIMEOUT_PARAMETER                   0x10
127 #define CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION    0x11
128
129 static const value_string command_vals[] = {
130     { CMD_GET_DATA_UID,                          "Get Data - UID" },
131     { CMD_GET_DATA_ATS,                          "Get Data - ATS" },
132     { CMD_LOAD_AUTHENTICATION_KEYS,              "Load Authentication Keys" },
133     { CMD_AUTHENTICATION_OBSOLETE,               "Authentication (Obsolete)" },
134     { CMD_AUTHENTICATION,                        "Authentication" },
135     { CMD_READ_BINARY_BLOCKS,                    "Read Binary Blocks" },
136     { CMD_UPDATE_BINARY_BLOCKS,                  "Update Binary Blocks" },
137     { CMD_VALUE_BLOCK_OPERATION,                 "Value Block Operation" },
138     { CMD_READ_VALUE_BLOCK,                      "Read Value Block" },
139     { CMD_RESTORE_VALUE_BLOCK,                   "Restore Value Block" },
140     { CMD_DIRECT_TRANSMIT,                       "Direct Transmit" },
141     { CMD_BI_COLOR_AND_BUZZER_LED_CONTROL,       "Bi-Color and Buzzer LED Control" },
142     { CMD_GET_FIRMWARE_VERSION,                  "Get Firmware Version" },
143     { CMD_GET_PICC_OPERATING_PARAMETER,          "Get PICC Operating Parameter" },
144     { CMD_SET_PICC_OPERATING_PARAMETER,          "Set PICC Operating Parameter" },
145     { CMD_SET_TIMEOUT_PARAMETER,                 "Set Timeout Parameter" },
146     { CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION,  "Set Buzzer Output for Card Detection" },
147     { 0, NULL }
148 };
149 static value_string_ext command_vals_ext = VALUE_STRING_EXT_INIT(command_vals);
150
151 static const range_string status_word_rvals[] = {
152     { 0x6300, 0x6300,   "Operation Fail" },
153     { 0x6a81, 0x6a81,   "Function not Supported" },
154     { 0x9000, 0x90FF,   "Success" },
155     { 0, 0, NULL }
156 };
157
158 static const value_string link_to_buzzer_vals[] = {
159     { 0x00,  "The buzzer will not turn on" },
160     { 0x01,  "The buzzer will turn on during the T1 Duration" },
161     { 0x02,  "The buzzer will turn on during the T2 Duration" },
162     { 0x03,  "The buzzer will turn on during the T1 and T2 Duration" },
163     { 0, NULL }
164 };
165
166 static const value_string key_structure_vals[] = {
167     { 0x00,  "Key is loaded into the reader volatile memory" },
168     { 0, NULL }
169 };
170
171 static const value_string poll_buzzer_status_vals[] = {
172     { 0x00,  "Buzzer disabled on card detected" },
173     { 0xFF,  "Buzzer enabled on card detected" },
174     { 0, NULL }
175 };
176
177 static const value_string key_type_vals[] = {
178     { 0x60,  "Type A" },
179     { 0x61,  "Type B" },
180     { 0, NULL }
181 };
182
183 static const value_string vb_op_vals[] = {
184     { 0x00,  "Store the \"Value\" into the block. The block will then be converted to a value block." },
185     { 0x01,  "Increment the value of the value block by the \"Value\". This command is only valid for value block." },
186     { 0x02,  "Decrement the value of the value block by the \"Value\". This command is only valid for value block." },
187     { 0, NULL }
188 };
189
190 void proto_register_acr122(void);
191 void proto_reg_handoff_acr122(void);
192
193 static void
194 duration_base(gchar *buf, guint32 value) {
195         g_snprintf(buf, ITEM_LABEL_LENGTH, "%u.%03u s", value * 100 / 1000, value * 100 % 1000);
196 }
197
198 static void
199 timeout_base(gchar *buf, guint32 value) {
200         if (value == 0x00)
201             g_snprintf(buf, ITEM_LABEL_LENGTH, "No timeout check");
202         else if (value == 0xFF)
203             g_snprintf(buf, ITEM_LABEL_LENGTH, "Wait until the contactless chip responds");
204         else if (value < 12)
205             g_snprintf(buf, ITEM_LABEL_LENGTH, "%u [s]", value * 5);
206         else
207             g_snprintf(buf, ITEM_LABEL_LENGTH, "%u:%02u [mm:ss]", value * 5 / 60, value * 5 % 60);
208 }
209
210
211 static gint
212 dissect_acr122(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
213 {
214     proto_item      *main_item;
215     proto_tree      *main_tree;
216     proto_item      *p1_item;
217     proto_tree      *p1_tree;
218     proto_item      *p2_item;
219     proto_tree      *p2_tree;
220     proto_item      *sub_item;
221     proto_item      *sub_tree;
222     proto_item      *sw2_item;
223     proto_item      *sw2_tree;
224     gint             offset = 0;
225     guint32          value;
226     tvbuff_t        *next_tvb;
227     guint8           acr_class;
228     guint8           ins;
229     guint8           p1;
230     guint8           p2;
231     guint8           length;
232     guint8           command = CMD_UNKNOWN;
233     command_data_t  *command_data;
234     usb_conv_info_t *usb_conv_info;
235     wmem_tree_key_t  key[5];
236     guint32          bus_id;
237     guint32          device_address;
238     guint32          endpoint;
239     guint32          k_bus_id;
240     guint32          k_device_address;
241     guint32          k_endpoint;
242     guint32          k_frame_number;
243
244     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACR 122");
245     col_clear(pinfo->cinfo, COL_INFO);
246
247     main_item = proto_tree_add_item(tree, proto_acr122, tvb, offset, -1, ENC_NA);
248     main_tree = proto_item_add_subtree(main_item, ett_acr122);
249
250     if (!data) return offset;
251     usb_conv_info = (usb_conv_info_t *) data;
252
253     bus_id = usb_conv_info->bus_id;
254     device_address = usb_conv_info->device_address;
255     endpoint = usb_conv_info->endpoint;
256
257     k_bus_id  = bus_id;
258     k_device_address  = device_address;
259     k_endpoint        = endpoint;
260     k_frame_number    = pinfo->num;
261
262     key[0].length = 1;
263     key[0].key = &k_bus_id;
264     key[1].length = 1;
265     key[1].key = &k_device_address;
266     key[2].length = 1;
267     key[2].key = &k_endpoint;
268     key[3].length = 1;
269     key[3].key = &k_frame_number;
270     key[4].length = 0;
271     key[4].key = NULL;
272
273
274     if (pinfo->p2p_dir == P2P_DIR_SENT) { /* Request */
275         acr_class = tvb_get_guint8(tvb, offset);
276         ins = tvb_get_guint8(tvb, offset + 1);
277         p1 = tvb_get_guint8(tvb, offset + 2);
278         p2 = tvb_get_guint8(tvb, offset + 3);
279         length = tvb_get_guint8(tvb, offset + 4);
280
281         /* Recognize command by simple heuristic */
282         if (acr_class == 0xFF) {
283             if (ins == 0xCA && p1 == 0x00 && p2 == 0x00 && length == 0)
284                 command = CMD_GET_DATA_UID;
285             if (ins == 0xCA && p1 == 0x01 && p2 == 0x00 && length == 0)
286                 command = CMD_GET_DATA_ATS;
287             else if (ins == 0x82 && length == 6)
288                 command = CMD_LOAD_AUTHENTICATION_KEYS;
289             else if (ins == 0x88 && p1 == 0x00)
290                 command = CMD_AUTHENTICATION_OBSOLETE;
291             else if (ins == 0x86 && p1 == 0x00 && p2 == 0x00 && length == 5)
292                 command = CMD_AUTHENTICATION;
293             else if (ins == 0xB0 && p1 == 0x00)
294                 command = CMD_READ_BINARY_BLOCKS;
295             else if (ins == 0xD6 && p1 == 0x00)
296                 command = CMD_UPDATE_BINARY_BLOCKS;
297             else if (ins == 0xD7 && p1 == 0x00 && length == 5)
298                 command = CMD_VALUE_BLOCK_OPERATION;
299             else if (ins == 0xB1 && p1 == 0x00 && length == 4)
300                 command = CMD_READ_VALUE_BLOCK;
301             else if (ins == 0xD7 && p1 == 0x00 && length == 2)
302                 command = CMD_RESTORE_VALUE_BLOCK;
303             else if (ins == 0x00 && p1 == 0x00 && p2 == 0x00)
304                 command = CMD_DIRECT_TRANSMIT;
305             else if (ins == 0x00 && p1 == 0x40 && length == 4)
306                 command = CMD_BI_COLOR_AND_BUZZER_LED_CONTROL;
307             else if (ins == 0x00 && p1 == 0x48 && p2 == 0x00)
308                 command = CMD_GET_FIRMWARE_VERSION;
309             else if (ins == 0x00 && p1 == 0x50 && p2 == 0x00)
310                 command = CMD_GET_PICC_OPERATING_PARAMETER;
311             else if (ins == 0x00 && p1 == 0x51 && length == 0)
312                 command = CMD_SET_PICC_OPERATING_PARAMETER;
313             else if (ins == 0x00 && p1 == 0x41 && length == 0)
314                 command = CMD_SET_TIMEOUT_PARAMETER;
315             else if (ins == 0x00 && p1 == 0x52 && length == 0)
316                 command = CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION;
317         }
318
319         sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 4 + length, command);
320         PROTO_ITEM_SET_GENERATED(sub_item);
321         if (command == CMD_UNKNOWN)
322             expert_add_info(pinfo, sub_item, &ei_unknown_command_or_invalid_parameters);
323
324         col_add_fstr(pinfo->cinfo, COL_INFO, "Command: %s", val_to_str_ext_const(command, &command_vals_ext, "Unknown"));
325
326         proto_tree_add_item(main_tree, hf_class, tvb, offset, 1, ENC_BIG_ENDIAN);
327         offset += 1;
328
329         proto_tree_add_item(main_tree, hf_ins, tvb, offset, 1, ENC_BIG_ENDIAN);
330         offset += 1;
331
332         p1_item = proto_tree_add_item(main_tree, hf_p1, tvb, offset, 1, ENC_BIG_ENDIAN);
333         offset += 1;
334
335         p2_item = proto_tree_add_item(main_tree, hf_p2, tvb, offset, 1, ENC_BIG_ENDIAN);
336         offset += 1;
337
338         proto_tree_add_item(main_tree, hf_length, tvb, offset, 1, ENC_BIG_ENDIAN);
339         offset += 1;
340
341         switch (command) {
342         case CMD_DIRECT_TRANSMIT:
343             if (length > 0) {
344                 next_tvb = tvb_new_subset_length(tvb, offset, length);
345                 call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info);
346                 offset += length;
347             }
348             break;
349         case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL:
350             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
351             proto_tree_add_item(p2_tree, hf_led_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
352             proto_tree_add_item(p2_tree, hf_led_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
353             proto_tree_add_item(p2_tree, hf_led_green_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
354             proto_tree_add_item(p2_tree, hf_led_red_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
355             proto_tree_add_item(p2_tree, hf_led_initial_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
356             proto_tree_add_item(p2_tree, hf_led_initial_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
357             proto_tree_add_item(p2_tree, hf_led_final_green_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
358             proto_tree_add_item(p2_tree, hf_led_final_red_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
359
360             proto_tree_add_item(main_tree, hf_led_t1_duration, tvb, offset, 1, ENC_BIG_ENDIAN);
361             offset += 1;
362
363             proto_tree_add_item(main_tree, hf_led_t2_duration, tvb, offset, 1, ENC_BIG_ENDIAN);
364             offset += 1;
365
366             proto_tree_add_item(main_tree, hf_led_number_of_repetition, tvb, offset, 1, ENC_BIG_ENDIAN);
367             offset += 1;
368
369             proto_tree_add_item(main_tree, hf_led_link_to_buzzer, tvb, offset, 1, ENC_BIG_ENDIAN);
370             offset += 1;
371             break;
372         case  CMD_GET_DATA_UID:
373         case  CMD_GET_DATA_ATS:
374             /* Nothing to decode */
375             break;
376         case CMD_LOAD_AUTHENTICATION_KEYS:
377             p1_tree = proto_item_add_subtree(p1_item, ett_p1_item);
378             proto_tree_add_item(p1_tree, hf_key_structure, tvb, offset - 3, 1, ENC_BIG_ENDIAN);
379
380             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
381             proto_tree_add_item(p2_tree, hf_key_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
382
383             proto_tree_add_item(main_tree, hf_key, tvb, offset, 6, ENC_NA);
384             offset += 6;
385             break;
386         case CMD_AUTHENTICATION_OBSOLETE:
387             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
388             proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
389
390             proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN);
391             offset += 1;
392
393             proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN);
394             offset += 1;
395             break;
396         case CMD_AUTHENTICATION:
397             proto_tree_add_item(main_tree, hf_version, tvb, offset, 2, ENC_BIG_ENDIAN);
398             offset += 2;
399
400             proto_tree_add_item(main_tree, hf_block_number, tvb, offset, 1, ENC_BIG_ENDIAN);
401             offset += 1;
402
403             proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN);
404             offset += 1;
405
406             proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN);
407             offset += 1;
408             break;
409         case CMD_READ_BINARY_BLOCKS:
410             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
411             proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
412             break;
413         case CMD_UPDATE_BINARY_BLOCKS:
414             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
415             proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
416
417             proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA);
418             offset += length;
419             break;
420         case CMD_VALUE_BLOCK_OPERATION:
421             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
422             proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
423
424             proto_tree_add_item(main_tree, hf_vb_op, tvb, offset, 1, ENC_BIG_ENDIAN);
425             offset += 1;
426
427             proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN);
428             offset += 4;
429             break;
430         case CMD_READ_VALUE_BLOCK:
431             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
432             proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
433
434             break;
435         case CMD_RESTORE_VALUE_BLOCK:
436             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
437             proto_tree_add_item(p2_tree, hf_source_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
438
439             proto_tree_add_item(main_tree, hf_static_byte, tvb, offset, 1, ENC_BIG_ENDIAN);
440             offset += 1;
441
442             proto_tree_add_item(main_tree, hf_target_block_number, tvb, offset, 1, ENC_BIG_ENDIAN);
443             offset += 1;
444             break;
445         case CMD_SET_PICC_OPERATING_PARAMETER:
446             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
447             proto_tree_add_item(p2_tree, hf_picc_operating_auto_picc_polling, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
448             proto_tree_add_item(p2_tree, hf_picc_operating_auto_ats_generation, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
449             proto_tree_add_item(p2_tree, hf_picc_operating_polling_interval, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
450             proto_tree_add_item(p2_tree, hf_picc_operating_felica_424k, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
451             proto_tree_add_item(p2_tree, hf_picc_operating_felica_212k, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
452             proto_tree_add_item(p2_tree, hf_picc_operating_topaz, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
453             proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
454             proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
455             break;
456         case CMD_SET_TIMEOUT_PARAMETER:
457             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
458             proto_tree_add_item(p2_tree, hf_timeout, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
459             break;
460         case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION:
461             p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
462             proto_tree_add_item(p2_tree, hf_poll_buzzer_status, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
463             break;
464         case CMD_GET_PICC_OPERATING_PARAMETER:
465             /* No parameters */
466             break;
467         }
468
469         if (!pinfo->fd->flags.visited) {
470             command_data = wmem_new(wmem_file_scope(), command_data_t);
471             command_data->bus_id = bus_id;
472             command_data->device_address = device_address;
473             command_data->endpoint = endpoint;
474
475             command_data->command = command;
476             command_data->command_frame_number = pinfo->num;
477             command_data->response_frame_number = 0;
478
479             wmem_tree_insert32_array(command_info, key, command_data);
480         }
481
482     } else { /* Response */
483         guint32       command_frame_number = 0;
484         gboolean      use_status_word = FALSE;
485         wmem_tree_t  *wmem_tree;
486
487         key[3].length = 0;
488         key[3].key = NULL;
489
490         wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key);
491         if (wmem_tree) {
492             command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num);
493
494             if (command_data && (command_data->response_frame_number == 0 ||
495                     command_data->response_frame_number == pinfo->num)) {
496
497                 command = command_data->command;
498                 command_frame_number = command_data->command_frame_number;
499                 if (!pinfo->fd->flags.visited && command_data->response_frame_number == 0) {
500                     command_data->response_frame_number = pinfo->num;
501                 }
502             }
503         }
504
505         sub_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, tvb_captured_length_remaining(tvb, offset), command);
506         PROTO_ITEM_SET_GENERATED(sub_item);
507
508         col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s", val_to_str_ext_const(command, &command_vals_ext, "Unknown"));
509
510         if (command != CMD_UNKNOWN) {
511             sub_item = proto_tree_add_uint(main_tree, hf_response_for, tvb, offset, tvb_captured_length_remaining(tvb, offset), command_frame_number);
512             PROTO_ITEM_SET_GENERATED(sub_item);
513         }
514
515         switch (command) {
516         case CMD_GET_FIRMWARE_VERSION:
517             proto_tree_add_item(main_tree, hf_firmware_version, tvb, offset, -1, ENC_NA | ENC_ASCII);
518             offset += tvb_captured_length_remaining(tvb, offset);
519             break;
520
521         case CMD_DIRECT_TRANSMIT:
522             use_status_word = TRUE;
523
524             if (tvb_captured_length_remaining(tvb, offset) > 2) {
525                 next_tvb = tvb_new_subset_length(tvb, offset, tvb_captured_length_remaining(tvb, offset) - 2);
526                 call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info);
527                 offset += tvb_captured_length_remaining(tvb, offset) - 2;
528             }
529             break;
530
531
532         case CMD_READ_BINARY_BLOCKS:
533             use_status_word = TRUE;
534             proto_tree_add_item(main_tree, hf_data, tvb, offset, tvb_captured_length_remaining(tvb, offset) - 2, ENC_NA);
535             offset += tvb_captured_length_remaining(tvb, offset) - 2;
536             break;
537
538         case CMD_READ_VALUE_BLOCK:
539             use_status_word = TRUE;
540             proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN);
541             break;
542
543         case CMD_GET_DATA_UID:
544             use_status_word = TRUE;
545             proto_tree_add_item(main_tree, hf_uid, tvb, offset, tvb_captured_length_remaining(tvb, offset) - 2, ENC_NA);
546             offset += tvb_captured_length_remaining(tvb, offset) - 2;
547             break;
548
549         case CMD_GET_DATA_ATS:
550             use_status_word = TRUE;
551             proto_tree_add_item(main_tree, hf_ats, tvb, offset, tvb_captured_length_remaining(tvb, offset) - 2, ENC_NA);
552             offset += tvb_captured_length_remaining(tvb, offset) - 2;
553             break;
554
555         case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL:
556         case CMD_LOAD_AUTHENTICATION_KEYS:
557         case CMD_AUTHENTICATION:
558         case CMD_AUTHENTICATION_OBSOLETE:
559         case CMD_UPDATE_BINARY_BLOCKS:
560         case CMD_VALUE_BLOCK_OPERATION:
561         case CMD_RESTORE_VALUE_BLOCK:
562         case CMD_SET_TIMEOUT_PARAMETER:
563         case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION:
564         case CMD_SET_PICC_OPERATING_PARAMETER:
565         case CMD_GET_PICC_OPERATING_PARAMETER:
566         default:
567             use_status_word = TRUE;
568             break;
569         }
570
571         if (use_status_word) {
572             value = tvb_get_ntohs(tvb, offset);
573             col_append_fstr(pinfo->cinfo, COL_INFO, " - %s%s",  (((value & 0xFF00) != 0x9000) && (value & 0xFF00) != 0x6100) ? "Error: " : "", rval_to_str(value, status_word_rvals, "Unknown error"));
574
575             if ((value & 0xFF00) == 0x6100)
576                 col_append_fstr(pinfo->cinfo, COL_INFO, " - Length %u", value & 0x00FF);
577
578             sub_item = proto_tree_add_item(main_tree, hf_status_word, tvb, offset, 2, ENC_BIG_ENDIAN);
579             sub_tree = proto_item_add_subtree(sub_item, ett_status_word);
580             proto_tree_add_item(sub_tree, hf_status_word_sw1, tvb, offset, 1, ENC_BIG_ENDIAN);
581             offset += 1;
582             sw2_item = proto_tree_add_item(sub_tree, hf_status_word_sw2, tvb, offset, 1, ENC_BIG_ENDIAN);
583
584             if (command == CMD_BI_COLOR_AND_BUZZER_LED_CONTROL) {
585                 sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2);
586
587                 col_append_fstr(pinfo->cinfo, COL_INFO, " - Red LED: %s, Green LED: %s", (value & 0x02) ? "On" : "Off", (value & 0x01) ? "On" : "Off");
588
589                 proto_tree_add_item(sw2_tree, hf_status_word_led_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
590                 proto_tree_add_item(sw2_tree, hf_status_word_led_green, tvb, offset, 1, ENC_BIG_ENDIAN);
591                 proto_tree_add_item(sw2_tree, hf_status_word_led_red, tvb, offset, 1, ENC_BIG_ENDIAN);
592             } else if (command == CMD_SET_PICC_OPERATING_PARAMETER || command == CMD_GET_PICC_OPERATING_PARAMETER) {
593                 sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2);
594                 proto_tree_add_item(sw2_tree, hf_picc_operating_auto_picc_polling, tvb, offset, 1, ENC_BIG_ENDIAN);
595                 proto_tree_add_item(sw2_tree, hf_picc_operating_auto_ats_generation, tvb, offset, 1, ENC_BIG_ENDIAN);
596                 proto_tree_add_item(sw2_tree, hf_picc_operating_polling_interval, tvb, offset, 1, ENC_BIG_ENDIAN);
597                 proto_tree_add_item(sw2_tree, hf_picc_operating_felica_424k, tvb, offset, 1, ENC_BIG_ENDIAN);
598                 proto_tree_add_item(sw2_tree, hf_picc_operating_felica_212k, tvb, offset, 1, ENC_BIG_ENDIAN);
599                 proto_tree_add_item(sw2_tree, hf_picc_operating_topaz, tvb, offset, 1, ENC_BIG_ENDIAN);
600                 proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
601                 proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
602             }
603             offset += 1;
604         }
605     }
606
607     return offset;
608 }
609
610 void
611 proto_register_acr122(void)
612 {
613     module_t         *module;
614     expert_module_t  *expert_module;
615
616     static hf_register_info hf[] = {
617         { &hf_class,
618             { "Class",                           "acr122.class",
619             FT_UINT8, BASE_HEX, NULL, 0x00,
620             NULL, HFILL }
621         },
622         { &hf_ins,
623             { "Ins",                             "acr122.ins",
624             FT_UINT8, BASE_HEX, NULL, 0x00,
625             NULL, HFILL }
626         },
627         { &hf_p1,
628             { "P1",                              "acr122.p1",
629             FT_UINT8, BASE_HEX, NULL, 0x00,
630             NULL, HFILL }
631         },
632         { &hf_p2,
633             { "P2",                              "acr122.p2",
634             FT_UINT8, BASE_HEX, NULL, 0x00,
635             NULL, HFILL }
636         },
637         { &hf_length,
638             { "Length",                          "acr122.length",
639             FT_UINT8, BASE_HEX, NULL, 0x00,
640             NULL, HFILL }
641         },
642         { &hf_status_word,
643             { "Status Word",                     "acr122.status_word",
644             FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(status_word_rvals), 0x00,
645             NULL, HFILL }
646         },
647         { &hf_status_word_sw1,
648             { "SW1",                             "acr122.status_word.sw1",
649             FT_UINT8, BASE_HEX, NULL, 0x00,
650             NULL, HFILL }
651         },
652         { &hf_status_word_sw2,
653             { "SW2",                             "acr122.status_word.sw2",
654             FT_UINT8, BASE_HEX, NULL, 0x00,
655             NULL, HFILL }
656         },
657         { &hf_command,
658             { "Command",                         "acr122.command",
659             FT_UINT8, BASE_HEX | BASE_EXT_STRING, &command_vals_ext, 0x00,
660             NULL, HFILL }
661         },
662         { &hf_response,
663             { "Response",                         "acr122.response",
664             FT_UINT8, BASE_HEX | BASE_EXT_STRING, &command_vals_ext, 0x00,
665             NULL, HFILL }
666         },
667         { &hf_response_for,
668             { "Response for",                    "acr122.response_for",
669             FT_FRAMENUM, BASE_NONE, NULL, 0x00,
670             NULL, HFILL }
671         },
672         { &hf_picc_operating_auto_picc_polling,
673             { "Auto PICC Polling",               "acr122.picc_operating.auto_picc_polling",
674             FT_BOOLEAN, 8, NULL, 0x80,
675             NULL, HFILL }
676         },
677         { &hf_picc_operating_auto_ats_generation,
678             { "ATS Generation",                  "acr122.picc_operating.ats_generation",
679             FT_BOOLEAN, 8, NULL, 0x40,
680             NULL, HFILL }
681         },
682         { &hf_picc_operating_polling_interval,
683             { "Polling Interval",                "acr122.picc_operating.polling_interval",
684             FT_BOOLEAN, 8, NULL, 0x20,
685             NULL, HFILL }
686         },
687         { &hf_picc_operating_felica_424k,
688             { "FeliCa 424k",                     "acr122.picc_operating.felica_424k",
689             FT_BOOLEAN, 8, NULL, 0x10,
690             NULL, HFILL }
691         },
692         { &hf_picc_operating_felica_212k,
693             { "FeliCa 212k",                     "acr122.picc_operating.felica_212k",
694             FT_BOOLEAN, 8, NULL, 0x08,
695             NULL, HFILL }
696         },
697         { &hf_picc_operating_topaz,
698             { "Topaz",                           "acr122.picc_operating.topaz",
699             FT_BOOLEAN, 8, NULL, 0x04,
700             NULL, HFILL }
701         },
702         { &hf_picc_operating_iso_14443_type_b,
703             { "ISO 14443 Type B",                "acr122.picc_operating.iso_14443_type_b",
704             FT_BOOLEAN, 8, NULL, 0x02,
705             NULL, HFILL }
706         },
707         { &hf_picc_operating_iso_14443_type_a,
708             { "ISO 14443 Type A",                "acr122.picc_operating.iso_14443_type_a",
709             FT_BOOLEAN, 8, NULL, 0x01,
710             NULL, HFILL }
711         },
712         { &hf_firmware_version,
713             { "Firmware Version",                "acr122.firmware_version",
714             FT_STRING, BASE_NONE, NULL, 0x00,
715             NULL, HFILL }
716         },
717         { &hf_led_green_blinking_state,
718             { "Green LED Blinking",              "acr122.led.green.blinking",
719             FT_BOOLEAN, 8, NULL, 0x80,
720             NULL, HFILL }
721         },
722         { &hf_led_red_blinking_state,
723             { "Red LED Blinking",                "acr122.led.red.blinking",
724             FT_BOOLEAN, 8, NULL, 0x40,
725             NULL, HFILL }
726         },
727         { &hf_led_green_mask,
728             { "Green LED Mask",                  "acr122.led.green.mask",
729             FT_BOOLEAN, 8, NULL, 0x20,
730             NULL, HFILL }
731         },
732         { &hf_led_red_mask,
733             { "Red LED Mask",                    "acr122.led.red.mask",
734             FT_BOOLEAN, 8, NULL, 0x10,
735             NULL, HFILL }
736         },
737         { &hf_led_initial_green_blinking_state,
738             { "Initial Green LED Blinking",      "acr122.led.green.initial",
739             FT_BOOLEAN, 8, NULL, 0x08,
740             NULL, HFILL }
741         },
742         { &hf_led_initial_red_blinking_state,
743             { "Initial Red LED Blinking",        "acr122.led.red.initial",
744             FT_BOOLEAN, 8, NULL, 0x04,
745             NULL, HFILL }
746         },
747         { &hf_led_final_green_state,
748             { "Final Green LED",                 "acr122.led.green.final",
749             FT_BOOLEAN, 8, NULL, 0x02,
750             NULL, HFILL }
751         },
752         { &hf_led_final_red_state,
753             { "Final Red LED",                   "acr122.led.red.final",
754             FT_BOOLEAN, 8, NULL, 0x01,
755             NULL, HFILL }
756         },
757         { &hf_led_t1_duration,
758             { "T1 Duration",                     "acr122.led.t1_duration",
759             FT_UINT8, BASE_CUSTOM, CF_FUNC(duration_base), 0x00,
760             "Initial Blinking State", HFILL }
761         },
762         { &hf_led_t2_duration,
763             { "T2 Duration",                     "acr122.led.t2_duration",
764             FT_UINT8, BASE_CUSTOM, CF_FUNC(duration_base), 0x00,
765             "Toggle Blinking State", HFILL }
766         },
767         { &hf_led_number_of_repetition,
768             { "Number of Repetition",            "acr122.led.number_of_repetition",
769             FT_UINT8, BASE_DEC, NULL, 0x00,
770             NULL, HFILL }
771         },
772         { &hf_led_link_to_buzzer,
773             { "Link to Buzzer",                  "acr122.led.link_to_buzzer",
774             FT_UINT8, BASE_HEX, VALS(link_to_buzzer_vals), 0x00,
775             NULL, HFILL }
776         },
777         { &hf_poll_buzzer_status,
778             { "Poll Buzzer Status",              "acr122.poll_buzzer_status",
779             FT_UINT8, BASE_HEX, VALS(poll_buzzer_status_vals), 0x00,
780             NULL, HFILL }
781         },
782         { &hf_timeout,
783             { "Timeout",                         "acr122.timeout",
784             FT_UINT8, BASE_CUSTOM, CF_FUNC(timeout_base), 0x00,
785             NULL, HFILL }
786         },
787         { &hf_status_word_led_reserved,
788             { "Reserved",                        "acr122.status_word.sw2.reserved",
789             FT_UINT8, BASE_HEX, NULL, 0xFC,
790             NULL, HFILL }
791         },
792         { &hf_status_word_led_green,
793             { "Current Green LED",               "acr122.status_word.sw2.led.green",
794             FT_BOOLEAN, 8, NULL, 0x02,
795             NULL, HFILL }
796         },
797         { &hf_status_word_led_red,
798             { "Current Red LED",                 "acr122.status_word.sw2.led.red",
799             FT_BOOLEAN, 8, NULL, 0x01,
800             NULL, HFILL }
801         },
802         { &hf_key,
803             { "Key",                             "acr122.key",
804             FT_BYTES, BASE_NONE, NULL, 0x00,
805             NULL, HFILL }
806         },
807         { &hf_key_structure,
808             { "Key Structure",                   "acr122.key_structure",
809             FT_UINT8, BASE_HEX, VALS(key_structure_vals), 0x00,
810             NULL, HFILL }
811         },
812         { &hf_key_number,
813             { "Key Number",                      "acr122.key_number",
814             FT_UINT8, BASE_DEC, NULL, 0x00,
815             NULL, HFILL }
816         },
817         { &hf_key_type,
818             { "Key Type",                        "acr122.key_type",
819             FT_UINT8, BASE_HEX, VALS(key_type_vals), 0x00,
820             NULL, HFILL }
821         },
822         { &hf_block_number,
823             { "Block Number",                    "acr122.block_number",
824             FT_UINT8, BASE_DEC_HEX, NULL, 0x00,
825             NULL, HFILL }
826         },
827         { &hf_source_block_number,
828             { "Source Block Number",             "acr122.source_block_number",
829             FT_UINT8, BASE_DEC_HEX, NULL, 0x00,
830             NULL, HFILL }
831         },
832         { &hf_target_block_number,
833             { "Target Block Number",             "acr122.target_block_number",
834             FT_UINT8, BASE_DEC_HEX, NULL, 0x00,
835             NULL, HFILL }
836         },
837         { &hf_static_byte,
838             { "Static Byte",                     "acr122.static_byte",
839             FT_UINT8, BASE_HEX, NULL, 0x00,
840             NULL, HFILL }
841         },
842         { &hf_vb_op,
843             { "VB Op",                           "acr122.vb_op",
844             FT_UINT8, BASE_HEX, VALS(vb_op_vals), 0x00,
845             NULL, HFILL }
846         },
847         { &hf_version,
848             { "Version",                         "acr122.version",
849             FT_UINT16, BASE_HEX, NULL, 0x00,
850             NULL, HFILL }
851         },
852         { &hf_value,
853             { "Value",                           "acr122.value",
854             FT_INT32, BASE_DEC, NULL, 0x00,
855             NULL, HFILL }
856         },
857         { &hf_uid,
858             { "UID",                             "acr122.uid",
859             FT_BYTES, BASE_NONE, NULL, 0x00,
860             NULL, HFILL }
861         },
862         { &hf_ats,
863             { "ATS",                             "acr122.ats",
864             FT_BYTES, BASE_NONE, NULL, 0x00,
865             NULL, HFILL }
866         },
867         { &hf_data,
868             { "Data",                            "acr122.data",
869             FT_BYTES, BASE_NONE, NULL, 0x00,
870             NULL, HFILL }
871         },
872     };
873
874     static gint *ett[] = {
875         &ett_acr122,
876         &ett_p1_item,
877         &ett_p2_item,
878         &ett_status_word,
879         &ett_status_word_sw2
880     };
881
882     static ei_register_info ei[] = {
883         { &ei_unknown_command_or_invalid_parameters, { "acr122.expert.unknown_command", PI_PROTOCOL, PI_NOTE, "Unknown command or invalid parameters", EXPFILL }},
884     };
885
886     command_info = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
887
888     proto_acr122 = proto_register_protocol("Advanced Card Systems ACR122", "ACR 122", "acr122");
889     acr122_handle = register_dissector("acr122", dissect_acr122, proto_acr122);
890
891     proto_register_field_array(proto_acr122, hf, array_length(hf));
892     proto_register_subtree_array(ett, array_length(ett));
893     expert_module = expert_register_protocol(proto_acr122);
894     expert_register_field_array(expert_module, ei, array_length(ei));
895
896     module = prefs_register_protocol(proto_acr122, NULL);
897     prefs_register_static_text_preference(module, "version",
898             "ACR122U USB NFC Reader - Application Programming Interface V2.02",
899             "Version of protocol supported by this dissector.");
900 }
901
902 void
903 proto_reg_handoff_acr122(void)
904 {
905     pn532_handle = find_dissector_add_dependency("pn532", proto_acr122);
906     dissector_add_for_decode_as("usbccid.subdissector", acr122_handle);
907 }
908
909 /*
910  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
911  *
912  * Local variables:
913  * c-basic-offset: 4
914  * tab-width: 8
915  * indent-tabs-mode: nil
916  * End:
917  *
918  * vi: set shiftwidth=4 tabstop=8 expandtab:
919  * :indentSize=4:tabSize=8:noTabs=true:
920  */