HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-fix.c
blob08b9fc7cf4a8b90cdf0c43bd7a977cced4da5d7a
1 /* packet-fix.c
2 * Routines for Financial Information eXchange (FIX) Protocol dissection
3 * Copyright 2000, PC Drew <drewpc@ibsncentral.com>
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * Documentation: http://www.fixprotocol.org/
26 * Fields and messages from http://www.quickfixengine.org/ and http://sourceforge.net/projects/quickfix/files/ xml
30 #include "config.h"
32 #include <stdlib.h>
33 #include <string.h>
35 #include <glib.h>
37 #include <epan/packet.h>
38 #include <epan/expert.h>
39 #include <epan/prefs.h>
40 #include <epan/conversation.h>
42 #include "packet-tcp.h"
43 #include "packet-ssl.h"
45 typedef struct _fix_parameter {
46 int field_len;
47 int tag_len;
48 int value_offset;
49 int value_len;
50 int ctrla_offset;
51 } fix_parameter;
53 /* Initialize the protocol and registered fields */
54 static int proto_fix = -1;
56 /* desegmentation of fix */
57 static gboolean fix_desegment = TRUE;
59 /* Initialize the subtree pointers */
60 static gint ett_fix = -1;
61 static gint ett_unknow = -1;
62 static gint ett_badfield = -1;
63 static gint ett_checksum = -1;
65 static expert_field ei_fix_checksum_bad = EI_INIT;
67 static int hf_fix_data = -1; /* continuation data */
68 static int hf_fix_checksum_good = -1;
69 static int hf_fix_checksum_bad = -1;
70 static int hf_fix_field_value = -1;
71 static int hf_fix_field_tag = -1;
73 static dissector_handle_t fix_handle;
75 static range_t *global_fix_tcp_range = NULL;
76 static range_t *fix_tcp_range = NULL;
78 /* 8=FIX */
79 #define MARKER_TAG "8=FIX"
80 #define MARKER_LEN 5
82 static int fix_marker(tvbuff_t *tvb, int offset)
84 return tvb_strneql(tvb, offset, MARKER_TAG, MARKER_LEN);
88 * Fields and messages generated from http://www.quickfixengine.org/ xml (slightly modified)
91 #include "packet-fix.h"
93 static void dissect_fix_init(void) {
94 /* TODO load xml def for private field */
95 /* TODO check that fix_fields is really sorted */
98 static int
99 tag_search(int key)
101 int lower = 0, upper = array_length(fix_fields) -1;
102 while (lower <= upper) {
103 int middle = (lower + upper) / 2;
104 int res = fix_fields[middle].tag;
105 if (res < key) {
106 lower = middle + 1;
107 } else if (res == key) {
108 return middle;
109 } else {
110 upper = middle - 1;
113 return -1;
116 /* Code to actually dissect the packets */
117 static int fix_next_header(tvbuff_t *tvb, int offset)
119 /* try to resync to the next start */
120 guint min_len = tvb_length_remaining(tvb, offset);
121 const guint8 *data = tvb_get_string(wmem_packet_scope(), tvb, offset, min_len);
122 const guint8 *start = data;
124 while ((start = strstr(start, "\0018"))) {
125 min_len = (guint) (start +1 -data);
126 /* if remaining length < 6 return and let the next desegment round
127 test for 8=FIX
129 if (tvb_length_remaining(tvb, min_len + offset) < MARKER_LEN)
130 break;
131 if (!fix_marker(tvb, min_len +offset) )
132 break;
133 start++;
135 return min_len;
138 /* ----------------------------------------------
139 Format: name=value\001
141 static fix_parameter *fix_param(tvbuff_t *tvb, int offset)
143 static fix_parameter ret;
144 int equals;
146 ret.ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
147 if (ret.ctrla_offset == -1) {
148 return NULL;
151 ret.field_len = ret.ctrla_offset - offset + 1;
152 equals = tvb_find_guint8(tvb, offset, ret.field_len, '=');
153 if (equals == -1) {
154 return NULL;
157 ret.value_offset = equals + 1;
158 ret.tag_len = ret.value_offset - offset - 1;
159 ret.value_len = ret.ctrla_offset - ret.value_offset;
160 return &ret;
163 /* ---------------------------------------------- */
164 static int fix_header_len(tvbuff_t *tvb, int offset)
166 int base_offset, ctrla_offset;
167 char *value;
168 int size;
169 fix_parameter *tag;
171 base_offset = offset;
173 /* get at least the fix version: 8=FIX.x.x */
174 if (fix_marker(tvb, offset) != 0) {
175 return fix_next_header(tvb, offset);
178 /* begin string */
179 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
180 if (ctrla_offset == -1) {
181 /* it should be there, (minimum size is big enough)
182 * if not maybe it's not really
183 * a FIX packet but it's too late to bail out.
185 return fix_next_header(tvb, offset +MARKER_LEN) +MARKER_LEN;
187 offset = ctrla_offset + 1;
189 /* msg length */
190 if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) {
191 /* not a tag or not the BodyLength tag, give up */
192 return fix_next_header(tvb, offset);
195 value = tvb_get_string(wmem_packet_scope(), tvb, tag->value_offset, tag->value_len);
196 /* Fix version, msg type, length and checksum aren't in body length.
197 * If the packet is big enough find the checksum
199 size = atoi(value) +tag->ctrla_offset - base_offset +1;
200 if (tvb_length_remaining(tvb, base_offset) > size +4) {
201 /* 10= should be there */
202 offset = base_offset +size;
203 if (tvb_strneql(tvb, offset, "10=", 3) != 0) {
204 /* No? bogus packet, try to find the next header */
205 return fix_next_header(tvb, base_offset +MARKER_LEN) +MARKER_LEN;
207 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
208 if (ctrla_offset == -1) {
209 /* assume checksum is 7 bytes 10=xxx\01 */
210 return size+7;
212 return size +ctrla_offset -offset +1;
214 else {
216 /* assume checksum is 7 bytes 10=xxx\01 */
217 return size +7;
220 /* ---------------------------------------------- */
221 static int
222 dissect_fix_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
224 /* Set up structures needed to add the protocol subtree and manage it */
225 proto_item *ti;
226 proto_tree *fix_tree;
227 int pdu_len;
228 int offset = 0;
229 int field_offset, ctrla_offset;
230 int tag_value;
231 char *value;
232 char *tag_str;
233 fix_parameter *tag;
234 const char *msg_type;
236 /* Make entries in Protocol column and Info column on summary display */
237 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIX");
238 col_clear(pinfo->cinfo, COL_INFO);
240 /* get at least the fix version: 8=FIX.x.x */
241 if (fix_marker(tvb, 0) != 0) {
242 /* not a fix packet start but it's a fix packet */
243 col_set_str(pinfo->cinfo, COL_INFO, "[FIX continuation]");
244 ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA);
245 fix_tree = proto_item_add_subtree(ti, ett_fix);
246 proto_tree_add_item(fix_tree, hf_fix_data, tvb, 0, -1, ENC_NA);
247 return tvb_length(tvb);
250 pdu_len = tvb_reported_length(tvb);
251 ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA);
252 fix_tree = proto_item_add_subtree(ti, ett_fix);
254 /* begin string */
255 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
256 if (ctrla_offset == -1) {
257 return tvb_length(tvb);
259 offset = ctrla_offset + 1;
261 /* msg length */
262 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
263 if (ctrla_offset == -1) {
264 return tvb_length(tvb);
266 offset = ctrla_offset + 1;
268 /* msg type */
269 if (!(tag = fix_param(tvb, offset)) || tag->value_len < 1) {
270 return tvb_length(tvb);
273 value = tvb_get_string(wmem_packet_scope(), tvb, tag->value_offset, tag->value_len);
274 msg_type = str_to_str(value, messages_val, "FIX Message (%s)");
275 col_add_str(pinfo->cinfo, COL_INFO, msg_type);
277 /* In the interest of speed, if "tree" is NULL, don't do any work not
278 * necessary to generate protocol tree items.
280 field_offset = 0;
282 while(field_offset < pdu_len && (tag = fix_param(tvb, field_offset)) ) {
283 int i, found;
285 if (tag->tag_len < 1) {
286 field_offset = tag->ctrla_offset + 1;
287 continue;
290 tag_str = tvb_get_string(wmem_packet_scope(), tvb, field_offset, tag->tag_len);
291 tag_value = atoi(tag_str);
292 if (tag->value_len < 1) {
293 proto_tree *field_tree;
294 /* XXX - put an error indication here. It's too late
295 to return FALSE; we've already started dissecting,
296 and if a heuristic dissector starts dissecting
297 (either updating the columns or creating a protocol
298 tree) and then gives up, it leaves crud behind that
299 messes up other dissectors that might process the
300 packet. */
301 ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: <missing value>", tag_value);
302 field_tree = proto_item_add_subtree(ti, ett_badfield);
303 proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
304 field_offset = tag->ctrla_offset + 1;
305 continue;
308 /* fix_fields array is sorted by tag_value */
309 found = 0;
310 if ((i = tag_search(tag_value)) >= 0) {
311 found = 1;
314 value = tvb_get_string(wmem_packet_scope(), tvb, tag->value_offset, tag->value_len);
315 if (found) {
316 if (fix_fields[i].table) {
317 if (tree) {
318 switch (fix_fields[i].type) {
319 case 1: /* strings */
320 proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
321 "%s (%s)", value, str_to_str(value, (string_string *)fix_fields[i].table, "unknown %s"));
322 break;
323 case 2: /* char */
324 proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
325 "%s (%s)", value, val_to_str(*value, (value_string *)fix_fields[i].table, "unknown %d"));
326 break;
327 default:
328 proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
329 "%s (%s)", value, val_to_str(atoi(value), (value_string *)fix_fields[i].table, "unknown %d"));
330 break;
334 else {
335 proto_item *item;
337 /* checksum */
338 switch(tag_value) {
339 case 10:
341 proto_tree *checksum_tree;
342 guint8 sum = 0;
343 const guint8 *sum_data = tvb_get_ptr(tvb, 0, field_offset);
344 gboolean sum_ok;
345 int j;
347 for (j = 0; j < field_offset; j++, sum_data++) {
348 sum += *sum_data;
350 sum_ok = (atoi(value) == sum);
351 if (sum_ok) {
352 item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
353 value, "%s [correct]", value);
355 else {
356 item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
357 value, "%s [incorrect should be %d]", value, sum);
359 checksum_tree = proto_item_add_subtree(item, ett_checksum);
360 item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_good, tvb, field_offset, tag->field_len, sum_ok);
361 PROTO_ITEM_SET_GENERATED(item);
362 item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_bad, tvb, field_offset, tag->field_len, !sum_ok);
363 PROTO_ITEM_SET_GENERATED(item);
364 if (!sum_ok)
365 expert_add_info(pinfo, item, &ei_fix_checksum_bad);
367 break;
368 default:
369 proto_tree_add_string(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value);
370 break;
374 else if (tree) {
375 proto_tree *field_tree;
377 /* XXX - it could be -1 if the tag isn't a number */
378 ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: %s", tag_value, value);
379 field_tree = proto_item_add_subtree(ti, ett_unknow);
380 proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
381 proto_tree_add_item(field_tree, hf_fix_field_value, tvb, tag->value_offset, tag->value_len, ENC_ASCII|ENC_NA);
384 field_offset = tag->ctrla_offset + 1;
386 tag_str = NULL;
388 return tvb_length(tvb);
391 static guint
392 get_fix_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
394 int fix_len;
396 fix_len = fix_header_len(tvb, offset);
397 return fix_len;
400 /* ------------------------------------
401 fixed-length part isn't really a constant but if we assume it's at least:
402 8=FIX.x.y\01 10
403 9=x\01 4
404 35=x\01 5
405 10=y\01 5
407 it should catch all 9= size
410 #define FIX_MIN_LEN 24
412 static int
413 dissect_fix_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
415 tcp_dissect_pdus(tvb, pinfo, tree, fix_desegment, FIX_MIN_LEN,
416 get_fix_pdu_len, dissect_fix_packet, data);
418 return tvb_length(tvb);
421 static int
422 dissect_fix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
424 return dissect_fix_pdus(tvb, pinfo, tree, data);
427 /* Code to actually dissect the packets */
428 static gboolean
429 dissect_fix_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
431 conversation_t *conv;
433 /* get at least the fix version: 8=FIX.x.x */
434 if (fix_marker(tvb, 0) != 0) {
435 /* not a fix packet */
436 return FALSE;
439 conv = find_or_create_conversation(pinfo);
440 conversation_set_dissector(conv, fix_handle);
442 dissect_fix_pdus(tvb, pinfo, tree, data);
443 return TRUE;
446 /* Register the protocol with Wireshark */
447 static void fix_prefs(void)
449 dissector_delete_uint_range("tcp.port", fix_tcp_range, fix_handle);
450 g_free(fix_tcp_range);
451 fix_tcp_range = range_copy(global_fix_tcp_range);
452 dissector_add_uint_range("tcp.port", fix_tcp_range, fix_handle);
455 /* this format is require because a script is used to build the C function
456 that calls all the protocol registration.
459 void
460 proto_register_fix(void)
462 static hf_register_info hf[] = {
463 { &hf_fix_data,
464 { "Continuation Data", "fix.data", FT_BYTES, BASE_NONE, NULL, 0x00,
465 NULL, HFILL }
468 { &hf_fix_field_tag,
469 { "Field Tag", "fix.field.tag", FT_UINT16, BASE_DEC, NULL, 0x0,
470 "Field length.", HFILL }},
472 { &hf_fix_field_value,
473 { "Field Value", "fix.field.value", FT_STRING, BASE_NONE, NULL, 0x0,
474 NULL, HFILL }},
476 { &hf_fix_checksum_good,
477 { "Good Checksum", "fix.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
478 "True: checksum matches packet content; False: doesn't match content or not checked", HFILL }},
480 { &hf_fix_checksum_bad,
481 { "Bad Checksum", "fix.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
482 "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
485 /* Setup protocol subtree array */
486 static gint *ett[] = {
487 &ett_fix,
488 &ett_unknow,
489 &ett_badfield,
490 &ett_checksum,
493 static ei_register_info ei[] = {
494 { &ei_fix_checksum_bad, { "fix.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
497 module_t *fix_module;
498 expert_module_t* expert_fix;
500 /* register re-init routine */
501 register_init_routine(&dissect_fix_init);
503 /* Register the protocol name and description */
504 proto_fix = proto_register_protocol("Financial Information eXchange Protocol",
505 "FIX", "fix");
507 /* Allow dissector to find be found by name. */
508 fix_handle = new_register_dissector("fix", dissect_fix, proto_fix);
510 proto_register_field_array(proto_fix, hf, array_length(hf));
511 proto_register_field_array(proto_fix, hf_FIX, array_length(hf_FIX));
512 proto_register_subtree_array(ett, array_length(ett));
513 expert_fix = expert_register_protocol(proto_fix);
514 expert_register_field_array(expert_fix, ei, array_length(ei));
516 fix_module = prefs_register_protocol(proto_fix, fix_prefs);
517 prefs_register_bool_preference(fix_module, "desegment",
518 "Reassemble FIX messages spanning multiple TCP segments",
519 "Whether the FIX dissector should reassemble messages spanning multiple TCP segments."
520 " To use this option, you must also enable"
521 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
522 &fix_desegment);
524 prefs_register_range_preference(fix_module, "tcp.port", "TCP Ports", "TCP Ports range", &global_fix_tcp_range, 65535);
526 fix_tcp_range = range_empty();
530 void
531 proto_reg_handoff_fix(void)
533 /* Let the tcp dissector know that we're interested in traffic */
534 heur_dissector_add("tcp", dissect_fix_heur, proto_fix);
535 /* Register a fix handle to "tcp.port" to be able to do 'decode-as' */
536 dissector_add_handle("tcp.port", fix_handle);