1 /* packet-nasdaq-soup.c
2 * Routines for NASDAQ SOUP 2.0 Protocol dissection
3 * Copyright 2007,2008 Didier Gautheron <dgautheron@magic.fr>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
11 * Documentation: http://www.nasdaqtrader.com/Trader.aspx?id=DPSpecs
13 * http://www.nasdaqtrader.com/content/technicalsupport/specifications/dataproducts/souptcp.pdf
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
22 void proto_register_nasdaq_soup(void);
23 void proto_reg_handoff_nasdaq_soup(void);
25 static const value_string message_types_val
[] = {
26 { 'S', "Sequenced Data" },
27 { 'R', "Client Heartbeat" },
28 { 'H', "Server Heartbeat" },
29 { '+' , "Debug Packet" },
30 { 'A', "Login Accepted" },
31 { 'J', "Login Rejected" },
32 { 'L', "Login Request" },
33 { 'U', "Unsequenced Data" },
34 { 'O', "Logout Request" },
38 static const value_string reject_code_val
[] = {
39 { 'A', "Not authorized" },
40 { 'S', "Session not available" },
44 /* Initialize the protocol and registered fields */
45 static int proto_nasdaq_soup
;
46 static dissector_handle_t nasdaq_soup_handle
;
47 static dissector_handle_t nasdaq_itch_handle
;
49 /* desegmentation of Nasdaq Soup */
50 static bool nasdaq_soup_desegment
= true;
52 /* Initialize the subtree pointers */
53 static int ett_nasdaq_soup
;
55 static int hf_nasdaq_soup_packet_type
;
56 static int hf_nasdaq_soup_message
;
57 static int hf_nasdaq_soup_text
;
58 static int hf_nasdaq_soup_packet_eol
;
59 static int hf_nasdaq_soup_username
;
60 static int hf_nasdaq_soup_password
;
61 static int hf_nasdaq_soup_session
;
62 static int hf_nasdaq_soup_seq_number
;
63 static int hf_nasdaq_soup_reject_code
;
66 dissect_nasdaq_soup_packet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, proto_tree
*tree
, int offset
, int linelen
)
68 uint8_t nasdaq_soup_type
;
69 tvbuff_t
*new_tvb
= NULL
;
71 nasdaq_soup_type
= tvb_get_uint8(tvb
, offset
);
72 proto_tree_add_item(tree
, hf_nasdaq_soup_packet_type
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
75 switch (nasdaq_soup_type
) {
76 case '+': /* debug msg */
77 proto_tree_add_item(tree
, hf_nasdaq_soup_text
, tvb
, offset
, linelen
-1, ENC_ASCII
);
80 case 'A': /* login accept */
81 proto_tree_add_item(tree
, hf_nasdaq_soup_session
, tvb
, offset
, 10, ENC_ASCII
);
84 proto_tree_add_item(tree
, hf_nasdaq_soup_seq_number
, tvb
, offset
, 10, ENC_ASCII
);
87 case 'J': /* login reject */
88 proto_tree_add_item(tree
, hf_nasdaq_soup_reject_code
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
92 case 'U': /* unsequenced data packed */
93 case 'S': /* sequenced data packed */
94 if (linelen
> 1 && nasdaq_itch_handle
) {
95 new_tvb
= tvb_new_subset_length(tvb
, offset
,linelen
-1);
97 proto_tree_add_item(tree
, hf_nasdaq_soup_message
, tvb
, offset
, linelen
-1, ENC_ASCII
);
102 case 'L': /* login request */
103 proto_tree_add_item(tree
, hf_nasdaq_soup_username
, tvb
, offset
, 6, ENC_ASCII
);
106 proto_tree_add_item(tree
, hf_nasdaq_soup_password
, tvb
, offset
, 10, ENC_ASCII
);
109 proto_tree_add_item(tree
, hf_nasdaq_soup_session
, tvb
, offset
, 10, ENC_ASCII
);
112 proto_tree_add_item(tree
, hf_nasdaq_soup_seq_number
, tvb
, offset
, 10, ENC_ASCII
);
116 case 'H': /* server heartbeat */
117 case 'O': /* logout request */
118 case 'R': /* client heartbeat */
123 proto_tree_add_item(tree
, hf_nasdaq_soup_message
, tvb
, offset
, linelen
-1, ENC_ASCII
);
124 offset
+= linelen
-1;
128 proto_tree_add_item(tree
, hf_nasdaq_soup_packet_eol
, tvb
, offset
, 1, ENC_ASCII
);
130 call_dissector(nasdaq_itch_handle
, new_tvb
, pinfo
, parent_tree
);
135 /* ---------------------------- */
137 dissect_nasdaq_soup(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
140 proto_tree
*nasdaq_soup_tree
= NULL
;
141 uint8_t nasdaq_soup_type
;
147 while (tvb_offset_exists(tvb
, offset
)) {
148 /* there's only a \n no \r */
149 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, nasdaq_soup_desegment
&& pinfo
->can_desegment
);
152 * We didn't find a line ending, and we're doing desegmentation;
153 * tell the TCP dissector where the data for this message starts
154 * in the data it handed us, and tell it we need one more byte
155 * (we may need more, but we'll try again if what we get next
156 * isn't enough), and return.
158 pinfo
->desegment_offset
= offset
;
159 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
160 return tvb_captured_length(tvb
);
163 nasdaq_soup_type
= tvb_get_uint8(tvb
, offset
);
165 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Nasdaq-SOUP");
166 col_clear(pinfo
->cinfo
, COL_INFO
);
169 col_append_str(pinfo
->cinfo
, COL_INFO
, "; ");
170 col_set_fence(pinfo
->cinfo
, COL_INFO
);
172 col_append_str(pinfo
->cinfo
, COL_INFO
, val_to_str(nasdaq_soup_type
, message_types_val
, "Unknown packet type (0x%02x)"));
175 ti
= proto_tree_add_item(tree
, proto_nasdaq_soup
, tvb
, offset
, linelen
+1, ENC_NA
);
176 nasdaq_soup_tree
= proto_item_add_subtree(ti
, ett_nasdaq_soup
);
178 dissect_nasdaq_soup_packet(tvb
, pinfo
, tree
, nasdaq_soup_tree
, offset
, linelen
);
179 offset
= next_offset
;
181 return tvb_captured_length(tvb
);
185 proto_register_nasdaq_soup(void)
188 /* Setup list of header fields See Section 1.6.1 for details*/
189 static hf_register_info hf
[] = {
191 { &hf_nasdaq_soup_packet_type
,
192 { "Packet Type", "nasdaq-soup.packet_type",
193 FT_CHAR
, BASE_HEX
, VALS(message_types_val
), 0x0,
196 { &hf_nasdaq_soup_reject_code
,
197 { "Login Reject Code", "nasdaq-soup.reject_code",
198 FT_CHAR
, BASE_HEX
, VALS(reject_code_val
), 0x0,
201 { &hf_nasdaq_soup_message
,
202 { "Message", "nasdaq-soup.message",
203 FT_STRING
, BASE_NONE
, NULL
, 0x0,
206 { &hf_nasdaq_soup_text
,
207 { "Debug Text", "nasdaq-soup.text",
208 FT_STRING
, BASE_NONE
, NULL
, 0x0,
211 { &hf_nasdaq_soup_username
,
212 { "User Name", "nasdaq-soup.username",
213 FT_STRING
, BASE_NONE
, NULL
, 0x0,
216 { &hf_nasdaq_soup_password
,
217 { "Password", "nasdaq-soup.password",
218 FT_STRING
, BASE_NONE
, NULL
, 0x0,
221 { &hf_nasdaq_soup_session
,
222 { "Session", "nasdaq-soup.session",
223 FT_STRING
, BASE_NONE
, NULL
, 0x0,
224 "Session ID", HFILL
}},
226 { &hf_nasdaq_soup_seq_number
,
227 { "Sequence number", "nasdaq-soup.seq_number",
228 FT_STRING
, BASE_NONE
, NULL
, 0x0,
231 { &hf_nasdaq_soup_packet_eol
,
232 { "End Of Packet", "nasdaq-soup.packet_eol",
233 FT_STRING
, BASE_NONE
, NULL
, 0x0,
237 /* Setup protocol subtree array */
238 static int *ett
[] = {
242 module_t
*nasdaq_soup_module
;
244 /* Register the protocol name and description */
245 proto_nasdaq_soup
= proto_register_protocol("Nasdaq-SoupTCP version 2.0","NASDAQ-SOUP", "nasdaq_soup");
247 /* Required function calls to register the header fields and subtrees used */
248 proto_register_field_array(proto_nasdaq_soup
, hf
, array_length(hf
));
249 proto_register_subtree_array(ett
, array_length(ett
));
251 /* Register the dissector */
252 nasdaq_soup_handle
= register_dissector("nasdaq_soup", dissect_nasdaq_soup
, proto_nasdaq_soup
);
254 /* Register preferences */
255 nasdaq_soup_module
= prefs_register_protocol(proto_nasdaq_soup
, NULL
);
256 prefs_register_bool_preference(nasdaq_soup_module
, "desegment",
257 "Reassemble Nasdaq-SoupTCP messages spanning multiple TCP segments",
258 "Whether the Nasdaq-SoupTCP dissector should reassemble messages spanning multiple TCP segments.",
259 &nasdaq_soup_desegment
);
262 /* If this dissector uses sub-dissector registration add a registration routine.
263 This format is required because a script is used to find these routines and
264 create the code that calls these routines.
267 proto_reg_handoff_nasdaq_soup(void)
269 nasdaq_itch_handle
= find_dissector_add_dependency("nasdaq-itch", proto_nasdaq_soup
);
270 dissector_add_uint_range_with_preference("tcp.port", "", nasdaq_soup_handle
);
274 * Editor modelines - https://www.wireshark.org/tools/modelines.html
279 * indent-tabs-mode: nil
282 * vi: set shiftwidth=4 tabstop=8 expandtab:
283 * :indentSize=4:tabSize=8:noTabs=true: