Extend reassembly documentation

Documentation changes only (comments and docbook).

Update WSDG with the fragment_add_seq_check API that was introduced in
Wireshark 1.10.

Fix typos and clarify the many functions we have for adding reassembling
fragments.

Change-Id: I38715a8f58e9cf1fe3e34ee4b1a4ae339630282b
Reviewed-on: https://code.wireshark.org/review/14066
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Peter Wu 2016-02-22 00:54:50 +01:00 committed by Anders Broman
parent 9ff932bf5e
commit c2f85b6925
3 changed files with 111 additions and 54 deletions

View File

@ -653,6 +653,10 @@ and the subsequent packets don't have the expect format.
To dissect these packets you need to wait until all the parts have
arrived and then start the dissection.
The following sections will guide you through two common cases. For a
description of all possible functions, structures and parameters, see
'epan/reassemble.h'.
[[ChDissectReassembleUdp]]
==== How to reassemble split UDP packets
@ -699,10 +703,9 @@ if (flags & FL_FRAGMENT) { /* fragmented */
guint16 msg_num = tvb_get_ntohs(tvb, offset); offset += 2;
pinfo->fragmented = TRUE;
frag_msg = fragment_add_seq_check(tvb, offset, pinfo,
msg_seqid, /* ID for fragments belonging together */
msg_fragment_table, /* list of message fragments */
msg_reassembled_table, /* list of reassembled messages */
frag_msg = fragment_add_seq_check(msg_reassembly_table,
tvb, offset, pinfo,
msg_seqid, NULL, /* ID for fragments belonging together */
msg_num, /* fragment sequence number */
tvb_captured_length_remaining(tvb, offset), /* fragment length - to the end */
flags & FL_FRAG_LAST); /* More fragments? */
@ -713,7 +716,9 @@ We start by saving the fragmented state of this packet, so we can restore it
later. Next comes some protocol specific stuff, to dig the fragment data out of
the stream if it's present. Having decided it is present, we let the function
+fragment_add_seq_check()+ do its work. We need to provide this with a certain
amount of data.
amount of parameters:
* The +msg_reassembly_table+ table is for bookkeeping and is described later.
* The tvb buffer we are dissecting.
@ -725,8 +730,8 @@ amount of data.
fragments in flight, and this is used to key the relevant one to be used for
reassembly.
* The +msg_fragment_table+ and the +msg_reassembled_table+ are variables we need
to declare. We'll consider these in detail later.
* Optional additional data for identifying the fragment. Can be set to +NULL+
(as is done in the example) for most dissectors.
* msg_num is the packet number within the sequence.
@ -781,25 +786,29 @@ Now the mysterious data we passed into the +fragment_add_seq_check()+.
.Reassembling fragments - Initialisation
====
----
static GHashTable *msg_fragment_table = NULL;
static GHashTable *msg_reassembled_table = NULL;
static reassembly_table reassembly_table;
static void
msg_init_protocol(void)
{
fragment_table_init(&msg_fragment_table);
reassembled_table_init(&msg_reassembled_table);
reassembly_table_init(&msg_reassemble_table,
&addresses_ports_reassembly_table_functions);
}
----
====
First a couple of hash tables are declared, and these are initialised in the
protocol initialisation routine. Following that, a +fragment_items+ structure is
allocated and filled in with a series of ett items, hf data items, and a string
tag. The ett and hf values should be included in the relevant tables like all
the other variables your protocol may use. The hf variables need to be placed in
the structure something like the following. Of course the names may need to be
adjusted.
First a +reassembly_table+ structure is declared and initialised in the protocol
initialisation routine. The second parameter specifies the functions that should
be used for identifying fragments. We will use
+addresses_ports_reassembly_table_functions+ in order to identify fragments by
the given sequence number (+msg_seqid+), the source and destination addresses
and ports from the packet.
Following that, a +fragment_items+ structure is allocated and filled in with a
series of ett items, hf data items, and a string tag. The ett and hf values
should be included in the relevant tables like all the other variables your
protocol may use. The hf variables need to be placed in the structure something
like the following. Of course the names may need to be adjusted.
.Reassembling fragments - Data
====

View File

@ -1960,11 +1960,11 @@ fragment_add_seq(reassembly_table *table, tvbuff_t *tvb, const int offset,
* This function assumes frag_number being a block sequence number.
* The bsn for the first block is 0.
*
* If "no_frag_number" is TRUE, it uses the next expected fragment number
* If REASSEMBLE_FLAGS_NO_FRAG_NUMBER, it uses the next expected fragment number
* as the fragment number if there is a reassembly in progress, otherwise
* it uses 0.
*
* If "no_frag_number" is FALSE, it uses the "frag_number" argument as
* If not REASSEMBLE_FLAGS_NO_FRAG_NUMBER, it uses the "frag_number" argument as
* the fragment number.
*
* If this is the first fragment seen for this datagram, a new
@ -2077,6 +2077,8 @@ fragment_add_seq_next(reassembly_table *table, tvbuff_t *tvb, const int offset,
const void *data, const guint32 frag_data_len,
const gboolean more_frags)
{
/* Use a dummy frag_number (0), it is ignored since
* REASSEMBLE_FLAGS_NO_FRAG_NUMBER is set. */
return fragment_add_seq_check_work(table, tvb, offset, pinfo, id, data,
0, frag_data_len, more_frags,
REASSEMBLE_FLAGS_NO_FRAG_NUMBER);

View File

@ -1,5 +1,5 @@
/* reassemble.h
* Declarations of outines for {fragment,segment} reassembly
* Declarations of routines for {fragment,segment} reassembly
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
@ -77,10 +77,12 @@ typedef struct _fragment_item {
* provided fragment number of the first fragment does
* not start with 0
* XXX - does this apply only to reassembly heads? */
guint32 datalen; /**< Only valid in first item of list and when
* flags&FD_DATALEN_SET is set;
* number of bytes or (if flags&FD_BLOCKSEQUENCE set)
* segments in the datagram */
guint32 datalen; /**< When flags&FD_BLOCKSEQUENCE is set, the
index of the last block (segments in
datagram + 1); otherwise the number of
bytes of the full datagram. Only valid in
the first item of the fragments list when
flags&FD_DATALEN is set.*/
guint32 reassembled_in; /**< frame where this PDU was reassembled,
only valid in the first item of the list
and when FD_DEFRAGMENTED is set*/
@ -119,11 +121,20 @@ typedef struct _fragment_item {
* in the tvb, and if not, do something a bit odd. */
#define REASSEMBLE_FLAGS_CHECK_DATA_PRESENT 0x0004
/* a function for creating temporary hash keys */
/*
* Generates a fragment identifier based on the given parameters. "data" is an
* opaque type whose interpretation is up to the caller of fragment_add*
* functions and the fragment key function (possibly NULL if you do not care).
*
* Keys returned by this function are only used within this packet scope.
*/
typedef gpointer (*fragment_temporary_key)(const packet_info *pinfo,
const guint32 id, const void *data);
/* a function for creating persistent hash keys */
/*
* Like fragment_temporary_key, but used for identifying reassembled fragments
* which may persist through multiple packets.
*/
typedef gpointer (*fragment_persistent_key)(const packet_info *pinfo,
const guint32 id, const void *data);
@ -181,14 +192,27 @@ reassembly_table_destroy(reassembly_table *table);
* The list of fragments for a specific datagram is kept sorted for
* easier handling.
*
* Datagrams (messages) are identified by a key generated by
* fragment_temporary_key or fragment_persistent_key, based on the "pinfo", "id"
* and "data" pairs. (This is the sole purpose of "data".)
*
* Fragments are identified by "frag_offset".
*
* Returns a pointer to the head of the fragment data list if we have all the
* fragments, NULL otherwise.
* fragments, NULL otherwise. Note that the reassembled fragments list may have
* a non-zero fragment offset, the only guarantee is that no gaps exist within
* the list.
*/
WS_DLL_PUBLIC fragment_head *
fragment_add(reassembly_table *table, tvbuff_t *tvb, const int offset,
const packet_info *pinfo, const guint32 id, const void *data,
const guint32 frag_offset, const guint32 frag_data_len,
const gboolean more_frags);
/*
* Like fragment_add, except that the fragment may be added to multiple
* reassembly tables. This is needed when multiple protocol layers try
* to add the same packet to the reassembly table.
*/
WS_DLL_PUBLIC fragment_head *
fragment_add_multiple_ok(reassembly_table *table, tvbuff_t *tvb,
const int offset, const packet_info *pinfo,
@ -198,13 +222,18 @@ fragment_add_multiple_ok(reassembly_table *table, tvbuff_t *tvb,
const gboolean more_frags);
/*
* This routine extends fragment_add to use a "reassembled_table"
* included in the reassembly table.
* Like fragment_add, but maintains a table for completed reassemblies.
*
* If, after processing this fragment, we have all the fragments, they
* remove that from the fragment hash table if necessary and add it
* to the table of reassembled fragments, and return a pointer to the
* head of the fragment list.
* If the packet was seen before, return the head of the fully reassembled
* fragments list (NULL if there was none).
*
* Otherwise (if reassembly was not possible before), try to to add the new
* fragment to the fragments table. If reassembly is now possible, remove all
* (reassembled) fragments from the fragments table and store it as a completed
* reassembly. The head of this reassembled fragments list is returned.
*
* Otherwise (if reassembly is still not possible after adding this fragment),
* return NULL.
*/
WS_DLL_PUBLIC fragment_head *
fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset,
@ -212,22 +241,19 @@ fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset,
const void *data, const guint32 frag_offset,
const guint32 frag_data_len, const gboolean more_frags);
/* same as fragment_add() but this one assumes frag_number is a block
sequence number. note that frag_number is 0 for the first fragment. */
/*
* These functions add a new fragment to the fragment hash table,
* assuming that frag_number is a block sequence number (starting from zero for
* the first fragment of each datagram).
* Like fragment_add, but fragments have a block sequence number starting from
* zero (for the first fragment of each datagram). This differs from
* fragment_add for which the fragment may start at any offset.
*
* If this is the first fragment seen for this datagram, a new
* "fragment_head" structure is allocated to refer to the reassembled
* packet, and:
*
* if "more_frags" is false, and either we have no sequence numbers, or
* are using the 802.11 hack, it is assumed that this is the only fragment
* in the datagram. The structure is not added to the hash
* table, and not given any fragments to refer to, but is just returned.
* are using the 802.11 hack (via fragment_add_seq_802_11), it is assumed that
* this is the only fragment in the datagram. The structure is not added to the
* hash table, and not given any fragments to refer to, but is just returned.
*
* In this latter case reassembly wasn't done (since there was only one
* fragment in the packet); dissectors can check the 'next' pointer on the
@ -247,12 +273,8 @@ fragment_add_seq(reassembly_table *table, tvbuff_t *tvb, const int offset,
const gboolean more_frags, const guint32 flags);
/*
* These routines extend fragment_add_seq to use the "reassembled_table".
*
* If, after processing this fragment, we have all the fragments, they
* remove that from the fragment hash table if necessary and add it
* to the table of reassembled fragments, and return a pointer to the
* head of the fragment list.
* Like fragment_add_seq, but maintains a table for completed reassemblies
* just like fragment_add_check.
*/
WS_DLL_PUBLIC fragment_head *
fragment_add_seq_check(reassembly_table *table, tvbuff_t *tvb, const int offset,
@ -261,6 +283,11 @@ fragment_add_seq_check(reassembly_table *table, tvbuff_t *tvb, const int offset,
const guint32 frag_number, const guint32 frag_data_len,
const gboolean more_frags);
/*
* Like fragment_add_seq_check, but immediately returns a fragment list for a
* new fragment. This is a workaround specific for the 802.11 dissector, do not
* use it elsewhere.
*/
WS_DLL_PUBLIC fragment_head *
fragment_add_seq_802_11(reassembly_table *table, tvbuff_t *tvb,
const int offset, const packet_info *pinfo,
@ -268,17 +295,31 @@ fragment_add_seq_802_11(reassembly_table *table, tvbuff_t *tvb,
const guint32 frag_number, const guint32 frag_data_len,
const gboolean more_frags);
/*
* Like fragment_add_seq_check, but without explicit fragment number. Fragments
* are simply appended until no "more_frags" is false.
*/
WS_DLL_PUBLIC fragment_head *
fragment_add_seq_next(reassembly_table *table, tvbuff_t *tvb, const int offset,
const packet_info *pinfo, const guint32 id,
const void *data, const guint32 frag_data_len,
const gboolean more_frags);
/*
* Start a reassembly, expecting "tot_len" as the number of given fragments (not
* the number of bytes). Data can be added later using fragment_add_seq_check.
*/
WS_DLL_PUBLIC void
fragment_start_seq_check(reassembly_table *table, const packet_info *pinfo,
const guint32 id, const void *data,
const guint32 tot_len);
/*
* Mark end of reassembly and returns the reassembled fragment (if completed).
* Use it when fragments were added with "more_flags" set while you discovered
* that no more fragments have to be added.
* XXX rename to fragment_finish as it works also for fragment_add?
*/
WS_DLL_PUBLIC fragment_head *
fragment_end_seq_next(reassembly_table *table, const packet_info *pinfo,
const guint32 id, const void *data);
@ -290,18 +331,23 @@ WS_DLL_PUBLIC void
fragment_add_seq_offset(reassembly_table *table, const packet_info *pinfo, const guint32 id,
const void *data, const guint32 fragment_offset);
/* to specify how much to reassemble, for fragmentation where last fragment can not be
* identified by flags or such.
* note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment.
/*
* Sets the expected index for the last block (for fragment_add_seq functions)
* or the expected number of bytes (for fragment_add functions). A reassembly
* must already have started.
*
* Note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment.
* i.e. since the block numbers start at 0, if we specify tot_len==2, that
* actually means we want to defragment 3 blocks, block 0, 1 and 2.
*
*/
WS_DLL_PUBLIC void
fragment_set_tot_len(reassembly_table *table, const packet_info *pinfo,
const guint32 id, const void *data, const guint32 tot_len);
/* to resad whatever totlen previously set */
/*
* Return the expected index for the last block (for fragment_add_seq functions)
* or the expected number of bytes (for fragment_add functions).
*/
WS_DLL_PUBLIC guint32
fragment_get_tot_len(reassembly_table *table, const packet_info *pinfo,
const guint32 id, const void *data);