Index: contrib/README
===================================================================
--- contrib/README	(revision 600)
+++ contrib/README	(revision 726)
@@ -51,2 +51,5 @@
 
 - dict_legacy: XML and DTD files for the dict_legacy_xml.fdx extension.
+
+- wireshark: This contains some information on how to use Wireshark to monitor Diameter
+	exchange protected with TLS. It involves patching the wireshark software.
Index: contrib/wireshark/HOWTO
===================================================================
--- contrib/wireshark/HOWTO	(revision 726)
+++ contrib/wireshark/HOWTO	(revision 726)
@@ -0,0 +1,68 @@
+	  --------
+	  FOREWORD
+	  --------
+			   
+The patch in this folder allows Wireshark to process packets that contain TLS-protected
+Diameter messages over SCTP multi-stream associations. Each SCTP stream pairs is handled
+as a separate TLS channel (RFC3436), which is consistent with freeDiameter 1.0.x mechanism.
+
+It should be noted however that rfc3588bis (revised Diameter) recommends that DTLS is used
+instead of TLS over SCTP, for the reasons highlighted in the introduction of RFC6083.
+When this new mechanism is implemented in freeDiameter, a different patch will probably
+be required for wireshark.
+
+
+The instructions in this file will change your wireshark binary in a way suitable for
+analysis of Diameter over TLS over SCTP, but may have unexpected side-effects
+on some other protocols analysis (including DTLS).
+
+The instructions refer to Debian-style packaging (apt), you should adapt 
+the process to build a new modified package of wireshark for your distribution.
+
+The provided patch has been successfully tested with:
+ - wireshark-1.2.7 (Ubuntu Lucid)
+ - wireshark-1.2.11 (Ubuntu Maverick)
+It may or may not work on more recent or ancient versions.
+
+
+	------------
+	INSTRUCTIONS
+	------------
+
+The steps are:
+ - get your wireshark source
+ 	apt-get source wireshark
+	cd wireshark-1.2.*
+	
+ - apply the patch
+ 	cat ~/wireshark-1.2.7-diameter-tls.patch | patch -p1
+
+ - increase the version number
+ 	dch -lfD "Added support for Diameter over TLS over SCTP"
+	
+ - Create a new package, this might take a while
+	debian/rules binary
+
+ - Install the modified version
+ 	sudo dpkg --install ../wireshark-common_*fD*.deb ../wireshark_*fD*.deb
+
+ - Start the new wireshark:
+ 	wireshark &
+	
+To analyze a capture file, you will need the private keys of both peers involved.
+
+Let's imagine for example:
+  peer A with IP address 192.168.0.10 has private key privA.pem
+  peer B with IP address 192.168.0.11 has private key privB.pem
+  
+In wireshark you must do the following:
+ - go to menu Edit->Preferences
+ - In the left panel, under Protocols, scroll to "SSL" and select it.
+ - In the right panel, fill "RSA keys list" as follow:
+	192.168.0.10,3869,diameter,/absolute/path/to/privA.pem;192.168.0.11,3869,diameter,/absolute/path/to/privB.pem
+ - You may find also useful to select an SSL debug file to get a hint of any problem.
+ 
+Once this configuration is complete, you should be able to see the contents of SCTP packets, 
+including protected Diameter payload.
+
+Check the "sample" subdirectory for a test capture file.
Index: contrib/wireshark/sample/192.168.103.10.priv.pem
===================================================================
--- contrib/wireshark/sample/192.168.103.10.priv.pem	(revision 726)
+++ contrib/wireshark/sample/192.168.103.10.priv.pem	(revision 726)
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDMcXy2iVqcXkGaY44yNihVNzW/zHptqID49/ZyyyOinxHenvf9
+o/fr613XvUuyquaapL99yiMPuLU3I1UxxacWBSAb496eGd7fY1Udw1RtqKCeb60c
+jpTc3zKySGPHtnzOxeSMDK/R6uqkFirF6Lnu18mKZyAwJtvFYnh0wK3SwwIDAQAB
+AoGAa6kX08hhPxcj1Pm4WBjNBJMeavJzRmwF/xYVYj43ddvuvR1Z2ugOFt7LfGDj
+DCOTbLx1Wvinng/W3kJtCtjbM3w3k5cuFJdJcURXda73IHSaJOHnBAw5RlvFCE79
+12yKqGOBgy80gGHDlqnSIjISCGb/9wLcHYLccakekckPc4ECQQDubt5fWzN4wUwU
+yW+e/SO9Vz4j+FiIC2aZy2OM9XXt6cgh4v0hQ3l0sWVJ6lTvK17aD9LXE5rluAOI
+thnPZElFAkEA24GH8Po/+3K6A5d5Zh1+hwoMLbWrykQDWSOgtmaOtbAvezlolF8O
+W18pVdvyMJg3gUiCA/rHG+r+OBxa4sx4ZwJAH4c1jHJo2fzlbJI+Wk2q3iydIPCD
+9GldhdSpM0h58Z3KQwDa6/0aIF4cwKtl08JuZnNVM+95ugqdHQTHYO8n6QJBAIgO
+m+KEWxBSpnX/d+IRuhGd6rqSdu8ihSjFaqJko2R+1o98oBQHb3C3ZXmwoUf5sb3S
+4bPxx2TIndbNzI/zyVUCQGqN7eyoeTxtPD8P08lUGTUnC2n0imZ1mU5p8Bnv8gw5
+lwt9qxuz0Ujr7uFPPu58bvGsYeoFUV23WRmS0rKLXv0=
+-----END RSA PRIVATE KEY-----
Index: contrib/wireshark/sample/192.168.103.20.priv.pem
===================================================================
--- contrib/wireshark/sample/192.168.103.20.priv.pem	(revision 726)
+++ contrib/wireshark/sample/192.168.103.20.priv.pem	(revision 726)
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDef8CrqawfvmCLBwmlPRlWjwB6V4TvVMRhivAYlwwFbUSoU5bm
+2D780IBr3fNL3zP38ySa7r9cXxPgk7mbj3PhcJbI0Ix0AjQdFSB08AOXev4gqU8p
+qgEODFV04tnFhOcDysp77qH/DFuNwxd2xtFUbGKfGhroAssHxJuogOmiWQIDAQAB
+AoGAP6H7wVyCLIXu6HP3zzkdIQM+2L5k92mfzGHG7tFsD7VDWHyngJfB093xjGfq
+p/1KyJPSGTlEoy9R6P12rMWnFv7sYYKmPGfKdRUMxZYIXbplw6+L/gwW3MCiOMDD
+zRzRjknE3a+Mjo3e2XMHh6Z+GJ61megMeGInODP05/h66AECQQDyFhT+D8DVj1hp
+RlaYTFDKCmS9rgMQ+g4YyqMLzuakkKwaJwbCIlMbQortGBvY9I+0uZC4jklcOpnl
+YYcGIUEBAkEA60l5uAVBk6vKWKWX2cksBP/VlJM2B9pkvmlL7tPwJVEfoaAzZx4N
+rPpC9sOsFlX1ShpirAmIqmvY16in4xEJWQJBAOvULSEOcZjZapQrjEIS3gTkOR06
+fgw0vDTUeh8PsEmSEcXsTL4jt/fvS+0KNl6UZ8Xzm5LeMYLiJ3d4GZQUIwECQQCb
+vYLoH/KMQMYrb1DYQ6TzmjRRqC+3ewP8Vc6BQ6BN0yjQ3y2nL+l1eiIhHNwn3LYE
+Wvq9TYI87C4YcfbPAlPhAkEA0bNU/Utgdbv/yT4lUmw+0toqFHkcT5s13RFWzNJU
+KdQ308kwz9rSDmuQ8eYzn5V02TioJKV4r0NZz+WcCyDY3A==
+-----END RSA PRIVATE KEY-----
Index: contrib/wireshark/sample/README
===================================================================
--- contrib/wireshark/sample/README	(revision 726)
+++ contrib/wireshark/sample/README	(revision 726)
@@ -0,0 +1,56 @@
+This folder contains an example capture file, as well as the two
+private keys required to decode the TLS-protected exchanges.
+
+In order to decrypt properly the packets, you'll need a patched wireshark (see parent directory)
+and the SSL "RSA Private Keys" properties set to (replace with real full path):
+  192.168.103.10,3869,diameter,freeDiameter/contrib/wireshark/sample/192.168.103.10.priv.pem;192.168.103.20,3869,diameter,freeDiameter/contrib/wireshark/sample/192.168.103.20.priv.pem
+
+
+This capture contains everything that was exchanged by the peer since it boot up.
+The captured peer is "relay.a.rt.freediameter.net" with IP address 192.168.103.20.
+
+Here is the detail of what you can see in the capture, if the decyphering 
+works as expected, in chronological order:
+
+-----------------------------------------------------------------------------
+Frames		| Comments
+-----------------------------------------------------------------------------
+1-24		| Peer booting up: DHCP, NTP, ...
+		|
+25-29		| Connection attempt from 192.168.103.10
+		|   first attempt on SCTP (frames 26-27)
+		|   then on TCP (frames 28-29)
+		|
+32-35		| freeDiameter starting: Diameter Identities
+		|   from the peer's configuration file are
+		|   DNS resolved.
+		|
+36-39		| SCTP connection to 192.168.103.10
+		|
+40-45		| Failed attempt to connect to 192.168.103.30
+		|   where freeDiameter was not started.
+		|
+46-49		| (I think this is trigged by Debug output, 
+		|   I have to check)
+		|
+50-73		| TLS handshake on first stream pair (#0).
+		|
+74-90		| Resumed handshakes on streams #1 and #2 in parallel.
+		|   (not sure where to find that it is resumed,
+		|    except that certificates are not re-exchanged)
+		|
+91-92		| CER/CEA exchange.
+93-96		| DWR/DWA exchange.
+		|
+103-118		| SCTP heartbeats are exchanged more frequently than DWR/DWA.
+		|
+119-124		| Concurrent DWR/DWA (it happens sometimes)
+		|
+125-128		| Another failed attempt to 192.168.103.30 (cf. frames 40-45)
+		|
+137-140		| DPR/DPA exchange.
+		|
+141-153		| TLS clean shutdown on all streams in parallel.
+		|
+154-157		| SCTP association is closed.
+-----------------------------------------------------------------------------
Index: contrib/wireshark/wireshark-1.2.7-diameter-tls.patch
===================================================================
--- contrib/wireshark/wireshark-1.2.7-diameter-tls.patch	(revision 726)
+++ contrib/wireshark/wireshark-1.2.7-diameter-tls.patch	(revision 726)
@@ -0,0 +1,685 @@
+diff -Nur wireshark-1.2.7/epan/conversation.c wireshark-1.2.7-fD/epan/conversation.c
+--- wireshark-1.2.7/epan/conversation.c	2010-04-01 01:44:39.000000000 +0900
++++ wireshark-1.2.7-fD/epan/conversation.c	2011-02-23 14:26:35.000000000 +0900
+@@ -40,6 +40,11 @@
+ static GHashTable *conversation_hashtable_exact = NULL;
+ 
+ /*
++ * Hash table for conversations without strid.
++ */
++static GHashTable *conversation_hashtable_no_strid = NULL;
++
++/*
+  * Hash table for conversations with one wildcard address.
+  */
+ static GHashTable *conversation_hashtable_no_addr2 = NULL;
+@@ -63,6 +68,7 @@
+ 	port_type ptype;
+ 	guint32	port1;
+ 	guint32	port2;
++	guint32	strid;
+ } conversation_key;
+ #endif
+ /*
+@@ -193,6 +199,7 @@
+ 	hash_val += key->port1;
+ 	ADD_ADDRESS_TO_HASH(hash_val, &key->addr2);
+ 	hash_val += key->port2;
++	hash_val += key->strid;
+ 
+ 	return hash_val;
+ }
+@@ -217,6 +224,78 @@
+ 	 */
+ 	if (v1->port1 == v2->port1 &&
+ 	    v1->port2 == v2->port2 &&
++	    v1->strid == v2->strid &&
++	    ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) &&
++	    ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) {
++		/*
++		 * Yes.  It's the same conversation, and the two
++		 * address/port pairs are going in the same direction.
++		 */
++		return 1;
++	}
++
++	/*
++	 * Is the first port 2 the same as the second port 1, the first
++	 * port 1 the same as the second port 2, the first address 2
++	 * the same as the second address 1, and the first address 1
++	 * the same as the second address 2?
++	 */
++	if (v1->port2 == v2->port1 &&
++	    v1->port1 == v2->port2 &&
++	    v1->strid == v2->strid &&
++	    ADDRESSES_EQUAL(&v1->addr2, &v2->addr1) &&
++	    ADDRESSES_EQUAL(&v1->addr1, &v2->addr2)) {
++		/*
++		 * Yes.  It's the same conversation, and the two
++		 * address/port pairs are going in opposite directions.
++		 */
++		return 1;
++	}
++
++	/*
++	 * The addresses or the ports don't match.
++	 */
++	return 0;
++}
++
++/*
++ * Compute the hash value for two given address/port pairs if the match
++ * has a wildcard stream id.
++ */
++static guint
++conversation_hash_no_strid(gconstpointer v)
++{
++	const conversation_key *key = (const conversation_key *)v;
++	guint hash_val;
++
++	hash_val = 0;
++	ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
++	hash_val += key->port1;
++	hash_val += key->port2;
++
++	return hash_val;
++}
++
++/*
++ * Compare two conversation keys, except for the stream id value.
++ */
++static gint
++conversation_match_no_strid(gconstpointer v, gconstpointer w)
++{
++	const conversation_key *v1 = (const conversation_key *)v;
++	const conversation_key *v2 = (const conversation_key *)w;
++
++	if (v1->ptype != v2->ptype)
++		return 0;	/* different types of port */
++
++	/*
++	 * Are the first and second port 1 values the same, the first and
++	 * second port 2 values the same, the first and second address
++	 * 1 values the same, and the first and second address 2 values
++	 * the same?
++	 */
++	if (v1->port1 == v2->port1 &&
++	    v1->port2 == v2->port2 &&
+ 	    ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) &&
+ 	    ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) {
+ 		/*
+@@ -263,6 +342,7 @@
+ 	ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
+ 	hash_val += key->port1;
+ 	hash_val += key->port2;
++	hash_val += key->strid;
+ 
+ 	return hash_val;
+ }
+@@ -289,6 +369,7 @@
+ 	 */
+ 	if (v1->port1 == v2->port1 &&
+ 	    v1->port2 == v2->port2 &&
++	    v1->strid == v2->strid &&
+ 	    ADDRESSES_EQUAL(&v1->addr1, &v2->addr1)) {
+ 		/*
+ 		 * Yes.  It's the same conversation, and the two
+@@ -317,6 +398,7 @@
+ 	ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
+ 	hash_val += key->port1;
+ 	ADD_ADDRESS_TO_HASH(hash_val, &key->addr2);
++	hash_val += key->strid;
+ 
+ 	return hash_val;
+ }
+@@ -342,6 +424,7 @@
+ 	 * address 2 values the same?
+ 	 */
+ 	if (v1->port1 == v2->port1 &&
++	    v1->strid == v2->strid &&
+ 	    ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) &&
+ 	    ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) {
+ 		/*
+@@ -370,6 +453,7 @@
+ 	hash_val = 0;
+ 	ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
+ 	hash_val += key->port1;
++	hash_val += key->strid;
+ 
+ 	return hash_val;
+ }
+@@ -394,6 +478,7 @@
+ 	 * and second address 1 values the same?
+ 	 */
+ 	if (v1->port1 == v2->port1 &&
++	    v1->strid == v2->strid &&
+ 	    ADDRESSES_EQUAL(&v1->addr1, &v2->addr1)) {
+ 		/*
+ 		 * Yes.  It's the same conversation, and the two
+@@ -420,6 +505,8 @@
+ 	conversation_keys = NULL;
+ 	if (conversation_hashtable_exact != NULL)
+ 		g_hash_table_destroy(conversation_hashtable_exact);
++	if (conversation_hashtable_no_strid != NULL)
++		g_hash_table_destroy(conversation_hashtable_no_strid);
+ 	if (conversation_hashtable_no_addr2 != NULL)
+ 		g_hash_table_destroy(conversation_hashtable_no_addr2);
+ 	if (conversation_hashtable_no_port2 != NULL)
+@@ -438,6 +525,9 @@
+ 	conversation_hashtable_exact =
+ 	    g_hash_table_new(conversation_hash_exact,
+ 	      conversation_match_exact);
++	conversation_hashtable_no_strid =
++	    g_hash_table_new(conversation_hash_no_strid,
++	      conversation_match_no_strid);
+ 	conversation_hashtable_no_addr2 =
+ 	    g_hash_table_new(conversation_hash_no_addr2,
+ 	      conversation_match_no_addr2);
+@@ -466,6 +556,15 @@
+ conversation_new(guint32 setup_frame, address *addr1, address *addr2, port_type ptype,
+     guint32 port1, guint32 port2, guint options)
+ {
++	return conversation_new_ext(setup_frame, addr1, addr2, ptype,
++    		port1, port2, options & ~(DISTINCT_SCTP_STREAMID), 0);
++
++}
++
++conversation_t *
++conversation_new_ext(guint32 setup_frame, address *addr1, address *addr2, port_type ptype,
++    guint32 port1, guint32 port2, guint options, guint16 strid)
++{
+ /*
+ 	DISSECTOR_ASSERT(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
+ 				"A conversation template may not be constructed without wildcard options");
+@@ -486,7 +585,11 @@
+ 		if (options & (NO_PORT2|NO_PORT2_FORCE)) {
+ 			hashtable = conversation_hashtable_no_port2;
+ 		} else {
+-			hashtable = conversation_hashtable_exact;
++			if (options & DISTINCT_SCTP_STREAMID) {
++				hashtable = conversation_hashtable_exact;
++			} else {
++				hashtable = conversation_hashtable_no_strid;
++			}
+ 		}
+ 	}
+ 
+@@ -495,6 +598,7 @@
+ 	existing_key.ptype = ptype;
+ 	existing_key.port1 = port1;
+ 	existing_key.port2 = port2;
++	existing_key.strid = strid;
+ 
+ 	conversation = g_hash_table_lookup(hashtable, &existing_key);
+ 	tc = conversation; /* Remember if lookup was successful */
+@@ -507,6 +611,7 @@
+ 	new_key->ptype = ptype;
+ 	new_key->port1 = port1;
+ 	new_key->port2 = port2;
++	new_key->strid = strid;
+ 
+ 	if (conversation) {
+ 		for (; conversation->next; conversation = conversation->next)
+@@ -568,8 +673,13 @@
+ 		g_hash_table_insert(conversation_hashtable_no_addr2,
+ 		    conv->key_ptr, conv);
+ 	} else {
+-		g_hash_table_insert(conversation_hashtable_exact,
+-		    conv->key_ptr, conv);
++		if (conv->options & DISTINCT_SCTP_STREAMID) {
++			g_hash_table_insert(conversation_hashtable_exact,
++			    conv->key_ptr, conv);
++		} else {
++			g_hash_table_insert(conversation_hashtable_no_strid,
++			    conv->key_ptr, conv);
++		}
+ 	}
+ }
+ 
+@@ -602,18 +712,23 @@
+ 		g_hash_table_insert(conversation_hashtable_no_port2,
+ 		    conv->key_ptr, conv);
+ 	} else {
+-		g_hash_table_insert(conversation_hashtable_exact,
+-		    conv->key_ptr, conv);
++		if (conv->options & DISTINCT_SCTP_STREAMID) {
++			g_hash_table_insert(conversation_hashtable_exact,
++			    conv->key_ptr, conv);
++		} else {
++			g_hash_table_insert(conversation_hashtable_no_strid,
++			    conv->key_ptr, conv);
++		}
+ 	}
+ }
+ 
+ /*
+  * Search a particular hash table for a conversation with the specified
+- * {addr1, port1, addr2, port2} and set up before frame_num.
++ * {addr1, port1, addr2, port2, strid} and set up before frame_num.
+  */
+ static conversation_t *
+ conversation_lookup_hashtable(GHashTable *hashtable, guint32 frame_num, address *addr1, address *addr2,
+-    port_type ptype, guint32 port1, guint32 port2)
++    port_type ptype, guint32 port1, guint32 port2, guint16 strid)
+ {
+ 	conversation_t* conversation;
+ 	conversation_t* match;
+@@ -628,6 +743,7 @@
+ 	key.ptype = ptype;
+ 	key.port1 = port1;
+ 	key.port2 = port2;
++	key.strid = strid;
+ 
+ 	match = g_hash_table_lookup(hashtable, &key);
+ 
+@@ -685,12 +801,19 @@
+ find_conversation(guint32 frame_num, address *addr_a, address *addr_b, port_type ptype,
+     guint32 port_a, guint32 port_b, guint options)
+ {
++	return find_conversation_ext(frame_num, addr_a, addr_b, ptype,
++    		port_a, port_b, options | IGNORE_SCTP_STREAMID, 0);
++}
++conversation_t *
++find_conversation_ext(guint32 frame_num, address *addr_a, address *addr_b, port_type ptype,
++    guint32 port_a, guint32 port_b, guint options, guint16 strid)
++{
+    conversation_t *conversation;
+ 
+    /*
+-    * First try an exact match, if we have two addresses and ports.
++    * First try an exact match, if we have two addresses and ports and strid.
+     */
+-   if (!(options & (NO_ADDR_B|NO_PORT_B))) {
++   if (!(options & (NO_ADDR_B|NO_PORT_B|IGNORE_SCTP_STREAMID))) {
+       /*
+        * Neither search address B nor search port B are wildcarded,
+        * start out with an exact match.
+@@ -699,7 +822,7 @@
+       conversation =
+          conversation_lookup_hashtable(conversation_hashtable_exact,
+          frame_num, addr_a, addr_b, ptype,
+-         port_a, port_b);
++         port_a, port_b, strid);
+       if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+          /* In Fibre channel, OXID & RXID are never swapped as
+           * TCP/UDP ports are in TCP/IP.
+@@ -707,7 +830,33 @@
+          conversation =
+             conversation_lookup_hashtable(conversation_hashtable_exact,
+             frame_num, addr_b, addr_a, ptype,
+-            port_a, port_b);
++            port_a, port_b, strid);
++      }
++      if (conversation != NULL)
++         return conversation;
++   }
++
++   /*
++    * Then, ignoring strid try an exact match, if we have two addresses and ports.
++    */
++   if (!(options & (NO_ADDR_B|NO_PORT_B|NO_IGNORE_SCTP_STREAMID))) {
++      /*
++       * 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_no_strid,
++         frame_num, addr_a, addr_b, ptype,
++         port_a, port_b, strid);
++      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_strid,
++            frame_num, addr_b, addr_a, ptype,
++            port_a, port_b, strid);
+       }
+       if (conversation != NULL)
+          return conversation;
+@@ -729,7 +878,7 @@
+        */
+       conversation =
+          conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+-         frame_num, addr_a, addr_b, ptype, port_a, port_b);
++         frame_num, addr_a, addr_b, ptype, port_a, port_b, strid);
+       if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+          /* In Fibre channel, OXID & RXID are never swapped as
+           * TCP/UDP ports are in TCP/IP.
+@@ -737,7 +886,7 @@
+          conversation =
+             conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+             frame_num, addr_b, addr_a, ptype,
+-            port_a, port_b);
++            port_a, port_b, strid);
+       }
+       if (conversation != NULL) {
+          /*
+@@ -779,7 +928,7 @@
+       if (!(options & NO_ADDR_B)) {
+          conversation =
+             conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+-            frame_num, addr_b, addr_a, ptype, port_b, port_a);
++            frame_num, addr_b, addr_a, ptype, port_b, port_a, strid);
+          if (conversation != NULL) {
+             /*
+              * If this is for a connection-oriented
+@@ -821,14 +970,14 @@
+        */
+       conversation =
+          conversation_lookup_hashtable(conversation_hashtable_no_port2,
+-         frame_num, addr_a, addr_b, ptype, port_a, port_b);
++         frame_num, addr_a, addr_b, ptype, port_a, port_b, strid);
+       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,
+-            frame_num, addr_b, addr_a, ptype, port_a, port_b);
++            frame_num, addr_b, addr_a, ptype, port_a, port_b, strid);
+       }
+       if (conversation != NULL) {
+          /*
+@@ -870,7 +1019,7 @@
+       if (!(options & NO_PORT_B)) {
+          conversation =
+             conversation_lookup_hashtable(conversation_hashtable_no_port2,
+-            frame_num, addr_b, addr_a, ptype, port_b, port_a);
++            frame_num, addr_b, addr_a, ptype, port_b, port_a, strid);
+          if (conversation != NULL) {
+             /*
+              * If this is for a connection-oriented
+@@ -907,7 +1056,7 @@
+     */
+    conversation =
+       conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+-      frame_num, addr_a, addr_b, ptype, port_a, port_b);
++      frame_num, addr_a, addr_b, ptype, port_a, port_b, strid);
+    if (conversation != NULL) {
+       /*
+        * If this is for a connection-oriented protocol:
+@@ -952,11 +1101,11 @@
+    if (addr_a->type == AT_FC)
+       conversation =
+       conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+-      frame_num, addr_b, addr_a, ptype, port_a, port_b);
++      frame_num, addr_b, addr_a, ptype, port_a, port_b, strid);
+    else
+       conversation =
+       conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+-      frame_num, addr_b, addr_a, ptype, port_b, port_a);
++      frame_num, addr_b, addr_a, ptype, port_b, port_a, strid);
+    if (conversation != NULL) {
+       /*
+        * If this is for a connection-oriented protocol, set the
+diff -Nur wireshark-1.2.7/epan/conversation.h wireshark-1.2.7-fD/epan/conversation.h
+--- wireshark-1.2.7/epan/conversation.h	2010-04-01 01:44:39.000000000 +0900
++++ wireshark-1.2.7-fD/epan/conversation.h	2011-02-23 14:25:44.000000000 +0900
+@@ -39,11 +39,13 @@
+  * TEMPLATE flag will be altered once the first connections (connection
+  * oriented protocols only) to include the newly found information which
+  * matched the wildcard options.
++ * DISTINCT_SCTP_STREAMID will also save the SCTP stream identifier, if any.
+  */
+ #define NO_ADDR2 0x01
+ #define NO_PORT2 0x02
+ #define NO_PORT2_FORCE 0x04
+ #define CONVERSATION_TEMPLATE 0x08
++#define DISTINCT_SCTP_STREAMID 0x10
+ 
+ /*
+  * Flags to pass to "find_conversation()" to indicate that the address B
+@@ -51,6 +53,8 @@
+  */
+ #define NO_ADDR_B 0x01
+ #define NO_PORT_B 0x02
++#define IGNORE_SCTP_STREAMID 0x04
++#define NO_IGNORE_SCTP_STREAMID 0x08
+ 
+ #include "packet.h"		/* for conversation dissector type */
+ 
+@@ -64,6 +68,7 @@
+ 	port_type ptype;
+ 	guint32	port1;
+ 	guint32	port2;
++	guint16	strid;
+ } conversation_key;
+ 
+ typedef struct conversation {
+@@ -85,6 +90,13 @@
+ extern conversation_t *find_conversation(guint32 frame_num, address *addr_a, address *addr_b,
+     port_type ptype, guint32 port_a, guint32 port_b, guint options);
+ 
++/* for SCTP stream */
++extern conversation_t *conversation_new_ext(guint32 setup_frame, address *addr1, address *addr2,
++    port_type ptype, guint32 port1, guint32 port2, guint options, guint16 strid);
++extern conversation_t *find_conversation_ext(guint32 frame_num, address *addr_a, address *addr_b,
++    port_type ptype, guint32 port_a, guint32 port_b, guint options, guint16 strid);
++    
++
+ 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);
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-diameter.c wireshark-1.2.7-fD/epan/dissectors/packet-diameter.c
+--- wireshark-1.2.7/epan/dissectors/packet-diameter.c	2010-04-01 01:44:21.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-diameter.c	2011-02-23 13:33:10.000000000 +0900
+@@ -63,8 +63,10 @@
+ #include "packet-ntp.h"
+ #include "packet-diameter.h"
+ #include "diam_dict.h"
++#include "packet-ssl.h"
+ 
+ #define SCTP_PORT_DIAMETER	3868
++#define SCTP_TLS_PORT_DIAMETER	3869
+ 
+ /* Diameter Header Flags */
+ /*                                      RPETrrrrCCCCCCCCCCCCCCCCCCCCCCCC  */
+@@ -271,10 +273,13 @@
+ 
+ 
+ static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
++static guint gbl_diameterSctpTlsPort=SCTP_TLS_PORT_DIAMETER;
+ 
+ static dissector_handle_t diameter_tcp_handle;
+ static range_t *global_diameter_tcp_port_range;
++static range_t *global_diameter_tcp_tls_port_range;
+ #define DEFAULT_DIAMETER_PORT_RANGE "3868"
++#define DEFAULT_DIAMETER_TLS_PORT_RANGE "3869"
+ 
+ /* desegmentation of Diameter over TCP */
+ static gboolean gbl_diameter_desegment = TRUE;
+@@ -1358,13 +1363,27 @@
+     dissector_add("tcp.port", port, diameter_tcp_handle);
+ }
+ 
++static void
++range_delete_callback_sec(guint32 port)
++{
++    ssl_dissector_delete(port, "diameter", TRUE);
++}
++
++static void
++range_add_callback_sec(guint32 port)
++{
++    ssl_dissector_add(port, "diameter", TRUE);
++}
++
+ void
+ proto_reg_handoff_diameter(void)
+ {
+ 	static gboolean Initialized=FALSE;
+ 	static guint SctpPort;
++	static guint SctpsPort;
+ 	static dissector_handle_t diameter_handle;
+ 	static range_t *diameter_tcp_port_range;
++	static range_t *diameters_tcp_port_range;
+ 
+ 	if (!Initialized) {
+ 		diameter_handle = find_dissector("diameter");
+@@ -1382,20 +1401,27 @@
+ 		/* AVP Code: 463 EAP-Reissued-Payload */
+ 		dissector_add("diameter.base", 463, 
+ 			new_create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
++			
++		/* set port for future deletes */
++		diameter_tcp_port_range = range_copy(global_diameter_tcp_port_range);
++		range_foreach(diameter_tcp_port_range, range_add_callback);
++		diameters_tcp_port_range = range_copy(global_diameter_tcp_tls_port_range);
++		range_foreach(diameters_tcp_port_range, range_add_callback_sec);
++		
++		dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
++		ssl_dissector_add(gbl_diameterSctpTlsPort, "diameter", TRUE);
+ 
+ 		Initialized=TRUE;
+ 	} else {
+ 		range_foreach(diameter_tcp_port_range, range_delete_callback);
+ 		g_free(diameter_tcp_port_range);
++		range_foreach(diameters_tcp_port_range, range_delete_callback_sec);
++		g_free(diameters_tcp_port_range);
+ 		dissector_delete("sctp.port", SctpPort, diameter_handle);
+ 	}
+ 
+-	/* set port for future deletes */
+-	diameter_tcp_port_range = range_copy(global_diameter_tcp_port_range);
+-	range_foreach(diameter_tcp_port_range, range_add_callback);
+ 
+-	SctpPort=gbl_diameterSctpPort;
+-	dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
++	
+ }
+ 
+ /* registration with the filtering engine */
+@@ -1543,8 +1569,9 @@
+ 	diameter_dissector_table = register_dissector_table("diameter.base", "DIAMETER_3GPP_AVPS", FT_UINT32, BASE_DEC);
+ 	diameter_3gpp_avp_dissector_table = register_dissector_table("diameter.3gpp", "DIAMETER_3GPP_AVPS", FT_UINT32, BASE_DEC);
+ 
+-	/* Set default TCP ports */
++	/* Set default TCP & TLS ports */
+ 	range_convert_str(&global_diameter_tcp_port_range, DEFAULT_DIAMETER_PORT_RANGE, MAX_UDP_PORT);
++	range_convert_str(&global_diameter_tcp_tls_port_range, DEFAULT_DIAMETER_TLS_PORT_RANGE, MAX_UDP_PORT);
+ 
+ 	/* Register configuration options for ports */
+ 	diameter_module = prefs_register_protocol(proto_diameter,
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-sctp.c wireshark-1.2.7-fD/epan/dissectors/packet-sctp.c
+--- wireshark-1.2.7/epan/dissectors/packet-sctp.c	2010-04-01 01:44:28.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-sctp.c	2011-02-23 13:54:13.000000000 +0900
+@@ -2693,6 +2693,7 @@
+   b_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_B_BIT;
+   u_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_U_BIT;
+   stream_id = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
++  pinfo->strid = stream_id;
+   stream_seq_num = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
+   tsn = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
+ 
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-ssl.c wireshark-1.2.7-fD/epan/dissectors/packet-ssl.c
+--- wireshark-1.2.7/epan/dissectors/packet-ssl.c	2010-04-01 01:44:34.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-ssl.c	2011-02-23 14:56:36.000000000 +0900
+@@ -500,6 +500,7 @@
+     guint* conv_version;
+     Ssl_private_key_t * private_key;
+     guint32 port;
++    guint16 strid;
+ 
+     ti = NULL;
+     ssl_tree   = NULL;
+@@ -507,9 +508,14 @@
+     first_record_in_frame = TRUE;
+     ssl_session = NULL;
+     port = 0;
++    strid = 0;
+ 
+ 
+     ssl_debug_printf("\ndissect_ssl enter frame #%u (%s)\n", pinfo->fd->num, (pinfo->fd->flags.visited)?"already visited":"first time");
++    
++    if (pinfo->ptype == PT_SCTP) {
++    	ssl_debug_printf("\ndissect_ssl SCTP stream %hd\n", pinfo->strid);
++    }
+ 
+     /* Track the version using conversations to reduce the
+      * chance that a packet that simply *looks* like a v2 or
+@@ -523,14 +529,14 @@
+      *       the conv_version, must set the copy in the conversation
+      *       in addition to conv_version
+      */
+-    conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+-                                     pinfo->srcport, pinfo->destport, 0);
++    conversation = find_conversation_ext(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
++                                     pinfo->srcport, pinfo->destport, NO_IGNORE_SCTP_STREAMID, pinfo->strid);
+ 
+     if (!conversation)
+     {
+         /* create a new conversation */
+-        conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+-                                        pinfo->srcport, pinfo->destport, 0);
++        conversation = conversation_new_ext(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
++                                        pinfo->srcport, pinfo->destport, (pinfo->ptype == PT_SCTP) ? DISTINCT_SCTP_STREAMID : 0, pinfo->strid);
+         ssl_debug_printf("  new conversation = %p created\n", (void *)conversation);
+     }
+     conv_data = conversation_get_proto_data(conversation, proto_ssl);
+@@ -549,7 +555,7 @@
+         conversation_add_proto_data(conversation, proto_ssl, ssl_session);
+ 
+         /* we need to know which side of the conversation is speaking */
+-        if (ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP)) {
++        if (ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP)) {
+             dummy.addr = pinfo->src;
+             dummy.port = port = pinfo->srcport;
+         } else {
+@@ -762,7 +768,7 @@
+      * add decrypted data to this packet info */
+     ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl, state 0x%02X\n",
+         record_length, ssl->state);
+-    direction = ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
++    direction = ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP);
+ 
+     /* retrieve decoder for this packet direction */
+     if (direction != 0) {
+@@ -1504,7 +1510,7 @@
+             col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
+         dissect_ssl3_change_cipher_spec(tvb, ssl_record_tree,
+                                         offset, conv_version, content_type);
+-        if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP));
++        if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP));
+         break;
+     case SSL_ID_ALERT:
+     {
+@@ -1566,8 +1572,8 @@
+         /* we need dissector information when the selected packet is shown.
+          * ssl session pointer is NULL at that time, so we can't access
+          * info cached there*/
+-        association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
+-        association = association ? association: ssl_association_find(ssl_associations, pinfo->destport, pinfo->ptype == PT_TCP);
++        association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP);
++        association = association ? association: ssl_association_find(ssl_associations, pinfo->destport, pinfo->ptype != PT_UDP);
+ 
+         proto_item_set_text(ssl_record_tree,
+            "%s Record Layer: %s Protocol: %s",
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-ssl-utils.c wireshark-1.2.7-fD/epan/dissectors/packet-ssl-utils.c
+--- wireshark-1.2.7/epan/dissectors/packet-ssl-utils.c	2010-04-01 01:44:27.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-ssl-utils.c	2011-02-23 13:33:10.000000000 +0900
+@@ -2713,9 +2713,10 @@
+     fprintf(stderr, "association_add() could not find handle for protocol:%s\n",protocol);
+   } else {
+     if(port) {
+-      if(tcp)
++      if(tcp) {
+         dissector_add("tcp.port", port, handle);
+-      else
++        dissector_add("sctp.port", port, handle);
++      } else
+         dissector_add("udp.port", port, handle);
+     }
+     g_tree_insert(associations, assoc, assoc);
+diff -Nur wireshark-1.2.7/epan/packet_info.h wireshark-1.2.7-fD/epan/packet_info.h
+--- wireshark-1.2.7/epan/packet_info.h	2010-04-01 01:44:40.000000000 +0900
++++ wireshark-1.2.7-fD/epan/packet_info.h	2011-02-23 13:54:52.000000000 +0900
+@@ -169,6 +169,7 @@
+   tvbuff_t *gssapi_decrypted_tvb;
+   gboolean gssapi_data_encrypted;
+ 
++  guint16 strid; /* Stream Id of the last DATA chunk in the packet */
+   guint32 ppid;  /* SCTP PPI of current DATA chunk */
+   guint32 ppids[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present
+                                       * in the SCTP packet
