epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / stream.c
blob097babc163074dd08b6c2604e19d653aa1637ef6
1 /* stream.c
3 * Definititions for handling circuit-switched protocols
4 * which are handled as streams, and don't have lengths
5 * and IDs such as are required for reassemble.h
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
16 #include <glib.h>
17 #include <epan/packet.h>
18 #include <epan/reassemble.h>
19 #include <epan/stream.h>
20 #include <epan/tvbuff.h>
21 #include <wsutil/ws_assert.h>
24 typedef struct {
25 fragment_head *fd_head; /* the reassembled data, NULL
26 * until we add the last fragment */
27 uint32_t pdu_number; /* Number of this PDU within the stream */
29 /* id of this pdu (globally unique) */
30 uint32_t id;
31 } stream_pdu_t;
34 struct stream_pdu_fragment
36 uint32_t len; /* the length of this fragment */
37 stream_pdu_t *pdu;
38 bool final_fragment;
41 struct stream {
42 /* the key used to add this stream to stream_hash */
43 struct stream_key *key;
45 /* pdu to add the next fragment to, or NULL if we need to start
46 * a new PDU.
48 stream_pdu_t *current_pdu;
50 /* number of PDUs added to this stream so far */
51 uint32_t pdu_counter;
53 /* the framenumber and offset of the last fragment added;
54 used for sanity-checking */
55 uint32_t lastfrag_framenum;
56 uint32_t lastfrag_offset;
60 /*****************************************************************************
62 * Stream hash
65 /* key */
66 typedef struct stream_key {
67 /* streams are attached to conversations */
68 const struct conversation *conv;
69 int p2p_dir;
70 } stream_key_t;
73 /* hash func */
74 static unsigned stream_hash_func(const void *k)
76 const stream_key_t *key = (const stream_key_t *)k;
78 return (GPOINTER_TO_UINT(key->conv)) ^ key->p2p_dir;
81 /* compare func */
82 static gboolean stream_compare_func(const void *a,
83 const void *b)
85 const stream_key_t *key1 = (const stream_key_t *)a;
86 const stream_key_t *key2 = (const stream_key_t *)b;
87 if( key1 -> p2p_dir != key2 -> p2p_dir)
88 return FALSE;
90 return (key1 -> conv == key2 -> conv );
93 /* the hash table */
94 static GHashTable *stream_hash;
97 /* cleanup reset function, call from stream_cleanup() */
98 static void cleanup_stream_hash( void ) {
99 if( stream_hash != NULL ) {
100 g_hash_table_destroy( stream_hash );
101 stream_hash = NULL;
105 /* init function, call from stream_init() */
106 static void init_stream_hash( void ) {
107 ws_assert(stream_hash==NULL);
108 stream_hash = g_hash_table_new(stream_hash_func,
109 stream_compare_func);
112 /* lookup function, returns null if not found */
113 static stream_t *stream_hash_lookup( const struct conversation *conv, int p2p_dir )
115 stream_key_t key;
116 key.conv = conv;
117 key.p2p_dir=p2p_dir;
118 return (stream_t *)g_hash_table_lookup(stream_hash, &key);
122 static stream_t *new_stream( stream_key_t *key )
124 stream_t *val;
126 val = wmem_new(wmem_file_scope(), stream_t);
127 val -> key = key;
128 val -> pdu_counter = 0;
129 val -> current_pdu = NULL;
130 val -> lastfrag_framenum = 0;
131 val -> lastfrag_offset = 0;
132 g_hash_table_insert(stream_hash, key, val);
134 return val;
138 /* insert function */
139 static stream_t *stream_hash_insert( const struct conversation *conv, int p2p_dir )
141 stream_key_t *key;
143 key = wmem_new(wmem_file_scope(), stream_key_t);
144 key->conv = conv;
145 key->p2p_dir = p2p_dir;
147 return new_stream(key);
151 /******************************************************************************
153 * PDU data
156 /* pdu counter, for generating unique pdu ids */
157 static uint32_t pdu_counter;
159 static void stream_cleanup_pdu_data(void)
163 static void stream_init_pdu_data(void)
165 pdu_counter = 0;
169 /* new pdu in this stream */
170 static stream_pdu_t *stream_new_pdu(stream_t *stream)
172 stream_pdu_t *pdu;
173 pdu = wmem_new(wmem_file_scope(), stream_pdu_t);
174 pdu -> fd_head = NULL;
175 pdu -> pdu_number = stream -> pdu_counter++;
176 pdu -> id = pdu_counter++;
177 return pdu;
180 /*****************************************************************************
182 * fragment hash
185 /* key */
186 typedef struct fragment_key {
187 const stream_t *stream;
188 uint32_t framenum;
189 uint32_t offset;
190 } fragment_key_t;
193 /* hash func */
194 static unsigned fragment_hash_func(const void *k)
196 const fragment_key_t *key = (const fragment_key_t *)k;
197 return (GPOINTER_TO_UINT(key->stream)) + ((unsigned)key -> framenum) + ((unsigned)key->offset);
200 /* compare func */
201 static gboolean fragment_compare_func(const void *a,
202 const void *b)
204 const fragment_key_t *key1 = (const fragment_key_t *)a;
205 const fragment_key_t *key2 = (const fragment_key_t *)b;
206 return (key1 -> stream == key2 -> stream &&
207 key1 -> framenum == key2 -> framenum &&
208 key1 -> offset == key2 -> offset );
211 /* the hash table */
212 static GHashTable *fragment_hash;
215 /* cleanup function, call from stream_cleanup() */
216 static void cleanup_fragment_hash( void ) {
217 if( fragment_hash != NULL ) {
218 g_hash_table_destroy( fragment_hash );
219 fragment_hash = NULL;
223 /* init function, call from stream_init() */
224 static void init_fragment_hash( void ) {
225 ws_assert(fragment_hash==NULL);
226 fragment_hash = g_hash_table_new(fragment_hash_func,
227 fragment_compare_func);
231 /* lookup function, returns null if not found */
232 static stream_pdu_fragment_t *fragment_hash_lookup( const stream_t *stream, uint32_t framenum, uint32_t offset )
234 fragment_key_t key;
235 stream_pdu_fragment_t *val;
237 key.stream = stream;
238 key.framenum = framenum;
239 key.offset = offset;
240 val = (stream_pdu_fragment_t *)g_hash_table_lookup(fragment_hash, &key);
242 return val;
246 /* insert function */
247 static stream_pdu_fragment_t *fragment_hash_insert( const stream_t *stream, uint32_t framenum, uint32_t offset,
248 uint32_t length)
250 fragment_key_t *key;
251 stream_pdu_fragment_t *val;
253 key = wmem_new(wmem_file_scope(), fragment_key_t);
254 key->stream = stream;
255 key->framenum = framenum;
256 key->offset = offset;
258 val = wmem_new(wmem_file_scope(), stream_pdu_fragment_t);
259 val->len = length;
260 val->pdu = NULL;
261 val->final_fragment = false;
263 g_hash_table_insert(fragment_hash, key, val);
264 return val;
267 /*****************************************************************************/
269 /* reassembly table */
270 static reassembly_table stream_reassembly_table;
272 /* Initialise a new stream. Call this when you first identify a distinct
273 * stream. */
274 stream_t *stream_new ( const struct conversation *conv, int p2p_dir )
276 stream_t * stream;
278 /* we don't want to replace the previous data if we get called twice on the
279 same conversation, so do a lookup first */
280 stream = stream_hash_lookup(conv, p2p_dir);
281 DISSECTOR_ASSERT( stream == NULL );
283 stream = stream_hash_insert(conv, p2p_dir);
284 return stream;
288 /* retrieve a previously-created stream.
290 * Returns null if no matching stream was found.
292 stream_t *find_stream ( const struct conversation *conv, int p2p_dir )
294 return stream_hash_lookup(conv,p2p_dir);
297 /* cleanup the stream routines */
298 /* Note: stream_cleanup must only be called when seasonal memory
299 * is also freed since the hash tables countain pointers to
300 * wmem_file_scoped memory.
302 void stream_cleanup( void )
304 cleanup_stream_hash();
305 cleanup_fragment_hash();
306 stream_cleanup_pdu_data();
307 reassembly_table_destroy(&stream_reassembly_table);
310 /* initialise the stream routines */
311 void stream_init( void )
313 init_stream_hash();
314 init_fragment_hash();
315 stream_init_pdu_data();
317 reassembly_table_init(&stream_reassembly_table,
318 &addresses_reassembly_table_functions);
321 /*****************************************************************************/
323 stream_pdu_fragment_t *stream_find_frag( stream_t *stream, uint32_t framenum, uint32_t offset )
325 return fragment_hash_lookup( stream, framenum, offset );
328 stream_pdu_fragment_t *stream_add_frag( stream_t *stream, uint32_t framenum, uint32_t offset,
329 tvbuff_t *tvb, packet_info *pinfo, bool more_frags )
331 fragment_head *fd_head;
332 stream_pdu_t *pdu;
333 stream_pdu_fragment_t *frag_data;
335 DISSECTOR_ASSERT(stream);
337 /* check that this fragment is at the end of the stream */
338 DISSECTOR_ASSERT( framenum > stream->lastfrag_framenum ||
339 (framenum == stream->lastfrag_framenum && offset > stream->lastfrag_offset));
342 pdu = stream->current_pdu;
343 if( pdu == NULL ) {
344 /* start a new pdu */
345 pdu = stream->current_pdu = stream_new_pdu(stream);
348 /* add it to the reassembly tables */
349 fd_head = fragment_add_seq_next(&stream_reassembly_table,
350 tvb, 0, pinfo, pdu->id, NULL,
351 tvb_reported_length(tvb), more_frags);
352 /* add it to our hash */
353 frag_data = fragment_hash_insert( stream, framenum, offset, tvb_reported_length(tvb));
354 frag_data -> pdu = pdu;
356 if( fd_head != NULL ) {
357 /* if this was the last fragment, update the pdu data.
359 pdu -> fd_head = fd_head;
361 /* start a new pdu next time */
362 stream->current_pdu = NULL;
364 frag_data -> final_fragment = true;
367 /* stashing the framenum and offset permit future sanity checks */
368 stream -> lastfrag_framenum = framenum;
369 stream -> lastfrag_offset = offset;
371 return frag_data;
375 tvbuff_t *stream_process_reassembled(
376 tvbuff_t *tvb, int offset, packet_info *pinfo,
377 const char *name, const stream_pdu_fragment_t *frag,
378 const struct _fragment_items *fit,
379 bool *update_col_infop, proto_tree *tree)
381 stream_pdu_t *pdu;
382 DISSECTOR_ASSERT(frag);
383 pdu = frag->pdu;
385 /* we handle non-terminal fragments ourselves, because
386 reassemble.c messes them up */
387 if(!frag->final_fragment) {
388 if (pdu->fd_head != NULL && fit->hf_reassembled_in != NULL) {
389 proto_tree_add_uint(tree,
390 *(fit->hf_reassembled_in), tvb,
391 0, 0, pdu->fd_head->reassembled_in);
393 return NULL;
396 return process_reassembled_data(tvb, offset, pinfo, name, pdu->fd_head,
397 fit, update_col_infop, tree);
400 uint32_t stream_get_frag_length( const stream_pdu_fragment_t *frag)
402 DISSECTOR_ASSERT( frag );
403 return frag->len;
406 fragment_head *stream_get_frag_data( const stream_pdu_fragment_t *frag)
408 DISSECTOR_ASSERT( frag );
409 return frag->pdu->fd_head;
412 uint32_t stream_get_pdu_no( const stream_pdu_fragment_t *frag)
414 DISSECTOR_ASSERT( frag );
415 return frag->pdu->pdu_number;
419 * Editor modelines - https://www.wireshark.org/tools/modelines.html
421 * Local variables:
422 * c-basic-offset: 4
423 * tab-width: 8
424 * indent-tabs-mode: nil
425 * End:
427 * vi: set shiftwidth=4 tabstop=8 expandtab:
428 * :indentSize=4:tabSize=8:noTabs=true: