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