diff options
author | Guy Harris <guy@alum.mit.edu> | 2002-04-22 08:50:49 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2002-04-22 08:50:49 +0000 |
commit | 6718d0fe055de882b3a062c6a83f4835f370808f (patch) | |
tree | 1d7175313a19ec35430dc9a0a07887c20927cc91 /packet-dsi.c | |
parent | d215b735038a3ecb00b193446cb9fa0761b2c4ed (diff) | |
download | wireshark-6718d0fe055de882b3a062c6a83f4835f370808f.tar.gz wireshark-6718d0fe055de882b3a062c6a83f4835f370808f.tar.bz2 wireshark-6718d0fe055de882b3a062c6a83f4835f370808f.zip |
Add support for DSI packet reassembly.
svn path=/trunk/; revision=5222
Diffstat (limited to 'packet-dsi.c')
-rw-r--r-- | packet-dsi.c | 478 |
1 files changed, 162 insertions, 316 deletions
diff --git a/packet-dsi.c b/packet-dsi.c index c81288578b..b80e577d30 100644 --- a/packet-dsi.c +++ b/packet-dsi.c @@ -2,7 +2,7 @@ * Routines for dsi packet dissection * Copyright 2001, Randy McEoin <rmceoin@pe.com> * - * $Id: packet-dsi.c,v 1.10 2002/04/14 22:56:02 guy Exp $ + * $Id: packet-dsi.c,v 1.11 2002/04/22 08:50:49 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -39,11 +39,11 @@ # include <netinet/in.h> #endif -#include <string.h> #include <glib.h> #include <epan/packet.h> -#include <epan/strutil.h> -#include <epan/conversation.h> + +#include "prefs.h" +#include "packet-frame.h" /* The information in this module (DSI) comes from: @@ -63,7 +63,7 @@ * |-------------------------------| * |reserved field | * |-------------------------------| -*/ + */ static int proto_dsi = -1; static int hf_dsi_flags = -1; @@ -75,7 +75,9 @@ static int hf_dsi_reserved = -1; static gint ett_dsi = -1; -static dissector_handle_t dsi_handle; +/* desegmentation of DSI */ +static gboolean dsi_desegment = TRUE; + static dissector_handle_t data_handle; #define TCP_PORT_DSI 548 @@ -110,335 +112,172 @@ static const value_string func_vals[] = { {DSIFUNC_ATTN, "Attention" }, {0, NULL } }; - -static GMemChunk *vals = NULL; - -typedef struct { - int state; - guint8 flags,command; - guint16 requestid; - gint32 code; - guint32 length; /* total length of this DSI request/reply */ - guint32 reserved; - guint32 seen; /* bytes seen so far */ -}hash_entry_t; - -enum {NONE,FIRSTDATA,MOREDATA,DONE}; - -#define hash_init_count 20 -#define hash_val_length (sizeof(hash_entry_t)) - -static guint32 last_abs_sec = 0; -static guint32 last_abs_usec= 0; -static guint32 highest_num = 0; - -/* Hash functions */ -gint dsi_equal (gconstpointer v, gconstpointer v2); -guint dsi_hash (gconstpointer v); - -static guint dsi_packet_init_count = 200; - -typedef struct { - guint32 packetnum; -} dsi_request_key; - -typedef struct { - guint8 flags; - guint8 command; - guint16 requestid; - guint32 length; - guint32 seen; /* bytes seen so far, including this packet */ -} dsi_request_val; - -static GHashTable *dsi_request_hash = NULL; -static GMemChunk *dsi_request_keys = NULL; -static GMemChunk *dsi_request_records = NULL; - -/* Hash Functions */ -gint dsi_equal (gconstpointer v, gconstpointer v2) -{ - dsi_request_key *val1 = (dsi_request_key*)v; - dsi_request_key *val2 = (dsi_request_key*)v2; - - if (val1->packetnum == val2->packetnum) { - return 1; - } - return 0; -} - -guint dsi_hash (gconstpointer v) -{ - dsi_request_key *dsi_key = (dsi_request_key*)v; - return GPOINTER_TO_UINT(dsi_key->packetnum); -} - -void -dsi_hash_insert(guint32 packetnum, guint8 flags, guint8 command, - guint16 requestid, guint32 length, guint32 seen) -{ - dsi_request_val *request_val; - dsi_request_key *request_key; - - /* Now remember info about this continuation packet */ - - request_key = g_mem_chunk_alloc(dsi_request_keys); - request_key->packetnum = packetnum; - - request_val = g_mem_chunk_alloc(dsi_request_records); - request_val->flags = flags; - request_val->command = command; - request_val->requestid = requestid; - request_val->length = length; - request_val->seen = seen; - - g_hash_table_insert(dsi_request_hash, request_key, request_val); -} - -/* Returns TRUE or FALSE. If TRUE, the record was found */ - -gboolean -dsi_hash_lookup(guint32 packetnum, guint8 *flags, guint8 *command, - guint16 *requestid, guint32 *length, guint32 *seen) -{ - dsi_request_val *request_val; - dsi_request_key request_key; - - request_key.packetnum = packetnum; - - request_val = (dsi_request_val*) - g_hash_table_lookup(dsi_request_hash, &request_key); - - if (request_val) { - *flags = request_val->flags; - *command = request_val->command; - *requestid = request_val->requestid; - *length = request_val->length; - *seen = request_val->seen; - return TRUE; - } - else { - return FALSE; - } -} - -/* The state_machine remembers information about continuation packets */ -/* returns TRUE if it found a previously known continuation packet */ -gboolean -dsi_state_machine( hash_entry_t *hash_info, tvbuff_t *tvb, packet_info *pinfo, - int offset) -{ - frame_data *fd; - guint32 data_here; - guint8 flags,command; - guint16 requestid; - guint32 length; - guint32 seen; - gboolean found_hash; - - fd=pinfo->fd; - - found_hash=dsi_hash_lookup(fd->num, &flags, &command, &requestid, - &length, &seen); - if (found_hash==TRUE) - { - hash_info->flags = flags; - hash_info->command = command; - hash_info->requestid = requestid; - hash_info->length = length; - hash_info->seen = seen; - return TRUE; - } - - /* is this sequentially the next packet? */ - if (highest_num > fd->num) - { - hash_info->state = NONE; - return FALSE; - } - - highest_num = fd->num; - - if ((hash_info->state == NONE) || (hash_info->state == DONE)) - { - hash_info->state = NONE; - hash_info->length = tvb_get_ntohl(tvb, offset+8); - data_here = tvb_length_remaining(tvb, offset+16); - if (data_here < hash_info->length) - { - hash_info->flags = tvb_get_guint8(tvb, offset); - hash_info->command = tvb_get_guint8(tvb, offset+1); - hash_info->requestid = tvb_get_ntohs(tvb, offset+2); - hash_info->code = tvb_get_ntohl(tvb, offset+4); - hash_info->reserved = tvb_get_ntohl(tvb, offset+12); - hash_info->seen = data_here; - hash_info->state = FIRSTDATA; - } - return FALSE; - } - - - if (hash_info->state == FIRSTDATA) - hash_info->state = MOREDATA; - - /* we must be receiving more data */ - data_here = tvb_length_remaining(tvb, offset); - hash_info->seen += data_here; - if (hash_info->seen >= hash_info->length) - hash_info->state = DONE; - - dsi_hash_insert(fd->num, hash_info->flags, - hash_info->command, hash_info->requestid, - hash_info->length,hash_info->seen); - - return FALSE; -} - static void -dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +dissect_dsi_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *dsi_tree; proto_item *ti; - conversation_t *conversation; - hash_entry_t *hash_info; - gint offset = 0; - gboolean prev_cont; /* TRUE if a previously known - * continuation packet */ - char cont_str[256]; - - gchar *flag_str; - gchar *func_str; - guint8 dsi_flags,dsi_command; - guint16 dsi_requestid; - gint32 dsi_code; - guint32 dsi_length; - guint32 dsi_reserved; + guint8 dsi_flags,dsi_command; + guint16 dsi_requestid; + gint32 dsi_code; + guint32 dsi_length; + guint32 dsi_reserved; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSI"); if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO); - conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_TCP, - pinfo->srcport, pinfo->destport, 0); - if (conversation == NULL) - { - conversation = conversation_new(&pinfo->src, &pinfo->dst, - pinfo->ptype, pinfo->srcport, pinfo->destport, 0); - } - conversation_set_dissector(conversation, dsi_handle); - hash_info = conversation_get_proto_data(conversation, proto_dsi); - if (hash_info == NULL) - { - hash_info = g_mem_chunk_alloc(vals); - hash_info->state = NONE; - conversation_add_proto_data(conversation, proto_dsi, - hash_info); + dsi_flags = tvb_get_guint8(tvb, 0); + dsi_command = tvb_get_guint8(tvb, 1); + dsi_requestid = tvb_get_ntohs(tvb, 2); + dsi_code = tvb_get_ntohl(tvb, 4); + dsi_length = tvb_get_ntohl(tvb, 8); + dsi_reserved = tvb_get_ntohl(tvb, 12); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%u)", + val_to_str(dsi_flags, flag_vals, + "Unknown flag (0x%02x)"), + val_to_str(dsi_command, func_vals, + "Unknown function (0x%02x)"), + dsi_requestid); } - prev_cont=dsi_state_machine( hash_info, tvb, pinfo, offset); - - if ((hash_info->state == NONE) && (prev_cont!=TRUE)) - { - dsi_flags = tvb_get_guint8(tvb, offset); - dsi_command = tvb_get_guint8(tvb, offset+1); - dsi_requestid = tvb_get_ntohs(tvb, offset+2); - dsi_code = tvb_get_ntohl(tvb, offset+4); - dsi_length = tvb_get_ntohl(tvb, offset+8); - dsi_reserved = tvb_get_ntohl(tvb, offset+12); - }else - { - dsi_flags = hash_info->flags; - dsi_command = hash_info->command; - dsi_requestid = hash_info->requestid; - dsi_code = hash_info->code; - dsi_length = hash_info->length; - dsi_reserved = hash_info->reserved; + + if (tree) { + ti = proto_tree_add_item(tree, proto_dsi, tvb, 0, -1, FALSE); + dsi_tree = proto_item_add_subtree(ti, ett_dsi); + + proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb, + 0, 1, dsi_flags); + proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb, + 1, 1, dsi_command); + proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb, + 2, 2, dsi_requestid); + proto_tree_add_int(dsi_tree, hf_dsi_code, tvb, + 4, 4, dsi_code); + proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb, + 8, 4, dsi_length, + "Length: %u bytes", dsi_length); + proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb, + 12, 4, dsi_reserved); + call_dissector(data_handle,tvb_new_subset(tvb, 16,-1,tvb_reported_length_remaining(tvb,16)), pinfo, dsi_tree); } +} - if (check_col(pinfo->cinfo, COL_INFO)) { - if ((func_str = match_strval(dsi_command, func_vals))) - { - flag_str = match_strval(dsi_flags, flag_vals); - if ((hash_info->state == MOREDATA) || - (hash_info->state == DONE) || - (prev_cont == TRUE)) - { - sprintf(cont_str,"Continued: %d/%d", - hash_info->seen,hash_info->length); - }else - { - cont_str[0]=0; +static void +dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + volatile int offset = 0; + int length_remaining; + guint32 plen; + int length; + tvbuff_t *next_tvb; + + while (tvb_reported_length_remaining(tvb, offset) != 0) { + length_remaining = tvb_length_remaining(tvb, offset); + + /* + * Can we do reassembly? + */ + if (dsi_desegment && pinfo->can_desegment) { + /* + * Yes - is the DSI header split across segment + * boundaries? + */ + if (length_remaining < 12) { + /* + * Yes. Tell the TCP dissector where + * the data for this message starts in + * the data it handed us, and how many + * more bytes we need, and return. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = 12 - length_remaining; + return; } - col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%d) %s", - flag_str,func_str,dsi_requestid, - cont_str); } - } + /* + * Get the length of the DSI packet. + */ + plen = tvb_get_ntohl(tvb, offset+8); + + /* + * Can we do reassembly? + */ + if (dsi_desegment && pinfo->can_desegment) { + /* + * Yes - is the DSI packet split across segment + * boundaries? + */ + if ((guint32)length_remaining < plen + 16) { + /* + * Yes. Tell the TCP dissector where + * the data for this message starts in + * the data it handed us, and how many + * more bytes we need, and return. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = + (plen + 16) - length_remaining; + return; + } + } - if (tree) - { - ti = proto_tree_add_item(tree, proto_dsi, tvb, offset, -1, - FALSE); - dsi_tree = proto_item_add_subtree(ti, ett_dsi); - - if (prev_cont == TRUE) - { - proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb, - 0, 0, dsi_requestid); - call_dissector(data_handle,tvb, pinfo, dsi_tree); - }else - { - proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb, - offset, 1, dsi_flags); - proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb, - offset+1, 1, dsi_command); - proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb, - offset+2, 2, dsi_requestid); - proto_tree_add_int(dsi_tree, hf_dsi_code, tvb, - offset+4, 4, dsi_code); - proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb, - offset+8, 4, dsi_length, - "Length: %d bytes", dsi_length); - proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb, - offset+12, 4, dsi_reserved); - call_dissector(data_handle,tvb_new_subset(tvb, 16,-1,tvb_reported_length_remaining(tvb,16)), pinfo, dsi_tree); + /* + * Construct a tvbuff containing the amount of the payload + * we have available. Make its reported length the + * amount of data in the DSI packet. + * + * XXX - if reassembly isn't enabled. the subdissector + * will throw a BoundsError exception, rather than a + * ReportedBoundsError exception. We really want + * a tvbuff where the length is "length", the reported + * length is "plen + 16", and the "if the snapshot length + * were infinite" length is the minimum of the + * reported length of the tvbuff handed to us and "plen+16", + * with a new type of exception thrown if the offset is + * within the reported length but beyond that third length, + * with that exception getting the "Unreassembled Packet" + * error. + */ + length = length_remaining; + if ((guint32)length > plen + 16) + length = plen + 16; + next_tvb = tvb_new_subset(tvb, offset, length, plen + 16); + + /* + * Dissect the DSI packet. + * + * Catch the ReportedBoundsError exception; if this + * particular message happens to get a ReportedBoundsError + * exception, that doesn't mean that we should stop + * dissecting DSI messages within this frame or chunk + * of reassembled data. + * + * If it gets a BoundsError, we can stop, as there's nothing + * more to see, so we just re-throw it. + */ + TRY { + dissect_dsi_packet(next_tvb, pinfo, tree); + } + CATCH(BoundsError) { + RETHROW; } + CATCH(ReportedBoundsError) { + show_reported_bounds_error(tvb, pinfo, tree); + } + ENDTRY; + /* + * Skip the DSI header and the payload. + */ + offset += plen + 16; } } -static void dsi_reinit( void){ - - last_abs_sec = 0; - last_abs_usec= 0; - highest_num = 0; - - if (vals) - g_mem_chunk_destroy(vals); - if (dsi_request_hash) - g_hash_table_destroy(dsi_request_hash); - if (dsi_request_keys) - g_mem_chunk_destroy(dsi_request_keys); - if (dsi_request_records) - g_mem_chunk_destroy(dsi_request_records); - - dsi_request_hash = g_hash_table_new(dsi_hash, dsi_equal); - - dsi_request_keys = g_mem_chunk_new("dsi_request_keys", - sizeof(dsi_request_key), - dsi_packet_init_count * sizeof(dsi_request_key), - G_ALLOC_AND_FREE); - dsi_request_records = g_mem_chunk_new("dsi_request_records", - sizeof(dsi_request_val), - dsi_packet_init_count * sizeof(dsi_request_val), - G_ALLOC_AND_FREE); - - vals = g_mem_chunk_new("dsi_vals", hash_val_length, - hash_init_count * hash_val_length, - G_ALLOC_AND_FREE); -} - void proto_register_dsi(void) { @@ -478,19 +317,26 @@ proto_register_dsi(void) static gint *ett[] = { &ett_dsi, }; + module_t *dsi_module; proto_dsi = proto_register_protocol("Data Stream Interface", "DSI", "dsi"); proto_register_field_array(proto_dsi, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); - register_init_routine( &dsi_reinit); - - dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi); + dsi_module = prefs_register_protocol(proto_dsi, NULL); + prefs_register_bool_preference(dsi_module, "desegment", + "Desegment all DSI messages spanning multiple TCP segments", + "Whether the DSI dissector should desegment all messages spanning multiple TCP segments", + &dsi_desegment); } void proto_reg_handoff_dsi(void) { - data_handle = find_dissector("data"); + static dissector_handle_t dsi_handle; + + dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi); dissector_add("tcp.port", TCP_PORT_DSI, dsi_handle); + + data_handle = find_dissector("data"); } |