HTTPS (almost) everywhere.
[metze/wireshark/wip.git] / epan / dissectors / packet-ouch.c
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 = -1;
261 static dissector_handle_t ouch_handle;
262
263 /* Initialize the subtree pointers */
264 static gint ett_ouch = -1;
265
266 static int hf_ouch_bbo_weight_indicator = -1;
267 static int hf_ouch_broken_trade_reason = -1;
268 static int hf_ouch_buy_sell_indicator = -1;
269 static int hf_ouch_cancel_reason = -1;
270 static int hf_ouch_capacity = -1;
271 static int hf_ouch_cross_type = -1;
272 static int hf_ouch_customer_type = -1;
273 static int hf_ouch_decrement_shares = -1;
274 static int hf_ouch_display = -1;
275 static int hf_ouch_event_code = -1;
276 static int hf_ouch_executed_shares = -1;
277 static int hf_ouch_execution_price = -1;
278 static int hf_ouch_existing_order_token = -1;
279 static int hf_ouch_firm = -1;
280 static int hf_ouch_iso_eligible = -1;
281 static int hf_ouch_liquidity_flag = -1;
282 static int hf_ouch_match_number = -1;
283 static int hf_ouch_message = -1;
284 static int hf_ouch_min_quantity = -1;
285 static int hf_ouch_new_execution_price = -1;
286 static int hf_ouch_order_reference_number = -1;
287 static int hf_ouch_order_state = -1;
288 static int hf_ouch_order_token = -1;
289 static int hf_ouch_packet_type = -1;
290 static int hf_ouch_previous_order_token = -1;
291 static int hf_ouch_price = -1;
292 static int hf_ouch_price_correction_reason = -1;
293 static int hf_ouch_quantity_prevented_from_trading = -1;
294 static int hf_ouch_reference_price = -1;
295 static int hf_ouch_reference_price_type = -1;
296 static int hf_ouch_reject_reason = -1;
297 static int hf_ouch_replacement_order_token = -1;
298 static int hf_ouch_shares = -1;
299 static int hf_ouch_stock = -1;
300 static int hf_ouch_tif = -1;
301 static int hf_ouch_timestamp = -1;
302 static int hf_ouch_trade_correction_reason = -1;
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     proto_tree *tree,
313     const int hf,
314     tvbuff_t *tvb,
315     gint offset)
316 {
317     guint64 ts = tvb_get_ntoh64(tvb, offset);
318     char *buf = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH);
319     guint32 tmp, hours, mins, secs, nsecs;
320
321     nsecs = (guint32)(ts % G_GUINT64_CONSTANT(1000000000));
322     tmp = (guint32)(ts / G_GUINT64_CONSTANT(1000000000));
323
324     hours = tmp / 3600;
325     mins = (tmp % 3600) / 60;
326     secs = tmp % 60;
327
328     g_snprintf(buf, ITEM_LABEL_LENGTH,
329                "%u:%02u:%02u.%09u",
330                hours, mins, secs, nsecs);
331
332     proto_tree_add_string(tree, hf, tvb, offset, 8, buf);
333 }
334
335 /** BASE_CUSTOM formatter for prices
336  *
337  * OUCH prices are integers, with four implicit decimal places.  So we
338  * insert the decimal point, and add a leading dollar sign as well. */
339 static void
340 format_price(
341     char *buf,
342     guint32 value)
343 {
344     if (value == 0x7fffffff) {
345         g_snprintf(buf, ITEM_LABEL_LENGTH, "%s", "Market");
346     } else {
347         g_snprintf(buf, ITEM_LABEL_LENGTH,
348                    "$%u.%04u",
349                    value / 10000, value % 10000);
350     }
351 }
352
353 /** BASE_CUSTOM formatter for reference price type code
354  *
355  * Displays the code value as a character, not its ASCII value, as
356  * would be done by BASE_DEC and friends. */
357 static void
358 format_reference_price_type(
359     char *buf,
360     guint32 value)
361 {
362     g_snprintf(buf, ITEM_LABEL_LENGTH,
363                "%s (%c)",
364                val_to_str_const(value,
365                                 ouch_reference_price_type_val,
366                                 "Unknown"),
367                value);
368 }
369
370 /** BASE_CUSTOM formatter for the Time In Force (TIF) code
371  *
372  * There are three reserved values for the TIF: 0, 99998 and 99999.
373  * These are trapped and displayed as an appropriate string.  All
374  * other values are printed as a duration in hours, minutes and
375  * seconds. */
376 static void
377 format_tif(
378     gchar *buf,
379     guint32 value)
380 {
381     guint32 hours;
382     guint32 mins;
383     guint32 secs;
384
385     switch (value) {
386     case 0:
387         g_snprintf(buf, ITEM_LABEL_LENGTH, "Immediate Or Cancel (%u)", value);
388         break;
389
390     case 99998:
391         g_snprintf(buf, ITEM_LABEL_LENGTH, "Market Hours (%u)", value);
392         break;
393
394     case 99999:
395         g_snprintf(buf, ITEM_LABEL_LENGTH, "System Hours (%u)", value);
396         break;
397
398     default:
399         hours = value / 3600;
400         mins = (value % 3600) / 60;
401         secs = value % 60;
402
403         g_snprintf(buf, ITEM_LABEL_LENGTH,
404                    "%uh %02um %02us (%u seconds)",
405                    hours, mins, secs,
406                    value);
407         break;
408     }
409 }
410
411
412 static int
413 dissect_ouch(
414     tvbuff_t *tvb,
415     packet_info *pinfo,
416     proto_tree *tree,
417     void *data _U_)
418 {
419     proto_item *ti;
420     proto_tree *ouch_tree = NULL;
421     const char *pkt_name;
422     guint16 reported_len;
423     guint8 pkt_type;
424     int offset = 0;
425
426     /* Get the OUCH message type value */
427     pkt_type = tvb_get_guint8(tvb, offset);
428     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     if (pkt_type == 'U' && (reported_len == 79 || reported_len == 80)) {
437         pkt_type = 'R';
438     }
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     if (pkt_type == 'M' && reported_len == 28) {
445         pkt_type = 'm';
446     }
447
448     /* Since we use the packet name a few times, get and save that value */
449     pkt_name = val_to_str(pkt_type, pkt_type_val, "Unknown (%u)");
450
451     /* Set the protocol name in the summary display */
452     col_set_str(pinfo->cinfo, COL_PROTOCOL, "OUCH");
453
454     /* Set the packet name in the info column */
455     col_add_str(pinfo->cinfo, COL_INFO, pkt_name);
456
457     if (tree) {
458         /* Create a sub-tree for the OUCH packet details */
459         ti = proto_tree_add_item(tree,
460                                  proto_ouch,
461                                  tvb, 0, -1, ENC_NA);
462
463         ouch_tree = proto_item_add_subtree(ti, ett_ouch);
464
465         /* Append the packet name to the sub-tree item */
466         proto_item_append_text(ti, ", %s", pkt_name);
467
468         /* Packet type (using the cooked value). */
469         proto_tree_add_item(ouch_tree, hf_ouch_packet_type,
470                                   tvb, offset, 1, ENC_ASCII|ENC_NA);
471         offset += 1;
472
473         switch (pkt_type) {
474         case 'O': /* Enter Order */
475             proto_tree_add_item(ouch_tree,
476                                 hf_ouch_order_token,
477                                 tvb, offset, 14,
478                                 ENC_ASCII|ENC_NA);
479             offset += 14;
480
481             proto_tree_add_item(ouch_tree,
482                                 hf_ouch_buy_sell_indicator,
483                                 tvb, offset, 1,
484                                 ENC_ASCII|ENC_NA);
485             offset += 1;
486
487             proto_tree_add_item(ouch_tree,
488                                 hf_ouch_shares,
489                                 tvb, offset, 4,
490                                 ENC_BIG_ENDIAN);
491             offset += 4;
492
493             proto_tree_add_item(ouch_tree,
494                                 hf_ouch_stock,
495                                 tvb, offset, 8,
496                                 ENC_ASCII|ENC_NA);
497             offset += 8;
498
499             proto_tree_add_item(ouch_tree,
500                                 hf_ouch_price,
501                                 tvb, offset, 4,
502                                 ENC_BIG_ENDIAN);
503             offset += 4;
504
505             proto_tree_add_item(ouch_tree,
506                                 hf_ouch_tif,
507                                 tvb, offset, 4,
508                                 ENC_BIG_ENDIAN);
509             offset += 4;
510
511             proto_tree_add_item(ouch_tree,
512                                 hf_ouch_firm,
513                                 tvb, offset, 4,
514                                 ENC_ASCII|ENC_NA);
515             offset += 4;
516
517             proto_tree_add_item(ouch_tree,
518                                 hf_ouch_display,
519                                 tvb, offset, 1,
520                                 ENC_ASCII|ENC_NA);
521             offset += 1;
522
523             proto_tree_add_item(ouch_tree,
524                                 hf_ouch_capacity,
525                                 tvb, offset, 1,
526                                 ENC_ASCII|ENC_NA);
527             offset += 1;
528
529             proto_tree_add_item(ouch_tree,
530                                 hf_ouch_iso_eligible,
531                                 tvb, offset, 1,
532                                 ENC_ASCII|ENC_NA);
533             offset += 1;
534
535             proto_tree_add_item(ouch_tree,
536                                 hf_ouch_min_quantity,
537                                 tvb, offset, 4,
538                                 ENC_BIG_ENDIAN);
539             offset += 4;
540
541             proto_tree_add_item(ouch_tree,
542                                 hf_ouch_cross_type,
543                                 tvb, offset, 1,
544                                 ENC_ASCII|ENC_NA);
545             offset += 1;
546
547             if (reported_len >= 49) { /* Added in 4.1 */
548                 proto_tree_add_item(ouch_tree,
549                                     hf_ouch_customer_type,
550                                     tvb, offset, 1,
551                                     ENC_ASCII|ENC_NA);
552                 offset += 1;
553             }
554             break;
555
556         case 'A': /* Accepted */
557             ouch_tree_add_timestamp(ouch_tree,
558                                     hf_ouch_timestamp,
559                                     tvb, offset);
560             offset += 8;
561
562             proto_tree_add_item(ouch_tree,
563                                 hf_ouch_order_token,
564                                 tvb, offset, 14,
565                                 ENC_ASCII|ENC_NA);
566             offset += 14;
567
568             proto_tree_add_item(ouch_tree,
569                                 hf_ouch_buy_sell_indicator,
570                                 tvb, offset, 1,
571                                 ENC_BIG_ENDIAN);
572             offset += 1;
573
574             proto_tree_add_item(ouch_tree,
575                                 hf_ouch_shares,
576                                 tvb, offset, 4,
577                                 ENC_BIG_ENDIAN);
578             offset += 4;
579
580             proto_tree_add_item(ouch_tree,
581                                 hf_ouch_stock,
582                                 tvb, offset, 8,
583                                 ENC_ASCII|ENC_NA);
584             offset += 8;
585
586             proto_tree_add_item(ouch_tree,
587                                 hf_ouch_price,
588                                 tvb, offset, 4,
589                                 ENC_BIG_ENDIAN);
590             offset += 4;
591
592             proto_tree_add_item(ouch_tree,
593                                 hf_ouch_tif,
594                                 tvb, offset, 4,
595                                 ENC_BIG_ENDIAN);
596             offset += 4;
597
598             proto_tree_add_item(ouch_tree,
599                                 hf_ouch_firm,
600                                 tvb, offset, 4,
601                                 ENC_ASCII|ENC_NA);
602             offset += 4;
603
604             proto_tree_add_item(ouch_tree,
605                                 hf_ouch_display,
606                                 tvb, offset, 1,
607                                 ENC_ASCII|ENC_NA);
608             offset += 1;
609
610             proto_tree_add_item(ouch_tree,
611                                 hf_ouch_order_reference_number,
612                                 tvb, offset, 8,
613                                 ENC_BIG_ENDIAN);
614             offset += 8;
615
616             proto_tree_add_item(ouch_tree,
617                                 hf_ouch_capacity,
618                                 tvb, offset, 1,
619                                 ENC_ASCII|ENC_NA);
620             offset += 1;
621
622             proto_tree_add_item(ouch_tree,
623                                 hf_ouch_iso_eligible,
624                                 tvb, offset, 1,
625                                 ENC_ASCII|ENC_NA);
626             offset += 1;
627
628             proto_tree_add_item(ouch_tree,
629                                 hf_ouch_min_quantity,
630                                 tvb, offset, 4,
631                                 ENC_BIG_ENDIAN);
632             offset += 4;
633
634             proto_tree_add_item(ouch_tree,
635                                 hf_ouch_cross_type,
636                                 tvb, offset, 1,
637                                 ENC_ASCII|ENC_NA);
638             offset += 1;
639
640             proto_tree_add_item(ouch_tree,
641                                 hf_ouch_order_state,
642                                 tvb, offset, 1,
643                                 ENC_ASCII|ENC_NA);
644             offset += 1;
645
646             if (reported_len >= 66) { /* Added in 4.2 */
647                 proto_tree_add_item(ouch_tree,
648                                     hf_ouch_bbo_weight_indicator,
649                                     tvb, offset, 1,
650                                     ENC_ASCII|ENC_NA);
651                 offset += 1;
652             }
653             break;
654
655         case 'U': /* Replace Order */
656             proto_tree_add_item(ouch_tree,
657                                 hf_ouch_existing_order_token,
658                                 tvb, offset, 14,
659                                 ENC_ASCII|ENC_NA);
660             offset += 14;
661
662             proto_tree_add_item(ouch_tree,
663                                 hf_ouch_replacement_order_token,
664                                 tvb, offset, 14,
665                                 ENC_ASCII|ENC_NA);
666             offset += 14;
667
668             proto_tree_add_item(ouch_tree,
669                                 hf_ouch_shares,
670                                 tvb, offset, 4,
671                                 ENC_BIG_ENDIAN);
672             offset += 4;
673
674             proto_tree_add_item(ouch_tree,
675                                 hf_ouch_price,
676                                 tvb, offset, 4,
677                                 ENC_BIG_ENDIAN);
678             offset += 4;
679
680             proto_tree_add_item(ouch_tree,
681                                 hf_ouch_tif,
682                                 tvb, offset, 4,
683                                 ENC_BIG_ENDIAN);
684             offset += 4;
685
686             proto_tree_add_item(ouch_tree,
687                                 hf_ouch_display,
688                                 tvb, offset, 1,
689                                 ENC_ASCII|ENC_NA);
690             offset += 1;
691
692             proto_tree_add_item(ouch_tree,
693                                 hf_ouch_iso_eligible,
694                                 tvb, offset, 1,
695                                 ENC_ASCII|ENC_NA);
696             offset += 1;
697
698             proto_tree_add_item(ouch_tree,
699                                 hf_ouch_min_quantity,
700                                 tvb, offset, 4,
701                                 ENC_BIG_ENDIAN);
702             offset += 4;
703             break;
704
705         case 'X': /* Cancel Order */
706             proto_tree_add_item(ouch_tree,
707                                 hf_ouch_order_token,
708                                 tvb, offset, 14,
709                                 ENC_ASCII|ENC_NA);
710             offset += 14;
711
712             proto_tree_add_item(ouch_tree,
713                                 hf_ouch_shares,
714                                 tvb, offset, 4,
715                                 ENC_BIG_ENDIAN);
716             offset += 4;
717             break;
718
719         case 'M': /* Modify Order (from 4.2 onwards) */
720             proto_tree_add_item(ouch_tree,
721                                 hf_ouch_order_token,
722                                 tvb, offset, 14,
723                                 ENC_ASCII|ENC_NA);
724             offset += 14;
725
726             proto_tree_add_item(ouch_tree,
727                                 hf_ouch_buy_sell_indicator,
728                                 tvb, offset, 1,
729                                 ENC_BIG_ENDIAN);
730             offset += 1;
731
732             proto_tree_add_item(ouch_tree,
733                                 hf_ouch_shares,
734                                 tvb, offset, 4,
735                                 ENC_BIG_ENDIAN);
736             offset += 4;
737             break;
738
739         case 'S': /* System Event */
740             ouch_tree_add_timestamp(ouch_tree,
741                                     hf_ouch_timestamp,
742                                     tvb, offset);
743             offset += 8;
744
745             proto_tree_add_item(ouch_tree,
746                                 hf_ouch_event_code,
747                                 tvb, offset, 1,
748                                 ENC_ASCII|ENC_NA);
749             offset += 1;
750             break;
751
752         case 'R': /* Replaced */
753             ouch_tree_add_timestamp(ouch_tree,
754                                     hf_ouch_timestamp,
755                                     tvb, offset);
756             offset += 8;
757
758             proto_tree_add_item(ouch_tree,
759                                 hf_ouch_replacement_order_token,
760                                 tvb, offset, 14,
761                                 ENC_ASCII|ENC_NA);
762             offset += 14;
763
764             proto_tree_add_item(ouch_tree,
765                                 hf_ouch_buy_sell_indicator,
766                                 tvb, offset, 1,
767                                 ENC_BIG_ENDIAN);
768             offset += 1;
769
770             proto_tree_add_item(ouch_tree,
771                                 hf_ouch_shares,
772                                 tvb, offset, 4,
773                                 ENC_BIG_ENDIAN);
774             offset += 4;
775
776             proto_tree_add_item(ouch_tree,
777                                 hf_ouch_stock,
778                                 tvb, offset, 8,
779                                 ENC_ASCII|ENC_NA);
780             offset += 8;
781
782             proto_tree_add_item(ouch_tree,
783                                 hf_ouch_price,
784                                 tvb, offset, 4,
785                                 ENC_BIG_ENDIAN);
786             offset += 4;
787
788             proto_tree_add_item(ouch_tree,
789                                 hf_ouch_tif,
790                                 tvb, offset, 4,
791                                 ENC_BIG_ENDIAN);
792             offset += 4;
793
794             proto_tree_add_item(ouch_tree,
795                                 hf_ouch_firm,
796                                 tvb, offset, 4,
797                                 ENC_ASCII|ENC_NA);
798             offset += 4;
799
800             proto_tree_add_item(ouch_tree,
801                                 hf_ouch_display,
802                                 tvb, offset, 1,
803                                 ENC_ASCII|ENC_NA);
804             offset += 1;
805
806             proto_tree_add_item(ouch_tree,
807                                 hf_ouch_order_reference_number,
808                                 tvb, offset, 8,
809                                 ENC_BIG_ENDIAN);
810             offset += 8;
811
812             proto_tree_add_item(ouch_tree,
813                                 hf_ouch_capacity,
814                                 tvb, offset, 1,
815                                 ENC_ASCII|ENC_NA);
816             offset += 1;
817
818             proto_tree_add_item(ouch_tree,
819                                 hf_ouch_iso_eligible,
820                                 tvb, offset, 1,
821                                 ENC_ASCII|ENC_NA);
822             offset += 1;
823
824             proto_tree_add_item(ouch_tree,
825                                 hf_ouch_min_quantity,
826                                 tvb, offset, 4,
827                                 ENC_BIG_ENDIAN);
828             offset += 4;
829
830             proto_tree_add_item(ouch_tree,
831                                 hf_ouch_cross_type,
832                                 tvb, offset, 1,
833                                 ENC_ASCII|ENC_NA);
834             offset += 1;
835
836             proto_tree_add_item(ouch_tree,
837                                 hf_ouch_order_state,
838                                 tvb, offset, 1,
839                                 ENC_ASCII|ENC_NA);
840             offset += 1;
841
842             proto_tree_add_item(ouch_tree,
843                                 hf_ouch_previous_order_token,
844                                 tvb, offset, 14,
845                                 ENC_ASCII|ENC_NA);
846             offset += 14;
847
848             if (reported_len >= 80) { /* Added in 4.2 */
849                 proto_tree_add_item(ouch_tree,
850                                     hf_ouch_bbo_weight_indicator,
851                                     tvb, offset, 1,
852                                     ENC_BIG_ENDIAN);
853                 offset += 1;
854             }
855             break;
856
857         case 'C': /* Canceled */
858             ouch_tree_add_timestamp(ouch_tree,
859                                     hf_ouch_timestamp,
860                                     tvb, offset);
861             offset += 8;
862
863             proto_tree_add_item(ouch_tree,
864                                 hf_ouch_order_token,
865                                 tvb, offset, 14,
866                                 ENC_ASCII|ENC_NA);
867             offset += 14;
868
869             proto_tree_add_item(ouch_tree,
870                                 hf_ouch_decrement_shares,
871                                 tvb, offset, 4,
872                                 ENC_BIG_ENDIAN);
873             offset += 4;
874
875             proto_tree_add_item(ouch_tree,
876                                 hf_ouch_cancel_reason,
877                                 tvb, offset, 1,
878                                 ENC_ASCII|ENC_NA);
879             offset += 1;
880             break;
881
882         case 'D': /* AIQ Canceled */
883             ouch_tree_add_timestamp(ouch_tree,
884                                     hf_ouch_timestamp,
885                                     tvb, offset);
886             offset += 8;
887
888             proto_tree_add_item(ouch_tree,
889                                 hf_ouch_order_token,
890                                 tvb, offset, 14,
891                                 ENC_ASCII|ENC_NA);
892             offset += 14;
893
894             proto_tree_add_item(ouch_tree,
895                                 hf_ouch_decrement_shares,
896                                 tvb, offset, 4,
897                                 ENC_BIG_ENDIAN);
898             offset += 4;
899
900             proto_tree_add_item(ouch_tree,
901                                 hf_ouch_cancel_reason,
902                                 tvb, offset, 1,
903                                 ENC_ASCII|ENC_NA);
904             offset += 1;
905
906             proto_tree_add_item(ouch_tree,
907                                 hf_ouch_quantity_prevented_from_trading,
908                                 tvb, offset, 4,
909                                 ENC_BIG_ENDIAN);
910             offset += 4;
911
912             proto_tree_add_item(ouch_tree,
913                                 hf_ouch_execution_price,
914                                 tvb, offset, 4,
915                                 ENC_BIG_ENDIAN);
916             offset += 4;
917
918             proto_tree_add_item(ouch_tree,
919                                 hf_ouch_liquidity_flag,
920                                 tvb, offset, 1,
921                                 ENC_ASCII|ENC_NA);
922             offset += 1;
923             break;
924
925         case 'E': /* Executed */
926             ouch_tree_add_timestamp(ouch_tree,
927                                     hf_ouch_timestamp,
928                                     tvb, offset);
929             offset += 8;
930
931             proto_tree_add_item(ouch_tree,
932                                 hf_ouch_order_token,
933                                 tvb, offset, 14,
934                                 ENC_ASCII|ENC_NA);
935             offset += 14;
936
937             proto_tree_add_item(ouch_tree,
938                                 hf_ouch_executed_shares,
939                                 tvb, offset, 4,
940                                 ENC_BIG_ENDIAN);
941             offset += 4;
942
943             proto_tree_add_item(ouch_tree,
944                                 hf_ouch_execution_price,
945                                 tvb, offset, 4,
946                                 ENC_BIG_ENDIAN);
947             offset += 4;
948
949             proto_tree_add_item(ouch_tree,
950                                 hf_ouch_liquidity_flag,
951                                 tvb, offset, 1,
952                                 ENC_ASCII|ENC_NA);
953             offset += 1;
954
955             proto_tree_add_item(ouch_tree,
956                                 hf_ouch_match_number,
957                                 tvb, offset, 8,
958                                 ENC_BIG_ENDIAN);
959             offset += 8;
960             break;
961
962         case 'B': /* Broken Trade */
963             ouch_tree_add_timestamp(ouch_tree,
964                                     hf_ouch_timestamp,
965                                     tvb, offset);
966             offset += 8;
967
968             proto_tree_add_item(ouch_tree,
969                                 hf_ouch_order_token,
970                                 tvb, offset, 14,
971                                 ENC_ASCII|ENC_NA);
972             offset += 14;
973
974             proto_tree_add_item(ouch_tree,
975                                 hf_ouch_match_number,
976                                 tvb, offset, 8,
977                                 ENC_BIG_ENDIAN);
978             offset += 8;
979
980             proto_tree_add_item(ouch_tree,
981                                 hf_ouch_broken_trade_reason,
982                                 tvb, offset, 1,
983                                 ENC_ASCII|ENC_NA);
984             offset += 1;
985             break;
986
987         case 'F': /* Trade Correction (4.2 onwards) */
988             ouch_tree_add_timestamp(ouch_tree,
989                                     hf_ouch_timestamp,
990                                     tvb, offset);
991             offset += 8;
992
993             proto_tree_add_item(ouch_tree,
994                                 hf_ouch_order_token,
995                                 tvb, offset, 14,
996                                 ENC_ASCII|ENC_NA);
997             offset += 14;
998
999             proto_tree_add_item(ouch_tree,
1000                                 hf_ouch_executed_shares,
1001                                 tvb, offset, 4,
1002                                 ENC_BIG_ENDIAN);
1003             offset += 4;
1004
1005             proto_tree_add_item(ouch_tree,
1006                                 hf_ouch_execution_price,
1007                                 tvb, offset, 4,
1008                                 ENC_BIG_ENDIAN);
1009             offset += 4;
1010
1011             proto_tree_add_item(ouch_tree,
1012                                 hf_ouch_liquidity_flag,
1013                                 tvb, offset, 1,
1014                                 ENC_ASCII|ENC_NA);
1015             offset += 1;
1016
1017             proto_tree_add_item(ouch_tree,
1018                                 hf_ouch_match_number,
1019                                 tvb, offset, 8,
1020                                 ENC_BIG_ENDIAN);
1021             offset += 8;
1022
1023             proto_tree_add_item(ouch_tree,
1024                                 hf_ouch_trade_correction_reason,
1025                                 tvb, offset, 1,
1026                                 ENC_ASCII|ENC_NA);
1027             offset += 1;
1028             break;
1029
1030         case 'G': /* Executed with Reference Price (4.2 onwards) */
1031             ouch_tree_add_timestamp(ouch_tree,
1032                                     hf_ouch_timestamp,
1033                                     tvb, offset);
1034             offset += 8;
1035
1036             proto_tree_add_item(ouch_tree,
1037                                 hf_ouch_order_token,
1038                                 tvb, offset, 14,
1039                                 ENC_ASCII|ENC_NA);
1040             offset += 14;
1041
1042             proto_tree_add_item(ouch_tree,
1043                                 hf_ouch_executed_shares,
1044                                 tvb, offset, 4,
1045                                 ENC_BIG_ENDIAN);
1046             offset += 4;
1047
1048             proto_tree_add_item(ouch_tree,
1049                                 hf_ouch_execution_price,
1050                                 tvb, offset, 4,
1051                                 ENC_BIG_ENDIAN);
1052             offset += 4;
1053
1054             proto_tree_add_item(ouch_tree,
1055                                 hf_ouch_liquidity_flag,
1056                                 tvb, offset, 1,
1057                                 ENC_ASCII|ENC_NA);
1058             offset += 1;
1059
1060             proto_tree_add_item(ouch_tree,
1061                                 hf_ouch_match_number,
1062                                 tvb, offset, 8,
1063                                 ENC_BIG_ENDIAN);
1064             offset += 8;
1065
1066             proto_tree_add_item(ouch_tree,
1067                                 hf_ouch_reference_price,
1068                                 tvb, offset, 4,
1069                                 ENC_BIG_ENDIAN);
1070             offset += 4;
1071
1072             proto_tree_add_item(ouch_tree,
1073                                 hf_ouch_reference_price_type,
1074                                 tvb, offset, 1,
1075                                 ENC_BIG_ENDIAN);
1076             offset += 1;
1077             break;
1078
1079         case 'K': /* Price Correction */
1080             ouch_tree_add_timestamp(ouch_tree,
1081                                     hf_ouch_timestamp,
1082                                     tvb, offset);
1083             offset += 8;
1084
1085             proto_tree_add_item(ouch_tree,
1086                                 hf_ouch_order_token,
1087                                 tvb, offset, 14,
1088                                 ENC_ASCII|ENC_NA);
1089             offset += 14;
1090
1091             proto_tree_add_item(ouch_tree,
1092                                 hf_ouch_match_number,
1093                                 tvb, offset, 8,
1094                                 ENC_BIG_ENDIAN);
1095             offset += 8;
1096
1097             proto_tree_add_item(ouch_tree,
1098                                 hf_ouch_new_execution_price,
1099                                 tvb, offset, 4,
1100                                 ENC_BIG_ENDIAN);
1101             offset += 4;
1102
1103             proto_tree_add_item(ouch_tree,
1104                                 hf_ouch_price_correction_reason,
1105                                 tvb, offset, 1,
1106                                 ENC_ASCII|ENC_NA);
1107             offset += 1;
1108             break;
1109
1110         case 'J': /* Rejected Order */
1111             ouch_tree_add_timestamp(ouch_tree,
1112                                     hf_ouch_timestamp,
1113                                     tvb, offset);
1114             offset += 8;
1115
1116             proto_tree_add_item(ouch_tree,
1117                                 hf_ouch_order_token,
1118                                 tvb, offset, 14,
1119                                 ENC_ASCII|ENC_NA);
1120             offset += 14;
1121
1122             proto_tree_add_item(ouch_tree,
1123                                 hf_ouch_reject_reason,
1124                                 tvb, offset, 1,
1125                                 ENC_ASCII|ENC_NA);
1126             offset += 1;
1127             break;
1128
1129         case 'P': /* Cancel Pending */
1130             ouch_tree_add_timestamp(ouch_tree,
1131                                     hf_ouch_timestamp,
1132                                     tvb, offset);
1133             offset += 8;
1134
1135             proto_tree_add_item(ouch_tree,
1136                                 hf_ouch_order_token,
1137                                 tvb, offset, 14,
1138                                 ENC_ASCII|ENC_NA);
1139             offset += 14;
1140             break;
1141
1142         case 'I': /* Cancel Reject */
1143             ouch_tree_add_timestamp(ouch_tree,
1144                                     hf_ouch_timestamp,
1145                                     tvb, offset);
1146             offset += 8;
1147
1148             proto_tree_add_item(ouch_tree,
1149                                 hf_ouch_order_token,
1150                                 tvb, offset, 14,
1151                                 ENC_ASCII|ENC_NA);
1152             offset += 14;
1153             break;
1154
1155         case 'T': /* Order Priority Update (4.2 onwards) */
1156             ouch_tree_add_timestamp(ouch_tree,
1157                                     hf_ouch_timestamp,
1158                                     tvb, offset);
1159             offset += 8;
1160
1161             proto_tree_add_item(ouch_tree,
1162                                 hf_ouch_order_token,
1163                                 tvb, offset, 14,
1164                                 ENC_ASCII|ENC_NA);
1165             offset += 14;
1166
1167             proto_tree_add_item(ouch_tree,
1168                                 hf_ouch_price,
1169                                 tvb, offset, 4,
1170                                 ENC_BIG_ENDIAN);
1171             offset += 4;
1172
1173             proto_tree_add_item(ouch_tree,
1174                                 hf_ouch_display,
1175                                 tvb, offset, 1,
1176                                 ENC_ASCII|ENC_NA);
1177             offset += 1;
1178
1179             proto_tree_add_item(ouch_tree,
1180                                 hf_ouch_order_reference_number,
1181                                 tvb, offset, 8,
1182                                 ENC_BIG_ENDIAN);
1183             offset += 8;
1184             break;
1185
1186         case 'm': /* Order Modified (4.2 onwards) */
1187             ouch_tree_add_timestamp(ouch_tree,
1188                                     hf_ouch_timestamp,
1189                                     tvb, offset);
1190             offset += 8;
1191
1192             proto_tree_add_item(ouch_tree,
1193                                 hf_ouch_order_token,
1194                                 tvb, offset, 14,
1195                                 ENC_ASCII|ENC_NA);
1196             offset += 14;
1197
1198             proto_tree_add_item(ouch_tree,
1199                                 hf_ouch_buy_sell_indicator,
1200                                 tvb, offset, 1,
1201                                 ENC_BIG_ENDIAN);
1202             offset += 1;
1203
1204             proto_tree_add_item(ouch_tree,
1205                                 hf_ouch_shares,
1206                                 tvb, offset, 4,
1207                                 ENC_BIG_ENDIAN);
1208             offset += 4;
1209             break;
1210
1211         default:
1212             /* Unknown */
1213             proto_tree_add_item(tree,
1214                                 hf_ouch_message,
1215                                 tvb, offset, -1, ENC_NA);
1216             offset += reported_len - 1;
1217             break;
1218         }
1219     }
1220
1221     return offset;
1222 }
1223
1224 /** Returns a guess if a packet is OUCH or not
1225  *
1226  * Since SOUP doesn't have a sub-protocol type flag, we have to use a
1227  * heuristic decision to determine if the contained protocol is OUCH
1228  * or ITCH (or something else entirely).  We look at the message type
1229  * code, and since we know that we're being called from SOUP, we can
1230  * check the passed-in length too: if the type code and the length
1231  * match, we guess at OUCH. */
1232 static gboolean
1233 dissect_ouch_heur(
1234     tvbuff_t *tvb,
1235     packet_info *pinfo,
1236     proto_tree *tree,
1237     void *data _U_)
1238 {
1239     guint8 msg_type = tvb_get_guint8(tvb, 0);
1240     guint msg_len = tvb_reported_length(tvb);
1241
1242     switch (msg_type) {
1243     case 'O': /* Enter order (with or without optional customer type) */
1244         if (msg_len != 48 && msg_len != 49) {
1245             return FALSE;
1246         }
1247         break;
1248
1249     case 'U': /* Replace order or Replaced (4.0, 4.1) or Replaced (4.2) */
1250         if (msg_len != 47 && msg_len != 79 && msg_len != 80) {
1251             return FALSE;
1252         }
1253         break;
1254
1255     case 'X': /* Cancel order */
1256         if (msg_len != 19) {
1257             return FALSE;
1258         }
1259         break;
1260
1261     case 'M': /* Modify Order or Order Modified (added 4.2) */
1262         if (msg_len != 20 && msg_len != 28) {
1263             return FALSE;
1264         }
1265         break;
1266
1267     case 'S': /* System event */
1268         if (msg_len != 10) {
1269             return FALSE;
1270         }
1271         break;
1272
1273     case 'A': /* Accepted */
1274         if (msg_len != 65 && msg_len != 66) {
1275             return FALSE;
1276         }
1277         break;
1278
1279     case 'C': /* Canceled */
1280         if (msg_len != 28) {
1281             return FALSE;
1282         }
1283         break;
1284
1285     case 'D': /* AIQ Canceled */
1286         if (msg_len != 37) {
1287             return FALSE;
1288         }
1289         break;
1290     case 'E': /* Executed */
1291         if (msg_len != 40) {
1292             return FALSE;
1293         }
1294         break;
1295
1296     case 'F': /* Trade Correction */
1297         if (msg_len != 41) {
1298             return FALSE;
1299         }
1300         break;
1301
1302     case 'G': /* Executed with Reference Price */
1303         if (msg_len != 45) {
1304             return FALSE;
1305         }
1306         break;
1307
1308     case 'B': /* Broken Trade */
1309         if (msg_len != 32) {
1310             return FALSE;
1311         }
1312         break;
1313
1314     case 'K': /* Correction */
1315         if (msg_len != 36) {
1316             return FALSE;
1317         }
1318         break;
1319
1320     case 'J': /* Rejected */
1321         if (msg_len != 24) {
1322             return FALSE;
1323         }
1324         break;
1325
1326     case 'P': /* Cancel Pending */
1327         if (msg_len != 23) {
1328             return FALSE;
1329         }
1330         break;
1331
1332     case 'I': /* Cancel Reject */
1333         if (msg_len != 23) {
1334             return FALSE;
1335         }
1336         break;
1337
1338     case 'T': /* Order Priority Update */
1339         if (msg_len != 36) {
1340             return FALSE;
1341         }
1342         break;
1343
1344     default:
1345         /* Not a known OUCH message code */
1346         return FALSE;
1347     }
1348
1349     /* Perform dissection of this (initial) packet */
1350     dissect_ouch(tvb, pinfo, tree, NULL);
1351
1352     return TRUE;
1353 }
1354
1355
1356 void
1357 proto_register_ouch(void)
1358 {
1359     /* Setup list of header fields  See Section 1.6.1 for details*/
1360     static hf_register_info hf[] = {
1361
1362         { &hf_ouch_bbo_weight_indicator,
1363           { "BBO Weight Indicator", "ouch.bbo_weight_indicator",
1364             FT_CHAR, BASE_HEX, VALS(ouch_bbo_weight_indicator_val), 0x0,
1365             NULL, HFILL }},
1366
1367         { &hf_ouch_broken_trade_reason,
1368           { "Broken Trade Reason", "ouch.broken_trade_reason",
1369             FT_CHAR, BASE_HEX, VALS(ouch_broken_trade_reason_val), 0x0,
1370             NULL, HFILL }},
1371
1372         { &hf_ouch_buy_sell_indicator,
1373           { "Buy/Sell Indicator", "ouch.buy_sell_indicator",
1374             FT_CHAR, BASE_HEX, VALS(ouch_buy_sell_indicator_val), 0x0,
1375             NULL, HFILL }},
1376
1377         { &hf_ouch_cancel_reason,
1378           { "Cancel Reason", "ouch.cancel_reason",
1379             FT_CHAR, BASE_HEX, VALS(ouch_cancel_reason_val), 0x0,
1380             NULL, HFILL }},
1381
1382         { &hf_ouch_capacity,
1383           { "Capacity", "ouch.capacity",
1384             FT_CHAR, BASE_HEX, VALS(ouch_capacity_val), 0x0,
1385             NULL, HFILL }},
1386
1387         { &hf_ouch_cross_type,
1388           { "Cross Type", "ouch.cross_type",
1389             FT_CHAR, BASE_HEX, VALS(ouch_cross_type_val), 0x0,
1390             NULL, HFILL }},
1391
1392         { &hf_ouch_customer_type,
1393           { "Customer Type", "ouch.customer_type",
1394             FT_CHAR, BASE_HEX, VALS(ouch_customer_type_val), 0x0,
1395             NULL, HFILL }},
1396
1397         { &hf_ouch_decrement_shares,
1398           { "Decrement Shares", "ouch.decrement_shares",
1399             FT_UINT32, BASE_DEC, NULL, 0x0,
1400             NULL, HFILL }},
1401
1402         { &hf_ouch_display,
1403           { "Display", "ouch.display",
1404             FT_CHAR, BASE_HEX, VALS(ouch_display_val), 0x0,
1405             NULL, HFILL }},
1406
1407         { &hf_ouch_event_code,
1408           { "Event Code", "ouch.event_code",
1409             FT_CHAR, BASE_HEX, VALS(ouch_event_code_val), 0x0,
1410             NULL, HFILL }},
1411
1412         { &hf_ouch_executed_shares,
1413           { "Executed Shares", "ouch.executed_shares",
1414             FT_UINT32, BASE_DEC, NULL, 0x0,
1415             NULL, HFILL }},
1416
1417         { &hf_ouch_execution_price,
1418           { "Execution Price", "ouch.execution_price",
1419             FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1420             NULL, HFILL }},
1421
1422         { &hf_ouch_existing_order_token,
1423           { "Existing Order Token", "ouch.existing_order_token",
1424             FT_STRING, BASE_NONE, NULL, 0x0,
1425             NULL, HFILL }},
1426
1427         { &hf_ouch_firm,
1428           { "Firm", "ouch.firm",
1429             FT_STRING, BASE_NONE, NULL, 0x0,
1430             NULL, HFILL }},
1431
1432         { &hf_ouch_iso_eligible,
1433           { "Intermarket Sweep Eligibility", "ouch.iso_eligible",
1434             FT_CHAR, BASE_HEX, VALS(ouch_iso_eligibility_val), 0x0,
1435             NULL, HFILL }},
1436
1437         { &hf_ouch_liquidity_flag,
1438           { "Liquidity Flag", "ouch.liquidity_flag",
1439             FT_CHAR, BASE_HEX, VALS(ouch_liquidity_flag_val), 0x0,
1440             NULL, HFILL }},
1441
1442         { &hf_ouch_match_number,
1443           { "Match Number", "ouch.match_number",
1444             FT_UINT64, BASE_DEC, NULL, 0x0,
1445             NULL, HFILL }},
1446
1447         { &hf_ouch_message,
1448           { "Unknown Message", "ouch.unknown_message",
1449             FT_BYTES, BASE_NONE, NULL, 0x0,
1450             NULL, HFILL }},
1451
1452         { &hf_ouch_min_quantity,
1453           { "Minimum Quantity", "ouch.min_quantity",
1454             FT_UINT32, BASE_DEC, NULL, 0x0,
1455             NULL, HFILL }},
1456
1457         { &hf_ouch_new_execution_price,
1458           { "New Execution Price", "ouch.new_execution_price",
1459             FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1460             NULL, HFILL }},
1461
1462         { &hf_ouch_order_reference_number,
1463           { "Order Reference Number", "ouch.order_reference_number",
1464             FT_UINT64, BASE_DEC, NULL, 0x0,
1465             NULL, HFILL }},
1466
1467         { &hf_ouch_order_state,
1468           { "Order State", "ouch.order_state",
1469             FT_CHAR, BASE_HEX, VALS(ouch_order_state_val), 0x0,
1470             NULL, HFILL }},
1471
1472         { &hf_ouch_order_token,
1473           { "Order Token", "ouch.order_token",
1474             FT_STRING, BASE_NONE, NULL, 0x0,
1475             NULL, HFILL }},
1476
1477         { &hf_ouch_packet_type,
1478           { "Packet Type", "ouch.packet_type",
1479             FT_CHAR, BASE_HEX, VALS(pkt_type_val), 0x0,
1480             NULL, HFILL }},
1481
1482         { &hf_ouch_previous_order_token,
1483           { "Previous Order Token", "ouch.previous_order_token",
1484             FT_STRING, BASE_NONE, NULL, 0x0,
1485             NULL, HFILL }},
1486
1487         { &hf_ouch_price,
1488           { "Price", "ouch.price",
1489             FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1490             NULL, HFILL }},
1491
1492         { &hf_ouch_price_correction_reason,
1493           { "Price Correction Reason", "ouch.price_correction_reason",
1494             FT_CHAR, BASE_HEX, VALS(ouch_price_correction_reason_val), 0x0,
1495             NULL, HFILL }},
1496
1497         { &hf_ouch_quantity_prevented_from_trading,
1498           { "Quantity Prevented from Trading",
1499             "ouch.quantity_prevented_from_trading",
1500             FT_UINT32, BASE_DEC, NULL, 0x0,
1501             NULL, HFILL }},
1502
1503         { &hf_ouch_reference_price,
1504           { "Reference Price", "ouch.reference_price",
1505             FT_UINT32, BASE_CUSTOM, CF_FUNC(format_price), 0x0,
1506             NULL, HFILL }},
1507
1508         { &hf_ouch_reference_price_type,
1509           { "Reference Price Type", "ouch.reference_price_type",
1510             FT_UINT32, BASE_CUSTOM, CF_FUNC(format_reference_price_type), 0x0,
1511             NULL, HFILL }},
1512
1513         { &hf_ouch_reject_reason,
1514           { "Reject Reason", "ouch.reject_reason",
1515             FT_CHAR, BASE_HEX, VALS(ouch_reject_reason_val), 0x0,
1516             NULL, HFILL }},
1517
1518         { &hf_ouch_replacement_order_token,
1519           { "Replacement Order Token", "ouch.replacement_order_token",
1520             FT_STRING, BASE_NONE, NULL, 0x0,
1521             NULL, HFILL }},
1522
1523         { &hf_ouch_shares,
1524           { "Shares", "ouch.shares",
1525             FT_UINT32, BASE_DEC, NULL, 0x0,
1526             NULL, HFILL }},
1527
1528         { &hf_ouch_stock,
1529           { "Stock", "ouch.stock",
1530             FT_STRING, BASE_NONE, NULL, 0x0,
1531             NULL, HFILL }},
1532
1533         { &hf_ouch_tif,
1534           { "Time In Force", "ouch.tif",
1535             FT_UINT32, BASE_CUSTOM, CF_FUNC(format_tif), 0x0,
1536             NULL, HFILL }},
1537
1538         { &hf_ouch_timestamp,
1539           { "Timestamp", "ouch.timestamp",
1540             FT_STRING, BASE_NONE, NULL, 0x0,
1541             NULL, HFILL }},
1542
1543         { &hf_ouch_trade_correction_reason,
1544           { "Trade Correction Reason", "ouch.trade_correction_reason",
1545             FT_CHAR, BASE_HEX, VALS(ouch_trade_correction_reason_val), 0x0,
1546             NULL, HFILL }}
1547     };
1548
1549     /* Setup protocol subtree array */
1550     static gint *ett[] = {
1551         &ett_ouch
1552     };
1553
1554     /* Register the protocol name and description */
1555     proto_ouch = proto_register_protocol("OUCH", "OUCH", "ouch");
1556
1557     /* Required function calls to register the header fields and
1558      * subtrees used */
1559     proto_register_field_array(proto_ouch, hf, array_length(hf));
1560     proto_register_subtree_array(ett, array_length(ett));
1561 }
1562
1563
1564 /* If this dissector uses sub-dissector registration add a
1565  * registration routine.  This format is required because a script is
1566  * used to find these routines and create the code that calls these
1567  * routines. */
1568 void
1569 proto_reg_handoff_ouch(void)
1570 {
1571     ouch_handle = create_dissector_handle(dissect_ouch, proto_ouch);
1572     heur_dissector_add("soupbintcp", dissect_ouch_heur, "OUCH over SoupBinTCP", "ouch_soupbintcp", proto_ouch, HEURISTIC_ENABLE);
1573     dissector_add_uint_range_with_preference("tcp.port", "", ouch_handle);
1574 }
1575
1576
1577
1578 /*
1579  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1580  *
1581  * Local variables:
1582  * c-basic-offset: 4
1583  * tab-width: 8
1584  * indent-tabs-mode: nil
1585  * End:
1586  *
1587  * vi: set shiftwidth=4 tabstop=8 expandtab:
1588  * :indentSize=4:tabSize=8:noTabs=true:
1589  */