* Copyright 2000, Axis Communications AB
* Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com
*
- * $Id: packet-ieee80211.c,v 1.54 2002/04/13 18:41:47 guy Exp $
+ * $Id: packet-ieee80211.c,v 1.55 2002/04/17 08:25:05 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Marco Molteni
* Lena-Marie Nilsson
* Magnus Hultman-Persson
- *
*/
#ifdef HAVE_CONFIG_H
#include <epan/proto.h>
#include <epan/packet.h>
#include <epan/resolv.h>
+#include "prefs.h"
+#include "reassemble.h"
#include "packet-ipx.h"
#include "packet-llc.h"
#include "packet-ieee80211.h"
#include "etypes.h"
+/* Defragment fragmented 802.11 datagrams */
+static gboolean wlan_defragment = TRUE;
+
+/* Tables for reassembly of fragments. */
+static GHashTable *wlan_fragment_table = NULL;
+static GHashTable *wlan_reassembled_table = NULL;
+
/* ************************************************************************* */
/* Miscellaneous Constants */
/* ************************************************************************* */
/* ************************************************************************* */
static int hf_fcs = -1;
+/* ************************************************************************* */
+/* Header values for reassembly */
+/* ************************************************************************* */
+static int hf_fragments = -1;
+static int hf_fragment = -1;
+static int hf_fragment_overlap = -1;
+static int hf_fragment_overlap_conflict = -1;
+static int hf_fragment_multiple_tails = -1;
+static int hf_fragment_too_long_fragment = -1;
+static int hf_fragment_error = -1;
static int proto_wlan_mgt = -1;
static gint ett_proto_flags = -1;
static gint ett_cap_tree = -1;
static gint ett_fc_tree = -1;
+static gint ett_fragments = -1;
+static gint ett_fragment = -1;
static gint ett_80211_mgt = -1;
static gint ett_fixed_parameters = -1;
ether_to_str(addr), type);
}
+static void
+show_fragments(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ fragment_data *fd_head)
+{
+ guint32 offset;
+ fragment_data *fd;
+ proto_tree *ft;
+ proto_item *fi;
+
+ fi = proto_tree_add_item(tree, hf_fragments, tvb, 0, -1, FALSE);
+ ft = proto_item_add_subtree(fi, ett_fragments);
+ offset = 0;
+ for (fd = fd_head->next; fd != NULL; fd = fd->next){
+ if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ /*
+ * This fragment 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_fragment_error;
+ } else {
+ hf = hf_fragment;
+ }
+ fei = proto_tree_add_none_format(ft, hf, tvb, offset, fd->len,
+ "Frame:%u payload:%u-%u",
+ fd->frame, offset, offset+fd->len-1);
+ fet = proto_item_add_subtree(fei, ett_fragment);
+ if (fd->flags&FD_OVERLAP)
+ proto_tree_add_boolean(fet, hf_fragment_overlap, tvb, 0, 0, TRUE);
+ if (fd->flags&FD_OVERLAPCONFLICT) {
+ proto_tree_add_boolean(fet, hf_fragment_overlap_conflict, tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_MULTIPLETAILS) {
+ proto_tree_add_boolean(fet, hf_fragment_multiple_tails, tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_TOOLONGFRAGMENT) {
+ proto_tree_add_boolean(fet, hf_fragment_too_long_fragment, tvb, 0, 0,
+ TRUE);
+ }
+ } else {
+ /*
+ * Nothing of interest for this fragment.
+ */
+ proto_tree_add_none_format(ft, hf_fragment, tvb, offset, fd->len,
+ "Frame:%u payload:%u-%u",
+ fd->frame, offset, offset+fd->len-1);
+ }
+ offset += fd->len;
+ }
+ if (fd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
+ }
+}
+
/* ************************************************************************* */
/* Dissect 802.11 frame */
/* ************************************************************************* */
gboolean has_radio_information)
{
guint16 fcf, flags, frame_type_subtype;
+ guint16 seq_control;
+ guint32 seq_number, frag_number;
+ gboolean more_frags;
const guint8 *src = NULL, *dst = NULL;
proto_item *ti = NULL;
proto_item *flag_item;
proto_tree *flag_tree;
proto_tree *fc_tree;
guint16 hdr_len;
- tvbuff_t *next_tvb;
+ tvbuff_t *volatile next_tvb;
guint32 addr_type;
volatile gboolean is_802_2;
val_to_str(frame_type_subtype, frame_type_subtype_vals,
"Unrecognized (Reserved frame)"));
+ flags = COOK_FLAGS (fcf);
+ more_frags = HAVE_FRAGMENTS (flags);
+
/* Add the radio information, if present, and the FC to the current tree */
if (tree)
{
tvb, 0, 1,
COOK_FRAME_SUBTYPE (fcf));
- flags = COOK_FLAGS (fcf);
-
flag_item =
proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 1, 1,
flags, "Flags: 0x%X", flags);
* Decode the part of the frame header that isn't the same for all
* frame types.
*/
+ seq_control = 0;
+ frag_number = 0;
+ seq_number = 0;
+
switch (frame_type_subtype)
{
SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst);
SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst);
+ seq_control = tvb_get_letohs(tvb, 22);
+ frag_number = COOK_FRAGMENT_NUMBER(seq_control);
+ seq_number = COOK_SEQUENCE_NUMBER(seq_control);
+
if (tree)
{
proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
tvb_get_ptr (tvb, 16, 6));
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
}
break;
SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst);
SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst);
+ seq_control = tvb_get_letohs(tvb, 22);
+ frag_number = COOK_FRAGMENT_NUMBER(seq_control);
+ seq_number = COOK_SEQUENCE_NUMBER(seq_control);
+
/* Now if we have a tree we start adding stuff */
if (tree)
{
proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
tvb_get_ptr (tvb, 16, 6));
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
/* add items for wlan.addr filter */
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
tvb_get_ptr (tvb, 10, 6));
proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 16, 6, src);
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
/* add items for wlan.addr filter */
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst);
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
/* add items for wlan.addr filter */
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
tvb_get_ptr (tvb, 10, 6));
proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst);
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6, src);
/* add items for wlan.addr filter */
/*
* Now dissect the body of a non-WEP-encrypted frame.
*/
- next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+
+ /*
+ * Do defragmentation if "wlan_defragment" is true.
+ *
+ * We have to do some special handling to catch frames that
+ * have the "More Fragments" indicator not set but that
+ * don't show up as reassembled and don't have any other
+ * fragments present. Some networking interfaces appear
+ * to do reassembly even when you're capturing raw packets
+ * *and* show the reassembled packet without the "More
+ * Fragments" indicator set *but* with a non-zero fragment
+ * number.
+ *
+ * (This could get some false positives if we really *did* only
+ * capture the last fragment of a fragmented packet, but that's
+ * life.)
+ *
+ * XXX - what about short frames?
+ */
+ if (wlan_defragment && (more_frags || frag_number != 0)) {
+ gboolean save_fragmented;
+ fragment_data *fd_head;
+ unsigned char *buf;
+
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+
+ /*
+ * If we've already seen this frame, look it up in the
+ * table of reassembled packets, otherwise add it to
+ * whatever reassembly is in progress, if any, and see
+ * if it's done.
+ */
+ fd_head = fragment_add_seq_check(tvb, hdr_len, pinfo, seq_number,
+ wlan_fragment_table,
+ wlan_reassembled_table,
+ frag_number,
+ tvb_length_remaining(tvb, hdr_len),
+ more_frags);
+ if (fd_head != NULL) {
+ /*
+ * Either this is reassembled or it wasn't fragmented
+ * (see comment above about some networking interfaces).
+ * In either case, it's now in the table of reassembled
+ * packets.
+ *
+ * If the "fragment_data" structure doesn't have a list of
+ * fragments, we assume it's a placeholder to mark those
+ * not-really-fragmented packets, and just treat this as
+ * a non-fragmented frame.
+ */
+ if (fd_head->next != NULL) {
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ add_new_data_source(pinfo->fd, next_tvb, "Reassembled 802.11");
+
+ /* Show all fragments. */
+ show_fragments(next_tvb, pinfo, hdr_tree, fd_head);
+ } else {
+ /*
+ * Not fragmented, really.
+ * Show it as a regular frame.
+ */
+ next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+ }
+ pinfo->fragmented = FALSE;
+ } else {
+ /*
+ * Not yet reassembled.
+ */
+ pinfo->fragmented = save_fragmented;
+ next_tvb = NULL;
+ }
+ } else {
+ /*
+ * XXX - how do we know it's the last fragment?
+ */
+ if (frag_number != 0) {
+ /* Just show this as a fragment. */
+ next_tvb = NULL;
+ } else
+ next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+ }
+
+ if (next_tvb == NULL) {
+ /* Just show this as a fragment. */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Fragmented IEEE 802.11 frame");
+ next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+ call_dissector(data_handle, next_tvb, pinfo, tree);
+ return;
+ }
+
switch (COOK_FRAME_TYPE (fcf))
{
}
ENDTRY;
- if (COOK_FRAGMENT_NUMBER(tvb_get_letohs(tvb, 22)) > 0) {
- /* Just show this as a fragment. */
- if (check_col(pinfo->cinfo, COL_INFO))
- col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented IEEE 802.11 frame");
- call_dissector(data_handle, next_tvb, pinfo, tree);
- break;
- }
-
if (is_802_2)
call_dissector(llc_handle, next_tvb, pinfo, tree);
else
dissect_ieee80211_common (tvb, pinfo, tree, TRUE, FALSE);
}
+static void
+wlan_defragment_init(void)
+{
+ fragment_table_init(&wlan_fragment_table);
+ reassembled_table_init(&wlan_reassembled_table);
+}
+
void
proto_register_wlan (void)
{
{"Frame Check Sequence (not verified)", "wlan.fcs", FT_UINT32, BASE_HEX,
NULL, 0, "", HFILL }},
+ {&hf_fragment_overlap,
+ {"Fragment overlap", "wlan.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
+
+ {&hf_fragment_overlap_conflict,
+ {"Conflicting data in fragment overlap", "wlan.fragment.overlap.conflict",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping fragments contained conflicting data", HFILL }},
+
+ {&hf_fragment_multiple_tails,
+ {"Multiple tail fragments found", "wlan.fragment.multipletails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when defragmenting the packet", HFILL }},
+
+ {&hf_fragment_too_long_fragment,
+ {"Fragment too long", "wlan.fragment.toolongfragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Fragment contained data past end of packet", HFILL }},
+
+ {&hf_fragment_error,
+ {"Defragmentation error", "wlan.fragment.error",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "Defragmentation error due to illegal fragments", HFILL }},
+
+ {&hf_fragment,
+ {"802.11 Fragment", "wlan.fragment", FT_NONE, BASE_NONE, NULL, 0x0,
+ "802.11 Fragment", HFILL }},
+
+ {&hf_fragments,
+ {"802.11 Fragments", "wlan.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
+ "WTP Fragments", HFILL }},
+
{&hf_wep_iv,
{"Initialization Vector", "wlan.wep.iv", FT_UINT24, BASE_HEX, NULL, 0,
"Initialization Vector", HFILL }},
&ett_80211,
&ett_fc_tree,
&ett_proto_flags,
+ &ett_fragments,
+ &ett_fragment,
&ett_80211_mgt,
&ett_fixed_parameters,
&ett_tagged_parameters,
&ett_wep_parameters,
&ett_cap_tree,
};
+ module_t *wlan_module;
proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN",
"IEEE 802.11", "wlan");
register_dissector("wlan", dissect_ieee80211, proto_wlan);
register_dissector("wlan_fixed", dissect_ieee80211_fixed, proto_wlan);
+ register_init_routine(wlan_defragment_init);
+
+ /* Register configuration options */
+ wlan_module = prefs_register_protocol(proto_wlan, NULL);
+ prefs_register_bool_preference(wlan_module, "defragment",
+ "Reassemble fragmented 802.11 datagrams",
+ "Whether fragmented 802.11 datagrams should be reassembled",
+ &wlan_defragment);
}
void
/* reassemble.c
* Routines for {fragment,segment} reassembly
*
- * $Id: reassemble.c,v 1.11 2002/04/17 04:54:30 guy Exp $
+ * $Id: reassemble.c,v 1.12 2002/04/17 08:25:04 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
guint32 id;
} fragment_key;
+typedef struct _reassembled_key {
+ guint32 frame;
+ guint32 id;
+} reassembled_key;
+
static GMemChunk *fragment_key_chunk = NULL;
+static GMemChunk *reassembled_key_chunk = NULL;
static GMemChunk *fragment_data_chunk = NULL;
static int fragment_init_count = 200;
return hash_val;
}
+static gint
+reassembled_equal(gconstpointer k1, gconstpointer k2)
+{
+ reassembled_key* key1 = (reassembled_key*) k1;
+ reassembled_key* key2 = (reassembled_key*) k2;
+
+ /*key.frame is the first item to compare since item is most
+ likely to differ between sessions, thus shortcircuiting
+ the comparasion of addresses.
+ */
+ return ( ( (key1->frame == key2->frame) &&
+ (key1->id == key2->id)
+ ) ?
+ TRUE : FALSE);
+}
+
+static guint
+reassembled_hash(gconstpointer k)
+{
+ reassembled_key* key = (reassembled_key*) k;
+ guint hash_val;
+
+ hash_val = 0;
+
+/* The frame number is probably good enough as a hash value;
+ there's probably not going to be too many reassembled
+ packets that end at the same frame.
+*/
+
+ hash_val = key->frame;
+
+ 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.
+ * For a fragment 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
return TRUE;
}
+/*
+ * For a reassembled-packet hash table entry, free the fragment data
+ * to which the value refers.
+ * (The actual key and value structures get freed by "reassemble_init()".)
+ */
+static gboolean
+free_all_reassembled_fragments(gpointer key_arg _U_, gpointer value,
+ gpointer user_data _U_)
+{
+ fragment_data *fd_head;
+
+ for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) {
+ if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED))
+ g_free(fd_head->data);
+ }
+
+ return TRUE;
+}
+
/*
* Initialize a fragment table.
*/
}
}
+/*
+ * Initialize a reassembled-packet table.
+ */
+void
+reassembled_table_init(GHashTable **reassembled_table)
+{
+ if (*reassembled_table != NULL) {
+ /*
+ * The reassembled-packet 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(*reassembled_table,
+ free_all_reassembled_fragments, NULL);
+ } else {
+ /* The fragment table does not exist. Create it */
+ *reassembled_table = g_hash_table_new(reassembled_hash,
+ reassembled_equal);
+ }
+}
+
/*
* Free up all space allocated for fragment keys and data.
*/
{
if (fragment_key_chunk != NULL)
g_mem_chunk_destroy(fragment_key_chunk);
+ if (reassembled_key_chunk != NULL)
+ g_mem_chunk_destroy(reassembled_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);
+ reassembled_key_chunk = g_mem_chunk_new("reassembled_key_chunk",
+ sizeof(reassembled_key),
+ fragment_init_count * sizeof(reassembled_key),
+ G_ALLOC_ONLY);
fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk",
sizeof(fragment_data),
fragment_init_count * sizeof(fragment_data),
fd_head->flags |= FD_PARTIAL_REASSEMBLY;
}
}
+
/*
* This function adds a new fragment to the fragment hash table.
* If this is the first fragment seen for this datagram, a new entry
return fd_head;
}
-
-
/*
- * 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.
+ * This function adds a new fragment to the entry for a reassembly
+ * operation.
+ *
* 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.
+ * Returns TRUE if we have all the fragments, FALSE otherwise.
*
* This function assumes frag_number being a block sequence number.
* The bsn for the first block is 0.
*/
-fragment_data *
-fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
- GHashTable *fragment_table, guint32 frag_number,
+static gboolean
+fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
+ packet_info *pinfo, guint32 id, guint32 frag_number,
guint32 frag_data_len, gboolean more_frags)
{
- fragment_key key, *new_key;
- fragment_data *fd_head;
fragment_data *fd;
fragment_data *fd_i;
fragment_data *last_fd;
guint32 max, dfpos, size;
- /* 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=FD_BLOCKSEQUENCE;
- 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 |= FD_TOOLONGFRAGMENT;
fd_head->flags |= FD_TOOLONGFRAGMENT;
LINK_FRAG(fd_head,fd);
- return (fd_head);
+ return TRUE;
}
/* make sure it doesnt conflict with previous data */
dfpos=0;
fd->flags |= FD_OVERLAPCONFLICT;
fd_head->flags |= FD_OVERLAPCONFLICT;
LINK_FRAG(fd_head,fd);
- return (fd_head);
+ return TRUE;
}
if ( memcmp(fd_head->data+dfpos,
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);
+ return TRUE;
}
/* it was just an overlap, link it and return */
LINK_FRAG(fd_head,fd);
- return (fd_head);
+ return TRUE;
}
/* If we have reached this point, the packet is not defragmented yet.
if (max <= fd_head->datalen) {
/* we have not received all packets yet */
- return NULL;
+ return FALSE;
}
allows us to skip any trailing fragments */
fd_head->flags |= FD_DEFRAGMENTED;
- return fd_head;
+ return TRUE;
+}
+
+/*
+ * 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.
+ *
+ * Returns a pointer to the head of the fragment data list if we have all the
+ * fragments, NULL otherwise.
+ *
+ * This function assumes frag_number being a block sequence number.
+ * The bsn for the first block is 0.
+ */
+fragment_data *
+fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ fragment_key key, *new_key;
+ fragment_data *fd_head;
+ fragment_data *fd;
+ fragment_data *fd_i;
+ fragment_data *last_fd;
+ guint32 max, dfpos, size;
+
+ /* 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=FD_BLOCKSEQUENCE;
+ 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);
+ }
+
+ if (fragment_add_seq_work(fd_head, tvb, offset, pinfo, id,
+ frag_number, frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ */
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
+}
+
+/*
+ * This function adds fragment_data structure to a reassembled-packet
+ * hash table, using the reassembly ID and frame number as the key.
+ */
+static void
+fragment_reassembled(fragment_data *fd_head, packet_info *pinfo, guint32 id,
+ GHashTable *reassembled_table)
+{
+ reassembled_key *new_key;
+
+ new_key = g_mem_chunk_alloc(reassembled_key_chunk);
+ new_key->frame = pinfo->fd->num;
+ new_key->id = id;
+ g_hash_table_insert(reassembled_table, new_key, fd_head);
+}
+
+/*
+ * This function adds a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new
+ * "fragment_data" structure is allocated to refer to the reassembled,
+ * packet, and:
+ *
+ * if "more_frags" is false, the structure is not added to
+ * the hash table, and not given any fragments to refer to,
+ * but is just returned;
+ *
+ * if "more_frags" is true, this fragment is added to the linked
+ * list of fragments for this packet, and the "fragment_data"
+ * structure is put into the hash table.
+ *
+ * Otherwise, this fragment is just added to the linked list of fragments
+ * for this packet.
+ *
+ * Returns a pointer to the head of the fragment data list, and removes
+ * that from the fragment hash table if necessary and adds it to the
+ * table of reassembled fragments, if we have all the fragments or if
+ * this is the only fragment and "more_frags" is false, returns NULL
+ * otherwise.
+ *
+ * This function assumes frag_number being a block sequence number.
+ * The bsn for the first block is 0.
+ */
+fragment_data *
+fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ reassembled_key reass_key;
+ fragment_key key, *new_key, *old_key;
+ gpointer orig_key, value;
+ fragment_data *fd_head;
+ fragment_data *fd;
+ fragment_data *fd_i;
+ fragment_data *last_fd;
+ guint32 max, dfpos, size;
+
+ /*
+ * Have we already seen this frame?
+ * If so, look for it in the table of reassembled packets.
+ */
+ if (pinfo->fd->flags.visited) {
+ reass_key.frame = pinfo->fd->num;
+ reass_key.id = id;
+
+ return g_hash_table_lookup(reassembled_table, &reass_key);
+ }
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ if (!g_hash_table_lookup_extended(fragment_table, &key,
+ &orig_key, &value)) {
+ /* 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=FD_BLOCKSEQUENCE;
+ fd_head->data=NULL;
+
+ if (!more_frags) {
+ /*
+ * This is the last snooped fragment for this
+ * packet as well; that means it's the only
+ * fragment. Just add it to the table of
+ * reassembled packets, and return it.
+ */
+ fragment_reassembled(fd_head, pinfo, id,
+ reassembled_table);
+ return fd_head;
+ }
+
+ /*
+ * 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);
+ } else {
+ /*
+ * We found it.
+ */
+ fd_head = value;
+ }
+
+ if (fragment_add_seq_work(fd_head, tvb, offset, pinfo, id,
+ frag_number, frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ * Remove this from the table of in-progress
+ * reassemblies, add it to the table of
+ * reassembled packets, and return it.
+ */
+
+ /*
+ * Free up the copies of the addresses from the old key.
+ */
+ old_key = orig_key;
+ g_free((gpointer)old_key->src.data);
+ g_free((gpointer)old_key->dst.data);
+
+ /*
+ * Remove the entry from the fragment table.
+ */
+ g_hash_table_remove(fragment_table, &key);
+
+ /*
+ * Add it to the table of reassembled packets.
+ */
+ fragment_reassembled(fd_head, pinfo, id, reassembled_table);
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
}