diff --git a/libs/freetdm/docs/ss7-native-bridge.txt b/libs/freetdm/docs/ss7-native-bridge.txt
new file mode 100644
index 0000000000..d44b067b0a
--- /dev/null
+++ b/libs/freetdm/docs/ss7-native-bridge.txt
@@ -0,0 +1,43 @@
+SS7 Native Bridge
+
+Native bridge is enabled on 2 conditions:
+
+* The SIP header FreeTDM-TransUUID is set in the originating leg and matches a freetdm channel
+* The variable freetdm_native_sigbridge is true and the originating leg is also a freetdm channel
+
+Some coding rules apply to this feature:
+
+- Each channel is responsible for clearning its own peer_data and event queue
+  at the end of the call (when moving to DOWN state)
+
+- Each channel dequeues messages only from its own queue and enqueues messages
+  in the peer's queue, with the only exception being messages received before
+  the bridge is stablished (IAM for sure and possible SAM messages) because
+  if the bridge is not yet stablished the messages must be queued by the channel
+  in its own queue temporarily until the bridge is ready
+
+- When the bridge is ready it is the responsibility of the incoming channel to
+  move the messages that stored temporarily in its own queue to the bridged peer queue
+
+- During hangup, each channel is responsible for moving itself to DOWN. The procedure
+  however differs slightly depending on the hangup conditions
+
+  If the user requests hangup (ie, FreeSWITCH) the request will be noted by setting the 
+  FTDM_CHANNEL_USER_HANGUP flag but will not be processed yet because call control is
+  driven only by the link messages (so no hangup from ESL or command line allowed)
+
+  When REL message comes, the channel receiving it must move to TERMINATING state and:
+	    
+	- If the user has not hangup yet (FTDM_CHANNEL_USER_HANGUP flag not set) then
+	  notify the user via SIGEVENT_STOP and wait for the user to move to HANGUP
+	  state by calling ftdm_channel_call_hangup() before sending RLC 
+
+	- If the user did hangup already (FTDM_CHANNEL_USER_HANGUP flag is set) then
+	  skip user notification and move to HANGUP state directly where the RLC message
+	  will be sent
+
+- On HANGUP state the RLC is sent and the channel is moved to DOWN, final state
+  The peer channel will forward the REL message and wait for RLC from the network, when
+  RLC is received the channel can move straight to DOWN itself because the peer channel
+  is completing its own shutdown procedure when it received the REL message
+
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 1c39703182..b6a6f49ca1 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -1409,7 +1409,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 		chan_id = 0;
 	}
 
-	if (session && globals.sip_headers) {
+	if (session && globals.sip_headers && !switch_core_session_check_interface (session,freetdm_endpoint_interface) ) {
 		switch_channel_t *channel = switch_core_session_get_channel(session);
 		const char *sipvar;
 
@@ -1474,7 +1474,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-NADI");
 		if (sipvar) {
 			ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_nadi", sipvar);
-		}   
+		}
 
 		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON");
 		if (sipvar) {
@@ -1726,7 +1726,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 				ftdm_channel_get_span_id(peer_private->ftdmchan), ftdm_channel_get_id(peer_private->ftdmchan));
 				switch_core_session_rwunlock(network_peer);
 			}
-
 		/* Figure out if there is a native bridge requested through dial plan variable and the originating channel is also freetdm (not going through SIP) */
 		} else if (session
 		 && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) 
@@ -2043,6 +2042,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
 		if (!ftdm_strlen_zero(var_value)) {
 			switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN", "%s", var_value);
 		}
+		
 		var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_nadi");
 		if (!ftdm_strlen_zero(var_value)) {
 			switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-NADI", "%s", var_value);
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index e132aaab70..78e65dfe88 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -2203,9 +2203,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *
 {
 	ftdm_status_t status = FTDM_SUCCESS;
 
-	if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
+	/* In native sigbridge mode we ignore hangup requests from the user and hangup only when the signaling module decides it */
+	if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && chan->state != FTDM_CHANNEL_STATE_TERMINATING) {
+
 		ftdm_log_chan_ex(chan, file, func, line, FTDM_LOG_LEVEL_DEBUG, 
 				"Ignoring hangup in channel in state %s (native bridge enabled)\n", ftdm_channel_state2str(chan->state));
+		ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP);
 		goto done;
 	}
 
diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c
index bd670d0062..e5aba9d408 100644
--- a/libs/freetdm/src/ftdm_state.c
+++ b/libs/freetdm/src/ftdm_state.c
@@ -48,7 +48,6 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c
 	ftdm_time_t diff = 0;
 	ftdm_channel_state_t state = fchan->state;
 
-
 #if 0
 	/*  I could not perform this sanity check without more disruptive changes. Ideally we should check here if the signaling module completing the state
 		executed a state processor (called ftdm_channel_advance_states() which call fchan->span->state_processor(fchan)) for the state. That is just a 
@@ -59,6 +58,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c
 		ftdm_channel_advance_states() would set the state_status to PROCESSING and then the check below for STATUS_NEW would be valid. Currently is not
 		valid because the signaling module may be completing the state at the end of the state_processor callback and therefore the state will still be
 		in STATUS_NEW, and is perfectly valid ... */
+
 	if (fchan->state_status == FTDM_STATE_STATUS_NEW) {
 		ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_CRIT, 
 						"Asking to complete state change from %s to %s in %llums, but the state is still unprocessed (this might be a bug!)\n", 
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
index 3f1a03f4d8..df872b260c 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
@@ -35,7 +35,7 @@
  *
  */
 
-#if 0 
+#if 0
 #define SMG_RELAY_DBG
 #endif
 
@@ -1332,7 +1332,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span,
 					}
 		
 #ifdef SMG_RELAY_DBG
-					stream->write_function(stream," blk_flag=%x | ckt_flag=%x | chan_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags, ftdmchan->flags);
+					stream->write_function(stream," | blk_flag=%x | ckt_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags);
 #endif
 					stream->write_function(stream, "\n");
 				} /* if ( hole, sig, voice) */
@@ -1374,36 +1374,26 @@ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int c
 			}
 
 			if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
-				/* now that we have the right channel...put a lock on it so no-one else can use it */
 				ftdm_mutex_lock(ftdmchan->mutex);
 
 				/* check if there is a pending state change|give it a bit to clear */
 				if (check_for_state_change(ftdmchan)) {
 					SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic);
-					/* check if we need to die */
 					ftdm_assert(0, "State change not completed\n");
-					/* unlock the channel again before we exit */
 					ftdm_mutex_unlock(ftdmchan->mutex);
-					/* move to the next channel */
 					continue;
 				} else {
-					/* throw the ckt block flag */
 					sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX);
-
-					/* set the channel to suspended state */
 					ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
 				}
-
-				/* unlock the channel again before we exit */
+				
 				ftdm_mutex_unlock(ftdmchan->mutex);
+			}
 
-			} /* if ( span and chan) */
+		}
 
-		} /* if ( cic != 0) */
-
-		/* go the next circuit */
 		x++;
-	} /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */
+	}
 
 	handle_show_blocks(stream, span, chan, verbose);
 
@@ -1440,33 +1430,22 @@ static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int c
 			}
 
 			if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
-				/* now that we have the right channel...put a lock on it so no-one else can use it */
 				ftdm_mutex_lock(ftdmchan->mutex);
 
 				/* check if there is a pending state change|give it a bit to clear */
 				if (check_for_state_change(ftdmchan)) {
 					SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic);
-					/* check if we need to die */
 					ftdm_assert(0, "State change not completed\n");
-					/* unlock the channel again before we exit */
 					ftdm_mutex_unlock(ftdmchan->mutex);
-					/* move to the next channel */
 					continue;
 				} else {
-					/* throw the ckt block flag */
 					sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_UNBLK_TX);
-
-					/* clear the block flag */
 					sngss7_clear_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX);
-
-					/* check group blocking */
 					sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX); 
 					
-					/* set the channel to suspended state */
 					ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
 				}
 
-				/* unlock the channel again before we exit */
 				ftdm_mutex_unlock(ftdmchan->mutex);
 
 			}
@@ -1812,6 +1791,8 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c
 				/* throw the grp maint. block flag */
 				sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX);
 
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+
 				/* bring the sig status down */
 				sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN);
 
@@ -1945,6 +1926,7 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c
 
 				/* bring the sig status up */
 				sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP);
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
 
 				/* if this is the first channel in the range */
 				if (!main_chan) {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
index f48d25ce3c..4e0a20d5f3 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
@@ -131,6 +131,16 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 
 		/* KONRAD FIX ME : check in case there is a ckt and grp block */
 	}
+	
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_TX);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX_DN);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_TX);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_SENT);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX_DN);
+	sngss7_clear_ckt_flag(sngss7_info, FLAG_FULL_NUMBER);
 
 	/* check whether the ftdm channel is in a state to accept a call */
 	switch (ftdmchan->state) {
@@ -175,6 +185,12 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 					/* fill in ANI */
 					ftdm_set_string(ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.cid_num.digits);
 				}
+				else {
+					if (g_ftdm_sngss7_data.cfg.force_inr) {
+						sngss7_set_ckt_flag(sngss7_info, FLAG_INR_TX);
+						sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT);
+					}
+				}
 
 				if (siConEvnt->cgPtyNum.scrnInd.pres) {
 					/* fill in the screening indication value */
@@ -186,6 +202,11 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 					ftdmchan->caller_data.pres = siConEvnt->cgPtyNum.presRest.val;
 				}	
 			} else {
+				if (g_ftdm_sngss7_data.cfg.force_inr) {
+					sngss7_set_ckt_flag(sngss7_info, FLAG_INR_TX);
+					sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT);
+				}
+
 				SS7_INFO_CHAN(ftdmchan,"No Calling party (ANI) information in IAM!%s\n", " ");
 			}
 
@@ -436,10 +457,26 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 	/**************************************************************************/
 	case (INFORMATION):
 		SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INF\n", sngss7_info->circuit->cic);
+
+		SS7_DEBUG_CHAN (ftdmchan, "Cancelling T.39 timer %s\n", " ");
+		/* check if t39 is active */
+		if (sngss7_info->t39.hb_timer_id) {
+			ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id);
+			SS7_DEBUG_CHAN (ftdmchan, "T.39 timer has been cancelled upon receiving INF message %s\n", " ");
+		}
+
+		sngss7_set_ckt_flag(sngss7_info, FLAG_INF_RX_DN);
+		ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE);		
+		
 		break;
 	/**************************************************************************/
 	case (INFORMATREQ):
 		SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INR\n", sngss7_info->circuit->cic);
+
+		ft_to_sngss7_inf(ftdmchan, siCnStEvnt);
+
+		sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX);
+		
 		break;
 	/**************************************************************************/
 	case (SUBSADDR):
@@ -1143,11 +1180,12 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 		break;
 	/**************************************************************************/
 	case SIT_STA_CGBRSP:			/* mntc. oriented CGB response */
-		/*handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);*/
+		SS7_INFO(" Rx CGBA \n");
 		break;
 	/**************************************************************************/
 	case SIT_STA_CGURSP:			/* mntc. oriented CGU response */
 		/*SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));*/
+		SS7_INFO(" Rx CGUA \n");
 		break;
 	/**************************************************************************/
 	case SIT_STA_GRSREQ:			/* circuit group reset request */
@@ -2472,6 +2510,8 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 
 				/* bring the sig status down */
 				sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN);
+				
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
 
 				/* unlock the channel again before we exit */
 				ftdm_mutex_unlock(ftdmchan->mutex);
@@ -2589,8 +2629,7 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 	while( x < loop_range ) {
 		if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE)  {
 			loop_range++;
-		}
-		else {
+		} else {
 			if (extract_chan_data(x, &sngss7_info, &ftdmchan)) {
 				SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x);
 			}
@@ -2627,7 +2666,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 				if (sngss7_channel_status_clear(sngss7_info)) {
 					sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP);
 				}
-			
+				
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
 				ftdm_mutex_unlock(ftdmchan->mutex);
 
 				/* update the bit and byte counter*/
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c
index b13c98b1e6..92931c4b8d 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c
@@ -81,6 +81,7 @@ void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCo
 
 	/* initalize the sngss7_event */
 	sngss7_event = ftdm_malloc(sizeof(*sngss7_event));
+	
 	if (sngss7_event == NULL) {
 		SS7_ERROR("Failed to allocate memory for sngss7_event!\n");
 		SS7_FUNC_TRACE_EXIT(__FUNCTION__);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
index fe129c0f73..1098126890 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
@@ -340,10 +340,9 @@ static void handle_hw_alarm(ftdm_event_t *e)
 /* MONITIOR THREADS ***********************************************************/
 static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
 {
-	ftdm_interrupt_t	*ftdm_sangoma_ss7_int[3];
+	ftdm_interrupt_t	*ftdm_sangoma_ss7_int[2];
 	ftdm_span_t 		*ftdmspan = (ftdm_span_t *) obj;
 	ftdm_channel_t 		*ftdmchan = NULL;
-	ftdm_channel_t 		*peerchan = NULL;
 	ftdm_event_t 		*event = NULL;
 	sngss7_event_data_t	*sngss7_event = NULL;
 	sngss7_span_data_t	*sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
@@ -368,12 +367,6 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
 		goto ftdm_sangoma_ss7_run_exit;
 	}
 
-	/* get an interrupt queue for this span for peer channel events */
-	if (ftdm_queue_get_interrupt (sngss7_span->peer_chans, &ftdm_sangoma_ss7_int[2]) != FTDM_SUCCESS) {
-		SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for peer channel events queue!\n", ftdmspan->span_id);
-		goto ftdm_sangoma_ss7_run_exit;
-	}
-
 	while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) {
 		int x = 0;
 		if (b_alarm_test) {
@@ -410,42 +403,26 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
 
 			/* clean out all pending channel state changes */
 			while ((ftdmchan = ftdm_queue_dequeue (ftdmspan->pendingchans))) {
+				sngss7_chan_data_t *chan_info = ftdmchan->call_data;
 				
 				/*first lock the channel */
 				ftdm_mutex_lock(ftdmchan->mutex);
 
 				/* process state changes for this channel until they are all done */
 				ftdm_channel_advance_states(ftdmchan);
+
+				if (chan_info->peer_data) {
+					/* clean out all pending stack events in the peer channel */
+					while ((sngss7_event = ftdm_queue_dequeue(chan_info->event_queue))) {
+						ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event);
+					       	ftdm_safe_free(sngss7_event);
+					}
+				}
  
 				/* unlock the channel */
 				ftdm_mutex_unlock (ftdmchan->mutex);				
 			}
 
-			/* clean out all peer pending channel events */
-			while ((peerchan = ftdm_queue_dequeue (sngss7_span->peer_chans))) {
-				/* note that the channels being dequeued here may not belong to this span
-				   they may belong to just about any other span that one of our channels
-				   happens to be bridged to */
-				sngss7_chan_data_t *peer_info = peerchan->call_data;
-				sngss7_chan_data_t *chan_info = peer_info->peer_data;
-				ftdmchan = chan_info->ftdmchan;
-
-				/* 
-				   if there is any state changes at all, those will be done in the opposite channel
-				   to peerchan (where the original event was received), therefore we must lock ftdmchan, 
-				   but do not need to lock peerchan as we only read its event queue, which is already 
-				   locked when dequeueing */
-				ftdm_channel_lock(ftdmchan);
-
-				/* clean out all pending stack events in the peer channel */
-				while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) {
-					ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event);
-					ftdm_safe_free(sngss7_event);
-				}
-
-				ftdm_channel_unlock(ftdmchan);				
-			}
-
 			/* clean out all pending stack events */
 			while ((sngss7_event = ftdm_queue_dequeue(sngss7_span->event_queue))) {
 				ftdm_sangoma_ss7_process_stack_event(sngss7_event);
@@ -561,16 +538,16 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
 	ftdm_channel_advance_states(ftdmchan);
 
 	if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) {
-		/* this is the first event in a call, flush the event queue */
-		sngss7_flush_queue(sngss7_info->event_queue);
-		/* clear the peer if any */
-		sngss7_info->peer_data = NULL;
 		clone_event++;
 	}
 
-	/* if the call has already started and the event is not a release confirmation, clone the event */
-	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) && 
-        sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) {
+	/* If the call has already started (we only bridge events related to calls)
+	 * and the event is not a release confirmation, then clone the event.
+	 * We do not clone release cfm events because that is the only event (final event) that is not
+	 * bridged to the other leg, the first Spirou customer we had explicitly requested to send
+	 * release confirm as soon as the release is received and therefore not wait for the other leg
+	 * to send release confirm (hence, not need to clone and enqueue in the other leg) */
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) && sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) {
 		clone_event++;
 	}
 
@@ -597,11 +574,38 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
 		event_clone = ftdm_calloc(1, sizeof(*sngss7_event));
 		if (event_clone) {
 			memcpy(event_clone, sngss7_event, sizeof(*sngss7_event));
-			ftdm_queue_enqueue(sngss7_info->event_queue, event_clone);
+			/* if we have already a peer channel then enqueue the event in their queue */
 			if (sngss7_info->peer_data) {
-				sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_data;
+				ftdm_span_t *peer_span = sngss7_info->peer_data->ftdmchan->span;
+				if (sngss7_info->peer_event_transfer_cnt) {
+					sngss7_event_data_t *peer_event = NULL;
+					int qi = 0;
+					/* looks like for the first time we found our peer, transfer any messages we enqueued */
+					for (qi = 0; qi < sngss7_info->peer_event_transfer_cnt; qi++) {
+						peer_event = ftdm_queue_dequeue(sngss7_info->event_queue);
+						if (peer_event) {
+							ftdm_queue_enqueue(sngss7_info->peer_data->event_queue, peer_event);
+						} else {
+							/* This should never happen! */
+							SS7_CRIT_CHAN(ftdmchan,"[CIC:%d]What!? someone stole my messages!\n", sngss7_info->circuit->cic);
+						}
+					}
+					SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Transferred %d messages into my peer's queue\n", 
+							sngss7_info->circuit->cic, sngss7_info->peer_event_transfer_cnt);
+					sngss7_info->peer_event_transfer_cnt = 0;
+				}
 				/* we already have a peer attached, wake him up */
-				ftdm_queue_enqueue(sngss7_peer_span->peer_chans, sngss7_info->ftdmchan);
+				ftdm_queue_enqueue(sngss7_info->peer_data->event_queue, event_clone);
+				ftdm_queue_enqueue(peer_span->pendingchans, sngss7_info->peer_data->ftdmchan);
+			} else {
+				/* we don't have a peer yet, save the event on our own queue for later
+				 * only the first event in this queue is directly consumed by our peer (IAM), subsequent events
+				 * must be transferred by us to their queue as soon as we find our peer */
+				ftdm_queue_enqueue(sngss7_info->event_queue, event_clone);
+				if (sngss7_event->event_id != SNGSS7_CON_IND_EVENT) {
+					/* This could be an SAM, save it for transfer once we know who our peer is (if we ever find that) */
+					sngss7_info->peer_event_transfer_cnt++;
+				}
 			}
 		}
 	}
@@ -614,25 +618,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
 			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
 			break;
 		case SNGSS7_REL_CFM_EVENT:
-			{
-				if (sngss7_info->peer_data) {
-					ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan;
-					ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
-					if (peer_chan) {
-						/* we need to unlock our chan or we risk deadlock */
-						ftdm_channel_advance_states(ftdmchan);
-						ftdm_channel_unlock(ftdmchan);
-
-						ftdm_channel_lock(peer_chan);
-						if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) {
-							ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN);
-						}
-						ftdm_channel_unlock(peer_chan);
-
-						ftdm_channel_lock(ftdmchan);
-					}
-				}
-			}
+			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 			break;
 		default:
 			break;
@@ -1011,7 +997,11 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t
 			ftdm_channel_t *close_chan = ftdmchan;
 			sngss7_clear_ckt_flag(sngss7_info, FLAG_SUS_RECVD);
 			sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED);
+			sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_ACM);
+			sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_CPG);
+
 			sngss7_flush_queue(sngss7_info->event_queue);
+			sngss7_info->peer_data = NULL;
 			ftdm_channel_close (&close_chan);
 		}
 		break;
@@ -1026,9 +1016,22 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t
 
 	case FTDM_CHANNEL_STATE_TERMINATING:
 		{
-			ft_to_sngss7_rlc(ftdmchan);
+			/* Release confirm is sent immediately, since Spirou customer asked us not to wait for the second call leg
+			 * to come back with a release confirm ... */
 			/* when receiving REL we move to TERMINATING and notify the user that the bridge is ending */
-			sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP);
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP)) {
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+			} else {
+				/* Notify the user and wait for their ack before sending RLC */
+				sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP);
+			}
+		}
+		break;
+
+	case FTDM_CHANNEL_STATE_HANGUP:
+		{
+			ft_to_sngss7_rlc(ftdmchan);
+			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 		}
 		break;
 
@@ -1053,11 +1056,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
 									sngss7_info->blk_flags);
 
 	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
-		/* DIALING is the only state we process normally when doing an outgoing call that is natively bridged */
+		/* DIALING is the only state we process normally when doing an outgoing call that is natively bridged, 
+		 * all other states are run by a different state machine (and the freetdm core does not do any checking) */
 		if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) {
 			return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan);
 		}
-		sngss7_info->peer_data = NULL;
 	}
 
 	/*check what state we are supposed to be in */
@@ -1080,23 +1083,91 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
 		}
 
 		/* check if the end of pulsing (ST) character has arrived or the right number of digits */
-		if (ftdmchan->caller_data.dnis.digits[i-1] == 'F') {
+		if (ftdmchan->caller_data.dnis.digits[i-1] == 'F'
+		    || sngss7_test_ckt_flag(sngss7_info, FLAG_FULL_NUMBER) ) 
+		{
 			SS7_DEBUG_CHAN(ftdmchan, "Received the end of pulsing character %s\n", "");
 
-			/* remove the ST */
-			ftdmchan->caller_data.dnis.digits[i-1] = '\0';
-			
-			/*now go to the RING state */
-			state_flag = 0;
-			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
+			if (!sngss7_test_ckt_flag(sngss7_info, FLAG_FULL_NUMBER)) {
+				/* remove the ST */
+				ftdmchan->caller_data.dnis.digits[i-1] = '\0';
+				sngss7_set_ckt_flag(sngss7_info, FLAG_FULL_NUMBER);
+			}
 			
+			if (sngss7_test_ckt_flag(sngss7_info, FLAG_INR_TX)) {
+				if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INR_SENT) ) {
+					ft_to_sngss7_inr(ftdmchan);
+					sngss7_set_ckt_flag(sngss7_info, FLAG_INR_SENT);
+					
+					SS7_DEBUG_CHAN (ftdmchan, "Scheduling T.39 timer %s \n", " ");
+					
+					/* start ISUP t39 */
+					if (ftdm_sched_timer (sngss7_info->t39.sched,
+										"t39",
+										sngss7_info->t39.beat,
+										sngss7_info->t39.callback,
+										&sngss7_info->t39,
+										&sngss7_info->t39.hb_timer_id)) 
+					{
+				
+						SS7_ERROR ("Unable to schedule timer T39, hanging up call!\n");
+
+						ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE;
+						sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL);
+				
+						/* end the call */
+						state_flag = 0;
+						ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+					}
+				}else {
+					state_flag = 0;
+					ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
+				}
+			} else {
+				state_flag = 0;
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
+			}
 		} else if (i >= sngss7_info->circuit->min_digits) {
 			SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, sngss7_info->circuit->min_digits);
 
-			/*now go to the RING state */
-			state_flag = 0;
-			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
-			
+			if (sngss7_test_ckt_flag(sngss7_info, FLAG_INR_TX)) {
+				if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INR_SENT) ) {
+					ft_to_sngss7_inr(ftdmchan);
+					sngss7_set_ckt_flag(sngss7_info, FLAG_INR_SENT);
+					
+					SS7_DEBUG_CHAN (ftdmchan, "Scheduling T.39 timer %s\n", " " );
+					
+					/* start ISUP t39 */
+					if (ftdm_sched_timer (sngss7_info->t39.sched,
+										"t39",
+										sngss7_info->t39.beat,
+										sngss7_info->t39.callback,
+										&sngss7_info->t39,
+										&sngss7_info->t39.hb_timer_id)) 
+					{
+				
+						SS7_ERROR ("Unable to schedule timer T39, hanging up call!\n");
+
+						ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE;
+						sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL);
+				
+						/* end the call */
+						state_flag = 0;
+						ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+					}
+					
+					state_flag = 0;
+					ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+				}else {
+					if (sngss7_test_ckt_flag(sngss7_info, FLAG_INF_RX_DN) ) {
+						state_flag = 0;
+						ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
+					}
+				}
+			} else {
+				state_flag = 0;
+				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
+			}
 		} else {
 			/* if we are coming from idle state then we have already been here once before */
 			if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) {
@@ -1152,6 +1223,15 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
 	/**************************************************************************/
 	case FTDM_CHANNEL_STATE_RING:	/*incoming call request */
 
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_TX);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX_DN);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_TX);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_SENT);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX);
+		sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX_DN);
+		
 		if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
 			SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
 			break;
@@ -1162,6 +1242,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
 			ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id);
 		}
 
+		/* cancel t39 timer */
+		if (sngss7_info->t39.hb_timer_id) {
+			ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id);
+		}
+
 		SS7_DEBUG_CHAN(ftdmchan, "Sending incoming call from %s to %s to FTDM core\n",
 					ftdmchan->caller_data.ani.digits,
 					ftdmchan->caller_data.dnis.digits);
@@ -1512,19 +1597,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
 
 		if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) {
 			ftdm_channel_t *close_chan = ftdmchan;
-
-			/* detach native bridging if needed (only the outbound leg is responsible for that)
-			   Inbound leg was responsible of flushing its queue of events, but peer attach/detach
-			   is left as an outbound leg responsibility
-			 */
-			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
-				sngss7_chan_data_t *peer_info = sngss7_info->peer_data;
-				sngss7_info->peer_data = NULL;
-				if (peer_info) {
-					peer_info->peer_data = NULL;
-				}
-			}
-
 			/* close the channel */
 			SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", "");
 			sngss7_flush_queue(sngss7_info->event_queue);
@@ -2404,12 +2476,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
 		return FTDM_FAIL;
 	}
 
-	/* create an peer channel queue for this span */
-	if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SNGSS7_PEER_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) {
-		SS7_CRITICAL("Unable to create peer chans queue!\n");
-		return FTDM_FAIL;
-	}
-
 	/*setup the span structure with the info so far */
 	g_ftdm_sngss7_data.sig_cb 		= sig_cb;
 	span->start 					= ftdm_sangoma_ss7_start;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
index 63d4ded203..4ccf4efe0e 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
@@ -395,6 +395,7 @@ typedef struct sng_isup_ckt {
 	uint16_t		t16;
 	uint16_t		t17;
 	uint32_t		t35;
+	uint32_t		t39;
 	uint16_t		tval;
 } sng_isup_ckt_t;
 
@@ -466,6 +467,7 @@ typedef struct sng_ss7_cfg {
 	sng_nsap_t			nsap[MAX_NSAPS+1];
 	sng_isap_t			isap[MAX_ISAPS+1];	
 	sng_glare_resolution	glareResolution;
+	uint32_t				force_inr;
 } sng_ss7_cfg_t;
 
 typedef struct ftdm_sngss7_data {
@@ -517,12 +519,14 @@ typedef struct sngss7_chan_data {
 	sngss7_glare_data_t		glare;
 	sngss7_timer_data_t		t35;
 	sngss7_timer_data_t		t10;
+	sngss7_timer_data_t		t39;
 	sngss7_group_data_t		rx_grs;
 	sngss7_group_data_t		rx_gra;
 	sngss7_group_data_t		tx_grs;
 	sngss7_group_data_t		ucic;
 	ftdm_queue_t 			*event_queue;
-	struct sngss7_chan_data *peer_data;
+	struct sngss7_chan_data         *peer_data;
+	uint8_t peer_event_transfer_cnt;
 } sngss7_chan_data_t;
 
 #define SNGSS7_RX_GRS_PENDING (1 << 0)
@@ -536,7 +540,6 @@ typedef struct sngss7_span_data {
 	sngss7_group_data_t		rx_cgu;
 	sngss7_group_data_t		tx_cgu;
 	ftdm_queue_t 			*event_queue;
-	ftdm_queue_t                    *peer_chans;
 } sngss7_span_data_t;
 
 typedef struct sngss7_event_data
@@ -584,6 +587,15 @@ typedef enum {
 	FLAG_SENT_CPG			= (1 << 17),
 	FLAG_SUS_RECVD		    = (1 << 18),
 	FLAG_T6_CANCELED 		= (1 << 19),
+	FLAG_INR_TX			= (1 << 20),
+	FLAG_INR_SENT			= (1 << 21),
+	FLAG_INR_RX			= (1 << 22),
+	FLAG_INR_RX_DN			= (1 << 23),
+	FLAG_INF_TX			= (1 << 24),
+	FLAG_INF_SENT			= (1 << 25),
+	FLAG_INF_RX			= (1 << 26),
+	FLAG_INF_RX_DN			= (1 << 27),
+	FLAG_FULL_NUMBER			= (1 << 28),
 	FLAG_RELAY_DOWN			= (1 << 30),
 	FLAG_CKT_RECONFIG		= (1 << 31)
 } sng_ckt_flag_t;
@@ -606,6 +618,14 @@ typedef enum {
 	"INF_RESUME", \
 	"INF_PAUSED", \
 	"TX_ACM_SENT" \
+	"TX_INR" \
+	"INR_SENT" \
+	"RX_INR" \
+	"RX_INR_DN" \
+	"TX_INF" \
+	"INF SENT" \
+	"RX_INF" \
+	"RX_INF_DN" \
 	"RELAY_DOWN", \
 	"CKT_RECONFIG"
 FTDM_STR2ENUM_P(ftmod_ss7_ckt_state2flag, ftmod_ss7_ckt_flag2str, sng_ckt_flag_t)
@@ -820,6 +840,9 @@ void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan);
 void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan);
 void ft_to_sngss7_itx (ftdm_channel_t * ftdmchan);
 void ft_to_sngss7_txa (ftdm_channel_t * ftdmchan);
+void ft_to_sngss7_inr(ftdm_channel_t * ftdmchan);
+void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr);
+
 
 
 /* in ftmod_sangoma_ss7_in.c */
@@ -949,6 +972,7 @@ ftdm_status_t sngss7_add_raw_data(sngss7_chan_data_t *sngss7_info, uint8_t* data
 /* in ftmod_sangoma_ss7_timers.c */
 void handle_isup_t35(void *userdata);
 void handle_isup_t10(void *userdata);
+void handle_isup_t39(void *userdata);
 
 /******************************************************************************/
 
@@ -970,7 +994,7 @@ if (ftdmchan->state == new_state) { \
 #define SS7_INFO_CHAN(fchan, msg, args...)	ftdm_log_chan(fchan, FTDM_LOG_INFO, msg , ##args)
 #define SS7_WARN_CHAN(fchan, msg, args...)	ftdm_log_chan(fchan, FTDM_LOG_WARNING, msg , ##args)
 #define SS7_ERROR_CHAN(fchan, msg, args...)	ftdm_log_chan(fchan, FTDM_LOG_ERROR, msg , ##args)
-#define SS7_CTRIT_CHAN(fchan, msg, args...)	ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args)
+#define SS7_CRIT_CHAN(fchan, msg, args...)	ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args)
 
 #ifdef SS7_CODE_DEVEL
 #define SS7_DEVEL_DEBUG(a,...)   ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ );
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
index 5f0a0f0960..9ba11ada58 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
@@ -48,6 +48,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 	SiConEvnt 			iam;
 	ftdm_bool_t         native_going_up = FTDM_FALSE;
 	sngss7_chan_data_t	*sngss7_info = ftdmchan->call_data;;
+	sngss7_event_data_t *event_clone = NULL;
 	
 	SS7_FUNC_TRACE_ENTER (__FUNCTION__);
 	
@@ -75,28 +76,25 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 				SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", 
 						sngss7_info->circuit->cic, peer_info->circuit->cic);
 
+				/* retrieve only first message from the others guys queue (must be IAM) */
+				event_clone = ftdm_queue_dequeue(peer_info->event_queue);
+
 				/* make each one of us aware of the native bridge */
 				peer_info->peer_data = sngss7_info;
 				sngss7_info->peer_data = peer_info;
 
-				/* flush our own queue */
-				sngss7_flush_queue(sngss7_info->event_queue);
-
 				/* Go to up until release comes, note that state processing is done different and much simpler when there is a peer,
 				   We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function
-                   because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped 
+				   because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped 
 				   and we still need those variables for further IAM processing */
 				native_going_up = FTDM_TRUE;
 			}
 		}
 	}
 
-	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && sngss7_info->peer_data) {
-		sngss7_span_data_t *span_data = ftdmchan->span->signal_data;
-		sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue);
-		/* Retrieve IAM from our peer */
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
 		if (!event_clone) {
-			SS7_ERROR_CHAN(ftdmchan, "No event clone in peer queue!%s\n", "");
+			SS7_ERROR_CHAN(ftdmchan, "No IAM event clone in peer queue!%s\n", "");
 		} else if (event_clone->event_id != SNGSS7_CON_IND_EVENT) {
 			/* first message in the queue should ALWAYS be an IAM */
 			SS7_ERROR_CHAN(ftdmchan, "Invalid initial peer message type '%d'\n", event_clone->event_id);
@@ -141,9 +139,6 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 				copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum);
 			}
 		}
-		/* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events,
-		   this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */
-		ftdm_queue_enqueue(span_data->peer_chans, sngss7_info->peer_data->ftdmchan);
 	} else if (sngss7_info->circuit->transparent_iam &&
 		sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) {
 		SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic);
@@ -234,12 +229,107 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 		  the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */
 		ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
 		ftdm_channel_advance_states(ftdmchan);
-    }
+	}
+	
+	ftdm_safe_free(event_clone);
 
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
 
+void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr)
+{
+	SiCnStEvnt evnt;
+	sngss7_chan_data_t	*sngss7_info = ftdmchan->call_data;
+	
+	memset (&evnt, 0x0, sizeof (evnt));
+	
+	evnt.infoInd.eh.pres	   = PRSNT_NODEF;
+	evnt.infoInd.cgPtyAddrRespInd.pres = PRSNT_NODEF;
+	evnt.infoInd.cgPtyCatRespInd.pres = PRSNT_NODEF;
+
+	evnt.infoInd.chrgInfoRespInd.pres =  PRSNT_NODEF;
+	evnt.infoInd.chrgInfoRespInd.val = 0;
+	evnt.infoInd.solInfoInd.pres = PRSNT_NODEF;
+	evnt.infoInd.solInfoInd.val = 0;
+	evnt.infoInd.holdProvInd.pres =  PRSNT_NODEF;
+	evnt.infoInd.holdProvInd.val = 0;	
+	evnt.infoInd.spare.pres =  PRSNT_NODEF;
+	evnt.infoInd.spare.val = 0;
+
+	if (inr->infoReqInd.eh.pres == PRSNT_NODEF) {
+		if ((inr->infoReqInd.holdingInd.pres ==  PRSNT_NODEF) && (inr->infoReqInd.holdingInd.val == HOLD_REQ)) {
+			SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting holding information. Holding is not supported in INF.\n", sngss7_info->circuit->cic);
+		}
+		if ((inr->infoReqInd.chrgInfoReqInd.pres ==  PRSNT_NODEF) && (inr->infoReqInd.chrgInfoReqInd.val == CHRGINFO_REQ)) {
+			SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting charging information. Charging is not supported in INF.\n", sngss7_info->circuit->cic);
+		}
+		if ((inr->infoReqInd.malCaIdReqInd.pres ==  PRSNT_NODEF) && (inr->infoReqInd.malCaIdReqInd.val == CHRGINFO_REQ)) {
+			SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting malicious call id. Malicious call id is not supported in INF.\n", sngss7_info->circuit->cic);
+		}
+		
+		if ((inr->infoReqInd.cgPtyAdReqInd.pres ==  PRSNT_NODEF) && (inr->infoReqInd.cgPtyAdReqInd.val == CGPRTYADDREQ_REQ)) {
+			evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_INCL;
+			copy_cgPtyNum_to_sngss7 (ftdmchan, &evnt.cgPtyNum);
+		} else {
+			evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_NOTINCL;
+		}
+		
+		if ((inr->infoReqInd.cgPtyCatReqInd.pres ==  PRSNT_NODEF) && (inr->infoReqInd.cgPtyCatReqInd.val == CGPRTYCATREQ_REQ)) {
+			evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_INCL;
+			copy_cgPtyCat_to_sngss7 (ftdmchan, &evnt.cgPtyCat);
+		} else {
+			evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_NOTINCL;
+		}
+	}
+	else {
+		SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR with no information request. Sending back default INF.\n", sngss7_info->circuit->cic);
+	}
+		
+	sng_cc_inf(1, 
+			  sngss7_info->suInstId,
+			  sngss7_info->spInstId,
+			  sngss7_info->circuit->id, 
+			  &evnt, 
+			  INFORMATION);
+
+	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx INF\n", sngss7_info->circuit->cic);
+	
+}
+
+void ft_to_sngss7_inr(ftdm_channel_t *ftdmchan)
+{
+	SiCnStEvnt evnt;
+	sngss7_chan_data_t	*sngss7_info = ftdmchan->call_data;
+
+	memset (&evnt, 0x0, sizeof (evnt));
+
+	evnt.infoReqInd.eh.pres	   = PRSNT_NODEF;
+	evnt.infoReqInd.cgPtyAdReqInd.pres = PRSNT_NODEF;
+	evnt.infoReqInd.cgPtyAdReqInd.val=CGPRTYADDREQ_REQ;
+
+	evnt.infoReqInd.holdingInd.pres =  PRSNT_NODEF;
+	evnt.infoReqInd.holdingInd.val = HOLD_REQ;
+
+	evnt.infoReqInd.cgPtyCatReqInd.pres = PRSNT_NODEF;
+	evnt.infoReqInd.cgPtyCatReqInd.val = CGPRTYCATREQ_REQ;
+
+	evnt.infoReqInd.chrgInfoReqInd.pres =  PRSNT_NODEF;
+	evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_REQ;
+
+	evnt.infoReqInd.malCaIdReqInd.pres =  PRSNT_NODEF;
+	evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFOREQ;
+
+	sng_cc_inr(1, 
+			  sngss7_info->suInstId,
+			  sngss7_info->spInstId,
+			  sngss7_info->circuit->id, 
+			  &evnt, 
+			  INFORMATREQ);
+
+	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx INR\n", sngss7_info->circuit->cic);
+}
+
 void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan)
 {
 	SS7_FUNC_TRACE_ENTER (__FUNCTION__);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
index 7426b033b8..96359ba595 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
@@ -186,7 +186,7 @@ ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPt
 		ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Calling NADI value \"%s\"\n", clg_nadi);
 		cgPtyNum->natAddrInd.val = atoi(clg_nadi);
 	}
-	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", cgPtyNum->presRest.val);
+	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number NADI value %d\n", cgPtyNum->natAddrInd.val);
 
 	return copy_tknStr_to_sngss7(caller_data->cid_num.digits, &cgPtyNum->addrSig, &cgPtyNum->oddEven);
 }
@@ -257,7 +257,7 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc
         locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi;
 
         locPtyNum->scrnInd.pres = pres_val;
-        val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind");
+		val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind");
         if (!ftdm_strlen_zero(val)) {
 			locPtyNum->scrnInd.val = atoi(val);
 			ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c
index 6138ea34b0..8cac996213 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c
@@ -49,7 +49,7 @@
 /******************************************************************************/
 
 /* PROTOTYPES *****************************************************************/
-void handle_isup_t35(void *userdata);
+
 /******************************************************************************/
 
 /* FUNCTIONS ******************************************************************/
@@ -76,10 +76,13 @@ void handle_isup_t35(void *userdata)
     /* end the call */
     ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
 
-    /* kill t10 if active */
+    /* kill t10 t39 if active */
     if (sngss7_info->t10.hb_timer_id) {
         ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id);
     }
+    if (sngss7_info->t39.hb_timer_id) {
+        ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id);
+    }
 
     /*unlock*/
     ftdm_channel_unlock(ftdmchan);
@@ -108,7 +111,43 @@ void handle_isup_t10(void *userdata)
 
 	SS7_FUNC_TRACE_EXIT(__FUNCTION__);
 }
- 
+
+void handle_isup_t39(void *userdata)
+{
+	SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+	sngss7_timer_data_t *timer = userdata;
+	sngss7_chan_data_t  *sngss7_info = timer->sngss7_info;
+	ftdm_channel_t      *ftdmchan = sngss7_info->ftdmchan;
+
+	/* now that we have the right channel...put a lock on it so no-one else can use it */
+	ftdm_channel_lock(ftdmchan);
+
+	/* Q.764 2.2.5 Address incomplete (T35 expiry action is hangup with cause 28 according to Table A.1/Q.764) */
+	SS7_ERROR("[Call-Control] Timer 39 expired on CIC = %d\n", sngss7_info->circuit->cic);
+
+	/* set the flag to indicate this hangup is started from the local side */
+	sngss7_set_ckt_flag(sngss7_info, FLAG_LOCAL_REL);
+
+	/* hang up on timer expiry */
+	ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_INVALID_NUMBER_FORMAT;
+
+	/* end the call */
+	ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+
+	/* kill t10 t35 if active */
+	if (sngss7_info->t10.hb_timer_id) {
+		ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id);
+	}
+	if (sngss7_info->t35.hb_timer_id) {
+		ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id);
+	}
+
+	/*unlock*/
+	ftdm_channel_unlock(ftdmchan);
+
+	SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+}
 /******************************************************************************/
 /* For Emacs:
  * Local Variables:
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
index 724fee25b9..f64356dd1f 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
@@ -146,6 +146,7 @@ typedef struct sng_ccSpan
 	uint32_t		t16;
 	uint32_t		t17;
 	uint32_t		t35;
+	uint32_t		t39;
 	uint32_t		tval;
 } sng_ccSpan_t;
 
@@ -487,6 +488,7 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen)
 
 	/* Set the transparent_iam_max_size to default value */
 	g_ftdm_sngss7_data.cfg.transparent_iam_max_size=800;
+	g_ftdm_sngss7_data.cfg.force_inr = 0;
 
 	/* extract all the information from the parameters */
 	for (i = 0; i < num_parms; i++) {
@@ -508,6 +510,14 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen)
 			ftmod_ss7_set_glare_resolution (parm->val);
 			SS7_DEBUG("Found glare resolution configuration = %d  %s\n", g_ftdm_sngss7_data.cfg.glareResolution, parm->val );
 		}
+		else if (!strcasecmp(parm->var, "force-inr")) {
+			if (ftdm_true(parm->val)) {
+				g_ftdm_sngss7_data.cfg.force_inr = 1;
+			} else {
+				g_ftdm_sngss7_data.cfg.force_inr = 0;
+			}
+			SS7_DEBUG("Found INR force configuration = %s\n", parm->val );
+		}
 		else {
 			SS7_ERROR("Found an invalid parameter \"%s\"!\n", parm->val);
 			return FTDM_FAIL;
@@ -2004,7 +2014,6 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span)
 			flag_loc_nadi = 1;
 			sng_ccSpan.loc_nadi = atoi(parm->val);
 			SS7_DEBUG("Found default LOC_NADI parm->value = %d\n", sng_ccSpan.loc_nadi);
-	
 		/**********************************************************************/
 		} else if (!strcasecmp(parm->var, "lpa_on_cot")) {
 		/**********************************************************************/
@@ -2062,6 +2071,11 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span)
 			sng_ccSpan.t35 = atoi(parm->val);
 			SS7_DEBUG("Found isup t35 = %d\n",sng_ccSpan.t35);
 		/**********************************************************************/
+		} else if (!strcasecmp(parm->var, "isup.t39")) {
+		/**********************************************************************/
+			sng_ccSpan.t39 = atoi(parm->val);
+			SS7_DEBUG("Found isup t39 = %d\n",sng_ccSpan.t39);
+		/**********************************************************************/
 		} else if (!strcasecmp(parm->var, "isup.tval")) {
 		/**********************************************************************/
 			sng_ccSpan.tval = atoi(parm->val);
@@ -3044,6 +3058,12 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan)
 		} else {
 			g_ftdm_sngss7_data.cfg.isupCkt[x].t35		= ccSpan->t35;
 		}
+		if (ccSpan->t39 == 0) {
+			g_ftdm_sngss7_data.cfg.isupCkt[x].t39		= 120;
+		} else {
+			g_ftdm_sngss7_data.cfg.isupCkt[x].t39		= ccSpan->t39;
+		}
+		
 		if (ccSpan->tval == 0) {
 			g_ftdm_sngss7_data.cfg.isupCkt[x].tval		= 10;
 		} else {
@@ -3148,6 +3168,13 @@ static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan)
 		ss7_info->t10.callback		= handle_isup_t10;
 		ss7_info->t10.sngss7_info	= ss7_info;
 
+		/* prepare the timer structures */
+		ss7_info->t39.sched		= ((sngss7_span_data_t *)(ftdmspan->signal_data))->sched;
+		ss7_info->t39.counter		= 1;
+		ss7_info->t39.beat		= (isupCkt->t39) * 100; /* beat is in ms, t39 is in 100ms */
+		ss7_info->t39.callback		= handle_isup_t39;
+		ss7_info->t39.sngss7_info	= ss7_info;
+
 
 	/**************************************************************************/
 	} /* for (i == 1; i < ftdmspan->chan_count; i++) */