From c74f85f7ab6c7b3712d1a2c279f950530fb4def7 Mon Sep 17 00:00:00 2001
From: Viktor Krikun <v.krikun@zfoneproject.com>
Date: Sat, 19 Nov 2011 13:40:00 +0000
Subject: [PATCH] Recheck and implement missing features in Acive-Passive logs

(closes #23)
---
 include/zrtp.h                                | 42 ++++++++++-----
 include/zrtp_engine.h                         |  8 +--
 include/zrtp_log.h                            |  8 +++
 include/zrtp_pbx.h                            | 13 +++++
 include/zrtp_protocol.h                       |  9 ++--
 include/zrtp_types.h                          | 33 ++++++++----
 .../xcode/libzrtp.xcodeproj/project.pbxproj   |  2 +-
 src/zrtp.c                                    | 23 +++++---
 src/zrtp_engine.c                             | 42 ++++++++++++++-
 src/zrtp_log.c                                | 15 ++++++
 src/zrtp_pbx.c                                | 52 +++++++++++++++++++
 src/zrtp_protocol.c                           | 29 ++++++++++-
 12 files changed, 233 insertions(+), 43 deletions(-)

diff --git a/include/zrtp.h b/include/zrtp.h
index 2927b2a4aa..37595ab735 100644
--- a/include/zrtp.h
+++ b/include/zrtp.h
@@ -115,6 +115,24 @@ typedef enum zrtp_license_mode_t
 	ZRTP_LICENSE_MODE_UNLIMITED
 } zrtp_license_mode_t;
 
+/**
+ * @brief Enumeration to define Signaling initiator/responder roles.
+ * 
+ * Used by libzrtp to optimize some internal processes and protocol handshake.
+ *
+ * @sas zrtp_stream_start().
+ */
+typedef enum zrtp_signaling_role_t
+{
+	/** @brief Unknown Signaling role, should be used when the app can't determine the role. */
+	ZRTP_SIGNALING_ROLE_UNKNOWN	= 0,
+	/** @brief Signaling Initiator. */	
+	ZRTP_SIGNALING_ROLE_INITIATOR,
+	/** @brief Signaling Responder. */
+	ZRTP_SIGNALING_ROLE_RESPONDER,	
+	ZRTP_SIGNALING_ROLE_COUNT
+} zrtp_signaling_role_t;
+
 
 /** @brief 12-byte ZID for unique ZRTP endpoint identification. */
 typedef unsigned char zrtp_zid_t[12];
@@ -123,9 +141,9 @@ typedef unsigned char zrtp_zid_t[12];
 typedef char zrtp_client_id_t[16];
 	
 /**
- * \brief ZRTP global configuration options
- * \ingroup zrtp_main_init
- * \warning Use \ref zrtp_config_defaults() before start configuring this structure.
+ * @brief ZRTP global configuration options
+ * @ingroup zrtp_main_init
+ * @warning Use \ref zrtp_config_defaults() before start configuring this structure.
  */
 typedef struct zrtp_config_t
 {	
@@ -431,10 +449,9 @@ zrtp_status_t zrtp_down(zrtp_global_t* zrtp);
  * \param profile - the session configuration profile. If value of this parameter is NULL, default 
  *     profile will be used. NULL profile usage is equivalent to calling zrtp_profile_defaults().
  * \param zid - ZRTP peer identificator.  
- * \param is_initiator - identifies if the endpoint was the signaling initiator of the call. Used to 
+ * \param role - identifies if the endpoint was the signaling initiator of the call. Used to 
  *    provide Passive Mode options to the developer. If your application doesn't control signaling 
- *    or you don't want to support Passive Mode features - set this flag to 1. Check \ref XXX for 
- *    more information.
+ *    or you don't want to support Passive Mode features - set it to ZRTP_SIGNALING_ROLE_UNKNOWN.
  * \param session - allocated session structure.
  * \return 
  *  - zrtp_status_ok if initialization is successful;
@@ -444,7 +461,7 @@ zrtp_status_t zrtp_down(zrtp_global_t* zrtp);
 zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp,
 								 zrtp_profile_t* profile,
 								 zrtp_zid_t zid,
-								 uint8_t is_initiator,
+								 zrtp_signaling_role_t role,
 								 zrtp_session_t **session);
 /**
  * \brief ZRTP Session context deinitialization
@@ -461,8 +478,8 @@ void zrtp_session_down(zrtp_session_t *session);
 /**
  * \brief Obtain information about ZRTP session
  *
- * Function initialize and fills all fields of zrtp_session_info_t structure accordint to
- * current state of ZRTP session.
+ * Function initialize and fills all fields of zrtp_session_info_t structure according to
+ * the current state of ZRTP session.
  *
  * \param session - zrtp session which parameters should be extracted;
  * \param info - out structure to be initialized.
@@ -530,7 +547,8 @@ zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream
  *  - \ref XXX_GUIDE_CB \ref XXX_GUIDE_MANAGEMENT
  *  - zrtp_stream_stop() zrtp_stream_secure() zrtp_stream_clear()
  */
-zrtp_status_t zrtp_stream_start(zrtp_stream_t* stream, uint32_t ssrc);
+zrtp_status_t zrtp_stream_start(zrtp_stream_t* stream,
+								uint32_t ssrc);
 
 /**
  * \brief ZRTP protocol stopping
@@ -751,7 +769,7 @@ zrtp_status_t  zrtp_process_srtcp( zrtp_stream_t *stream,
 /* \} */
 
 /**
- * \defgroup zrtp_main_utils Utilites
+ * \defgroup zrtp_main_utils Utilities
  * \ingroup zrtp_api
  * \{
  */
@@ -768,7 +786,7 @@ zrtp_status_t  zrtp_process_srtcp( zrtp_stream_t *stream,
  * starting the protocol from the ZRTP_STATE_ACTIVE state.
  * 
  * \param stream - stream for operating with;
- * \param hash_buff - signaling hash buffer. Function accpt string, not a binary value!;
+ * \param hash_buff - signaling hash buffer. Function accepts string, not a binary value!;
  * \param hash_buff_length - signaling hash length in bytes (must be 64 bytes);
  * \return:
  *  - zrtp_status_ok if the operation finished successfully
diff --git a/include/zrtp_engine.h b/include/zrtp_engine.h
index 8b818dee2d..a2c7e05de5 100644
--- a/include/zrtp_engine.h
+++ b/include/zrtp_engine.h
@@ -58,7 +58,7 @@ extern "C"
  */
 #define ZRTP_PASSIVE2_TEST(stream) \
 ( !((ZRTP_LICENSE_MODE_PASSIVE == stream->zrtp->lic_mode) && \
-	stream->session->is_initiator) )
+	(stream->session->signaling_role == ZRTP_SIGNALING_ROLE_INITIATOR)) )
 	
 /**
  * @brief Test Passive Rule N3
@@ -128,7 +128,7 @@ zrtp_status_t _zrtp_protocol_decrypt( zrtp_protocol_t *self,
 	
 	
 /*===========================================================================*/
-/*	CRTPTO Utilites														     */
+/*	CRTPTO Utilities														     */
 /*===========================================================================*/
 
 /**
@@ -237,7 +237,7 @@ int _zrtp_can_start_stream( zrtp_stream_t* stream,
 						    zrtp_stream_t** conc,
 						    zrtp_stream_mode_t mode);
 
-/** Return ZRTP Stream mode which sould be used for current stream. */
+/** Return ZRTP Stream mode which should be used for current stream. */
 zrtp_stream_mode_t _zrtp_define_stream_mode(zrtp_stream_t* stream);
 
 /*!
@@ -257,7 +257,7 @@ uint8_t _zrtp_choose_best_comp( zrtp_profile_t* profile,
 
 /*!
  * \brief Computes replay timeouts
- * This function computes messages replays schedule. There are some recomended
+ * This function computes messages replays schedule. There are some recommended
  * values by ZRTP specification, but in some network environments values may be
  * sligh different
  */
diff --git a/include/zrtp_log.h b/include/zrtp_log.h
index 75193ac1d5..ca2213eca4 100644
--- a/include/zrtp_log.h
+++ b/include/zrtp_log.h
@@ -143,6 +143,14 @@ const char* zrtp_log_mode2str(zrtp_stream_mode_t mode);
 /** Returns symbolical name of the protocol and security events. */
 const char* zrtp_log_event2str(uint8_t event);
 
+/**
+ * Returns character name of the Signaling role.
+ *
+ * @param role One of zrtp_signaling_role_t values.
+ * @return character name of the \c role.
+ */
+const char* zrtp_log_sign_role2str(unsigned role);
+
 
 /** Print out ZRTP environment configuration setting to log level 3. */
 void  zrtp_print_env_settings();
diff --git a/include/zrtp_pbx.h b/include/zrtp_pbx.h
index 94ce80cce1..485ec74670 100644
--- a/include/zrtp_pbx.h
+++ b/include/zrtp_pbx.h
@@ -91,6 +91,19 @@ zrtp_status_t zrtp_register_with_trusted_mitm(zrtp_stream_t* stream);
  * \ref XXX_DRAFT, XXX_GUIDE
  */
 zrtp_status_t zrtp_resolve_mitm_call(zrtp_stream_t* stream1, zrtp_stream_t* stream2);
+	
+/**
+ * @brief Links two lags of Trusted ZRTP MiTM call together.
+ * 
+ * This function allows libzrtp2 to optimize protocol behavior of one leg depending on the state and
+ * parameters of the other lag. MitM boxes should use this API whenever possible.
+ *
+ * @param stream1 - one leg of the trusted MiTM call;
+ * @param stream2 - another leg of the trusted MiTM call.
+ *
+ * @return zrtp_status_ok in case of success.
+ */
+zrtp_status_t zrtp_link_mitm_calls(zrtp_stream_t* stream1, zrtp_stream_t* stream2);
 
 /**
  * \brief Updates remote-side SAS value and rendering scheme
diff --git a/include/zrtp_protocol.h b/include/zrtp_protocol.h
index 7e8986ff55..fbc157dfa7 100644
--- a/include/zrtp_protocol.h
+++ b/include/zrtp_protocol.h
@@ -282,7 +282,8 @@ typedef struct zrtp_packet_Hello
 	
 	/** Signature support flag */
 	uint8_t			sigflag:1;
-	uint8_t			padding1:1;
+		
+	uint8_t			uflag:1;
 	
 	/** Hash scheme count */	
 	uint8_t			hc:4;	
@@ -300,7 +301,7 @@ typedef struct zrtp_packet_Hello
 	/** PK Type count */
 	uint8_t			kc:4;
 #elif ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN
-	uint8_t			padding1:1;
+	uint8_t			uflag:1;
 	uint8_t			sigflag:1;
 	uint8_t			mitmflag:1;
 	uint8_t			pasive:1;
@@ -400,7 +401,7 @@ typedef struct zrtp_packet_Confirm
 	/** Unused (Set to zero and ignored) */
 	uint8_t				pad[2];
 	
-	/** Length of optionas signature field  */
+	/** Length of optional signature field  */
 	uint8_t				sig_length;
 	
 	/** boolean flags for allowclear, SAS verified and disclose */	
@@ -478,7 +479,7 @@ typedef struct
 	zrtp_msg_hdr_t	hdr;
 	zrtp_uchar4_t	version;			/** Zfone discovery protocol version */
 	zrtp_uchar8_t	endpointhash;		/** Zfone endpoint unique identifier */
-	zrtp_uchar8_t	peerendpointhash;	/**    EndpointHash copied from Ping message */
+	zrtp_uchar8_t	peerendpointhash;	/** EndpointHash copied from Ping message */
 	uint32_t		peerssrc;
 } zrtp_packet_zfonepingack_t;
 
diff --git a/include/zrtp_types.h b/include/zrtp_types.h
index 817caafa1d..fa7b0f1034 100644
--- a/include/zrtp_types.h
+++ b/include/zrtp_types.h
@@ -51,7 +51,7 @@ typedef enum zrtp_state_t
 	ZRTP_STATE_PENDINGCLEAR,			/** CLEAR request have been received */
 	ZRTP_STATE_INITIATINGERROR,			/** Protocol ERROR detected on local side */
 	ZRTP_STATE_PENDINGERROR,			/** Protocol ERROR received from the remote peer */
-	ZRTP_STATE_ERROR,					/** Protcol ERROR state. Check zrtp_stream_info#last_error*/
+	ZRTP_STATE_ERROR,					/** Protocol ERROR state. Check zrtp_stream_info#last_error*/
 #if (defined(ZRTP_BUILD_FOR_CSD) && (ZRTP_BUILD_FOR_CSD == 1))
 	ZRTP_STATE_DRIVEN_INITIATOR,
 	ZRTP_STATE_DRIVEN_RESPONDER,
@@ -404,7 +404,7 @@ struct zrtp_global_t
     /** This object is used to synchronize sessions list operations */
     zrtp_mutex_t*			sessions_protector;
 		
-	/** Set of feedback callbacks used by libzrtp to interact witrh the user-space.*/
+	/** Set of feedback callbacks used by libzrtp to interact with the user-space.*/
 	zrtp_callback_t			cb;
 };
 
@@ -471,7 +471,7 @@ typedef struct zrtp_secrets_t
 	uint32_t				wrongs;
 	uint32_t				wrongs_curr;
 	
-	/** This flag equals one iff the secrets have been uploaded from the cache. */
+	/** This flag equals one if the secrets have been uploaded from the cache. */
     uint8_t					is_ready;	
 } zrtp_secrets_t;
 
@@ -543,7 +543,7 @@ typedef struct zrtp_dh_crypto_context_t
 	/** DH public value */
 	struct BigNum			pv;
 	
-	/** DH public value precalculated for remote side */
+	/** DH public value recalculated for remote side */
 	struct BigNum			peer_pv;
 	
 	/** DH shared secret. DHSS = hash(DHResult) */
@@ -742,7 +742,7 @@ struct zrtp_stream_t
 	uint8_t					allowclear;
 	
 	/*!
-	 * This flag shows when remote side is "pasice" (has license mode PASSIVE)
+	 * This flag shows when remote side is "passive" (has license mode PASSIVE)
 	 * Available for reading in CLEAR state.      
 	 */
 	uint8_t					peer_passive;
@@ -780,6 +780,11 @@ struct zrtp_stream_t
 	 */
 	uint8_t					peer_mitm_flag;
 	
+	/**
+	 * Duplicates U flag from peer Hello message
+	 */
+	uint8_t					peer_super_flag;
+	
 	/*!
 	 * \brief Pointer to the concurrent DH stream
 	 * If Commit messages are sent by both ZRTP endpoints at the same time, but
@@ -796,7 +801,7 @@ struct zrtp_stream_t
 	/** Back-pointer to the ZRTP global data */
 	zrtp_global_t			*zrtp;
 	
-	/** Pointer to paren t-session context. Used for back capability */
+	/** Pointer to parent session context. Used for back capability */
 	zrtp_session_t			*session;
 	
 	/*!< Public key exchange component used within current stream */
@@ -808,6 +813,12 @@ struct zrtp_stream_t
 	 */
 	void					*usr_data;
 	
+	/*!
+	 * Pointer to the peer stream during a trusted MiTM call.
+	 * @sa zrtp_link_mitm_calls()
+	 */
+	zrtp_stream_t			*linked_mitm;
+	
 	/*!
 	 * \brief Stream data protector
 	 * A mutex is used to avoid race conditions during asynchronous calls
@@ -846,11 +857,13 @@ struct zrtp_session_t
 	 */
 	zrtp_string16_t			peer_zid;
 	
-	/*!< ZRTP profile, defined crypto options and behavior for every stream within cirrent session */
+	/*!< ZRTP profile, defined crypto options and behavior for every stream within current session */
 	zrtp_profile_t			profile;
 	
-	/**	Define endpoint Signaling role. Different from ZRTP Initiator/Responder role */
-	uint8_t					is_initiator;
+	/*
+	 * Signaling Role which protocol was started with, one of zrtp_signaling_role_t values.
+	 */
+	unsigned				signaling_role;
 	
 	/*!
 	 * \brief Set of retained secrets and flags for the current ZRTP session.
@@ -859,7 +872,7 @@ struct zrtp_session_t
 	 */
 	zrtp_secrets_t			secrets;
 	
-	/*!< ZRTP session key used to extand ZRTP session without additional DH exchange */
+	/*!< ZRTP session key used to extend ZRTP session without additional DH exchange */
 	zrtp_string64_t			zrtpsess;    	
 	
 	/** First SAS base32/256 string */
diff --git a/projects/xcode/libzrtp.xcodeproj/project.pbxproj b/projects/xcode/libzrtp.xcodeproj/project.pbxproj
index 5eec2ac3f5..d6410e978d 100644
--- a/projects/xcode/libzrtp.xcodeproj/project.pbxproj
+++ b/projects/xcode/libzrtp.xcodeproj/project.pbxproj
@@ -413,7 +413,7 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0410;
+				LastUpgradeCheck = 0420;
 			};
 			buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "libzrtp" */;
 			compatibilityVersion = "Xcode 3.2";
diff --git a/src/zrtp.c b/src/zrtp.c
index 6c5470cca8..d5a228150d 100644
--- a/src/zrtp.c
+++ b/src/zrtp.c
@@ -72,7 +72,7 @@ zrtp_status_t zrtp_init(zrtp_config_t* config, zrtp_global_t** zrtp)
 		return zrtp_status_alloc_fail;
     }	
 	zrtp_memset(new_zrtp, 0, sizeof(zrtp_global_t));
-	
+		
 	/*
 	 * Apply configuration according to the config
 	 */		
@@ -188,7 +188,7 @@ zrtp_status_t zrtp_down(zrtp_global_t* zrtp)
 zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp,
 								zrtp_profile_t* profile,
 								zrtp_zid_t zid,
-								uint8_t is_initiator,
+								zrtp_signaling_role_t role,
 								zrtp_session_t **session)
 {
     uint32_t i = 0;
@@ -243,6 +243,7 @@ zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp,
 		ZRTP_LOG(3, (_ZTU_,"   allowclear: %s\n", profile->allowclear?"ON":"OFF"));
 		ZRTP_LOG(3, (_ZTU_,"   autosecure: %s\n", profile->autosecure?"ON":"OFF"));
 		ZRTP_LOG(3, (_ZTU_," disclose_bit: %s\n", profile->disclose_bit?"ON":"OFF"));
+		ZRTP_LOG(3, (_ZTU_," signal. role: %s\n", zrtp_log_sign_role2str(role)));	
 		ZRTP_LOG(3, (_ZTU_,"          TTL: %u\n", profile->cache_ttl));
 				
 		ZRTP_LOG(3, (_ZTU_,"  SAS schemes: "));
@@ -280,7 +281,7 @@ zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp,
 	zrtp_zstrncpyc(ZSTR_GV(new_session->zid), (const char*)zid, sizeof(zrtp_zid_t));	
 
 	new_session->zrtp = zrtp;
-	new_session->is_initiator = is_initiator;
+	new_session->signaling_role = role;
 	new_session->mitm_alert_detected = 0;
 
 	/*
@@ -356,7 +357,8 @@ void zrtp_session_down(zrtp_session_t *session)
 	/* Stop ZRTP engine and clear all crypto sources for every stream in the session. */
 	zrtp_mutex_lock(session->streams_protector);
 	for(i=0; i<ZRTP_MAX_STREAMS_PER_SESSION; i++) {
-		zrtp_stream_stop(&session->streams[i]);			
+		zrtp_stream_t *the_stream = &session->streams[i]; 		
+		zrtp_stream_stop(the_stream);
 	}
 	zrtp_mutex_unlock(session->streams_protector);
 
@@ -437,7 +439,7 @@ zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream
 	
 	new_stream->dh_cc.initialized_with	= ZRTP_COMP_UNKN;
 	bnBegin(&new_stream->dh_cc.peer_pv);
-	ZSTR_SET_EMPTY(new_stream->dh_cc.dhss);
+	ZSTR_SET_EMPTY(new_stream->dh_cc.dhss);		
 	
 	ZRTP_LOG(3, (_ZTU_,"\tEmpty slot was found - initializing new stream with ID=%u.\n", new_stream->id));
 
@@ -507,11 +509,16 @@ zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream
 	uint8_t i = 0;
 	int8_t* comp_ptr = NULL;
 
+	/* Set Protocol Version and ClientID */
 	zrtp_memcpy(hello->version, ZRTP_PROTOCOL_VERSION, ZRTP_VERSION_SIZE);
 	zrtp_memcpy(hello->cliend_id, session->zrtp->client_id.buffer, session->zrtp->client_id.length);
-	hello->pasive =  (ZRTP_LICENSE_MODE_PASSIVE == session->zrtp->lic_mode) ? 1 : 0;
-	hello->mitmflag = session->zrtp->is_mitm;
-	hello->sigflag	= 0;
+		
+	/* Set flags. */
+	hello->pasive	=  (ZRTP_LICENSE_MODE_PASSIVE == session->zrtp->lic_mode) ? 1 : 0;
+	hello->uflag	= (ZRTP_LICENSE_MODE_UNLIMITED == session->zrtp->lic_mode) ? 1 : 0;
+	hello->mitmflag = session->zrtp->is_mitm;	
+	hello->sigflag	= 0;	
+		
 	zrtp_memcpy(hello->zid, session->zid.buffer, session->zid.length);
 	
 	comp_ptr = (int8_t*)hello->comp;
diff --git a/src/zrtp_engine.c b/src/zrtp_engine.c
index 07d14f185b..1e2b4ac48d 100644
--- a/src/zrtp_engine.c
+++ b/src/zrtp_engine.c
@@ -333,6 +333,15 @@ zrtp_status_t zrtp_stream_stop(zrtp_stream_t* stream)
 	 */
 	 ZRTP_LOG(3,(_ZTU_,"STOP STREAM ID=%u mode=%s state=%s.\n",
 				stream->id, zrtp_log_mode2str(stream->mode), zrtp_log_state2str(stream->state)));
+	
+	/*
+	 * Unlink deleted stream for the peer MiTM stream if necessary. It may
+	 * prevent some recae-conditions as we always test for NULL before
+	 * accessing linked_mitm.
+	 */
+	if (stream->linked_mitm) {
+		stream->linked_mitm->linked_mitm = NULL;
+	}
 
     if (stream->state != ZRTP_STATE_NONE) {
 		/*
@@ -352,7 +361,9 @@ zrtp_status_t zrtp_stream_stop(zrtp_stream_t* stream)
 		zrtp_mutex_destroy(stream->stream_protector);
 
 		zrtp_memset(stream, 0, sizeof(zrtp_stream_t));
+		
 		stream->mode = ZRTP_STREAM_MODE_UNKN;
+		
 		_zrtp_change_state(stream, ZRTP_STATE_NONE);
     } else {
 		s = zrtp_status_wrong_state;
@@ -601,6 +612,7 @@ zrtp_status_t _zrtp_machine_process_while_in_wait4hello( zrtp_stream_t* stream,
 				if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) {
 					stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION);
 				}
+				ZRTP_LOG(2,(_ZTU_,"\tINFO: Switching to Clear due to Active/Passive restrictions.\n"));
 			}
 			
 			s = _zrtp_machine_enter_clear(stream);
@@ -663,6 +675,7 @@ zrtp_status_t _zrtp_machine_process_while_in_wait4helloack( zrtp_stream_t* strea
 				if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) {
 					stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_PASSIVE_RESTRICTION);
 				}
+				ZRTP_LOG(2,(_ZTU_,"\tINFO: Switching to Clear due to Active/Passive restrictions.\n"));
 			}
 			status = _zrtp_machine_enter_clear(stream);
 		}
@@ -1035,6 +1048,22 @@ static zrtp_status_t _zrtp_machine_enter_clear(zrtp_stream_t* stream)
 	if (stream->zrtp->cb.event_cb.on_zrtp_protocol_event) {
 		stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_CLEAR);
 	}
+	
+	/*
+	 * Now, let's check if the transition to CLEAR was caused by Active/Passive rules.
+	 * If local endpoint is a MitM and peer MiTM linked stream is Unlimited, we
+	 * could break the rules and send commit to Passive endpoint.
+	 */
+	if (stream->zrtp->is_mitm && stream->peer_passive) {
+		if (stream->linked_mitm && stream->linked_mitm->peer_super_flag) {
+			ZRTP_LOG(2,(_ZTU_,"INFO: Current stream ID=%u was switched to CLEAR-mode due to Active/Passive"
+						" restrictions, but we are running in MiTM mode and peer linked stream is"
+						" Super-active. Go Secure!\n", stream->id));
+			
+			/* @note: don't use zrtp_secure_stream() wrapper as it checks for Active/Passive stuff. */
+			_zrtp_machine_start_initiating_secure(stream);
+		}
+	}
 
 	return zrtp_status_ok;
 }
@@ -1211,8 +1240,17 @@ zrtp_status_t _zrtp_machine_process_hello(zrtp_stream_t* stream, zrtp_rtp_info_t
 		zrtp_zstrncpyc(ZSTR_GV(session->peer_zid), (const char*) peer_hello->zid, sizeof(zrtp_zid_t));
 	}
 
-	/* Remember remote Passive flag */
-	stream->peer_passive = peer_hello->pasive;	
+	/*
+	 * Process Remote flags.
+	 */
+	if (peer_hello->pasive && peer_hello->uflag) {
+		ZRTP_LOG(2,(_ZTU_,"\tWARNING! Received HELLO which both P and U flags set.\n"));
+		return zrtp_status_fail;
+	}
+	
+	stream->peer_passive = peer_hello->pasive;		
+	stream->peer_super_flag = peer_hello->uflag;
+	
 	stream->peer_mitm_flag = peer_hello->mitmflag;
 	if (stream->peer_mitm_flag) {
 		stream->mitm_mode = ZRTP_MITM_MODE_CLIENT;
diff --git a/src/zrtp_log.c b/src/zrtp_log.c
index 19ab390da1..6de359f134 100644
--- a/src/zrtp_log.c
+++ b/src/zrtp_log.c
@@ -384,6 +384,21 @@ const char* zrtp_log_event2str(uint8_t event)
 	}
 }
 
+static char* _sign_role_name[] =
+{
+	"Unknown",
+	"Initiator",
+	"Responder"
+};
+
+const char* zrtp_log_sign_role2str(unsigned role) {
+	if (role < ZRTP_SIGNALING_ROLE_COUNT) {
+		return _sign_role_name[role];
+	} else {
+		return k_unknown;
+	}
+}
+
 /*---------------------------------------------------------------------------*/
 typedef struct _zrtp_aling_test
 {
diff --git a/src/zrtp_pbx.c b/src/zrtp_pbx.c
index a7e399ec39..f0fff569bf 100644
--- a/src/zrtp_pbx.c
+++ b/src/zrtp_pbx.c
@@ -341,6 +341,13 @@ zrtp_status_t zrtp_register_with_trusted_mitm(zrtp_stream_t* stream)
 	if (!stream->protocol) {
 		return zrtp_status_bad_param;
 	}
+	
+	/* Passive Client endpoint should NOT generate PBX Secret. */
+	if ((stream->mitm_mode == ZRTP_MITM_MODE_REG_CLIENT) &&
+		(ZRTP_LICENSE_MODE_PASSIVE != stream->zrtp->lic_mode)) {
+		ZRTP_LOG(2,(_ZTU_,"WARNING: Passive Client endpoint should NOT generate PBX Secert.\n"));
+		return zrtp_status_bad_param;
+	}
 
 	/*
 	 * Generate new MitM cache:
@@ -389,6 +396,51 @@ zrtp_status_t zrtp_register_with_trusted_mitm(zrtp_stream_t* stream)
 	return s;
 }
 
+/*---------------------------------------------------------------------------*/
+zrtp_status_t zrtp_link_mitm_calls(zrtp_stream_t *stream1, zrtp_stream_t *stream2)
+{
+	ZRTP_LOG(3,(_ZTU_,"Link to MiTM call together stream1=%u stream2=%u.\n", stream1->id, stream2->id));
+	
+	/* This APi is for MiTM endpoints only. */
+	if (stream1->zrtp->is_mitm) {
+		return zrtp_status_bad_param;
+	}
+	
+	stream1->linked_mitm = stream2;
+	stream2->linked_mitm = stream1;
+	
+	{
+		zrtp_stream_t *passive = NULL;
+		zrtp_stream_t *unlimited = NULL;
+	
+		/* Check if we have at least one Unlimited endpoint. */
+		if (stream1->peer_super_flag)
+			unlimited = stream1;
+		else if (stream2->peer_super_flag)
+			unlimited = stream2;
+	
+		/* Check if the peer stream is Passive */
+		if (unlimited) {
+			passive = (stream1 == unlimited) ? stream2 : stream1;
+			if (!passive->peer_passive)
+				passive = NULL;
+		}
+		
+		/* Ok, we haver Unlimited and Passive at two ends, let's make an exception and switch Passive to Secure. */
+		if (unlimited && passive) {
+			if (passive->state == ZRTP_STATE_CLEAR) {
+				ZRTP_LOG(2,(_ZTU_,"INFO: zrtp_link_mitm_calls() stream with id=%u is Unlimited and"
+							" Peer stream with id=%u is Passive in CLEAR state, switch the passive one to SECURE.\n"));
+				
+				/* @note: don't use zrtp_secure_stream() wrapper as it checks for Active/Passive stuff. */				
+				_zrtp_machine_start_initiating_secure(passive);
+			}
+		}		
+	}
+	
+	return zrtp_status_ok;
+}
+
 /*---------------------------------------------------------------------------*/
 zrtp_status_t zrtp_update_remote_options( zrtp_stream_t* stream,
 										  zrtp_sas_id_t transf_sas_scheme,
diff --git a/src/zrtp_protocol.c b/src/zrtp_protocol.c
index 392509d328..a98e53aa37 100644
--- a/src/zrtp_protocol.c
+++ b/src/zrtp_protocol.c
@@ -1097,6 +1097,24 @@ zrtp_status_t _zrtp_machine_enter_secure(zrtp_stream_t* stream)
 		zrtp_wipe_zstring(ZSTR_GV(stream->dh_cc.dhss));
 	}
 	
+	/*
+	 * Now, let's check if the transition to CLEAR was caused by Active/Passive rules.
+	 * If local endpoint is a MitM and peer MiTM linked stream is Unlimited, we
+	 * could break the rules and send commit to Passive endpoint.
+	 */
+	if (stream->zrtp->is_mitm && stream->peer_super_flag) {
+		if (stream->linked_mitm && stream->linked_mitm->peer_passive) {
+			if (stream->linked_mitm->state == ZRTP_STATE_CLEAR) {
+				ZRTP_LOG(2,(_ZTU_,"INFO: Linked Peer stream id=%u suspended in CLEAR-state due to"
+							" Active/Passive restrictions, but we are running in MiTM mode and "
+							"current peer endpoint is Super-Active. Let's Go Secure for the linked stream.\n", stream->id));
+				
+				/* @note: don't use zrtp_secure_stream() wrapper as it checks for Active/Passive stuff. */
+				_zrtp_machine_start_initiating_secure(stream->linked_mitm);
+			}
+		}
+	}
+	
 	/*
 	 * Increase calls counter for Preshared mode and reset it on DH
 	 */
@@ -1249,6 +1267,7 @@ zrtp_status_t _zrtp_machine_process_confirm( zrtp_stream_t *stream,
     
     
     // MARK: TRACE CONFIRM HMAC ERROR
+#if 0
     {
         char buff[512];
         ZRTP_LOG(3,(_ZTU_,"HMAC TRACE. VERIFY\n"));
@@ -1261,6 +1280,7 @@ zrtp_status_t _zrtp_machine_process_confirm( zrtp_stream_t *stream,
         ZRTP_LOG(3,(_ZTU_,"\t      hmac:%s.\n",
                     hex2str((const char*)confirm->hmac, ZRTP_HMAC_SIZE, buff, sizeof(buff))));
     }
+#endif
     
 
 	if (0 != zrtp_memcmp(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) {
@@ -1366,8 +1386,13 @@ zrtp_status_t _zrtp_machine_process_confirm( zrtp_stream_t *stream,
 			_zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1);
 			return zrtp_status_fail;
 		}
-
-		stream->mitm_mode = ZRTP_MITM_MODE_REG_CLIENT;
+		
+		/* Passive endpoint should ignore PBX Enrollment. */
+		if (ZRTP_LICENSE_MODE_PASSIVE != stream->zrtp->lic_mode) {
+			stream->mitm_mode = ZRTP_MITM_MODE_REG_CLIENT;
+		} else {
+			ZRTP_LOG(2,(_ZTU_,"\tINFO: Ignore PBX Enrollment flag as we are Passive ID=%u\n", stream->id));			
+		}
 	}
 
 	stream->cache_ttl = ZRTP_MIN(session->profile.cache_ttl, zrtp_ntoh32(confirm->expired_interval));