Add support for SCTP reassembly from Robin Seggelmann.

You must enable this feature via Edit/Preferences/Protocols/SCTP

svn path=/trunk/; revision=20756
This commit is contained in:
Michael Tüxen 2007-02-09 16:38:57 +00:00
parent 2532bc2a1a
commit f20299ba4b
3 changed files with 682 additions and 9 deletions

View File

@ -2580,6 +2580,10 @@ Abhik Sarkar <sarkar.abhik [AT] gmail.com> {
(as generated by the Cisco ITP packet logging facility)
}
Robin Seggelmann <seggelmann [AT] fh-muenster.de> {
Support for SCTP reassembly.
}
and by:
Pavel Roskin <proski [AT] gnu.org>

View File

@ -15,13 +15,16 @@
*
* Copyright 2000-2005 Michael Tuexen <tuexen [AT] fh-muenster.de>
* Still to do (so stay tuned)
* - support for reassembly
* - error checking mode
* * padding errors
* * length errors
* * bundling errors
* * value errors
*
*
* Reassembly added 2006 by Robin Seggelmann
*
*
* $Id$
*
* Wireshark - Network traffic analyzer
@ -55,6 +58,9 @@
#include <epan/addr_resolv.h>
#include "packet-sctp.h"
#include <epan/sctpppids.h>
#include <epan/emem.h>
#define LT(x, y) ((gint32)((x) - (y)) < 0)
#define NETWORK_BYTE_ORDER FALSE
#define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
@ -179,6 +185,11 @@ static int hf_pktdrop_chunk_truncated_length = -1;
static int hf_pktdrop_chunk_reserved = -1;
static int hf_pktdrop_chunk_data_field = -1;
static int hf_sctp_reassembled_in = -1;
static int hf_sctp_duplicate = -1;
static int hf_sctp_fragments = -1;
static int hf_sctp_fragment = -1;
static dissector_table_t sctp_port_dissector_table;
static dissector_table_t sctp_ppi_dissector_table;
static heur_dissector_list_t sctp_heur_subdissector_list;
@ -200,6 +211,9 @@ static gint ett_sctp_parameter_type= -1;
static gint ett_sctp_sack_chunk_gap_block = -1;
static gint ett_sctp_unrecognized_parameter_parameter = -1;
static gint ett_sctp_fragments = -1;
static gint ett_sctp_fragment = -1;
static dissector_handle_t data_handle;
#define SCTP_DATA_CHUNK_ID 0
@ -317,6 +331,8 @@ static gboolean show_chunk_types = TRUE;
static gboolean show_always_control_chunks = TRUE;
static gint sctp_checksum = SCTP_CHECKSUM_CRC32C;
static gboolean use_reassembly = FALSE;
static struct _sctp_info sctp_info;
/* adler32.c -- compute the Adler-32 checksum of a data stream
@ -1568,6 +1584,595 @@ dissect_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree, gui
#define SCTP_DATA_CHUNK_B_BIT 0x02
#define SCTP_DATA_CHUNK_U_BIT 0x04
/* table to hold fragmented SCTP messages */
static GHashTable *frag_table = NULL;
typedef struct _frag_key {
guint16 sport;
guint16 dport;
guint32 verification_tag;
guint16 stream_id;
guint16 stream_seq_num;
} frag_key;
static gint
frag_equal(gconstpointer k1, gconstpointer k2)
{
const frag_key* key1 = (const frag_key*) k1;
const frag_key* key2 = (const frag_key*) k2;
return ( (key1->sport == key2->sport) &&
(key1->dport == key1->dport) &&
(key1->verification_tag == key1->verification_tag) &&
(key1->stream_id == key1->stream_id) &&
(key1->stream_seq_num == key1->stream_seq_num)
? TRUE : FALSE);
}
static guint
frag_hash(gconstpointer k)
{
const frag_key* key = (const frag_key*) k;
return key->sport ^ key->dport ^ key->verification_tag ^
key->stream_id ^ key->stream_seq_num;
}
static void
frag_free_msgs(sctp_frag_msg *msg)
{
sctp_frag_be *beginend;
sctp_fragment *fragment;
/* free all begins */
while (msg->begins) {
beginend = msg->begins;
msg->begins = msg->begins->next;
g_free(beginend);
}
/* free all ends */
while (msg->ends) {
beginend = msg->ends;
msg->ends = msg->ends->next;
g_free(beginend);
}
/* free all fragments */
while (msg->fragments) {
fragment = msg->fragments;
msg->fragments = msg->fragments->next;
g_free(fragment->data);
g_free(fragment);
}
g_free(msg);
}
static void
frag_table_init(void)
{
/* destroy an existing hast table and create a new one */
if (frag_table) {
g_hash_table_destroy(frag_table);
}
frag_table = g_hash_table_new_full(frag_hash, frag_equal, (GDestroyNotify) g_free,
(GDestroyNotify) frag_free_msgs);
}
static sctp_frag_msg*
find_message(guint16 stream_id, guint16 stream_seq_num)
{
frag_key key;
key.sport = sctp_info.sport;
key.dport = sctp_info.dport;
key.verification_tag = sctp_info.verification_tag;
key.stream_id = stream_id;
key.stream_seq_num = stream_seq_num;
return g_hash_table_lookup(frag_table, &key);
}
static sctp_fragment*
find_fragment(guint32 tsn, guint16 stream_id, guint16 stream_seq_num)
{
sctp_frag_msg *msg;
sctp_fragment *next_fragment;
msg = find_message(stream_id, stream_seq_num);
if (msg) {
next_fragment = msg->fragments;
while (next_fragment) {
if (next_fragment->tsn == tsn) return next_fragment;
next_fragment = next_fragment->next;
}
}
return NULL;
}
static sctp_fragment*
add_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 tsn,
guint16 stream_id, guint16 stream_seq_num, guint8 b_bit, guint8 e_bit)
{
sctp_frag_msg *msg;
sctp_fragment *fragment, *last_fragment;
sctp_frag_be *beginend, *last_beginend;
frag_key *key;
/* lookup message. if not found, create it */
msg = find_message(stream_id, stream_seq_num);
if (!msg) {
msg = g_malloc (sizeof (sctp_frag_msg));
msg->begins = NULL;
msg->ends = NULL;
msg->fragments = NULL;
msg->messages = NULL;
msg->next = NULL;
key = g_malloc(sizeof (frag_key));
key->sport = sctp_info.sport;
key->dport = sctp_info.dport;
key->verification_tag = sctp_info.verification_tag;
key->stream_id = stream_id;
key->stream_seq_num = stream_seq_num;
g_hash_table_insert(frag_table, key, msg);
}
/* lookup segment. if not found, create it */
fragment = find_fragment(tsn, stream_id, stream_seq_num);
if (fragment) {
/* this fragment is already known.
* compare frame number to check if it's a duplicate
*/
if (fragment->frame_num == pinfo->fd->num) {
return fragment;
} else {
/* there already is a fragment having the same ports, v_tag,
* stream id, stream_seq_num and tsn but it appeared in a different
* frame, so it must be a duplicate fragment. maybe a retransmission?
* Mark it as duplicate and return NULL
*/
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, " (Duplicate Message Fragment)");
proto_tree_add_uint(tree, hf_sctp_duplicate, tvb, 0, 0, fragment->frame_num);
return NULL;
}
}
/* create new fragment */
fragment = g_malloc (sizeof (sctp_fragment));
fragment->frame_num = pinfo->fd->num;
fragment->tsn = tsn;
fragment->len = tvb_length(tvb);
fragment->next = NULL;
if (fragment->len) {
fragment->data = g_malloc (fragment->len);
tvb_memcpy(tvb, fragment->data, 0, fragment->len);
}
/* add new fragment to linked list. sort ascending by tsn */
if (!msg->fragments) msg->fragments = fragment;
else {
if (msg->fragments->tsn > fragment->tsn) {
fragment->next = msg->fragments;
msg->fragments = fragment;
} else {
last_fragment = msg->fragments;
while (last_fragment->next &&
last_fragment->next->tsn < fragment->tsn)
last_fragment = last_fragment->next;
fragment->next = last_fragment->next;
last_fragment->next = fragment;
}
}
/* save begin or end if neccessary */
if (b_bit && !e_bit) {
beginend = g_malloc (sizeof (sctp_frag_be));
beginend->fragment = fragment;
beginend->next = NULL;
/* add begin to linked list. sort descending by tsn */
if (!msg->begins) msg->begins = beginend;
else {
if (msg->begins->fragment->tsn < beginend->fragment->tsn) {
beginend->next = msg->begins;
msg->begins = beginend;
} else {
last_beginend = msg->begins;
while (last_beginend->next &&
last_beginend->next->fragment->tsn > beginend->fragment->tsn)
last_beginend = last_beginend->next;
beginend->next = last_beginend->next;
last_beginend->next = beginend;
}
}
}
if (!b_bit && e_bit) {
beginend = g_malloc (sizeof (sctp_frag_be));
beginend->fragment = fragment;
beginend->next = NULL;
/* add end to linked list. sort ascending by tsn */
if (!msg->ends) msg->ends = beginend;
else {
if (msg->begins->fragment->tsn > beginend->fragment->tsn) {
beginend->next = msg->ends;
msg->ends = beginend;
} else {
last_beginend = msg->ends;
while (last_beginend->next &&
last_beginend->next->fragment->tsn < beginend->fragment->tsn)
last_beginend = last_beginend->next;
beginend->next = last_beginend->next;
last_beginend->next = beginend;
}
}
}
return fragment;
}
static tvbuff_t*
fragment_reassembly(tvbuff_t *tvb, sctp_fragment* fragment,
packet_info *pinfo, proto_tree *tree, guint16 stream_id,
guint16 stream_seq_num)
{
sctp_frag_msg *msg;
sctp_complete_msg *message, *last_message;
sctp_fragment *frag_i, *last_frag, *first_frag;
sctp_frag_be *begin, *end, *beginend;
guint32 len, offset = 0;
tvbuff_t* new_tvb = NULL;
proto_item *item;
proto_tree *ptree;
msg = find_message(stream_id, stream_seq_num);
if (!msg) {
/* no message, we can't do anything */
return NULL;
}
/* check if fragment is part of an already reassembled message */
for (message = msg->messages;
message &&
!(message->begin <= fragment->tsn && message->end >= fragment->tsn) &&
!(message->begin > message->end &&
(message->begin <= fragment->tsn || message->end >= fragment->tsn));
message = message->next);
if (message) {
/* we found the reassembled message this fragment belongs to */
if (fragment == message->reassembled_in) {
/* this is the last fragment, create data source */
new_tvb = tvb_new_real_data(message->data, message->len, message->len);
tvb_set_child_real_data_tvbuff(tvb, new_tvb);
add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message");
/* display reassembly info */
item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, FALSE);
ptree = proto_item_add_subtree(item, ett_sctp_fragments);
proto_item_append_text(item, " (%u bytes, %u fragments): ",
message->len, message->end - message->begin + 1);
if (message->begin > message->end) {
for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
frag_i;
frag_i = frag_i->next) {
proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
offset += frag_i->len;
}
for (frag_i = msg->fragments;
frag_i && frag_i->tsn <= message->end;
frag_i = frag_i->next) {
proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
offset += frag_i->len;
}
} else {
for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
frag_i && frag_i->tsn <= message->end;
frag_i = frag_i->next) {
proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
offset += frag_i->len;
}
}
return new_tvb;
}
/* this is not the last fragment,
* so let the user know the frame where the reassembly is
*/
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, " (Message Fragment) ");
proto_tree_add_uint(tree, hf_sctp_reassembled_in, tvb, 0, 0, message->reassembled_in->frame_num);
return NULL;
}
/* this fragment has not been reassembled, yet
* check now if we can reassemble it
* at first look for the first and last tsn of the msg
*/
for (begin = msg->begins;
begin && begin->fragment->tsn > fragment->tsn;
begin = begin->next);
/* in case begin still is null, set it to first (highest) begin
* maybe the message tsn restart at 0 in between
*/
if (!begin) begin = msg->begins;
for (end = msg->ends;
end && end->fragment->tsn < fragment->tsn;
end = end->next);
/* in case end still is null, set it to first (lowest) end
* maybe the message tsn restart at 0 in between
*/
if (!end) end = msg->ends;
if (!begin || !end || !msg->fragments ||
(begin->fragment->tsn > end->fragment->tsn && msg->fragments->tsn)) {
/* begin and end have not been collected, yet
* or there might be a tsn restart but the first fragment hasn't a tsn of 0
* just mark as fragment
*/
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, " (Message Fragment) ");
return NULL;
}
/* we found possible begin and end
* look for the first fragment and then try to get to the end
*/
first_frag = begin->fragment;
/* while looking if all fragments are there
* we can calculate the overall length that
* we need in case of success
*/
len = first_frag->len;
/* check if begin is past end
* this can happen if there has been a tsn restart
* or we just got the wrong begin and end
* so give it a try
*/
if (begin->fragment->tsn > end->fragment->tsn) {
for (last_frag = first_frag, frag_i = first_frag->next;
frag_i && frag_i->tsn == (last_frag->tsn + 1);
last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
/* check if we reached the last possible tsn
* if yes, restart and continue
*/
if ((last_frag->tsn + 1)) {
/* there are just fragments missing */
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, " (Message Fragment) ");
return NULL;
}
/* we got all fragments until the last possible tsn
* and the first is 0 if we got here
*/
len += msg->fragments->len;
for (last_frag = msg->fragments, frag_i = last_frag->next;
frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1);
last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
} else {
for (last_frag = first_frag, frag_i = first_frag->next;
frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1);
last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
}
if (!frag_i || frag_i != end->fragment || frag_i->tsn != (last_frag->tsn + 1)) {
/* we need more fragments. just mark as fragment */
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, " (Message Fragment) ");
return NULL;
}
/* ok, this message is complete, we can reassemble it
* but at first don't forget to add the length of the last fragment
*/
len += frag_i->len;
message = se_alloc (sizeof (sctp_complete_msg));
message->begin = begin->fragment->tsn;
message->end = end->fragment->tsn;
message->reassembled_in = fragment;
message->len = len;
message->data = se_alloc(len);
/* now copy all fragments */
if (begin->fragment->tsn > end->fragment->tsn) {
/* a tsn restart has occured */
for (frag_i = first_frag;
frag_i;
frag_i = frag_i->next) {
if (frag_i->len && frag_i->data) memcpy(message->data + offset, frag_i->data, frag_i->len);
offset += frag_i->len;
/* release fragment data */
g_free(frag_i->data);
frag_i->data = NULL;
}
for (frag_i = msg->fragments;
frag_i && frag_i->tsn <= end->fragment->tsn;
frag_i = frag_i->next) {
if (frag_i->len && frag_i->data) memcpy(message->data + offset, frag_i->data, frag_i->len);
offset += frag_i->len;
/* release fragment data */
g_free(frag_i->data);
frag_i->data = NULL;
}
} else {
for (frag_i = first_frag;
frag_i && frag_i->tsn <= end->fragment->tsn;
frag_i = frag_i->next) {
if (frag_i->len && frag_i->data) memcpy(message->data + offset, frag_i->data, frag_i->len);
offset += frag_i->len;
/* release fragment data */
g_free(frag_i->data);
frag_i->data = NULL;
}
}
/* save message */
if (!msg->messages) {
msg->messages = message;
} else {
for (last_message = msg->messages;
last_message->next;
last_message = last_message->next);
last_message->next = message;
}
/* remove begin and end from list */
if (msg->begins == begin) {
msg->begins = begin->next;
} else {
for (beginend = msg->begins;
beginend && beginend->next != begin;
beginend = beginend->next);
if (beginend->next == begin) beginend->next = begin->next;
}
g_free(begin);
if (msg->ends == end) {
msg->ends = end->next;
} else {
for (beginend = msg->ends;
beginend && beginend->next != end;
beginend = beginend->next);
if (beginend->next == end) beginend->next = end->next;
}
g_free(end);
/* create data source */
new_tvb = tvb_new_real_data(message->data, len, len);
tvb_set_child_real_data_tvbuff(tvb, new_tvb);
add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message");
/* display reassembly info */
item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, FALSE);
ptree = proto_item_add_subtree(item, ett_sctp_fragments);
proto_item_append_text(item, " (%u bytes, %u fragments): ",
message->len, message->end - message->begin + 1);
if (message->begin > message->end) {
for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
frag_i;
frag_i = frag_i->next) {
proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
offset += frag_i->len;
}
for (frag_i = msg->fragments;
frag_i && frag_i->tsn <= message->end;
frag_i = frag_i->next) {
proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
offset += frag_i->len;
}
} else {
for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
frag_i && frag_i->tsn <= message->end;
frag_i = frag_i->next) {
proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
offset += frag_i->len;
}
}
/* it's not fragmented anymore */
pinfo->fragmented = FALSE;
return new_tvb;
}
static gboolean
dissect_fragmented_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree,
proto_tree *chunk_tree, guint32 tsn, guint32 ppi, guint16 stream_id,
guint16 stream_seq_num, guint8 b_bit, guint8 e_bit)
{
sctp_fragment* fragment;
tvbuff_t* new_tvb = NULL;
/* add fragement to list of known fragments. returns NULL if segment is a duplicate */
fragment = add_fragment(payload_tvb, pinfo, chunk_tree, tsn, stream_id, stream_seq_num, b_bit, e_bit);
if (fragment) new_tvb = fragment_reassembly(payload_tvb, fragment, pinfo, chunk_tree, stream_id, stream_seq_num);
/* pass reassembled data to next dissector, if possible */
if (new_tvb) return dissect_payload(new_tvb, pinfo, tree, ppi);
/* no reasemmbly done, do nothing */
return TRUE;
}
static const true_false_string sctp_data_chunk_e_bit_value = {
"Last segment",
"Not the last segment"
@ -1591,6 +2196,8 @@ dissect_data_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo
tvbuff_t *payload_tvb;
proto_tree *flags_tree;
guint8 e_bit, b_bit, u_bit;
guint16 stream_id, stream_seq_num = 0;
guint32 tsn;
if (chunk_length <= DATA_CHUNK_HEADER_LENGTH) {
proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
@ -1608,6 +2215,13 @@ dissect_data_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo
pinfo->ppid[number_of_ppid] = payload_proto_id;
}
e_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_E_BIT;
b_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_B_BIT;
u_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_U_BIT;
stream_id = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
stream_seq_num = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
tsn = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
if (chunk_tree) {
proto_item_set_len(chunk_item, DATA_CHUNK_HEADER_LENGTH);
flags_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
@ -1619,10 +2233,6 @@ dissect_data_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo
proto_tree_add_item(chunk_tree, hf_data_chunk_stream_seq_number, chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET, DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH, NETWORK_BYTE_ORDER);
proto_tree_add_item(chunk_tree, hf_data_chunk_payload_proto_id, chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH, NETWORK_BYTE_ORDER);
e_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_E_BIT;
b_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_B_BIT;
u_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_U_BIT;
proto_item_append_text(chunk_item, "(%s, ", (u_bit) ? "unordered" : "ordered");
if (b_bit) {
if (e_bit)
@ -1644,8 +2254,25 @@ dissect_data_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo
chunk_length - DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - DATA_CHUNK_HEADER_LENGTH, "", "s"));
}
payload_tvb = tvb_new_subset(chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET, chunk_length - DATA_CHUNK_HEADER_LENGTH, chunk_length - DATA_CHUNK_HEADER_LENGTH);
return dissect_payload(payload_tvb, pinfo, tree, payload_proto_id);
payload_tvb = tvb_new_subset(chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET, chunk_length - DATA_CHUNK_HEADER_LENGTH, chunk_length - DATA_CHUNK_HEADER_LENGTH);
/* Is this a fragment? */
if (b_bit && e_bit) {
/* No - just call the subdissector. */
return dissect_payload(payload_tvb, pinfo, tree, payload_proto_id);
} else {
/* Yes. */
pinfo->fragmented = TRUE;
/* if reassembly off just mark as fragment for next dissector and proceed */
if (!use_reassembly) return dissect_payload(payload_tvb, pinfo, tree, payload_proto_id);
/* if unordered set stream_seq_num to 0 for easier handling */
if (u_bit) stream_seq_num = 0;
/* start reassembly */
return dissect_fragmented_payload(payload_tvb, pinfo, tree, chunk_tree, tsn, payload_proto_id, stream_id, stream_seq_num, b_bit, e_bit);
}
}
#define INIT_CHUNK_INITIATE_TAG_LENGTH 4
@ -2479,7 +3106,6 @@ dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
memset(&sctp_info, 0, sizeof(struct _sctp_info));
sctp_info.verification_tag = tvb_get_ntohl(tvb, VERIFICATION_TAG_OFFSET);
/* FIXME: Do we need to put this into _sctp_info? */
sctp_info.sport = pinfo->srcport;
sctp_info.dport = pinfo->destport;
SET_ADDRESS(&sctp_info.ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
@ -2594,6 +3220,11 @@ proto_register_sctp(void)
{ &hf_pktdrop_chunk_truncated_length, { "Truncated length", "sctp.pktdrop_truncated_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL } },
{ &hf_pktdrop_chunk_reserved, { "Reserved", "sctp.pktdrop_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL } },
{ &hf_pktdrop_chunk_data_field, { "Data field", "sctp.pktdrop_datafield", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL } },
{ &hf_sctp_fragment, { "SCTP Fragment", "sctp.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,NULL, HFILL }},
{ &hf_sctp_fragments, { "Reassembled SCTP Fragments", "sctp.fragments", FT_NONE, BASE_NONE, NULL, 0x0,NULL, HFILL }},
{ &hf_sctp_reassembled_in, { "Reassembled Message in frame", "sctp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_sctp_duplicate, { "Fragment already seen in frame", "sctp.duplicate", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL }},
};
/* Setup protocol subtree array */
@ -2611,6 +3242,8 @@ proto_register_sctp(void)
&ett_sctp_parameter_type,
&ett_sctp_sack_chunk_gap_block,
&ett_sctp_unrecognized_parameter_parameter,
&ett_sctp_fragments,
&ett_sctp_fragment
};
static enum_val_t sctp_checksum_options[] = {
@ -2645,6 +3278,10 @@ proto_register_sctp(void)
"Try heuristic sub-dissectors first",
"Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port or PPI",
&try_heuristic_first);
prefs_register_bool_preference(sctp_module, "reassembly",
"Reassemble fragmented SCTP user messages",
"Whether fragmented SCTP user messages should be reassembled",
&use_reassembly);
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_sctp, hf, array_length(hf));
@ -2654,6 +3291,8 @@ proto_register_sctp(void)
sctp_port_dissector_table = register_dissector_table("sctp.port", "SCTP port", FT_UINT16, BASE_DEC);
sctp_ppi_dissector_table = register_dissector_table("sctp.ppi", "SCTP payload protocol identifier", FT_UINT32, BASE_HEX);
register_heur_dissector_list("sctp", &sctp_heur_subdissector_list);
register_init_routine(frag_table_init);
}
void

View File

@ -37,7 +37,6 @@ struct _sctp_info {
gboolean crc32c_correct;
gboolean checksum_zero;
gboolean vtag_reflected;
/* FIXME: do we need the ports and addresses to be here? */
guint16 sport;
guint16 dport;
address ip_src;
@ -47,4 +46,35 @@ struct _sctp_info {
tvbuff_t *tvb[MAXIMUM_NUMBER_OF_TVBS];
};
typedef struct _sctp_fragment {
guint32 frame_num;
guint32 tsn;
guint32 len;
unsigned char *data;
struct _sctp_fragment *next;
} sctp_fragment;
typedef struct _sctp_frag_be {
sctp_fragment* fragment;
struct _sctp_frag_be *next;
} sctp_frag_be;
typedef struct _sctp_complete_msg {
guint32 begin;
guint32 end;
sctp_fragment* reassembled_in;
guint32 len;
unsigned char *data;
struct _sctp_complete_msg *next;
} sctp_complete_msg;
typedef struct _sctp_frag_msg {
sctp_frag_be* begins;
sctp_frag_be* ends;
sctp_fragment* fragments;
sctp_complete_msg* messages;
struct _sctp_frag_msg* next;
} sctp_frag_msg;
#endif