Do the checks for the presence of a conversation dissector the same way
[obnox/wireshark/wip.git] / epan / conversation.c
1 /* conversation.c
2  * Routines for building lists of packets that are part of a "conversation"
3  *
4  * $Id: conversation.c,v 1.5 2000/11/18 07:00:31 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #ifdef HAVE_NETINET_IN_H
37 # include <netinet/in.h>
38 #endif
39
40 #include <string.h>
41 #include <glib.h>
42 #include "packet.h"
43 #include "conversation.h"
44
45 /*
46  * Hash table for conversations with no wildcards.
47  */
48 static GHashTable *conversation_hashtable_exact = NULL;
49
50 /*
51  * Hash table for conversations with wildcard destination address.
52  */
53 static GHashTable *conversation_hashtable_no_dst_addr = NULL;
54
55 /*
56  * Hash table for conversations with wildcard destination port.
57  */
58 static GHashTable *conversation_hashtable_no_dst_port = NULL;
59
60 /*
61  * Hash table for conversations with wildcard destination address and port.
62  */
63 static GHashTable *conversation_hashtable_no_dst = NULL;
64
65 static GMemChunk *conversation_key_chunk = NULL;
66 static GMemChunk *conversation_chunk = NULL;
67
68 #ifdef __NOT_USED__ 
69 typedef struct conversation_key {
70         struct conversation_key *next;
71         address src;
72         address dst;
73         port_type ptype;
74         guint32 port_src;
75         guint32 port_dst;
76 } conversation_key;
77 #endif
78 /*
79  * Linked list of conversation keys, so we can, before freeing them all,
80  * free the address data allocations associated with them.
81  */
82 static conversation_key *conversation_keys;
83
84 static guint32 new_index;
85
86 static int conversation_init_count = 200;
87
88 /*
89  * Compute the hash value for a given set of source and destination
90  * addresses and ports if the match is to be exact.
91  */
92 static guint 
93 conversation_hash_exact(gconstpointer v)
94 {
95         conversation_key *key = (conversation_key *)v;
96         guint hash_val;
97         int i;
98
99         hash_val = 0;
100         for (i = 0; i < key->src.len; i++)
101                 hash_val += key->src.data[i];
102
103         hash_val += key->port_src;
104
105         for (i = 0; i < key->dst.len; i++)
106                 hash_val += key->dst.data[i];
107
108         hash_val += key->port_dst;
109
110         return hash_val;
111 }
112
113 /*
114  * Compare two conversation keys for an exact match.
115  */
116 static gint
117 conversation_match_exact(gconstpointer v, gconstpointer w)
118 {
119         conversation_key *v1 = (conversation_key *)v;
120         conversation_key *v2 = (conversation_key *)w;
121
122         if (v1->ptype != v2->ptype)
123                 return 0;       /* different types of port */
124
125         /*
126          * Are the first and second source ports the same, the first and
127          * second destination ports the same, the first and second source
128          * addresses the same, and the first and second destination
129          * addresses the same?
130          */
131         if (v1->port_src == v2->port_src &&
132             v1->port_dst == v2->port_dst &&
133             v1->src.type == v2->src.type &&
134             v1->src.len == v2->src.len &&
135             memcmp(v1->src.data, v2->src.data, v1->src.len) == 0 &&
136             v1->dst.type == v2->dst.type &&
137             v1->dst.type == v2->dst.type &&
138             v1->dst.len == v2->dst.len &&
139             memcmp(v1->dst.data, v2->dst.data, v1->dst.len) == 0) {
140                 /*
141                  * Yes.  It's the same conversation, and the two
142                  * address/port pairs are going in the same direction.
143                  */
144                 return 1;
145         }
146
147         /*
148          * Is the first destination port the same as the second source
149          * port, the first source port the same as the second destination
150          * port, the first destination address the same as the second
151          * source address, and the first source address the same as the
152          * second destination address?
153          */
154         if (v1->port_dst == v2->port_src &&
155             v1->port_src == v2->port_dst &&
156             v1->dst.type == v2->src.type &&
157             v1->dst.len == v2->src.len &&
158             memcmp(v1->dst.data, v2->src.data, v1->dst.len) == 0 &&
159             v1->src.type == v2->dst.type &&
160             v1->src.len == v2->dst.len &&
161             memcmp(v1->src.data, v2->dst.data, v1->src.len) == 0) {
162                 /*
163                  * Yes.  It's the same conversation, and the two
164                  * address/port pairs are going in opposite directions.
165                  */
166                 return 1;
167         }
168
169         /*
170          * The addresses or the ports don't match.
171          */     
172         return 0;
173 }
174
175 /*
176  * Compute the hash value for a given set of source and destination
177  * addresses and ports if the match has a wildcard destination address.
178  */
179 static guint 
180 conversation_hash_no_dst_addr(gconstpointer v)
181 {
182         conversation_key *key = (conversation_key *)v;
183         guint hash_val;
184         int i;
185
186         hash_val = 0;
187         for (i = 0; i < key->src.len; i++)
188                 hash_val += key->src.data[i];
189
190         hash_val += key->port_src;
191
192         hash_val += key->port_dst;
193
194         return hash_val;
195 }
196
197 /*
198  * Compare two conversation keys, except for the destination address.
199  * We don't check both directions of the conversation - the routine
200  * doing the hash lookup has to do two searches, as the hash key
201  * will be different for the two directions.
202  */
203 static gint
204 conversation_match_no_dst_addr(gconstpointer v, gconstpointer w)
205 {
206         conversation_key *v1 = (conversation_key *)v;
207         conversation_key *v2 = (conversation_key *)w;
208
209         if (v1->ptype != v2->ptype)
210                 return 0;       /* different types of port */
211
212         /*
213          * Are the first and second source ports the same, the first and
214          * second destination ports the same, and the first and second
215          * source addresses the same?
216          */
217         if (v1->port_src == v2->port_src &&
218             v1->port_dst == v2->port_dst &&
219             v1->src.type == v2->src.type &&
220             v1->src.len == v2->src.len &&
221             memcmp(v1->src.data, v2->src.data, v1->src.len) == 0) {
222                 /*
223                  * Yes.  It's the same conversation, and the two
224                  * address/port pairs are going in the same direction.
225                  */
226                 return 1;
227         }
228
229         /*
230          * The addresses or the ports don't match.
231          */     
232         return 0;
233 }
234
235 /*
236  * Compute the hash value for a given set of source and destination
237  * addresses and ports if the match has a wildcard destination port.
238  */
239 static guint 
240 conversation_hash_no_dst_port(gconstpointer v)
241 {
242         conversation_key *key = (conversation_key *)v;
243         guint hash_val;
244         int i;
245
246         hash_val = 0;
247         for (i = 0; i < key->src.len; i++)
248                 hash_val += key->src.data[i];
249
250         hash_val += key->port_src;
251
252         for (i = 0; i < key->dst.len; i++)
253                 hash_val += key->dst.data[i];
254
255         return hash_val;
256 }
257
258 /*
259  * Compare two conversation keys, except for the destination port.
260  * We don't check both directions of the conversation - the routine
261  * doing the hash lookup has to do two searches, as the hash key
262  * will be different for the two directions.
263  */
264 static gint
265 conversation_match_no_dst_port(gconstpointer v, gconstpointer w)
266 {
267         conversation_key *v1 = (conversation_key *)v;
268         conversation_key *v2 = (conversation_key *)w;
269
270         if (v1->ptype != v2->ptype)
271                 return 0;       /* different types of port */
272
273         /*
274          * Are the first and second source ports the same, the first and
275          * second source addresses the same, and the first and second
276          * destination addresses the same?
277          */
278         if (v1->port_src == v2->port_src &&
279             v1->src.type == v2->src.type &&
280             v1->src.len == v2->src.len &&
281             memcmp(v1->src.data, v2->src.data, v1->src.len) == 0 &&
282             v1->dst.type == v2->dst.type &&
283             v1->dst.type == v2->dst.type &&
284             v1->dst.len == v2->dst.len &&
285             memcmp(v1->dst.data, v2->dst.data, v1->dst.len) == 0) {
286                 /*
287                  * Yes.  It's the same conversation, and the two
288                  * address/port pairs are going in the same direction.
289                  */
290                 return 1;
291         }
292
293         /*
294          * The addresses or the ports don't match.
295          */     
296         return 0;
297 }
298
299 /*
300  * Compute the hash value for a given set of source and destination
301  * addresses and ports if the match has a wildcard destination.
302  */
303 static guint 
304 conversation_hash_no_dst(gconstpointer v)
305 {
306         conversation_key *key = (conversation_key *)v;
307         guint hash_val;
308         int i;
309
310         hash_val = 0;
311         for (i = 0; i < key->src.len; i++)
312                 hash_val += key->src.data[i];
313
314         hash_val += key->port_src;
315
316         return hash_val;
317 }
318
319 /*
320  * Compare the source address and port in the two conversation keys.
321  * We don't check both directions of the conversation - the routine
322  * doing the hash lookup has to do two searches, as the hash key
323  * will be different for the two directions.
324  */
325 static gint
326 conversation_match_no_dst(gconstpointer v, gconstpointer w)
327 {
328         conversation_key *v1 = (conversation_key *)v;
329         conversation_key *v2 = (conversation_key *)w;
330
331         if (v1->ptype != v2->ptype)
332                 return 0;       /* different types of port */
333
334         /*
335          * Are the first and second source ports the same and the first
336          * and second source addresses the same?
337          */
338         if (v1->port_src == v2->port_src &&
339             v1->src.type == v2->src.type &&
340             v1->src.len == v2->src.len &&
341             memcmp(v1->src.data, v2->src.data, v1->src.len) == 0) {
342                 /*
343                  * Yes.  It's the same conversation, and the two
344                  * address/port pairs are going in the same direction.
345                  */
346                 return 1;
347         }
348
349         /*
350          * The addresses or the ports don't match.
351          */     
352         return 0;
353 }
354
355 /*
356  * Initialize some variables every time a file is loaded or re-loaded.
357  * Destroy all existing conversations, and create a new hash table
358  * for the conversations in the new file.
359  */
360 void
361 conversation_init(void)
362 {
363         conversation_key *key;
364
365         /*
366          * Free the addresses associated with the conversation keys.
367          */
368         for (key = conversation_keys; key != NULL; key = key->next) {
369                 /*
370                  * Grr.  I guess the theory here is that freeing
371                  * something sure as heck modifies it, so you
372                  * want to ban attempts to free it, but, alas,
373                  * if we make the "data" field of an "address"
374                  * structure not a "const", the compiler whines if
375                  * we try to make it point into the data for a packet,
376                  * as that's a "const" array (and should be, as dissectors
377                  * shouldn't trash it).
378                  *
379                  * So we cast the complaint into oblivion, and rely on
380                  * the fact that these addresses are known to have had
381                  * their data mallocated, i.e. they don't point into,
382                  * say, the middle of the data for a packet.
383                  */
384                 g_free((gpointer)key->src.data);
385                 g_free((gpointer)key->dst.data);
386         }
387         conversation_keys = NULL;
388         if (conversation_hashtable_exact != NULL)
389                 g_hash_table_destroy(conversation_hashtable_exact);
390         if (conversation_hashtable_no_dst_addr != NULL)
391                 g_hash_table_destroy(conversation_hashtable_no_dst_addr);
392         if (conversation_hashtable_no_dst_port != NULL)
393                 g_hash_table_destroy(conversation_hashtable_no_dst_port);
394         if (conversation_hashtable_no_dst != NULL)
395                 g_hash_table_destroy(conversation_hashtable_no_dst);
396         if (conversation_key_chunk != NULL)
397                 g_mem_chunk_destroy(conversation_key_chunk);
398         if (conversation_chunk != NULL)
399                 g_mem_chunk_destroy(conversation_chunk);
400
401         conversation_hashtable_exact =
402             g_hash_table_new(conversation_hash_exact,
403               conversation_match_exact);
404         conversation_hashtable_no_dst_addr =
405             g_hash_table_new(conversation_hash_no_dst_addr,
406               conversation_match_no_dst_addr);
407         conversation_hashtable_no_dst_port =
408             g_hash_table_new(conversation_hash_no_dst_port,
409               conversation_match_no_dst_port);
410         conversation_hashtable_no_dst =
411             g_hash_table_new(conversation_hash_no_dst,
412               conversation_match_no_dst);
413         conversation_key_chunk = g_mem_chunk_new("conversation_key_chunk",
414             sizeof(conversation_key),
415             conversation_init_count * sizeof(struct conversation_key),
416             G_ALLOC_AND_FREE);
417         conversation_chunk = g_mem_chunk_new("conversation_chunk",
418             sizeof(conversation_t),
419             conversation_init_count * sizeof(conversation_t),
420             G_ALLOC_AND_FREE);
421
422         /*
423          * Start the conversation indices over at 0.
424          */
425         new_index = 0;
426 }
427
428 /*
429  * Copy an address, allocating a new buffer for the address data.
430  */
431 static void
432 copy_address(address *to, address *from)
433 {
434         guint8 *data;
435
436         to->type = from->type;
437         to->len = from->len;
438         data = g_malloc(from->len);
439         memcpy(data, from->data, from->len);
440         to->data = data;
441 }
442
443 /*
444  * Given source and destination addresses and ports for a packet,
445  * create a new conversation to contain packets between those address/port
446  * pairs. The options field is used to flag the destination address/port 
447  * are not given and any value is acceptable.
448
449  */
450 conversation_t *
451 conversation_new(address *src, address *dst, port_type ptype,
452     guint32 src_port, guint32 dst_port, void *data, guint options)
453 {
454         conversation_t *conversation;
455         conversation_key *new_key;
456
457         new_key = g_mem_chunk_alloc(conversation_key_chunk);
458         new_key->next = conversation_keys;
459         conversation_keys = new_key;
460         copy_address(&new_key->src, src);
461         copy_address(&new_key->dst, dst);
462         new_key->ptype = ptype;
463         new_key->port_src = src_port;
464         new_key->port_dst = dst_port;
465
466         conversation = g_mem_chunk_alloc(conversation_chunk);
467         conversation->index = new_index;
468         conversation->data = data;
469
470 /* clear dissector pointer */
471         conversation->dissector.new_d = NULL;
472
473 /* set the options and key pointer */
474         conversation->options = options;
475         conversation->key_ptr = new_key;
476
477         new_index++;
478
479         if (options & NO_DST_ADDR) {
480                 if (options & NO_DST_PORT) {
481                         g_hash_table_insert(conversation_hashtable_no_dst,
482                             new_key, conversation);
483                 } else {
484                         g_hash_table_insert(conversation_hashtable_no_dst_addr,
485                             new_key, conversation);
486                 }
487         } else {
488                 if (options & NO_DST_PORT) {
489                         g_hash_table_insert(conversation_hashtable_no_dst_port,
490                             new_key, conversation);
491                 } else {
492                         g_hash_table_insert(conversation_hashtable_exact,
493                             new_key, conversation);
494                 }
495         }
496         return conversation;
497 }
498
499 /* Set the destination port in a key.  Remove the original from table,
500    update the options and port values, insert the updated key.
501 */
502 void conversation_set_port( conversation_t *conv, guint32 port){
503
504         /*
505          * If the destination port has already been set, don't set it
506          * again.
507          */
508         if (!(conv->options & NO_DST_PORT))
509                 return;
510
511         if (conv->options & NO_DST_ADDR) {
512                 g_hash_table_remove(conversation_hashtable_no_dst,
513                     conv->key_ptr);
514         } else {
515                 g_hash_table_remove(conversation_hashtable_no_dst_port,
516                     conv->key_ptr);
517         }
518         conv->options &= ~NO_DST_PORT;
519         conv->key_ptr->port_dst  = port;
520         if (conv->options & NO_DST_ADDR) {
521                 g_hash_table_insert(conversation_hashtable_no_dst_addr,
522                     conv->key_ptr, conv);
523         } else {
524                 g_hash_table_insert(conversation_hashtable_exact,
525                     conv->key_ptr, conv);
526         }
527
528
529 /* Set the destination address in a key.  Remove the original from
530    table, update the options and port values, insert the updated key.
531 */
532 void conversation_set_addr( conversation_t *conv, address *addr){
533
534         /*
535          * If the destination address has already been set, don't set it
536          * again.
537          */
538         if (!(conv->options & NO_DST_ADDR))
539                 return;
540
541         if (conv->options & NO_DST_PORT) {
542                 g_hash_table_remove(conversation_hashtable_no_dst,
543                     conv->key_ptr);
544         } else {
545                 g_hash_table_remove(conversation_hashtable_no_dst_addr,
546                     conv->key_ptr);
547         }
548         conv->options &= ~NO_DST_ADDR;
549         copy_address(&conv->key_ptr->dst, addr);
550         if (conv->options & NO_DST_PORT) {
551                 g_hash_table_insert(conversation_hashtable_no_dst_port,
552                     conv->key_ptr, conv);
553         } else {
554                 g_hash_table_insert(conversation_hashtable_exact,
555                     conv->key_ptr, conv);
556         }
557 }
558
559 static conversation_t *
560 conversation_match(GHashTable *hashtable, address *src, address *dst,
561     port_type ptype, guint32 src_port, guint32 dst_port)
562 {
563         conversation_key key;
564
565         /*
566          * We don't make a copy of the address data, we just copy the
567          * pointer to it, as "key" disappears when we return.
568          */
569         key.src = *src;
570         key.dst = *dst;
571         key.ptype = ptype;
572         key.port_src = src_port;
573         key.port_dst = dst_port;
574         return g_hash_table_lookup(hashtable, &key);
575 }
576  
577 /*
578  * Given source and destination addresses and ports for a packet,
579  * search for a conversation containing packets between those address/port
580  * pairs.  Returns NULL if not found.  If the NO_DEST_ADDR and/or NO_DEST_PORT
581  * flags are set in the conversation options field, that value will not
582  * be used.
583  */
584 conversation_t *
585 find_conversation(address *src, address *dst, port_type ptype,
586     guint32 src_port, guint32 dst_port, guint options)
587 {
588         conversation_t *conversation;
589
590         if (options & NO_DST_ADDR) {
591                 if (options & NO_DST_PORT) {
592                         /*
593                          * Wildcard the address and port - first try looking
594                          * for a conversation with the specified source
595                          * address and port, then try looking for one with a
596                          * source address and port that's the specified
597                          * *destination* address and port (this packet may be
598                          * going in the opposite direction from the first
599                          * packet in the conversation).
600                          */
601                         conversation =
602                             conversation_match(conversation_hashtable_no_dst,
603                                 src, dst, ptype, src_port, dst_port);
604                         if (conversation != NULL)
605                                 return conversation;
606                         return conversation_match(conversation_hashtable_no_dst,
607                             dst, src, ptype, dst_port, src_port);
608                 } else {
609                         /*
610                          * Wildcard the address - first try looking for a
611                          * conversation with the specified source address
612                          * and port and destination port, then try looking
613                          * for one with a source address and port that's
614                          * the specified *destination* address and port and
615                          * a destination port that's the specified *source*
616                          * port (this packet may be going in the opposite
617                          * direction from the first packet in the conversation).
618                          */
619                         conversation =
620                             conversation_match(conversation_hashtable_no_dst_addr,
621                                 src, dst, ptype, src_port, dst_port);
622                         if (conversation != NULL)
623                                 return conversation;
624                         return conversation_match(conversation_hashtable_no_dst_addr,
625                             dst, src, ptype, dst_port, src_port);
626                 }
627         } else {
628                 if (options & NO_DST_PORT) {
629                         /*
630                          * Wildcard the port - first try looking for a
631                          * conversation with the specified source address
632                          * and port and destination address, then try looking
633                          * for one with a source address and port that's
634                          * the specified *destination* address and port and
635                          * a destination address that's the specified *source*
636                          * address (this packet may be going in the opposite
637                          * direction from the first packet in the conversation).
638                          */
639                         conversation =
640                             conversation_match(conversation_hashtable_no_dst_port,
641                               src, dst, ptype, src_port, dst_port);
642                         if (conversation != NULL)
643                                 return conversation;
644                         return conversation_match(conversation_hashtable_no_dst_port,
645                             dst, src, ptype, dst_port, src_port);
646                 } else {
647                         /*
648                          * Search for an exact match.  That search checks both
649                          * directions.
650                          */
651                         return conversation_match(conversation_hashtable_exact,
652                             src, dst, ptype, src_port, dst_port);
653                 }
654         }
655 }
656
657 /*
658  * Set the dissector for a conversation.
659  */
660 void
661 old_conversation_set_dissector(conversation_t *conversation,
662     old_dissector_t dissector)
663 {
664         conversation->is_old_dissector = TRUE;
665         conversation->dissector.old_d = dissector;
666 }
667
668 void
669 conversation_set_dissector(conversation_t *conversation,
670     dissector_t dissector)
671 {
672         conversation->is_old_dissector = FALSE;
673         conversation->dissector.new_d = dissector;
674 }
675
676 /*
677  * Given source and destination addresses and ports for a packet,
678  * search for a conversational dissector.
679  * If found, call it and return TRUE, otherwise return FALSE.
680  *
681  * Will search for a exact match (src & dst), then search for wild
682  * card matches: try to match any port on the destination address first,
683  * then try to match any address on the port, then try to match any 
684  * address and any port. 
685  */
686 gboolean
687 old_try_conversation_dissector(address *src, address *dst, port_type ptype,
688     guint32 src_port, guint32 dst_port, const u_char *pd, int offset,
689     frame_data *fd, proto_tree *tree)
690 {
691         conversation_t *conversation;
692         tvbuff_t *tvb;
693
694         conversation = find_conversation(src, dst, ptype, src_port, dst_port, 0);
695
696         if (conversation == NULL)
697                 conversation = find_conversation(src, dst, ptype, src_port, dst_port, NO_DST_ADDR);
698
699         if (conversation == NULL)
700                 conversation = find_conversation(src, dst, ptype, src_port, dst_port, NO_DST_PORT);
701
702         if (conversation == NULL)
703                 conversation = find_conversation(src, dst, ptype, src_port, dst_port,
704                     NO_DST_PORT | NO_DST_ADDR);
705
706         if (conversation != NULL) {
707                 if (conversation->is_old_dissector) {
708                         if (conversation->dissector.old_d == NULL)
709                                 return FALSE;
710                         (*conversation->dissector.old_d)(pd, offset, fd, tree);
711                 } else {
712                         if (conversation->dissector.new_d == NULL)
713                                 return FALSE;
714
715                         /*
716                          * Old dissector calling new dissector; use
717                          * "tvb_create_from_top()" to remap.
718                          *
719                          * XXX - what about the "pd" argument?  Do
720                          * any dissectors not just pass that along and
721                          * let the "offset" argument handle stepping
722                          * through the packet?
723                          */
724                         tvb = tvb_create_from_top(offset);
725                         (*conversation->dissector.new_d)(tvb, &pi, tree);
726                 }
727                 return TRUE;
728         }
729         return FALSE;
730 }
731
732 /*
733  * Given source and destination addresses and ports for a packet,
734  * search for a conversational dissector.
735  * If found, call it and return TRUE, otherwise return FALSE.
736  *
737  * Will search for a exact match (src & dst), then search for wild
738  * card matches: try to match any port on the destination address first,
739  * then try to match any address on the port, then try to match any 
740  * address and any port. 
741  */
742 gboolean
743 try_conversation_dissector(address *src, address *dst, port_type ptype,
744     guint32 src_port, guint32 dst_port, tvbuff_t *tvb, packet_info *pinfo,
745     proto_tree *tree)
746 {
747         conversation_t *conversation;
748         const guint8 *pd;
749         int offset;
750
751         conversation = find_conversation(src, dst, ptype, src_port, dst_port, 0);
752
753         if (conversation == NULL)
754                 conversation = find_conversation(src, dst, ptype, src_port, dst_port, NO_DST_ADDR);
755
756         if (conversation == NULL)
757                 conversation = find_conversation(src, dst, ptype, src_port, dst_port, NO_DST_PORT);
758
759         if (conversation == NULL)
760                 conversation = find_conversation(src, dst, ptype, src_port, dst_port,
761                     NO_DST_PORT | NO_DST_ADDR);
762
763         if (conversation != NULL) {
764                 if (conversation->is_old_dissector) {
765                         if (conversation->dissector.old_d == NULL)
766                                 return FALSE;
767
768                         /*
769                          * New dissector calling old dissector; use
770                          * "tvb_compat()" to remap.
771                          *
772                          * "is_old_dissector" won't be set unless
773                          * "dissector.old_d" is set.
774                          */
775                         tvb_compat(tvb, &pd, &offset);
776                         (*conversation->dissector.old_d)(pd, offset, pinfo->fd,
777                             tree);
778                 } else {
779                         if (conversation->dissector.new_d == NULL)
780                                 return FALSE;
781                         (*conversation->dissector.new_d)(tvb, pinfo, tree);
782                 }
783                 return TRUE;
784         }
785         return FALSE;
786 }