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