/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 | } |