Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-bist-itch.c
Line
Count
Source
1
/* packet-bist-itch.c
2
 * Routines for BIST-ITCH dissection
3
 * Copyright 2025, Sadettin Er <sadettin.er@b-ulltech.com>
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
//
13
//  Documentation:
14
//  https://www.borsaistanbul.com/files/bistech-itch-protocol-specification.pdf
15
16
#include "config.h"
17
18
#include <wireshark.h>
19
20
#include <epan/packet.h>
21
#include <epan/prefs.h>
22
#include <epan/column-utils.h>
23
#include <wsutil/to_str.h>
24
#include <wsutil/type_util.h>
25
#include <wsutil/wmem/wmem.h>
26
27
static bool bist_show_bigint_price;
28
static dissector_handle_t bist_handle;
29
30
static const value_string message_types_val[] = {
31
    { 'A', "Add Order"                 },
32
    { 'Z', "Equilibrium Price"         },
33
    { 'M', "Combo Leg"                 },
34
    { 'E', "Order Executed"            },
35
    { 'T', "Second"                    },
36
    { 'P', "Trade"                     },
37
    { 'C', "Order Executed w/ Price"   },
38
    { 'D', "Order Delete"              },
39
    { 'S', "System Event"              },
40
    { 'R', "Order Book Directory"      },
41
    { 'Y', "Order Book Flush"          },
42
    { 'V', "Short Sell Status"         },
43
    { 'O', "Order Book State"          },
44
    { 'L', "Tick Size"                 },
45
    { 0,   NULL                        }
46
};
47
48
static const value_string bist_itch_side_vals[] = {
49
    { 'B', "Buy"  },
50
    { 'S', "Sell" },
51
    { 0,   NULL   }
52
};
53
54
static const value_string bist_itch_event_vals[] = {
55
    { 'O', "Start of Messages" },
56
    { 'C', "End of Messages"   },
57
    { 0,   NULL                }
58
};
59
60
61
static int hf_bist_message;
62
static int hf_bist_version;
63
static int hf_bist_message_type;
64
static int hf_bist_nanosecond;
65
static int hf_bist_second;
66
static int hf_bist_orderbook_id;
67
static int hf_bist_order_id;
68
static int hf_bist_side;
69
static int hf_bist_quantity;
70
static int hf_bist_price;
71
static int hf_bist_match_id;
72
static int hf_bist_combo_group;
73
static int hf_bist_printable;
74
static int hf_bist_occurred_cross;
75
static int hf_bist_event_code;
76
static int hf_bist_symbol;
77
static int hf_bist_isin;
78
static int hf_bist_financial_product;
79
static int hf_bist_trading_currency;
80
static int hf_bist_tick_size;
81
static int hf_bist_price_from;
82
static int hf_bist_price_to;
83
static int hf_bist_leg_order_book;
84
static int hf_bist_leg_side;
85
static int hf_bist_leg_ratio;
86
static int hf_bist_short_sell_status;
87
static int hf_bist_state_name;
88
static int hf_bist_bid_qty;
89
static int hf_bist_ask_qty;
90
static int hf_bist_best_bid_price;
91
static int hf_bist_best_ask_price;
92
static int hf_bist_best_bid_qty;
93
static int hf_bist_ranking_seq;
94
static int hf_bist_ranking_time;
95
static int hf_bist_order_attributes;
96
static int hf_bist_lot_type;
97
static int hf_bist_long_name;
98
static int hf_bist_price_decimals;
99
static int hf_bist_nominal_decimals;
100
static int hf_bist_odd_lot_size;
101
static int hf_bist_round_lot_size;
102
static int hf_bist_block_lot_size;
103
static int hf_bist_nominal_value;
104
static int hf_bist_number_of_leg;
105
static int hf_bist_underlying_orderbook_id;
106
static int hf_bist_strike_price;
107
static int hf_bist_expiration_date;
108
static int hf_bist_strike_price_decimals;
109
static int hf_bist_put_or_call;
110
static int hf_bist_ranking_type;
111
static int hf_bist_combo_orderbook_id;
112
static int hf_bist_eq_bid_qty;
113
static int hf_bist_eq_ask_qty;
114
static int hf_bist_reserved1;
115
static int hf_bist_reserved2;
116
static int hf_bist_unexpected;
117
118
static int  proto_bist;
119
static int ett_bist_itch;
120
121
static int add_price(proto_tree *tree, int hf_id, tvbuff_t *tvb, unsigned offset)
122
0
{
123
0
    uint32_t raw = tvb_get_ntohl(tvb, offset);
124
0
    double val = bist_show_bigint_price ? raw / 10000.0 : (double)raw;
125
0
    proto_tree_add_double(tree, hf_id, tvb, offset, 4, val);
126
0
    return offset + 4;
127
0
}
128
129
static int dissect_timestamp(tvbuff_t *tvb, proto_tree *tree, unsigned offset)
130
0
{
131
0
    proto_tree_add_item(tree, hf_bist_nanosecond, tvb, offset, 4, ENC_BIG_ENDIAN);
132
0
    return offset + 4;
133
0
}
134
135
static int dissect_quantity(tvbuff_t *tvb, packet_info *pinfo,
136
                            proto_tree *tree, unsigned offset)
137
0
{
138
0
    uint64_t q;
139
0
    proto_tree_add_item_ret_uint64(tree, hf_bist_quantity, tvb,
140
0
                                   offset, 8, ENC_BIG_ENDIAN, &q);
141
0
    col_append_fstr(pinfo->cinfo, COL_INFO, "qty %" PRIu64 " ", q);
142
0
    return offset + 8;
143
0
}
144
145
static int dissect_order_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset)
146
0
{
147
0
    uint64_t oid;
148
0
    proto_tree_add_item_ret_uint64(tree, hf_bist_order_id, tvb,
149
0
                                   offset, 8, ENC_BIG_ENDIAN, &oid);
150
0
    col_append_fstr(pinfo->cinfo, COL_INFO, "%" PRIu64 " ", oid);
151
0
    return offset + 8;
152
0
}
153
154
/* Guard for optional/trailing bytes: if remaining < len, bail out (goto done). */
155
/* Avoids malformed on omitted reserved fields; don’t use for required fields. */
156
0
#define NEED(len) do { \
157
0
    if (tvb_reported_length_remaining(tvb, offset) < (len)) \
158
0
        goto done; \
159
0
} while (0)
160
161
static int
162
dissect_bist_itch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
163
0
{
164
0
    proto_item *ti;
165
0
    proto_tree *bist_tree = NULL;
166
0
    int         offset    = 0;
167
0
    uint8_t     type      = tvb_get_uint8(tvb, offset);
168
169
170
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "bist‑ITCH");
171
0
    const char *type_desc = val_to_str(pinfo->pool, type, message_types_val, "Unknown (0x%02x)");
172
0
    col_clear(pinfo->cinfo, COL_INFO);
173
0
    col_add_str(pinfo->cinfo, COL_INFO, type_desc);
174
175
0
    ti = proto_tree_add_protocol_format(tree, proto_bist, tvb, 0, -1,
176
0
                                        "bist ITCH, %s", type_desc);
177
0
    bist_tree = proto_item_add_subtree(ti, ett_bist_itch);
178
0
    proto_tree_add_uint(bist_tree, hf_bist_message_type, tvb, 0, 1, type);
179
0
    offset += 1;
180
181
0
    switch (type) {
182
0
    case 'A': { // Add Order
183
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
184
0
        offset = dissect_order_id(tvb, pinfo, bist_tree, offset);
185
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
186
0
        proto_tree_add_item(bist_tree, hf_bist_side, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
187
0
        NEED(4);
188
0
        proto_tree_add_item(bist_tree, hf_bist_ranking_seq, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
189
0
        NEED(8 + 4 + 2 + 1);
190
0
        offset = dissect_quantity(tvb, pinfo, bist_tree, offset);  // 8
191
0
        offset = add_price(bist_tree, hf_bist_price, tvb, offset); // 4
192
0
        proto_tree_add_item(bist_tree, hf_bist_order_attributes, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
193
0
        proto_tree_add_item(bist_tree, hf_bist_lot_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
194
0
        NEED(8);
195
0
        proto_tree_add_item(bist_tree, hf_bist_ranking_time, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
196
0
        break;
197
0
    }
198
0
    case 'Z': { // Equilibrium Price
199
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
200
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
201
0
        proto_tree_add_item(bist_tree, hf_bist_eq_bid_qty, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
202
0
        proto_tree_add_item(bist_tree, hf_bist_eq_ask_qty, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
203
0
        offset = add_price(bist_tree, hf_bist_price, tvb, offset);
204
0
        offset = add_price(bist_tree, hf_bist_best_bid_price, tvb, offset);
205
0
        offset = add_price(bist_tree, hf_bist_best_ask_price, tvb, offset);
206
0
        proto_tree_add_item(bist_tree, hf_bist_bid_qty, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
207
0
        proto_tree_add_item(bist_tree, hf_bist_ask_qty, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
208
0
        break;
209
0
    }
210
0
    case 'M': { // Combo Leg
211
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
212
0
        proto_tree_add_item(bist_tree, hf_bist_combo_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
213
0
        proto_tree_add_item(bist_tree, hf_bist_leg_order_book, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
214
0
        proto_tree_add_item(bist_tree, hf_bist_leg_side, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
215
0
        proto_tree_add_item(bist_tree, hf_bist_leg_ratio, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
216
0
        break;
217
0
    }
218
0
    case 'E': { // Order Executed
219
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
220
0
        offset = dissect_order_id(tvb, pinfo, bist_tree, offset);
221
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
222
0
        proto_tree_add_item(bist_tree, hf_bist_side, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
223
0
        offset = dissect_quantity(tvb, pinfo, bist_tree, offset);
224
0
        proto_tree_add_item(bist_tree, hf_bist_match_id, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
225
0
        proto_tree_add_item(bist_tree, hf_bist_combo_group, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
226
0
        proto_tree_add_item(bist_tree, hf_bist_reserved1, tvb, offset, 7, ENC_NA); offset += 7;
227
0
        proto_tree_add_item(bist_tree, hf_bist_reserved2, tvb, offset, 7, ENC_NA); offset += 7;
228
0
        break;
229
0
    }
230
0
    case 'T': { // Second
231
0
        proto_tree_add_item(bist_tree, hf_bist_second, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
232
0
        break;
233
0
    }
234
0
    case 'P': { // Trade
235
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
236
0
        proto_tree_add_item(bist_tree, hf_bist_match_id, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
237
0
        proto_tree_add_item(bist_tree, hf_bist_combo_group, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
238
0
        proto_tree_add_item(bist_tree, hf_bist_side, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
239
0
        offset = dissect_quantity(tvb, pinfo, bist_tree, offset);
240
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
241
0
        offset = add_price(bist_tree, hf_bist_price, tvb, offset);
242
0
        proto_tree_add_item(bist_tree, hf_bist_reserved1, tvb, offset, 7, ENC_NA); offset += 7;
243
0
        proto_tree_add_item(bist_tree, hf_bist_reserved2, tvb, offset, 7, ENC_NA); offset += 7;
244
0
        proto_tree_add_item(bist_tree, hf_bist_printable, tvb, offset, 1, ENC_ASCII); offset += 1;
245
0
        proto_tree_add_item(bist_tree, hf_bist_occurred_cross, tvb, offset, 1, ENC_ASCII); offset += 1;
246
0
        break;
247
0
    }
248
0
    case 'C': { // Order Executed with price
249
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
250
0
        offset = dissect_order_id(tvb, pinfo, bist_tree, offset);
251
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
252
0
        proto_tree_add_item(bist_tree, hf_bist_side, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
253
0
        offset = dissect_quantity(tvb, pinfo, bist_tree, offset);
254
0
        proto_tree_add_item(bist_tree, hf_bist_match_id, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
255
0
        proto_tree_add_item(bist_tree, hf_bist_combo_group, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
256
0
        proto_tree_add_item(bist_tree, hf_bist_reserved1, tvb, offset, 7, ENC_NA); offset += 7;
257
0
        proto_tree_add_item(bist_tree, hf_bist_reserved2, tvb, offset, 7, ENC_NA); offset += 7;
258
0
        offset = add_price(bist_tree, hf_bist_price, tvb, offset);
259
0
        proto_tree_add_item(bist_tree, hf_bist_occurred_cross, tvb, offset, 1, ENC_ASCII); offset += 1;
260
0
        proto_tree_add_item(bist_tree, hf_bist_printable, tvb, offset, 1, ENC_ASCII); offset += 1;
261
0
        break;
262
0
    }
263
0
    case 'D': { // Order Delete
264
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
265
0
        offset = dissect_order_id(tvb, pinfo, bist_tree, offset);
266
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
267
0
        proto_tree_add_item(bist_tree, hf_bist_side, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
268
0
        break;
269
0
    }
270
0
    case 'S': { // System Event
271
0
        offset = dissect_timestamp(tvb, bist_tree, offset); // 1..4
272
0
        proto_tree_add_item(bist_tree, hf_bist_event_code, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;  // 'O' or 'C'
273
0
        break;
274
0
    }
275
0
    case 'R': { // Orderbook Directory
276
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
277
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
278
0
        proto_tree_add_item(bist_tree, hf_bist_symbol, tvb, offset, 32, ENC_ASCII); offset += 32;
279
0
        proto_tree_add_item(bist_tree, hf_bist_long_name, tvb, offset, 32, ENC_ASCII); offset += 32;
280
0
        proto_tree_add_item(bist_tree, hf_bist_isin, tvb, offset, 12, ENC_ASCII); offset += 12;
281
0
        proto_tree_add_item(bist_tree, hf_bist_financial_product, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
282
0
        proto_tree_add_item(bist_tree, hf_bist_trading_currency, tvb, offset, 3, ENC_ASCII); offset += 3;
283
0
        proto_tree_add_item(bist_tree, hf_bist_price_decimals, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
284
0
        proto_tree_add_item(bist_tree, hf_bist_nominal_decimals, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
285
0
        proto_tree_add_item(bist_tree, hf_bist_odd_lot_size, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
286
0
        proto_tree_add_item(bist_tree, hf_bist_round_lot_size, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
287
0
        proto_tree_add_item(bist_tree, hf_bist_block_lot_size, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
288
0
        proto_tree_add_item(bist_tree, hf_bist_nominal_value, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
289
0
        proto_tree_add_item(bist_tree, hf_bist_number_of_leg, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
290
0
        proto_tree_add_item(bist_tree, hf_bist_underlying_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
291
0
        offset = add_price(bist_tree, hf_bist_strike_price, tvb, offset);
292
0
        proto_tree_add_item(bist_tree, hf_bist_expiration_date, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
293
0
        proto_tree_add_item(bist_tree, hf_bist_strike_price_decimals, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
294
0
        proto_tree_add_item(bist_tree, hf_bist_put_or_call, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
295
0
        NEED(1);
296
0
        proto_tree_add_item(bist_tree, hf_bist_ranking_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
297
0
        break;
298
0
    }
299
0
    case 'Y': { // Orderbook Flush
300
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
301
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
302
0
        break;
303
0
    }
304
0
    case 'V': { // Short Sell Status
305
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
306
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
307
0
        proto_tree_add_item(bist_tree, hf_bist_short_sell_status, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
308
0
        break;
309
0
    }
310
0
    case 'O': { // Orderbook State
311
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
312
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
313
0
        proto_tree_add_item(bist_tree, hf_bist_state_name, tvb, offset, 20, ENC_ASCII); offset += 20;
314
0
        break;
315
0
    }
316
0
    case 'L': { // Tick Size
317
0
        offset = dissect_timestamp(tvb, bist_tree, offset);
318
0
        proto_tree_add_item(bist_tree, hf_bist_orderbook_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
319
0
        proto_tree_add_item(bist_tree, hf_bist_tick_size, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8;
320
0
        offset = add_price(bist_tree, hf_bist_price_from, tvb, offset);
321
0
        offset = add_price(bist_tree, hf_bist_price_to, tvb, offset);
322
0
        break;
323
0
    }
324
0
    default: {
325
0
        proto_tree_add_item(bist_tree, hf_bist_message, tvb, offset, -1, ENC_NA);
326
0
        offset = tvb_captured_length(tvb);
327
0
        break;
328
0
    }
329
0
    }
330
331
    /* Show any trailing/extra bytes for this message type. */
332
0
    NEED(1);
333
0
    proto_tree_add_item(bist_tree, hf_bist_unexpected, tvb, offset, -1, ENC_NA);
334
335
0
done:
336
0
    return tvb_captured_length(tvb);
337
0
}
338
339
void proto_register_bist(void)
340
16
{
341
16
    static hf_register_info hf_bist[] = {
342
16
        { &hf_bist_version,              { "Version",                 "bist-itch.version",                 FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
343
16
        { &hf_bist_message_type,         { "Message Type",            "bist-itch.message_type",            FT_UINT8,  BASE_HEX,  VALS(message_types_val), 0x0, NULL, HFILL } },
344
16
        { &hf_bist_second,               { "Second",                  "bist-itch.second",                  FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
345
16
        { &hf_bist_nanosecond,           { "Nanosecond",              "bist-itch.nanosecond",              FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
346
16
        { &hf_bist_orderbook_id,         { "Order Book ID",           "bist-itch.orderbook_id",            FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
347
16
        { &hf_bist_order_id,             { "Order ID",                "bist-itch.order_id",                FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
348
16
        { &hf_bist_side,                 { "Side",                    "bist-itch.side",                    FT_UINT8,  BASE_HEX,  VALS(bist_itch_side_vals), 0x0, NULL, HFILL } },
349
16
        { &hf_bist_quantity,             { "Quantity",                "bist-itch.quantity",                FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
350
16
        { &hf_bist_price,                { "Price",                   "bist-itch.price",                   FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
351
16
        { &hf_bist_match_id,             { "Match ID",                "bist-itch.match_id",                FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
352
16
        { &hf_bist_combo_group,          { "Combo Group ID",          "bist-itch.combo_group",             FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
353
16
        { &hf_bist_printable,            { "Printable",               "bist-itch.printable",               FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
354
16
        { &hf_bist_occurred_cross,       { "Occurred at Cross",       "bist-itch.occurred_cross",          FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
355
16
        { &hf_bist_event_code,           { "Event Code",              "bist-itch.event_code",              FT_UINT8,  BASE_HEX,  VALS(bist_itch_event_vals), 0x0, NULL, HFILL } },
356
16
        { &hf_bist_symbol,               { "Symbol",                  "bist-itch.symbol",                  FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
357
16
        { &hf_bist_long_name,            { "Long Name",               "bist-itch.long_name",               FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
358
16
        { &hf_bist_isin,                 { "ISIN",                    "bist-itch.isin",                    FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
359
16
        { &hf_bist_financial_product,    { "Financial Product",       "bist-itch.financial_product",       FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
360
16
        { &hf_bist_trading_currency,     { "Trading Currency",        "bist-itch.trading_currency",        FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
361
16
        { &hf_bist_tick_size,            { "Tick Size",               "bist-itch.tick_size",               FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
362
16
        { &hf_bist_price_from,           { "Price From",              "bist-itch.price_from",              FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
363
16
        { &hf_bist_price_to,             { "Price To",                "bist-itch.price_to",                FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
364
16
        { &hf_bist_short_sell_status,    { "Short Sell Status",       "bist-itch.short_sell_status",       FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
365
16
        { &hf_bist_state_name,           { "State Name",              "bist-itch.state_name",              FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
366
16
        { &hf_bist_ranking_seq,          { "Ranking Sequence #",      "bist-itch.ranking_seq",             FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
367
16
        { &hf_bist_ranking_time,         { "Ranking Time (ns)",       "bist-itch.ranking_time",            FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
368
16
        { &hf_bist_order_attributes,     { "Order Attributes",        "bist-itch.order_attributes",        FT_UINT16, BASE_HEX,  NULL, 0x0, NULL, HFILL } },
369
16
        { &hf_bist_lot_type,             { "Lot Type",                "bist-itch.lot_type",                FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
370
16
        { &hf_bist_price_decimals,       { "Price Decimals",          "bist-itch.price_decimals",          FT_UINT16, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
371
16
        { &hf_bist_nominal_decimals,     { "Nominal Decimals",        "bist-itch.nominal_decimals",        FT_UINT16, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
372
16
        { &hf_bist_odd_lot_size,         { "Odd-Lot Size",            "bist-itch.odd_lot_size",            FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
373
16
        { &hf_bist_round_lot_size,       { "Round-Lot Size",          "bist-itch.round_lot_size",          FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
374
16
        { &hf_bist_block_lot_size,       { "Block-Lot Size",          "bist-itch.block_lot_size",          FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
375
16
        { &hf_bist_nominal_value,        { "Nominal Value",           "bist-itch.nominal_value",           FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
376
16
        { &hf_bist_number_of_leg,        { "Number of Legs",          "bist-itch.number_of_leg",           FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
377
16
        { &hf_bist_underlying_orderbook_id, { "Underlying Orderbook", "bist-itch.underlying_orderbook_id", FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
378
16
        { &hf_bist_strike_price,         { "Strike Price",            "bist-itch.strike_price",            FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
379
16
        { &hf_bist_expiration_date,      { "Expiration Date",         "bist-itch.expiration_date",         FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
380
16
        { &hf_bist_strike_price_decimals,{ "Strike Price Decimals",   "bist-itch.strike_price_decimals",   FT_UINT16, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
381
16
        { &hf_bist_put_or_call,          { "Put/Call",                "bist-itch.put_or_call",             FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
382
16
        { &hf_bist_ranking_type,         { "Ranking Type",            "bist-itch.ranking_type",            FT_UINT8,  BASE_DEC,  NULL, 0x0, NULL, HFILL } },
383
16
        { &hf_bist_message,              { "Raw Message",             "bist-itch.message",                 FT_BYTES,  BASE_NONE, NULL, 0x0, NULL, HFILL } },
384
16
        { &hf_bist_combo_orderbook_id,   { "Combo Order Book ID",     "bist-itch.combo_orderbook_id",      FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
385
16
        { &hf_bist_leg_order_book,       { "Leg Order Book ID",       "bist-itch.leg_order_book",          FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
386
16
        { &hf_bist_leg_side,             { "Leg Side",                "bist-itch.leg_side",                FT_UINT8,  BASE_HEX,  VALS(bist_itch_side_vals), 0x0, NULL, HFILL } },
387
16
        { &hf_bist_leg_ratio,            { "Leg Ratio",               "bist-itch.leg_ratio",               FT_UINT32, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
388
16
        { &hf_bist_bid_qty,              { "Best Bid Qty",            "bist-itch.bid_qty",                 FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
389
16
        { &hf_bist_ask_qty,              { "Best Ask Qty",            "bist-itch.ask_qty",                 FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
390
16
        { &hf_bist_best_bid_price,       { "Best Bid Price",          "bist-itch.best_bid_price",          FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
391
16
        { &hf_bist_best_ask_price,       { "Best Ask Price",          "bist-itch.best_ask_price",          FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
392
16
        { &hf_bist_best_bid_qty,         { "Next-Level Bid Qty",      "bist-itch.best_bid_qty",            FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
393
16
        { &hf_bist_eq_bid_qty,           { "Avail Bid Qty at Equilibrium", "bist-itch.eq_bid_qty",         FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
394
16
        { &hf_bist_eq_ask_qty,           { "Avail Ask Qty @ Equilibrium", "bist-itch.eq_ask_qty",          FT_UINT64, BASE_DEC,  NULL, 0x0, NULL, HFILL } },
395
16
        { &hf_bist_reserved1,            { "Reserved",                "bist-itch.reserved1",               FT_BYTES,  BASE_NONE, NULL, 0x0, NULL, HFILL } },
396
16
        { &hf_bist_reserved2,            { "Reserved",                "bist-itch.reserved2",               FT_BYTES,  BASE_NONE, NULL, 0x0, NULL, HFILL } },
397
16
        { &hf_bist_unexpected,           { "Unexpected Bytes",        "bist-itch.unexpected",              FT_BYTES,  BASE_NONE, NULL, 0x0, NULL, HFILL } },
398
16
    };
399
400
16
    static int *ett[] = {
401
16
        &ett_bist_itch
402
16
    };
403
404
16
    proto_bist = proto_register_protocol("BIST ITCH", "BIST‑ITCH", "bist_itch");
405
16
    proto_register_field_array(proto_bist, hf_bist, array_length(hf_bist));
406
16
    proto_register_subtree_array(ett, array_length(ett));
407
408
16
    module_t *pref = prefs_register_protocol(proto_bist, NULL);
409
16
    prefs_register_bool_preference(pref, "show_bigint_price",
410
16
        "Show Prices as Decimals",
411
16
        "If enabled, 4‑byte price fields are divided by 10000 and shown as doubles.",
412
16
        &bist_show_bigint_price);
413
414
16
    bist_handle = register_dissector("bist-itch", dissect_bist_itch, proto_bist);
415
16
}
416
417
void proto_reg_handoff_bist(void)
418
16
{
419
16
    dissector_add_for_decode_as("moldudp64.payload", bist_handle);
420
16
    dissector_add_for_decode_as("moldudp.payload",   bist_handle);
421
16
}