### Bug Summary

File: | builds/wireshark/wireshark/epan/dissectors/packet-mdb.c
Warning: | line 1221, column 5 Value stored to 'offset' is never read

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-mdb.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-06-09-100419-3529-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-mdb.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /*
2 | * packet-mdb.c
3 | * Routines for MDB dissection
4 | * Copyright 2023 Martin Kaiser for PayTec AG (www.paytec.ch)
5 | *
6 | * Wireshark - Network traffic analyzer
7 | * By Gerald Combs <gerald@wireshark.org>
8 | * Copyright 1998 Gerald Combs
9 | *
10 | * SPDX-License-Identifier: GPL-2.0-or-later
11 | */
12 |
13 | /*
14 | * The MDB (Multi-Drop Bus) protocol is used inside a vending machine. MDB
15 | * defines the communication between the main control board (VMC = Vending
16 | * Machine Controller) and peripheral components, e.g. a payment terminal
17 | * or a bill validator.
18 | *
19 | * The VMC acts as bus master and sends a request to one peripheral at a time.
20 | * A peripheral may send data only in response to such a request.
21 | *
22 | * The MDB specification is maintained by the National Automatic Merchandising
23 | * Association (NAMA). As of August 2023, the current version of the MDB
24 | * specification is 4.3. It is available from
25 | * https://namanow.org/nama-releases-mdb-version-4-3/
26 | *
27 | * The pcap input format for this dissector is documented at
28 | * https://www.kaiser.cx/pcap-mdb.html
29 | */
30 |
31 | #include "config.h"
32 | #include <epan/expert.h>
33 | #include <epan/packet.h>
34 | #include <epan/conversation.h>
35 | #include <epan/tfs.h>
36 | #include <wsutil/array.h>
37 | #include <wiretap/wtap.h>
38 |
39 | void proto_reg_handoff_mdb(void);
40 | void proto_register_mdb(void);
41 |
42 | static int proto_mdb;
43 |
44 | static int ett_mdb;
45 | static int ett_mdb_hdr;
46 | static int ett_mdb_cl;
47 | static int ett_mdb_cgw;
48 | static int ett_mdb_bv;
49 |
50 | static int hf_mdb_hdr_ver;
51 | static int hf_mdb_event;
52 | static int hf_mdb_addr;
53 | static int hf_mdb_cmd;
54 | static int hf_mdb_cl_setup_sub;
55 | static int hf_mdb_cl_feat_lvl;
56 | static int hf_mdb_cl_cols;
57 | static int hf_mdb_cl_rows;
58 | static int hf_mdb_cl_disp_info;
59 | static int hf_mdb_cl_max_price;
60 | static int hf_mdb_cl_min_price;
61 | static int hf_mdb_cl_vend_sub;
62 | static int hf_mdb_cl_item_price;
63 | static int hf_mdb_cl_item_num;
64 | static int hf_mdb_cl_reader_sub;
65 | static int hf_mdb_cl_resp;
66 | static int hf_mdb_cl_scale;
67 | static int hf_mdb_cl_dec_pl;
68 | static int hf_mdb_cl_max_rsp_time;
69 | static int hf_mdb_cl_vend_amt;
70 | static int hf_mdb_cl_expns_sub;
71 | static int hf_mdb_cl_manuf_code;
72 | static int hf_mdb_cl_ser_num;
73 | static int hf_mdb_cl_mod_num;
74 | static int hf_mdb_cl_opt_feat;
75 | static int hf_mdb_cgw_feat_lvl;
76 | static int hf_mdb_cgw_scale;
77 | static int hf_mdb_cgw_dec_pl;
78 | static int hf_mdb_cgw_resp;
79 | static int hf_mdb_cgw_max_rsp_time;
80 | static int hf_mdb_cgw_report_sub;
81 | static int hf_mdb_cgw_dts_evt_code;
82 | static int hf_mdb_cgw_duration;
83 | static int hf_mdb_cgw_activity;
84 | static int hf_mdb_cgw_expns_sub;
85 | static int hf_mdb_cgw_opt_feat;
86 | static int hf_mdb_cgw_manuf_code;
87 | static int hf_mdb_cgw_ser_num;
88 | static int hf_mdb_cgw_mod_num;
89 | static int hf_mdb_bv_setup_bill_val_feature;
90 | static int hf_mdb_bv_setup_ctry_currency_code;
91 | static int hf_mdb_bv_setup_bill_scal_fac;
92 | static int hf_mdb_bv_setup_dec_places;
93 | static int hf_mdb_bv_setup_bill_stacker_cap;
94 | static int hf_mdb_bv_setup_bill_sec_lvls;
95 | static int hf_mdb_bv_setup_escrow;
96 | static int hf_mdb_bv_setup_bill_type_cred;
97 | static int hf_mdb_bv_bill_enable;
98 | static int hf_mdb_bv_bill_escrow_enable;
99 | static int hf_mdb_bv_poll_state;
100 | static int hf_mdb_bv_poll_bill_routing_state;
101 | static int hf_mdb_bv_poll_bill_type;
102 | static int hf_mdb_bv_escrow_state;
103 | static int hf_mdb_bv_stacker;
104 | static int hf_mdb_bv_exp_cmd;
105 | static int hf_mdb_bv_exp_opt_feat;
106 | static int hf_mdb_bv_exp_opt_feat_enable;
107 | static int hf_mdb_bv_exp_manufact_code;
108 | static int hf_mdb_bv_exp_serial_num;
109 | static int hf_mdb_bv_exp_model_tuning_num;
110 | static int hf_mdb_bv_exp_software_version;
111 | static int hf_mdb_bv_exp_bill_type_routing;
112 | static int hf_mdb_bv_exp_manual_dispense_enable;
113 | static int hf_mdb_bv_exp_bill_recycler_enabled;
114 | static int hf_mdb_bv_exp_bill_count;
115 | static int hf_mdb_bv_exp_dispenser_full_state;
116 | static int hf_mdb_bv_exp_bill_type_dispensed;
117 | static int hf_mdb_bv_exp_bill_type_number_bills;
118 | static int hf_mdb_bv_exp_dispense_value_bills;
119 | static int hf_mdb_bv_exp_payout_state;
120 | static int hf_mdb_bv_exp_dispenser_payout_activity;
121 |
122 | static int hf_mdb_ack;
123 | static int hf_mdb_data;
124 | static int hf_mdb_chk;
125 | static int hf_mdb_chk_status;
126 | static int hf_mdb_response_in;
127 | static int hf_mdb_response_to;
128 | static int hf_mdb_time;
129 |
130 | static expert_field ei_mdb_short_packet;
131 | static expert_field ei_mdb_bad_checksum;
132 |
133 | static dissector_handle_t mdb_handle;
134 |
135 | /* MDB is a master slave protocol, so per request, there is exactly one response */
136 | typedef struct {
137 | uint32_t req_num, rep_num;
138 | nstime_t req_time;
139 | uint16_t cmd; // In case of expanse cmd, 2 byte are used
140 | } mdb_transaction_t;
141 |
142 | typedef struct {
143 | wmem_tree_t* transactions;
144 | uint32_t last_req_packet;
145 | uint16_t last_cmd;
146 | } mdb_conv_info_t;
147 |
148 | static mdb_conv_info_t* get_mdb_conv_info(packet_info* pinfo)
149 | {
150 | conversation_t* conversation;
151 | mdb_conv_info_t* conv_info;
152 |
153 | conversation = find_or_create_conversation(pinfo);
154 | conv_info = (mdb_conv_info_t*)conversation_get_proto_data(conversation, proto_mdb);
155 | if (!conv_info) {
156 | conv_info = wmem_new0(wmem_file_scope(), mdb_conv_info_t)((mdb_conv_info_t*)wmem_alloc0((wmem_file_scope()), sizeof(mdb_conv_info_t )));
157 | conv_info->transactions = wmem_tree_new(wmem_file_scope());
158 | conversation_add_proto_data(conversation, proto_mdb, conv_info);
159 | }
160 | return conv_info;
161 | }
162 |
163 | #define MDB_EVT_DATA_MST_PER0xFF 0xFF
164 | #define MDB_EVT_DATA_PER_MST0xFE 0xFE
165 | #define MDB_EVT_BUS_RESET0xFD 0xFD
166 |
167 | #define MDB_PSEUDO_HDR_LEN2 2
168 |
169 | static bool_Bool is_mdb_reply(uint8_t byte) {
170 | return (byte == 0x00 || byte == 0xAA || byte == 0xFF);
171 | }
172 |
173 | static const value_string mdb_event[] = {
174 | { MDB_EVT_DATA_MST_PER0xFF, "Data transfer Master -> Peripheral" },
175 | { MDB_EVT_DATA_PER_MST0xFE, "Data transfer Peripheral -> Master" },
176 | { MDB_EVT_BUS_RESET0xFD, "Bus reset" },
177 | { 0, NULL((void*)0) }
178 | };
179 |
180 | #define ADDR_VMC"VMC" "VMC"
181 |
182 | #define ADDR_CASHLESS10x10 0x10
183 | #define ADDR_COMMS_GW0x18 0x18
184 | #define ADDR_BILL_VALIDATOR0x30 0x30
185 |
186 | #define ADDR_MASK0xF8 0xF8
187 | #define CMD_MASK0x07 0x07
188 | #define SUB_CMD_OFFSET8 8
189 |
190 | static const value_string mdb_addr[] = {
191 | { 0x00, "Reserved for VMC" },
192 | { 0x08, "Changer" },
193 | { ADDR_CASHLESS10x10, "Cashless #1" },
194 | { ADDR_COMMS_GW0x18, "Communications Gateway" },
195 | { 0x20, "Display" },
196 | { 0x28, "Energy Management System" },
197 | { ADDR_BILL_VALIDATOR0x30, "Bill Validator" },
198 | { 0x38, "Reserved for Future Standard Peripheral" },
199 | { 0x40, "Universal Satellite Device #1" },
200 | { 0x48, "Universal Satellite Device #2" },
201 | { 0x50, "Universal Satellite Device #3" },
202 | { 0x58, "Coin Hopper or Tube - Dispenser 1" },
203 | { 0x60, "Cashless #2" },
204 | { 0x68, "Age Verification Device" },
205 | { 0x70, "Coin Hopper or Tube - Dispenser 2" },
206 | { 0xF0, "Vending Machine Specific Peripheral #1" },
207 | { 0xF8, "Vending Machine Specific Peripheral #2" },
208 | { 0, NULL((void*)0) }
209 | };
210 |
211 | static const value_string mdb_ack[] = {
212 | { 0x00, "ACK" },
213 | { 0xAA, "RET" },
214 | { 0xFF, "NAK" },
215 | { 0, NULL((void*)0) }
216 | };
217 |
218 | /*
219 | * These are just the command bits in the address + command byte. MDB supports
220 | * two Cashless peripherals (Cashless #1 and #2) with different addresses,
221 | * both use the same commands.
222 | */
223 | #define MDB_CL_CMD_SETUP0x01 0x01
224 | #define MDB_CL_CMD_VEND0x03 0x03
225 | #define MDB_CL_CMD_READER0x04 0x04
226 | #define MDB_CL_CMD_EXPNS0x07 0x07
227 |
228 | static const value_string mdb_cl_cmd[] = {
229 | { 0x00, "Reset" },
230 | { MDB_CL_CMD_SETUP0x01, "Setup" },
231 | { 0x02, "Poll" },
232 | { MDB_CL_CMD_VEND0x03, "Vend" },
233 | { MDB_CL_CMD_READER0x04, "Reader" },
234 | { MDB_CL_CMD_EXPNS0x07, "Expansion" },
235 | { 0, NULL((void*)0) }
236 | };
237 |
238 | #define MDB_CL_SETUP_CFG_DATA0x00 0x00
239 | #define MDB_CL_SETUP_MAX_MIN0x01 0x01
240 |
241 | static const value_string mdb_cl_setup_sub_cmd[] = {
242 | { MDB_CL_SETUP_CFG_DATA0x00, "Config Data" },
243 | { MDB_CL_SETUP_MAX_MIN0x01, "Max/Min Prices" },
244 | { 0, NULL((void*)0) }
245 | };
246 |
247 | #define MDB_CL_VEND_REQ0x00 0x00
248 | #define MDB_CL_VEND_SUC0x02 0x02
249 |
250 | static const value_string mdb_cl_vend_sub_cmd[] = {
251 | { MDB_CL_VEND_REQ0x00, "Vend Request" },
252 | { MDB_CL_VEND_SUC0x02, "Vend Success" },
253 | { 0x04, "Session Complete" },
254 | { 0, NULL((void*)0) }
255 | };
256 |
257 | static const value_string mdb_cl_reader_sub_cmd[] = {
258 | { 0x00, "Reader Disable" },
259 | { 0x01, "Reader Enable" },
260 | { 0, NULL((void*)0) }
261 | };
262 |
263 | #define MDB_CL_EXPNS_REQ_ID0x00 0x00
264 | #define MDB_CL_EXPNS_OPT_ENA0x04 0x04
265 |
266 | static const value_string mdb_cl_expns_sub_cmd[] = {
267 | { MDB_CL_EXPNS_REQ_ID0x00, "Request ID" },
268 | { MDB_CL_EXPNS_OPT_ENA0x04, "Optional Feature Enabled" },
269 | { 0, NULL((void*)0) }
270 | };
271 |
272 | #define MDB_CL_RESP_RD_CFG_DATA0x01 0x01
273 | #define MDB_CL_RESP_VEND_APRV0x05 0x05
274 | #define MDB_CL_RESP_PER_ID0x09 0x09
275 |
276 | static const value_string mdb_cl_resp[] = {
277 | { 0x00, "Just Reset" },
278 | { MDB_CL_RESP_RD_CFG_DATA0x01, "Reader Config Data" },
279 | { 0x03, "Begin Session" },
280 | { MDB_CL_RESP_VEND_APRV0x05, "Vend Approved" },
281 | { 0x06, "Vend Denied" },
282 | { 0x07, "End Session" },
283 | { MDB_CL_RESP_PER_ID0x09, "Peripheral ID" },
284 | { 0x0b, "Cmd Out Of Sequence" },
285 | { 0, NULL((void*)0) }
286 | };
287 |
288 | /*
289 | * For the Communications Gateway, we use the complete address + command byte
290 | * as value for the value string. The values here match those in the MDB
291 | * specification.
292 | *
293 | * There's only one Communications Gateway, the address bits are always the
294 | * same. (This is different from the Cashless peripherals, see above.)
295 | */
296 | #define MDB_CGW_ADDR_CMD_SETUP0x19 0x19
297 | #define MDB_CGW_ADDR_CMD_REPORT0x1B 0x1B
298 | #define MDB_CGW_ADDR_CMD_EXPNS0x1F 0x1F
299 |
300 | static const value_string mdb_cgw_addr_cmd[] = {
301 | { 0x18, "Reset" },
302 | { MDB_CGW_ADDR_CMD_SETUP0x19, "Setup" },
303 | { 0x1A, "Poll" },
304 | { MDB_CGW_ADDR_CMD_REPORT0x1B, "Report" },
305 | { MDB_CGW_ADDR_CMD_EXPNS0x1F, "Expansion" },
306 | { 0, NULL((void*)0) }
307 | };
308 |
309 | #define MDB_CGW_REPORT_DTS_EVT0x02 0x02
310 |
311 | static const value_string mdb_cgw_report_sub_cmd[] = {
312 | { 0x01, "Transaction" },
313 | { MDB_CGW_REPORT_DTS_EVT0x02, "DTS Event" },
314 | { 0, NULL((void*)0) }
315 | };
316 |
317 | #define MDB_CGW_EXPNS_FEAT_ENA0x01 0x01
318 |
319 | static const value_string mdb_cgw_expns_sub_cmd[] = {
320 | { 0x00, "Identification" },
321 | { MDB_CGW_EXPNS_FEAT_ENA0x01, "Feature enable" },
322 | { 0x02, "Time/Date Request" },
323 | { 0, NULL((void*)0) }
324 | };
325 |
326 | #define MDB_CGW_RESP_CFG0x01 0x01
327 | #define MDB_CGW_RESP_PER_ID0x06 0x06
328 |
329 | static const value_string mdb_cgw_resp[] = {
330 | { 0x00, "Just Reset" },
331 | { MDB_CGW_RESP_CFG0x01, "Comms Gateway Config" },
332 | { 0x05, "DTS Event Acknowledge" },
333 | { MDB_CGW_RESP_PER_ID0x06, "Peripheral ID" },
334 | { 0, NULL((void*)0) }
335 | };
336 |
337 | /*
338 | * Commands for Bill Validator
339 | */
340 | #define MDB_BV_CMD_SETUP0x01 0x01
341 | #define MDB_BV_CMD_SECURITY0x02 0x02
342 | #define MDB_BV_CMD_POLL0x03 0x03
343 | #define MDB_BV_CMD_BILL_TYPE0x04 0x04
344 | #define MDB_BV_CMD_ESCROW0x05 0x05
345 | #define MDB_BV_CMD_STACKER0x06 0x06
346 | #define MDB_BV_CMD_EXPNS0x07 0x07
347 | #define MDB_BV_CMD_NONE0xFF 0xFF
348 |
349 | static const value_string mdb_bv_cmd[] = {
350 | { 0x00, "Reset" },
351 | { MDB_BV_CMD_SETUP0x01, "Setup" },
352 | { MDB_BV_CMD_SECURITY0x02, "Security" },
353 | { MDB_BV_CMD_POLL0x03, "Poll" },
354 | { MDB_BV_CMD_BILL_TYPE0x04, "Bill type" },
355 | { MDB_BV_CMD_ESCROW0x05, "Escrow" },
356 | { MDB_BV_CMD_STACKER0x06, "Stacker" },
357 | { MDB_BV_CMD_EXPNS0x07, "Expansion" },
358 | { 0, NULL((void*)0) }
359 | };
360 |
361 | #define MDB_BV_LVL1_WITHOUT_OPT_BITS0x00 0x00
362 | #define MDB_BV_LVL2_FEATURE_ENABLE0x01 0x01
363 | #define MDB_BV_LVL2_ID_WITH_OPTION_BITS0x02 0x02
364 | #define MDB_BV_RECYCL_SETUP0x03 0x03
365 | #define MDB_BV_RECYCL_ENABLE0x04 0x04
366 | #define MDB_BV_BILL_DISPENSE_STAT0x05 0x05
367 | #define MDB_BV_DISPENSE_BILL0x06 0x06
368 | #define MDB_BV_DISPENSE_VAL0x07 0x07
369 | #define MDB_BV_PAYOUT_STAT0x08 0x08
370 | #define MDB_BV_PAYOUT_VALUE_POLL0x09 0x09
371 | #define MDB_BV_PAYOUT_CANCEL0x0A 0x0A
372 |
373 | static const value_string mdb_bv_exp_cmd[] = {
374 | { MDB_BV_LVL1_WITHOUT_OPT_BITS0x00, "Level1 Identification without option bits" },
375 | { MDB_BV_LVL2_FEATURE_ENABLE0x01, "Level2+ Feature Enable" },
376 | { MDB_BV_LVL2_ID_WITH_OPTION_BITS0x02, "ID with Option Bits" },
377 | { MDB_BV_RECYCL_SETUP0x03, "Recycler Setup" },
378 | { MDB_BV_RECYCL_ENABLE0x04, "Recycler Enable" },
379 | { MDB_BV_BILL_DISPENSE_STAT0x05, "Bill Dispense Status" },
380 | { MDB_BV_DISPENSE_BILL0x06, "Dispense Bill" },
381 | { MDB_BV_DISPENSE_VAL0x07, "Dispense Value" },
382 | { MDB_BV_PAYOUT_STAT0x08, "Payout Status" },
383 | { MDB_BV_PAYOUT_VALUE_POLL0x09, "Payout Value Poll" },
384 | { MDB_BV_PAYOUT_CANCEL0x0A, "Payout Cancel" },
385 | { 0, NULL((void*)0) }
386 | };
387 |
388 | static const true_false_string mdb_bv_escrow_state = { "Escrow Stack Bill", "Escrow Return Bill" };
389 |
390 | // Format: 1yyyxxxx, where yyy = Bill routing, xxxx = Bill type (0 to 15)
391 | static const value_string mdb_bv_poll_bill_routing_state[] = {
392 | { 0x00, "Bill Stacked" },
393 | { 0x01, "Escrow Position" },
394 | { 0x02, "Bill Returned" },
395 | { 0x03, "Bill to Recycler" },
396 | { 0x04, "Disabled Bill Rejected" },
397 | { 0x05, "Bill to Recycler" },
398 | { 0x06, "Manual Dispense" },
399 | { 0x07, "Transferred from Recycler to Cashbox" },
400 | { 0, NULL((void*)0) }
401 | };
402 |
403 |
404 | static const value_string mdb_bv_poll_state[] = {
405 | /* Bill Validator (Only) */
406 | { 0x01, "Defective Motor" }, // One of the motors has failed to perform its expected assignment.
407 | { 0x02, "Sensor Problem" }, // One of the sensors has failed to provide its response.
408 | { 0x03, "Validator Busy" }, // The validator is busy and can not answer a detailed command right now.
409 | { 0x04, "ROM Checksum Error" }, // The validators internal checksum does not match the calculated checksum.
410 | { 0x05, "Validator Jammed" }, // A bill(s) has jammed in the acceptance path.
411 | { 0x06, "Validator was reset" }, // The validator has been reset since the last POLL.
412 | { 0x07, "Bill removed" }, // A bill in the escrow position has been removed by an unknown means. A BILL RETURNED message should also be sent.
413 | { 0x08, "Cash Box out of position" }, // The validator has detected the cash box to be open or removed.
414 | { 0x09, "Validator disabled" }, // The validator has been disabled, by the VMC or because of internal conditions.
415 | { 0x0A, "Invalid Escrow request" }, // An ESCROW command was requested for a bill not in the escrow position.
416 | { 0x0B, "Bill rejected" }, // A bill was detected, but rejected because it could not be identified.
417 | { 0x0C, "Possible Credited Bill Removal" }, // There has been an attempt to remove a credited (stacked) bill.
418 | { 0x40, "Disabled validator, number of attempts to input bill" }, // Format: 010xxxxx
419 | /* Bill Recycler (Only) */
420 | { 0x21, "Escrow request" }, // An escrow lever activation has been detected. If a button is present and activated.
421 | { 0x22, "Dispenser Payout Busy" }, // The dispenser is busy activating payout devices.
422 | { 0x23, "Dispenser Busy" }, // The dispenser is busy and can not answer a detailed command right now
423 | { 0x24, "Defective Dispenser Sensor" }, // The dispenser has detected one of the dispenser sensors behaving abnormally
424 |
425 | { 0x26, "Dispenser did not start / motor problem" },
426 | { 0x27, "Dispenser Jam" }, // A dispenser payout attempt has resulted in jammed condition.
427 | { 0x28, "ROM Checksum Error" }, // The dispensers internal checksum does not match the calculated checksum.
428 | // (If separate from validator microprocessor.)
429 | { 0x29, "Dispenser Disabled" }, // dispenser disabled because of error or bill in escrow position
430 | { 0x2A, "Bill Waiting" }, // waiting for customer removal
431 | { 0x2F, "Filled key pressed" }, // The VMC should request a new DISPENSER STATUS
432 | { 0, NULL((void*)0) }
433 | };
434 |
435 | static const value_string mdb_bv_exp_bills_recyc_enabled[] = {
436 | { 0x00, "Bill type disabled" },
437 | { 0x01, "Only High quality bills are used" },
438 | { 0x02, "Only High and Medium quality bills are used" },
439 | { 0x03, "Use all possible bills" },
440 | { 0, NULL((void*)0) }
441 | };
442 |
443 | static void dissect_mdb_ack(tvbuff_t *tvb, int offset,
444 | packet_info *pinfo, proto_tree *tree)
445 | {
446 | uint32_t ack;
447 |
448 | proto_tree_add_item_ret_uint(tree, hf_mdb_ack, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &ack);
449 | col_set_str(pinfo->cinfo, COL_INFO,
450 | val_to_str_const(ack, mdb_ack, "Invalid ack byte"));
451 | }
452 |
453 | static void mdb_set_addrs(uint8_t event, uint8_t addr, packet_info *pinfo)
454 | {
455 | const char *periph = val_to_str(pinfo->pool, addr, mdb_addr, "Unknown (0x%02x)");
456 |
457 | /* pinfo->p2p_dir is from the perspective of the master (VMC) */
458 |
459 | if (event == MDB_EVT_DATA_MST_PER0xFF) {
460 | set_address(&pinfo->src, AT_STRINGZ, (int)strlen(ADDR_VMC"VMC")+1, ADDR_VMC"VMC");
461 | set_address(&pinfo->dst, AT_STRINGZ, (int)strlen(periph)+1, periph);
462 | pinfo->p2p_dir = P2P_DIR_SENT0;
463 | }
464 | else if (event == MDB_EVT_DATA_PER_MST0xFE) {
465 | set_address(&pinfo->src, AT_STRINGZ, (int)strlen(periph)+1, periph);
466 | set_address(&pinfo->dst, AT_STRINGZ, (int)strlen(ADDR_VMC"VMC")+1, ADDR_VMC"VMC");
467 | pinfo->p2p_dir = P2P_DIR_RECV1;
468 | }
469 | }
470 |
471 | static void mdb_add_checksum(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int total_len)
472 | {
473 | if (total_len <= 1) return;
474 | uint8_t calculated_checksum = 0;
475 |
476 | for (int i = 0; i < total_len - 1; i++) {
477 | uint8_t val = tvb_get_uint8(tvb, offset + i);
478 | /* The MDB checksum is a simple sum modulo 256. Using uint8_t
479 | * causes an intentional wrap-around that perfectly matches the modulo.
480 | */
481 | calculated_checksum += val;
482 | }
483 |
484 | proto_tree_add_checksum(tree, tvb, offset + total_len - 1, hf_mdb_chk, hf_mdb_chk_status, &ei_mdb_bad_checksum, pinfo, calculated_checksum, ENC_BIG_ENDIAN0x00000000, PROTO_CHECKSUM_VERIFY0x01);
485 | }
486 |
487 | static void dissect_mdb_cl_setup(tvbuff_t *tvb, int offset,
488 | packet_info *pinfo, proto_tree *tree)
489 | {
490 | uint32_t sub_cmd, price;
491 | const char *s;
492 | proto_item *pi;
493 |
494 | proto_tree_add_item_ret_uint(tree, hf_mdb_cl_setup_sub,
495 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &sub_cmd);
496 | s = try_val_to_str(sub_cmd, mdb_cl_setup_sub_cmd);
497 | if (s) {
498 | col_set_str(pinfo->cinfo, COL_INFO, s);
499 | }
500 | offset++;
501 |
502 | switch (sub_cmd) {
503 | case MDB_CL_SETUP_CFG_DATA0x00:
504 | proto_tree_add_item(tree, hf_mdb_cl_feat_lvl, tvb, offset, 1,
505 | ENC_BIG_ENDIAN0x00000000);
506 | offset++;
507 | proto_tree_add_item(tree, hf_mdb_cl_cols, tvb, offset, 1,
508 | ENC_BIG_ENDIAN0x00000000);
509 | offset++;
510 | proto_tree_add_item(tree, hf_mdb_cl_rows, tvb, offset, 1,
511 | ENC_BIG_ENDIAN0x00000000);
512 | offset++;
513 | proto_tree_add_item(tree, hf_mdb_cl_disp_info, tvb, offset, 1,
514 | ENC_BIG_ENDIAN0x00000000);
515 | break;
516 |
517 | case MDB_CL_SETUP_MAX_MIN0x01:
518 | if (tvb_reported_length_remaining(tvb, offset) == 5) {
519 | /* This is the "default version" of Max/Min Prices. */
520 |
521 | /* XXX - convert the scaled prices into actual amounts */
522 | pi = proto_tree_add_item_ret_uint(tree, hf_mdb_cl_max_price,
523 | tvb, offset, 2, ENC_BIG_ENDIAN0x00000000, &price);
524 | if (price == 0xFFFF) {
525 | proto_item_append_text(pi, " (unknown)");
526 | }
527 | offset += 2;
528 |
529 | pi = proto_tree_add_item_ret_uint(tree, hf_mdb_cl_min_price,
530 | tvb, offset, 2, ENC_BIG_ENDIAN0x00000000, &price);
531 | if (price == 0x0000) {
532 | proto_item_append_text(pi, " (unknown)");
533 | }
534 | }
535 | else if (tvb_reported_length_remaining(tvb, offset) == 11) {
536 | /* This is the "expanded currency version" of Max/Min Prices. */
537 |
538 | proto_tree_add_item(tree, hf_mdb_cl_max_price, tvb, offset, 4,
539 | ENC_BIG_ENDIAN0x00000000);
540 | offset += 4;
541 | proto_tree_add_item(tree, hf_mdb_cl_min_price, tvb, offset, 4,
542 | ENC_BIG_ENDIAN0x00000000);
543 | }
544 | /* XXX - expert info for other lengths */
545 | break;
546 | }
547 | }
548 |
549 | static void dissect_mdb_cl_vend(tvbuff_t *tvb, int offset,
550 | packet_info *pinfo, proto_tree *tree)
551 | {
552 | uint32_t sub_cmd, price, item;
553 | const char *s;
554 |
555 | proto_tree_add_item_ret_uint(tree, hf_mdb_cl_vend_sub, tvb, offset, 1,
556 | ENC_BIG_ENDIAN0x00000000, &sub_cmd);
557 | s = try_val_to_str(sub_cmd, mdb_cl_vend_sub_cmd);
558 | if (s) {
559 | col_set_str(pinfo->cinfo, COL_INFO, s);
560 | }
561 | offset++;
562 |
563 | switch (sub_cmd) {
564 | case MDB_CL_VEND_REQ0x00:
565 | if (tvb_reported_length_remaining(tvb, offset) == 5) {
566 | proto_tree_add_item_ret_uint(tree, hf_mdb_cl_item_price, tvb,
567 | offset, 2, ENC_BIG_ENDIAN0x00000000, &price);
568 | offset += 2;
569 | proto_tree_add_item_ret_uint(tree, hf_mdb_cl_item_num, tvb,
570 | offset, 2, ENC_BIG_ENDIAN0x00000000, &item);
571 | col_append_fstr(pinfo->cinfo, COL_INFO, " (item %d, price %d)",
572 | item, price);
573 | }
574 | /* XXX - dissect the longer request in Expanded Currency Mode */
575 | break;
576 | case MDB_CL_VEND_SUC0x02:
577 | proto_tree_add_item(tree, hf_mdb_cl_item_num, tvb, offset, 2,
578 | ENC_BIG_ENDIAN0x00000000);
579 | break;
580 | }
581 | }
582 |
583 | static int
584 | dissect_mdb_cl_id_fields(tvbuff_t *tvb, int offset, proto_tree *tree)
585 | {
586 | proto_tree_add_item(tree, hf_mdb_cl_manuf_code, tvb, offset, 3, ENC_ASCII0x00000000);
587 | offset += 3;
588 | proto_tree_add_item(tree, hf_mdb_cl_ser_num, tvb, offset, 12, ENC_ASCII0x00000000);
589 | offset += 12;
590 | proto_tree_add_item(tree, hf_mdb_cl_mod_num, tvb, offset, 12, ENC_ASCII0x00000000);
591 | offset += 12;
592 | /* XXX - dissect the Software Version bytes */
593 | offset += 2;
594 |
595 | return offset;
596 | }
597 |
598 | static void dissect_mdb_cl_expns(tvbuff_t *tvb, int offset, packet_info *pinfo,
599 | proto_tree *tree)
600 | {
601 | uint32_t sub_cmd;
602 | const char *s;
603 |
604 | proto_tree_add_item_ret_uint(tree, hf_mdb_cl_expns_sub,
605 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &sub_cmd);
606 | s = try_val_to_str(sub_cmd, mdb_cl_expns_sub_cmd);
607 | if (s) {
608 | col_set_str(pinfo->cinfo, COL_INFO, s);
609 | }
610 | offset++;
611 |
612 | switch (sub_cmd) {
613 | case MDB_CL_EXPNS_REQ_ID0x00:
614 | dissect_mdb_cl_id_fields(tvb, offset, tree);
615 | break;
616 | case MDB_CL_EXPNS_OPT_ENA0x04:
617 | /* XXX - add a bitmask for the Optional Feature Bits */
618 | proto_tree_add_item(tree, hf_mdb_cl_opt_feat, tvb, offset, 4,
619 | ENC_BIG_ENDIAN0x00000000);
620 | break;
621 | }
622 | }
623 |
624 | static void dissect_mdb_cl_rd_cfg_data(tvbuff_t *tvb, int offset,
625 | packet_info *pinfo _U___attribute__((unused)), proto_tree *tree)
626 | {
627 | proto_tree_add_item(tree, hf_mdb_cl_feat_lvl, tvb, offset, 1,
628 | ENC_BIG_ENDIAN0x00000000);
629 | offset++;
630 | /* XXX - dissect Country/Currency Code */
631 | offset += 2;
632 | proto_tree_add_item(tree, hf_mdb_cl_scale, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
633 | offset++;
634 | proto_tree_add_item(tree, hf_mdb_cl_dec_pl, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
635 | offset++;
636 | proto_tree_add_item(tree, hf_mdb_cl_max_rsp_time, tvb, offset, 1,
637 | ENC_TIME_SECS0x00000012 | ENC_BIG_ENDIAN0x00000000);
638 | }
639 |
640 | static void dissect_mdb_mst_per_cl( tvbuff_t *tvb, int offset, int len _U___attribute__((unused)),
641 | packet_info *pinfo, proto_tree *tree, proto_item *cmd_it,
642 | uint8_t addr_byte, mdb_conv_info_t* conv_info _U___attribute__((unused)))
643 | {
644 | uint8_t cmd = addr_byte & 0x07; /* the 3-bit command */
645 | proto_tree *cl_tree;
646 | uint32_t sub_cmd;
647 | const char *s;
648 |
649 | s = val_to_str_const(cmd, mdb_cl_cmd, "Unknown");
650 | proto_item_append_text(cmd_it, " (%s)", s);
651 | col_set_str(pinfo->cinfo, COL_INFO, s);
652 |
653 | cl_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_cl,
654 | NULL((void*)0), "Cashless");
655 |
656 | s = NULL((void*)0);
657 | switch (cmd) {
658 | case MDB_CL_CMD_SETUP0x01:
659 | dissect_mdb_cl_setup(tvb, offset, pinfo, cl_tree);
660 | break;
661 | case MDB_CL_CMD_VEND0x03:
662 | dissect_mdb_cl_vend(tvb, offset, pinfo, cl_tree);
663 | break;
664 | case MDB_CL_CMD_READER0x04:
665 | proto_tree_add_item_ret_uint(cl_tree, hf_mdb_cl_reader_sub,
666 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &sub_cmd);
667 | s = try_val_to_str(sub_cmd, mdb_cl_reader_sub_cmd);
668 | break;
669 | case MDB_CL_CMD_EXPNS0x07:
670 | dissect_mdb_cl_expns(tvb, offset, pinfo, cl_tree);
671 | break;
672 | }
673 | if (s)
674 | col_set_str(pinfo->cinfo, COL_INFO, s);
675 | }
676 |
677 | static void dissect_mdb_per_mst_cl( tvbuff_t *tvb, int offset,
678 | int len _U___attribute__((unused)), packet_info *pinfo, proto_tree *tree, mdb_conv_info_t* conv_info _U___attribute__((unused)))
679 | {
680 | proto_tree *cl_tree;
681 | uint32_t cl_resp;
682 |
683 | cl_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_cl,
684 | NULL((void*)0), "Cashless");
685 |
686 | proto_tree_add_item_ret_uint(cl_tree, hf_mdb_cl_resp, tvb, offset, 1,
687 | ENC_BIG_ENDIAN0x00000000, &cl_resp);
688 | col_set_str(pinfo->cinfo,
689 | COL_INFO, val_to_str_const(cl_resp, mdb_cl_resp, "Unknown"));
690 | offset++;
691 |
692 | switch (cl_resp) {
693 | case MDB_CL_RESP_RD_CFG_DATA0x01:
694 | dissect_mdb_cl_rd_cfg_data(tvb, offset, pinfo, cl_tree);
695 | break;
696 | case MDB_CL_RESP_VEND_APRV0x05:
697 | if (tvb_reported_length_remaining(tvb, offset) == 3) {
698 | proto_tree_add_item(cl_tree, hf_mdb_cl_vend_amt, tvb, offset,
699 | 2, ENC_BIG_ENDIAN0x00000000);
700 | }
701 | /* XXX - dissect the longer response in Expanded Currency Mode */
702 | break;
703 | case MDB_CL_RESP_PER_ID0x09:
704 | dissect_mdb_cl_id_fields(tvb, offset, tree);
705 | /* XXX - check if we have Optional Feature Bits */
706 | break;
707 | }
708 | }
709 |
710 | static void dissect_mdb_cgw_report(tvbuff_t *tvb, int offset,
711 | packet_info *pinfo, proto_tree *tree)
712 | {
713 | uint32_t sub_cmd;
714 | const char *s;
715 |
716 | proto_tree_add_item_ret_uint(tree, hf_mdb_cgw_report_sub,
717 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &sub_cmd);
718 | s = try_val_to_str(sub_cmd, mdb_cgw_report_sub_cmd);
719 | if (s) {
720 | col_set_str(pinfo->cinfo, COL_INFO, s);
721 | }
722 | offset++;
723 |
724 | switch (sub_cmd) {
725 | case MDB_CGW_REPORT_DTS_EVT0x02:
726 | proto_tree_add_item(tree, hf_mdb_cgw_dts_evt_code, tvb, offset, 10,
727 | ENC_ASCII0x00000000);
728 | offset += 10;
729 | /* XXX - dissect Date */
730 | offset += 4;
731 | /* XXX - dissect Time */
732 | offset += 2;
733 | proto_tree_add_item(tree, hf_mdb_cgw_duration, tvb, offset, 4,
734 | ENC_BIG_ENDIAN0x00000000);
735 | offset += 4;
736 | proto_tree_add_item(tree, hf_mdb_cgw_activity, tvb, offset, 1,
737 | ENC_BIG_ENDIAN0x00000000);
738 | break;
739 | }
740 | }
741 |
742 | static void dissect_mdb_cgw_expns(tvbuff_t *tvb, int offset,
743 | packet_info *pinfo, proto_tree *tree)
744 | {
745 | uint32_t sub_cmd;
746 | const char *s;
747 |
748 | proto_tree_add_item_ret_uint(tree, hf_mdb_cgw_expns_sub,
749 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &sub_cmd);
750 | s = try_val_to_str(sub_cmd, mdb_cgw_expns_sub_cmd);
751 | if (s) {
752 | col_set_str(pinfo->cinfo, COL_INFO, s);
753 | }
754 | offset++;
755 |
756 | switch (sub_cmd) {
757 | case MDB_CGW_EXPNS_FEAT_ENA0x01:
758 | proto_tree_add_item(tree, hf_mdb_cgw_opt_feat, tvb, offset, 4,
759 | ENC_BIG_ENDIAN0x00000000);
760 | break;
761 | }
762 | }
763 |
764 | static void dissect_mdb_mst_per_cgw( tvbuff_t *tvb, int offset, int len,
765 | packet_info *pinfo, proto_tree *tree, proto_item *cmd_it,
766 | uint8_t addr_cmd_byte, mdb_conv_info_t* conv_info _U___attribute__((unused)))
767 | {
768 | proto_tree *cgw_tree;
769 | const char *s;
770 |
771 | s = val_to_str_const(addr_cmd_byte, mdb_cgw_addr_cmd, "Unknown");
772 | proto_item_append_text(cmd_it, " (%s)", s);
773 | col_set_str(pinfo->cinfo, COL_INFO, s);
774 |
775 | cgw_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_cgw,
776 | NULL((void*)0), "Communications Gateway");
777 |
778 | switch (addr_cmd_byte) {
779 | case MDB_CGW_ADDR_CMD_SETUP0x19:
780 | proto_tree_add_item(cgw_tree, hf_mdb_cgw_feat_lvl, tvb, offset, 1,
781 | ENC_BIG_ENDIAN0x00000000);
782 | offset++;
783 | proto_tree_add_item(cgw_tree, hf_mdb_cgw_scale, tvb, offset, 1,
784 | ENC_BIG_ENDIAN0x00000000);
785 | offset++;
786 | proto_tree_add_item(cgw_tree, hf_mdb_cgw_dec_pl, tvb, offset, 1,
787 | ENC_BIG_ENDIAN0x00000000);
788 | break;
789 | case MDB_CGW_ADDR_CMD_REPORT0x1B:
790 | dissect_mdb_cgw_report(tvb, offset, pinfo, cgw_tree);
791 | break;
792 | case MDB_CGW_ADDR_CMD_EXPNS0x1F:
793 | dissect_mdb_cgw_expns(tvb, offset, pinfo, cgw_tree);
794 | break;
795 | }
796 | }
797 |
798 | static void dissect_mdb_per_mst_cgw( tvbuff_t *tvb, int offset,
799 | int len, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, mdb_conv_info_t* conv_info _U___attribute__((unused)))
800 | {
801 | proto_tree *cgw_tree;
802 | uint32_t cgw_resp;
803 |
804 | cgw_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_cgw,
805 | NULL((void*)0), "Communications Gateway");
806 |
807 | proto_tree_add_item_ret_uint(cgw_tree, hf_mdb_cgw_resp, tvb, offset, 1,
808 | ENC_BIG_ENDIAN0x00000000, &cgw_resp);
809 | col_set_str(pinfo->cinfo,
810 | COL_INFO, val_to_str_const(cgw_resp, mdb_cgw_resp, "Unknown"));
811 | offset++;
812 |
813 | switch (cgw_resp) {
814 | case MDB_CGW_RESP_CFG0x01:
815 | proto_tree_add_item(cgw_tree, hf_mdb_cgw_feat_lvl, tvb, offset, 1,
816 | ENC_BIG_ENDIAN0x00000000);
817 | offset++;
818 | proto_tree_add_item(cgw_tree, hf_mdb_cgw_max_rsp_time, tvb, offset,
819 | 2, ENC_TIME_SECS0x00000012 | ENC_BIG_ENDIAN0x00000000);
820 | break;
821 | case MDB_CGW_RESP_PER_ID0x06:
822 | proto_tree_add_item(tree, hf_mdb_cgw_manuf_code, tvb, offset, 3,
823 | ENC_ASCII0x00000000);
824 | offset += 3;
825 | proto_tree_add_item(tree, hf_mdb_cgw_ser_num, tvb, offset, 12,
826 | ENC_ASCII0x00000000);
827 | offset += 12;
828 | proto_tree_add_item(tree, hf_mdb_cgw_mod_num, tvb, offset, 12,
829 | ENC_ASCII0x00000000);
830 | offset += 12;
831 | /* XXX - dissect the Software Version bytes */
832 | offset += 2;
833 | proto_tree_add_item(tree, hf_mdb_cgw_opt_feat, tvb, offset, 4,
834 | ENC_BIG_ENDIAN0x00000000);
835 | break;
836 | }
837 | }
838 |
839 | static int dissect_mdb_bv_setup_fields(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
840 | {
841 | wmem_strbuf_t* bill_str = wmem_strbuf_new(pinfo->pool, "");
842 |
843 | proto_tree_add_item(tree, hf_mdb_bv_setup_bill_val_feature, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
844 | offset += 1;
845 | proto_tree_add_item(tree, hf_mdb_bv_setup_ctry_currency_code, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
846 | offset += 2;
847 | proto_tree_add_item(tree, hf_mdb_bv_setup_bill_scal_fac, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
848 | offset += 2;
849 | proto_tree_add_item(tree, hf_mdb_bv_setup_dec_places, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
850 | offset += 1;
851 | proto_tree_add_item(tree, hf_mdb_bv_setup_bill_stacker_cap, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
852 | offset += 2;
853 | proto_tree_add_item(tree, hf_mdb_bv_setup_bill_sec_lvls, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
854 | offset += 2;
855 | proto_tree_add_item(tree, hf_mdb_bv_setup_escrow, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
856 | offset += 1;
857 |
858 | uint8_t bill_val;
859 | for (int i = 0; i < 16; i++) {
860 | bill_val = tvb_get_uint8(tvb, offset + i);
861 | // Append each bill value to comma separated string
862 | wmem_strbuf_append_printf(bill_str, "%u%s", bill_val, (i < 15) ? "," : "");
863 | }
864 | // Add the formatted string to the protocol tree
865 | proto_tree_add_string_format_value(tree, hf_mdb_bv_setup_bill_type_cred, tvb, offset, 16,
866 | bill_str->str, "Bill values: %s", bill_str->str);
867 | offset += 16;
868 |
869 | return offset;
870 | }
871 |
872 | static int dissect_mdb_bv_poll_stat_bill_accept(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
873 | {
874 | uint32_t bill_routing;
875 |
876 | proto_tree_add_item_ret_uint(tree, hf_mdb_bv_poll_bill_routing_state, tvb, offset, 1, ENC_NA0x00000000, &bill_routing);
877 | proto_tree_add_item(tree, hf_mdb_bv_poll_bill_type, tvb, offset, 1, ENC_NA0x00000000);
878 |
879 | col_add_str(pinfo->cinfo, COL_INFO,
880 | val_to_str(pinfo->pool, bill_routing, mdb_bv_poll_bill_routing_state, "Unknown Bill Routing: 0x%x"));
881 |
882 | offset += 1;
883 |
884 | return offset;
885 | }
886 |
887 | static int dissect_mdb_bv_poll_fields(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
888 | {
889 | uint8_t cmd = tvb_get_uint8(tvb, offset);
890 |
891 | if (cmd & 0x80)
892 | {
893 | // Bills Accepted response
894 | dissect_mdb_bv_poll_stat_bill_accept(tvb, offset, pinfo, tree);
895 | offset += 1;
896 | }
897 | else if (cmd > 0x1A)
898 | {
899 | // File transport layer response
900 | offset += 1;
901 | }
902 | else
903 | {
904 | proto_tree_add_item(tree, hf_mdb_bv_poll_state, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
905 | col_add_str(pinfo->cinfo, COL_INFO,
906 | val_to_str(pinfo->pool, cmd, mdb_bv_poll_state, "Unknown Poll Response 0x%x"));
907 | offset += 1;
908 | }
909 |
910 | return offset;
911 | }
912 |
913 | static int dissect_mdb_bv_bill_type(tvbuff_t *tvb, int offset, proto_tree *tree)
914 | {
915 | proto_tree_add_item(tree, hf_mdb_bv_bill_enable, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
916 | offset += 2;
917 | proto_tree_add_item(tree, hf_mdb_bv_bill_escrow_enable, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
918 | offset += 2;
919 |
920 | return offset;
921 | }
922 |
923 | static int dissect_mdb_bv_escrow(tvbuff_t *tvb, int offset, proto_tree *tree)
924 | {
925 | proto_tree_add_item(tree, hf_mdb_bv_escrow_state, tvb, offset, 1, ENC_NA0x00000000);
926 | offset += 1;
927 |
928 | return offset;
929 | }
930 |
931 | static int dissect_mdb_bv_stacker(tvbuff_t *tvb, int offset, proto_tree *tree)
932 | {
933 | proto_tree_add_item(tree, hf_mdb_bv_stacker, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
934 | offset += 2;
935 |
936 | return offset;
937 | }
938 |
939 | static int dissect_mdb_bv_exp_id_opt_fields(tvbuff_t *tvb, int offset,
940 | proto_tree *tree, bool_Bool opt_features)
941 | {
942 | proto_tree_add_item(tree, hf_mdb_bv_exp_manufact_code, tvb, offset, 3, ENC_ASCII0x00000000);
943 | offset += 3;
944 | proto_tree_add_item(tree, hf_mdb_bv_exp_serial_num, tvb, offset, 12, ENC_ASCII0x00000000);
945 | offset += 12;
946 | proto_tree_add_item(tree, hf_mdb_bv_exp_model_tuning_num, tvb, offset, 12, ENC_ASCII0x00000000);
947 | offset += 12;
948 | proto_tree_add_item(tree, hf_mdb_bv_exp_software_version, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
949 | offset += 2;
950 | // Only for cmd 37 02
951 | if (opt_features) {
952 | proto_tree_add_item(tree, hf_mdb_bv_exp_opt_feat, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
953 | offset += 4;
954 | }
955 |
956 | return offset;
957 | }
958 |
959 | static int dissect_mdb_bv_exp_recycler_setup(tvbuff_t *tvb, int offset, proto_tree *tree)
960 | {
961 | proto_tree_add_item(tree, hf_mdb_bv_exp_manual_dispense_enable, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
962 | offset += 2;
963 |
964 | return offset;
965 | }
966 |
967 | static int dissect_mdb_bv_exp_recycler_enable(tvbuff_t *tvb, int offset, proto_tree *tree)
968 | {
969 | proto_tree_add_item(tree, hf_mdb_bv_exp_bill_type_routing, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
970 | offset += 2;
971 |
972 | for (int i = 0; i < 16; i++) {
973 | proto_tree_add_item(tree, hf_mdb_bv_exp_bill_recycler_enabled, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
974 | offset += 1;
975 | }
976 |
977 | return offset;
978 | }
979 |
980 | static int dissect_mdb_bv_exp_dispense_status(tvbuff_t *tvb, int offset, proto_tree *tree)
981 | {
982 | proto_tree_add_item(tree, hf_mdb_bv_exp_dispenser_full_state, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
983 | offset += 2;
984 | for (int i = 0; i < 32; i++) {
985 | proto_tree_add_item(tree, hf_mdb_bv_exp_bill_count, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
986 | offset += 1;
987 | }
988 |
989 | return offset;
990 | }
991 |
992 | static int dissect_mdb_bv_exp_dispense_bill(tvbuff_t *tvb, int offset, proto_tree *tree)
993 | {
994 | proto_tree_add_item(tree, hf_mdb_bv_exp_bill_type_dispensed, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
995 | offset += 1;
996 | proto_tree_add_item(tree, hf_mdb_bv_exp_bill_type_number_bills, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
997 | offset += 2;
998 |
999 | return offset;
1000 | }
1001 |
1002 | static int dissect_mdb_bv_exp_dispense_value_bill(tvbuff_t *tvb, int offset, proto_tree *tree)
1003 | {
1004 | proto_tree_add_item(tree, hf_mdb_bv_exp_dispense_value_bills, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
1005 | offset += 2;
1006 |
1007 | return offset;
1008 | }
1009 |
1010 | static int dissect_mdb_bv_exp_payout_status(tvbuff_t *tvb, int offset, proto_tree *tree)
1011 | {
1012 | for (int i = 0; i < 16; i++) {
1013 | proto_tree_add_item(tree, hf_mdb_bv_exp_payout_state, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
1014 | offset += 2;
1015 | }
1016 |
1017 | return offset;
1018 | }
1019 |
1020 | static int dissect_mdb_bv_exp_payout_value_poll(tvbuff_t *tvb, int offset, proto_tree *tree)
1021 | {
1022 | proto_tree_add_item(tree, hf_mdb_bv_exp_dispenser_payout_activity, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000);
1023 | offset += 2;
1024 |
1025 | return offset;
1026 | }
1027 |
1028 | static void dissect_mdb_bv_expns_mst_per(tvbuff_t *tvb, int offset, packet_info *pinfo,
1029 | proto_tree *tree)
1030 | {
1031 | const char *s;
1032 | uint32_t sub_cmd = tvb_get_uint8(tvb, offset);
1033 |
1034 | s = try_val_to_str(sub_cmd, mdb_bv_exp_cmd);
1035 | if (s) {
1036 | col_set_str(pinfo->cinfo, COL_INFO, s);
1037 | }
1038 |
1039 | switch (sub_cmd) {
1040 | case MDB_BV_LVL2_FEATURE_ENABLE0x01:
1041 | proto_tree_add_item(tree, hf_mdb_bv_exp_opt_feat_enable, tvb, offset, 4,
1042 | ENC_BIG_ENDIAN0x00000000);
1043 | break;
1044 | case MDB_BV_RECYCL_ENABLE0x04:
1045 | dissect_mdb_bv_exp_recycler_enable(tvb, offset, tree);
1046 | break;
1047 | case MDB_BV_DISPENSE_BILL0x06:
1048 | dissect_mdb_bv_exp_dispense_bill(tvb, offset, tree);
1049 | break;
1050 | case MDB_BV_DISPENSE_VAL0x07:
1051 | dissect_mdb_bv_exp_dispense_value_bill(tvb, offset, tree);
1052 | break;
1053 | case MDB_BV_PAYOUT_CANCEL0x0A:
1054 | // Nothing to dissect
1055 | break;
1056 | }
1057 | }
1058 |
1059 | static void dissect_mdb_bv_expns_per_mst(tvbuff_t *tvb, int offset, proto_tree *tree, uint16_t cmd)
1060 | {
1061 | uint8_t sub_cmd = cmd >> SUB_CMD_OFFSET8;
1062 |
1063 | switch (sub_cmd) {
1064 | case MDB_BV_LVL1_WITHOUT_OPT_BITS0x00:
1065 | dissect_mdb_bv_exp_id_opt_fields(tvb, offset, tree, false0);
1066 | break;
1067 | case MDB_BV_LVL2_ID_WITH_OPTION_BITS0x02:
1068 | dissect_mdb_bv_exp_id_opt_fields(tvb, offset, tree, true1);
1069 | break;
1070 | case MDB_BV_RECYCL_SETUP0x03:
1071 | dissect_mdb_bv_exp_recycler_setup(tvb, offset, tree);
1072 | break;
1073 | case MDB_BV_BILL_DISPENSE_STAT0x05:
1074 | dissect_mdb_bv_exp_dispense_status(tvb, offset, tree);
1075 | break;
1076 | case MDB_BV_PAYOUT_STAT0x08:
1077 | dissect_mdb_bv_exp_payout_status(tvb, offset, tree);
1078 | break;
1079 | case MDB_BV_PAYOUT_VALUE_POLL0x09:
1080 | dissect_mdb_bv_exp_payout_value_poll(tvb, offset, tree);
1081 | break;
1082 | // FTL Expansion commands not implemented yet
1083 | }
1084 | }
1085 |
1086 | static void dissect_mdb_mst_per_bv( tvbuff_t *tvb, int offset, int len,
1087 | packet_info *pinfo, proto_tree *tree, proto_item *cmd_it,
1088 | uint8_t addr_cmd_byte, mdb_conv_info_t* conv_info)
1089 | {
1090 | uint8_t cmd = CMD_MASK0x07 & addr_cmd_byte; /* the 3-bit command */
1091 | proto_tree *bv_tree;
1092 | mdb_transaction_t* transaction;
1093 | uint8_t sub_cmd = 0;
1094 | const char *s;
1095 |
1096 | s = val_to_str(pinfo->pool, cmd, mdb_bv_cmd, "Unknown Command: 0x%x");
1097 | proto_item_append_text(cmd_it, " (%s)", s);
1098 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s (Request)", s);
1099 |
1100 | bv_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_bv,
1101 | NULL((void*)0), "Bill Validator");
1102 |
1103 | switch (cmd) {
1104 | case MDB_BV_CMD_SETUP0x01:
1105 | break;
1106 | case MDB_BV_CMD_SECURITY0x02:
1107 | break;
1108 | case MDB_BV_CMD_BILL_TYPE0x04:
1109 | dissect_mdb_bv_bill_type(tvb, offset, bv_tree);
1110 | break;
1111 | case MDB_BV_CMD_ESCROW0x05:
1112 | dissect_mdb_bv_escrow(tvb, offset, bv_tree);
1113 | break;
1114 | case MDB_BV_CMD_STACKER0x06:
1115 | break;
1116 | case MDB_BV_CMD_EXPNS0x07:
1117 | sub_cmd = tvb_get_uint8(tvb, offset);
1118 | dissect_mdb_bv_expns_mst_per(tvb, offset, pinfo, bv_tree);
1119 | break;
1120 | }
1121 |
1122 | if (!pinfo->fd->visited)
1123 | {
1124 | //Create the request information
1125 | transaction = wmem_new0(wmem_file_scope(), mdb_transaction_t)((mdb_transaction_t*)wmem_alloc0((wmem_file_scope()), sizeof( mdb_transaction_t)));
1126 | transaction->req_num = pinfo->num;
1127 | transaction->req_time = pinfo->abs_ts;
1128 |
1129 | // If not MDB_BV_CMD_EXPNS, then sub_cmd is just 0
1130 | transaction->cmd = (cmd | (sub_cmd << SUB_CMD_OFFSET8));
1131 | wmem_tree_insert32(conv_info->transactions, pinfo->num, (void*)transaction);
1132 | conv_info->last_cmd = transaction->cmd;
1133 | conv_info->last_req_packet = pinfo->num;
1134 | }
1135 | else
1136 | {
1137 | transaction = (mdb_transaction_t*)wmem_tree_lookup32_le(conv_info->transactions, pinfo->num);
1138 | }
1139 |
1140 | if ((transaction != NULL((void*)0)) && (transaction->rep_num))
1141 | {
1142 | proto_item* it = proto_tree_add_uint(tree, hf_mdb_response_in, NULL((void*)0), 0, 0, transaction->rep_num);
1143 | proto_item_set_generated(it);
1144 |
1145 | }
1146 | }
1147 |
1148 |
1149 | static void dissect_mdb_mst_per(tvbuff_t *tvb, int offset, packet_info *pinfo,
1150 | proto_tree *tree)
1151 | {
1152 | uint8_t addr_byte, addr;
1153 | int mst_per_len;
1154 | unsigned data_len;
1155 | proto_item *cmd_it;
1156 |
1157 | mst_per_len = tvb_reported_length_remaining(tvb, offset);
1158 | if (mst_per_len <= 0) {
1159 | expert_add_info(pinfo, tree, &ei_mdb_short_packet);
1160 | return;
1161 | }
1162 |
1163 | if (mst_per_len == 1) {
1164 | dissect_mdb_ack(tvb, offset, pinfo, tree);
1165 | return;
1166 | }
1167 |
1168 | /*
1169 | * Our packet has one address byte, an optional data block and one
1170 | * checksum byte.
1171 | */
1172 |
1173 | data_len = mst_per_len - 2;
1174 | int start_offset = offset;
1175 |
1176 | /*
1177 | * The address byte is 5-bit address | 3-bit command.
1178 | *
1179 | * The specification uses 8-bit addresses which are the address byte
1180 | * with the three lowest bits set to 0.
1181 | *
1182 | * The commands are defined as the complete address byte (i.e. they
1183 | * include the address part). This does not make much sense: Cashless #1
1184 | * and #2 have different addresses but exactly the same 3-bit commands.
1185 | *
1186 | * In this dissector, we try to use the same values as the specification.
1187 | */
1188 | addr_byte = tvb_get_uint8(tvb, offset);
1189 | addr = addr_byte & ADDR_MASK0xF8;
1190 | proto_tree_add_uint_bits_format_value(tree, hf_mdb_addr,
1191 | tvb, 8*offset, 5, addr, ENC_BIG_ENDIAN0x00000000, "0x%02x", addr);
1192 | cmd_it = proto_tree_add_uint(tree, hf_mdb_cmd, tvb, offset, 1, addr_byte & CMD_MASK0x07);
1193 | mdb_set_addrs(MDB_EVT_DATA_MST_PER0xFF, addr, pinfo);
1194 | mdb_conv_info_t* conv_info = get_mdb_conv_info(pinfo);
1195 | offset++;
1196 |
1197 | /*
1198 | * We call the peripheral functions even if data_len == 0 so they can fix
1199 | * up the command with peripheral-specific info.
1200 | */
1201 | switch (addr) {
1202 | case ADDR_CASHLESS10x10:
1203 | dissect_mdb_mst_per_cl(tvb, offset, data_len, pinfo, tree,
1204 | cmd_it, addr_byte, conv_info);
1205 | break;
1206 | case ADDR_COMMS_GW0x18:
1207 | dissect_mdb_mst_per_cgw(tvb, offset, data_len, pinfo, tree,
1208 | cmd_it, addr_byte, conv_info);
1209 | break;
1210 | case ADDR_BILL_VALIDATOR0x30:
1211 | dissect_mdb_mst_per_bv(tvb, offset, data_len, pinfo, tree,
1212 | cmd_it, addr_byte, conv_info);
1213 | break;
1214 | default:
1215 | if (data_len > 0) {
1216 | proto_tree_add_item(tree, hf_mdb_data,
1217 | tvb, offset, data_len, ENC_NA0x00000000);
1218 | }
1219 | break;
1220 | }
1221 | offset += data_len;
| Value stored to 'offset' is never read
1222 |
1223 | /* Verify the checksum */
1224 | mdb_add_checksum(tvb, pinfo, tree, start_offset, data_len + 2);
1225 | }
1226 |
1227 | static void dissect_mdb_per_mst_bv( tvbuff_t *tvb, int offset,
1228 | int len, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree, mdb_conv_info_t* conv_info)
1229 | {
1230 | proto_tree *bv_tree;
1231 | mdb_transaction_t* transaction;
1232 |
1233 | if (!pinfo->fd->visited)
1234 | {
1235 | transaction = (mdb_transaction_t*)wmem_tree_lookup32_le(conv_info->transactions, conv_info->last_req_packet);
1236 | if (transaction)
1237 | {
1238 | transaction->rep_num = pinfo->num;
1239 | }
1240 | else
1241 | {
1242 | transaction = wmem_new0(wmem_file_scope(), mdb_transaction_t)((mdb_transaction_t*)wmem_alloc0((wmem_file_scope()), sizeof( mdb_transaction_t)));
1243 | transaction->rep_num = pinfo->num;
1244 | }
1245 | wmem_tree_insert32(conv_info->transactions, pinfo->num, (void*)transaction);
1246 | }
1247 | else
1248 | {
1249 | transaction = (mdb_transaction_t*)wmem_tree_lookup32_le(conv_info->transactions, pinfo->num);
1250 | }
1251 |
1252 | //Sanity check
1253 | if (transaction == NULL((void*)0))
1254 | return;
1255 |
1256 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s (Response)",
1257 | val_to_str(pinfo->pool, transaction->cmd & CMD_MASK0x07, mdb_bv_cmd, "Unknown Command: 0x%x"));
1258 |
1259 | switch (transaction->cmd & CMD_MASK0x07) {
1260 | case MDB_BV_CMD_SETUP0x01:
1261 | bv_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_bv, NULL((void*)0), "Setup Response");
1262 | dissect_mdb_bv_setup_fields(tvb, offset, pinfo, bv_tree);
1263 | break;
1264 | case MDB_BV_CMD_SECURITY0x02:
1265 | /* bv_tree = */ proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_bv, NULL((void*)0), "Security Response");
1266 | break;
1267 | case MDB_BV_CMD_POLL0x03:
1268 | bv_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_bv, NULL((void*)0), "Poll Response");
1269 | dissect_mdb_bv_poll_fields(tvb, offset, pinfo, bv_tree);
1270 | break;
1271 | case MDB_BV_CMD_BILL_TYPE0x04:
1272 | break;
1273 | case MDB_BV_CMD_ESCROW0x05:
1274 | break;
1275 | case MDB_BV_CMD_STACKER0x06:
1276 | bv_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_bv, NULL((void*)0), "Stacker Response");
1277 | dissect_mdb_bv_stacker(tvb, offset, bv_tree);
1278 | break;
1279 | case MDB_BV_CMD_EXPNS0x07:
1280 | bv_tree = proto_tree_add_subtree(tree, tvb, offset, len, ett_mdb_bv, NULL((void*)0), "Expansion Feature Response");
1281 | dissect_mdb_bv_expns_per_mst(tvb, offset, bv_tree, transaction->cmd);
1282 | break;
1283 | }
1284 |
1285 | // This is a reply
1286 | if (transaction->req_num)
1287 | {
1288 | proto_item* it;
1289 | nstime_t ns;
1290 |
1291 | it = proto_tree_add_uint(tree, hf_mdb_response_to, NULL((void*)0), 0, 0, transaction->req_num);
1292 | proto_item_set_generated(it);
1293 |
1294 | nstime_delta(&ns, &pinfo->abs_ts, &transaction->req_time);
1295 | it = proto_tree_add_time(tree, hf_mdb_time, NULL((void*)0), 0, 0, &ns);
1296 | proto_item_set_generated(it);
1297 | }
1298 |
1299 | }
1300 |
1301 | /*
1302 | * Peripheral-to-Master messages can be simple control replies (ACK, NAK, RET)
1303 | * that do not include a checksum. Master-to-Peripheral commands always
1304 | * require a checksum, which is why this check is only needed for
1305 | * Peripheral-to-Master events.
1306 | */
1307 | static void dissect_mdb_per_mst(tvbuff_t *tvb, int offset, packet_info *pinfo,
1308 | proto_tree *tree, uint8_t addr)
1309 | {
1310 | int per_mst_len;
1311 | unsigned data_len;
1312 |
1313 | /*
1314 | * A packet from peripheral to master is either a single ACK/NAK byte or
1315 | * a non-empty data block followed by one checksum byte.
1316 | */
1317 |
1318 | per_mst_len = tvb_reported_length_remaining(tvb, offset);
1319 | if (per_mst_len <= 0) {
1320 | expert_add_info(pinfo, tree, &ei_mdb_short_packet);
1321 | return;
1322 | }
1323 |
1324 | if (per_mst_len == 1) {
1325 | dissect_mdb_ack(tvb, offset, pinfo, tree);
1326 | return;
1327 | }
1328 |
1329 | col_set_str(pinfo->cinfo,
1330 | COL_INFO, val_to_str_const(addr, mdb_addr, "Unknown"));
1331 |
1332 | mdb_conv_info_t* conv_info = get_mdb_conv_info(pinfo);
1333 |
1334 | data_len = per_mst_len - 1;
1335 | int start_offset = offset;
1336 |
1337 | /*
1338 | * Peripheral-to-Master messages can be simple control replies (ACK, NAK, RET)
1339 | * that do not include a checksum.
1340 | */
1341 | bool_Bool checksum_needed = true1;
1342 | if (data_len == 1 && is_mdb_reply(tvb_get_uint8(tvb, offset))) {
1343 | checksum_needed = false0;
1344 | }
1345 |
1346 |
1347 | switch (addr) {
1348 | case ADDR_CASHLESS10x10:
1349 | dissect_mdb_per_mst_cl(tvb, offset, data_len, pinfo, tree, conv_info);
1350 | break;
1351 | case ADDR_COMMS_GW0x18:
1352 | dissect_mdb_per_mst_cgw(tvb, offset, data_len, pinfo, tree, conv_info);
1353 | break;
1354 | case ADDR_BILL_VALIDATOR0x30:
1355 | dissect_mdb_per_mst_bv(tvb, offset, data_len, pinfo, tree, conv_info);
1356 | break;
1357 | default:
1358 | proto_tree_add_item(tree, hf_mdb_data, tvb, offset, data_len, ENC_NA0x00000000);
1359 | break;
1360 | }
1361 | offset += data_len;
1362 |
1363 | if (checksum_needed) {
1364 | mdb_add_checksum(tvb, pinfo, tree, start_offset, data_len + 1);
1365 | }
1366 | }
1367 |
1368 | static int dissect_mdb(tvbuff_t *tvb,
1369 | packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
1370 | {
1371 | int offset = 0, offset_ver, offset_evt;
1372 | uint8_t version, event, addr;
1373 | proto_tree *mdb_tree, *hdr_tree;
1374 | proto_item *tree_ti, *hdr_ti;
1375 |
1376 | /* We need at least the shortest possible pseudo header. */
1377 | if (tvb_captured_length(tvb) < 3)
1378 | return 0;
1379 |
1380 | offset_ver = offset;
1381 | version = tvb_get_uint8(tvb, offset++);
1382 | if (version != 0)
1383 | return 0;
1384 |
1385 | offset_evt = offset;
1386 | event = tvb_get_uint8(tvb, offset++);
1387 | if (!try_val_to_str(event, mdb_event))
1388 | return 0;
1389 |
1390 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MDB");
1391 | col_clear(pinfo->cinfo, COL_INFO);
1392 |
1393 | tree_ti = proto_tree_add_item(tree, proto_mdb, tvb, 0, -1, ENC_NA0x00000000);
1394 | mdb_tree = proto_item_add_subtree(tree_ti, ett_mdb);
1395 |
1396 | hdr_tree = proto_tree_add_subtree(mdb_tree, tvb, 0, -1, ett_mdb_hdr,
1397 | &hdr_ti, "Pseudo header");
1398 |
1399 | proto_tree_add_item(hdr_tree, hf_mdb_hdr_ver,
1400 | tvb, offset_ver, 1, ENC_BIG_ENDIAN0x00000000);
1401 | proto_tree_add_item(hdr_tree, hf_mdb_event,
1402 | tvb, offset_evt, 1, ENC_BIG_ENDIAN0x00000000);
1403 |
1404 | /* Packets from peripheral to master always have an address byte in their
1405 | pseudo header. */
1406 | if (event == MDB_EVT_DATA_PER_MST0xFE) {
1407 | /* See the comment in dissect_mdb_mst_per about MDB addresses. */
1408 | addr = tvb_get_uint8(tvb, offset) & ADDR_MASK0xF8;
1409 | proto_tree_add_uint_bits_format_value(hdr_tree, hf_mdb_addr,
1410 | tvb, 8*offset, 5, addr, ENC_BIG_ENDIAN0x00000000, "0x%02x", addr);
1411 | offset++;
1412 | mdb_set_addrs(event, addr, pinfo);
1413 | }
1414 |
1415 | /* We're now at the end of the pseudo header. */
1416 | proto_item_set_len(hdr_ti, offset);
1417 |
1418 | if (event == MDB_EVT_BUS_RESET0xFD)
1419 | return offset;
1420 |
1421 | if (event == MDB_EVT_DATA_MST_PER0xFF)
1422 | dissect_mdb_mst_per(tvb, offset, pinfo, mdb_tree);
1423 | else if (event == MDB_EVT_DATA_PER_MST0xFE)
1424 | dissect_mdb_per_mst(tvb, offset, pinfo, mdb_tree, addr);
1425 |
1426 | return tvb_reported_length(tvb);
1427 | }
1428 |
1429 | void proto_register_mdb(void)
1430 | {
1431 | expert_module_t* expert_mdb;
1432 |
1433 | static int *ett[] = {
1434 | &ett_mdb,
1435 | &ett_mdb_hdr,
1436 | &ett_mdb_cl,
1437 | &ett_mdb_cgw,
1438 | &ett_mdb_bv
1439 | };
1440 |
1441 | static hf_register_info hf[] = {
1442 | { &hf_mdb_hdr_ver,
1443 | { "Version", "mdb.hdr_ver",
1444 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1445 | },
1446 | { &hf_mdb_event,
1447 | { "Event", "mdb.event",
1448 | FT_UINT8, BASE_HEX, VALS(mdb_event)((0 ? (const struct _value_string*)0 : ((mdb_event)))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1449 | },
1450 | { &hf_mdb_addr,
1451 | { "Address", "mdb.addr",
1452 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1453 | },
1454 | { &hf_mdb_cmd,
1455 | { "Command", "mdb.cmd",
1456 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1457 | },
1458 | { &hf_mdb_cl_setup_sub,
1459 | { "Sub-command", "mdb.cashless.setup_sub_cmd",
1460 | FT_UINT8, BASE_HEX, VALS(mdb_cl_setup_sub_cmd)((0 ? (const struct _value_string*)0 : ((mdb_cl_setup_sub_cmd )))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1461 | },
1462 | { &hf_mdb_cl_feat_lvl,
1463 | { "Feature level", "mdb.cashless.feature_level",
1464 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1465 | },
1466 | { &hf_mdb_cl_cols,
1467 | { "Columns on display", "mdb.cashless.columns",
1468 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1469 | },
1470 | { &hf_mdb_cl_rows,
1471 | { "Rows on display", "mdb.cashless.rows",
1472 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1473 | },
1474 | { &hf_mdb_cl_disp_info,
1475 | { "Display information", "mdb.cashless.disp_info",
1476 | FT_UINT8, BASE_HEX, NULL((void*)0), 0x07, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1477 | },
1478 | { &hf_mdb_cl_max_price,
1479 | { "Maximum price", "mdb.cashless.max_price",
1480 | FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1481 | },
1482 | { &hf_mdb_cl_min_price,
1483 | { "Minimum price", "mdb.cashless.min_price",
1484 | FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1485 | },
1486 | { &hf_mdb_cl_vend_sub,
1487 | { "Sub-command", "mdb.cashless.vend_sub_cmd",
1488 | FT_UINT8, BASE_HEX, VALS(mdb_cl_vend_sub_cmd)((0 ? (const struct _value_string*)0 : ((mdb_cl_vend_sub_cmd) ))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1489 | },
1490 | { &hf_mdb_cl_item_price,
1491 | { "Item Price", "mdb.cashless.item_price",
1492 | FT_UINT32, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1493 | },
1494 | { &hf_mdb_cl_item_num,
1495 | { "Item Number", "mdb.cashless.item_number",
1496 | FT_UINT32, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1497 | },
1498 | { &hf_mdb_cl_reader_sub,
1499 | { "Sub-command", "mdb.cashless.reader_sub_cmd",
1500 | FT_UINT8, BASE_HEX, VALS(mdb_cl_reader_sub_cmd)((0 ? (const struct _value_string*)0 : ((mdb_cl_reader_sub_cmd )))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1501 | },
1502 | { &hf_mdb_cl_resp,
1503 | { "Response", "mdb.cashless.resp",
1504 | FT_UINT8, BASE_HEX, VALS(mdb_cl_resp)((0 ? (const struct _value_string*)0 : ((mdb_cl_resp)))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1505 | },
1506 | { &hf_mdb_cl_scale,
1507 | { "Scale factor", "mdb.cashless.scale_factor",
1508 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1509 | },
1510 | { &hf_mdb_cl_dec_pl,
1511 | { "Decimal places", "mdb.cashless.decimal_places",
1512 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1513 | },
1514 | { &hf_mdb_cl_max_rsp_time,
1515 | { "Application maximum response time", "mdb.cashless.max_rsp_time",
1516 | FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1517 | },
1518 | { &hf_mdb_cl_vend_amt,
1519 | { "Vend Amount", "mdb.cashless.vend_amount",
1520 | FT_UINT32, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1521 | },
1522 | { &hf_mdb_cl_expns_sub,
1523 | { "Sub-command", "mdb.cashless.expansion_sub_cmd",
1524 | FT_UINT8, BASE_HEX, VALS(mdb_cl_expns_sub_cmd)((0 ? (const struct _value_string*)0 : ((mdb_cl_expns_sub_cmd )))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1525 | },
1526 | { &hf_mdb_cl_manuf_code,
1527 | { "Manufacturer Code", "mdb.cashless.manuf_code",
1528 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1529 | },
1530 | { &hf_mdb_cl_ser_num,
1531 | { "Serial Number", "mdb.cashless.serial_number",
1532 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1533 | },
1534 | { &hf_mdb_cl_mod_num,
1535 | { "Model Number", "mdb.cashless.model_number",
1536 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1537 | },
1538 | { &hf_mdb_cl_opt_feat,
1539 | { "Optional Feature Bits", "mdb.cashless.opt_feature_bits",
1540 | FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1541 | },
1542 | { &hf_mdb_cgw_feat_lvl,
1543 | { "Feature level", "mdb.comms_gw.feature_level",
1544 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1545 | },
1546 | { &hf_mdb_cgw_scale,
1547 | { "Scale factor", "mdb.comms_gw.scale_factor",
1548 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1549 | },
1550 | { &hf_mdb_cgw_dec_pl,
1551 | { "Decimal places", "mdb.comms_gw.decimal_places",
1552 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1553 | },
1554 | { &hf_mdb_cgw_resp,
1555 | { "Response", "mdb.comms_gw.resp",
1556 | FT_UINT8, BASE_HEX, VALS(mdb_cgw_resp)((0 ? (const struct _value_string*)0 : ((mdb_cgw_resp)))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1557 | },
1558 | { &hf_mdb_cgw_max_rsp_time,
1559 | { "Application maximum response time", "mdb.comms_gw.max_rsp_time",
1560 | FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1561 | },
1562 | { &hf_mdb_cgw_report_sub,
1563 | { "Sub-command", "mdb.comms_gw.report_sub_cmd", FT_UINT8,
1564 | BASE_HEX, VALS(mdb_cgw_report_sub_cmd)((0 ? (const struct _value_string*)0 : ((mdb_cgw_report_sub_cmd )))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1565 | },
1566 | { &hf_mdb_cgw_dts_evt_code,
1567 | { "DTS Event Code", "mdb.comms_gw.dts_event_code",
1568 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1569 | },
1570 | { &hf_mdb_cgw_duration,
1571 | { "Duration", "mdb.comms_gw.duration",
1572 | FT_UINT32, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1573 | },
1574 | { &hf_mdb_cgw_activity,
1575 | { "Activity", "mdb.comms_gw.activity",
1576 | FT_BOOLEAN, 8, TFS(&tfs_active_inactive)((0 ? (const struct true_false_string*)0 : ((&tfs_active_inactive )))), 0x1, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1577 | },
1578 | { &hf_mdb_cgw_expns_sub,
1579 | { "Sub-command", "mdb.comms_gw.expansion_sub_cmd", FT_UINT8,
1580 | BASE_HEX, VALS(mdb_cgw_expns_sub_cmd)((0 ? (const struct _value_string*)0 : ((mdb_cgw_expns_sub_cmd )))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1581 | },
1582 | { &hf_mdb_cgw_opt_feat,
1583 | { "Optional Feature Bits", "mdb.comms_gw.opt_feature_bits",
1584 | FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1585 | },
1586 | { &hf_mdb_cgw_manuf_code,
1587 | { "Manufacturer Code", "mdb.comms_gw.manuf_code",
1588 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1589 | },
1590 | { &hf_mdb_cgw_ser_num,
1591 | { "Serial Number", "mdb.comms_gw.serial_number",
1592 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1593 | },
1594 | { &hf_mdb_cgw_mod_num,
1595 | { "Model Number", "mdb.comms_gw.model_number",
1596 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1597 | },
1598 | { &hf_mdb_bv_setup_bill_val_feature,
1599 | { "Bill Validator Feature Level", "mdb.bv.setup.feature_level",
1600 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1601 | },
1602 | { &hf_mdb_bv_setup_ctry_currency_code,
1603 | { "Country/Currency Code", "mdb.bv.setup.ctry_currency",
1604 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1605 | },
1606 | { &hf_mdb_bv_setup_bill_scal_fac,
1607 | { "Bill scaling factor", "mdb.bv.setup.bill_scale_factor",
1608 | FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1609 | },
1610 | { &hf_mdb_bv_setup_dec_places,
1611 | { "Decimal Places", "mdb.bv.setup.dec_places",
1612 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1613 | },
1614 | { &hf_mdb_bv_setup_bill_stacker_cap,
1615 | { "Stacker Capacity", "mdb.bv.setup.stacker_cap",
1616 | FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1617 | },
1618 | { &hf_mdb_bv_setup_bill_sec_lvls,
1619 | { "Security Levels", "mdb.bv.setup.sec_levels",
1620 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1621 | },
1622 | { &hf_mdb_bv_setup_escrow,
1623 | { "Escrow capability", "mdb.bv.setup.escrow",
1624 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1625 | },
1626 | { &hf_mdb_bv_setup_bill_type_cred,
1627 | { "Bill Type Credit", "mdb.bv.setup.bill_type_credit",
1628 | FT_STRING, BASE_NONE, NULL((void*)0), 0, "Bill values per channel", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1629 | },
1630 | { &hf_mdb_bv_bill_enable,
1631 | { "Bill Enable State", "mdb.bv.bill_type.enable",
1632 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1633 | },
1634 | { &hf_mdb_bv_bill_escrow_enable,
1635 | { "Bill Escrow Enable State", "mdb.bv.bill_type.escrow_enable",
1636 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1637 | },
1638 | { &hf_mdb_bv_poll_bill_routing_state,
1639 | { "Escrow", "mdb.bv.poll.routing_state",
1640 | FT_UINT8, BASE_HEX, VALS(mdb_bv_poll_bill_routing_state)((0 ? (const struct _value_string*)0 : ((mdb_bv_poll_bill_routing_state )))), 0x70, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1641 | },
1642 | { &hf_mdb_bv_poll_bill_type,
1643 | { "Bill Type", "mdb.bv.poll.bill_type",
1644 | FT_UINT8, BASE_HEX, NULL((void*)0), 0x0F, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1645 | },
1646 | { &hf_mdb_bv_poll_state,
1647 | { "Bill Accept State", "mdb.bv.poll.state",
1648 | FT_UINT8, BASE_HEX, VALS(mdb_bv_poll_state)((0 ? (const struct _value_string*)0 : ((mdb_bv_poll_state))) ), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1649 | },
1650 | { &hf_mdb_bv_escrow_state,
1651 | { "Escrow", "mdb.bv.escrow.state",
1652 | FT_BOOLEAN, 8, TFS(&mdb_bv_escrow_state)((0 ? (const struct true_false_string*)0 : ((&mdb_bv_escrow_state )))), 0x01, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1653 | },
1654 | { &hf_mdb_bv_stacker,
1655 | { "Stacker Full", "mdb.bv.stacker.full_state",
1656 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1657 | },
1658 | { &hf_mdb_bv_exp_cmd,
1659 | { "Expansion Command", "mdb.bv.exp.cmd", FT_UINT8,
1660 | BASE_HEX, VALS(mdb_bv_exp_cmd)((0 ? (const struct _value_string*)0 : ((mdb_bv_exp_cmd)))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1661 | },
1662 | // EXPANSION cmd: Level 1/2 Identification with/Without Option bits
1663 | { &hf_mdb_bv_exp_opt_feat,
1664 | { "Bill Type Routing", "mdb.bv.exp.bill_type_routing",
1665 | FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1666 | },
1667 | { &hf_mdb_bv_exp_manufact_code,
1668 | { "Manufacturer Code", "mdb.bv.expns.manufact_code",
1669 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1670 | },
1671 | { &hf_mdb_bv_exp_serial_num,
1672 | { "Serial Number", "mdb.bv.expns.serial_num",
1673 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1674 | },
1675 | { &hf_mdb_bv_exp_model_tuning_num,
1676 | { "Model/Tuning number", "mdb.bv.expns.model_tuning_num",
1677 | FT_STRING, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1678 | },
1679 | { &hf_mdb_bv_exp_software_version,
1680 | { "Software version", "mdb.bv.expns.software_version",
1681 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1682 | },
1683 | // EXPANSION cmd: Lvl2 Feature enable
1684 | { &hf_mdb_bv_exp_opt_feat_enable,
1685 | { "Level 2+ Feature enable", "mdb.bv.exp.opt_feat",
1686 | FT_UINT32, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1687 | },
1688 | // EXPANSION cmd: Recycler Setup
1689 | { &hf_mdb_bv_exp_bill_type_routing,
1690 | { "Bill Type Routing", "mdb.bv.exp.bill_type_routing",
1691 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1692 | },
1693 | // EXPANSION cmd: Recycler Enable
1694 | { &hf_mdb_bv_exp_manual_dispense_enable,
1695 | { "Manual Dispense Enable", "mdb.bv.exp.manual_dispense_enable",
1696 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1697 | },
1698 | { &hf_mdb_bv_exp_bill_recycler_enabled,
1699 | { "Bill Recycler Enabled", "mdb.bv.exp.bill_recycler_enabled",
1700 | FT_UINT8, BASE_HEX, VALS(mdb_bv_exp_bills_recyc_enabled)((0 ? (const struct _value_string*)0 : ((mdb_bv_exp_bills_recyc_enabled )))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1701 | },
1702 | // EXPANSION cmd: Bill Dispense Status
1703 | { &hf_mdb_bv_exp_dispenser_full_state,
1704 | { "Dispenser Full Status", "mdb.bv.exp.dispenser_full_state",
1705 | FT_UINT16, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1706 | },
1707 | { &hf_mdb_bv_exp_bill_count,
1708 | { "Bill count", "mdb.bv.exp.bill_count",
1709 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1710 | },
1711 | // EXPANSION cmd: Dispense Bill
1712 | { &hf_mdb_bv_exp_bill_type_dispensed,
1713 | { "Bill type to be dispensed", "mdb.bv.exp.bill_type_disp",
1714 | FT_UINT8, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1715 | },
1716 | { &hf_mdb_bv_exp_bill_type_number_bills,
1717 | { "Bills type number of bills", "mdb.bv.exp.bill_type_num_bills",
1718 | FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1719 | },
1720 | // EXPANSION cmd: Dispense Value
1721 | { &hf_mdb_bv_exp_dispense_value_bills,
1722 | { "Bill value to be paid out", "mdb.bv.exp.dispense_value_bills",
1723 | FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1724 | },
1725 | // EXPANSION cmd: Payout Status
1726 | { &hf_mdb_bv_exp_payout_state,
1727 | { "Number of bills paid out", "mdb.bv.exp.payout_state_num_bills",
1728 | FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1729 | },
1730 | // EXPANSION cmd: Payout Value Poll
1731 | { &hf_mdb_bv_exp_dispenser_payout_activity,
1732 | { "Dispenser Payout Activity", "mdb.bv.exp.payout_value_activity",
1733 | FT_UINT16, BASE_DEC, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1734 | },
1735 | // EXPANSION cmd: Payout Cancel
1736 | // No data
1737 | // EXPANSION cmd: FTL REQ to RCV
1738 | // EXPANSION cmd: FTL Send Block
1739 | // EXPANSION cmd: FTL OK to Send
1740 | // EXPANSION cmd: FTL REQ to Send
1741 | // EXPANSION cmd: Diagnostics
1742 | { &hf_mdb_ack,
1743 | { "Ack byte", "mdb.ack",
1744 | FT_UINT8, BASE_HEX, VALS(mdb_ack)((0 ? (const struct _value_string*)0 : ((mdb_ack)))), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1745 | },
1746 | { &hf_mdb_data,
1747 | { "Data", "mdb.data",
1748 | FT_BYTES, BASE_NONE, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1749 | },
1750 | { &hf_mdb_chk,
1751 | { "Checksum", "mdb.chk",
1752 | FT_UINT8, BASE_HEX, NULL((void*)0), 0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1753 | },
1754 | { &hf_mdb_chk_status,
1755 | { "Checksum Status", "mdb.chk.status",
1756 | FT_UINT8, BASE_NONE, VALS(proto_checksum_vals)((0 ? (const struct _value_string*)0 : ((proto_checksum_vals) ))), 0x0,
1757 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1758 | },
1759 | { &hf_mdb_response_in,
1760 | { "Response In", "mdb.response_in",
1761 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE)((gpointer) (glong) (FT_FRAMENUM_RESPONSE)), 0x0,
1762 | "The response to this request is in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1763 | },
1764 | { &hf_mdb_response_to,
1765 | { "Request In", "mdb.response_to",
1766 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST)((gpointer) (glong) (FT_FRAMENUM_REQUEST)), 0x0,
1767 | "This is a response to the request in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1768 | },
1769 | { &hf_mdb_time,
1770 | { "Time", "mdb.time",
1771 | FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0,
1772 | "The time between the Call and the Reply", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1773 | }
1774 | };
1775 |
1776 | static ei_register_info ei[] = {
1777 | { &ei_mdb_short_packet,
1778 | { "mdb.short_packet", PI_PROTOCOL0x09000000, PI_ERROR0x00800000,
1779 | "MDB packet without payload", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
1780 | { &ei_mdb_bad_checksum,
1781 | { "mdb.bad_checksum", PI_CHECKSUM0x01000000, PI_ERROR0x00800000,
1782 | "Bad checksum", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }}
1783 | };
1784 |
1785 | proto_mdb = proto_register_protocol("Multi-Drop Bus", "MDB", "mdb");
1786 | proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
1787 | proto_register_field_array(proto_mdb, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
1788 | expert_mdb = expert_register_protocol(proto_mdb);
1789 | expert_register_field_array(expert_mdb, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
1790 | mdb_handle = register_dissector("mdb", dissect_mdb, proto_mdb);
1791 | }
1792 |
1793 | void proto_reg_handoff_mdb(void)
1794 | {
1795 | dissector_add_uint("wtap_encap", WTAP_ENCAP_MDB223, mdb_handle);
1796 | }
1797 |
1798 | /*
1799 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
1800 | *
1801 | * Local variables:
1802 | * c-basic-offset: 4
1803 | * tab-width: 8
1804 | * indent-tabs-mode: nil
1805 | * End:
1806 | *
1807 | * vi: set shiftwidth=4 tabstop=8 expandtab:
1808 | * :indentSize=4:tabSize=8:noTabs=true:
1809 | */