Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-ouch.c
Line
Count
Source
1
/* packet-ouch.c
2
 * Routines for OUCH 4.x protocol dissection
3
 * Copyright (C) 2013, 2015, 2016 David Arnold <d@0x1.org>
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
/* OUCH is a stock exchange order entry protocol published and used by
13
 * NASDAQ.  This dissector supports versions 4.x, which differ from
14
 * earlier versions by adopting binary encoding for numeric values.
15
 *
16
 * OUCH is usually encapsulated within NASDAQ's SoupBinTCP protocol,
17
 * running over a TCP connection from the trading application to the
18
 * exchange.  SOUP provides framing, heartbeats and authentication;
19
 * consequently none of these is present in OUCH.
20
 *
21
 * Other exchanges have created order entry protocols very similar to
22
 * OUCH, but typically they differ in subtle ways (and continue to
23
 * diverge as time progresses) so I have not attempted to dissect
24
 * anything other than proper NASDAQ OUCH in this code.
25
 *
26
 * Specifications are available from NASDAQ's website, although the
27
 * links to find them tend to move around over time.  At the time of
28
 * writing, the correct URL is:
29
 *
30
 * http://www.nasdaqtrader.com/content/technicalsupport/specifications/TradingProducts/OUCH4.2.pdf
31
 */
32
33
34
#include "config.h"
35
36
#include <epan/packet.h>
37
38
void proto_register_ouch(void);
39
void proto_reg_handoff_ouch(void);
40
41
static const value_string pkt_type_val[] = {
42
    { 'O', "Enter Order" },
43
    { 'U', "Replace Order" },
44
    { 'X', "Cancel Order" },
45
    { 'M', "Modify Order" },
46
    { 'S', "System Event" },
47
    { 'A', "Accepted" },
48
    { 'R', "Replaced" }, /* 'U' on the wire, but use 'R' to disambiguate */
49
    { 'C', "Canceled" },
50
    { 'D', "AIQ Canceled" },
51
    { 'E', "Executed" },
52
    { 'F', "Trade Correction" },
53
    { 'G', "Executed with Reference Price" },
54
    { 'B', "Broken Trade" },
55
    { 'K', "Price Correction" },
56
    { 'J', "Rejected" },
57
    { 'P', "Cancel Pending" },
58
    { 'I', "Cancel Reject" },
59
    { 'T', "Order Priority Update" },
60
    { 'm', "Order Modified" }, /* 'M' on the wire; 'm' to disambiguate */
61
    { 0, NULL }
62
};
63
64
65
static const value_string ouch_bbo_weight_indicator_val[] = {
66
    { '0', "0 - 0.2%" },
67
    { '1', "0.2 - 1%" },
68
    { '2', "1 - 2%" },
69
    { '3', "Greater than 2%" },
70
    { ' ', "Unspecified" },
71
    { 'S', "Sets the QBBO while joining the NBBO" },
72
    { 'N', "Improves the NBBO upon entry" },
73
    { 0, NULL }
74
};
75
76
static const value_string ouch_broken_trade_reason_val[] = {
77
    { 'E', "Erroneous" },
78
    { 'C', "Consent" },
79
    { 'S', "Supervisory" },
80
    { 'X', "External" },
81
    { 0, NULL }
82
};
83
84
static const value_string ouch_buy_sell_indicator_val[] = {
85
    { 'B', "Buy Order" },
86
    { 'S', "Sell Order" },
87
    { 'T', "Sell Short" },
88
    { 'E', "Sell Short Exempt" },
89
    { 0, NULL }
90
};
91
92
static const value_string ouch_cancel_reason_val[] = {
93
    { 'C', "Cross cancel" },
94
    { 'D', "Regulatory restriction" },
95
    { 'E', "Closed" },
96
    { 'H', "Halted" },
97
    { 'I', "Immediate or Cancel order" },
98
    { 'K', "Market Collars" },
99
    { 'Q', "Self-match prevention" },
100
    { 'S', "Supervisory" },
101
    { 'T', "Timeout" },
102
    { 'U', "User requested cancel" },
103
    { 'X', "Open Protection" },
104
    { 'Z', "System cancel" },
105
    { 0, NULL }
106
};
107
108
static const value_string ouch_capacity_val[] = {
109
    { 'A', "Agency" },
110
    { 'O', "Other" },
111
    { 'P', "Principal" },
112
    { 'R', "Riskless" },
113
    { 0, NULL }
114
};
115
116
static const value_string ouch_cross_type_val[] = {
117
    { 'N', "No Cross" },
118
    { 'O', "Opening Cross" },
119
    { 'C', "Closing Cross" },
120
    { 'I', "Intra-day Cross" }, /* Seems to have been removed */
121
    { 'H', "Halt/IPO Cross" },
122
    { 'R', "Retail" }, /* Not in 4.0 */
123
    { 'S', "Supplemental Order" },
124
    { 0, NULL }
125
};
126
127
/* Not in 4.0 */
128
static const value_string ouch_customer_type_val[] = {
129
    { 'R', "Retail designated order" },
130
    { 'N', "Not a retail designated order" },
131
    { ' ', "Default configured for port" },
132
    { 0, NULL }
133
};
134
135
static const value_string ouch_display_val[] = {
136
    { 'A', "Attributable-Price to Display" },
137
    { 'I', "Imbalance-Only" },
138
    { 'L', "Post-Only and Attributable - Price to Display" },
139
    { 'M', "Mid-Point Peg" },
140
    { 'N', "Non-Display" },
141
    { 'O', "Retail Order Type 1" }, /* Not in 4.0 */
142
    { 'P', "Post-Only" },
143
    { 'Q', "Retail Price Improvement Order" }, /* Not in 4.0 */
144
    { 'R', "Round-Lot Only" }, /* Seems to have been removed? */
145
    { 'T', "Retail Order Type 2" }, /* Not in 4.0 */
146
    { 'W', "Mid-point Peg Post Only" },
147
    { 'Y', "Anonymous-Price to Comply" },
148
    { 'Z', "Entered as displayed bu changed to non-displayed "
149
           "(Priced to comply)" }, /* New in 4.2 */
150
    { 0, NULL}
151
};
152
153
static const value_string ouch_event_code_val[] = {
154
    { 'S', "Start of Day" },
155
    { 'E', "End of Day" },
156
    { 0, NULL}
157
};
158
159
static const value_string ouch_iso_eligibility_val[] = {
160
    { 'Y', "Eligible" },
161
    { 'N', "Not eligible" },
162
    { 0, NULL }
163
};
164
165
static const value_string ouch_liquidity_flag_val[] = {
166
    { '0', "Supplemental Order Execution" },
167
    { '4', "Added displayed liquidity in a Group A Symbol" },
168
    { '5', "Added non-displayed liquidity in a Group A Symbol" },
169
    { '6', "Removed liquidity in a Group A Symbol" },
170
    { '7', "Displayed, liquidity-adding order improves the NBBO" },
171
    { '8', "Displayed, liquidity-adding order sets the QBBO while joining the NBBO" },
172
    { 'A', "Added" },
173
    { 'C', "Closing Cross" },
174
    { 'H', "Halt/IPO Cross" },
175
    { 'I', "Intraday/Post-Market Cross" }, /* Seems to have been removed */
176
    { 'J', "Non-displayed adding liquidity" },
177
    { 'K', "Halt Cross" },
178
    { 'L', "Closing Cross (imbalance-only)" },
179
    { 'M', "Opening Cross (imbalance-only)" },
180
    { 'N', "Halt Cross, orders entered in pilot symbols during the LULD Trading Pause" },
181
    { 'O', "Opening Cross" },
182
    { 'R', "Removed" },
183
    { 'W', "Added post-only" }, /* Removed 4.2 2013/02/05 */
184
    { 'a', "Added displayed liquidity in a SCIP Symbol" },
185
    { 'b', "Displayed, liquidity-adding order improves the NBBO in pilot symbol during specified LULD Pricing Pilot timeframe" },
186
    { 'c', "Added displayed liquidity in a pilot symbol during specified LULD Pricing Pilot timeframe" },
187
    { 'd', "Retail designated execution that removed liquidity" },
188
    { 'e', "Retail designated execution that added displayed liquidity" },
189
    { 'f', "Retail designated execution that added non-displayed liquidity" },
190
    { 'g', "Added non-displayed mid-point liquidity in a Group A Symbol" },
191
    { 'h', "Removed liquidity in a pilot symbol during specified LULD Pricing Pilot timeframe" },
192
    { 'j', "RPI (Retail Price Improving) order provides liquidity" },
193
    { 'k', "Added liquidity via a midpoint order" },
194
    { 'm', "Removed liquidity at a midpoint" },
195
    { 'r', "Retail Order removes RPI liquidity" },
196
    { 't', "Retail Order removes price improving non-displayed liquidity other than RPI liquidity" },
197
    { 'x', "Displayed, liquidity-adding order improves the NBBO in a SCIP Symbol" },
198
    { 'y', "Displayed, liquidity-adding order set the QBBO while joining the NBBO in a SCIP Symbol" },
199
    { 0, NULL }
200
};
201
202
static const value_string ouch_order_state_val[] = {
203
    { 'L', "Order Live" },
204
    { 'D', "Order Dead" },
205
    { 0, NULL }
206
};
207
208
static const value_string ouch_price_correction_reason_val[] = {
209
    { 'E', "Erroneous" },
210
    { 'C', "Consent" },
211
    { 'S', "Supervisory" },
212
    { 'X', "External" },
213
    { 0, NULL }
214
};
215
216
static const value_string ouch_reference_price_type_val[] = {
217
    { 'I', "Intraday Indicative Value" },
218
    { 0, NULL }
219
};
220
221
static const value_string ouch_reject_reason_val[] = {
222
    { 'T', "Test Mode" },
223
    { 'H', "Halted" },
224
    { 'Z', "Shares exceeds configured safety threshold" },
225
    { 'S', "Invalid Stock" },
226
    { 'D', "Invalid Display Type" },
227
    { 'C', "NASDAQ is Closed" },
228
    { 'L', "Requested firm not authorized for requested clearing "
229
           "type on this account" },
230
    { 'M', "Outside of permitted times for requested clearing type" },
231
    { 'R', "This order is not allowed in this type of cross" },
232
    { 'X', "Invalid Price" },
233
    { 'N', "Invalid Minimum Quantity" },
234
    { 'O', "Other" },
235
    { 'W', "Invalid Mid-point Post Only Price" },
236
    { 'a', "Reject All enabled" },
237
    { 'b', "Easy to Borrow (ETB) reject" },
238
    { 'c', "Restricted symbol list reject" },
239
    { 'd', "ISO order restriction" },
240
    { 'e', "Odd lot order restriction" },
241
    { 'f', "Mid-Point order restriction" },
242
    { 'g', "Pre-market order restriction" },
243
    { 'h', "Post-market order restriction" },
244
    { 'i', "Short sale order restriction" },
245
    { 'j', "On Open order restriction" },
246
    { 'k', "On Close order restriction" },
247
    { 'l', "Two sided quote reject" },
248
    { 'm', "Exceeded shares limit" },
249
    { 'n', "Exceeded dollar value limit" },
250
    { 0, NULL}
251
};
252
253
static const value_string ouch_trade_correction_reason_val[] = {
254
    { 'N', "Adjusted to NAV" },
255
    { 0, NULL }
256
};
257
258
259
/* Initialize the protocol and registered fields */
260
static int proto_ouch;
261
static dissector_handle_t ouch_handle;
262
263
/* Initialize the subtree pointers */
264
static int ett_ouch;
265
266
static int hf_ouch_bbo_weight_indicator;
267
static int hf_ouch_broken_trade_reason;
268
static int hf_ouch_buy_sell_indicator;
269
static int hf_ouch_cancel_reason;
270
static int hf_ouch_capacity;
271
static int hf_ouch_cross_type;
272
static int hf_ouch_customer_type;
273
static int hf_ouch_decrement_shares;
274
static int hf_ouch_display;
275
static int hf_ouch_event_code;
276
static int hf_ouch_executed_shares;
277
static int hf_ouch_execution_price;
278
static int hf_ouch_existing_order_token;
279
static int hf_ouch_firm;
280
static int hf_ouch_iso_eligible;
281
static int hf_ouch_liquidity_flag;
282
static int hf_ouch_match_number;
283
static int hf_ouch_message;
284
static int hf_ouch_min_quantity;
285
static int hf_ouch_new_execution_price;
286
static int hf_ouch_order_reference_number;
287
static int hf_ouch_order_state;
288
static int hf_ouch_order_token;
289
static int hf_ouch_packet_type;
290
static int hf_ouch_previous_order_token;
291
static int hf_ouch_price;
292
static int hf_ouch_price_correction_reason;
293
static int hf_ouch_quantity_prevented_from_trading;
294
static int hf_ouch_reference_price;
295
static int hf_ouch_reference_price_type;
296
static int hf_ouch_reject_reason;
297
static int hf_ouch_replacement_order_token;
298
static int hf_ouch_shares;
299
static int hf_ouch_stock;
300
static int hf_ouch_tif;
301
static int hf_ouch_timestamp;
302
static int hf_ouch_trade_correction_reason;
303
304
305
/** Format an OUCH timestamp into a useful string
306
 *
307
 * We use this function rather than a BASE_CUSTOM formatter because
308
 * BASE_CUSTOM doesn't support passing a 64-bit value to the
309
 * formatting function. */
310
static void
311
ouch_tree_add_timestamp(
312
    packet_info *pinfo,
313
    proto_tree *tree,
314
    const int hf,
315
    tvbuff_t *tvb,
316
    int offset)
317
0
{
318
0
    uint64_t ts = tvb_get_ntoh64(tvb, offset);
319
0
    char *buf = (char *)wmem_alloc(pinfo->pool, ITEM_LABEL_LENGTH);
320
0
    uint32_t tmp, hours, mins, secs, nsecs;
321
322
0
    nsecs = (uint32_t)(ts % UINT64_C(1000000000));
323
0
    tmp = (uint32_t)(ts / UINT64_C(1000000000));
324
325
0
    hours = tmp / 3600;
326
0
    mins = (tmp % 3600) / 60;
327
0
    secs = tmp % 60;
328
329
0
    snprintf(buf, ITEM_LABEL_LENGTH,
330
0
               "%u:%02u:%02u.%09u",
331
0
               hours, mins, secs, nsecs);
332
333
0
    proto_tree_add_string(tree, hf, tvb, offset, 8, buf);
334
0
}
335
336
/** BASE_CUSTOM formatter for prices
337
 *
338
 * OUCH prices are integers, with four implicit decimal places.  So we
339
 * insert the decimal point, and add a leading dollar sign as well. */
340
static void
341
format_price(
342
    char *buf,
343
    uint32_t value)
344
0
{
345
0
    if (value == 0x7fffffff) {
346
0
        snprintf(buf, ITEM_LABEL_LENGTH, "%s", "Market");
347
0
    } else {
348
0
        snprintf(buf, ITEM_LABEL_LENGTH,
349
0
                   "$%u.%04u",
350
0
                   value / 10000, value % 10000);
351
0
    }
352
0
}
353
354
/** BASE_CUSTOM formatter for reference price type code
355
 *
356
 * Displays the code value as a character, not its ASCII value, as
357
 * would be done by BASE_DEC and friends. */
358
static void
359
format_reference_price_type(
360
    char *buf,
361
    uint32_t value)
362
0
{
363
0
    const char *name = val_to_str_const(value,
364
0
                                        ouch_reference_price_type_val,
365
0
                                        "Unknown");
366
367
0
    if (value >= 0x20 && value < 0x7f) {
368
0
        snprintf(buf, ITEM_LABEL_LENGTH, "%s (%c)", name, (char)value);
369
0
    } else {
370
0
        snprintf(buf, ITEM_LABEL_LENGTH, "%s (0x%02x)", name, value);
371
0
    }
372
0
}
373
374
/** BASE_CUSTOM formatter for the Time In Force (TIF) code
375
 *
376
 * There are three reserved values for the TIF: 0, 99998 and 99999.
377
 * These are trapped and displayed as an appropriate string.  All
378
 * other values are printed as a duration in hours, minutes and
379
 * seconds. */
380
static void
381
format_tif(
382
    char *buf,
383
    uint32_t value)
384
0
{
385
0
    uint32_t hours;
386
0
    uint32_t mins;
387
0
    uint32_t secs;
388
389
0
    switch (value) {
390
0
    case 0:
391
0
        snprintf(buf, ITEM_LABEL_LENGTH, "Immediate Or Cancel (%u)", value);
392
0
        break;
393
394
0
    case 99998:
395
0
        snprintf(buf, ITEM_LABEL_LENGTH, "Market Hours (%u)", value);
396
0
        break;
397
398
0
    case 99999:
399
0
        snprintf(buf, ITEM_LABEL_LENGTH, "System Hours (%u)", value);
400
0
        break;
401
402
0
    default:
403
0
        hours = value / 3600;
404
0
        mins = (value % 3600) / 60;
405
0
        secs = value % 60;
406
407
0
        snprintf(buf, ITEM_LABEL_LENGTH,
408
0
                   "%uh %02um %02us (%u seconds)",
409
0
                   hours, mins, secs,
410
0
                   value);
411
0
        break;
412
0
    }
413
0
}
414
415
416
static int
417
dissect_ouch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
418
0
{
419
0
    proto_item *ti;
420
0
    proto_tree *ouch_tree = NULL;
421
0
    const char *pkt_name;
422
0
    unsigned reported_len;
423
0
    uint8_t pkt_type;
424
0
    unsigned offset = 0;
425
426
    /* Get the OUCH message type value */
427
0
    pkt_type = tvb_get_uint8(tvb, offset);
428
0
    reported_len = tvb_reported_length(tvb);
429
430
    /* OUCH has two messages with the same code: Replace Order and
431
     * Replaced.  It's possible to tell which is which because clients
432
     * send the Replace Order, and NASDAQ sends Replaced replies.
433
     * Nonetheless, this complicates the switch, so instead we
434
     * distinguish between them by length, and use 'R' for Replaced
435
     * (like XPRS does). */
436
0
    if (pkt_type == 'U' && (reported_len == 79 || reported_len == 80)) {
437
0
        pkt_type = 'R';
438
0
    }
439
440
    /* OUCH has two messages with the same code: Modify Order and
441
     * Modified.  Again, one is sent by clients, the other sent by
442
     * NASDAQ.  We change Modified to 'm' for simplicity in the
443
     * switch. */
444
0
    if (pkt_type == 'M' && reported_len == 28) {
445
0
        pkt_type = 'm';
446
0
    }
447
448
    /* Since we use the packet name a few times, get and save that value */
449
0
    pkt_name = val_to_str(pinfo->pool, pkt_type, pkt_type_val, "Unknown (%u)");
450
451
    /* Set the protocol name in the summary display */
452
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "OUCH");
453
454
    /* Set the packet name in the info column */
455
0
    col_add_str(pinfo->cinfo, COL_INFO, pkt_name);
456
457
0
    if (tree) {
458
        /* Create a sub-tree for the OUCH packet details */
459
0
        ti = proto_tree_add_item(tree,
460
0
                                 proto_ouch,
461
0
                                 tvb, 0, -1, ENC_NA);
462
463
0
        ouch_tree = proto_item_add_subtree(ti, ett_ouch);
464
465
        /* Append the packet name to the sub-tree item */
466
0
        proto_item_append_text(ti, ", %s", pkt_name);
467
468
        /* Packet type (using the cooked value). */
469
0
        proto_tree_add_item(ouch_tree, hf_ouch_packet_type,
470
0
                                  tvb, offset, 1, ENC_ASCII);
471
0
        offset += 1;
472
473
0
        switch (pkt_type) {
474
0
        case 'O': /* Enter Order */
475
0
            proto_tree_add_item(ouch_tree,
476
0
                                hf_ouch_order_token,
477
0
                                tvb, offset, 14,
478
0
                                ENC_ASCII);
479
0
            offset += 14;
480
481
0
            proto_tree_add_item(ouch_tree,
482
0
                                hf_ouch_buy_sell_indicator,
483
0
                                tvb, offset, 1,
484
0
                                ENC_ASCII);
485
0
            offset += 1;
486
487
0
            proto_tree_add_item(ouch_tree,
488
0
                                hf_ouch_shares,
489
0
                                tvb, offset, 4,
490
0
                                ENC_BIG_ENDIAN);
491
0
            offset += 4;
492
493
0
            proto_tree_add_item(ouch_tree,
494
0
                                hf_ouch_stock,
495
0
                                tvb, offset, 8,
496
0
                                ENC_ASCII);
497
0
            offset += 8;
498
499
0
            proto_tree_add_item(ouch_tree,
500
0
                                hf_ouch_price,
501
0
                                tvb, offset, 4,
502
0
                                ENC_BIG_ENDIAN);
503
0
            offset += 4;
504
505
0
            proto_tree_add_item(ouch_tree,
506
0
                                hf_ouch_tif,
507
0
                                tvb, offset, 4,
508
0
                                ENC_BIG_ENDIAN);
509
0
            offset += 4;
510
511
0
            proto_tree_add_item(ouch_tree,
512
0
                                hf_ouch_firm,
513
0
                                tvb, offset, 4,
514
0
                                ENC_ASCII);
515
0
            offset += 4;
516
517
0
            proto_tree_add_item(ouch_tree,
518
0
                                hf_ouch_display,
519
0
                                tvb, offset, 1,
520
0
                                ENC_ASCII);
521
0
            offset += 1;
522
523
0
            proto_tree_add_item(ouch_tree,
524
0
                                hf_ouch_capacity,
525
0
                                tvb, offset, 1,
526
0
                                ENC_ASCII);
527
0
            offset += 1;
528
529
0
            proto_tree_add_item(ouch_tree,
530
0
                                hf_ouch_iso_eligible,
531
0
                                tvb, offset, 1,
532
0
                                ENC_ASCII);
533
0
            offset += 1;
534
535
0
            proto_tree_add_item(ouch_tree,
536
0
                                hf_ouch_min_quantity,
537
0
                                tvb, offset, 4,
538
0
                                ENC_BIG_ENDIAN);
539
0
            offset += 4;
540
541
0
            proto_tree_add_item(ouch_tree,
542
0
                                hf_ouch_cross_type,
543
0
                                tvb, offset, 1,
544
0
                                ENC_ASCII);
545
0
            offset += 1;
546
547
0
            if (reported_len >= 49) { /* Added in 4.1 */
548
0
                proto_tree_add_item(ouch_tree,
549
0
                                    hf_ouch_customer_type,
550
0
                                    tvb, offset, 1,
551
0
                                    ENC_ASCII);
552
0
                offset += 1;
553
0
            }
554
0
            break;
555
556
0
        case 'A': /* Accepted */
557
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
558
0
                                    hf_ouch_timestamp,
559
0
                                    tvb, offset);
560
0
            offset += 8;
561
562
0
            proto_tree_add_item(ouch_tree,
563
0
                                hf_ouch_order_token,
564
0
                                tvb, offset, 14,
565
0
                                ENC_ASCII);
566
0
            offset += 14;
567
568
0
            proto_tree_add_item(ouch_tree,
569
0
                                hf_ouch_buy_sell_indicator,
570
0
                                tvb, offset, 1,
571
0
                                ENC_ASCII);
572
0
            offset += 1;
573
574
0
            proto_tree_add_item(ouch_tree,
575
0
                                hf_ouch_shares,
576
0
                                tvb, offset, 4,
577
0
                                ENC_BIG_ENDIAN);
578
0
            offset += 4;
579
580
0
            proto_tree_add_item(ouch_tree,
581
0
                                hf_ouch_stock,
582
0
                                tvb, offset, 8,
583
0
                                ENC_ASCII);
584
0
            offset += 8;
585
586
0
            proto_tree_add_item(ouch_tree,
587
0
                                hf_ouch_price,
588
0
                                tvb, offset, 4,
589
0
                                ENC_BIG_ENDIAN);
590
0
            offset += 4;
591
592
0
            proto_tree_add_item(ouch_tree,
593
0
                                hf_ouch_tif,
594
0
                                tvb, offset, 4,
595
0
                                ENC_BIG_ENDIAN);
596
0
            offset += 4;
597
598
0
            proto_tree_add_item(ouch_tree,
599
0
                                hf_ouch_firm,
600
0
                                tvb, offset, 4,
601
0
                                ENC_ASCII);
602
0
            offset += 4;
603
604
0
            proto_tree_add_item(ouch_tree,
605
0
                                hf_ouch_display,
606
0
                                tvb, offset, 1,
607
0
                                ENC_ASCII);
608
0
            offset += 1;
609
610
0
            proto_tree_add_item(ouch_tree,
611
0
                                hf_ouch_order_reference_number,
612
0
                                tvb, offset, 8,
613
0
                                ENC_BIG_ENDIAN);
614
0
            offset += 8;
615
616
0
            proto_tree_add_item(ouch_tree,
617
0
                                hf_ouch_capacity,
618
0
                                tvb, offset, 1,
619
0
                                ENC_ASCII);
620
0
            offset += 1;
621
622
0
            proto_tree_add_item(ouch_tree,
623
0
                                hf_ouch_iso_eligible,
624
0
                                tvb, offset, 1,
625
0
                                ENC_ASCII);
626
0
            offset += 1;
627
628
0
            proto_tree_add_item(ouch_tree,
629
0
                                hf_ouch_min_quantity,
630
0
                                tvb, offset, 4,
631
0
                                ENC_BIG_ENDIAN);
632
0
            offset += 4;
633
634
0
            proto_tree_add_item(ouch_tree,
635
0
                                hf_ouch_cross_type,
636
0
                                tvb, offset, 1,
637
0
                                ENC_ASCII);
638
0
            offset += 1;
639
640
0
            proto_tree_add_item(ouch_tree,
641
0
                                hf_ouch_order_state,
642
0
                                tvb, offset, 1,
643
0
                                ENC_ASCII);
644
0
            offset += 1;
645
646
0
            if (reported_len >= 66) { /* Added in 4.2 */
647
0
                proto_tree_add_item(ouch_tree,
648
0
                                    hf_ouch_bbo_weight_indicator,
649
0
                                    tvb, offset, 1,
650
0
                                    ENC_ASCII);
651
0
                offset += 1;
652
0
            }
653
0
            break;
654
655
0
        case 'U': /* Replace Order */
656
0
            proto_tree_add_item(ouch_tree,
657
0
                                hf_ouch_existing_order_token,
658
0
                                tvb, offset, 14,
659
0
                                ENC_ASCII);
660
0
            offset += 14;
661
662
0
            proto_tree_add_item(ouch_tree,
663
0
                                hf_ouch_replacement_order_token,
664
0
                                tvb, offset, 14,
665
0
                                ENC_ASCII);
666
0
            offset += 14;
667
668
0
            proto_tree_add_item(ouch_tree,
669
0
                                hf_ouch_shares,
670
0
                                tvb, offset, 4,
671
0
                                ENC_BIG_ENDIAN);
672
0
            offset += 4;
673
674
0
            proto_tree_add_item(ouch_tree,
675
0
                                hf_ouch_price,
676
0
                                tvb, offset, 4,
677
0
                                ENC_BIG_ENDIAN);
678
0
            offset += 4;
679
680
0
            proto_tree_add_item(ouch_tree,
681
0
                                hf_ouch_tif,
682
0
                                tvb, offset, 4,
683
0
                                ENC_BIG_ENDIAN);
684
0
            offset += 4;
685
686
0
            proto_tree_add_item(ouch_tree,
687
0
                                hf_ouch_display,
688
0
                                tvb, offset, 1,
689
0
                                ENC_ASCII);
690
0
            offset += 1;
691
692
0
            proto_tree_add_item(ouch_tree,
693
0
                                hf_ouch_iso_eligible,
694
0
                                tvb, offset, 1,
695
0
                                ENC_ASCII);
696
0
            offset += 1;
697
698
0
            proto_tree_add_item(ouch_tree,
699
0
                                hf_ouch_min_quantity,
700
0
                                tvb, offset, 4,
701
0
                                ENC_BIG_ENDIAN);
702
0
            offset += 4;
703
0
            break;
704
705
0
        case 'X': /* Cancel Order */
706
0
            proto_tree_add_item(ouch_tree,
707
0
                                hf_ouch_order_token,
708
0
                                tvb, offset, 14,
709
0
                                ENC_ASCII);
710
0
            offset += 14;
711
712
0
            proto_tree_add_item(ouch_tree,
713
0
                                hf_ouch_shares,
714
0
                                tvb, offset, 4,
715
0
                                ENC_BIG_ENDIAN);
716
0
            offset += 4;
717
0
            break;
718
719
0
        case 'M': /* Modify Order (from 4.2 onwards) */
720
0
            proto_tree_add_item(ouch_tree,
721
0
                                hf_ouch_order_token,
722
0
                                tvb, offset, 14,
723
0
                                ENC_ASCII);
724
0
            offset += 14;
725
726
0
            proto_tree_add_item(ouch_tree,
727
0
                                hf_ouch_buy_sell_indicator,
728
0
                                tvb, offset, 1,
729
0
                                ENC_ASCII);
730
0
            offset += 1;
731
732
0
            proto_tree_add_item(ouch_tree,
733
0
                                hf_ouch_shares,
734
0
                                tvb, offset, 4,
735
0
                                ENC_BIG_ENDIAN);
736
0
            offset += 4;
737
0
            break;
738
739
0
        case 'S': /* System Event */
740
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
741
0
                                    hf_ouch_timestamp,
742
0
                                    tvb, offset);
743
0
            offset += 8;
744
745
0
            proto_tree_add_item(ouch_tree,
746
0
                                hf_ouch_event_code,
747
0
                                tvb, offset, 1,
748
0
                                ENC_ASCII);
749
0
            offset += 1;
750
0
            break;
751
752
0
        case 'R': /* Replaced */
753
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
754
0
                                    hf_ouch_timestamp,
755
0
                                    tvb, offset);
756
0
            offset += 8;
757
758
0
            proto_tree_add_item(ouch_tree,
759
0
                                hf_ouch_replacement_order_token,
760
0
                                tvb, offset, 14,
761
0
                                ENC_ASCII);
762
0
            offset += 14;
763
764
0
            proto_tree_add_item(ouch_tree,
765
0
                                hf_ouch_buy_sell_indicator,
766
0
                                tvb, offset, 1,
767
0
                                ENC_ASCII);
768
0
            offset += 1;
769
770
0
            proto_tree_add_item(ouch_tree,
771
0
                                hf_ouch_shares,
772
0
                                tvb, offset, 4,
773
0
                                ENC_BIG_ENDIAN);
774
0
            offset += 4;
775
776
0
            proto_tree_add_item(ouch_tree,
777
0
                                hf_ouch_stock,
778
0
                                tvb, offset, 8,
779
0
                                ENC_ASCII);
780
0
            offset += 8;
781
782
0
            proto_tree_add_item(ouch_tree,
783
0
                                hf_ouch_price,
784
0
                                tvb, offset, 4,
785
0
                                ENC_BIG_ENDIAN);
786
0
            offset += 4;
787
788
0
            proto_tree_add_item(ouch_tree,
789
0
                                hf_ouch_tif,
790
0
                                tvb, offset, 4,
791
0
                                ENC_BIG_ENDIAN);
792
0
            offset += 4;
793
794
0
            proto_tree_add_item(ouch_tree,
795
0
                                hf_ouch_firm,
796
0
                                tvb, offset, 4,
797
0
                                ENC_ASCII);
798
0
            offset += 4;
799
800
0
            proto_tree_add_item(ouch_tree,
801
0
                                hf_ouch_display,
802
0
                                tvb, offset, 1,
803
0
                                ENC_ASCII);
804
0
            offset += 1;
805
806
0
            proto_tree_add_item(ouch_tree,
807
0
                                hf_ouch_order_reference_number,
808
0
                                tvb, offset, 8,
809
0
                                ENC_BIG_ENDIAN);
810
0
            offset += 8;
811
812
0
            proto_tree_add_item(ouch_tree,
813
0
                                hf_ouch_capacity,
814
0
                                tvb, offset, 1,
815
0
                                ENC_ASCII);
816
0
            offset += 1;
817
818
0
            proto_tree_add_item(ouch_tree,
819
0
                                hf_ouch_iso_eligible,
820
0
                                tvb, offset, 1,
821
0
                                ENC_ASCII);
822
0
            offset += 1;
823
824
0
            proto_tree_add_item(ouch_tree,
825
0
                                hf_ouch_min_quantity,
826
0
                                tvb, offset, 4,
827
0
                                ENC_BIG_ENDIAN);
828
0
            offset += 4;
829
830
0
            proto_tree_add_item(ouch_tree,
831
0
                                hf_ouch_cross_type,
832
0
                                tvb, offset, 1,
833
0
                                ENC_ASCII);
834
0
            offset += 1;
835
836
0
            proto_tree_add_item(ouch_tree,
837
0
                                hf_ouch_order_state,
838
0
                                tvb, offset, 1,
839
0
                                ENC_ASCII);
840
0
            offset += 1;
841
842
0
            proto_tree_add_item(ouch_tree,
843
0
                                hf_ouch_previous_order_token,
844
0
                                tvb, offset, 14,
845
0
                                ENC_ASCII);
846
0
            offset += 14;
847
848
0
            if (reported_len >= 80) { /* Added in 4.2 */
849
0
                proto_tree_add_item(ouch_tree,
850
0
                                    hf_ouch_bbo_weight_indicator,
851
0
                                    tvb, offset, 1,
852
0
                                    ENC_ASCII);
853
0
                offset += 1;
854
0
            }
855
0
            break;
856
857
0
        case 'C': /* Canceled */
858
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
859
0
                                    hf_ouch_timestamp,
860
0
                                    tvb, offset);
861
0
            offset += 8;
862
863
0
            proto_tree_add_item(ouch_tree,
864
0
                                hf_ouch_order_token,
865
0
                                tvb, offset, 14,
866
0
                                ENC_ASCII);
867
0
            offset += 14;
868
869
0
            proto_tree_add_item(ouch_tree,
870
0
                                hf_ouch_decrement_shares,
871
0
                                tvb, offset, 4,
872
0
                                ENC_BIG_ENDIAN);
873
0
            offset += 4;
874
875
0
            proto_tree_add_item(ouch_tree,
876
0
                                hf_ouch_cancel_reason,
877
0
                                tvb, offset, 1,
878
0
                                ENC_ASCII);
879
0
            offset += 1;
880
0
            break;
881
882
0
        case 'D': /* AIQ Canceled */
883
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
884
0
                                    hf_ouch_timestamp,
885
0
                                    tvb, offset);
886
0
            offset += 8;
887
888
0
            proto_tree_add_item(ouch_tree,
889
0
                                hf_ouch_order_token,
890
0
                                tvb, offset, 14,
891
0
                                ENC_ASCII);
892
0
            offset += 14;
893
894
0
            proto_tree_add_item(ouch_tree,
895
0
                                hf_ouch_decrement_shares,
896
0
                                tvb, offset, 4,
897
0
                                ENC_BIG_ENDIAN);
898
0
            offset += 4;
899
900
0
            proto_tree_add_item(ouch_tree,
901
0
                                hf_ouch_cancel_reason,
902
0
                                tvb, offset, 1,
903
0
                                ENC_ASCII);
904
0
            offset += 1;
905
906
0
            proto_tree_add_item(ouch_tree,
907
0
                                hf_ouch_quantity_prevented_from_trading,
908
0
                                tvb, offset, 4,
909
0
                                ENC_BIG_ENDIAN);
910
0
            offset += 4;
911
912
0
            proto_tree_add_item(ouch_tree,
913
0
                                hf_ouch_execution_price,
914
0
                                tvb, offset, 4,
915
0
                                ENC_BIG_ENDIAN);
916
0
            offset += 4;
917
918
0
            proto_tree_add_item(ouch_tree,
919
0
                                hf_ouch_liquidity_flag,
920
0
                                tvb, offset, 1,
921
0
                                ENC_ASCII);
922
0
            offset += 1;
923
0
            break;
924
925
0
        case 'E': /* Executed */
926
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
927
0
                                    hf_ouch_timestamp,
928
0
                                    tvb, offset);
929
0
            offset += 8;
930
931
0
            proto_tree_add_item(ouch_tree,
932
0
                                hf_ouch_order_token,
933
0
                                tvb, offset, 14,
934
0
                                ENC_ASCII);
935
0
            offset += 14;
936
937
0
            proto_tree_add_item(ouch_tree,
938
0
                                hf_ouch_executed_shares,
939
0
                                tvb, offset, 4,
940
0
                                ENC_BIG_ENDIAN);
941
0
            offset += 4;
942
943
0
            proto_tree_add_item(ouch_tree,
944
0
                                hf_ouch_execution_price,
945
0
                                tvb, offset, 4,
946
0
                                ENC_BIG_ENDIAN);
947
0
            offset += 4;
948
949
0
            proto_tree_add_item(ouch_tree,
950
0
                                hf_ouch_liquidity_flag,
951
0
                                tvb, offset, 1,
952
0
                                ENC_ASCII);
953
0
            offset += 1;
954
955
0
            proto_tree_add_item(ouch_tree,
956
0
                                hf_ouch_match_number,
957
0
                                tvb, offset, 8,
958
0
                                ENC_BIG_ENDIAN);
959
0
            offset += 8;
960
0
            break;
961
962
0
        case 'B': /* Broken Trade */
963
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
964
0
                                    hf_ouch_timestamp,
965
0
                                    tvb, offset);
966
0
            offset += 8;
967
968
0
            proto_tree_add_item(ouch_tree,
969
0
                                hf_ouch_order_token,
970
0
                                tvb, offset, 14,
971
0
                                ENC_ASCII);
972
0
            offset += 14;
973
974
0
            proto_tree_add_item(ouch_tree,
975
0
                                hf_ouch_match_number,
976
0
                                tvb, offset, 8,
977
0
                                ENC_BIG_ENDIAN);
978
0
            offset += 8;
979
980
0
            proto_tree_add_item(ouch_tree,
981
0
                                hf_ouch_broken_trade_reason,
982
0
                                tvb, offset, 1,
983
0
                                ENC_ASCII);
984
0
            offset += 1;
985
0
            break;
986
987
0
        case 'F': /* Trade Correction (4.2 onwards) */
988
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
989
0
                                    hf_ouch_timestamp,
990
0
                                    tvb, offset);
991
0
            offset += 8;
992
993
0
            proto_tree_add_item(ouch_tree,
994
0
                                hf_ouch_order_token,
995
0
                                tvb, offset, 14,
996
0
                                ENC_ASCII);
997
0
            offset += 14;
998
999
0
            proto_tree_add_item(ouch_tree,
1000
0
                                hf_ouch_executed_shares,
1001
0
                                tvb, offset, 4,
1002
0
                                ENC_BIG_ENDIAN);
1003
0
            offset += 4;
1004
1005
0
            proto_tree_add_item(ouch_tree,
1006
0
                                hf_ouch_execution_price,
1007
0
                                tvb, offset, 4,
1008
0
                                ENC_BIG_ENDIAN);
1009
0
            offset += 4;
1010
1011
0
            proto_tree_add_item(ouch_tree,
1012
0
                                hf_ouch_liquidity_flag,
1013
0
                                tvb, offset, 1,
1014
0
                                ENC_ASCII);
1015
0
            offset += 1;
1016
1017
0
            proto_tree_add_item(ouch_tree,
1018
0
                                hf_ouch_match_number,
1019
0
                                tvb, offset, 8,
1020
0
                                ENC_BIG_ENDIAN);
1021
0
            offset += 8;
1022
1023
0
            proto_tree_add_item(ouch_tree,
1024
0
                                hf_ouch_trade_correction_reason,
1025
0
                                tvb, offset, 1,
1026
0
                                ENC_ASCII);
1027
0
            offset += 1;
1028
0
            break;
1029
1030
0
        case 'G': /* Executed with Reference Price (4.2 onwards) */
1031
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1032
0
                                    hf_ouch_timestamp,
1033
0
                                    tvb, offset);
1034
0
            offset += 8;
1035
1036
0
            proto_tree_add_item(ouch_tree,
1037
0
                                hf_ouch_order_token,
1038
0
                                tvb, offset, 14,
1039
0
                                ENC_ASCII);
1040
0
            offset += 14;
1041
1042
0
            proto_tree_add_item(ouch_tree,
1043
0
                                hf_ouch_executed_shares,
1044
0
                                tvb, offset, 4,
1045
0
                                ENC_BIG_ENDIAN);
1046
0
            offset += 4;
1047
1048
0
            proto_tree_add_item(ouch_tree,
1049
0
                                hf_ouch_execution_price,
1050
0
                                tvb, offset, 4,
1051
0
                                ENC_BIG_ENDIAN);
1052
0
            offset += 4;
1053
1054
0
            proto_tree_add_item(ouch_tree,
1055
0
                                hf_ouch_liquidity_flag,
1056
0
                                tvb, offset, 1,
1057
0
                                ENC_ASCII);
1058
0
            offset += 1;
1059
1060
0
            proto_tree_add_item(ouch_tree,
1061
0
                                hf_ouch_match_number,
1062
0
                                tvb, offset, 8,
1063
0
                                ENC_BIG_ENDIAN);
1064
0
            offset += 8;
1065
1066
0
            proto_tree_add_item(ouch_tree,
1067
0
                                hf_ouch_reference_price,
1068
0
                                tvb, offset, 4,
1069
0
                                ENC_BIG_ENDIAN);
1070
0
            offset += 4;
1071
1072
0
            proto_tree_add_item(ouch_tree,
1073
0
                                hf_ouch_reference_price_type,
1074
0
                                tvb, offset, 1,
1075
0
                                ENC_BIG_ENDIAN);
1076
0
            offset += 1;
1077
0
            break;
1078
1079
0
        case 'K': /* Price Correction */
1080
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1081
0
                                    hf_ouch_timestamp,
1082
0
                                    tvb, offset);
1083
0
            offset += 8;
1084
1085
0
            proto_tree_add_item(ouch_tree,
1086
0
                                hf_ouch_order_token,
1087
0
                                tvb, offset, 14,
1088
0
                                ENC_ASCII);
1089
0
            offset += 14;
1090
1091
0
            proto_tree_add_item(ouch_tree,
1092
0
                                hf_ouch_match_number,
1093
0
                                tvb, offset, 8,
1094
0
                                ENC_BIG_ENDIAN);
1095
0
            offset += 8;
1096
1097
0
            proto_tree_add_item(ouch_tree,
1098
0
                                hf_ouch_new_execution_price,
1099
0
                                tvb, offset, 4,
1100
0
                                ENC_BIG_ENDIAN);
1101
0
            offset += 4;
1102
1103
0
            proto_tree_add_item(ouch_tree,
1104
0
                                hf_ouch_price_correction_reason,
1105
0
                                tvb, offset, 1,
1106
0
                                ENC_ASCII);
1107
0
            offset += 1;
1108
0
            break;
1109
1110
0
        case 'J': /* Rejected Order */
1111
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1112
0
                                    hf_ouch_timestamp,
1113
0
                                    tvb, offset);
1114
0
            offset += 8;
1115
1116
0
            proto_tree_add_item(ouch_tree,
1117
0
                                hf_ouch_order_token,
1118
0
                                tvb, offset, 14,
1119
0
                                ENC_ASCII);
1120
0
            offset += 14;
1121
1122
0
            proto_tree_add_item(ouch_tree,
1123
0
                                hf_ouch_reject_reason,
1124
0
                                tvb, offset, 1,
1125
0
                                ENC_ASCII);
1126
0
            offset += 1;
1127
0
            break;
1128
1129
0
        case 'P': /* Cancel Pending */
1130
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1131
0
                                    hf_ouch_timestamp,
1132
0
                                    tvb, offset);
1133
0
            offset += 8;
1134
1135
0
            proto_tree_add_item(ouch_tree,
1136
0
                                hf_ouch_order_token,
1137
0
                                tvb, offset, 14,
1138
0
                                ENC_ASCII);
1139
0
            offset += 14;
1140
0
            break;
1141
1142
0
        case 'I': /* Cancel Reject */
1143
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1144
0
                                    hf_ouch_timestamp,
1145
0
                                    tvb, offset);
1146
0
            offset += 8;
1147
1148
0
            proto_tree_add_item(ouch_tree,
1149
0
                                hf_ouch_order_token,
1150
0
                                tvb, offset, 14,
1151
0
                                ENC_ASCII);
1152
0
            offset += 14;
1153
0
            break;
1154
1155
0
        case 'T': /* Order Priority Update (4.2 onwards) */
1156
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1157
0
                                    hf_ouch_timestamp,
1158
0
                                    tvb, offset);
1159
0
            offset += 8;
1160
1161
0
            proto_tree_add_item(ouch_tree,
1162
0
                                hf_ouch_order_token,
1163
0
                                tvb, offset, 14,
1164
0
                                ENC_ASCII);
1165
0
            offset += 14;
1166
1167
0
            proto_tree_add_item(ouch_tree,
1168
0
                                hf_ouch_price,
1169
0
                                tvb, offset, 4,
1170
0
                                ENC_BIG_ENDIAN);
1171
0
            offset += 4;
1172
1173
0
            proto_tree_add_item(ouch_tree,
1174
0
                                hf_ouch_display,
1175
0
                                tvb, offset, 1,
1176
0
                                ENC_ASCII);
1177
0
            offset += 1;
1178
1179
0
            proto_tree_add_item(ouch_tree,
1180
0
                                hf_ouch_order_reference_number,
1181
0
                                tvb, offset, 8,
1182
0
                                ENC_BIG_ENDIAN);
1183
0
            offset += 8;
1184
0
            break;
1185
1186
0
        case 'm': /* Order Modified (4.2 onwards) */
1187
0
            ouch_tree_add_timestamp(pinfo, ouch_tree,
1188
0
                                    hf_ouch_timestamp,
1189
0
                                    tvb, offset);
1190
0
            offset += 8;
1191
1192
0
            proto_tree_add_item(ouch_tree,
1193
0
                                hf_ouch_order_token,
1194
0
                                tvb, offset, 14,
1195
0
                                ENC_ASCII);
1196
0
            offset += 14;
1197
1198
0
            proto_tree_add_item(ouch_tree,
1199
0
                                hf_ouch_buy_sell_indicator,
1200
0
                                tvb, offset, 1,
1201
0
                                ENC_ASCII);
1202
0
            offset += 1;
1203
1204
0
            proto_tree_add_item(ouch_tree,
1205
0
                                hf_ouch_shares,
1206
0
                                tvb, offset, 4,
1207
0
                                ENC_BIG_ENDIAN);
1208
0
            offset += 4;
1209
0
            break;
1210
1211
0
        default:
1212
            /* Unknown */
1213
0
            proto_tree_add_item(tree,
1214
0
                                hf_ouch_message,
1215
0
                                tvb, offset, -1, ENC_NA);
1216
0
            offset += reported_len - 1;
1217
0
            break;
1218
0
        }
1219
0
    }
1220
1221
0
    if (!tree) {
1222
        /* offset only advances while building the tree */
1223
0
        return tvb_captured_length(tvb);
1224
0
    }
1225
0
    return offset;
1226
0
}
1227
1228
/** Returns a guess if a packet is OUCH or not
1229
 *
1230
 * Since SOUP doesn't have a sub-protocol type flag, we have to use a
1231
 * heuristic decision to determine if the contained protocol is OUCH
1232
 * or ITCH (or something else entirely).  We look at the message type
1233
 * code, and since we know that we're being called from SOUP, we can
1234
 * check the passed-in length too: if the type code and the length
1235
 * match, we guess at OUCH. */
1236
static bool
1237
dissect_ouch_heur(
1238
    tvbuff_t *tvb,
1239
    packet_info *pinfo,
1240
    proto_tree *tree,
1241
    void *data _U_)
1242
0
{
1243
0
    uint8_t msg_type = tvb_get_uint8(tvb, 0);
1244
0
    unsigned msg_len = tvb_reported_length(tvb);
1245
1246
0
    switch (msg_type) {
1247
0
    case 'O': /* Enter order (with or without optional customer type) */
1248
0
        if (msg_len != 48 && msg_len != 49) {
1249
0
            return false;
1250
0
        }
1251
0
        break;
1252
1253
0
    case 'U': /* Replace order or Replaced (4.0, 4.1) or Replaced (4.2) */
1254
0
        if (msg_len != 47 && msg_len != 79 && msg_len != 80) {
1255
0
            return false;
1256
0
        }
1257
0
        break;
1258
1259
0
    case 'X': /* Cancel order */
1260
0
        if (msg_len != 19) {
1261
0
            return false;
1262
0
        }
1263
0
        break;
1264
1265
0
    case 'M': /* Modify Order or Order Modified (added 4.2) */
1266
0
        if (msg_len != 20 && msg_len != 28) {
1267
0
            return false;
1268
0
        }
1269
0
        break;
1270
1271
0
    case 'S': /* System event */
1272
0
        if (msg_len != 10) {
1273
0
            return false;
1274
0
        }
1275
0
        break;
1276
1277
0
    case 'A': /* Accepted */
1278
0
        if (msg_len != 65 && msg_len != 66) {
1279
0
            return false;
1280
0
        }
1281
0
        break;
1282
1283
0
    case 'C': /* Canceled */
1284
0
        if (msg_len != 28) {
1285
0
            return false;
1286
0
        }
1287
0
        break;
1288
1289
0
    case 'D': /* AIQ Canceled */
1290
0
        if (msg_len != 37) {
1291
0
            return false;
1292
0
        }
1293
0
        break;
1294
0
    case 'E': /* Executed */
1295
0
        if (msg_len != 40) {
1296
0
            return false;
1297
0
        }
1298
0
        break;
1299
1300
0
    case 'F': /* Trade Correction */
1301
0
        if (msg_len != 41) {
1302
0
            return false;
1303
0
        }
1304
0
        break;
1305
1306
0
    case 'G': /* Executed with Reference Price */
1307
0
        if (msg_len != 45) {
1308
0
            return false;
1309
0
        }
1310
0
        break;
1311
1312
0
    case 'B': /* Broken Trade */
1313
0
        if (msg_len != 32) {
1314
0
            return false;
1315
0
        }
1316
0
        break;
1317
1318
0
    case 'K': /* Correction */
1319
0
        if (msg_len != 36) {
1320
0
            return false;
1321
0
        }
1322
0
        break;
1323
1324
0
    case 'J': /* Rejected */
1325
0
        if (msg_len != 24) {
1326
0
            return false;
1327
0
        }
1328
0
        break;
1329
1330
0
    case 'P': /* Cancel Pending */
1331
0
        if (msg_len != 23) {
1332
0
            return false;
1333
0
        }
1334
0
        break;
1335
1336
0
    case 'I': /* Cancel Reject */
1337
0
        if (msg_len != 23) {
1338
0
            return false;
1339
0
        }
1340
0
        break;
1341
1342
0
    case 'T': /* Order Priority Update */
1343
0
        if (msg_len != 36) {
1344
0
            return false;
1345
0
        }
1346
0
        break;
1347
1348
0
    default:
1349
        /* Not a known OUCH message code */
1350
0
        return false;
1351
0
    }
1352
1353
    /* Perform dissection of this (initial) packet */
1354
0
    dissect_ouch(tvb, pinfo, tree, NULL);
1355
1356
0
    return true;
1357
0
}
1358
1359
1360
void
1361
proto_register_ouch(void)
1362
16
{
1363
    /* Setup list of header fields  See Section 1.6.1 for details*/
1364
16
    static hf_register_info hf[] = {
1365
1366
16
        { &hf_ouch_bbo_weight_indicator,
1367
16
          { "BBO Weight Indicator", "ouch.bbo_weight_indicator",
1368
16
            FT_CHAR, BASE_HEX, VALS(ouch_bbo_weight_indicator_val), 0x0,
1369
16
            NULL, HFILL }},
1370
1371
16
        { &hf_ouch_broken_trade_reason,
1372
16
          { "Broken Trade Reason", "ouch.broken_trade_reason",
1373
16
            FT_CHAR, BASE_HEX, VALS(ouch_broken_trade_reason_val), 0x0,
1374
16
            NULL, HFILL }},
1375
1376
16
        { &hf_ouch_buy_sell_indicator,
1377
16
          { "Buy/Sell Indicator", "ouch.buy_sell_indicator",
1378
16
            FT_CHAR, BASE_HEX, VALS(ouch_buy_sell_indicator_val), 0x0,
1379
16
            NULL, HFILL }},
1380
1381
16
        { &hf_ouch_cancel_reason,
1382
16
          { "Cancel Reason", "ouch.cancel_reason",
1383
16
            FT_CHAR, BASE_HEX, VALS(ouch_cancel_reason_val), 0x0,
1384
16
            NULL, HFILL }},
1385
1386
16
        { &hf_ouch_capacity,
1387
16
          { "Capacity", "ouch.capacity",
1388
16
            FT_CHAR, BASE_HEX, VALS(ouch_capacity_val), 0x0,
1389
16
            NULL, HFILL }},
1390
1391
16
        { &hf_ouch_cross_type,
1392
16
          { "Cross Type", "ouch.cross_type",
1393
16
            FT_CHAR, BASE_HEX, VALS(ouch_cross_type_val), 0x0,
1394
16
            NULL, HFILL }},
1395
1396
16
        { &hf_ouch_customer_type,
1397
16
          { "Customer Type", "ouch.customer_type",
1398
16
            FT_CHAR, BASE_HEX, VALS(ouch_customer_type_val), 0x0,
1399
16
            NULL, HFILL }},
1400
1401
16
        { &hf_ouch_decrement_shares,
1402
16
          { "Decrement Shares", "ouch.decrement_shares",
1403
16
            FT_UINT32, BASE_DEC, NULL, 0x0,
1404
16
            NULL, HFILL }},
1405
1406
16
        { &hf_ouch_display,
1407
16
          { "Display", "ouch.display",
1408
16
            FT_CHAR, BASE_HEX, VALS(ouch_display_val), 0x0,
1409
16
            NULL, HFILL }},
1410
1411
16
        { &hf_ouch_event_code,
1412
16
          { "Event Code", "ouch.event_code",
1413
16
            FT_CHAR, BASE_HEX, VALS(ouch_event_code_val), 0x0,
1414
16
            NULL, HFILL }},
1415
1416
16
        { &hf_ouch_executed_shares,
1417
16
          { "Executed Shares", "ouch.executed_shares",
1418
16
            FT_UINT32, BASE_DEC, NULL, 0x0,
1419
16
            NULL, HFILL }},
1420
1421
16
        { &hf_ouch_execution_price,
1422
16
          { "Execution Price", "ouch.execution_price",
1423
16
            FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1424
16
            NULL, HFILL }},
1425
1426
16
        { &hf_ouch_existing_order_token,
1427
16
          { "Existing Order Token", "ouch.existing_order_token",
1428
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1429
16
            NULL, HFILL }},
1430
1431
16
        { &hf_ouch_firm,
1432
16
          { "Firm", "ouch.firm",
1433
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1434
16
            NULL, HFILL }},
1435
1436
16
        { &hf_ouch_iso_eligible,
1437
16
          { "Intermarket Sweep Eligibility", "ouch.iso_eligible",
1438
16
            FT_CHAR, BASE_HEX, VALS(ouch_iso_eligibility_val), 0x0,
1439
16
            NULL, HFILL }},
1440
1441
16
        { &hf_ouch_liquidity_flag,
1442
16
          { "Liquidity Flag", "ouch.liquidity_flag",
1443
16
            FT_CHAR, BASE_HEX, VALS(ouch_liquidity_flag_val), 0x0,
1444
16
            NULL, HFILL }},
1445
1446
16
        { &hf_ouch_match_number,
1447
16
          { "Match Number", "ouch.match_number",
1448
16
            FT_UINT64, BASE_DEC, NULL, 0x0,
1449
16
            NULL, HFILL }},
1450
1451
16
        { &hf_ouch_message,
1452
16
          { "Unknown Message", "ouch.unknown_message",
1453
16
            FT_BYTES, BASE_NONE, NULL, 0x0,
1454
16
            NULL, HFILL }},
1455
1456
16
        { &hf_ouch_min_quantity,
1457
16
          { "Minimum Quantity", "ouch.min_quantity",
1458
16
            FT_UINT32, BASE_DEC, NULL, 0x0,
1459
16
            NULL, HFILL }},
1460
1461
16
        { &hf_ouch_new_execution_price,
1462
16
          { "New Execution Price", "ouch.new_execution_price",
1463
16
            FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1464
16
            NULL, HFILL }},
1465
1466
16
        { &hf_ouch_order_reference_number,
1467
16
          { "Order Reference Number", "ouch.order_reference_number",
1468
16
            FT_UINT64, BASE_DEC, NULL, 0x0,
1469
16
            NULL, HFILL }},
1470
1471
16
        { &hf_ouch_order_state,
1472
16
          { "Order State", "ouch.order_state",
1473
16
            FT_CHAR, BASE_HEX, VALS(ouch_order_state_val), 0x0,
1474
16
            NULL, HFILL }},
1475
1476
16
        { &hf_ouch_order_token,
1477
16
          { "Order Token", "ouch.order_token",
1478
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1479
16
            NULL, HFILL }},
1480
1481
16
        { &hf_ouch_packet_type,
1482
16
          { "Packet Type", "ouch.packet_type",
1483
16
            FT_CHAR, BASE_HEX, VALS(pkt_type_val), 0x0,
1484
16
            NULL, HFILL }},
1485
1486
16
        { &hf_ouch_previous_order_token,
1487
16
          { "Previous Order Token", "ouch.previous_order_token",
1488
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1489
16
            NULL, HFILL }},
1490
1491
16
        { &hf_ouch_price,
1492
16
          { "Price", "ouch.price",
1493
16
            FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1494
16
            NULL, HFILL }},
1495
1496
16
        { &hf_ouch_price_correction_reason,
1497
16
          { "Price Correction Reason", "ouch.price_correction_reason",
1498
16
            FT_CHAR, BASE_HEX, VALS(ouch_price_correction_reason_val), 0x0,
1499
16
            NULL, HFILL }},
1500
1501
16
        { &hf_ouch_quantity_prevented_from_trading,
1502
16
          { "Quantity Prevented from Trading",
1503
16
            "ouch.quantity_prevented_from_trading",
1504
16
            FT_UINT32, BASE_DEC, NULL, 0x0,
1505
16
            NULL, HFILL }},
1506
1507
16
        { &hf_ouch_reference_price,
1508
16
          { "Reference Price", "ouch.reference_price",
1509
16
            FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1510
16
            NULL, HFILL }},
1511
1512
16
        { &hf_ouch_reference_price_type,
1513
16
          { "Reference Price Type", "ouch.reference_price_type",
1514
16
            FT_UINT32, BASE_CUSTOM, CF_FUNC(format_reference_price_type), 0x0,
1515
16
            NULL, HFILL }},
1516
1517
16
        { &hf_ouch_reject_reason,
1518
16
          { "Reject Reason", "ouch.reject_reason",
1519
16
            FT_CHAR, BASE_HEX, VALS(ouch_reject_reason_val), 0x0,
1520
16
            NULL, HFILL }},
1521
1522
16
        { &hf_ouch_replacement_order_token,
1523
16
          { "Replacement Order Token", "ouch.replacement_order_token",
1524
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1525
16
            NULL, HFILL }},
1526
1527
16
        { &hf_ouch_shares,
1528
16
          { "Shares", "ouch.shares",
1529
16
            FT_UINT32, BASE_DEC, NULL, 0x0,
1530
16
            NULL, HFILL }},
1531
1532
16
        { &hf_ouch_stock,
1533
16
          { "Stock", "ouch.stock",
1534
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1535
16
            NULL, HFILL }},
1536
1537
16
        { &hf_ouch_tif,
1538
16
          { "Time In Force", "ouch.tif",
1539
16
            FT_UINT32, BASE_CUSTOM, CF_FUNC(format_tif), 0x0,
1540
16
            NULL, HFILL }},
1541
1542
16
        { &hf_ouch_timestamp,
1543
16
          { "Timestamp", "ouch.timestamp",
1544
16
            FT_STRING, BASE_NONE, NULL, 0x0,
1545
16
            NULL, HFILL }},
1546
1547
16
        { &hf_ouch_trade_correction_reason,
1548
16
          { "Trade Correction Reason", "ouch.trade_correction_reason",
1549
16
            FT_CHAR, BASE_HEX, VALS(ouch_trade_correction_reason_val), 0x0,
1550
16
            NULL, HFILL }}
1551
16
    };
1552
1553
    /* Setup protocol subtree array */
1554
16
    static int *ett[] = {
1555
16
        &ett_ouch
1556
16
    };
1557
1558
    /* Register the protocol name and description */
1559
16
    proto_ouch = proto_register_protocol("OUCH", "OUCH", "ouch");
1560
1561
    /* Required function calls to register the header fields and
1562
     * subtrees used */
1563
16
    proto_register_field_array(proto_ouch, hf, array_length(hf));
1564
16
    proto_register_subtree_array(ett, array_length(ett));
1565
1566
    /* Register the dissector */
1567
16
    ouch_handle = register_dissector("ouch", dissect_ouch, proto_ouch);
1568
16
}
1569
1570
1571
/* If this dissector uses sub-dissector registration add a
1572
 * registration routine.  This format is required because a script is
1573
 * used to find these routines and create the code that calls these
1574
 * routines. */
1575
void
1576
proto_reg_handoff_ouch(void)
1577
16
{
1578
16
    heur_dissector_add("soupbintcp", dissect_ouch_heur, "OUCH over SoupBinTCP", "ouch_soupbintcp", proto_ouch, HEURISTIC_ENABLE);
1579
16
    dissector_add_uint_range_with_preference("tcp.port", "", ouch_handle);
1580
16
}
1581
1582
1583
1584
/*
1585
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1586
 *
1587
 * Local variables:
1588
 * c-basic-offset: 4
1589
 * tab-width: 8
1590
 * indent-tabs-mode: nil
1591
 * End:
1592
 *
1593
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1594
 * :indentSize=4:tabSize=8:noTabs=true:
1595
 */