1 /* conversation.c
2  * Routines for building lists of packets that are part of a "conversation"
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "config.h"
12 
13 #include <string.h>
14 #include <glib.h>
15 #include "packet.h"
16 #include "to_str.h"
17 #include "conversation.h"
18 
19 /* define DEBUG_CONVERSATION for pretty debug printing */
20 /* #define DEBUG_CONVERSATION */
21 #include "conversation_debug.h"
22 
23 #ifdef DEBUG_CONVERSATION
24 int _debug_conversation_indent = 0;
25 #endif
26 
27 struct endpoint {
28 	address addr1;
29 	address addr2;
30 	endpoint_type etype;
31 	guint32 port1;
32 	guint32 port2;
33 	guint options;
34 };
35 
36 struct conversation_key {
37 	struct conversation_key *next;
38 	address	addr1;
39 	address	addr2;
40 	endpoint_type etype;
41 	guint32	port1;
42 	guint32	port2;
43 };
44 
45 /*
46  * Hash table for conversations with no wildcards.
47  */
48 static wmem_map_t *conversation_hashtable_exact = NULL;
49 
50 /*
51  * Hash table for conversations with one wildcard address.
52  */
53 static wmem_map_t *conversation_hashtable_no_addr2 = NULL;
54 
55 /*
56  * Hash table for conversations with one wildcard port.
57  */
58 static wmem_map_t *conversation_hashtable_no_port2 = NULL;
59 
60 /*
61  * Hash table for conversations with one wildcard address and port.
62  */
63 static wmem_map_t *conversation_hashtable_no_addr2_or_port2 = NULL;
64 
65 
66 static guint32 new_index;
67 
68 /*
69  * Placeholder for address-less conversations.
70  */
71 static address null_address_ = ADDRESS_INIT_NONE;
72 
73 
74 /*
75  * Creates a new conversation with known endpoints based on a conversation
76  * created with the CONVERSATION_TEMPLATE option while keeping the
77  * conversation created with the CONVERSATION_TEMPLATE option so it can still
78  * match future connections.
79  *
80  * Passing a pointer to a conversation whose options mask does not include
81  * CONVERSATION_TEMPLATE or where the conversation's protocol type (ptype)
82  * indicates a non-connnection oriented protocol will return the conversation
83  * without changes.
84  *
85  * addr2 and port2 are used in the function if their respective conversation
86  * options bits are set (NO_ADDR2 and NO_PORT2).
87  */
88 static conversation_t *
conversation_create_from_template(conversation_t * conversation,const address * addr2,const guint32 port2)89 conversation_create_from_template(conversation_t *conversation, const address *addr2, const guint32 port2)
90 {
91 	/*
92 	 * Add a new conversation and keep the conversation template only if the
93 	 * CONVERSATION_TEMPLATE bit is set for a connection oriented protocol.
94 	 */
95 	if (conversation->options & CONVERSATION_TEMPLATE &&
96 	    conversation->key_ptr->etype != ENDPOINT_UDP)
97 	{
98 		/*
99 		 * Set up a new options mask where the conversation template bit and the
100 		 * bits for absence of a second address and port pair have been removed.
101 		 */
102 		conversation_t *new_conversation_from_template;
103 		guint options = conversation->options & ~(CONVERSATION_TEMPLATE | NO_ADDR2 | NO_PORT2);
104 
105 		/*
106 		 * Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask?
107 		 */
108 		if (conversation->options & NO_ADDR2 &&
109 		    conversation->options & NO_PORT2)
110 		{
111 			/*
112 			 * The conversation template was created without knowledge of both
113 			 * the second address as well as the second port. Create a new
114 			 * conversation with new 2nd address and 2nd port.
115 			 */
116 			new_conversation_from_template =
117 				conversation_new(conversation->setup_frame,
118 						 &conversation->key_ptr->addr1, addr2,
119 						 conversation->key_ptr->etype, conversation->key_ptr->port1,
120 						 port2, options);
121 		}
122 		else if (conversation->options & NO_PORT2)
123 		{
124 			/*
125 			 * The conversation template was created without knowledge of port 2
126 			 * only. Create a new conversation with new 2nd port.
127 			 */
128 			new_conversation_from_template =
129 				conversation_new(conversation->setup_frame,
130 						 &conversation->key_ptr->addr1, &conversation->key_ptr->addr2,
131 						 conversation->key_ptr->etype, conversation->key_ptr->port1,
132 						 port2, options);
133 		}
134 		else if (conversation->options & NO_ADDR2)
135 		{
136 			/*
137 			 * The conversation template was created without knowledge of address
138 			 * 2. Create a new conversation with new 2nd address.
139 			 */
140 			new_conversation_from_template =
141 				conversation_new(conversation->setup_frame,
142 						 &conversation->key_ptr->addr1, addr2,
143 						 conversation->key_ptr->etype, conversation->key_ptr->port1,
144 						 conversation->key_ptr->port2, options);
145 		}
146 		else
147 		{
148 			/*
149 			 * The CONVERSATION_TEMPLATE bit was set, but no other bit that the
150 			 * CONVERSATION_TEMPLATE bit controls is active. Just return the old
151 			 * conversation.
152 			 */
153 			return conversation;
154 		}
155 
156 		/*
157 		 * Set the protocol dissector used for the template conversation as
158 		 * the handler of the new conversation as well.
159 		 */
160 		new_conversation_from_template->dissector_tree = conversation->dissector_tree;
161 
162 		return new_conversation_from_template;
163 	}
164 	else
165 	{
166 		return conversation;
167 	}
168 }
169 
170 /*
171  * Compute the hash value for two given address/port pairs if the match
172  * is to be exact.
173  */
174 /* https://web.archive.org/web/20070615045827/http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
175  * (formerly at http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing)
176  * One-at-a-Time hash
177  */
178 guint
conversation_hash_exact(gconstpointer v)179 conversation_hash_exact(gconstpointer v)
180 {
181 	const conversation_key_t key = (const conversation_key_t)v;
182 	guint hash_val;
183 	address tmp_addr;
184 
185 	hash_val = 0;
186 	tmp_addr.len  = 4;
187 
188 	hash_val = add_address_to_hash(hash_val, &key->addr1);
189 
190 	tmp_addr.data = &key->port1;
191 	hash_val = add_address_to_hash(hash_val, &tmp_addr);
192 
193 	hash_val = add_address_to_hash(hash_val, &key->addr2);
194 
195 	tmp_addr.data = &key->port2;
196 	hash_val = add_address_to_hash(hash_val, &tmp_addr);
197 
198 	hash_val += ( hash_val << 3 );
199 	hash_val ^= ( hash_val >> 11 );
200 	hash_val += ( hash_val << 15 );
201 
202 	return hash_val;
203 }
204 
205 /*
206  * Compare two conversation keys for an exact match.
207  */
208 static gint
conversation_match_exact(gconstpointer v,gconstpointer w)209 conversation_match_exact(gconstpointer v, gconstpointer w)
210 {
211 	const conversation_key_t v1 = (const conversation_key_t)v;
212 	const conversation_key_t v2 = (const conversation_key_t)w;
213 
214 	if (v1->etype != v2->etype)
215 		return 0;	/* different types of port */
216 
217 	/*
218 	 * Are the first and second port 1 values the same, the first and
219 	 * second port 2 values the same, the first and second address
220 	 * 1 values the same, and the first and second address 2 values
221 	 * the same?
222 	 */
223 	if (v1->port1 == v2->port1 &&
224 	    v1->port2 == v2->port2 &&
225 	    addresses_equal(&v1->addr1, &v2->addr1) &&
226 	    addresses_equal(&v1->addr2, &v2->addr2)) {
227 		/*
228 		 * Yes.  It's the same conversation, and the two
229 		 * address/port pairs are going in the same direction.
230 		 */
231 		return 1;
232 	}
233 
234 	/*
235 	 * Is the first port 2 the same as the second port 1, the first
236 	 * port 1 the same as the second port 2, the first address 2
237 	 * the same as the second address 1, and the first address 1
238 	 * the same as the second address 2?
239 	 */
240 	if (v1->port2 == v2->port1 &&
241 	    v1->port1 == v2->port2 &&
242 	    addresses_equal(&v1->addr2, &v2->addr1) &&
243 	    addresses_equal(&v1->addr1, &v2->addr2)) {
244 		/*
245 		 * Yes.  It's the same conversation, and the two
246 		 * address/port pairs are going in opposite directions.
247 		 */
248 		return 1;
249 	}
250 
251 	/*
252 	 * The addresses or the ports don't match.
253 	 */
254 	return 0;
255 }
256 
257 /*
258  * Compute the hash value for two given address/port pairs if the match
259  * has a wildcard address 2.
260  */
261 static guint
conversation_hash_no_addr2(gconstpointer v)262 conversation_hash_no_addr2(gconstpointer v)
263 {
264 	const conversation_key_t key = (const conversation_key_t)v;
265 	guint hash_val;
266 	address tmp_addr;
267 
268 	hash_val = 0;
269 	tmp_addr.len  = 4;
270 
271 	hash_val = add_address_to_hash(hash_val, &key->addr1);
272 
273 	tmp_addr.data = &key->port1;
274 	hash_val = add_address_to_hash(hash_val, &tmp_addr);
275 
276 	tmp_addr.data = &key->port2;
277 	hash_val = add_address_to_hash(hash_val, &tmp_addr);
278 
279 	hash_val += ( hash_val << 3 );
280 	hash_val ^= ( hash_val >> 11 );
281 	hash_val += ( hash_val << 15 );
282 
283 	return hash_val;
284 }
285 
286 /*
287  * Compare two conversation keys, except for the address 2 value.
288  * We don't check both directions of the conversation - the routine
289  * doing the hash lookup has to do two searches, as the hash key
290  * will be different for the two directions.
291  */
292 static gint
conversation_match_no_addr2(gconstpointer v,gconstpointer w)293 conversation_match_no_addr2(gconstpointer v, gconstpointer w)
294 {
295 	const conversation_key_t v1 = (const conversation_key_t)v;
296 	const conversation_key_t v2 = (const conversation_key_t)w;
297 
298 	if (v1->etype != v2->etype)
299 		return 0;	/* different types of port */
300 
301 	/*
302 	 * Are the first and second port 1 values the same, the first and
303 	 * second port 2 valuess the same, and the first and second
304 	 * address 1 values the same?
305 	 */
306 	if (v1->port1 == v2->port1 &&
307 	    v1->port2 == v2->port2 &&
308 	    addresses_equal(&v1->addr1, &v2->addr1)) {
309 		/*
310 		 * Yes.  It's the same conversation, and the two
311 		 * address/port pairs are going in the same direction.
312 		 */
313 		return 1;
314 	}
315 
316 	/*
317 	 * The addresses or the ports don't match.
318 	 */
319 	return 0;
320 }
321 
322 /*
323  * Compute the hash value for two given address/port pairs if the match
324  * has a wildcard port 2.
325  */
326 static guint
conversation_hash_no_port2(gconstpointer v)327 conversation_hash_no_port2(gconstpointer v)
328 {
329 	const conversation_key_t key = (const conversation_key_t)v;
330 	guint hash_val;
331 	address tmp_addr;
332 
333 	hash_val = 0;
334 	tmp_addr.len  = 4;
335 
336 	hash_val = add_address_to_hash(hash_val, &key->addr1);
337 
338 	tmp_addr.data = &key->port1;
339 	hash_val = add_address_to_hash(hash_val, &tmp_addr);
340 
341 	hash_val = add_address_to_hash(hash_val, &key->addr2);
342 
343 	hash_val += ( hash_val << 3 );
344 	hash_val ^= ( hash_val >> 11 );
345 	hash_val += ( hash_val << 15 );
346 
347 	return hash_val;
348 }
349 
350 /*
351  * Compare two conversation keys, except for the port 2 value.
352  * We don't check both directions of the conversation - the routine
353  * doing the hash lookup has to do two searches, as the hash key
354  * will be different for the two directions.
355  */
356 static gint
conversation_match_no_port2(gconstpointer v,gconstpointer w)357 conversation_match_no_port2(gconstpointer v, gconstpointer w)
358 {
359 	const conversation_key_t v1 = (const conversation_key_t)v;
360 	const conversation_key_t v2 = (const conversation_key_t)w;
361 
362 	if (v1->etype != v2->etype)
363 		return 0;	/* different types of port */
364 
365 	/*
366 	 * Are the first and second port 1 values the same, the first and
367 	 * second address 1 values the same, and the first and second
368 	 * address 2 values the same?
369 	 */
370 	if (v1->port1 == v2->port1 &&
371 	    addresses_equal(&v1->addr1, &v2->addr1) &&
372 	    addresses_equal(&v1->addr2, &v2->addr2)) {
373 		/*
374 		 * Yes.  It's the same conversation, and the two
375 		 * address/port pairs are going in the same direction.
376 		 */
377 		return 1;
378 	}
379 
380 	/*
381 	 * The addresses or the ports don't match.
382 	 */
383 	return 0;
384 }
385 
386 /*
387  * Compute the hash value for two given address/port pairs if the match
388  * has a wildcard address 2 and port 2.
389  */
390 static guint
conversation_hash_no_addr2_or_port2(gconstpointer v)391 conversation_hash_no_addr2_or_port2(gconstpointer v)
392 {
393 	const conversation_key_t key = (const conversation_key_t)v;
394 	guint hash_val;
395 	address tmp_addr;
396 
397 	hash_val = 0;
398 	tmp_addr.len  = 4;
399 
400 	hash_val = add_address_to_hash(hash_val, &key->addr1);
401 
402 	tmp_addr.data = &key->port1;
403 	hash_val = add_address_to_hash(hash_val, &tmp_addr);
404 
405 	hash_val += ( hash_val << 3 );
406 	hash_val ^= ( hash_val >> 11 );
407 	hash_val += ( hash_val << 15 );
408 
409 	return hash_val;
410 }
411 
412 /*
413  * Compare the address 1 and port 1 in the two conversation keys.
414  * We don't check both directions of the conversation - the routine
415  * doing the hash lookup has to do two searches, as the hash key
416  * will be different for the two directions.
417  */
418 static gint
conversation_match_no_addr2_or_port2(gconstpointer v,gconstpointer w)419 conversation_match_no_addr2_or_port2(gconstpointer v, gconstpointer w)
420 {
421 	const conversation_key_t v1 = (const conversation_key_t)v;
422 	const conversation_key_t v2 = (const conversation_key_t)w;
423 
424 	if (v1->etype != v2->etype)
425 		return 0;	/* different types of port */
426 
427 	/*
428 	 * Are the first and second port 1 values the same and the first
429 	 * and second address 1 values the same?
430 	 */
431 	if (v1->port1 == v2->port1 &&
432 	    addresses_equal(&v1->addr1, &v2->addr1)) {
433 		/*
434 		 * Yes.  It's the same conversation, and the two
435 		 * address/port pairs are going in the same direction.
436 		 */
437 		return 1;
438 	}
439 
440 	/*
441 	 * The addresses or the ports don't match.
442 	 */
443 	return 0;
444 }
445 
446 /**
447  * Create a new hash tables for conversations.
448  */
449 void
conversation_init(void)450 conversation_init(void)
451 {
452 	/*
453 	 * Free up any space allocated for conversation protocol data
454 	 * areas.
455 	 *
456 	 * We can free the space, as the structures it contains are
457 	 * pointed to by conversation data structures that were freed
458 	 * above.
459 	 */
460 	conversation_hashtable_exact =
461 	    wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_exact,
462 	      conversation_match_exact);
463 	conversation_hashtable_no_addr2 =
464 	    wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2,
465 	      conversation_match_no_addr2);
466 	conversation_hashtable_no_port2 =
467 	    wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_port2,
468 	      conversation_match_no_port2);
469 	conversation_hashtable_no_addr2_or_port2 =
470 	    wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2_or_port2,
471 	      conversation_match_no_addr2_or_port2);
472 
473 }
474 
475 /**
476  * Initialize some variables every time a file is loaded or re-loaded.
477  */
conversation_epan_reset(void)478 void conversation_epan_reset(void)
479 {
480 	/*
481 	 * Start the conversation indices over at 0.
482 	 */
483 	new_index = 0;
484 }
485 
486 /*
487  * Does the right thing when inserting into one of the conversation hash tables,
488  * taking into account ordering and hash chains and all that good stuff.
489  *
490  * Mostly adapted from the old conversation_new().
491  */
492 static void
conversation_insert_into_hashtable(wmem_map_t * hashtable,conversation_t * conv)493 conversation_insert_into_hashtable(wmem_map_t *hashtable, conversation_t *conv)
494 {
495 	conversation_t *chain_head, *chain_tail, *cur, *prev;
496 
497 	chain_head = (conversation_t *)wmem_map_lookup(hashtable, conv->key_ptr);
498 
499 	if (NULL==chain_head) {
500 		/* New entry */
501 		conv->next = NULL;
502 		conv->last = conv;
503 		wmem_map_insert(hashtable, conv->key_ptr, conv);
504 		DPRINT(("created a new conversation chain"));
505 	}
506 	else {
507 		/* There's an existing chain for this key */
508 		DPRINT(("there's an existing conversation chain"));
509 
510 		chain_tail = chain_head->last;
511 
512 		if (conv->setup_frame >= chain_tail->setup_frame) {
513 			/* This convo belongs at the end of the chain */
514 			conv->next = NULL;
515 			conv->last = NULL;
516 			chain_tail->next = conv;
517 			chain_head->last = conv;
518 		}
519 		else {
520 			/* Loop through the chain to find the right spot */
521 			cur = chain_head;
522 			prev = NULL;
523 
524 			for (; (conv->setup_frame > cur->setup_frame) && cur->next; prev=cur, cur=cur->next)
525 				;
526 
527 			if (NULL==prev) {
528 				/* Changing the head of the chain */
529 				conv->next = chain_head;
530 				conv->last = chain_tail;
531 				chain_head->last = NULL;
532 				wmem_map_insert(hashtable, conv->key_ptr, conv);
533 			}
534 			else {
535 				/* Inserting into the middle of the chain */
536 				conv->next = cur;
537 				conv->last = NULL;
538 				prev->next = conv;
539 			}
540 		}
541 	}
542 }
543 
544 /*
545  * Does the right thing when removing from one of the conversation hash tables,
546  * taking into account ordering and hash chains and all that good stuff.
547  */
548 static void
conversation_remove_from_hashtable(wmem_map_t * hashtable,conversation_t * conv)549 conversation_remove_from_hashtable(wmem_map_t *hashtable, conversation_t *conv)
550 {
551 	conversation_t *chain_head, *cur, *prev;
552 
553 	chain_head = (conversation_t *)wmem_map_lookup(hashtable, conv->key_ptr);
554 
555 	if (conv == chain_head) {
556 		/* We are currently the front of the chain */
557 		if (NULL == conv->next) {
558 			/* We are the only conversation in the chain, no need to
559 			 * update next pointer, but do not call
560 			 * wmem_map_remove() either because the conv data
561 			 * will be re-inserted. */
562 			wmem_map_steal(hashtable, conv->key_ptr);
563 		}
564 		else {
565 			/* Update the head of the chain */
566 			chain_head = conv->next;
567 			chain_head->last = conv->last;
568 
569 			if (conv->latest_found == conv)
570 				chain_head->latest_found = NULL;
571 			else
572 				chain_head->latest_found = conv->latest_found;
573 
574 			wmem_map_insert(hashtable, chain_head->key_ptr, chain_head);
575 		}
576 	}
577 	else {
578 		/* We are not the front of the chain. Loop through to find us.
579 		 * Start loop at chain_head->next rather than chain_head because
580 		 * we already know we're not at the head. */
581 		cur = chain_head->next;
582 		prev = chain_head;
583 
584 		for (; (cur != conv) && cur->next; prev=cur, cur=cur->next)
585 			;
586 
587 		if (cur != conv) {
588 			/* XXX: Conversation not found. Wrong hashtable? */
589 			return;
590 		}
591 
592 		prev->next = conv->next;
593 
594 		if (NULL == conv->next) {
595 			/* We're at the very end of the list. */
596 			chain_head->last = prev;
597 		}
598 
599 		if (chain_head->latest_found == conv)
600 			chain_head->latest_found = prev;
601 	}
602 }
603 
604 /*
605  * Given two address/port pairs for a packet, create a new conversation
606  * to contain packets between those address/port pairs.
607  *
608  * The options field is used to specify whether the address 2 value
609  * and/or port 2 value are not given and any value is acceptable
610  * when searching for this conversation.
611  */
612 conversation_t *
conversation_new(const guint32 setup_frame,const address * addr1,const address * addr2,const endpoint_type etype,const guint32 port1,const guint32 port2,const guint options)613 conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2,
614     const endpoint_type etype, const guint32 port1, const guint32 port2, const guint options)
615 {
616 /*
617 	DISSECTOR_ASSERT(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
618 				"A conversation template may not be constructed without wildcard options");
619 */
620 	wmem_map_t* hashtable;
621 	conversation_t *conversation=NULL;
622 	conversation_key_t new_key;
623 
624 #ifdef DEBUG_CONVERSATION
625 	gchar *addr1_str, *addr2_str;
626 	if (addr1 == NULL) {
627 		/*
628 		 * No address 1.
629 		 */
630 		if (options & NO_ADDR2) {
631 			/*
632 			 * Neither address 1 nor address 2.
633 			 */
634 			if (options & NO_PORT2) {
635 				/*
636 				 * Port 1 but not port 2.
637 				 */
638 				DPRINT(("creating conversation for frame #%u: ID %u (etype=%d)",
639 					    setup_frame, port1, etype));
640 			} else {
641 				/*
642 				 * Ports 1 and 2.
643 				 */
644 				DPRINT(("creating conversation for frame #%u: %u -> %u (etype=%d)",
645 					    setup_frame, port1, port2, etype));
646 			}
647 		} else {
648 			/*
649 			 * Address 2 but not address 1.
650 			 */
651 			addr2_str = address_to_str(NULL, addr2);
652 			if (options & NO_PORT2) {
653 				/*
654 				 * Port 1 but not port 2.
655 				 */
656 				DPRINT(("creating conversation for frame #%u: ID %u, address %s (etype=%d)",
657 					    setup_frame, port1, addr2_str, etype));
658 			} else {
659 				/*
660 				 * Ports 1 and 2.
661 				 */
662 				DPRINT(("creating conversation for frame #%u: %u -> %s:%u (etype=%d)",
663 					    setup_frame, port1, addr2_str, port2, etype));
664 			}
665 			wmem_free(NULL, addr2_str);
666 		}
667 	} else {
668 		/*
669 		 * Address 1.
670 		 */
671 		addr1_str = address_to_str(NULL, addr1);
672 		if (options & NO_ADDR2) {
673 			/*
674 			 * Address 1 but no address 2.
675 			 */
676 			if (options & NO_PORT2) {
677 				/*
678 				 * Port 1 but not port 2.
679 				 */
680 				DPRINT(("creating conversation for frame #%u: %s:%u (etype=%d)",
681 					    setup_frame, addr1_str, port1, etype));
682 			} else {
683 				/*
684 				 * Ports 1 and 2.
685 				 */
686 				DPRINT(("creating conversation for frame #%u: %s:%u -> %u (etype=%d)",
687 					    setup_frame, addr1_str, port1, port2, etype));
688 			}
689 		} else {
690 			/*
691 			 * Addresses 1 and 2.
692 			 */
693 			addr2_str = address_to_str(NULL, addr2);
694 			if (options & NO_PORT2) {
695 				/*
696 				 * Port 1 but not port 2.
697 				 */
698 				DPRINT(("creating conversation for frame #%u: %s:%u -> %s (etype=%d)",
699 					    setup_frame, addr1_str, port1, addr2_str, etype));
700 			} else {
701 				/*
702 				 * Ports 1 and 2.
703 				 */
704 				DPRINT(("creating conversation for frame #%u: %s:%u -> %s:%u (etype=%d)",
705 					    setup_frame, addr1_str, port1, addr2_str, port2, etype));
706 			}
707 			wmem_free(NULL, addr2_str);
708 		}
709 		wmem_free(NULL, addr1_str);
710 	}
711 #endif
712 
713 	if (options & NO_ADDR2) {
714 		if (options & (NO_PORT2|NO_PORT2_FORCE)) {
715 			hashtable = conversation_hashtable_no_addr2_or_port2;
716 		} else {
717 			hashtable = conversation_hashtable_no_addr2;
718 		}
719 	} else {
720 		if (options & (NO_PORT2|NO_PORT2_FORCE)) {
721 			hashtable = conversation_hashtable_no_port2;
722 		} else {
723 			hashtable = conversation_hashtable_exact;
724 		}
725 	}
726 
727 	new_key = wmem_new(wmem_file_scope(), struct conversation_key);
728 	if (addr1 != NULL) {
729 		copy_address_wmem(wmem_file_scope(), &new_key->addr1, addr1);
730 	} else {
731 		clear_address(&new_key->addr1);
732 	}
733 	if (addr2 != NULL) {
734 		copy_address_wmem(wmem_file_scope(), &new_key->addr2, addr2);
735 	} else {
736 		clear_address(&new_key->addr2);
737 	}
738 	new_key->etype = etype;
739 	new_key->port1 = port1;
740 	new_key->port2 = port2;
741 
742 	conversation = wmem_new0(wmem_file_scope(), conversation_t);
743 
744 	conversation->conv_index = new_index;
745 	conversation->setup_frame = conversation->last_frame = setup_frame;
746 	conversation->data_list = NULL;
747 
748 	conversation->dissector_tree = wmem_tree_new(wmem_file_scope());
749 
750 	/* set the options and key pointer */
751 	conversation->options = options;
752 	conversation->key_ptr = new_key;
753 
754 	new_index++;
755 
756 	DINDENT();
757 	conversation_insert_into_hashtable(hashtable, conversation);
758 	DENDENT();
759 
760 	return conversation;
761 }
762 
conversation_new_by_id(const guint32 setup_frame,const endpoint_type etype,const guint32 id,const guint options)763 conversation_t *conversation_new_by_id(const guint32 setup_frame, const endpoint_type etype, const guint32 id, const guint options)
764 {
765 	/* Force the lack of an address or port 2 */
766 	return conversation_new(setup_frame, NULL, NULL, etype, id, 0, options | NO_ADDR2 | NO_PORT2);
767 }
768 
769 /*
770  * Set the port 2 value in a key.  Remove the original from table,
771  * update the options and port values, insert the updated key.
772  */
773 void
conversation_set_port2(conversation_t * conv,const guint32 port)774 conversation_set_port2(conversation_t *conv, const guint32 port)
775 {
776 	DISSECTOR_ASSERT_HINT(!(conv->options & CONVERSATION_TEMPLATE),
777 	    "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask");
778 
779 	DPRINT(("called for port=%d", port));
780 
781 	/*
782 	 * If the port 2 value is not wildcarded, don't set it.
783 	 */
784 	if ((!(conv->options & NO_PORT2)) || (conv->options & NO_PORT2_FORCE))
785 		return;
786 
787 	DINDENT();
788 	if (conv->options & NO_ADDR2) {
789 		conversation_remove_from_hashtable(conversation_hashtable_no_addr2_or_port2, conv);
790 	} else {
791 		conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
792 	}
793 	conv->options &= ~NO_PORT2;
794 	conv->key_ptr->port2  = port;
795 	if (conv->options & NO_ADDR2) {
796 		conversation_insert_into_hashtable(conversation_hashtable_no_addr2, conv);
797 	} else {
798 		conversation_insert_into_hashtable(conversation_hashtable_exact, conv);
799 	}
800 	DENDENT();
801 }
802 
803 /*
804  * Set the address 2 value in a key.  Remove the original from
805  * table, update the options and port values, insert the updated key.
806  */
807 void
conversation_set_addr2(conversation_t * conv,const address * addr)808 conversation_set_addr2(conversation_t *conv, const address *addr)
809 {
810 	char* addr_str;
811 	DISSECTOR_ASSERT_HINT(!(conv->options & CONVERSATION_TEMPLATE),
812 			"Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask");
813 
814 	addr_str = address_to_str(NULL, addr);
815 	DPRINT(("called for addr=%s", addr_str));
816 	wmem_free(NULL, addr_str);
817 
818 	/*
819 	 * If the address 2 value is not wildcarded, don't set it.
820 	 */
821 	if (!(conv->options & NO_ADDR2))
822 		return;
823 
824 	DINDENT();
825 	if (conv->options & NO_PORT2) {
826 		conversation_remove_from_hashtable(conversation_hashtable_no_addr2_or_port2, conv);
827 	} else {
828 		conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
829 	}
830 	conv->options &= ~NO_ADDR2;
831 	copy_address_wmem(wmem_file_scope(), &conv->key_ptr->addr2, addr);
832 	if (conv->options & NO_PORT2) {
833 		conversation_insert_into_hashtable(conversation_hashtable_no_port2, conv);
834 	} else {
835 		conversation_insert_into_hashtable(conversation_hashtable_exact, conv);
836 	}
837 	DENDENT();
838 }
839 
840 /*
841  * Search a particular hash table for a conversation with the specified
842  * {addr1, port1, addr2, port2} and set up before frame_num.
843  */
844 static conversation_t *
conversation_lookup_hashtable(wmem_map_t * hashtable,const guint32 frame_num,const address * addr1,const address * addr2,const endpoint_type etype,const guint32 port1,const guint32 port2)845 conversation_lookup_hashtable(wmem_map_t *hashtable, const guint32 frame_num, const address *addr1, const address *addr2,
846     const endpoint_type etype, const guint32 port1, const guint32 port2)
847 {
848 	conversation_t* convo=NULL;
849 	conversation_t* match=NULL;
850 	conversation_t* chain_head=NULL;
851 	struct conversation_key key;
852 
853 	/*
854 	 * We don't make a copy of the address data, we just copy the
855 	 * pointer to it, as "key" disappears when we return.
856 	 */
857 	if (addr1 != NULL) {
858 		key.addr1 = *addr1;
859 	} else {
860 		clear_address(&key.addr1);
861 	}
862 	if (addr2 != NULL) {
863 		key.addr2 = *addr2;
864 	} else {
865 		clear_address(&key.addr2);
866 	}
867 	key.etype = etype;
868 	key.port1 = port1;
869 	key.port2 = port2;
870 
871 	chain_head = (conversation_t *)wmem_map_lookup(hashtable, &key);
872 
873 	if (chain_head && (chain_head->setup_frame <= frame_num)) {
874 		match = chain_head;
875 
876 		if ((chain_head->last)&&(chain_head->last->setup_frame<=frame_num))
877 			return chain_head->last;
878 
879 		if ((chain_head->latest_found)&&(chain_head->latest_found->setup_frame<=frame_num))
880 			match = chain_head->latest_found;
881 
882 		for (convo = match; convo && convo->setup_frame <= frame_num; convo = convo->next) {
883 			if (convo->setup_frame > match->setup_frame) {
884 				match = convo;
885 			}
886 		}
887 	}
888 
889 	if (match)
890 		chain_head->latest_found = match;
891 
892 	return match;
893 }
894 
895 
896 /*
897  * Given two address/port pairs for a packet, search for a conversation
898  * containing packets between those address/port pairs.  Returns NULL if
899  * not found.
900  *
901  * We try to find the most exact match that we can, and then proceed to
902  * try wildcard matches on the "addr_b" and/or "port_b" argument if a more
903  * exact match failed.
904  *
905  * Either or both of the "addr_b" and "port_b" arguments may be specified as
906  * a wildcard by setting the NO_ADDR_B or NO_PORT_B flags in the "options"
907  * argument.  We do only wildcard matches on addresses and ports specified
908  * as wildcards.
909  *
910  * I.e.:
911  *
912  *	if neither "addr_b" nor "port_b" were specified as wildcards, we
913  *	do an exact match (addr_a/port_a and addr_b/port_b) and, if that
914  *	succeeds, we return a pointer to the matched conversation;
915  *
916  *	otherwise, if "port_b" wasn't specified as a wildcard, we try to
917  *	match any address 2 with the specified port 2 (addr_a/port_a and
918  *	{any}/port_b) and, if that succeeds, we return a pointer to the
919  *	matched conversation;
920  *
921  *	otherwise, if "addr_b" wasn't specified as a wildcard, we try to
922  *	match any port 2 with the specified address 2 (addr_a/port_a and
923  *	addr_b/{any}) and, if that succeeds, we return a pointer to the
924  *	matched conversation;
925  *
926  *	otherwise, we try to match any address 2 and any port 2
927  *	(addr_a/port_a and {any}/{any}) and, if that succeeds, we return
928  *	a pointer to the matched conversation;
929  *
930  *	otherwise, we found no matching conversation, and return NULL.
931  */
932 conversation_t *
find_conversation(const guint32 frame_num,const address * addr_a,const address * addr_b,const endpoint_type etype,const guint32 port_a,const guint32 port_b,const guint options)933 find_conversation(const guint32 frame_num, const address *addr_a, const address *addr_b, const endpoint_type etype,
934     const guint32 port_a, const guint32 port_b, const guint options)
935 {
936 	conversation_t *conversation;
937 
938 	DINSTR(gchar *addr_a_str = address_to_str(NULL, addr_a));
939 	DINSTR(gchar *addr_b_str = address_to_str(NULL, addr_b));
940 	/*
941 	 * First try an exact match, if we have two addresses and ports.
942 	 */
943 	if (!(options & (NO_ADDR_B|NO_PORT_B))) {
944 		/*
945 		 * Neither search address B nor search port B are wildcarded,
946 		 * start out with an exact match.
947 		 */
948 		DPRINT(("trying exact match: %s:%d -> %s:%d",
949 		    addr_a_str, port_a, addr_b_str, port_b));
950 		conversation =
951 		    conversation_lookup_hashtable(conversation_hashtable_exact,
952 			frame_num, addr_a, addr_b, etype,
953 			port_a, port_b);
954 		/* Didn't work, try the other direction */
955 		if (conversation == NULL) {
956 			DPRINT(("trying exact match: %s:%d -> %s:%d",
957 			    addr_b_str, port_b, addr_a_str, port_a));
958 			conversation =
959 			    conversation_lookup_hashtable(conversation_hashtable_exact,
960 				frame_num, addr_b, addr_a, etype,
961 				port_b, port_a);
962 		}
963 		if ((conversation == NULL) && (addr_a->type == AT_FC)) {
964 			/* In Fibre channel, OXID & RXID are never swapped as
965 			 * TCP/UDP ports are in TCP/IP.
966 			 */
967 			DPRINT(("trying exact match: %s:%d -> %s:%d",
968 			    addr_b_str, port_a, addr_a_str, port_b));
969 			conversation =
970 			    conversation_lookup_hashtable(conversation_hashtable_exact,
971 				frame_num, addr_b, addr_a, etype,
972 				port_a, port_b);
973 		}
974 		DPRINT(("exact match %sfound",conversation?"":"not "));
975 		if (conversation != NULL)
976 			goto end;
977 	}
978 
979 	/*
980 	 * Well, that didn't find anything.  Try matches that wildcard
981 	 * one of the addresses, if we have two ports.
982 	 */
983 	if (!(options & NO_PORT_B)) {
984 		/*
985 		 * Search port B isn't wildcarded.
986 		 *
987 		 * First try looking for a conversation with the specified
988 		 * address A and port A as the first address and port, and
989 		 * with any address and the specified port B as the second
990 		 * address and port.
991 		 * ("addr_b" doesn't take part in this lookup.)
992 		 */
993 		DPRINT(("trying wildcarded match: %s:%d -> *:%d",
994 		    addr_a_str, port_a, port_b));
995 		conversation =
996 		    conversation_lookup_hashtable(conversation_hashtable_no_addr2,
997 			frame_num, addr_a, addr_b, etype, port_a, port_b);
998 		if ((conversation == NULL) && (addr_a->type == AT_FC)) {
999 			/* In Fibre channel, OXID & RXID are never swapped as
1000 			 * TCP/UDP ports are in TCP/IP.
1001 			 */
1002 			DPRINT(("trying wildcarded match: %s:%d -> *:%d",
1003 			    addr_b_str, port_a, port_b));
1004 			conversation =
1005 			    conversation_lookup_hashtable(conversation_hashtable_no_addr2,
1006 				frame_num, addr_b, addr_a, etype,
1007 				port_a, port_b);
1008 		}
1009 		if (conversation != NULL) {
1010 			/*
1011 			 * If search address B isn't wildcarded, and this is for a
1012 			 * connection-oriented protocol, set the second address for this
1013 			 * conversation to address B, as that's the address that matched the
1014 			 * wildcarded second address for this conversation.
1015 			 *
1016 			 * (This assumes that, for all connection oriented protocols, the
1017 			 * endpoints of a connection have only one address each, i.e. you
1018 			 * don't get packets in a given direction coming from more than one
1019 			 * address, unless the CONVERSATION_TEMPLATE option is set.)
1020 			 */
1021 			DPRINT(("wildcarded dest address match found"));
1022 			if (!(conversation->options & NO_ADDR_B) && etype != ENDPOINT_UDP)
1023 			{
1024 				if (!(conversation->options & CONVERSATION_TEMPLATE))
1025 				{
1026 					conversation_set_addr2(conversation, addr_b);
1027 				}
1028 				else
1029 				{
1030 					conversation =
1031 						conversation_create_from_template(conversation, addr_b, 0);
1032 				}
1033 			}
1034 			goto end;
1035 		}
1036 
1037 		/*
1038 		 * Well, that didn't find anything.
1039 		 * If search address B was specified, try looking for a
1040 		 * conversation with the specified address B and port B as
1041 		 * the first address and port, and with any address and the
1042 		 * specified port A as the second address and port (this
1043 		 * packet may be going in the opposite direction from the
1044 		 * first packet in the conversation).
1045 		 * ("addr_a" doesn't take part in this lookup.)
1046 		 */
1047 		if (!(options & NO_ADDR_B)) {
1048 			DPRINT(("trying wildcarded match: %s:%d -> *:%d",
1049 			    addr_b_str, port_b, port_a));
1050 			conversation =
1051 			    conversation_lookup_hashtable(conversation_hashtable_no_addr2,
1052 				frame_num, addr_b, addr_a, etype, port_b, port_a);
1053 			if (conversation != NULL) {
1054 				/*
1055 				 * If this is for a connection-oriented
1056 				 * protocol, set the second address for
1057 				 * this conversation to address A, as
1058 				 * that's the address that matched the
1059 				 * wildcarded second address for this
1060 				 * conversation.
1061 				 */
1062 				DPRINT(("match found"));
1063 				if (etype != ENDPOINT_UDP) {
1064 					if (!(conversation->options & CONVERSATION_TEMPLATE))
1065 					{
1066 						conversation_set_addr2(conversation, addr_a);
1067 					}
1068 					else
1069 					{
1070 						conversation =
1071 						    conversation_create_from_template(conversation, addr_a, 0);
1072 					}
1073 				}
1074 				goto end;
1075 			}
1076 		}
1077 	}
1078 
1079 	/*
1080 	 * Well, that didn't find anything.  Try matches that wildcard
1081 	 * one of the ports, if we have two addresses.
1082 	*/
1083 	if (!(options & NO_ADDR_B)) {
1084 		/*
1085 		 * Search address B isn't wildcarded.
1086 		 *
1087 		 * First try looking for a conversation with the specified
1088 		 * address A and port A as the first address and port, and
1089 		 * with the specified address B and any port as the second
1090 		 * address and port.
1091 		 * ("port_b" doesn't take part in this lookup.)
1092 		 */
1093 		DPRINT(("trying wildcarded match: %s:%d -> %s:*",
1094 		    addr_a_str, port_a, addr_b_str));
1095 		conversation =
1096 		    conversation_lookup_hashtable(conversation_hashtable_no_port2,
1097 			frame_num, addr_a, addr_b, etype, port_a, port_b);
1098 		if ((conversation == NULL) && (addr_a->type == AT_FC)) {
1099 			/* In Fibre channel, OXID & RXID are never swapped as
1100 			 * TCP/UDP ports are in TCP/IP
1101 			 */
1102 			DPRINT(("trying wildcarded match: %s:%d -> %s:*", addr_b_str, port_a, addr_a_str));
1103 			conversation =
1104 			    conversation_lookup_hashtable(conversation_hashtable_no_port2,
1105 				frame_num, addr_b, addr_a, etype, port_a, port_b);
1106 		}
1107 		if (conversation != NULL) {
1108 			/*
1109 			 * If search port B isn't wildcarded, and this is for a connection-
1110 			 * oriented protocol, set the second port for this conversation to
1111 			 * port B, as that's the port that matched the wildcarded second port
1112 			 * for this conversation.
1113 			 *
1114 			 * (This assumes that, for all connection oriented protocols, the
1115 			 * endpoints of a connection have only one port each, i.e. you don't
1116 			 * get packets in a given direction coming from more than one port,
1117 			 * unless the CONVERSATION_TEMPLATE option is set.)
1118 			 */
1119 			DPRINT(("match found"));
1120 			if (!(conversation->options & NO_PORT_B) && etype != ENDPOINT_UDP)
1121 			{
1122 				if (!(conversation->options & CONVERSATION_TEMPLATE))
1123 				{
1124 					conversation_set_port2(conversation, port_b);
1125 				}
1126 				else
1127 				{
1128 					conversation =
1129 					    conversation_create_from_template(conversation, 0, port_b);
1130 				}
1131 			}
1132 			goto end;
1133 		}
1134 
1135 		/*
1136 		 * Well, that didn't find anything.
1137 		 * If search port B was specified, try looking for a
1138 		 * conversation with the specified address B and port B
1139 		 * as the first address and port, and with the specified
1140 		 * address A and any port as the second address and port
1141 		 * (this packet may be going in the opposite direction
1142 		 * from the first packet in the conversation).
1143 		 * ("port_a" doesn't take part in this lookup.)
1144 		 */
1145 		if (!(options & NO_PORT_B)) {
1146 			DPRINT(("trying wildcarded match: %s:%d -> %s:*",
1147 			    addr_b_str, port_b, addr_a_str));
1148 			conversation =
1149 			    conversation_lookup_hashtable(conversation_hashtable_no_port2,
1150 				frame_num, addr_b, addr_a, etype, port_b, port_a);
1151 			if (conversation != NULL) {
1152 				/*
1153 				 * If this is for a connection-oriented
1154 				 * protocol, set the second port for
1155 				 * this conversation to port A, as
1156 				 * that's the address that matched the
1157 				 * wildcarded second address for this
1158 				 * conversation.
1159 				 */
1160 				DPRINT(("match found"));
1161 				if (etype != ENDPOINT_UDP)
1162 				{
1163 					if (!(conversation->options & CONVERSATION_TEMPLATE))
1164 					{
1165 						conversation_set_port2(conversation, port_a);
1166 					}
1167 					else
1168 					{
1169 						conversation =
1170 						    conversation_create_from_template(conversation, 0, port_a);
1171 					}
1172 				}
1173 				goto end;
1174 			}
1175 		}
1176 	}
1177 
1178 	/*
1179 	 * Well, that didn't find anything.  Try matches that wildcard
1180 	 * one address/port pair.
1181 	 *
1182 	 * First try looking for a conversation with the specified address A
1183 	 * and port A as the first address and port.
1184 	 * (Neither "addr_b" nor "port_b" take part in this lookup.)
1185 	 */
1186 	DPRINT(("trying wildcarded match: %s:%d -> *:*", addr_a_str, port_a));
1187 	conversation =
1188 	    conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
1189 		frame_num, addr_a, addr_b, etype, port_a, port_b);
1190 	if (conversation != NULL) {
1191 		/*
1192 		 * If this is for a connection-oriented protocol:
1193 		 *
1194 		 * if search address B isn't wildcarded, set the
1195 		 * second address for this conversation to address
1196 		 * B, as that's the address that matched the
1197 		 * wildcarded second address for this conversation;
1198 		 *
1199 		 * if search port B isn't wildcarded, set the
1200 		 * second port for this conversation to port B,
1201 		 * as that's the port that matched the wildcarded
1202 		 * second port for this conversation.
1203 		 */
1204 		DPRINT(("match found"));
1205 		if (etype != ENDPOINT_UDP)
1206 		{
1207 			if (!(conversation->options & CONVERSATION_TEMPLATE))
1208 			{
1209 				if (!(conversation->options & NO_ADDR_B))
1210 					conversation_set_addr2(conversation, addr_b);
1211 				if (!(conversation->options & NO_PORT_B))
1212 					conversation_set_port2(conversation, port_b);
1213 			}
1214 			else
1215 			{
1216 				conversation =
1217 				    conversation_create_from_template(conversation, addr_b, port_b);
1218 			}
1219 		}
1220 		goto end;
1221 	}
1222 	/* for Infiniband, don't try to look in addresses of reverse
1223 	 * direction, because it could be another different
1224 	 * valid conversation than what is being searched using
1225 	 * addr_a, port_a.
1226 	 */
1227 	if (etype != ENDPOINT_IBQP)
1228 	{
1229 
1230 		/*
1231 		 * Well, that didn't find anything.
1232 		 * If search address and port B were specified, try looking for a
1233 		 * conversation with the specified address B and port B as the
1234 		 * first address and port, and with any second address and port
1235 		 * (this packet may be going in the opposite direction from the
1236 		 * first packet in the conversation).
1237 		 * (Neither "addr_a" nor "port_a" take part in this lookup.)
1238 		 */
1239 		if ((addr_a != NULL) && (addr_a->type == AT_FC)) {
1240 			DPRINT(("trying wildcarded match: %s:%d -> *:*",
1241 			    addr_b_str, port_a));
1242 			conversation =
1243 			    conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
1244 				frame_num, addr_b, addr_a, etype, port_a, port_b);
1245 		} else {
1246 			DPRINT(("trying wildcarded match: %s:%d -> *:*",
1247 			    addr_b_str, port_b));
1248 			conversation =
1249 			    conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
1250 				frame_num, addr_b, addr_a, etype, port_b, port_a);
1251 		}
1252 		if (conversation != NULL) {
1253 			/*
1254 			 * If this is for a connection-oriented protocol, set the
1255 			 * second address for this conversation to address A, as
1256 			 * that's the address that matched the wildcarded second
1257 			 * address for this conversation, and set the second port
1258 			 * for this conversation to port A, as that's the port
1259 			 * that matched the wildcarded second port for this
1260 			 * conversation.
1261 			 */
1262 			DPRINT(("match found"));
1263 			if (etype != ENDPOINT_UDP)
1264 			{
1265 				if (!(conversation->options & CONVERSATION_TEMPLATE))
1266 				{
1267 					conversation_set_addr2(conversation, addr_a);
1268 					conversation_set_port2(conversation, port_a);
1269 				}
1270 				else
1271 				{
1272 					conversation = conversation_create_from_template(conversation, addr_a, port_a);
1273 				}
1274 			}
1275 			goto end;
1276 		}
1277 	}
1278 	DPRINT(("no matches found"));
1279 
1280 	/*
1281 	 * We found no conversation.
1282 	 */
1283 	conversation = NULL;
1284 
1285 end:
1286 	DINSTR(wmem_free(NULL, addr_a_str));
1287 	DINSTR(wmem_free(NULL, addr_b_str));
1288 	return conversation;
1289 }
1290 
find_conversation_by_id(const guint32 frame,const endpoint_type etype,const guint32 id,const guint options)1291 conversation_t *find_conversation_by_id(const guint32 frame, const endpoint_type etype, const guint32 id, const guint options)
1292 {
1293 	/* Force the lack of a address or port B */
1294 	return find_conversation(frame, &null_address_, &null_address_, etype, id, 0, options|NO_ADDR_B|NO_PORT_B);
1295 }
1296 
1297 void
conversation_add_proto_data(conversation_t * conv,const int proto,void * proto_data)1298 conversation_add_proto_data(conversation_t *conv, const int proto, void *proto_data)
1299 {
1300 	/* Add it to the list of items for this conversation. */
1301 	if (conv->data_list == NULL)
1302 		conv->data_list = wmem_tree_new(wmem_file_scope());
1303 
1304 	wmem_tree_insert32(conv->data_list, proto, proto_data);
1305 }
1306 
1307 void *
conversation_get_proto_data(const conversation_t * conv,const int proto)1308 conversation_get_proto_data(const conversation_t *conv, const int proto)
1309 {
1310 	/* No tree created yet */
1311 	if (conv->data_list == NULL)
1312 		return NULL;
1313 
1314 	return wmem_tree_lookup32(conv->data_list, proto);
1315 }
1316 
1317 void
conversation_delete_proto_data(conversation_t * conv,const int proto)1318 conversation_delete_proto_data(conversation_t *conv, const int proto)
1319 {
1320 	if (conv->data_list != NULL)
1321 		wmem_tree_remove32(conv->data_list, proto);
1322 }
1323 
1324 void
conversation_set_dissector_from_frame_number(conversation_t * conversation,const guint32 starting_frame_num,const dissector_handle_t handle)1325 conversation_set_dissector_from_frame_number(conversation_t *conversation,
1326 	const guint32 starting_frame_num, const dissector_handle_t handle)
1327 {
1328 	wmem_tree_insert32(conversation->dissector_tree, starting_frame_num, (void *)handle);
1329 }
1330 
1331 void
conversation_set_dissector(conversation_t * conversation,const dissector_handle_t handle)1332 conversation_set_dissector(conversation_t *conversation, const dissector_handle_t handle)
1333 {
1334 	conversation_set_dissector_from_frame_number(conversation, 0, handle);
1335 }
1336 
1337 dissector_handle_t
conversation_get_dissector(conversation_t * conversation,const guint32 frame_num)1338 conversation_get_dissector(conversation_t *conversation, const guint32 frame_num)
1339 {
1340 	return (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, frame_num);
1341 }
1342 
try_conversation_call_dissector_helper(conversation_t * conversation,gboolean * dissector_success,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1343 static gboolean try_conversation_call_dissector_helper(conversation_t *conversation, gboolean* dissector_success,
1344 					tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1345 {
1346 	int ret;
1347 	dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(
1348 					conversation->dissector_tree, pinfo->num);
1349 	if (handle == NULL)
1350 		return FALSE;
1351 
1352 	ret = call_dissector_only(handle, tvb, pinfo, tree, data);
1353 
1354 	/* Let the caller decide what to do with success or rejection */
1355 	(*dissector_success) = (ret != 0);
1356 
1357 	return TRUE;
1358 }
1359 
1360 /*
1361  * Given two address/port pairs for a packet, search for a matching
1362  * conversation and, if found and it has a conversation dissector,
1363  * call that dissector and return TRUE, otherwise return FALSE.
1364  *
1365  * This helper uses call_dissector_only which will NOT call the default
1366  * "data" dissector if the packet was rejected.
1367  * Our caller is responsible to call the data dissector explicitly in case
1368  * this function returns FALSE.
1369  */
1370 gboolean
try_conversation_dissector(const address * addr_a,const address * addr_b,const endpoint_type etype,const guint32 port_a,const guint32 port_b,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data,const guint options)1371 try_conversation_dissector(const address *addr_a, const address *addr_b, const endpoint_type etype,
1372     const guint32 port_a, const guint32 port_b, tvbuff_t *tvb, packet_info *pinfo,
1373     proto_tree *tree, void* data, const guint options)
1374 {
1375 	conversation_t *conversation;
1376 	gboolean dissector_success;
1377 
1378 	/* Try each mode based on option flags */
1379 
1380 	conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, 0);
1381 	if (conversation != NULL) {
1382 		if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1383 			return dissector_success;
1384 	}
1385 
1386 	if (options & NO_ADDR_B) {
1387 		conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_ADDR_B);
1388 		if (conversation != NULL) {
1389 			if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1390 				return dissector_success;
1391 		}
1392 	}
1393 
1394 	if (options & NO_PORT_B) {
1395 		conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_PORT_B);
1396 		if (conversation != NULL) {
1397 			if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1398 				return dissector_success;
1399 		}
1400 	}
1401 
1402 	if (options & (NO_ADDR_B|NO_PORT_B)) {
1403 		conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_ADDR_B|NO_PORT_B);
1404 		if (conversation != NULL) {
1405 			if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1406 				return dissector_success;
1407 		}
1408 	}
1409 
1410 	return FALSE;
1411 }
1412 
1413 gboolean
try_conversation_dissector_by_id(const endpoint_type etype,const guint32 id,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1414 try_conversation_dissector_by_id(const endpoint_type etype, const guint32 id, tvbuff_t *tvb,
1415     packet_info *pinfo, proto_tree *tree, void* data)
1416 {
1417 	conversation_t *conversation;
1418 
1419 	conversation = find_conversation_by_id(pinfo->num, etype, id, 0);
1420 
1421 	if (conversation != NULL) {
1422 		int ret;
1423 
1424 		dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, pinfo->num);
1425 		if (handle == NULL)
1426 			return FALSE;
1427 		ret = call_dissector_only(handle, tvb, pinfo, tree, data);
1428 		if (!ret) {
1429 			/* this packet was rejected by the dissector
1430 			 * so return FALSE in case our caller wants
1431 			 * to do some cleaning up.
1432 			 */
1433 			return FALSE;
1434 		}
1435 		return TRUE;
1436 	}
1437 	return FALSE;
1438 }
1439 
1440 /**  A helper function that calls find_conversation() using data from pinfo
1441  *  The frame number and addresses are taken from pinfo.
1442  */
1443 conversation_t *
find_conversation_pinfo(packet_info * pinfo,const guint options)1444 find_conversation_pinfo(packet_info *pinfo, const guint options)
1445 {
1446 	conversation_t *conv=NULL;
1447 
1448 	DINSTR(gchar *src_str = address_to_str(NULL, &pinfo->src));
1449 	DINSTR(gchar *dst_str = address_to_str(NULL, &pinfo->dst));
1450 	DPRINT(("called for frame #%u: %s:%d -> %s:%d (ptype=%d)",
1451 		pinfo->num, src_str, pinfo->srcport,
1452 		dst_str, pinfo->destport, pinfo->ptype));
1453 	DINDENT();
1454 	DINSTR(wmem_free(NULL, src_str));
1455 	DINSTR(wmem_free(NULL, dst_str));
1456 
1457 	/* Have we seen this conversation before? */
1458 	if (pinfo->use_endpoint) {
1459 		DISSECTOR_ASSERT(pinfo->conv_endpoint);
1460 		if ((conv = find_conversation(pinfo->num, &pinfo->conv_endpoint->addr1, &pinfo->conv_endpoint->addr2,
1461 					      pinfo->conv_endpoint->etype, pinfo->conv_endpoint->port1,
1462 					      pinfo->conv_endpoint->port2, pinfo->conv_endpoint->options)) != NULL) {
1463 			DPRINT(("found previous conversation for frame #%u (last_frame=%d)",
1464 					pinfo->num, conv->last_frame));
1465 			if (pinfo->num > conv->last_frame) {
1466 				conv->last_frame = pinfo->num;
1467 			}
1468 		}
1469 	} else {
1470 		if ((conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
1471 					      conversation_pt_to_endpoint_type(pinfo->ptype), pinfo->srcport,
1472 					      pinfo->destport, options)) != NULL) {
1473 			DPRINT(("found previous conversation for frame #%u (last_frame=%d)",
1474 					pinfo->num, conv->last_frame));
1475 			if (pinfo->num > conv->last_frame) {
1476 				conv->last_frame = pinfo->num;
1477 			}
1478 		}
1479 	}
1480 
1481 	DENDENT();
1482 
1483 	return conv;
1484 }
1485 
1486 /*  A helper function that calls find_conversation() and, if a conversation is
1487  *  not found, calls conversation_new().
1488  *  The frame number and addresses are taken from pinfo.
1489  *  No options are used, though we could extend this API to include an options
1490  *  parameter.
1491  */
1492 conversation_t *
find_or_create_conversation(packet_info * pinfo)1493 find_or_create_conversation(packet_info *pinfo)
1494 {
1495 	conversation_t *conv=NULL;
1496 
1497 	/* Have we seen this conversation before? */
1498 	if ((conv = find_conversation_pinfo(pinfo, 0)) == NULL) {
1499 		/* No, this is a new conversation. */
1500 		DPRINT(("did not find previous conversation for frame #%u",
1501 				pinfo->num));
1502 		DINDENT();
1503 		conv = conversation_new(pinfo->num, &pinfo->src,
1504 					&pinfo->dst, conversation_pt_to_endpoint_type(pinfo->ptype),
1505 					pinfo->srcport, pinfo->destport, 0);
1506 		DENDENT();
1507 	}
1508 
1509 	return conv;
1510 }
1511 
1512 conversation_t *
find_or_create_conversation_by_id(packet_info * pinfo,const endpoint_type etype,const guint32 id)1513 find_or_create_conversation_by_id(packet_info *pinfo, const endpoint_type etype, const guint32 id)
1514 {
1515 	conversation_t *conv=NULL;
1516 
1517 	/* Have we seen this conversation before? */
1518 	if ((conv = find_conversation_by_id(pinfo->num, etype, id, 0)) == NULL) {
1519 		/* No, this is a new conversation. */
1520 		DPRINT(("did not find previous conversation for frame #%u",
1521 				pinfo->num));
1522 		DINDENT();
1523 		conv = conversation_new_by_id(pinfo->num, etype, id, 0);
1524 		DENDENT();
1525 	}
1526 
1527 	return conv;
1528 }
1529 
conversation_create_endpoint(struct _packet_info * pinfo,address * addr1,address * addr2,endpoint_type etype,guint32 port1,guint32 port2,const guint options)1530 void conversation_create_endpoint(struct _packet_info *pinfo, address* addr1, address* addr2,
1531     endpoint_type etype, guint32 port1, guint32	port2, const guint options)
1532 {
1533 	pinfo->conv_endpoint = wmem_new0(pinfo->pool, struct endpoint);
1534 	pinfo->use_endpoint = TRUE;
1535 
1536 	if (addr1 != NULL)
1537 		copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr1, addr1);
1538 
1539 	if (addr2 != NULL)
1540 		copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr2, addr2);
1541 
1542 	pinfo->conv_endpoint->etype = etype;
1543 	pinfo->conv_endpoint->port1 = port1;
1544 	pinfo->conv_endpoint->port2 = port2;
1545 	pinfo->conv_endpoint->options = options;
1546 }
1547 
conversation_create_endpoint_by_id(struct _packet_info * pinfo,endpoint_type etype,guint32 id,const guint options)1548 void conversation_create_endpoint_by_id(struct _packet_info *pinfo,
1549     endpoint_type etype, guint32 id, const guint options)
1550 {
1551 	/* Force the lack of a address or port B */
1552 	conversation_create_endpoint(pinfo, &null_address_, &null_address_, etype, id, 0, options|NO_ADDR_B|NO_PORT_B);
1553 }
1554 
conversation_get_endpoint_by_id(struct _packet_info * pinfo,endpoint_type etype,const guint options)1555 guint32 conversation_get_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype, const guint options)
1556 {
1557 	if (pinfo->conv_endpoint == NULL)
1558 		return 0;
1559 
1560 	if ((pinfo->conv_endpoint->etype != etype) &&
1561 	    ((options & USE_LAST_ENDPOINT) != USE_LAST_ENDPOINT))
1562 		return 0;
1563 
1564 	return pinfo->conv_endpoint->port1;
1565 }
1566 
1567 wmem_map_t *
get_conversation_hashtable_exact(void)1568 get_conversation_hashtable_exact(void)
1569 {
1570 	return conversation_hashtable_exact;
1571 }
1572 
1573 wmem_map_t *
get_conversation_hashtable_no_addr2(void)1574 get_conversation_hashtable_no_addr2(void)
1575 {
1576 	return conversation_hashtable_no_addr2;
1577 }
1578 
1579 wmem_map_t *
get_conversation_hashtable_no_port2(void)1580 get_conversation_hashtable_no_port2(void)
1581 {
1582 	return conversation_hashtable_no_port2;
1583 }
1584 
1585 wmem_map_t *
get_conversation_hashtable_no_addr2_or_port2(void)1586 get_conversation_hashtable_no_addr2_or_port2(void)
1587 {
1588 	return conversation_hashtable_no_addr2_or_port2;
1589 }
1590 
1591 address*
conversation_key_addr1(const conversation_key_t key)1592 conversation_key_addr1(const conversation_key_t key)
1593 {
1594 	return &key->addr1;
1595 }
1596 
1597 address*
conversation_key_addr2(const conversation_key_t key)1598 conversation_key_addr2(const conversation_key_t key)
1599 {
1600 	return &key->addr2;
1601 }
1602 
1603 guint32
conversation_key_port1(const conversation_key_t key)1604 conversation_key_port1(const conversation_key_t key)
1605 {
1606 	return key->port1;
1607 }
1608 
1609 guint32
conversation_key_port2(const conversation_key_t key)1610 conversation_key_port2(const conversation_key_t key)
1611 {
1612 	return key->port2;
1613 }
1614 
1615 WS_DLL_PUBLIC
conversation_pt_to_endpoint_type(port_type pt)1616 endpoint_type conversation_pt_to_endpoint_type(port_type pt)
1617 {
1618 	switch (pt)
1619 	{
1620 	case PT_NONE:
1621 		return ENDPOINT_NONE;
1622 	case PT_SCTP:
1623 		return ENDPOINT_SCTP;
1624 	case PT_TCP:
1625 		return ENDPOINT_TCP;
1626 	case PT_UDP:
1627 		return ENDPOINT_UDP;
1628 	case PT_DCCP:
1629 		return ENDPOINT_DCCP;
1630 	case PT_IPX:
1631 		return ENDPOINT_IPX;
1632 	case PT_DDP:
1633 		return ENDPOINT_DDP;
1634 	case PT_IDP:
1635 		return ENDPOINT_IDP;
1636 	case PT_USB:
1637 		return ENDPOINT_USB;
1638 	case PT_I2C:
1639 		return ENDPOINT_I2C;
1640 	case PT_IBQP:
1641 		return ENDPOINT_IBQP;
1642 	case PT_BLUETOOTH:
1643 		return ENDPOINT_BLUETOOTH;
1644 	case PT_IWARP_MPA:
1645 		return ENDPOINT_IWARP_MPA;
1646 	}
1647 
1648 	DISSECTOR_ASSERT(FALSE);
1649 	return ENDPOINT_NONE;
1650 }
1651 
1652 gchar*
conversation_get_html_hash(const conversation_key_t key)1653 conversation_get_html_hash(const conversation_key_t key)
1654 {
1655 	gchar *hash, *addr1, *addr2;
1656 
1657 	addr1 = address_to_str(NULL, &key->addr1);
1658 	addr2 = address_to_str(NULL, &key->addr2);
1659 	hash = wmem_strdup_printf(NULL, "<tr><td>%s</td><td>%d</td><td>%s</td><td>%d</td></tr>\n",
1660 				  addr1, key->port1, addr2, key->port2);
1661 	wmem_free(NULL, addr1);
1662 	wmem_free(NULL, addr2);
1663 
1664 	return hash;
1665 }
1666 
1667 /*
1668  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1669  *
1670  * Local variables:
1671  * c-basic-offset: 8
1672  * tab-width: 8
1673  * indent-tabs-mode: t
1674  * End:
1675  *
1676  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1677  * :indentSize=8:tabSize=8:noTabs=false:
1678  */
1679