1 /* packet-zvt.c
2  * Routines for ZVT dissection
3  * Copyright 2014-2015, Martin Kaiser <martin@kaiser.cx>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 /* ZVT is a manufacturer-independent protocol between payment terminals and
13  * electronic cash-register systems / vending machines
14  *
15  * the specifications are available from https://www.terminalhersteller.de
16  *
17  * ZVT defines a "serial transport protocol" and a "TCP/IP transport
18  * protocol"
19  *
20  * ZVT can sit on top of USB, either the serial or the TCP/IP protocol
21  * can be used in this case - this is not supported for now
22  *
23  * a dump of ZVT data can be converted to pcap, using a user-defined DLT
24  * we register the dissector by name and try to auto-detect the serial
25  * or TCP/IP protocol
26  *
27  * finally, ZVT can run on top of TCP, the default port is 20007, only
28  * the TCP/IP protocol can be used here
29  */
30 
31 
32 #include "config.h"
33 
34 #include <epan/packet.h>
35 #include <epan/addr_resolv.h>
36 #include <epan/expert.h>
37 #include "packet-tcp.h"
38 
39 /* special characters of the serial transport protocol */
40 #define STX 0x02
41 #define ETX 0x03
42 #define ACK 0x06
43 #define DLE 0x10
44 #define NAK 0x15
45 
46 /* an APDU needs at least a 2-byte control-field and one byte length */
47 #define ZVT_APDU_MIN_LEN 3
48 
49 
50 static GHashTable *apdu_table = NULL, *bitmap_table = NULL, *tlv_table = NULL;
51 
52 static wmem_tree_t *transactions = NULL;
53 
54 typedef struct _zvt_transaction_t {
55     guint32 rqst_frame;
56     guint32 resp_frame;
57     guint16 ctrl;
58 } zvt_transaction_t;
59 
60 typedef enum _zvt_direction_t {
61     DIRECTION_UNKNOWN,
62     DIRECTION_ECR_TO_PT,
63     DIRECTION_PT_TO_ECR
64 } zvt_direction_t;
65 
66 /* source/destination address field */
67 #define ADDR_ECR "ECR"
68 #define ADDR_PT  "PT"
69 
70 #define CCRC_POS 0x80
71 #define CCRC_NEG 0x84
72 
73 /* "don't care" value for min_len_field */
74 #define LEN_FIELD_ANY G_MAXUINT32
75 
76 typedef struct _apdu_info_t {
77     guint16          ctrl;
78     guint32          min_len_field;
79     zvt_direction_t  direction;
80     void (*dissect_payload)(tvbuff_t *, gint, guint16,
81             packet_info *, proto_tree *, zvt_transaction_t *);
82 } apdu_info_t;
83 
84 /* control code 0 is not defined in the specification */
85 #define ZVT_CTRL_NONE      0x0000
86 
87 #define CTRL_STATUS        0x040F
88 #define CTRL_INT_STATUS    0x04FF
89 #define CTRL_REGISTRATION  0x0600
90 #define CTRL_AUTHORISATION 0x0601
91 #define CTRL_COMPLETION    0x060F
92 #define CTRL_ABORT         0x061E
93 #define CTRL_REVERSAL      0x0630
94 #define CTRL_REFUND        0x0631
95 #define CTRL_END_OF_DAY    0x0650
96 #define CTRL_DIAG          0x0670
97 #define CTRL_INIT          0x0693
98 #define CTRL_PRINT_LINE    0x06D1
99 #define CTRL_PRINT_TEXT    0x06D3
100 
101 static void dissect_zvt_int_status(tvbuff_t *tvb, gint offset, guint16 len,
102         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans);
103 static void dissect_zvt_reg(tvbuff_t *tvb, gint offset, guint16 len,
104         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans);
105 static void dissect_zvt_bitmap_seq(tvbuff_t *tvb, gint offset, guint16 len,
106         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans);
107 static void dissect_zvt_init(tvbuff_t *tvb, gint offset, guint16 len,
108         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans);
109 static void dissect_zvt_pass_bitmap_seq(tvbuff_t *tvb, gint offset, guint16 len,
110         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans);
111 static void dissect_zvt_abort(tvbuff_t *tvb, gint offset, guint16 len,
112         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans);
113 
114 static const apdu_info_t apdu_info[] = {
115     { CTRL_STATUS,        0, DIRECTION_PT_TO_ECR, dissect_zvt_bitmap_seq },
116     { CTRL_INT_STATUS,    0, DIRECTION_PT_TO_ECR, dissect_zvt_int_status },
117     { CTRL_REGISTRATION,  4, DIRECTION_ECR_TO_PT, dissect_zvt_reg },
118     /* authorisation has at least a 0x04 tag and 6 bytes for the amount */
119     { CTRL_AUTHORISATION, 7, DIRECTION_ECR_TO_PT, dissect_zvt_bitmap_seq },
120     { CTRL_COMPLETION,    0, DIRECTION_PT_TO_ECR, dissect_zvt_bitmap_seq },
121     { CTRL_ABORT,         0, DIRECTION_PT_TO_ECR, dissect_zvt_abort },
122     { CTRL_REVERSAL,      0, DIRECTION_ECR_TO_PT, dissect_zvt_pass_bitmap_seq },
123     { CTRL_REFUND,        0, DIRECTION_ECR_TO_PT, dissect_zvt_pass_bitmap_seq },
124     { CTRL_END_OF_DAY,    0, DIRECTION_ECR_TO_PT, NULL },
125     { CTRL_DIAG,          0, DIRECTION_ECR_TO_PT, NULL },
126     { CTRL_INIT,          0, DIRECTION_ECR_TO_PT, dissect_zvt_init },
127     { CTRL_PRINT_LINE,    0, DIRECTION_PT_TO_ECR, NULL },
128     { CTRL_PRINT_TEXT,    0, DIRECTION_PT_TO_ECR, dissect_zvt_bitmap_seq }
129 };
130 
131 
132 typedef struct _bitmap_info_t {
133     guint8   bmp;
134     guint16  payload_len;
135     gint (*dissect_payload)(tvbuff_t *, gint, packet_info *, proto_tree *);
136 } bitmap_info_t;
137 
138 #define BMP_TIMEOUT       0x01
139 #define BMP_MAX_STAT_INFO 0x02
140 #define BMP_SVC_BYTE      0x03
141 #define BMP_AMOUNT        0x04
142 #define BMP_PUMP_NR       0x05
143 #define BMP_TLV_CONTAINER 0x06
144 #define BMP_TRACE_NUM     0x0B
145 #define BMP_TIME          0x0C
146 #define BMP_DATE          0x0D
147 #define BMP_EXP_DATE      0x0E
148 #define BMP_CARD_SEQ_NUM  0x17
149 #define BMP_PAYMENT_TYPE  0x19
150 #define BMP_CARD_NUM      0x22
151 #define BMP_T2_DAT        0x23
152 #define BMP_T3_DAT        0x24
153 #define BMP_RES_CODE      0x27
154 #define BMP_TID           0x29
155 #define BMP_VU_NUMBER     0x2A
156 #define BMP_T1_DAT        0x2D
157 #define BMP_CVV_CVC       0x3A
158 #define BMP_AID           0x3B
159 #define BMP_ADD_DATA      0x3C
160 #define BMP_CC            0x49
161 #define BMP_RCPT_NUM      0x87
162 #define BMP_CARD_TYPE     0x8A
163 #define BMP_CARD_NAME     0x8B
164 
165 #define BMP_PLD_LEN_UNKNOWN 0  /* unknown/variable bitmap payload len */
166 
167 static gint dissect_zvt_amount(
168         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
169 static gint dissect_zvt_tlv_container(
170         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
171 static inline gint dissect_zvt_res_code(
172         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
173 static inline gint dissect_zvt_cc(
174         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
175 static inline gint dissect_zvt_terminal_id(
176         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
177 static inline gint dissect_zvt_time(
178         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
179 static inline gint dissect_zvt_date(
180         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
181 static inline gint dissect_zvt_card_type(
182         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
183 static inline gint dissect_zvt_trace_number(
184         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
185 static inline gint dissect_zvt_expiry_date(
186         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
187 static inline gint dissect_zvt_card_number(
188         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
189 static inline gint dissect_zvt_card_name(
190         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
191 static inline gint dissect_zvt_additional_data(
192         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
193 
194 static const bitmap_info_t bitmap_info[] = {
195     { BMP_TIMEOUT,                         1, NULL },
196     { BMP_MAX_STAT_INFO,                   1, NULL },
197     { BMP_SVC_BYTE,                        1, NULL },
198     { BMP_AMOUNT,                          6, dissect_zvt_amount },
199     { BMP_PUMP_NR,                         1, NULL },
200     { BMP_TLV_CONTAINER, BMP_PLD_LEN_UNKNOWN, dissect_zvt_tlv_container },
201     { BMP_TRACE_NUM,                       3, dissect_zvt_trace_number },
202     { BMP_TIME,                            3, dissect_zvt_time },
203     { BMP_DATE,                            2, dissect_zvt_date },
204     { BMP_EXP_DATE,                        2, dissect_zvt_expiry_date },
205     { BMP_CARD_SEQ_NUM,                    2, NULL },
206     { BMP_PAYMENT_TYPE,                    1, NULL },
207     { BMP_CARD_NUM,      BMP_PLD_LEN_UNKNOWN, dissect_zvt_card_number },
208     { BMP_T2_DAT,        BMP_PLD_LEN_UNKNOWN, NULL },
209     { BMP_T3_DAT,        BMP_PLD_LEN_UNKNOWN, NULL },
210     { BMP_RES_CODE,                        1, dissect_zvt_res_code },
211     { BMP_TID,                             4, dissect_zvt_terminal_id },
212     { BMP_VU_NUMBER,                      15, NULL },
213     { BMP_T1_DAT,        BMP_PLD_LEN_UNKNOWN, NULL },
214     { BMP_CVV_CVC,                         2, NULL },
215     { BMP_AID,                             8, NULL },
216     { BMP_ADD_DATA,      BMP_PLD_LEN_UNKNOWN, dissect_zvt_additional_data },
217     { BMP_CC,                              2, dissect_zvt_cc },
218     { BMP_RCPT_NUM,                        2, NULL },
219     { BMP_CARD_TYPE,                       1, dissect_zvt_card_type },
220     { BMP_CARD_NAME,     BMP_PLD_LEN_UNKNOWN, dissect_zvt_card_name }
221 };
222 
223 
224 void proto_register_zvt(void);
225 void proto_reg_handoff_zvt(void);
226 
227 static int proto_zvt = -1;
228 
229 static int ett_zvt = -1;
230 static int ett_zvt_apdu = -1;
231 static int ett_zvt_bitmap = -1;
232 static int ett_zvt_tlv_dat_obj = -1;
233 static int ett_zvt_tlv_subseq = -1;
234 static int ett_zvt_tlv_tag = -1;
235 
236 static int hf_zvt_resp_in = -1;
237 static int hf_zvt_resp_to = -1;
238 static int hf_zvt_serial_char = -1;
239 static int hf_zvt_crc = -1;
240 static int hf_zvt_ctrl = -1;
241 static int hf_zvt_ccrc = -1;
242 static int hf_zvt_aprc = -1;
243 static int hf_zvt_len = -1;
244 static int hf_zvt_data = -1;
245 static int hf_zvt_int_status = -1;
246 static int hf_zvt_pwd = -1;
247 static int hf_zvt_reg_cfg = -1;
248 static int hf_zvt_res_code = -1;
249 static int hf_zvt_cc = -1;
250 static int hf_zvt_amount = -1;
251 static int hf_zvt_terminal_id = -1;
252 static int hf_zvt_time = -1;
253 static int hf_zvt_date = -1;
254 static int hf_zvt_card_type = -1;
255 static int hf_zvt_bmp = -1;
256 static int hf_zvt_tlv_total_len = -1;
257 static int hf_zvt_tlv_tag = -1;
258 static int hf_zvt_tlv_tag_class = -1;
259 static int hf_zvt_tlv_tag_type = -1;
260 static int hf_zvt_tlv_len = -1;
261 static int hf_zvt_text_lines_line = -1;
262 static int hf_zvt_permitted_cmd = -1;
263 static int hf_zvt_receipt_type = -1;
264 static int hf_zvt_receipt_parameter_positive_customer = -1;
265 static int hf_zvt_receipt_parameter_negative_customer = -1;
266 static int hf_zvt_receipt_parameter_positive_merchant = -1;
267 static int hf_zvt_receipt_parameter_negative_merchant = -1;
268 static int hf_zvt_receipt_parameter_customer_before_merchant = -1;
269 static int hf_zvt_receipt_parameter_print_short_receipt = -1;
270 static int hf_zvt_receipt_parameter_no_product_data = -1;
271 static int hf_zvt_receipt_parameter_ecr_as_printer = -1;
272 static int hf_zvt_receipt_parameter = -1;
273 static int hf_zvt_trace_number = -1;
274 static int hf_zvt_expiry_date = -1;
275 static int hf_zvt_card_number = -1;
276 static int hf_zvt_card_name = -1;
277 static int hf_zvt_additional_data = -1;
278 static int hf_zvt_characters_per_line = -1;
279 
280 static int * const receipt_parameter_flag_fields[] = {
281     &hf_zvt_receipt_parameter_positive_customer,
282     &hf_zvt_receipt_parameter_negative_customer,
283     &hf_zvt_receipt_parameter_positive_merchant,
284     &hf_zvt_receipt_parameter_negative_merchant,
285     &hf_zvt_receipt_parameter_customer_before_merchant,
286     &hf_zvt_receipt_parameter_print_short_receipt,
287     &hf_zvt_receipt_parameter_no_product_data,
288     &hf_zvt_receipt_parameter_ecr_as_printer,
289     NULL
290 };
291 
292 static expert_field ei_invalid_apdu_len = EI_INIT;
293 
294 static const value_string serial_char[] = {
295     { STX, "Start of text (STX)" },
296     { ETX, "End of text (ETX)" },
297     { ACK, "Acknowledged (ACK)" },
298     { DLE, "Data line escape (DLE)" },
299     { NAK, "Not acknowledged (NAK)" },
300     { 0, NULL }
301 };
302 static value_string_ext serial_char_ext = VALUE_STRING_EXT_INIT(serial_char);
303 
304 
305 static const value_string ctrl_field[] = {
306     { CTRL_STATUS, "Status Information" },
307     { CTRL_INT_STATUS, "Intermediate Status Information" },
308     { CTRL_REGISTRATION, "Registration" },
309     { CTRL_AUTHORISATION, "Authorisation" },
310     { CTRL_COMPLETION, "Completion" },
311     { CTRL_ABORT, "Abort" },
312     { CTRL_REVERSAL, "Reversal" },
313     { CTRL_REFUND, "Refund" },
314     { CTRL_END_OF_DAY, "End Of Day" },
315     { CTRL_DIAG, "Diagnosis" },
316     { CTRL_INIT, "Initialisation" },
317     { CTRL_PRINT_LINE, "Print Line" },
318     { CTRL_PRINT_TEXT, "Print Text Block" },
319     { 0, NULL }
320 };
321 static value_string_ext ctrl_field_ext = VALUE_STRING_EXT_INIT(ctrl_field);
322 
323 /* ISO 4217 currency codes */
324 static const value_string zvt_cc[] = {
325     { 0x0978, "EUR" },
326     { 0, NULL }
327 };
328 
329 static const value_string receipt_type[] = {
330     { 0x01, "Transaction receipt (merchant)" },
331     { 0x02, "Transaction receipt (customer)" },
332     { 0x03, "Administration receipt" },
333     { 0, NULL }
334 };
335 
336 static const value_string card_type[] = {
337     {  2, "ec-card" },
338     {  5, "girocard" },
339     {  6, "Mastercard" },
340     { 10, "VISA" },
341     {  0, NULL }
342 };
343 static value_string_ext card_type_ext = VALUE_STRING_EXT_INIT(card_type);
344 
345 static const value_string bitmap[] = {
346     { BMP_TIMEOUT,       "Timeout" },
347     { BMP_MAX_STAT_INFO, "max. status info" },
348     { BMP_SVC_BYTE,      "Service byte" },
349     { BMP_AMOUNT,        "Amount" },
350     { BMP_PUMP_NR,       "Pump number" },
351     { BMP_TLV_CONTAINER, "TLV container" },
352     { BMP_TRACE_NUM,     "Trace number" },
353     { BMP_TIME,          "Time" },
354     { BMP_DATE,          "Date" },
355     { BMP_EXP_DATE,      "Expiry date" },
356     { BMP_CARD_SEQ_NUM,  "Card sequence number" },
357     { BMP_PAYMENT_TYPE,  "Payment type" },
358     { BMP_CARD_NUM,      "Card number" },
359     { BMP_T2_DAT,        "Track 2 data" },
360     { BMP_T3_DAT,        "Track 3 data" },
361     { BMP_RES_CODE,      "Result code" },
362     { BMP_TID,           "Terminal ID" },
363     { BMP_VU_NUMBER,     "Contract number"},
364     { BMP_T1_DAT,        "Track 1 data" },
365     { BMP_CVV_CVC,       "CVV / CVC" },
366     { BMP_AID,           "Authorization attribute" },
367     { BMP_ADD_DATA,      "Additional data" },
368     { BMP_CC,            "Currency code (CC)" },
369     { BMP_RCPT_NUM,      "Receipt number" },
370     { BMP_CARD_TYPE,     "Card type" },
371     { BMP_CARD_NAME,     "Card name" },
372     { 0, NULL }
373 };
374 static value_string_ext bitmap_ext = VALUE_STRING_EXT_INIT(bitmap);
375 
376 static const value_string tlv_tag_class[] = {
377     { 0x00, "Universal" },
378     { 0x01, "Application" },
379     { 0x02, "Context-specific" },
380     { 0x03, "Private" },
381     { 0, NULL }
382 };
383 static value_string_ext tlv_tag_class_ext = VALUE_STRING_EXT_INIT(tlv_tag_class);
384 
385 #define TLV_TAG_TEXT_LINES          0x07
386 #define TLV_TAG_ATTRIBUTE           0x09
387 #define TLV_TAG_PERMITTED_ZVT_CMD   0x0A
388 #define TLV_TAG_CHARS_PER_LINE      0x12
389 #define TLV_TAG_DISPLAY_TEXTS       0x24
390 #define TLV_TAG_PRINT_TEXTS         0x25
391 #define TLV_TAG_PERMITTED_ZVT_CMDS  0x26
392 #define TLV_TAG_SUPPORTED_CHARSETS  0x27
393 #define TLV_TAG_PAYMENT_TYPE        0x2F
394 #define TLV_TAG_EMV_CFG_PARAM       0x40
395 #define TLV_TAG_CARD_TYPE_ID        0x41
396 #define TLV_TAG_RECEIPT_PARAMETER   0x45
397 #define TLV_TAG_APPLICATION         0x60
398 #define TLV_TAG_RECEIPT_PARAM       0x1F04
399 #define TLV_TAG_RECEIPT_TYPE        0x1F07
400 #define TLV_TAG_CARDHOLDER_AUTH     0x1F10
401 #define TLV_TAG_ONLINE_FLAG         0x1F11
402 #define TLV_TAG_CARD_TYPE           0x1F12
403 
404 
405 typedef struct _tlv_seq_info_t {
406     guint txt_enc;
407 } tlv_seq_info_t;
408 
409 
410 static gint
411 dissect_zvt_tlv_seq(tvbuff_t *tvb, gint offset, guint16 seq_max_len,
412         packet_info *pinfo _U_, proto_tree *tree, tlv_seq_info_t *seq_info);
413 
414 typedef struct _tlv_info_t {
415     guint32 tag;
416     gint (*dissect_payload)(tvbuff_t *, gint, gint,
417             packet_info *, proto_tree *, tlv_seq_info_t *);
418 } tlv_info_t;
419 
420 static inline gint dissect_zvt_tlv_text_lines(
421         tvbuff_t *tvb, gint offset, gint len,
422         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info);
423 
424 static inline gint dissect_zvt_tlv_subseq(
425         tvbuff_t *tvb, gint offset, gint len,
426         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info);
427 
428 static inline gint dissect_zvt_tlv_permitted_cmd(
429         tvbuff_t *tvb, gint offset, gint len,
430         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info);
431 
432 static inline gint dissect_zvt_tlv_receipt_type(
433         tvbuff_t *tvb, gint offset, gint len,
434         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info);
435 
436 static inline gint dissect_zvt_tlv_receipt_param(
437         tvbuff_t *tvb, gint offset, gint len,
438         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info);
439 
440 static inline gint dissect_zvt_tlv_characters_per_line(
441         tvbuff_t *tvb, gint offset, gint len,
442         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info);
443 
444 static const tlv_info_t tlv_info[] = {
445     { TLV_TAG_TEXT_LINES, dissect_zvt_tlv_text_lines },
446     { TLV_TAG_DISPLAY_TEXTS, dissect_zvt_tlv_subseq },
447     { TLV_TAG_PRINT_TEXTS, dissect_zvt_tlv_subseq },
448     { TLV_TAG_PAYMENT_TYPE, dissect_zvt_tlv_subseq },
449     { TLV_TAG_PERMITTED_ZVT_CMDS, dissect_zvt_tlv_subseq },
450     { TLV_TAG_PERMITTED_ZVT_CMD, dissect_zvt_tlv_permitted_cmd },
451     { TLV_TAG_RECEIPT_TYPE, dissect_zvt_tlv_receipt_type },
452     { TLV_TAG_RECEIPT_PARAM, dissect_zvt_tlv_receipt_param },
453     { TLV_TAG_CHARS_PER_LINE, dissect_zvt_tlv_characters_per_line }
454 };
455 
456 static const value_string tlv_tags[] = {
457     { TLV_TAG_TEXT_LINES,         "Text lines" },
458     { TLV_TAG_ATTRIBUTE,          "Attribute"},
459     { TLV_TAG_CHARS_PER_LINE,
460         "Number of characters per line of the printer" },
461     { TLV_TAG_DISPLAY_TEXTS,      "Display texts" },
462     { TLV_TAG_PRINT_TEXTS,        "Print texts" },
463     { TLV_TAG_PERMITTED_ZVT_CMDS, "List of permitted ZVT commands" },
464     { TLV_TAG_SUPPORTED_CHARSETS, "List of supported character sets" },
465     { TLV_TAG_PAYMENT_TYPE,       "Payment type" },
466     { TLV_TAG_EMV_CFG_PARAM,      "EMV config parameter" },
467     { TLV_TAG_CARD_TYPE_ID,       "Card type ID" },
468     { TLV_TAG_RECEIPT_PARAMETER,  "Receipt parameter (EMV)" },
469     { TLV_TAG_APPLICATION,        "Application" },
470     { TLV_TAG_RECEIPT_PARAM,      "Receipt parameter" },
471     { TLV_TAG_RECEIPT_TYPE,       "Receipt type" },
472     { TLV_TAG_CARDHOLDER_AUTH,    "Cardholder authentication" },
473     { TLV_TAG_ONLINE_FLAG,        "Online flag" },
474     { TLV_TAG_CARD_TYPE,          "Card type" },
475     { 0, NULL }
476 };
477 static value_string_ext tlv_tags_ext = VALUE_STRING_EXT_INIT(tlv_tags);
478 
dissect_zvt_tlv_text_lines(tvbuff_t * tvb,gint offset,gint len,packet_info * pinfo _U_,proto_tree * tree,tlv_seq_info_t * seq_info)479 static inline gint dissect_zvt_tlv_text_lines(
480         tvbuff_t *tvb, gint offset, gint len,
481         packet_info *pinfo _U_, proto_tree *tree, tlv_seq_info_t *seq_info)
482 {
483     proto_tree_add_item(tree, hf_zvt_text_lines_line,
484             tvb, offset, len, seq_info->txt_enc | ENC_NA);
485     return len;
486 }
487 
488 
dissect_zvt_tlv_subseq(tvbuff_t * tvb,gint offset,gint len,packet_info * pinfo,proto_tree * tree,tlv_seq_info_t * seq_info)489 static inline gint dissect_zvt_tlv_subseq(
490         tvbuff_t *tvb, gint offset, gint len,
491         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info)
492 {
493     proto_tree *subseq_tree;
494 
495     subseq_tree = proto_tree_add_subtree(tree,
496             tvb, offset, len, ett_zvt_tlv_subseq, NULL,
497             "Subsequence");
498 
499     return dissect_zvt_tlv_seq(tvb, offset, len, pinfo, subseq_tree, seq_info);
500 }
501 
502 
dissect_zvt_tlv_permitted_cmd(tvbuff_t * tvb,gint offset,gint len,packet_info * pinfo _U_,proto_tree * tree,tlv_seq_info_t * seq_info _U_)503 static inline gint dissect_zvt_tlv_permitted_cmd(
504         tvbuff_t *tvb, gint offset, gint len,
505         packet_info *pinfo _U_, proto_tree *tree, tlv_seq_info_t *seq_info _U_)
506 {
507     proto_tree_add_item(tree, hf_zvt_permitted_cmd,
508             tvb, offset, len, ENC_BIG_ENDIAN);
509     return len;
510 }
511 
512 
dissect_zvt_tlv_receipt_type(tvbuff_t * tvb,gint offset,gint len,packet_info * pinfo _U_,proto_tree * tree,tlv_seq_info_t * seq_info _U_)513 static inline gint dissect_zvt_tlv_receipt_type(
514         tvbuff_t *tvb, gint offset, gint len,
515         packet_info *pinfo _U_, proto_tree *tree, tlv_seq_info_t *seq_info _U_)
516 {
517     proto_tree_add_item(tree, hf_zvt_receipt_type,
518             tvb, offset, len, ENC_BIG_ENDIAN);
519     return len;
520 }
521 
522 
dissect_zvt_tlv_receipt_param(tvbuff_t * tvb,gint offset,gint len,packet_info * pinfo _U_,proto_tree * tree,tlv_seq_info_t * seq_info _U_)523 static inline gint dissect_zvt_tlv_receipt_param(
524         tvbuff_t *tvb, gint offset, gint len,
525         packet_info *pinfo _U_, proto_tree *tree, tlv_seq_info_t *seq_info _U_)
526 {
527     proto_tree_add_bitmask(tree, tvb, offset, hf_zvt_receipt_parameter, ett_zvt_tlv_tag, receipt_parameter_flag_fields, ENC_BIG_ENDIAN);
528     return len;
529 }
530 
531 
dissect_zvt_tlv_characters_per_line(tvbuff_t * tvb,gint offset,gint len,packet_info * pinfo _U_,proto_tree * tree,tlv_seq_info_t * seq_info _U_)532 static inline gint dissect_zvt_tlv_characters_per_line(
533         tvbuff_t *tvb, gint offset, gint len,
534         packet_info *pinfo _U_, proto_tree *tree, tlv_seq_info_t *seq_info _U_)
535 {
536     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 1, NULL, FALSE);
537     proto_tree_add_string(tree, hf_zvt_characters_per_line, tvb, offset, 1, str);
538     return len;
539 }
540 
541 
542 static gint
dissect_zvt_tlv_tag(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint32 * tag)543 dissect_zvt_tlv_tag(tvbuff_t *tvb, gint offset,
544         packet_info *pinfo _U_, proto_tree *tree, guint32 *tag)
545 {
546     gint offset_start;
547     guint8 one_byte;
548     guint32 _tag;
549     proto_item *tag_ti;
550     proto_tree *tag_tree;
551 
552     offset_start = offset;
553 
554     one_byte = tvb_get_guint8(tvb, offset);
555     _tag = one_byte;
556     offset++;
557     if ((one_byte & 0x1F) == 0x1F) {
558         do {
559             if ((offset-offset_start)>4) {
560                 /* we support tags of <= 4 bytes
561                    (the specification defines only 1 and 2-byte tags) */
562                 return -1;
563             }
564             one_byte = tvb_get_guint8(tvb, offset);
565             _tag = _tag << 8 | (one_byte&0x7F);
566             offset++;
567         } while (one_byte & 0x80);
568     }
569 
570     tag_ti = proto_tree_add_uint_format(tree, hf_zvt_tlv_tag,
571             tvb, offset_start, offset-offset_start, _tag,
572             "Tag: %s (0x%x)",
573             val_to_str_ext(_tag, &tlv_tags_ext, "unknown"), _tag);
574 
575     tag_tree = proto_item_add_subtree(tag_ti, ett_zvt_tlv_tag);
576     proto_tree_add_item(tag_tree, hf_zvt_tlv_tag_class,
577             tvb, offset_start, 1, ENC_BIG_ENDIAN);
578     proto_tree_add_item(tag_tree, hf_zvt_tlv_tag_type,
579             tvb, offset_start, 1, ENC_BIG_ENDIAN);
580 
581     if (tag)
582         *tag = _tag;
583     return offset-offset_start;
584 }
585 
586 
587 static gint
dissect_zvt_tlv_len(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,int hf,guint16 * len)588 dissect_zvt_tlv_len(tvbuff_t *tvb, gint offset,
589         packet_info *pinfo _U_, proto_tree *tree, int hf, guint16 *len)
590 {
591     guint16 _len;
592     gint    len_bytes = 1;
593 
594     _len = tvb_get_guint8(tvb, offset);
595     if (_len & 0x80) {
596         if ((_len & 0x03) == 1) {
597             len_bytes++;
598             _len = tvb_get_guint8(tvb, offset+1);
599         }
600         else if ((_len & 0x03) == 2) {
601             len_bytes += 2;
602             _len = tvb_get_ntohs(tvb, offset+1);
603         }
604         else {
605             /* XXX - expert info */
606             return -1;
607         }
608     }
609 
610     proto_tree_add_uint(tree, hf, tvb, offset, len_bytes, _len);
611     if (len)
612         *len = _len;
613 
614     return len_bytes;
615 }
616 
617 
618 static gint
dissect_zvt_tlv_seq(tvbuff_t * tvb,gint offset,guint16 seq_max_len,packet_info * pinfo,proto_tree * tree,tlv_seq_info_t * seq_info)619 dissect_zvt_tlv_seq(tvbuff_t *tvb, gint offset, guint16 seq_max_len,
620         packet_info *pinfo, proto_tree *tree, tlv_seq_info_t *seq_info)
621 {
622     gint            offset_start;
623     proto_item     *dat_obj_it;
624     proto_tree     *dat_obj_tree;
625     gint            tag_len;
626     guint32         tag;
627     gint            data_len_bytes;
628     guint16         data_len = 0;
629     tlv_info_t     *ti;
630     gint            ret;
631 
632     if (!seq_info) {
633         seq_info = wmem_new(pinfo->pool, tlv_seq_info_t);
634 
635         /* by default, text lines are using the CP437 charset
636            there's an object to change the encoding
637            (XXX - does this change apply only to the current message?) */
638         seq_info->txt_enc = ENC_CP437;
639     }
640 
641     offset_start = offset;
642 
643     while (offset-offset_start < seq_max_len) {
644         dat_obj_tree = proto_tree_add_subtree(tree,
645             tvb, offset, -1, ett_zvt_tlv_dat_obj, &dat_obj_it,
646             "TLV data object");
647 
648         tag_len = dissect_zvt_tlv_tag(tvb, offset, pinfo, dat_obj_tree, &tag);
649         if (tag_len <= 0)
650             return offset - offset_start;
651         offset += tag_len;
652 
653         data_len_bytes = dissect_zvt_tlv_len(tvb, offset, pinfo,
654                 dat_obj_tree,hf_zvt_tlv_len, &data_len);
655         if (data_len_bytes > 0)
656             offset += data_len_bytes;
657 
658         /* set the sequence length now that we know it
659            this way, we don't have to put the whole switch statement
660            under if (data_len > 0) */
661         proto_item_set_len(dat_obj_it, tag_len + data_len_bytes + data_len);
662         if (data_len == 0)
663             continue;
664 
665         ti = (tlv_info_t *)g_hash_table_lookup(
666             tlv_table, GUINT_TO_POINTER((guint)tag));
667         if (ti && ti->dissect_payload) {
668             ret = ti->dissect_payload(
669                     tvb, offset, (gint)data_len, pinfo, dat_obj_tree, seq_info);
670             if (ret <= 0) {
671                 /* XXX - expert info */
672             }
673         }
674 
675         offset += data_len;
676     }
677 
678     return offset - offset_start;
679 }
680 
681 
682 static gint
dissect_zvt_tlv_container(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree)683 dissect_zvt_tlv_container(tvbuff_t *tvb, gint offset,
684         packet_info *pinfo, proto_tree *tree)
685 {
686     gint     offset_start;
687     gint     total_len_bytes, seq_len;
688     guint16  seq_max_len = 0;
689 
690     offset_start = offset;
691 
692     total_len_bytes = dissect_zvt_tlv_len(tvb, offset, pinfo,
693                 tree, hf_zvt_tlv_total_len, &seq_max_len);
694     if (total_len_bytes > 0)
695         offset += total_len_bytes;
696 
697     seq_len = dissect_zvt_tlv_seq(
698             tvb, offset, seq_max_len, pinfo, tree, NULL);
699     if (seq_len  > 0)
700         offset += seq_len;
701 
702     return offset - offset_start;
703 }
704 
705 
dissect_zvt_res_code(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)706 static inline gint dissect_zvt_res_code(
707         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
708 {
709     proto_tree_add_item(tree, hf_zvt_res_code, tvb, offset, 1, ENC_BIG_ENDIAN);
710     return 1;
711 }
712 
713 
dissect_zvt_cc(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)714 static inline gint dissect_zvt_cc(
715         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
716 {
717     proto_tree_add_item(tree, hf_zvt_cc, tvb, offset, 2, ENC_BIG_ENDIAN);
718     return 2;
719 }
720 
721 
dissect_zvt_card_type(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)722 static inline gint dissect_zvt_card_type(
723         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
724 {
725     proto_tree_add_item(tree, hf_zvt_card_type, tvb, offset, 1, ENC_BIG_ENDIAN);
726     return 1;
727 }
728 
729 
dissect_zvt_terminal_id(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)730 static inline gint dissect_zvt_terminal_id(
731         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
732 {
733     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 4, NULL, FALSE);
734     proto_tree_add_string(tree, hf_zvt_terminal_id, tvb, offset, 4, str);
735     return 4;
736 }
737 
738 
dissect_zvt_amount(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)739 static inline gint dissect_zvt_amount(
740         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
741 {
742     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 6, NULL, FALSE);
743     proto_tree_add_uint64(tree, hf_zvt_amount, tvb, offset, 6, g_ascii_strtoll(str,NULL,10));
744     return 6;
745 }
746 
747 
dissect_zvt_time(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)748 static inline gint dissect_zvt_time(
749         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
750 {
751     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 3, NULL, FALSE);
752     gchar  *fstr = (char *)wmem_alloc(pinfo->pool, 9);
753     fstr[0] = str[0];
754     fstr[1] = str[1];
755     fstr[2] = ':';
756     fstr[3] = str[2];
757     fstr[4] = str[3];
758     fstr[5] = ':';
759     fstr[6] = str[4];
760     fstr[7] = str[5];
761     fstr[8] = 0;
762     proto_tree_add_string(tree, hf_zvt_time, tvb, offset, 3, fstr);
763     return 3;
764 }
765 
766 
dissect_zvt_date(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)767 static inline gint dissect_zvt_date(
768         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
769 {
770     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 2, NULL, FALSE);
771     gchar  *fstr = (char *)wmem_alloc(pinfo->pool, 6);
772     fstr[0] = str[0];
773     fstr[1] = str[1];
774     fstr[2] = '/';
775     fstr[3] = str[2];
776     fstr[4] = str[3];
777     fstr[5] = 0;
778     proto_tree_add_string(tree, hf_zvt_date, tvb, offset, 2, fstr);
779     return 2;
780 }
781 
782 
dissect_zvt_expiry_date(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)783 static inline gint dissect_zvt_expiry_date(
784         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
785 {
786     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 2, NULL, FALSE);
787     gchar  *fstr = (char *)wmem_alloc(pinfo->pool, 6);
788     fstr[0] = str[0];
789     fstr[1] = str[1];
790     fstr[2] = '/';
791     fstr[3] = str[2];
792     fstr[4] = str[3];
793     fstr[5] = 0;
794     proto_tree_add_string(tree, hf_zvt_expiry_date, tvb, offset, 2, fstr);
795     return 2;
796 }
797 
798 
dissect_zvt_trace_number(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)799 static inline gint dissect_zvt_trace_number(
800         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
801 {
802     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset, 3, NULL, FALSE);
803     proto_tree_add_string(tree, hf_zvt_trace_number, tvb, offset, 3, str);
804     return 3;
805 }
806 
807 
dissect_zvt_card_number(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)808 static inline gint dissect_zvt_card_number(
809         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
810 {
811     guint8 tens = tvb_get_guint8(tvb, offset) & 0x0f;
812     guint8 ones = tvb_get_guint8(tvb, offset + 1) & 0x0f;
813     guint8 length = tens * 10 + ones;
814     const gchar *str = tvb_bcd_dig_to_str_be(pinfo->pool, tvb, offset + 2, length, NULL, FALSE);
815     proto_tree_add_string(tree, hf_zvt_card_number, tvb, offset + 2, length, str);
816     return 2 + length;
817 }
818 
819 
dissect_zvt_card_name(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)820 static inline gint dissect_zvt_card_name(
821         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
822 {
823     guint8 tens = tvb_get_guint8(tvb, offset) & 0x0f;
824     guint8 ones = tvb_get_guint8(tvb, offset + 1) & 0x0f;
825     guint8 length = tens * 10 + ones;
826     const guint8 * str = NULL;
827     proto_tree_add_item_ret_string(tree, hf_zvt_card_name, tvb, offset + 2, length, ENC_ASCII, pinfo->pool, &str);
828     return 2 + length;
829 }
830 
831 
dissect_zvt_additional_data(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)832 static inline gint dissect_zvt_additional_data(
833         tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
834 {
835     guint8 hundrets = tvb_get_guint8(tvb, offset) & 0x0f;
836     guint8 tens = tvb_get_guint8(tvb, offset + 1) & 0x0f;
837     guint8 ones = tvb_get_guint8(tvb, offset + 2) & 0x0f;
838     guint16 length = hundrets * 100 + tens * 10 + ones;
839     const guint8 * str = NULL;
840     proto_tree_add_item_ret_string(tree, hf_zvt_additional_data, tvb, offset + 3, length, ENC_ASCII, pinfo->pool, &str);
841     return 3 + length;
842 }
843 
844 
845 /* dissect one "bitmap", i.e BMP and the corresponding data */
846 static gint
dissect_zvt_bitmap(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree)847 dissect_zvt_bitmap(tvbuff_t *tvb, gint offset,
848         packet_info *pinfo, proto_tree *tree)
849 {
850     gint           offset_start;
851     guint8         bmp;
852     proto_item    *bitmap_it;
853     proto_tree    *bitmap_tree;
854     bitmap_info_t *bi;
855     gint           ret;
856 
857     offset_start = offset;
858 
859     bmp = tvb_get_guint8(tvb, offset);
860     if (try_val_to_str(bmp, bitmap) == NULL)
861         return -1;
862 
863     bitmap_tree = proto_tree_add_subtree(tree,
864             tvb, offset, -1, ett_zvt_bitmap, &bitmap_it, "Bitmap");
865 
866     proto_tree_add_item(bitmap_tree, hf_zvt_bmp,
867             tvb, offset, 1, ENC_BIG_ENDIAN);
868     proto_item_append_text(bitmap_it, ": %s",
869             val_to_str(bmp, bitmap, "unknown"));
870     offset++;
871 
872     bi = (bitmap_info_t *)g_hash_table_lookup(
873             bitmap_table, GUINT_TO_POINTER((guint)bmp));
874     if (bi) {
875         if (bi->dissect_payload) {
876             ret = bi->dissect_payload(tvb, offset, pinfo, bitmap_tree);
877             if (ret >= 0)
878                 offset += ret;
879         }
880         else if (bi->payload_len != BMP_PLD_LEN_UNKNOWN)
881             offset += bi->payload_len;
882     }
883 
884     proto_item_set_len(bitmap_it, offset - offset_start);
885     return offset - offset_start;
886 }
887 
888 
dissect_zvt_int_status(tvbuff_t * tvb,gint offset,guint16 len,packet_info * pinfo,proto_tree * tree,zvt_transaction_t * zvt_trans)889 static void dissect_zvt_int_status(tvbuff_t *tvb, gint offset, guint16 len,
890         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans)
891 {
892     proto_tree_add_item(tree, hf_zvt_int_status,
893             tvb, offset, 1, ENC_BIG_ENDIAN);
894     offset++;
895 
896     if (len > 1)
897         offset++; /* skip "timeout" */
898 
899     if (len > 2)
900         dissect_zvt_bitmap_seq(tvb, offset, len-2, pinfo, tree, zvt_trans);
901 }
902 
903 
904 static void
dissect_zvt_reg(tvbuff_t * tvb,gint offset,guint16 len _U_,packet_info * pinfo,proto_tree * tree,zvt_transaction_t * zvt_trans)905 dissect_zvt_reg(tvbuff_t *tvb, gint offset, guint16 len _U_,
906         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans)
907 {
908     proto_tree_add_item(tree, hf_zvt_pwd, tvb, offset, 3, ENC_NA);
909     offset += 3;
910 
911     proto_tree_add_item(tree, hf_zvt_reg_cfg,
912             tvb, offset, 1, ENC_BIG_ENDIAN);
913     offset++;
914 
915     /* check for the optional part CC|0x03|service byte|TLV */
916     if (tvb_captured_length_remaining(tvb, offset)>=2) {
917         offset += dissect_zvt_cc(tvb, offset, pinfo, tree);
918     }
919 
920     /* it's ok if the remaining len is 0 */
921     dissect_zvt_bitmap_seq(tvb, offset,
922             tvb_captured_length_remaining(tvb, offset),
923             pinfo, tree, zvt_trans);
924 }
925 
926 
dissect_zvt_init(tvbuff_t * tvb,gint offset,guint16 len _U_,packet_info * pinfo _U_,proto_tree * tree,zvt_transaction_t * zvt_trans _U_)927 static void dissect_zvt_init(
928         tvbuff_t *tvb, gint offset, guint16 len _U_, packet_info *pinfo _U_,
929         proto_tree *tree, zvt_transaction_t *zvt_trans _U_)
930 {
931     proto_tree_add_item(tree, hf_zvt_pwd, tvb, offset, 3, ENC_NA);
932 }
933 
934 
935 static void
dissect_zvt_abort(tvbuff_t * tvb,gint offset,guint16 len _U_,packet_info * pinfo,proto_tree * tree,zvt_transaction_t * zvt_trans)936 dissect_zvt_abort(tvbuff_t *tvb, gint offset, guint16 len _U_,
937         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans)
938 {
939     proto_tree_add_item(tree, hf_zvt_res_code, tvb, offset, 1, ENC_NA);
940     offset += 1;
941 
942     dissect_zvt_bitmap_seq(tvb, offset,
943             tvb_captured_length_remaining(tvb, offset),
944             pinfo, tree, zvt_trans);
945 }
946 
947 
948 static void
dissect_zvt_pass_bitmap_seq(tvbuff_t * tvb,gint offset,guint16 len _U_,packet_info * pinfo,proto_tree * tree,zvt_transaction_t * zvt_trans)949 dissect_zvt_pass_bitmap_seq(tvbuff_t *tvb, gint offset, guint16 len _U_,
950         packet_info *pinfo, proto_tree *tree, zvt_transaction_t *zvt_trans)
951 {
952     proto_tree_add_item(tree, hf_zvt_pwd, tvb, offset, 3, ENC_NA);
953     offset += 3;
954 
955     dissect_zvt_bitmap_seq(tvb, offset,
956             tvb_captured_length_remaining(tvb, offset),
957             pinfo, tree, zvt_trans);
958 }
959 
960 
961 /* dissect a sequence of bitmaps
962    (which may be the complete APDU payload or a part of it) */
963 static void
dissect_zvt_bitmap_seq(tvbuff_t * tvb,gint offset,guint16 len,packet_info * pinfo _U_,proto_tree * tree,zvt_transaction_t * zvt_trans _U_)964 dissect_zvt_bitmap_seq(tvbuff_t *tvb, gint offset, guint16 len,
965         packet_info *pinfo _U_, proto_tree *tree, zvt_transaction_t *zvt_trans _U_)
966 {
967     gint offset_start, ret;
968 
969     offset_start = offset;
970 
971     while (offset - offset_start < len) {
972         ret = dissect_zvt_bitmap(tvb, offset, pinfo, tree);
973         if (ret <=0)
974             break;
975         offset += ret;
976     }
977 }
978 
979 
980 static void
zvt_set_addresses(packet_info * pinfo,zvt_transaction_t * zvt_trans)981 zvt_set_addresses(packet_info *pinfo, zvt_transaction_t *zvt_trans)
982 {
983     apdu_info_t     *ai;
984     zvt_direction_t  dir = DIRECTION_UNKNOWN;
985 
986     if (!zvt_trans)
987         return;
988 
989     ai = (apdu_info_t *)g_hash_table_lookup(
990             apdu_table, GUINT_TO_POINTER((guint)zvt_trans->ctrl));
991     if (!ai)
992         return;
993 
994     if (zvt_trans->rqst_frame == pinfo->num) {
995         dir = ai->direction;
996     }
997     else if (zvt_trans->resp_frame == pinfo->num) {
998         if (ai->direction == DIRECTION_ECR_TO_PT)
999             dir = DIRECTION_PT_TO_ECR;
1000         else
1001             dir = DIRECTION_ECR_TO_PT;
1002     }
1003 
1004     if (dir  == DIRECTION_ECR_TO_PT) {
1005         set_address(&pinfo->src, AT_STRINGZ,
1006                 (int)strlen(ADDR_ECR)+1, ADDR_ECR);
1007         set_address(&pinfo->dst, AT_STRINGZ,
1008                 (int)strlen(ADDR_PT)+1, ADDR_PT);
1009     }
1010     else if (dir  == DIRECTION_PT_TO_ECR) {
1011         set_address(&pinfo->src, AT_STRINGZ,
1012                 (int)strlen(ADDR_PT)+1, ADDR_PT);
1013         set_address(&pinfo->dst, AT_STRINGZ,
1014                 (int)strlen(ADDR_ECR)+1, ADDR_ECR);
1015     }
1016 }
1017 
1018 
1019 /* dissect a ZVT APDU
1020    return -1 if we don't have a complete APDU, 0 if the packet is no ZVT APDU
1021    or the length of the ZVT APDU if all goes well */
1022 static int
dissect_zvt_apdu(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree)1023 dissect_zvt_apdu(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree)
1024 {
1025     gint               offset_start;
1026     guint8             len_bytes = 1; /* number of bytes for the len field */
1027     guint16            ctrl = ZVT_CTRL_NONE;
1028     guint16            len;
1029     guint8             byte;
1030     proto_item        *apdu_it;
1031     proto_tree        *apdu_tree;
1032     apdu_info_t       *ai;
1033     zvt_transaction_t *zvt_trans = NULL;
1034     proto_item        *it;
1035 
1036     offset_start = offset;
1037 
1038     if (tvb_captured_length_remaining(tvb, offset) < ZVT_APDU_MIN_LEN)
1039         return -1;
1040 
1041     len = tvb_get_guint8(tvb, offset+2);
1042     if (len == 0xFF) {
1043         len_bytes = 3;
1044         len = tvb_get_letohs(tvb, offset+3);
1045     }
1046 
1047     /* ZVT_APDU_MIN_LEN already includes one length byte */
1048     if (tvb_captured_length_remaining(tvb, offset) <
1049             ZVT_APDU_MIN_LEN + (len_bytes-1) + len) {
1050         return -1;
1051     }
1052 
1053     apdu_tree = proto_tree_add_subtree(tree,
1054             tvb, offset, -1, ett_zvt_apdu, &apdu_it, "ZVT APDU");
1055 
1056     byte = tvb_get_guint8(tvb, offset);
1057     if (byte == CCRC_POS || byte == CCRC_NEG) {
1058         proto_tree_add_item(apdu_tree, hf_zvt_ccrc, tvb, offset, 1, ENC_BIG_ENDIAN);
1059         col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
1060                 byte == CCRC_POS ? "Positive completion" : "Negative completion");
1061         offset++;
1062         proto_tree_add_item(apdu_tree, hf_zvt_aprc, tvb, offset, 1, ENC_BIG_ENDIAN);
1063         offset++;
1064 
1065         zvt_trans = (zvt_transaction_t *)wmem_tree_lookup32_le(
1066                 transactions, pinfo->num);
1067         if (zvt_trans && zvt_trans->resp_frame==0) {
1068             /* there's a pending request, this packet is the response */
1069             zvt_trans->resp_frame = pinfo->num;
1070         }
1071 
1072         if (zvt_trans && zvt_trans->resp_frame == pinfo->num) {
1073             it = proto_tree_add_uint(apdu_tree, hf_zvt_resp_to,
1074                     NULL, 0, 0, zvt_trans->rqst_frame);
1075             proto_item_set_generated(it);
1076         }
1077     }
1078     else {
1079         ctrl = tvb_get_ntohs(tvb, offset);
1080         proto_tree_add_item(apdu_tree, hf_zvt_ctrl, tvb, offset, 2, ENC_BIG_ENDIAN);
1081         col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
1082                 val_to_str_const(ctrl, ctrl_field, "Unknown 0x%x"));
1083         offset += 2;
1084 
1085         if (PINFO_FD_VISITED(pinfo)) {
1086             zvt_trans = (zvt_transaction_t *)wmem_tree_lookup32(
1087                     transactions, pinfo->num);
1088             if (zvt_trans && zvt_trans->rqst_frame==pinfo->num &&
1089                     zvt_trans->resp_frame!=0) {
1090                it = proto_tree_add_uint(apdu_tree, hf_zvt_resp_in,
1091                        NULL, 0, 0, zvt_trans->resp_frame);
1092                proto_item_set_generated(it);
1093             }
1094         }
1095         else {
1096             zvt_trans = wmem_new(wmem_file_scope(), zvt_transaction_t);
1097             zvt_trans->rqst_frame = pinfo->num;
1098             zvt_trans->resp_frame = 0;
1099             zvt_trans->ctrl = ctrl;
1100             wmem_tree_insert32(transactions,
1101                     zvt_trans->rqst_frame, (void *)zvt_trans);
1102         }
1103     }
1104 
1105     ai = (apdu_info_t *)g_hash_table_lookup(
1106             apdu_table, GUINT_TO_POINTER((guint)ctrl));
1107 
1108     it = proto_tree_add_uint(apdu_tree, hf_zvt_len, tvb, offset, len_bytes, len);
1109     if (ai && ai->min_len_field!=LEN_FIELD_ANY && len<ai->min_len_field) {
1110         expert_add_info_format(pinfo, it, &ei_invalid_apdu_len,
1111                 "The APDU length is too short. The minimum length is %d",
1112                 ai->min_len_field);
1113     }
1114     offset += len_bytes;
1115 
1116     zvt_set_addresses(pinfo, zvt_trans);
1117 
1118     if (len > 0) {
1119         if (ai && ai->dissect_payload)
1120             ai->dissect_payload(tvb, offset, len, pinfo, apdu_tree, zvt_trans);
1121         else
1122             proto_tree_add_item(apdu_tree, hf_zvt_data,
1123                     tvb, offset, len, ENC_NA);
1124     }
1125     offset += len;
1126 
1127     proto_item_set_len(apdu_it, offset - offset_start);
1128     return offset - offset_start;
1129 }
1130 
1131 
1132 static gint
dissect_zvt_serial(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree)1133 dissect_zvt_serial(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree)
1134 {
1135     gint  offset_start;
1136     int   apdu_len;
1137 
1138     offset_start = offset;
1139 
1140     if (tvb_reported_length_remaining(tvb, offset) == 1) {
1141         proto_tree_add_item(tree, hf_zvt_serial_char,
1142                 tvb, offset, 1, ENC_BIG_ENDIAN);
1143         offset++; /* ACK or NAK byte */
1144         return offset - offset_start;
1145     }
1146 
1147     proto_tree_add_item(tree, hf_zvt_serial_char,
1148             tvb, offset, 1, ENC_BIG_ENDIAN);
1149     offset ++; /* DLE byte */
1150     proto_tree_add_item(tree, hf_zvt_serial_char,
1151             tvb, offset, 1, ENC_BIG_ENDIAN);
1152     offset ++; /* STX byte */
1153 
1154     apdu_len = dissect_zvt_apdu(tvb, offset, pinfo, tree);
1155     if (apdu_len < 0)
1156         return apdu_len;
1157 
1158     offset += apdu_len;
1159 
1160     proto_tree_add_item(tree, hf_zvt_serial_char,
1161             tvb, offset, 1, ENC_BIG_ENDIAN);
1162     offset ++; /* DLE byte */
1163     proto_tree_add_item(tree, hf_zvt_serial_char,
1164             tvb, offset, 1, ENC_BIG_ENDIAN);
1165     offset ++; /* ETX byte */
1166 
1167     /* the CRC is little endian, the other fields are big endian */
1168     proto_tree_add_item(tree, hf_zvt_crc,
1169             tvb, offset, 2, ENC_LITTLE_ENDIAN);
1170     offset += 2; /* CRC bytes */
1171 
1172     return offset - offset_start;
1173 }
1174 
1175 
1176 static gboolean
valid_ctrl_field(tvbuff_t * tvb,gint offset)1177 valid_ctrl_field(tvbuff_t *tvb, gint offset)
1178 {
1179     if (tvb_get_guint8(tvb, offset) == 0x80 ||
1180         tvb_get_guint8(tvb, offset) == 0x84 ||
1181         try_val_to_str_ext(tvb_get_ntohs(tvb, offset), &ctrl_field_ext)) {
1182             return TRUE;
1183     }
1184 
1185     return FALSE;
1186 }
1187 
1188 
1189 static int
dissect_zvt(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1190 dissect_zvt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1191 {
1192     gint        zvt_len = 0;
1193     proto_item *zvt_ti;
1194     proto_tree *zvt_tree;
1195     gboolean    is_serial; /* serial or TCP/IP protocol? */
1196 
1197     if (tvb_captured_length(tvb) == 1 &&
1198             (tvb_get_guint8(tvb, 0) == ACK ||
1199              tvb_get_guint8(tvb, 0) == NAK)) {
1200         is_serial = TRUE;
1201     }
1202     else if (tvb_captured_length(tvb) >= 2 &&
1203             tvb_get_guint8(tvb, 0) == DLE &&
1204             tvb_get_guint8(tvb, 1) == STX) {
1205         is_serial = TRUE;
1206     }
1207     else if (tvb_captured_length(tvb) >= ZVT_APDU_MIN_LEN &&
1208             valid_ctrl_field(tvb, 0)) {
1209         is_serial = FALSE;
1210     }
1211     else
1212         return 0;
1213 
1214     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZVT");
1215     col_clear(pinfo->cinfo, COL_INFO);
1216     zvt_ti = proto_tree_add_protocol_format(tree, proto_zvt,
1217             tvb, 0, -1,
1218             "ZVT Kassenschnittstelle: %s", is_serial ?
1219             "Serial Transport Protocol" : "Transport Protocol TCP/IP");
1220     zvt_tree = proto_item_add_subtree(zvt_ti, ett_zvt);
1221 
1222     if (is_serial)
1223         zvt_len = dissect_zvt_serial(tvb, 0, pinfo, zvt_tree);
1224     else
1225         zvt_len = dissect_zvt_apdu(tvb, 0, pinfo, zvt_tree);
1226 
1227     /* zvt_len < 0 means that we have an incomplete APDU
1228        we can't do any reassembly here, so let's consume all bytes */
1229     if (zvt_len < 0)
1230         zvt_len = tvb_captured_length(tvb);
1231 
1232     proto_item_set_len(zvt_ti, zvt_len);
1233     return zvt_len;
1234 }
1235 
get_zvt_message_len(packet_info * pinfo _U_,tvbuff_t * tvb,int offset,void * data _U_)1236 static guint get_zvt_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
1237 {
1238     guint len = tvb_get_guint8(tvb, offset+2);
1239     if (len == 0xFF)
1240         if (tvb_captured_length_remaining(tvb, offset) >= 5)
1241             len = tvb_get_letohs(tvb, offset+3) + 5;
1242         else
1243             len = 0;
1244     else
1245         len += 3;
1246 
1247     return len;
1248 }
1249 
1250 static int
dissect_zvt_tcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1251 dissect_zvt_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1252 {
1253     tcp_dissect_pdus(tvb, pinfo, tree, TRUE, ZVT_APDU_MIN_LEN,
1254                      get_zvt_message_len, dissect_zvt, data);
1255     return tvb_captured_length(tvb);
1256 }
1257 
1258 static void
zvt_shutdown(void)1259 zvt_shutdown(void)
1260 {
1261     g_hash_table_destroy(tlv_table);
1262     g_hash_table_destroy(apdu_table);
1263     g_hash_table_destroy(bitmap_table);
1264 }
1265 
1266 void
proto_register_zvt(void)1267 proto_register_zvt(void)
1268 {
1269     guint     i;
1270     expert_module_t* expert_zvt;
1271 
1272     static gint *ett[] = {
1273         &ett_zvt,
1274         &ett_zvt_apdu,
1275         &ett_zvt_bitmap,
1276         &ett_zvt_tlv_dat_obj,
1277         &ett_zvt_tlv_subseq,
1278         &ett_zvt_tlv_tag
1279     };
1280     static hf_register_info hf[] = {
1281         { &hf_zvt_resp_in,
1282             { "Response In", "zvt.resp_in",
1283                 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1284         { &hf_zvt_resp_to,
1285             { "Response To", "zvt.resp_to",
1286                 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1287          { &hf_zvt_serial_char,
1288             { "Serial character", "zvt.serial_char", FT_UINT8,
1289                 BASE_HEX|BASE_EXT_STRING, &serial_char_ext, 0, NULL, HFILL } },
1290         { &hf_zvt_crc,
1291             { "CRC", "zvt.crc", FT_UINT16,
1292                 BASE_HEX, NULL, 0, NULL, HFILL } },
1293         { &hf_zvt_ctrl,
1294             { "Control-field", "zvt.control_field", FT_UINT16,
1295                 BASE_HEX|BASE_EXT_STRING, &ctrl_field_ext, 0, NULL, HFILL } },
1296         { &hf_zvt_ccrc,
1297             { "CCRC", "zvt.ccrc",
1298                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
1299         { &hf_zvt_aprc,
1300             { "APRC", "zvt.aprc",
1301                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
1302         { &hf_zvt_len,
1303             { "Length-field", "zvt.length_field",
1304                 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
1305         { &hf_zvt_data,
1306           { "APDU data", "zvt.data",
1307             FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
1308         { &hf_zvt_int_status,
1309             { "Intermediate status", "zvt.int_status",
1310                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
1311         { &hf_zvt_pwd,
1312             { "Password", "zvt.password",
1313                 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
1314         { &hf_zvt_reg_cfg,
1315             { "Config byte", "zvt.reg.config_byte",
1316                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
1317         { &hf_zvt_res_code,
1318             { "Result Code", "zvt.result_code",
1319                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
1320         /* we don't call the filter zvt.reg.cc, the currency code
1321            appears in several apdus */
1322         { &hf_zvt_cc,
1323             { "Currency Code", "zvt.cc",
1324                 FT_UINT16, BASE_HEX, VALS(zvt_cc), 0, NULL, HFILL } },
1325         { &hf_zvt_card_type,
1326             { "Card Type", "zvt.card_type", FT_UINT8,
1327                 BASE_DEC|BASE_EXT_STRING, &card_type_ext, 0, NULL, HFILL } },
1328         { &hf_zvt_terminal_id,
1329             { "Terminal ID", "zvt.terminal_id", FT_STRING,
1330                 BASE_NONE, NULL, 0, NULL, HFILL } },
1331         { &hf_zvt_amount,
1332             { "Amount", "zvt.amount", FT_UINT48,
1333                 BASE_DEC, NULL, 0, NULL, HFILL } },
1334         { &hf_zvt_time,
1335             { "Time", "zvt.time", FT_STRING,
1336                 BASE_NONE, NULL, 0, NULL, HFILL } },
1337         { &hf_zvt_date,
1338             { "Date", "zvt.date", FT_STRING,
1339                 BASE_NONE, NULL, 0, NULL, HFILL } },
1340         { &hf_zvt_bmp,
1341             { "BMP", "zvt.bmp", FT_UINT8,
1342                 BASE_HEX|BASE_EXT_STRING, &bitmap_ext, 0, NULL, HFILL } },
1343         { &hf_zvt_tlv_total_len,
1344             { "Total length", "zvt.tlv.total_len",
1345                 FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
1346         { &hf_zvt_tlv_tag,
1347             { "Tag", "zvt.tlv.tag", FT_UINT32,
1348                 BASE_HEX|BASE_EXT_STRING, &tlv_tags_ext, 0, NULL, HFILL } },
1349         { &hf_zvt_tlv_tag_class,
1350             { "Class", "zvt.tlv.tag.class", FT_UINT8,
1351                 BASE_HEX|BASE_EXT_STRING, &tlv_tag_class_ext,
1352                 0xC0, NULL, HFILL } },
1353         { &hf_zvt_tlv_tag_type,
1354             { "Type", "zvt.tlv.tag.type", FT_BOOLEAN,
1355                 8, TFS(&tfs_constructed_primitive), 0x20, NULL, HFILL } },
1356         { &hf_zvt_tlv_len,
1357             { "Length", "zvt.tlv.len",
1358                 FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
1359         { &hf_zvt_text_lines_line,
1360             { "Text line", "zvt.tlv.text_lines.line",
1361                 FT_STRING, STR_UNICODE, NULL, 0, NULL, HFILL } },
1362         { &hf_zvt_permitted_cmd,
1363             { "Permitted command", "zvt.tlv.permitted_command",
1364                 FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
1365         { &hf_zvt_receipt_type,
1366             { "Receipt type", "zvt.tlv.receipt_type",
1367                 FT_UINT16, BASE_HEX, VALS(receipt_type), 0, NULL, HFILL } },
1368         { &hf_zvt_receipt_parameter_positive_customer,
1369             { "Positive customer receipt", "zvt.tlv.receipt_parameter.positive_customer", FT_BOOLEAN,
1370                 8, TFS(&tfs_required_not_required), 0x80, NULL, HFILL } },
1371         { &hf_zvt_receipt_parameter_negative_customer,
1372             { "Negative customer receipt", "zvt.tlv.receipt_parameter.negative_customer", FT_BOOLEAN,
1373                 8, TFS(&tfs_required_not_required), 0x40, NULL, HFILL } },
1374         { &hf_zvt_receipt_parameter_positive_merchant,
1375             { "Positive merchant receipt", "zvt.tlv.receipt_parameter.positive_customer", FT_BOOLEAN,
1376                 8, TFS(&tfs_required_not_required), 0x20, NULL, HFILL } },
1377         { &hf_zvt_receipt_parameter_negative_merchant,
1378             { "Negative merchant receipt", "zvt.tlv.receipt_parameter.negative_customer", FT_BOOLEAN,
1379                 8, TFS(&tfs_required_not_required), 0x10, NULL, HFILL } },
1380         { &hf_zvt_receipt_parameter_customer_before_merchant,
1381             { "Customer receipt should be sent before the merchant receipt", "zvt.tlv.receipt_parameter.customer_first", FT_BOOLEAN,
1382                 8, TFS(&tfs_yes_no), 0x08, NULL, HFILL } },
1383         { &hf_zvt_receipt_parameter_print_short_receipt,
1384             { "Print short receipt", "zvt.tlv.receipt_parameter.short_receipt", FT_BOOLEAN,
1385                 8, TFS(&tfs_yes_no), 0x04, NULL, HFILL } },
1386         { &hf_zvt_receipt_parameter_no_product_data,
1387             { "Do not print product data (from BMP 3C) on the receipt", "zvt.tlv.receipt_parameter.no_product", FT_BOOLEAN,
1388                 8, TFS(&tfs_yes_no), 0x02, NULL, HFILL } },
1389         { &hf_zvt_receipt_parameter_ecr_as_printer,
1390             { "Use ECR as printer", "zvt.tlv.receipt_parameter.ecr_as_printer", FT_BOOLEAN,
1391                 8, TFS(&tfs_yes_no), 0x01, NULL, HFILL } },
1392         { &hf_zvt_receipt_parameter,
1393             { "Receipt parameter", "zvt.tlv.receipt_parameter", FT_UINT8,
1394                 BASE_HEX, NULL, 0x00, NULL, HFILL } },
1395         { &hf_zvt_trace_number,
1396             { "Trace number", "zvt.trace_number", FT_STRING,
1397                 BASE_NONE, NULL, 0, NULL, HFILL } },
1398         { &hf_zvt_expiry_date,
1399             { "Expiry date", "zvt.expiry_date", FT_STRING,
1400                 BASE_NONE, NULL, 0, NULL, HFILL } },
1401         { &hf_zvt_card_number,
1402             { "Card number", "zvt.card_number", FT_STRING,
1403                 BASE_NONE, NULL, 0, NULL, HFILL } },
1404         { &hf_zvt_card_name,
1405             { "Card name", "zvt.card_name", FT_STRING,
1406                 BASE_NONE, NULL, 0, NULL, HFILL } },
1407         { &hf_zvt_additional_data,
1408             { "Additional data", "zvt.additional_data", FT_STRING,
1409                 BASE_NONE, NULL, 0, NULL, HFILL } },
1410         { &hf_zvt_characters_per_line,
1411             { "Characters per line", "zvt.characters_per_line", FT_STRING,
1412                 BASE_NONE, NULL, 0, NULL, HFILL } },
1413     };
1414 
1415     static ei_register_info ei[] = {
1416         { &ei_invalid_apdu_len,
1417             { "zvt.apdu_len.invalid", PI_PROTOCOL, PI_WARN,
1418                 "The APDU length is too short. The minimum length is %d",
1419                 EXPFILL }}
1420     };
1421 
1422     apdu_table = g_hash_table_new(g_direct_hash, g_direct_equal);
1423     for(i=0; i<array_length(apdu_info); i++) {
1424         g_hash_table_insert(apdu_table,
1425                             GUINT_TO_POINTER((guint)apdu_info[i].ctrl),
1426                             (gpointer)(&apdu_info[i]));
1427     }
1428 
1429     bitmap_table = g_hash_table_new(g_direct_hash, g_direct_equal);
1430     for(i=0; i<array_length(bitmap_info); i++) {
1431         g_hash_table_insert(bitmap_table,
1432                             GUINT_TO_POINTER((guint)bitmap_info[i].bmp),
1433                             (gpointer)(&bitmap_info[i]));
1434     }
1435 
1436     tlv_table = g_hash_table_new(g_direct_hash, g_direct_equal);
1437     for(i=0; i<array_length(tlv_info); i++) {
1438         g_hash_table_insert(tlv_table,
1439                             GUINT_TO_POINTER((guint)tlv_info[i].tag),
1440                             (gpointer)(&tlv_info[i]));
1441     }
1442 
1443     proto_zvt = proto_register_protocol("ZVT Kassenschnittstelle", "ZVT", "zvt");
1444 
1445     proto_register_field_array(proto_zvt, hf, array_length(hf));
1446     proto_register_subtree_array(ett, array_length(ett));
1447     expert_zvt = expert_register_protocol(proto_zvt);
1448     expert_register_field_array(expert_zvt, ei, array_length(ei));
1449 
1450     transactions = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
1451 
1452     /* register by name to allow mapping to a user DLT */
1453     register_dissector("zvt", dissect_zvt, proto_zvt);
1454 
1455     register_shutdown_routine(zvt_shutdown);
1456 }
1457 
1458 
1459 void
proto_reg_handoff_zvt(void)1460 proto_reg_handoff_zvt(void)
1461 {
1462     dissector_handle_t  zvt_tcp_handle;
1463 
1464     zvt_tcp_handle = create_dissector_handle(dissect_zvt_tcp, proto_zvt);
1465 
1466     dissector_add_for_decode_as_with_preference("tcp.port", zvt_tcp_handle);
1467 }
1468 
1469 
1470 /*
1471  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1472  *
1473  * Local variables:
1474  * c-basic-offset: 4
1475  * tab-width: 8
1476  * indent-tabs-mode: nil
1477  * End:
1478  *
1479  * vi: set shiftwidth=4 tabstop=8 expandtab:
1480  * :indentSize=4:tabSize=8:noTabs=true:
1481  */
1482