Ethereal-dev: [Ethereal-dev] conversation.c patch (task completed)

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Peter Johansson" <Peter.Johansson@xxxxxxxxxxxx>
Date: Thu, 9 Dec 2004 17:12:53 +0100 (CET)
I have implemented what was discussed earlier with the possibility of
using conversation templates which are used to define an endpoint to which
all new connections that are made should be handled by the protocol
dissector that registered the conversation with the CONVERSATION_TEMPLATE
flag set in its options mask.

The supplied patch adds the ability to create conversations with wildcards
for either port, address or both. Once a connection is established to the
address-port pair that matches the conversation, a new conversation is
created with the address and port that matched the wildcard options while
the conversation that was initially created with the CONVERSATION_TEMPLATE
flag still remains intact to match more connections to the same wildcard
conversation. The newly created conversation has been stripped from its
NO_PORT_B, NO_ADDR_B and CONVERSATION_TEMPLATE flags.

While doing these code additions and changes, I also cleaned up the way
the code is indented with regards to the functions that I have made
changes in (it is no longer a mix of tabs and spaces).

/ Regards, Peter

/* conversation.h
 * Routines for building lists of packets that are part of a "conversation"
 *
 * $Id$
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __CONVERSATION_H__
#define __CONVERSATION_H__

/*
 * Flags to pass to "conversation_new()" to indicate that the address 2
 * and/or port 2 values for the conversation should be wildcards.
 */
#define NO_ADDR2 0x01
#define NO_PORT2 0x02
#define NO_PORT2_FORCE 0x04

/*
 * Flags to pass to "find_conversation()" to indicate that the address B
 * and/or port B search arguments are wildcards.
 */
#define NO_ADDR_B 0x01
#define NO_PORT_B 0x02
#define NO_PORT_B_FORCE 0x04

#include "packet.h"		/* for conversation dissector type */

/*
 * Data structure representing a conversation.
 */
typedef struct conversation_key {
	struct conversation_key *next;
	address	addr1;
	address	addr2;
	port_type ptype;
	guint32	port1;
	guint32	port2;
} conversation_key;

typedef struct conversation {
	struct conversation *next;	/* pointer to next conversation on hash chain */
	guint32	index;			/* unique ID for conversation */
	GSList *data_list;		/* list of data associated with conversation */
	dissector_handle_t dissector_handle;
					/* handle for protocol dissector client associated with conversation */
	guint	options;		/* wildcard flags */
	conversation_key *key_ptr;	/* pointer to the key for this conversation */
} conversation_t;

extern void conversation_init(void);

extern conversation_t *conversation_new(address *addr1, address *addr2,
    port_type ptype, guint32 port1, guint32 port2, guint options);

extern conversation_t *find_conversation(address *addr_a, address *addr_b,
    port_type ptype, guint32 port_a, guint32 port_b, guint options);

extern void conversation_add_proto_data(conversation_t *conv, int proto,
    void *proto_data);
extern void *conversation_get_proto_data(conversation_t *conv, int proto);
extern void conversation_delete_proto_data(conversation_t *conv, int proto);

extern void conversation_set_dissector(conversation_t *conversation,
    dissector_handle_t handle);
extern gboolean
try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype,
    guint32 port_a, guint32 port_b, tvbuff_t *tvb, packet_info *pinfo,
    proto_tree *tree);

/* These routines are used to set undefined values for a conversation */

extern void conversation_set_port2(conversation_t *conv, guint32 port);
extern void conversation_set_addr2(conversation_t *conv, address *addr);

#endif /* conversation.h */
--- conversation.c	Thu Dec 09 16:12:36 2004
+++ \ethereal-win32-libs\epan\conversation.c	Thu Dec 09 16:42:52 2004
@@ -1,7 +1,7 @@
 /* conversation.c
  * Routines for building lists of packets that are part of a "conversation"
  *
- * $Id$
+ * $Id: conversation.c 11400 2004-07-18 00:24:25Z guy $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@xxxxxxxxxxxx>
@@ -88,6 +88,99 @@
 static GMemChunk *conv_proto_data_area = NULL;
 
 /*
+ * Creates a new conversation with known endpoints based on a conversation
+ * created with the CONVERSATION_TEMPLATE option while keeping the
+ * conversation created with the CONVERSATION_TEMPLATE option so it can still
+ * match future connections.
+ *
+ * Passing a pointer to a conversation whose options mask does not include
+ * CONVERSATION_TEMPLATE or where the conversation's protocol type (ptype)
+ * indicates a non-connnection oriented protocol will return the conversation
+ * without changes.
+ *
+ * addr2 and port2 are used in the function if their respective conversation
+ * options bits are set (NO_ADDR2 and NO_PORT2).
+ */
+conversation_t *
+conversation_create_from_template(conversation_t *conversation, address *addr2, guint32 port2)
+{
+   /*
+    * Add a new conversation and keep the conversation template only if the
+    * CONVERSATION_TEMPLATE bit is set for a connection oriented protocol.
+    */
+   if(conversation->options & CONVERSATION_TEMPLATE &&
+      conversation->key_ptr->ptype != PT_UDP)
+   {
+      /*
+       * Set up a new options mask where the conversation template bit and the
+       * bits for absence of a second address and port pair have been removed.
+       */
+      conversation_t *new_conversation_from_template;
+      guint options = conversation->options & ~(CONVERSATION_TEMPLATE | NO_ADDR2 | NO_PORT2);
+
+      /*
+       * Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask?
+       */
+      if(conversation->options & NO_ADDR2 &&
+         conversation->options & NO_PORT2)
+      {
+         /*
+          * The conversation template was created without knowledge of both
+          * the second address as well as the second port. Create a new
+          * conversation with new 2nd address and 2nd port.
+          */
+         new_conversation_from_template =
+            conversation_new(&conversation->key_ptr->addr1, addr2,
+                             conversation->key_ptr->ptype, conversation->key_ptr->port1,
+                             port2, options);
+      }
+      else if(conversation->options & NO_PORT2)
+      {
+         /*
+          * The conversation template was created without knowledge of port 2
+          * only. Create a new conversation with new 2nd port.
+          */
+         new_conversation_from_template =
+            conversation_new(&conversation->key_ptr->addr1, &conversation->key_ptr->addr2,
+                             conversation->key_ptr->ptype, conversation->key_ptr->port1,
+                             port2, options);
+      }
+      else if(conversation->options & NO_ADDR2)
+      {
+         /*
+          * The conversation template was created without knowledge of address
+          * 2. Create a new conversation with new 2nd address.
+          */
+         new_conversation_from_template =
+            conversation_new(&conversation->key_ptr->addr1, addr2,
+                             conversation->key_ptr->ptype, conversation->key_ptr->port1,
+                             conversation->key_ptr->port2, options);
+      }
+      else
+      {
+         /*
+          * The CONVERSATION_TEMPLATE bit was set, but no other bit that the
+          * CONVERSATION_TEMPLATE bit controls is active. Just return the old
+          * conversation.
+          */
+         return conversation;
+      }
+
+      /*
+       * Set the protocol dissector used for the template conversation as
+       * the handler of the new conversation as well.
+       */
+      new_conversation_from_template->dissector_handle = conversation->dissector_handle;
+
+      return new_conversation_from_template;
+   }
+   else
+   {
+      return conversation;
+   }
+}
+
+/*
  * Compute the hash value for two given address/port pairs if the match
  * is to be exact.
  */
@@ -438,6 +531,10 @@
 conversation_new(address *addr1, address *addr2, port_type ptype,
     guint32 port1, guint32 port2, guint options)
 {
+/*
+	g_assert(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
+				"A conversation template may not be constructed without wildcard options");
+*/
 	conversation_t *conversation;
 	conversation_key *new_key;
 
@@ -454,10 +551,10 @@
 	conversation->index = new_index;
 	conversation->data_list = NULL;
 
-/* clear dissector handle */
+	/* clear dissector handle */
 	conversation->dissector_handle = NULL;
 
-/* set the options and key pointer */
+	/* set the options and key pointer */
 	conversation->options = options;
 	conversation->key_ptr = new_key;
 
@@ -490,10 +587,13 @@
 void
 conversation_set_port2(conversation_t *conv, guint32 port)
 {
+   g_assert(!(conv->options & CONVERSATION_TEMPLATE) &&
+            "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask");
+
 	/*
 	 * If the port 2 value is not wildcarded, don't set it.
 	 */
-        if ((!(conv->options & NO_PORT2)) || (conv->options & NO_PORT2_FORCE))
+	if ((!(conv->options & NO_PORT2)) || (conv->options & NO_PORT2_FORCE))
 		return;
 
 	if (conv->options & NO_ADDR2) {
@@ -521,6 +621,9 @@
 void
 conversation_set_addr2(conversation_t *conv, address *addr)
 {
+   g_assert(!(conv->options & CONVERSATION_TEMPLATE) &&
+            "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask");
+   
 	/*
 	 * If the address 2 value is not wildcarded, don't set it.
 	 */
@@ -608,261 +711,307 @@
 find_conversation(address *addr_a, address *addr_b, port_type ptype,
     guint32 port_a, guint32 port_b, guint options)
 {
-	conversation_t *conversation;
-
-	/*
-	 * First try an exact match, if we have two addresses and ports.
-	 */
-	if (!(options & (NO_ADDR_B|NO_PORT_B))) {
-		/*
-		 * Neither search address B nor search port B are wildcarded,
-		 * start out with an exact match.
-		 * Exact matches check both directions.
-		 */
-		conversation =
-		    conversation_lookup_hashtable(conversation_hashtable_exact,
-                                                  addr_a, addr_b, ptype,
-                                                  port_a, port_b);
-                if ((conversation == NULL) && (addr_a->type == AT_FC)) {
-                    /* In Fibre channel, OXID & RXID are never swapped as
-                     * TCP/UDP ports are in TCP/IP.
-                     */
-                    conversation =
-                        conversation_lookup_hashtable(conversation_hashtable_exact,
-                                                      addr_b, addr_a, ptype,
-                                                      port_a, port_b);
-                }
-		if (conversation != NULL)
-			return conversation;
-	}
-
-	/*
-	 * Well, that didn't find anything.  Try matches that wildcard
-	 * one of the addresses, if we have two ports.
-	 */
-	if (!(options & NO_PORT_B)) {
-		/*
-		 * Search port B isn't wildcarded.
-		 *
-		 * First try looking for a conversation with the specified
-		 * address A and port A as the first address and port, and
-		 * with any address and the specified port B as the second
-		 * address and port.
-		 * ("addr_b" doesn't take part in this lookup.)
-		 */
-		conversation =
-		    conversation_lookup_hashtable(conversation_hashtable_no_addr2,
-		        addr_a, addr_b, ptype, port_a, port_b);
-                if ((conversation == NULL) && (addr_a->type == AT_FC)) {
-                    /* In Fibre channel, OXID & RXID are never swapped as
-                     * TCP/UDP ports are in TCP/IP.
-                     */
-                    conversation =
-                        conversation_lookup_hashtable(conversation_hashtable_no_addr2,
-                                                      addr_b, addr_a, ptype,
-                                                      port_a, port_b);
-                }
-		if (conversation != NULL) {
-			/*
-			 * If search address B isn't wildcarded, and this
-			 * is for a connection-oriented protocol, set the
-			 * second address for this conversation to address
-			 * B, as that's the address that matched the
-			 * wildcarded second address for this conversation.
-			 *
-			 * (XXX - this assumes that, for all connection-
-			 * oriented protocols, the endpoints of a connection
-			 * have only one address each, i.e. you don't get
-			 * packets in a given direction coming from more than
-			 * one address.)
-			 */
-			if (!(options & NO_ADDR_B) && ptype != PT_UDP)
-				conversation_set_addr2(conversation, addr_b);
-			return conversation;
-		}
+   conversation_t *conversation;
 
-		/*
-		 * Well, that didn't find anything.
-		 * If search address B was specified, try looking for a
-		 * conversation with the specified address B and port B as
-		 * the first address and port, and with any address and the
-		 * specified port A as the second address and port (this
-		 * packet may be going in the opposite direction from the
-		 * first packet in the conversation).
-		 * ("addr_a" doesn't take part in this lookup.)
-		 */
-		if (!(options & NO_ADDR_B)) {
-                    conversation =
-                        conversation_lookup_hashtable(conversation_hashtable_no_addr2,
-                                                      addr_b, addr_a, ptype, port_b, port_a);
-			if (conversation != NULL) {
-				/*
-				 * If this is for a connection-oriented
-				 * protocol, set the second address for
-				 * this conversation to address A, as
-				 * that's the address that matched the
-				 * wildcarded second address for this
-				 * conversation.
-				 */
-				if (ptype != PT_UDP) {
-					conversation_set_addr2(conversation,
-					    addr_a);
-				}
-				return conversation;
-			}
-		}
-	}
-
-	/*
-	 * Well, that didn't find anything.  Try matches that wildcard
-	 * one of the ports, if we have two addresses.
-	 */
-	if (!(options & NO_ADDR_B)) {
-		/*
-		 * Search address B isn't wildcarded.
-		 *
-		 * First try looking for a conversation with the specified
-		 * address A and port A as the first address and port, and
-		 * with the specified address B and any port as the second
-		 * address and port.
-		 * ("port_b" doesn't take part in this lookup.)
-		 */
-		conversation =
-		    conversation_lookup_hashtable(conversation_hashtable_no_port2,
-		      addr_a, addr_b, ptype, port_a, port_b);
-                if ((conversation == NULL) && (addr_a->type == AT_FC)) {
-                    /* In Fibre channel, OXID & RXID are never swapped as
-                     * TCP/UDP ports are in TCP/IP
-                     */
-                    conversation =
-		    conversation_lookup_hashtable(conversation_hashtable_no_port2,
-		      addr_b, addr_a, ptype, port_a, port_b);
-                }
-		if (conversation != NULL) {
-			/*
-			 * If search port B isn't wildcarded, and this is
-			 * for a connection-oriented protocol, set the
-			 * second port for this conversation to port B,
-			 * as that's the port that matched the wildcarded
-			 * second port for this conversation.
-			 *
-			 * (XXX - this assumes that, for all connection-
-			 * oriented protocols, the endpoints of a connection
-			 * have only one port each, i.e. you don't get
-			 * packets in a given direction coming from more than
-			 * one port.)
-			 */
-			if (!(options & NO_PORT_B) && ptype != PT_UDP)
-				conversation_set_port2(conversation, port_b);
-			return conversation;
-		}
-
-		/*
-		 * Well, that didn't find anything.
-		 * If search port B was specified, try looking for a
-		 * conversation with the specified address B and port B
-		 * as the first address and port, and with the specified
-		 * address A and any port as the second address and port
-		 * (this packet may be going in the opposite direction
-		 * from the first packet in the conversation).
-		 * ("port_a" doesn't take part in this lookup.)
-		 */
-		if (!(options & NO_PORT_B)) {
-			conversation =
-			    conversation_lookup_hashtable(conversation_hashtable_no_port2,
-			      addr_b, addr_a, ptype, port_b, port_a);
-			if (conversation != NULL) {
-				/*
-				 * If this is for a connection-oriented
-				 * protocol, set the second port for
-				 * this conversation to port A, as
-				 * that's the address that matched the
-				 * wildcarded second address for this
-				 * conversation.
-				 */
-				if (ptype != PT_UDP) {
-					conversation_set_port2(conversation,
-					    port_a);
-				}
-				return conversation;
-			}
-		}
-	}
-
-	/*
-	 * Well, that didn't find anything.  Try matches that wildcard
-	 * one address/port pair.
-	 *
-	 * First try looking for a conversation with the specified address A
-	 * and port A as the first address and port.
-	 * (Neither "addr_b" nor "port_b" take part in this lookup.)
-	 */
-	conversation =
-	    conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
-	      addr_a, addr_b, ptype, port_a, port_b);
-	if (conversation != NULL) {
-		/*
-		 * If this is for a connection-oriented protocol:
-		 *
-		 *	if search address B isn't wildcarded, set the
-		 *	second address for this conversation to address
-		 *	B, as that's the address that matched the
-		 *	wildcarded second address for this conversation;
-		 *
-		 *	if search port B isn't wildcarded, set the
-		 *	second port for this conversation to port B,
-		 *	as that's the port that matched the wildcarded
-		 *	second port for this conversation.
-		 */
-		if (ptype != PT_UDP) {
-			if (!(options & NO_ADDR_B))
-				conversation_set_addr2(conversation, addr_b);
-			if (!(options & NO_PORT_B))
-				conversation_set_port2(conversation, port_b);
-		}
-		return conversation;
-	}
-
-	/*
-	 * Well, that didn't find anything.
-	 * If search address and port B were specified, try looking for a
-	 * conversation with the specified address B and port B as the
-	 * first address and port, and with any second address and port
-	 * (this packet may be going in the opposite direction from the
-	 * first packet in the conversation).
-	 * (Neither "addr_a" nor "port_a" take part in this lookup.)
-	 */
-        if (addr_a->type == AT_FC)
-            conversation =
-                conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
-                                              addr_b, addr_a, ptype, port_a,
-                                              port_b);
-        else 
+   /*
+    * First try an exact match, if we have two addresses and ports.
+    */
+   if (!(options & (NO_ADDR_B|NO_PORT_B))) {
+      /*
+       * Neither search address B nor search port B are wildcarded,
+       * start out with an exact match.
+       * Exact matches check both directions.
+       */
+      conversation =
+         conversation_lookup_hashtable(conversation_hashtable_exact,
+         addr_a, addr_b, ptype,
+         port_a, port_b);
+      if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+         /* In Fibre channel, OXID & RXID are never swapped as
+          * TCP/UDP ports are in TCP/IP.
+          */
+         conversation =
+            conversation_lookup_hashtable(conversation_hashtable_exact,
+            addr_b, addr_a, ptype,
+            port_a, port_b);
+      }
+      if (conversation != NULL)
+         return conversation;
+   }
+
+   /*
+    * Well, that didn't find anything.  Try matches that wildcard
+    * one of the addresses, if we have two ports.
+    */
+   if (!(options & NO_PORT_B)) {
+      /*
+       * Search port B isn't wildcarded.
+       *
+       * First try looking for a conversation with the specified
+       * address A and port A as the first address and port, and
+       * with any address and the specified port B as the second
+       * address and port.
+       * ("addr_b" doesn't take part in this lookup.)
+       */
+      conversation =
+         conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+         addr_a, addr_b, ptype, port_a, port_b);
+      if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+         /* In Fibre channel, OXID & RXID are never swapped as
+          * TCP/UDP ports are in TCP/IP.
+          */
+         conversation =
+            conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+            addr_b, addr_a, ptype,
+            port_a, port_b);
+      }
+      if (conversation != NULL) {
+         /*
+          * If search address B isn't wildcarded, and this is for a
+          * connection-oriented protocol, set the second address for this
+          * conversation to address B, as that's the address that matched the
+          * wildcarded second address for this conversation.
+          *
+          * (This assumes that, for all connection oriented protocols, the
+          * endpoints of a connection have only one address each, i.e. you
+          * don't get packets in a given direction coming from more than one
+          * address, unless the CONVERSATION_TEMPLATE option is set.)
+          */
+         if (!(options & NO_ADDR_B) && ptype != PT_UDP)
+         {
+            if(!(options & CONVERSATION_TEMPLATE))
+            {
+               conversation_set_addr2(conversation, addr_b);
+            }
+            else
+            {
+               conversation =
+                  conversation_create_from_template(conversation, addr_b, 0);
+            }
+         }
+         return conversation;
+      }
+
+      /*
+       * Well, that didn't find anything.
+       * If search address B was specified, try looking for a
+       * conversation with the specified address B and port B as
+       * the first address and port, and with any address and the
+       * specified port A as the second address and port (this
+       * packet may be going in the opposite direction from the
+       * first packet in the conversation).
+       * ("addr_a" doesn't take part in this lookup.)
+       */
+      if (!(options & NO_ADDR_B)) {
+         conversation =
+            conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+            addr_b, addr_a, ptype, port_b, port_a);
+         if (conversation != NULL) {
+            /*
+             * If this is for a connection-oriented
+             * protocol, set the second address for
+             * this conversation to address A, as
+             * that's the address that matched the
+             * wildcarded second address for this
+             * conversation.
+             */
+            if (ptype != PT_UDP) {
+               if(!(options & CONVERSATION_TEMPLATE))
+               {
+                  conversation_set_addr2(conversation, addr_a);
+               }
+               else
+               {
+                  conversation =
+                     conversation_create_from_template(conversation, addr_a, 0);
+               }
+            }
+            return conversation;
+         }
+      }
+   }
+
+   /*
+    * Well, that didn't find anything.  Try matches that wildcard
+    * one of the ports, if we have two addresses.
+   */
+   if (!(options & NO_ADDR_B)) {
+      /*
+       * Search address B isn't wildcarded.
+       *
+       * First try looking for a conversation with the specified
+       * address A and port A as the first address and port, and
+       * with the specified address B and any port as the second
+       * address and port.
+       * ("port_b" doesn't take part in this lookup.)
+       */
+      conversation =
+         conversation_lookup_hashtable(conversation_hashtable_no_port2,
+         addr_a, addr_b, ptype, port_a, port_b);
+      if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+         /* In Fibre channel, OXID & RXID are never swapped as
+          * TCP/UDP ports are in TCP/IP
+          */
+         conversation =
+            conversation_lookup_hashtable(conversation_hashtable_no_port2,
+            addr_b, addr_a, ptype, port_a, port_b);
+      }
+      if (conversation != NULL) {
+         /*
+          * If search port B isn't wildcarded, and this is for a connection-
+          * oriented protocol, set the second port for this conversation to
+          * port B, as that's the port that matched the wildcarded second port
+          * for this conversation.
+          *
+          * (This assumes that, for all connection oriented protocols, the
+          * endpoints of a connection have only one port each, i.e. you don't
+          * get packets in a given direction coming from more than one port,
+          * unless the CONVERSATION_TEMPLATE option is set.)
+          */
+         if (!(options & NO_PORT_B) && ptype != PT_UDP)
+         {
+            if(!(options & CONVERSATION_TEMPLATE))
+            {
+               conversation_set_port2(conversation, port_b);
+            }
+            else
+            {
+               conversation =
+                  conversation_create_from_template(conversation, 0, port_b);
+            }
+         }
+         return conversation;
+      }
+
+      /*
+       * Well, that didn't find anything.
+       * If search port B was specified, try looking for a
+       * conversation with the specified address B and port B
+       * as the first address and port, and with the specified
+       * address A and any port as the second address and port
+       * (this packet may be going in the opposite direction
+       * from the first packet in the conversation).
+       * ("port_a" doesn't take part in this lookup.)
+       */
+      if (!(options & NO_PORT_B)) {
+         conversation =
+            conversation_lookup_hashtable(conversation_hashtable_no_port2,
+            addr_b, addr_a, ptype, port_b, port_a);
+         if (conversation != NULL) {
+            /*
+             * If this is for a connection-oriented
+             * protocol, set the second port for
+             * this conversation to port A, as
+             * that's the address that matched the
+             * wildcarded second address for this
+             * conversation.
+             */
+            if (ptype != PT_UDP)
+            {
+               if(!(options & CONVERSATION_TEMPLATE))
+               {
+                  conversation_set_port2(conversation, port_a);
+               }
+               else
+               {
+                  conversation =
+                     conversation_create_from_template(conversation, 0, port_a);
+               }
+            }
+            return conversation;
+         }
+      }
+   }
+
+   /*
+    * Well, that didn't find anything.  Try matches that wildcard
+    * one address/port pair.
+    *
+    * First try looking for a conversation with the specified address A
+    * and port A as the first address and port.
+    * (Neither "addr_b" nor "port_b" take part in this lookup.)
+    */
+   conversation =
+      conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+      addr_a, addr_b, ptype, port_a, port_b);
+   if (conversation != NULL) {
+      /*
+       * If this is for a connection-oriented protocol:
+       *
+       * if search address B isn't wildcarded, set the
+       * second address for this conversation to address
+       * B, as that's the address that matched the
+       * wildcarded second address for this conversation;
+       *
+       * if search port B isn't wildcarded, set the
+       * second port for this conversation to port B,
+       * as that's the port that matched the wildcarded
+       * second port for this conversation.
+       */
+      if (ptype != PT_UDP)
+      {
+         if(!(options & CONVERSATION_TEMPLATE))
+         {
+            if (!(options & NO_ADDR_B))
+               conversation_set_addr2(conversation, addr_b);
+            if (!(options & NO_PORT_B))
+               conversation_set_port2(conversation, port_b);
+         }
+         else
+         {
             conversation =
-                conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
-                                              addr_b, addr_a, ptype, port_b,
-                                              port_a);
-	if (conversation != NULL) {
-		/*
-		 * If this is for a connection-oriented protocol, set the
-		 * second address for this conversation to address A, as
-		 * that's the address that matched the wildcarded second
-		 * address for this conversation, and set the second port
-		 * for this conversation to port A, as that's the port
-		 * that matched the wildcarded second port for this
-		 * conversation.
-		 */
-		if (ptype != PT_UDP) {
-			conversation_set_addr2(conversation, addr_a);
-			conversation_set_port2(conversation, port_a);
-		}
-		return conversation;
-	}
-
-	/*
-	 * We found no conversation.
-	 */
-	return NULL;
+               conversation_create_from_template(conversation, addr_b, port_b);
+         }
+      }
+      return conversation;
+   }
+
+   /*
+    * Well, that didn't find anything.
+    * If search address and port B were specified, try looking for a
+    * conversation with the specified address B and port B as the
+    * first address and port, and with any second address and port
+    * (this packet may be going in the opposite direction from the
+    * first packet in the conversation).
+    * (Neither "addr_a" nor "port_a" take part in this lookup.)
+    */
+   if (addr_a->type == AT_FC)
+      conversation =
+      conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+      addr_b, addr_a, ptype, port_a, port_b);
+   else 
+      conversation =
+      conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+      addr_b, addr_a, ptype, port_b, port_a);
+   if (conversation != NULL) {
+      /*
+       * If this is for a connection-oriented protocol, set the
+       * second address for this conversation to address A, as
+       * that's the address that matched the wildcarded second
+       * address for this conversation, and set the second port
+       * for this conversation to port A, as that's the port
+       * that matched the wildcarded second port for this
+       * conversation.
+       */
+      if (ptype != PT_UDP)
+      {
+         if(!(conversation->options & CONVERSATION_TEMPLATE))
+         {
+            conversation_set_addr2(conversation, addr_a);
+            conversation_set_port2(conversation, port_a);
+         }
+         else
+         {
+            conversation = conversation_create_from_template(conversation, addr_a, port_a);
+         }
+      }
+      return conversation;
+   }
+
+   /*
+    * We found no conversation.
+    */
+   return NULL;
 }
 
 static gint