Fix gcc 4.6 "set but not used [-Wunused-but-set-variable]" warnings.
[obnox/wireshark/wip.git] / epan / dissectors / packet-fix.c
1 /* packet-fix.c
2  * Routines for Financial Information eXchange (FIX) Protocol dissection
3  * Copyright 2000, PC Drew <drewpc@ibsncentral.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  * Documentation: http://www.fixprotocol.org/
26  * Fields and messages from http://www.quickfixengine.org/ xml
27  *
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <glib.h>
38
39 #include <epan/packet.h>
40 #include <epan/expert.h>
41 #include <epan/prefs.h>
42 #include <epan/conversation.h>
43
44 #include "packet-tcp.h"
45
46 typedef struct _fix_field {
47     int         tag;    /* FIX tag */
48     int         hf_id;
49     int         type;   /* */
50     const void *table;
51 } fix_field;
52
53 typedef struct _fix_parameter {
54     int field_len;
55     int tag_len;
56     int value_offset;
57     int value_len;
58     int ctrla_offset;
59 } fix_parameter;
60
61 /* Initialize the protocol and registered fields */
62 static int proto_fix = -1;
63 static dissector_handle_t fix_handle;
64
65 /* desegmentation of fix */
66 static gboolean fix_desegment = TRUE;
67
68 /* Initialize the subtree pointers */
69 static gint ett_fix = -1;
70 static gint ett_unknow = -1;
71 static gint ett_badfield = -1;
72 static gint ett_checksum = -1;
73
74 static int hf_fix_data = -1; /* continuation data */
75 static int hf_fix_checksum_good = -1;
76 static int hf_fix_checksum_bad = -1;
77 static int hf_fix_field_value = -1;
78 static int hf_fix_field_tag = -1;
79
80 static range_t *global_fix_tcp_range = NULL;
81 static range_t *fix_tcp_range = NULL;
82
83 /* 8=FIX */
84 #define MARKER_TAG "8=FIX"
85 #define MARKER_LEN 5
86 static int fix_marker(tvbuff_t *tvb, int offset)
87 {
88   return tvb_strneql(tvb, offset, MARKER_TAG, MARKER_LEN);
89 }
90
91 /*
92  * Fields and messages generated from http://www.quickfixengine.org/ xml (slightly modified)
93  */
94
95 #include "packet-fix.h"
96
97 static void dissect_fix_init(void) {
98     /* TODO load xml def for private field */
99     /* TODO check that fix_fields is really sorted */
100 }
101
102 static int
103 tag_search(int key)
104 {
105     int lower = 0, upper = array_length(fix_fields) -1;
106     while (lower <= upper) {
107         int middle = (lower + upper) / 2;
108         int res = fix_fields[middle].tag;
109         if (res < key) {
110             lower = middle + 1;
111         } else if (res == key) {
112             return middle;
113         } else {
114             upper = middle - 1;
115         }
116     }
117     return -1;
118 }
119
120 /* Code to actually dissect the packets */
121 static int fix_next_header(tvbuff_t *tvb, int offset)
122 {
123     /* try to resynch to the next start */
124     guint min_len = tvb_length_remaining(tvb, offset);
125     const guint8 *data = tvb_get_ephemeral_string(tvb, offset, min_len);
126     const guint8 *start = data;
127
128     while ((start = strstr(start, "\0018"))) {
129         min_len = (guint) (start +1 -data);
130         /*  if remaining length < 6 return and let the next desegment round
131             test for 8=FIX
132         */
133         if (tvb_length_remaining(tvb, min_len + offset) < MARKER_LEN)
134            break;
135         if (!fix_marker(tvb, min_len +offset) )
136             break;
137         start++;
138     }
139     return min_len;
140 }
141
142 /* ----------------------------------------------
143   Format: name=value\001
144 */
145 static fix_parameter *fix_param(tvbuff_t *tvb, int offset)
146 {
147     static fix_parameter ret;
148     int equals;
149
150     ret.ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
151     if (ret.ctrla_offset == -1) {
152         return NULL;
153     }
154
155     ret.field_len = ret.ctrla_offset - offset + 1;
156     equals = tvb_find_guint8(tvb, offset, ret.field_len, '=');
157     if (equals == -1) {
158         return NULL;
159     }
160
161     ret.value_offset = equals + 1;
162     ret.tag_len = ret.value_offset - offset - 1;
163     ret.value_len = ret.ctrla_offset - ret.value_offset;
164     return &ret;
165 }
166
167 /* ---------------------------------------------- */
168 static int fix_header_len(tvbuff_t *tvb, int offset)
169 {
170     int base_offset, ctrla_offset;
171     char *value;
172     int size;
173     fix_parameter *tag;
174
175     base_offset = offset;
176
177     /* get at least the fix version: 8=FIX.x.x */
178     if (fix_marker(tvb, offset) != 0) {
179         return fix_next_header(tvb, offset);
180     }
181
182     /* begin string */
183     ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
184     if (ctrla_offset == -1) {
185         /* it should be there, (minimum size is big enough)
186          * if not maybe it's not really
187          * a FIX packet but it's too late to bail out.
188         */
189         return fix_next_header(tvb, offset +MARKER_LEN) +MARKER_LEN;
190     }
191     offset = ctrla_offset + 1;
192
193     /* msg length */
194     if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) {
195         /* not a tag or not the BodyLength tag, give up */
196         return fix_next_header(tvb, offset);
197     }
198
199     value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len);
200     /* Fix version, msg type, length and checksum aren't in body length.
201      * If the packet is big enough find the checksum
202     */
203     size = atoi(value) +tag->ctrla_offset - base_offset +1;
204     if (tvb_length_remaining(tvb, base_offset) > size +4) {
205         /* 10= should be there */
206         offset = base_offset +size;
207         if (tvb_strneql(tvb, offset, "10=", 3) != 0) {
208             /* No? bogus packet, try to find the next header */
209             return fix_next_header(tvb, base_offset +MARKER_LEN)  +MARKER_LEN;
210         }
211         ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
212         if (ctrla_offset == -1) {
213             /* assume checksum is 7 bytes 10=xxx\01 */
214             return size+7;
215         }
216         return size +ctrla_offset -offset +1;
217     }
218     else {
219     }
220     /* assume checksum is 7 bytes 10=xxx\01 */
221     return size +7;
222 }
223
224 /* ---------------------------------------------- */
225 static void
226 dissect_fix_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
227 {
228     /* Set up structures needed to add the protocol subtree and manage it */
229     proto_item *ti;
230     proto_tree *fix_tree;
231     int pdu_len;
232     int offset = 0;
233     int field_offset, ctrla_offset;
234     int tag_value;
235     char *value;
236     char *tag_str;
237     fix_parameter *tag;
238
239     /* Make entries in Protocol column and Info column on summary display */
240     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIX");
241     col_clear(pinfo->cinfo, COL_INFO);
242
243     /* get at least the fix version: 8=FIX.x.x */
244     if (fix_marker(tvb, 0) != 0) {
245         /* not a fix packet start but it's a fix packet */
246         col_set_str(pinfo->cinfo, COL_INFO, "[FIX continuation]");
247         ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, FALSE);
248         fix_tree = proto_item_add_subtree(ti, ett_fix);
249         proto_tree_add_item(fix_tree, hf_fix_data, tvb, 0, -1, FALSE);
250         return;
251     }
252
253     pdu_len = tvb_reported_length(tvb);
254     ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, FALSE);
255     fix_tree = proto_item_add_subtree(ti, ett_fix);
256
257     /* begin string */
258     ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
259     if (ctrla_offset == -1) {
260         return;
261     }
262     offset = ctrla_offset + 1;
263
264     /* msg length */
265     ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
266     if (ctrla_offset == -1) {
267         return;
268     }
269     offset = ctrla_offset + 1;
270
271     /* msg type */
272     if (!(tag = fix_param(tvb, offset)) || tag->value_len < 1) {
273         return;
274     }
275
276     if (check_col(pinfo->cinfo, COL_INFO)) {
277         const char *msg_type;
278
279         value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len);
280         msg_type = str_to_str(value, messages_val, "FIX Message (%s)");
281         col_add_str(pinfo->cinfo, COL_INFO, msg_type);
282     }
283
284     /* In the interest of speed, if "tree" is NULL, don't do any work not
285      * necessary to generate protocol tree items.
286      */
287     field_offset = 0;
288
289     while(field_offset < pdu_len && (tag = fix_param(tvb, field_offset)) ) {
290         int i, found;
291
292         if (tag->tag_len < 1) {
293             field_offset =  tag->ctrla_offset + 1;
294             continue;
295         }
296
297         tag_str = tvb_get_ephemeral_string(tvb, field_offset, tag->tag_len);
298         tag_value = atoi(tag_str);
299         if (tag->value_len < 1) {
300             proto_tree *field_tree;
301             /* XXX - put an error indication here.  It's too late
302                to return FALSE; we've already started dissecting,
303                and if a heuristic dissector starts dissecting
304                (either updating the columns or creating a protocol
305                tree) and then gives up, it leaves crud behind that
306                messes up other dissectors that might process the
307                packet. */
308             ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: <missing value>", tag_value);
309             field_tree = proto_item_add_subtree(ti, ett_badfield);
310             proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
311             field_offset =  tag->ctrla_offset + 1;
312             continue;
313         }
314
315         /* fix_fields array is sorted by tag_value */
316         found = 0;
317         if ((i = tag_search(tag_value)) >= 0) {
318             found = 1;
319         }
320
321         value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len);
322         if (found) {
323             if (fix_fields[i].table) {
324                 if (tree) {
325                     switch (fix_fields[i].type) {
326                     case 1: /* strings */
327                         proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
328                             "%s (%s)", value, str_to_str(value, fix_fields[i].table, "unknow %s"));
329                         break;
330                     case 2: /* char */
331                         proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
332                             "%s (%s)", value, val_to_str(*value, fix_fields[i].table, "unknow %d"));
333                         break;
334                     default:
335                         proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
336                             "%s (%s)", value, val_to_str(atoi(value), fix_fields[i].table, "unknow %d"));
337                         break;
338                     }
339                 }
340             }
341             else {
342               proto_item *item;
343
344               /* checksum */
345               switch(tag_value) {
346               case 10:
347                 {
348                     proto_tree *checksum_tree;
349                     guint8 sum = 0;
350                     const guint8 *data = tvb_get_ptr(tvb, 0, field_offset);
351                     gboolean sum_ok;
352                     int j;
353
354                     for (j = 0; j < field_offset; j++, data++) {
355                          sum += *data;
356                     }
357                     sum_ok = (atoi(value) == sum);
358                     if (sum_ok) {
359                         item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
360                                 value, "%s [correct]", value);
361                     }
362                     else {
363                         item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
364                                 value, "%s [incorrect should be %d]", value, sum);
365                     }
366                     checksum_tree = proto_item_add_subtree(item, ett_checksum);
367                     item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_good, tvb, field_offset, tag->field_len, sum_ok);
368                     PROTO_ITEM_SET_GENERATED(item);
369                     item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_bad, tvb, field_offset, tag->field_len, !sum_ok);
370                     PROTO_ITEM_SET_GENERATED(item);
371                     if (!sum_ok)
372                         expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum");
373                 }
374                 break;
375               default:
376                 proto_tree_add_string(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value);
377                 break;
378               }
379             }
380         }
381         else if (tree) {
382           proto_tree *field_tree;
383
384           /* XXX - it could be -1 if the tag isn't a number */
385           ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: %s", tag_value, value);
386           field_tree = proto_item_add_subtree(ti, ett_unknow);
387           proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
388           proto_tree_add_item(field_tree, hf_fix_field_value, tvb, tag->value_offset, tag->value_len, FALSE);
389         }
390
391         field_offset =  tag->ctrla_offset + 1;
392
393         tag_str = NULL;
394     }
395     return;
396 }
397
398 static guint
399 get_fix_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
400 {
401     int fix_len;
402
403     fix_len = fix_header_len(tvb, offset);
404     return fix_len;
405 }
406
407 /* ------------------------------------
408    fixed-length part isn't really a constant but if we assume it's at least:
409        8=FIX.x.y\01   10
410        9=x\01          4
411        35=x\01         5
412        10=y\01         5
413                       24
414        it should catch all 9= size
415 */
416
417 #define FIX_MIN_LEN 24
418
419 static void
420 dissect_fix_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
421 {
422     tcp_dissect_pdus(tvb, pinfo, tree, fix_desegment, FIX_MIN_LEN,
423                      get_fix_pdu_len, dissect_fix_packet);
424
425 }
426
427 static void
428 dissect_fix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
429 {
430     dissect_fix_pdus(tvb, pinfo, tree);
431 }
432
433 /* Code to actually dissect the packets */
434 static gboolean
435 dissect_fix_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
436 {
437     conversation_t *conv;
438
439     /* get at least the fix version: 8=FIX.x.x */
440     if (fix_marker(tvb, 0) != 0) {
441         /* not a fix packet */
442         return FALSE;
443     }
444
445     conv = find_or_create_conversation(pinfo);
446     conversation_set_dissector(conv, fix_handle);
447
448     dissect_fix_pdus(tvb, pinfo, tree);
449     return TRUE;
450 }
451
452 /* Register the protocol with Wireshark */
453 static void range_delete_fix_tcp_callback(guint32 port) {
454     dissector_delete_uint("tcp.port", port, fix_handle);
455 }
456
457 static void range_add_fix_tcp_callback(guint32 port) {
458     dissector_add_uint("tcp.port", port, fix_handle);
459 }
460
461 static void fix_prefs(void)
462 {
463     range_foreach(fix_tcp_range, range_delete_fix_tcp_callback);
464     g_free(fix_tcp_range);
465     fix_tcp_range = range_copy(global_fix_tcp_range);
466     range_foreach(fix_tcp_range, range_add_fix_tcp_callback);
467 }
468
469 /* this format is require because a script is used to build the C function
470    that calls all the protocol registration.
471 */
472
473 void
474 proto_register_fix(void)
475 {
476 /* Setup list of header fields  See Section 1.6.1 for details*/
477     static hf_register_info hf[] = {
478         { &hf_fix_data,
479           { "Continuation Data", "fix.data", FT_BYTES, BASE_NONE, NULL, 0x00,
480             NULL, HFILL }
481         },
482
483         { &hf_fix_field_tag,
484           { "Field Tag",         "fix.field.tag", FT_UINT16, BASE_DEC, NULL, 0x0,
485             "Field length.", HFILL }},
486
487         { &hf_fix_field_value,
488           { "Field Value",       "fix.field.value", FT_STRING, BASE_NONE, NULL, 0x0,
489             NULL, HFILL }},
490
491         { &hf_fix_checksum_good,
492           { "Good Checksum",       "fix.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
493             "True: checksum matches packet content; False: doesn't match content or not checked", HFILL }},
494
495         { &hf_fix_checksum_bad,
496           { "Bad Checksum",        "fix.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
497             "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
498     };
499
500 /* Setup protocol subtree array */
501     static gint *ett[] = {
502         &ett_fix,
503         &ett_unknow,
504         &ett_badfield,
505         &ett_checksum,
506     };
507
508     module_t *fix_module;
509
510     /* register re-init routine */
511     register_init_routine(&dissect_fix_init);
512
513     /* Register the protocol name and description */
514     proto_fix = proto_register_protocol("Financial Information eXchange Protocol",
515                                         "FIX", "fix");
516
517     /* Required function calls to register the header fields and subtrees used */
518     proto_register_field_array(proto_fix, hf, array_length(hf));
519     proto_register_field_array(proto_fix, hf_FIX, array_length(hf_FIX));
520     proto_register_subtree_array(ett, array_length(ett));
521
522     fix_module = prefs_register_protocol(proto_fix, fix_prefs);
523     prefs_register_bool_preference(fix_module, "desegment",
524                                    "Reassemble FIX messages spanning multiple TCP segments",
525                                    "Whether the FIX dissector should reassemble messages spanning multiple TCP segments."
526                                    " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
527                                    &fix_desegment);
528
529     prefs_register_range_preference(fix_module, "tcp.port", "TCP Ports", "TCP Ports range", &global_fix_tcp_range, 65535);
530
531     fix_tcp_range = range_empty();
532 }
533
534
535 void
536 proto_reg_handoff_fix(void)
537 {
538     /* Let the tcp dissector know that we're interested in traffic      */
539     heur_dissector_add("tcp", dissect_fix_heur, proto_fix);
540     /* Register a fix handle to "tcp.port" to be able to do 'decode-as' */
541     fix_handle = create_dissector_handle(dissect_fix, proto_fix);
542     dissector_add_handle("tcp.port", fix_handle);
543 }
544