aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>2001-06-08 06:27:16 +0000
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>2001-06-08 06:27:16 +0000
commitb26ff6207728b7b02cd8b29fc5310b983fe9b53e (patch)
tree7c0357f6cc77b6e5400dce6519619e41c1a8388d
parentafebf3bcc2db298607a5d728559b5a8c7c9a927d (diff)
Move the fragment reassembly code into "reassemble.c" and
"reassemble.h", and remove IPv4 dependencies from it. Use it for OSI CLNP segment reassembly as well. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@3525 f5534014-38df-0310-8fa8-9805f1628bb7
-rw-r--r--Makefile.am5
-rw-r--r--Makefile.nmake3
-rw-r--r--file.c15
-rw-r--r--packet-clnp.c224
-rw-r--r--packet-ip.c345
-rw-r--r--reassemble.c371
-rw-r--r--reassemble.h77
-rw-r--r--tethereal.c15
8 files changed, 718 insertions, 337 deletions
diff --git a/Makefile.am b/Makefile.am
index e82836bc7d..4389706492 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,12 +1,11 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.332 2001/06/06 01:30:28 guy Exp $
+# $Id: Makefile.am,v 1.333 2001/06/08 06:27:15 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
# Copyright 1998 Gerald Combs
-#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -373,6 +372,8 @@ ETHEREAL_COMMON_SRC = \
ps.h \
ptvcursor.c \
ptvcursor.h \
+ reassemble.c \
+ reassemble.h \
register.c \
register.h \
smb.h \
diff --git a/Makefile.nmake b/Makefile.nmake
index 889eca633e..3cc8355879 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.114 2001/06/06 01:30:28 guy Exp $
+# $Id: Makefile.nmake,v 1.115 2001/06/08 06:27:15 guy Exp $
include config.nmake
include <win32.mak>
@@ -220,6 +220,7 @@ ETHEREAL_COMMON_OBJECTS = \
print.obj \
ps.obj \
ptvcursor.obj \
+ reassemble.obj \
register.obj \
util.obj \
xdlc.obj \
diff --git a/file.c b/file.c
index 83397b236f..6b83244346 100644
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.238 2001/06/05 07:38:33 guy Exp $
+ * $Id: file.c,v 1.239 2001/06/08 06:27:15 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -88,6 +88,7 @@
#include "gtk/packet_win.h"
#include "dfilter/dfilter.h"
#include "conversation.h"
+#include "reassemble.h"
#include "globals.h"
#include "gtk/colors.h"
@@ -149,6 +150,12 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
/* Initialize protocol-specific variables */
init_all_protocols();
+ /* Initialize the common data structures for fragment reassembly.
+ Must be done *after* "init_all_protocols()", as "init_all_protocols()"
+ may free up space for fragments, which it finds by using the
+ data structures that "reassemble_init()" frees. */
+ reassemble_init();
+
/* We're about to start reading the file. */
cf->state = FILE_READ_IN_PROGRESS;
@@ -912,6 +919,12 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
/* Initialize protocol-specific variables */
init_all_protocols();
+
+ /* Initialize the common data structures for fragment reassembly.
+ Must be done *after* "init_all_protocols()", as "init_all_protocols()"
+ may free up space for fragments, which it finds by using the
+ data structures that "reassemble_init()" frees. */
+ reassemble_init();
}
/* Freeze the packet list while we redo it, so we don't get any
diff --git a/packet-clnp.c b/packet-clnp.c
index 78ec69e43d..9d0ba98a99 100644
--- a/packet-clnp.c
+++ b/packet-clnp.c
@@ -1,7 +1,7 @@
/* packet-clnp.c
* Routines for ISO/OSI network and transport protocol packet disassembly
*
- * $Id: packet-clnp.c,v 1.29 2001/06/05 09:06:19 guy Exp $
+ * $Id: packet-clnp.c,v 1.30 2001/06/08 06:27:15 guy Exp $
* Laurent Deniel <deniel@worldnet.fr>
* Ralf Schneider <Ralf.Schneider@t-online.de>
*
@@ -39,6 +39,7 @@
#include <glib.h>
#include "prefs.h"
#include "packet.h"
+#include "reassemble.h"
#include "packet-osi.h"
#include "packet-osi-options.h"
#include "packet-isis.h"
@@ -50,6 +51,8 @@
static int proto_clnp = -1;
static gint ett_clnp = -1;
static gint ett_clnp_type = -1;
+static gint ett_clnp_segments = -1;
+static gint ett_clnp_segment = -1;
static gint ett_clnp_disc_pdu = -1;
static int proto_cotp = -1;
static gint ett_cotp = -1;
@@ -67,6 +70,13 @@ static int hf_clnp_dest_length = -1;
static int hf_clnp_dest = -1;
static int hf_clnp_src_length = -1;
static int hf_clnp_src = -1;
+static int hf_clnp_segments = -1;
+static int hf_clnp_segment = -1;
+static int hf_clnp_segment_overlap = -1;
+static int hf_clnp_segment_overlap_conflict = -1;
+static int hf_clnp_segment_multiple_tails = -1;
+static int hf_clnp_segment_too_long_segment = -1;
+static int hf_clnp_segment_error = -1;
/*
* ISO 8473 OSI CLNP definition (see RFC994)
@@ -259,9 +269,15 @@ static u_short dst_ref;
Subset of CLNP. */
static heur_dissector_list_t cotp_is_heur_subdissector_list;
+/*
+ * Reassembly of CLNP.
+ */
+static GHashTable *clnp_segment_table = NULL;
+
/* options */
static guint tp_nsap_selector = NSEL_TP;
static gboolean always_decode_transport = FALSE;
+static gboolean clnp_reassemble = FALSE;
/* function definitions */
@@ -1560,8 +1576,10 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
char *pdu_type_string;
proto_tree *type_tree;
guint16 segment_length;
+ guint16 du_id = 0;
guint16 segment_offset = 0;
guint16 cnf_cksum;
+ cksum_status_t cksum_status;
int offset;
u_char src_len, dst_len, nsel, opt_len = 0;
const guint8 *dst_addr, *src_addr;
@@ -1574,7 +1592,11 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
address save_net_dst;
address save_src;
address save_dst;
+ fragment_data *fd_head;
tvbuff_t *next_tvb;
+ packet_info save_pi;
+ gboolean must_restore_pi = FALSE;
+ gboolean update_col_info = TRUE;
if (check_col(pinfo->fd, COL_PROTOCOL))
col_set_str(pinfo->fd, COL_PROTOCOL, "CLNP");
@@ -1670,11 +1692,12 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
+ cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
+ cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
if (tree) {
proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
segment_length);
- cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
- switch (calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum)) {
+ switch (cksum_status) {
default:
/*
@@ -1754,10 +1777,11 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
segment_offset = tvb_get_ntohs(tvb, offset + 2);
+ du_id = tvb_get_ntohs(tvb, offset);
if (tree) {
proto_tree_add_text(clnp_tree, tvb, offset, 2,
"Data unit identifier: %06u",
- tvb_get_ntohs(tvb, offset));
+ du_id);
proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
"Segment offset : %6u",
segment_offset);
@@ -1803,10 +1827,156 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
fragment in a fragmented IP datagram; in the future, we will
probably reassemble fragments for IP, and may reassemble segments
for CLNP. */
- if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
+ /* If clnp_reassemble is on and this is a segment, then just add the segment
+ * to the hashtable.
+ */
+ if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
+ ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0)) {
+ /* We're reassembling, and this is part of a segmented datagram.
+ Add the segment to the hash table if the checksum is ok
+ and the frame isn't truncated. */
+ if (cksum_status != CKSUM_NOT_OK &&
+ (tvb_reported_length(tvb) <= tvb_length(tvb))) {
+ fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
+ segment_offset, segment_length - cnf_hdr_len,
+ cnf_type & CNF_MORE_SEGS);
+ } else {
+ fd_head=NULL;
+ }
+
+ if (fd_head != NULL) {
+ fragment_data *fd;
+ proto_tree *ft=NULL;
+ proto_item *fi=NULL;
+
+ /* OK, we have the complete reassembled payload. */
+ /* show all segments */
+ fi = proto_tree_add_item(clnp_tree, hf_clnp_segments,
+ tvb, 0, 0, FALSE);
+ ft = proto_item_add_subtree(fi, ett_clnp_segments);
+ for (fd = fd_head->next; fd != NULL; fd = fd->next){
+ if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ /* this segment has some flags set, create a subtree
+ * for it and display the flags.
+ */
+ proto_tree *fet = NULL;
+ proto_item *fei = NULL;
+ int hf;
+
+ if (fd->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ hf = hf_clnp_segment_error;
+ } else {
+ hf = hf_clnp_segment;
+ }
+ fei = proto_tree_add_none_format(ft, hf,
+ tvb, 0, 0,
+ "Frame:%d payload:%d-%d",
+ fd->frame,
+ fd->offset,
+ fd->offset+fd->len-1
+ );
+ fet = proto_item_add_subtree(fei, ett_clnp_segment);
+ if (fd->flags&FD_OVERLAP) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_overlap, tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_OVERLAPCONFLICT) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_overlap_conflict, tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_MULTIPLETAILS) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_multiple_tails, tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_TOOLONGFRAGMENT) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_too_long_segment, tvb, 0, 0,
+ TRUE);
+ }
+ } else {
+ /* nothing of interest for this segment */
+ proto_tree_add_none_format(ft, hf_clnp_segment,
+ tvb, 0, 0,
+ "Frame:%d payload:%d-%d",
+ fd->frame,
+ fd->offset,
+ fd->offset+fd->len-1
+ );
+ }
+ }
+ if (fd_head->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ if (check_col(pinfo->fd, COL_INFO)) {
+ col_set_str(pinfo->fd, COL_INFO, "[Illegal segments]");
+ update_col_info = FALSE;
+ }
+ }
+
+ /* Allocate a new tvbuff, referring to the reassembled payload. */
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
+ fd_head->datalen, "Reassembled");
+
+ /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
+ were handed refers, so it'll get cleaned up when that tvbuff
+ is cleaned up. */
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+
+ /* Add the defragmented data to the data source list. */
+ pinfo->fd->data_src = g_slist_append(pinfo->fd->data_src, next_tvb);
+
+ /* It's not fragmented. */
+ pinfo->fragmented = FALSE;
+
+ /* Save the current value of "pi", and adjust certain fields to
+ reflect the new tvbuff. */
+ save_pi = pi;
+ pi.compat_top_tvb = next_tvb;
+ pi.len = tvb_reported_length(next_tvb);
+ pi.captured_len = tvb_length(next_tvb);
+ must_restore_pi = TRUE;
+ } else {
+ /* We don't have the complete reassembled payload. */
+ next_tvb = NULL;
+ }
+ } else {
+ /* If this is the first segment, dissect its contents, otherwise
+ just show it as a segment.
+
+ XXX - if we eventually don't save the reassembled contents of all
+ segmented datagrams, we may want to always reassemble. */
+ if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
+ /* Not the first segment - don't dissect it. */
+ next_tvb = NULL;
+ } else {
+ /* First segment, or not segmented. Dissect what we have here. */
+
+ /* Get a tvbuff for the payload. */
+ next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+
+ /*
+ * If this is the first segment, but not the only segment,
+ * tell the next protocol that.
+ */
+ if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
+ pinfo->fragmented = TRUE;
+ else
+ pinfo->fragmented = FALSE;
+ }
+ }
+
+ if (next_tvb == NULL) {
+ /* Just show this as a segment. */
if (check_col(pinfo->fd, COL_INFO))
col_add_fstr(pinfo->fd, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
pdu_type_string, flag_string, segment_offset);
+
+ /* As we haven't reassembled anything, we haven't changed "pi", so
+ we don't have to restore it. */
dissect_data(tvb, offset, pinfo, tree);
return;
}
@@ -1821,7 +1991,6 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
PDU, skip that? */
if (nsel == (char)tp_nsap_selector || always_decode_transport) {
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE))
return; /* yes, it appears to be COTP or CLTP */
}
@@ -1855,7 +2024,6 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
"Discarded PDU");
discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
dissect_clnp(next_tvb, pinfo, discpdu_tree);
/* Restore the addresses. */
@@ -1879,11 +2047,15 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
if (check_col(pinfo->fd, COL_INFO))
col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
dissect_data(next_tvb, 0, pinfo, tree);
} /* dissect_clnp */
+static void
+clnp_reassemble_init(void)
+{
+ fragment_table_init(&clnp_segment_table);
+}
void proto_register_clnp(void)
{
@@ -1921,10 +2093,40 @@ void proto_register_clnp(void)
{ &hf_clnp_src,
{ " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
+
+ { &hf_clnp_segment_overlap,
+ { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Segment overlaps with other segments" }},
+
+ { &hf_clnp_segment_overlap_conflict,
+ { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping segments contained conflicting data" }},
+
+ { &hf_clnp_segment_multiple_tails,
+ { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when reassembling the packet" }},
+
+ { &hf_clnp_segment_too_long_segment,
+ { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Segment contained data past end of packet" }},
+
+ { &hf_clnp_segment_error,
+ { "Reassembly error", "clnp.segment.error", FT_NONE, BASE_DEC, NULL, 0x0,
+ "Reassembly error due to illegal segments" }},
+
+ { &hf_clnp_segment,
+ { "CLNP Segment", "clnp.segment", FT_NONE, BASE_DEC, NULL, 0x0,
+ "CLNP Segment" }},
+
+ { &hf_clnp_segments,
+ { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
+ "CLNP Segments" }},
};
static gint *ett[] = {
&ett_clnp,
&ett_clnp_type,
+ &ett_clnp_segments,
+ &ett_clnp_segment,
&ett_clnp_disc_pdu,
};
@@ -1943,7 +2145,10 @@ void proto_register_clnp(void)
"Always try to decode NSDU as transport PDUs",
"Always try to decode NSDU as transport PDUs",
&always_decode_transport);
-
+ prefs_register_bool_preference(clnp_module, "reassemble",
+ "Reassemble segmented CLNP datagrams",
+ "Whether segmented CLNP datagrams should be reassembled",
+ &clnp_reassemble);
}
void proto_register_cotp(void)
@@ -1980,6 +2185,7 @@ void proto_register_cltp(void)
proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
/* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
proto_register_subtree_array(ett, array_length(ett));
+ register_init_routine(clnp_reassemble_init);
}
void
diff --git a/packet-ip.c b/packet-ip.c
index 557efc3a55..1e2e937677 100644
--- a/packet-ip.c
+++ b/packet-ip.c
@@ -1,12 +1,11 @@
/* packet-ip.c
* Routines for IP and miscellaneous IP protocol packet disassembly
*
- * $Id: packet-ip.c,v 1.134 2001/06/05 05:54:14 guy Exp $
+ * $Id: packet-ip.c,v 1.135 2001/06/08 06:27:15 guy Exp $
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
- *
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -47,6 +46,7 @@
#include "resolv.h"
#include "ipproto.h"
#include "prefs.h"
+#include "reassemble.h"
#include "etypes.h"
#include "greproto.h"
#include "ppptypes.h"
@@ -301,319 +301,14 @@ typedef struct _e_ip
/*
* defragmentation of IPv4
*/
-static GHashTable *ip_fragment_table=NULL;
-
-typedef struct _ip_fragment_key {
- guint32 srcip;
- guint32 dstip;
- guint32 id;
-} ip_fragment_key;
-
-/* make sure that all flags that are set in a fragment entry is also set for
- * the flags field of ipfd_head !!!
- */
-/* only in ipfd_head: packet is defragmented */
-#define IPD_DEFRAGMENTED 0x0001
-/* there are overlapping fragments */
-#define IPD_OVERLAP 0x0002
-/* overlapping fragments contain different data */
-#define IPD_OVERLAPCONFLICT 0x0004
-/* more than one fragment which indicates end-of data */
-#define IPD_MULTIPLETAILS 0x0008
-/* fragment contains data past the end of the datagram */
-#define IPD_TOOLONGFRAGMENT 0x0010
-typedef struct _ip_fragment_data {
- struct _ip_fragment_data *next;
- guint32 frame;
- guint32 offset;
- guint32 len;
- guint32 datalen; /*Only valid in first item of list */
- guint32 flags;
- unsigned char *data;
-} ip_fragment_data;
-
-#define LINK_FRAG(ipfd_head,ipfd) \
- { ip_fragment_data *ipfd_i; \
- /* add fragment to list, keep list sorted */ \
- for(ipfd_i=ipfd_head;ipfd_i->next;ipfd_i=ipfd_i->next){ \
- if( (ipfd->offset) < (ipfd_i->next->offset) ) \
- break; \
- } \
- ipfd->next=ipfd_i->next; \
- ipfd_i->next=ipfd; \
- }
-
-
-static gint
-ip_fragment_equal(gconstpointer k1, gconstpointer k2)
-{
- ip_fragment_key* key1 = (ip_fragment_key*) k1;
- ip_fragment_key* key2 = (ip_fragment_key*) k2;
-
- return ( ( (key1->srcip == key2->srcip) &&
- (key1->dstip == key2->dstip) &&
- (key1->id == key2->id)
- ) ?
- TRUE : FALSE);
-}
-
-static guint
-ip_fragment_hash(gconstpointer k)
-{
- ip_fragment_key* key = (ip_fragment_key*) k;
-
- return (key->srcip ^ key->dstip ^ key->id);
-}
-
-static gboolean
-free_all_fragments(gpointer key, gpointer value, gpointer user_data)
-{
- ip_fragment_data *ipfd_head;
- ip_fragment_data *ipfd_i;
-
- ipfd_head=value;
- while(ipfd_head){
- ipfd_i=ipfd_head->next;
- if(ipfd_head->data){
- g_free(ipfd_head->data);
- }
- g_free(ipfd_head);
- ipfd_head=ipfd_i;
- }
-
- g_free(key);
- return TRUE;
-}
+static GHashTable *ip_fragment_table = NULL;
static void
ip_defragment_init(void)
{
- if( ip_fragment_table != NULL ){
- /* The fragment hash table exists.
- *
- * Remove all entries and free all memory.
- */
- g_hash_table_foreach_remove(ip_fragment_table,free_all_fragments,NULL);
- } else {
- /* The fragment table does not exist. Create it */
- ip_fragment_table = g_hash_table_new(ip_fragment_hash,
- ip_fragment_equal);
- }
-}
-
-/* This function adds a new fragment to the fragment hash table
- * If this is the first fragment seen in for this ip packet,
- * a new entry is created in the hash table, otherwise
- * This fragment is just added to the linked list of
- * fragments for this packet.
- * The list of fragments for a specific ip-packet is kept sorted for
- * easier handling.
- * tvb had better contain an IPv4 packet, or BAD things will probably happen.
- *
- * Returns a pointer to the head of the fragment data list if we have all the
- * fragments, NULL otherwise.
- */
-static ip_fragment_data *
-ip_fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
- guint32 floff)
-{
- ip_fragment_key *ipfk;
- ip_fragment_data *ipfd_head;
- ip_fragment_data *ipfd;
- ip_fragment_data *ipfd_i;
- guint32 frag_offset;
- guint32 max,dfpos;
-
-
- /* create key to search hash with */
- ipfk=g_malloc(sizeof(ip_fragment_key));
- memcpy(&ipfk->srcip, pinfo->src.data, sizeof(ipfk->srcip));
- memcpy(&ipfk->dstip, pinfo->dst.data, sizeof(ipfk->dstip));
- ipfk->id = id;
-
- ipfd_head=g_hash_table_lookup(ip_fragment_table, ipfk);
-
-
- /* have we already seen this frame ?*/
- if( pinfo->fd->flags.visited ){
- g_free(ipfk);
- if (ipfd_head != NULL && ipfd_head->flags & IPD_DEFRAGMENTED) {
- return ipfd_head;
- } else {
- return NULL;
- }
- }
-
-
-
- frag_offset = (floff & IP_OFFSET)*8;
-
- if (ipfd_head==NULL){
- /* not found, this must be the first snooped fragment for this
- * ip packet. Create list-head.
- */
- ipfd_head=g_malloc(sizeof(ip_fragment_data));
- /* head/first structure in list only holds no other data than
- * 'datalen' then we dont have to change the head of the list
- * even if we want to keep it sorted
- */
- ipfd_head->next=NULL;
- ipfd_head->datalen=0;
- ipfd_head->offset=0;
- ipfd_head->len=0;
- ipfd_head->flags=0;
- ipfd_head->data=NULL;
- g_hash_table_insert(ip_fragment_table, ipfk, ipfd_head);
- } else {
- /* this was not the first fragment, so we can throw ipfk
- * away, only used for the first fragment, 3 lines up
- */
- g_free(ipfk);
- }
-
-
- /* create new ipfd describing this fragment */
- ipfd = g_malloc(sizeof(ip_fragment_data));
- ipfd->next = NULL;
- ipfd->flags = 0;
- ipfd->frame = pinfo->fd->num;
- ipfd->offset = frag_offset;
- ipfd->len = pinfo->iplen;
- ipfd->len -= (pinfo->iphdrlen*4);
- ipfd->data = NULL;
-
-
-
- if( !(floff&IP_MF) ){
- /* this is a tail fragment */
- if (ipfd_head->datalen) {
- /* ok we have already seen other tails for this packet
- * it might be a duplicate.
- */
- if (ipfd_head->datalen != (ipfd->offset + ipfd->len) ){
- /* Oops, this tail indicates a different packet
- * len than the previous ones. Somethings wrong
- */
- ipfd->flags |= IPD_MULTIPLETAILS;
- ipfd_head->flags |= IPD_MULTIPLETAILS;
- }
- } else {
- /* this was the first tail fragment, now we know the
- * length of the packet
- */
- ipfd_head->datalen = ipfd->offset + ipfd->len;
- }
- }
-
-
-
-
- /* If the packet is already defragmented, this MUST be an overlap.
- * The entire defragmented packet is in ipfd_head->data
- * Even if we have previously defragmented this packet, we still check
- * check it. Someone might play overlap and TTL games.
- */
- if (ipfd_head->flags & IPD_DEFRAGMENTED) {
- ipfd->flags |= IPD_OVERLAP;
- ipfd_head->flags |= IPD_OVERLAP;
- /* make sure its not too long */
- if (ipfd->offset + ipfd->len > ipfd_head->datalen) {
- ipfd->flags |= IPD_TOOLONGFRAGMENT;
- ipfd_head->flags |= IPD_TOOLONGFRAGMENT;
- LINK_FRAG(ipfd_head,ipfd);
- return (ipfd_head);
- }
- /* make sure it doesnt conflict with previous data */
- if ( memcmp(ipfd_head->data+ipfd->offset,
- tvb_get_ptr(tvb,offset,ipfd->len),ipfd->len) ){
- ipfd->flags |= IPD_OVERLAPCONFLICT;
- ipfd_head->flags |= IPD_OVERLAPCONFLICT;
- LINK_FRAG(ipfd_head,ipfd);
- return (ipfd_head);
- }
- /* it was just an overlap, link it and return */
- LINK_FRAG(ipfd_head,ipfd);
- return (ipfd_head);
- }
-
-
-
- /* If we have reached this point, the packet is not defragmented yet.
- * Save all payload in a buffer until we can defragment.
- */
- ipfd->data = g_malloc(ipfd->len);
- tvb_memcpy(tvb, ipfd->data, offset, ipfd->len);
- LINK_FRAG(ipfd_head,ipfd);
-
-
- if( !(ipfd_head->datalen) ){
- /* if we dont know the datalen, there are still missing
- * packets. Cheaper than the check below.
- */
- return NULL;
- }
-
-
- /* check if we have received the entire fragment
- * this is easy since the list is sorted and the head is faked.
- */
- max = 0;
- for (ipfd_i=ipfd_head->next;ipfd_i;ipfd_i=ipfd_i->next) {
- if ( ((ipfd_i->offset)<=max) &&
- ((ipfd_i->offset+ipfd_i->len)>max) ){
- max = ipfd_i->offset+ipfd_i->len;
- }
- }
-
- if (max < (ipfd_head->datalen)) {
- /* we have not received all packets yet */
- return NULL;
- }
-
-
- if (max > (ipfd_head->datalen)) {
- /* oops, too long fragment detected */
- ipfd->flags |= IPD_TOOLONGFRAGMENT;
- ipfd_head->flags |= IPD_TOOLONGFRAGMENT;
- }
-
-
- /* we have received an entire packet, defragment it and
- * free all fragments
- */
- ipfd_head->data = g_malloc(max);
-
- /* add all data fragments */
- for (dfpos=0,ipfd_i=ipfd_head;ipfd_i;ipfd_i=ipfd_i->next) {
- if (ipfd_i->len) {
- if (ipfd_i->offset < dfpos) {
- ipfd_i->flags |= IPD_OVERLAP;
- ipfd_head->flags |= IPD_OVERLAP;
- if ( memcmp(ipfd_head->data+ipfd_i->offset,
- ipfd_i->data,
- MIN(ipfd_i->len,(dfpos-ipfd_i->offset))
- ) ){
- ipfd_i->flags |= IPD_OVERLAPCONFLICT;
- ipfd_head->flags |= IPD_OVERLAPCONFLICT;
- }
- }
- memcpy(ipfd_head->data+ipfd_i->offset,ipfd_i->data,ipfd_i->len);
- g_free(ipfd_i->data);
- ipfd_i->data=NULL;
-
- dfpos=MAX(dfpos,(ipfd_i->offset+ipfd_i->len));
- }
- }
-
- /* mark this packet as defragmented.
- allows us to skip any trailing fragments */
- ipfd_head->flags |= IPD_DEFRAGMENTED;
-
- return ipfd_head;
+ fragment_table_init(&ip_fragment_table);
}
-
-
void
capture_ip(const u_char *pd, int offset, packet_counts *ld) {
if (!BYTES_ARE_IN_FRAME(offset, IPH_MIN_LEN)) {
@@ -1101,7 +796,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint16 flags;
guint8 nxt;
guint16 ipsum;
- ip_fragment_data *ipfd_head;
+ fragment_data *ipfd_head;
tvbuff_t *next_tvb;
packet_info save_pi;
gboolean must_restore_pi = FALSE;
@@ -1273,13 +968,17 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
Add the fragment to the hash table if the checksum is ok
and the frame isn't truncated. */
if ((ipsum==0) && (tvb_reported_length(tvb) <= tvb_length(tvb))) {
- ipfd_head = ip_fragment_add(tvb, offset, pinfo, iph.ip_id, iph.ip_off);
+ ipfd_head = fragment_add(tvb, offset, pinfo, iph.ip_id,
+ ip_fragment_table,
+ (iph.ip_off & IP_OFFSET)*8,
+ pinfo->iplen - (pinfo->iphdrlen*4),
+ iph.ip_off & IP_MF);
} else {
ipfd_head=NULL;
}
if (ipfd_head != NULL) {
- ip_fragment_data *ipfd;
+ fragment_data *ipfd;
proto_tree *ft=NULL;
proto_item *fi=NULL;
@@ -1289,8 +988,8 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
tvb, 0, 0, FALSE);
ft = proto_item_add_subtree(fi, ett_ip_fragments);
for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
- if (ipfd->flags & (IPD_OVERLAP|IPD_OVERLAPCONFLICT
- |IPD_MULTIPLETAILS|IPD_TOOLONGFRAGMENT) ) {
+ if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
/* this fragment has some flags set, create a subtree
* for it and display the flags.
*/
@@ -1298,8 +997,8 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *fei=NULL;
int hf;
- if (ipfd->flags & (IPD_OVERLAPCONFLICT
- |IPD_MULTIPLETAILS|IPD_TOOLONGFRAGMENT) ) {
+ if (ipfd->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
hf = hf_ip_fragment_error;
} else {
hf = hf_ip_fragment;
@@ -1312,22 +1011,22 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
ipfd->offset+ipfd->len-1
);
fet = proto_item_add_subtree(fei, ett_ip_fragment);
- if (ipfd->flags&IPD_OVERLAP) {
+ if (ipfd->flags&FD_OVERLAP) {
proto_tree_add_boolean(fet,
hf_ip_fragment_overlap, tvb, 0, 0,
TRUE);
}
- if (ipfd->flags&IPD_OVERLAPCONFLICT) {
+ if (ipfd->flags&FD_OVERLAPCONFLICT) {
proto_tree_add_boolean(fet,
hf_ip_fragment_overlap_conflict, tvb, 0, 0,
TRUE);
}
- if (ipfd->flags&IPD_MULTIPLETAILS) {
+ if (ipfd->flags&FD_MULTIPLETAILS) {
proto_tree_add_boolean(fet,
hf_ip_fragment_multiple_tails, tvb, 0, 0,
TRUE);
}
- if (ipfd->flags&IPD_TOOLONGFRAGMENT) {
+ if (ipfd->flags&FD_TOOLONGFRAGMENT) {
proto_tree_add_boolean(fet,
hf_ip_fragment_too_long_fragment, tvb, 0, 0,
TRUE);
@@ -1343,8 +1042,8 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
);
}
}
- if (ipfd_head->flags & (IPD_OVERLAPCONFLICT
- |IPD_MULTIPLETAILS|IPD_TOOLONGFRAGMENT) ) {
+ if (ipfd_head->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
if (check_col(pinfo->fd, COL_INFO)) {
col_set_str(pinfo->fd, COL_INFO, "[Illegal fragments]");
update_col_info = FALSE;
diff --git a/reassemble.c b/reassemble.c
new file mode 100644
index 0000000000..30dad7024b
--- /dev/null
+++ b/reassemble.c
@@ -0,0 +1,371 @@
+/* reassemble.c
+ * Routines for {fragment,segment} reassembly
+ *
+ * $Id: reassemble.c,v 1.1 2001/06/08 06:27:16 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "packet.h"
+
+#include "reassemble.h"
+
+typedef struct _fragment_key {
+ address src;
+ address dst;
+ guint32 id;
+} fragment_key;
+
+static GMemChunk *fragment_key_chunk = NULL;
+static GMemChunk *fragment_data_chunk = NULL;
+static int fragment_init_count = 200;
+
+#define LINK_FRAG(fd_head,fd) \
+ { fragment_data *fd_i; \
+ /* add fragment to list, keep list sorted */ \
+ for(fd_i=fd_head;fd_i->next;fd_i=fd_i->next){ \
+ if( (fd->offset) < (fd_i->next->offset) ) \
+ break; \
+ } \
+ fd->next=fd_i->next; \
+ fd_i->next=fd; \
+ }
+
+
+static gint
+fragment_equal(gconstpointer k1, gconstpointer k2)
+{
+ fragment_key* key1 = (fragment_key*) k1;
+ fragment_key* key2 = (fragment_key*) k2;
+
+ return ( ( (ADDRESSES_EQUAL(&key1->src, &key2->src)) &&
+ (ADDRESSES_EQUAL(&key1->dst, &key2->dst)) &&
+ (key1->id == key2->id)
+ ) ?
+ TRUE : FALSE);
+}
+
+static guint
+fragment_hash(gconstpointer k)
+{
+ fragment_key* key = (fragment_key*) k;
+ guint hash_val;
+ int i;
+
+ hash_val = 0;
+ for (i = 0; i < key->src.len; i++)
+ hash_val += key->src.data[i];
+ for (i = 0; i < key->dst.len; i++)
+ hash_val += key->dst.data[i];
+ hash_val += key->id;
+
+ return hash_val;
+}
+
+/*
+ * For a hash table entry, free the address data to which the key refers
+ * and the fragment data to which the value refers.
+ * (The actual key and value structures get freed by "reassemble_init()".)
+ */
+static gboolean
+free_all_fragments(gpointer key_arg, gpointer value, gpointer user_data)
+{
+ fragment_key *key = key_arg;
+ fragment_data *fd_head;
+
+ /*
+ * Grr. I guess the theory here is that freeing
+ * something sure as heck modifies it, so you
+ * want to ban attempts to free it, but, alas,
+ * if we make the "data" field of an "address"
+ * structure not a "const", the compiler whines if
+ * we try to make it point into the data for a packet,
+ * as that's a "const" array (and should be, as dissectors
+ * shouldn't trash it).
+ *
+ * So we cast the complaint into oblivion, and rely on
+ * the fact that these addresses are known to have had
+ * their data mallocated, i.e. they don't point into,
+ * say, the middle of the data for a packet.
+ */
+ g_free((gpointer)key->src.data);
+ g_free((gpointer)key->dst.data);
+
+ for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) {
+ if (fd_head->data)
+ g_free(fd_head->data);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Initialize a fragment table.
+ */
+void
+fragment_table_init(GHashTable **fragment_table)
+{
+ if (*fragment_table != NULL) {
+ /*
+ * The fragment hash table exists.
+ *
+ * Remove all entries and free fragment data for
+ * each entry. (The key and value data is freed
+ * by "reassemble_init()".)
+ */
+ g_hash_table_foreach_remove(*fragment_table,
+ free_all_fragments, NULL);
+ } else {
+ /* The fragment table does not exist. Create it */
+ *fragment_table = g_hash_table_new(fragment_hash,
+ fragment_equal);
+ }
+}
+
+/*
+ * Free up all space allocated for fragment keys and data.
+ */
+void
+reassemble_init(void)
+{
+ if (fragment_key_chunk != NULL)
+ g_mem_chunk_destroy(fragment_key_chunk);
+ if (fragment_data_chunk != NULL)
+ g_mem_chunk_destroy(fragment_data_chunk);
+ fragment_key_chunk = g_mem_chunk_new("fragment_key_chunk",
+ sizeof(fragment_key),
+ fragment_init_count * sizeof(fragment_key),
+ G_ALLOC_ONLY);
+ fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk",
+ sizeof(fragment_data),
+ fragment_init_count * sizeof(fragment_data),
+ G_ALLOC_ONLY);
+}
+
+/*
+ * This function adds a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new entry
+ * is created in the hash table, otherwise this fragment is just added
+ * to the linked list of fragments for this packet.
+ * The list of fragments for a specific datagram is kept sorted for
+ * easier handling.
+ *
+ * Returns a pointer to the head of the fragment data list if we have all the
+ * fragments, NULL otherwise.
+ */
+fragment_data *
+fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ GHashTable *fragment_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ fragment_key key, *new_key;
+ fragment_data *fd_head;
+ fragment_data *fd;
+ fragment_data *fd_i;
+ guint32 max, dfpos;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ /* have we already seen this frame ?*/
+ if (pinfo->fd->flags.visited) {
+ if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) {
+ return fd_head;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (fd_head==NULL){
+ /* not found, this must be the first snooped fragment for this
+ * packet. Create list-head.
+ */
+ fd_head=g_mem_chunk_alloc(fragment_data_chunk);
+ /* head/first structure in list only holds no other data than
+ * 'datalen' then we don't have to change the head of the list
+ * even if we want to keep it sorted
+ */
+ fd_head->next=NULL;
+ fd_head->datalen=0;
+ fd_head->offset=0;
+ fd_head->len=0;
+ fd_head->flags=0;
+ fd_head->data=NULL;
+
+ /*
+ * We're going to use the key to insert the fragment,
+ * so allocate a structure for it, and copy the
+ * addresses, allocating new buffers for the address
+ * data.
+ */
+ new_key = g_mem_chunk_alloc(fragment_key_chunk);
+ COPY_ADDRESS(&new_key->src, &key.src);
+ COPY_ADDRESS(&new_key->dst, &key.dst);
+ new_key->id = key.id;
+ g_hash_table_insert(fragment_table, new_key, fd_head);
+ }
+
+ /* create new fd describing this fragment */
+ fd = g_mem_chunk_alloc(fragment_data_chunk);
+ fd->next = NULL;
+ fd->flags = 0;
+ fd->frame = pinfo->fd->num;
+ fd->offset = frag_offset;
+ fd->len = frag_data_len;
+ fd->data = NULL;
+
+ if (!more_frags) {
+ /*
+ * This is the tail fragment in the sequence.
+ */
+ if (fd_head->datalen) {
+ /* ok we have already seen other tails for this packet
+ * it might be a duplicate.
+ */
+ if (fd_head->datalen != (fd->offset + fd->len) ){
+ /* Oops, this tail indicates a different packet
+ * len than the previous ones. Somethings wrong
+ */
+ fd->flags |= FD_MULTIPLETAILS;
+ fd_head->flags |= FD_MULTIPLETAILS;
+ }
+ } else {
+ /* this was the first tail fragment, now we know the
+ * length of the packet
+ */
+ fd_head->datalen = fd->offset + fd->len;
+ }
+ }
+
+
+
+
+ /* If the packet is already defragmented, this MUST be an overlap.
+ * The entire defragmented packet is in fd_head->data
+ * Even if we have previously defragmented this packet, we still check
+ * check it. Someone might play overlap and TTL games.
+ */
+ if (fd_head->flags & FD_DEFRAGMENTED) {
+ fd->flags |= FD_OVERLAP;
+ fd_head->flags |= FD_OVERLAP;
+ /* make sure its not too long */
+ if (fd->offset + fd->len > fd_head->datalen) {
+ fd->flags |= FD_TOOLONGFRAGMENT;
+ fd_head->flags |= FD_TOOLONGFRAGMENT;
+ LINK_FRAG(fd_head,fd);
+ return (fd_head);
+ }
+ /* make sure it doesnt conflict with previous data */
+ if ( memcmp(fd_head->data+fd->offset,
+ tvb_get_ptr(tvb,offset,fd->len),fd->len) ){
+ fd->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ LINK_FRAG(fd_head,fd);
+ return (fd_head);
+ }
+ /* it was just an overlap, link it and return */
+ LINK_FRAG(fd_head,fd);
+ return (fd_head);
+ }
+
+
+
+ /* If we have reached this point, the packet is not defragmented yet.
+ * Save all payload in a buffer until we can defragment.
+ * XXX - what if we didn't capture the entire fragment due
+ * to a too-short snapshot length?
+ */
+ fd->data = g_malloc(fd->len);
+ tvb_memcpy(tvb, fd->data, offset, fd->len);
+ LINK_FRAG(fd_head,fd);
+
+
+ if( !(fd_head->datalen) ){
+ /* if we dont know the datalen, there are still missing
+ * packets. Cheaper than the check below.
+ */
+ return NULL;
+ }
+
+
+ /* check if we have received the entire fragment
+ * this is easy since the list is sorted and the head is faked.
+ */
+ max = 0;
+ for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
+ if ( ((fd_i->offset)<=max) &&
+ ((fd_i->offset+fd_i->len)>max) ){
+ max = fd_i->offset+fd_i->len;
+ }
+ }
+
+ if (max < (fd_head->datalen)) {
+ /* we have not received all packets yet */
+ return NULL;
+ }
+
+
+ if (max > (fd_head->datalen)) {
+ /* oops, too long fragment detected */
+ fd->flags |= FD_TOOLONGFRAGMENT;
+ fd_head->flags |= FD_TOOLONGFRAGMENT;
+ }
+
+
+ /* we have received an entire packet, defragment it and
+ * free all fragments
+ */
+ fd_head->data = g_malloc(max);
+
+ /* add all data fragments */
+ for (dfpos=0,fd_i=fd_head;fd_i;fd_i=fd_i->next) {
+ if (fd_i->len) {
+ if (fd_i->offset < dfpos) {
+ fd_i->flags |= FD_OVERLAP;
+ fd_head->flags |= FD_OVERLAP;
+ if ( memcmp(fd_head->data+fd_i->offset,
+ fd_i->data,
+ MIN(fd_i->len,(dfpos-fd_i->offset))
+ ) ){
+ fd_i->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ }
+ }
+ memcpy(fd_head->data+fd_i->offset,fd_i->data,fd_i->len);
+ g_free(fd_i->data);
+ fd_i->data=NULL;
+
+ dfpos=MAX(dfpos,(fd_i->offset+fd_i->len));
+ }
+ }
+
+ /* mark this packet as defragmented.
+ allows us to skip any trailing fragments */
+ fd_head->flags |= FD_DEFRAGMENTED;
+
+ return fd_head;
+}
diff --git a/reassemble.h b/reassemble.h
new file mode 100644
index 0000000000..8b96e72d1a
--- /dev/null
+++ b/reassemble.h
@@ -0,0 +1,77 @@
+/* reassemble.h
+ * Declarations of outines for {fragment,segment} reassembly
+ *
+ * $Id: reassemble.h,v 1.1 2001/06/08 06:27:16 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* make sure that all flags that are set in a fragment entry is also set for
+ * the flags field of fd_head !!!
+ */
+
+/* only in fd_head: packet is defragmented */
+#define FD_DEFRAGMENTED 0x0001
+
+/* there are overlapping fragments */
+#define FD_OVERLAP 0x0002
+
+/* overlapping fragments contain different data */
+#define FD_OVERLAPCONFLICT 0x0004
+
+/* more than one fragment which indicates end-of data */
+#define FD_MULTIPLETAILS 0x0008
+
+/* fragment contains data past the end of the datagram */
+#define FD_TOOLONGFRAGMENT 0x0010
+
+typedef struct _fragment_data {
+ struct _fragment_data *next;
+ guint32 frame;
+ guint32 offset;
+ guint32 len;
+ guint32 datalen; /*Only valid in first item of list */
+ guint32 flags;
+ unsigned char *data;
+} fragment_data;
+
+/*
+ * Initialize a fragment table.
+ */
+void fragment_table_init(GHashTable **fragment_table);
+
+/*
+ * Free up all space allocated for fragment keys and data.
+ */
+void reassemble_init(void);
+
+/*
+ * This function adds a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new entry
+ * is created in the hash table, otherwise this fragment is just added
+ * to the linked list of fragments for this packet.
+ * The list of fragments for a specific datagram is kept sorted for
+ * easier handling.
+ *
+ * Returns a pointer to the head of the fragment data list if we have all the
+ * fragments, NULL otherwise.
+ */
+fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags);
diff --git a/tethereal.c b/tethereal.c
index e4f9df5ba6..ba0b089831 100644
--- a/tethereal.c
+++ b/tethereal.c
@@ -1,6 +1,6 @@
/* tethereal.c
*
- * $Id: tethereal.c,v 1.84 2001/06/05 07:38:33 guy Exp $
+ * $Id: tethereal.c,v 1.85 2001/06/08 06:27:16 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -93,6 +93,7 @@
#include "resolv.h"
#include "util.h"
#include "conversation.h"
+#include "reassemble.h"
#include "plugins.h"
#include "register.h"
@@ -651,6 +652,12 @@ capture(int packet_count, int out_file_type)
/* Initialize protocol-specific variables */
init_all_protocols();
+ /* Initialize the common data structures for fragment reassembly.
+ Must be done *after* "init_all_protocols()", as "init_all_protocols()"
+ may free up space for fragments, which it finds by using the
+ data structures that "reassemble_init()" frees. */
+ reassemble_init();
+
ld.linktype = WTAP_ENCAP_UNKNOWN;
ld.pdh = NULL;
@@ -1501,6 +1508,12 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
/* Initialize protocol-specific variables */
init_all_protocols();
+ /* Initialize the common data structures for fragment reassembly.
+ Must be done *after* "init_all_protocols()", as "init_all_protocols()"
+ may free up space for fragments, which it finds by using the
+ data structures that "reassemble_init()" frees. */
+ reassemble_init();
+
cf->wth = wth;
cf->filed = fd;
cf->f_len = cf_stat.st_size;