2 * Routines for {fragment,segment} reassembly
4 * $Id: reassemble.c,v 1.2 2001/06/28 19:15:11 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include "reassemble.h"
35 typedef struct _fragment_key {
41 static GMemChunk *fragment_key_chunk = NULL;
42 static GMemChunk *fragment_data_chunk = NULL;
43 static int fragment_init_count = 200;
45 #define LINK_FRAG(fd_head,fd) \
46 { fragment_data *fd_i; \
47 /* add fragment to list, keep list sorted */ \
48 for(fd_i=fd_head;fd_i->next;fd_i=fd_i->next){ \
49 if( (fd->offset) < (fd_i->next->offset) ) \
52 fd->next=fd_i->next; \
58 fragment_equal(gconstpointer k1, gconstpointer k2)
60 fragment_key* key1 = (fragment_key*) k1;
61 fragment_key* key2 = (fragment_key*) k2;
63 return ( ( (ADDRESSES_EQUAL(&key1->src, &key2->src)) &&
64 (ADDRESSES_EQUAL(&key1->dst, &key2->dst)) &&
65 (key1->id == key2->id)
71 fragment_hash(gconstpointer k)
73 fragment_key* key = (fragment_key*) k;
78 for (i = 0; i < key->src.len; i++)
79 hash_val += key->src.data[i];
80 for (i = 0; i < key->dst.len; i++)
81 hash_val += key->dst.data[i];
88 * For a hash table entry, free the address data to which the key refers
89 * and the fragment data to which the value refers.
90 * (The actual key and value structures get freed by "reassemble_init()".)
93 free_all_fragments(gpointer key_arg, gpointer value, gpointer user_data)
95 fragment_key *key = key_arg;
96 fragment_data *fd_head;
99 * Grr. I guess the theory here is that freeing
100 * something sure as heck modifies it, so you
101 * want to ban attempts to free it, but, alas,
102 * if we make the "data" field of an "address"
103 * structure not a "const", the compiler whines if
104 * we try to make it point into the data for a packet,
105 * as that's a "const" array (and should be, as dissectors
106 * shouldn't trash it).
108 * So we cast the complaint into oblivion, and rely on
109 * the fact that these addresses are known to have had
110 * their data mallocated, i.e. they don't point into,
111 * say, the middle of the data for a packet.
113 g_free((gpointer)key->src.data);
114 g_free((gpointer)key->dst.data);
116 for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) {
118 g_free(fd_head->data);
125 * Initialize a fragment table.
128 fragment_table_init(GHashTable **fragment_table)
130 if (*fragment_table != NULL) {
132 * The fragment hash table exists.
134 * Remove all entries and free fragment data for
135 * each entry. (The key and value data is freed
136 * by "reassemble_init()".)
138 g_hash_table_foreach_remove(*fragment_table,
139 free_all_fragments, NULL);
141 /* The fragment table does not exist. Create it */
142 *fragment_table = g_hash_table_new(fragment_hash,
148 * Free up all space allocated for fragment keys and data.
151 reassemble_init(void)
153 if (fragment_key_chunk != NULL)
154 g_mem_chunk_destroy(fragment_key_chunk);
155 if (fragment_data_chunk != NULL)
156 g_mem_chunk_destroy(fragment_data_chunk);
157 fragment_key_chunk = g_mem_chunk_new("fragment_key_chunk",
158 sizeof(fragment_key),
159 fragment_init_count * sizeof(fragment_key),
161 fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk",
162 sizeof(fragment_data),
163 fragment_init_count * sizeof(fragment_data),
168 * This function adds a new fragment to the fragment hash table.
169 * If this is the first fragment seen for this datagram, a new entry
170 * is created in the hash table, otherwise this fragment is just added
171 * to the linked list of fragments for this packet.
172 * The list of fragments for a specific datagram is kept sorted for
175 * Returns a pointer to the head of the fragment data list if we have all the
176 * fragments, NULL otherwise.
179 fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
180 GHashTable *fragment_table, guint32 frag_offset,
181 guint32 frag_data_len, gboolean more_frags)
183 fragment_key key, *new_key;
184 fragment_data *fd_head;
189 /* create key to search hash with */
190 key.src = pinfo->src;
191 key.dst = pinfo->dst;
194 fd_head = g_hash_table_lookup(fragment_table, &key);
196 /* have we already seen this frame ?*/
197 if (pinfo->fd->flags.visited) {
198 if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) {
206 /* not found, this must be the first snooped fragment for this
207 * packet. Create list-head.
209 fd_head=g_mem_chunk_alloc(fragment_data_chunk);
210 /* head/first structure in list only holds no other data than
211 * 'datalen' then we don't have to change the head of the list
212 * even if we want to keep it sorted
222 * We're going to use the key to insert the fragment,
223 * so allocate a structure for it, and copy the
224 * addresses, allocating new buffers for the address
227 new_key = g_mem_chunk_alloc(fragment_key_chunk);
228 COPY_ADDRESS(&new_key->src, &key.src);
229 COPY_ADDRESS(&new_key->dst, &key.dst);
230 new_key->id = key.id;
231 g_hash_table_insert(fragment_table, new_key, fd_head);
234 /* create new fd describing this fragment */
235 fd = g_mem_chunk_alloc(fragment_data_chunk);
238 fd->frame = pinfo->fd->num;
239 fd->offset = frag_offset;
240 fd->len = frag_data_len;
245 * This is the tail fragment in the sequence.
247 if (fd_head->datalen) {
248 /* ok we have already seen other tails for this packet
249 * it might be a duplicate.
251 if (fd_head->datalen != (fd->offset + fd->len) ){
252 /* Oops, this tail indicates a different packet
253 * len than the previous ones. Somethings wrong
255 fd->flags |= FD_MULTIPLETAILS;
256 fd_head->flags |= FD_MULTIPLETAILS;
259 /* this was the first tail fragment, now we know the
260 * length of the packet
262 fd_head->datalen = fd->offset + fd->len;
269 /* If the packet is already defragmented, this MUST be an overlap.
270 * The entire defragmented packet is in fd_head->data
271 * Even if we have previously defragmented this packet, we still check
272 * check it. Someone might play overlap and TTL games.
274 if (fd_head->flags & FD_DEFRAGMENTED) {
275 fd->flags |= FD_OVERLAP;
276 fd_head->flags |= FD_OVERLAP;
277 /* make sure its not too long */
278 if (fd->offset + fd->len > fd_head->datalen) {
279 fd->flags |= FD_TOOLONGFRAGMENT;
280 fd_head->flags |= FD_TOOLONGFRAGMENT;
281 LINK_FRAG(fd_head,fd);
284 /* make sure it doesnt conflict with previous data */
285 if ( memcmp(fd_head->data+fd->offset,
286 tvb_get_ptr(tvb,offset,fd->len),fd->len) ){
287 fd->flags |= FD_OVERLAPCONFLICT;
288 fd_head->flags |= FD_OVERLAPCONFLICT;
289 LINK_FRAG(fd_head,fd);
292 /* it was just an overlap, link it and return */
293 LINK_FRAG(fd_head,fd);
299 /* If we have reached this point, the packet is not defragmented yet.
300 * Save all payload in a buffer until we can defragment.
301 * XXX - what if we didn't capture the entire fragment due
302 * to a too-short snapshot length?
304 fd->data = g_malloc(fd->len);
305 tvb_memcpy(tvb, fd->data, offset, fd->len);
306 LINK_FRAG(fd_head,fd);
309 if( !(fd_head->datalen) ){
310 /* if we dont know the datalen, there are still missing
311 * packets. Cheaper than the check below.
317 /* check if we have received the entire fragment
318 * this is easy since the list is sorted and the head is faked.
321 for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
322 if ( ((fd_i->offset)<=max) &&
323 ((fd_i->offset+fd_i->len)>max) ){
324 max = fd_i->offset+fd_i->len;
328 if (max < (fd_head->datalen)) {
329 /* we have not received all packets yet */
334 if (max > (fd_head->datalen)) {
335 /* oops, too long fragment detected */
336 fd->flags |= FD_TOOLONGFRAGMENT;
337 fd_head->flags |= FD_TOOLONGFRAGMENT;
341 /* we have received an entire packet, defragment it and
344 fd_head->data = g_malloc(max);
346 /* add all data fragments */
347 for (dfpos=0,fd_i=fd_head;fd_i;fd_i=fd_i->next) {
349 if (fd_i->offset < dfpos) {
350 fd_i->flags |= FD_OVERLAP;
351 fd_head->flags |= FD_OVERLAP;
352 if ( memcmp(fd_head->data+fd_i->offset,
354 MIN(fd_i->len,(dfpos-fd_i->offset))
356 fd_i->flags |= FD_OVERLAPCONFLICT;
357 fd_head->flags |= FD_OVERLAPCONFLICT;
360 memcpy(fd_head->data+fd_i->offset,fd_i->data,fd_i->len);
364 dfpos=MAX(dfpos,(fd_i->offset+fd_i->len));
368 /* mark this packet as defragmented.
369 allows us to skip any trailing fragments */
370 fd_head->flags |= FD_DEFRAGMENTED;