diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 1ede703a41..15e853236d 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -56,6 +56,9 @@
 #define FTDM_READ_TRACE_INDEX 0
 #define FTDM_WRITE_TRACE_INDEX 1
 
+ftdm_time_t time_last_throttle_log = 0;
+ftdm_time_t time_current_throttle_log = 0;
+
 static int time_is_init = 0;
 
 static void time_init(void)
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
index 98b09e9305..5142de5211 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
@@ -242,10 +242,10 @@ static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftd
 static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
 {
 
+	sngisdn_snd_event(span, event);
 	switch (event) {
 		/* Check if the span woke up from power-saving mode */
 		case FTDM_OOB_ALARM_CLEAR:
-			sngisdn_snd_event(span, SNG_L1EVENT_ALARM_OFF);
 			if (FTDM_SPAN_IS_BRI(span)) {
 				ftdm_channel_t *ftdmchan;
 				sngisdn_chan_data_t *sngisdn_info;
@@ -267,9 +267,6 @@ static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_eve
 				ftdm_iterator_free(chaniter);
 			}
 			break;
-		case FTDM_OOB_ALARM_TRAP:		
-			sngisdn_snd_event(span, SNG_L1EVENT_ALARM_ON);
-			break;
 		default:
 			/* Ignore other events for now */
 			break;
@@ -327,7 +324,7 @@ static void *ftdm_sangoma_isdn_dchan_run(ftdm_thread_t *me, void *obj)
 					len = 1000;
 					status = ftdm_channel_read(dchan, data, &len);
 					if (status == FTDM_SUCCESS) {
-						sngisdn_snd_data(span, data, len);
+						sngisdn_snd_data(dchan, data, len);
 					} else {
 						ftdm_log_chan_msg(dchan, FTDM_LOG_WARNING, "Failed to read from channel \n");
 					}
@@ -1019,7 +1016,8 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init)
 	g_sngisdn_event_interface.sta.sng_q931_trc_ind	= sngisdn_rcv_q931_trace;
 	g_sngisdn_event_interface.sta.sng_cc_sta_ind	= sngisdn_rcv_cc_ind;
 
-	g_sngisdn_event_interface.io.sng_data_req 	= sngisdn_rcv_data_req;
+	g_sngisdn_event_interface.io.sng_l1_data_req	= sngisdn_rcv_l1_data_req;
+	g_sngisdn_event_interface.io.sng_l1_cmd_req		= sngisdn_rcv_l1_cmd_req;
 	
 	for(i=1;i<=MAX_VARIANTS;i++) {		
 		ftdm_mutex_create(&g_sngisdn_data.ccs[i].mutex);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
index 75262c9627..7c66c38acf 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
@@ -293,8 +293,8 @@ void sngisdn_snd_reset(ftdm_channel_t *ftdmchan);
 void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan);
 void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan);
 void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan);
-void sngisdn_snd_data(ftdm_span_t *span, uint8_t *data, ftdm_size_t len);
-void sngisdn_snd_event(ftdm_span_t *span, sng_isdn_l1_event_t l1_event);
+void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len);
+void sngisdn_snd_event(ftdm_channel_t *span, sng_isdn_l1_event_t l1_event);
 
 /* Inbound Call Control functions */
 void sngisdn_rcv_con_ind(int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces);
@@ -314,7 +314,9 @@ void sngisdn_rcv_srv_ind(int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces)
 void sngisdn_rcv_srv_cfm(int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces);
 void sngisdn_rcv_rst_cfm(int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType);
 void sngisdn_rcv_rst_ind(int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType);
-int16_t sngisdn_rcv_data_req(uint16_t spId, uint8_t *buff, uint32_t length);
+int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_isdn_l1_frame_t *l1_frame);
+int16_t sngisdn_rcv_l1_cmd_req(uint16_t spId, sng_l1_cmd_t *l1_cmd);
+
 
 void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event);
 void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
index eabaa7affc..6c75fb3a81 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
@@ -156,34 +156,34 @@ ftdm_status_t sngisdn_stack_cfg(ftdm_span_t *span)
 ftdm_status_t sngisdn_stack_cfg_phy_gen(void)
 {
 	/*local variables*/
-    L1Mngmt     cfg;    /*configuration structure*/
-    Pst         pst;    /*post structure*/
+	L1Mngmt     cfg;    /*configuration structure*/
+	Pst         pst;    /*post structure*/
 
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 
-    /* insert the destination Entity */
-    pst.dstEnt = ENTL1;
+	/* insert the destination Entity */
+	pst.dstEnt = ENTL1;
 
-    /*clear the configuration structure*/
+	/*clear the configuration structure*/
 	memset(&cfg, 0, sizeof(cfg));
 
-    /*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	/*fill in some general sections of the header*/
+	stack_hdr_init(&cfg.hdr);
 
-    /*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTL1;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STGEN;
+	/*fill in the specific fields of the header*/
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTL1;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STGEN;
 
-    stack_pst_init(&cfg.t.cfg.s.l1Gen.sm );
-    cfg.t.cfg.s.l1Gen.sm.srcEnt     = ENTL1;
-    cfg.t.cfg.s.l1Gen.sm.dstEnt     = ENTSM;
+	stack_pst_init(&cfg.t.cfg.s.l1Gen.sm );
+	cfg.t.cfg.s.l1Gen.sm.srcEnt     = ENTL1;
+	cfg.t.cfg.s.l1Gen.sm.dstEnt     = ENTSM;
 
-    cfg.t.cfg.s.l1Gen.nmbLnks       = MAX_L1_LINKS+1;
-    cfg.t.cfg.s.l1Gen.poolTrUpper   = POOL_UP_TR;        /* upper pool threshold */
-    cfg.t.cfg.s.l1Gen.poolTrLower   = POOL_LW_TR;        /* lower pool threshold */
+	cfg.t.cfg.s.l1Gen.nmbLnks       = MAX_L1_LINKS;
+	cfg.t.cfg.s.l1Gen.poolTrUpper   = POOL_UP_TR;        /* upper pool threshold */
+	cfg.t.cfg.s.l1Gen.poolTrLower   = POOL_LW_TR;        /* lower pool threshold */
 
 	if (sng_isdn_phy_config(&pst, &cfg)) {
 		return FTDM_FAIL;
@@ -193,38 +193,38 @@ ftdm_status_t sngisdn_stack_cfg_phy_gen(void)
 
 ftdm_status_t sngisdn_stack_cfg_phy_psap(ftdm_span_t *span)
 {	
-    L1Mngmt				cfg;
-    Pst					pst;
+	L1Mngmt				cfg;
+	Pst					pst;
 
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
 
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 
-    /* insert the destination Entity */
-    pst.dstEnt = ENTL1;
+	/* insert the destination Entity */
+	pst.dstEnt = ENTL1;
 
-    /*clear the configuration structure*/
+	/*clear the configuration structure*/
 	memset(&cfg, 0, sizeof(cfg));
 
-    /*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	/*fill in some general sections of the header*/
+	stack_hdr_init(&cfg.hdr);
 
-    /*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTL1;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STPSAP;
+	/*fill in the specific fields of the header*/
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTL1;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STPSAP;
 
 	cfg.hdr.elmId.elmntInst1    = signal_data->link_id;
-	
+
 	if (!signal_data->dchan) {
 		ftdm_log(FTDM_LOG_ERROR, "%s:No d-channels specified\n", span->name);
 		return FTDM_FAIL;
-	} 
+	}
 
 	cfg.t.cfg.s.l1PSAP.sockfd = (int32_t)signal_data->dchan->sockfd;
-	
+
 	switch(span->trunk_type) {
 		case FTDM_TRUNK_E1:
 			cfg.t.cfg.s.l1PSAP.type = SNG_L1_TYPE_PRI;
@@ -240,9 +240,9 @@ ftdm_status_t sngisdn_stack_cfg_phy_psap(ftdm_span_t *span)
 		default:
 			ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunk type %d\n", span->name, span->trunk_type);
 			return FTDM_FAIL;
-	}	
-    cfg.t.cfg.s.l1PSAP.spId		= signal_data->link_id;
-		
+	}
+	cfg.t.cfg.s.l1PSAP.spId		= signal_data->link_id;
+
 	if (sng_isdn_phy_config(&pst, &cfg)) {
 		return FTDM_FAIL;
 	}
@@ -253,25 +253,25 @@ ftdm_status_t sngisdn_stack_cfg_phy_psap(ftdm_span_t *span)
 ftdm_status_t sngisdn_stack_cfg_q921_gen(void)
 {
 	BdMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 	/* insert the destination Entity */
-    pst.dstEnt = ENTLD;
+	pst.dstEnt = ENTLD;
 
-    /*clear the configuration structure*/
-    memset(&cfg, 0, sizeof(cfg));
+	/*clear the configuration structure*/
+	memset(&cfg, 0, sizeof(cfg));
 	/*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
-		
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTLD;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STGEN;
-    /* fill in the Gen Conf structures internal pst struct */
+	stack_hdr_init(&cfg.hdr);
 
-    stack_pst_init(&cfg.t.cfg.s.bdGen.sm);
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTLD;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STGEN;
+	/* fill in the Gen Conf structures internal pst struct */
+
+	stack_pst_init(&cfg.t.cfg.s.bdGen.sm);
 
 	cfg.t.cfg.s.bdGen.sm.dstEnt    = ENTSM;         /* entity */
 	
@@ -284,8 +284,8 @@ ftdm_status_t sngisdn_stack_cfg_q921_gen(void)
 #ifdef LAPD_3_4
 	cfg.t.cfg.s.bdGen.timeRes     = 100;      /* timer resolution = 1 sec */
 #endif
-    cfg.t.cfg.s.bdGen.poolTrUpper   = 2;        /* upper pool threshold */
-    cfg.t.cfg.s.bdGen.poolTrLower   = 1;        /* lower pool threshold */
+	cfg.t.cfg.s.bdGen.poolTrUpper   = 2;        /* upper pool threshold */
+	cfg.t.cfg.s.bdGen.poolTrLower   = 1;        /* lower pool threshold */
 
 	if (sng_isdn_q921_config(&pst, &cfg)) {
 		return FTDM_FAIL;
@@ -296,27 +296,27 @@ ftdm_status_t sngisdn_stack_cfg_q921_gen(void)
 ftdm_status_t sngisdn_stack_cfg_q921_msap(ftdm_span_t *span)
 {
 	BdMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
 
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 	/* insert the destination Entity */
-    pst.dstEnt = ENTLD;
+	pst.dstEnt = ENTLD;
 
-    /*clear the configuration structure*/
-    memset(&cfg, 0, sizeof(cfg));
+	/*clear the configuration structure*/
+	memset(&cfg, 0, sizeof(cfg));
 	/*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	stack_hdr_init(&cfg.hdr);
 
 	cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTLD;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STMSAP;
+	cfg.hdr.entId.ent   = ENTLD;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STMSAP;
 
 	cfg.t.cfg.s.bdMSAP.lnkNmb      = signal_data->link_id;
-	
+
 	cfg.t.cfg.s.bdMSAP.maxOutsFrms = 24;            /* MAC window */
 	cfg.t.cfg.s.bdMSAP.tQUpperTrs  = 32;           /* Tx Queue Upper Threshold */
 	cfg.t.cfg.s.bdMSAP.tQLowerTrs  = 24;            /* Tx Queue Lower Threshold */
@@ -328,7 +328,7 @@ ftdm_status_t sngisdn_stack_cfg_q921_msap(ftdm_span_t *span)
 	cfg.t.cfg.s.bdMSAP.route       = RTESPEC;            /* Route */
 	cfg.t.cfg.s.bdMSAP.dstProcId   = SFndProcId(); /* destination proc id */
 	cfg.t.cfg.s.bdMSAP.dstEnt      = ENTL1;        /* entity */
-	cfg.t.cfg.s.bdMSAP.dstInst     = S_INST;      /* instance */	
+	cfg.t.cfg.s.bdMSAP.dstInst     = S_INST;      /* instance */
 	cfg.t.cfg.s.bdMSAP.t201Tmr     = 1;            /* T201 - should be equal to t200Tmr */
 	cfg.t.cfg.s.bdMSAP.t202Tmr     = 2;          /* T202 */
 	cfg.t.cfg.s.bdMSAP.bndRetryCnt = 2;            /* bind retry counter */
@@ -377,7 +377,7 @@ ftdm_status_t sngisdn_stack_cfg_q921_msap(ftdm_span_t *span)
 	if (signal_data->setup_arb == SNGISDN_OPT_TRUE) {
 		cfg.t.cfg.s.bdMSAP.setUpArb    = ACTIVE;
 	} else if (signal_data->setup_arb == SNGISDN_OPT_FALSE) {
- 		cfg.t.cfg.s.bdMSAP.setUpArb    = PASSIVE;
+		cfg.t.cfg.s.bdMSAP.setUpArb    = PASSIVE;
 	}
 
 	if (sng_isdn_q921_config(&pst, &cfg)) {
@@ -389,24 +389,24 @@ ftdm_status_t sngisdn_stack_cfg_q921_msap(ftdm_span_t *span)
 ftdm_status_t sngisdn_stack_cfg_q921_dlsap(ftdm_span_t *span, uint8_t management)
 {
 	BdMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 	/* insert the destination Entity */
-    pst.dstEnt = ENTLD;
+	pst.dstEnt = ENTLD;
 
-    /*clear the configuration structure*/
-    memset(&cfg, 0, sizeof(cfg));
+	/*clear the configuration structure*/
+	memset(&cfg, 0, sizeof(cfg));
 	/*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	stack_hdr_init(&cfg.hdr);
 
 	/*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTLD;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STDLSAP;
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTLD;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STDLSAP;
 
 	cfg.t.cfg.s.bdDLSAP.lnkNmb		= signal_data->link_id;
 
@@ -418,10 +418,10 @@ ftdm_status_t sngisdn_stack_cfg_q921_dlsap(ftdm_span_t *span, uint8_t management
 	} else {
 		cfg.t.cfg.s.bdDLSAP.k			= 7;             	/* k */
 	}
-	
+
 	cfg.t.cfg.s.bdDLSAP.n200		= 3;             	/* n200 */
 	cfg.t.cfg.s.bdDLSAP.congTmr		= 300;           	/* congestion timer */
-	cfg.t.cfg.s.bdDLSAP.t200Tmr		= 1;				/* t1 changed from 25 */ 
+	cfg.t.cfg.s.bdDLSAP.t200Tmr		= 1;				/* t1 changed from 25 */
 	cfg.t.cfg.s.bdDLSAP.t203Tmr		= 10;				/* t3 changed from 50 */
 	cfg.t.cfg.s.bdDLSAP.mod			= 128;           	/* modulo */
 	cfg.t.cfg.s.bdDLSAP.selector	= 0;				/* Selector 0 */
@@ -471,28 +471,28 @@ ftdm_status_t sngisdn_stack_cfg_q921_dlsap(ftdm_span_t *span, uint8_t management
 ftdm_status_t sngisdn_stack_cfg_q931_gen(void)
 {
 	InMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 
-    /* insert the destination Entity */
-    pst.dstEnt = ENTIN;
+	/* insert the destination Entity */
+	pst.dstEnt = ENTIN;
 
-    /*clear the configuration structure*/
+	/*clear the configuration structure*/
 	memset(&cfg, 0, sizeof(cfg));
 
-    /*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	/*fill in some general sections of the header*/
+	stack_hdr_init(&cfg.hdr);
 
-    /*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTIN;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STGEN;
+	/*fill in the specific fields of the header*/
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTIN;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STGEN;
 
-    /* fill in the Gen Conf structures internal pst struct */
-    stack_pst_init(&cfg.t.cfg.s.inGen.sm);
+	/* fill in the Gen Conf structures internal pst struct */
+	stack_pst_init(&cfg.t.cfg.s.inGen.sm);
 
 	cfg.t.cfg.s.inGen.nmbSaps = MAX_VARIANTS+1;			/* Total number of variants supported */
 
@@ -526,26 +526,26 @@ ftdm_status_t sngisdn_stack_cfg_q931_gen(void)
 ftdm_status_t sngisdn_stack_cfg_q931_tsap(ftdm_span_t *span)
 {
 	InMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 	unsigned i;
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 
-    /* insert the destination Entity */
-    pst.dstEnt = ENTIN;
+	/* insert the destination Entity */
+	pst.dstEnt = ENTIN;
 
-    /*clear the configuration structure*/
+	/*clear the configuration structure*/
 	memset(&cfg, 0, sizeof(cfg));
 
-    /*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	/*fill in some general sections of the header*/
+	stack_hdr_init(&cfg.hdr);
 
-    /*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTIN;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STTSAP;
+	/*fill in the specific fields of the header*/
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTIN;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STTSAP;
 
 	cfg.t.cfg.s.inTSAP.sapId = signal_data->cc_id;
 
@@ -589,31 +589,31 @@ ftdm_status_t sngisdn_stack_cfg_q931_tsap(ftdm_span_t *span)
 ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
 {
 	InMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 
 	unsigned i;
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 
-    /* insert the destination Entity */
-    pst.dstEnt = ENTIN;
+	/* insert the destination Entity */
+	pst.dstEnt = ENTIN;
 
-    /*clear the configuration structure*/
+	/*clear the configuration structure*/
 	memset(&cfg, 0, sizeof(cfg));
 
-    /*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);
+	/*fill in some general sections of the header*/
+	stack_hdr_init(&cfg.hdr);
+
+	/*fill in the specific fields of the header*/
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTIN;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STDLSAP;
 
-    /*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTIN;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STDLSAP;
-	
 	cfg.hdr.response.selector=0;
 
-	
+
 	cfg.t.cfg.s.inDLSAP.sapId = signal_data->link_id;
 	cfg.t.cfg.s.inDLSAP.spId = signal_data->link_id;
 	cfg.t.cfg.s.inDLSAP.swtch = sng_isdn_stack_switchtype(signal_data->switchtype);
@@ -659,7 +659,7 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
 		cfg.t.cfg.s.inDLSAP.ctldInt[1] = 1;
 	}
 
-	cfg.t.cfg.s.inDLSAP.numRstInd = 255;	
+	cfg.t.cfg.s.inDLSAP.numRstInd = 255;
 	cfg.t.cfg.s.inDLSAP.relOpt = TRUE;
 #ifdef ISDN_SRV
 	cfg.t.cfg.s.inDLSAP.bcas = FALSE;
@@ -839,36 +839,36 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
 ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span)
 {
 	InMngmt cfg;
-    Pst     pst;
+	Pst     pst;
 	uint8_t	i;
-	uint8_t numCes=1;	
+	uint8_t numCes=1;
 
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
 	if (span->trunk_type == FTDM_TRUNK_BRI_PTMP && signal_data->signalling == SNGISDN_SIGNALING_NET) {
 		numCes = 8;
 	}
-    /* initalize the post structure */
-    stack_pst_init(&pst);
+	/* initalize the post structure */
+	stack_pst_init(&pst);
 
-    /* insert the destination Entity */
-    pst.dstEnt = ENTIN;
+	/* insert the destination Entity */
+	pst.dstEnt = ENTIN;
 
-    /*clear the configuration structure*/
+	/*clear the configuration structure*/
 	memset(&cfg, 0, sizeof(cfg));
 
-    /*fill in some general sections of the header*/
-    stack_hdr_init(&cfg.hdr);	
+	/*fill in some general sections of the header*/
+	stack_hdr_init(&cfg.hdr);
 
-    /*fill in the specific fields of the header*/
-    cfg.hdr.msgType     = TCFG;
-    cfg.hdr.entId.ent   = ENTIN;
-    cfg.hdr.entId.inst  = S_INST;
-    cfg.hdr.elmId.elmnt = STDLC;
+	/*fill in the specific fields of the header*/
+	cfg.hdr.msgType     = TCFG;
+	cfg.hdr.entId.ent   = ENTIN;
+	cfg.hdr.entId.inst  = S_INST;
+	cfg.hdr.elmId.elmnt = STDLC;
 
 	cfg.hdr.response.selector=0;
 
 	cfg.t.cfg.s.inLCe.sapId = signal_data->link_id;
-	
+
 
 	cfg.t.cfg.s.inLCe.lnkUpDwnInd = TRUE;
 	cfg.t.cfg.s.inLCe.tCon.enb = TRUE;
@@ -877,7 +877,7 @@ ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span)
 	cfg.t.cfg.s.inLCe.tDisc.val = 35;
 	cfg.t.cfg.s.inLCe.t314.enb = FALSE; /* if segmentation enabled, set to TRUE */
 	cfg.t.cfg.s.inLCe.t314.val = 35;
-		
+
 	cfg.t.cfg.s.inLCe.t332i.enb = FALSE; /* set to TRUE for NFAS */
 
 #ifdef NFAS
@@ -897,7 +897,6 @@ ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span)
 	cfg.t.cfg.s.inLCe.tRstAck.enb = TRUE;
 	cfg.t.cfg.s.inLCe.tRstAck.val = 10;
 
-
 	cfg.t.cfg.s.inLCe.usid = 0;
 	cfg.t.cfg.s.inLCe.tid = 0;
 
@@ -983,11 +982,11 @@ ftdm_status_t sngisdn_stack_cfg_cc_sap(ftdm_span_t *span)
 	cfg.t.cfg.s.ccISAP.pst.dstInst		= S_INST;
 	cfg.t.cfg.s.ccISAP.pst.dstProcId	= SFndProcId();
 
-    cfg.t.cfg.s.ccISAP.pst.prior		= PRIOR0;
-    cfg.t.cfg.s.ccISAP.pst.route		= RTESPEC;
-    cfg.t.cfg.s.ccISAP.pst.region		= S_REG;
-    cfg.t.cfg.s.ccISAP.pst.pool			= S_POOL;
-    cfg.t.cfg.s.ccISAP.pst.selector		= 0;
+	cfg.t.cfg.s.ccISAP.pst.prior		= PRIOR0;
+	cfg.t.cfg.s.ccISAP.pst.route		= RTESPEC;
+	cfg.t.cfg.s.ccISAP.pst.region		= S_REG;
+	cfg.t.cfg.s.ccISAP.pst.pool			= S_POOL;
+	cfg.t.cfg.s.ccISAP.pst.selector		= 0;
 
 	cfg.t.cfg.s.ccISAP.suId				= signal_data->cc_id;
 	cfg.t.cfg.s.ccISAP.spId				= signal_data->cc_id;
@@ -1005,19 +1004,19 @@ ftdm_status_t sngisdn_stack_cfg_cc_sap(ftdm_span_t *span)
 void stack_pst_init(Pst *pst)
 {
 	memset(pst, 0, sizeof(Pst));
-	 /*fill in the post structure*/
-    pst->dstProcId   = SFndProcId();
-    pst->dstInst     = S_INST;
+		/*fill in the post structure*/
+	pst->dstProcId   = SFndProcId();
+	pst->dstInst     = S_INST;
 
-    pst->srcProcId   = SFndProcId();
-    pst->srcEnt      = ENTSM;
-    pst->srcInst     = S_INST;
+	pst->srcProcId   = SFndProcId();
+	pst->srcEnt      = ENTSM;
+	pst->srcInst     = S_INST;
 
-    pst->prior       = PRIOR0;
-    pst->route       = RTESPEC;
-    pst->region      = S_REG;
-    pst->pool        = S_POOL;
-    pst->selector    = 0;
+	pst->prior       = PRIOR0;
+	pst->route       = RTESPEC;
+	pst->region      = S_REG;
+	pst->pool        = S_POOL;
+	pst->selector    = 0;
 	return;
 }
 
@@ -1026,21 +1025,21 @@ void stack_pst_init(Pst *pst)
 void stack_hdr_init(Header *hdr)
 {
 	hdr->msgType                = 0;
-    hdr->msgLen                 = 0;
-    hdr->entId.ent              = 0;
-    hdr->entId.inst             = 0;
-    hdr->elmId.elmnt            = 0;
-    hdr->elmId.elmntInst1       = 0;
-    hdr->elmId.elmntInst2       = 0;
-    hdr->elmId.elmntInst3       = 0;
-    hdr->seqNmb                 = 0;
-    hdr->version                = 0;
-    hdr->response.prior         = PRIOR0;
-    hdr->response.route         = RTESPEC;
-    hdr->response.mem.region    = S_REG;
-    hdr->response.mem.pool      = S_POOL;
-    hdr->transId                = 0;
-    hdr->response.selector      = 0;
+	hdr->msgLen                 = 0;
+	hdr->entId.ent              = 0;
+	hdr->entId.inst             = 0;
+	hdr->elmId.elmnt            = 0;
+	hdr->elmId.elmntInst1       = 0;
+	hdr->elmId.elmntInst2       = 0;
+	hdr->elmId.elmntInst3       = 0;
+	hdr->seqNmb                 = 0;
+	hdr->version                = 0;
+	hdr->response.prior         = PRIOR0;
+	hdr->response.route         = RTESPEC;
+	hdr->response.mem.region    = S_REG;
+	hdr->response.mem.pool      = S_POOL;
+	hdr->transId                = 0;
+	hdr->response.selector      = 0;
 	return;
 }
 
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
index c0ee11d980..94bd6e23e1 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
@@ -595,16 +595,65 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare)
 	return;
 }
 
-void sngisdn_snd_data(ftdm_span_t *span, uint8_t *data, ftdm_size_t len)
+/* We received an incoming frame on the d-channel, send data to the stack */
+void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len)
 {
-	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
-	sng_isdn_data_ind(signal_data->link_id, data, len);
+	l1_frame_t l1_frame;	
+	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) dchan->span->signal_data;
+
+	memset(&l1_frame, 0, sizeof(l1_frame));
+	l1_frame.len = len;
+
+	memcpy(&l1_frame.data, data, len);
+
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_CRC)) {
+		l1_frame.flags |= SNG_L1FRAME_ERROR_CRC;
+	}
+
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FRAME)) {
+		l1_frame.flags |= SNG_L1FRAME_ERROR_FRAME;
+	}
+	
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_ABORT)) {
+		l1_frame.flags |= SNG_L1FRAME_ERROR_ABORT;
+	}
+
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FIFO)) {
+		l1_frame.flags |= SNG_L1FRAME_ERROR_FIFO;
+	}
+
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_DMA)) {
+		l1_frame.flags |= SNG_L1FRAME_ERROR_DMA;
+	}
+
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_QUEUE_THRES)) {
+		/* Should we trigger congestion here? */		
+		l1_frame.flags |= SNG_L1FRAME_QUEUE_THRES;
+	}
+
+	if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_QUEUE_FULL)) {
+		/* Should we trigger congestion here? */
+		l1_frame.flags |= SNG_L1FRAME_QUEUE_FULL;
+	}
+	
+	sng_isdn_data_ind(signal_data->link_id, &l1_frame);
 }
 
-void sngisdn_snd_event(ftdm_span_t *span, sng_isdn_l1_event_t l1_event)
-{
-	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
-	sng_isdn_event_ind(signal_data->link_id, l1_event);
+void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event)
+{	
+	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) dchan->span->signal_data;
+	switch(event) {
+		case FTDM_OOB_ALARM_CLEAR:
+			sng_isdn_event_ind(signal_data->link_id, SNG_L1EVENT_ALARM_OFF);
+			break;
+		case FTDM_OOB_ALARM_TRAP:
+			sng_isdn_event_ind(signal_data->link_id, SNG_L1EVENT_ALARM_ON);
+			break;
+		default:
+			/* We do not care about the other OOB events for now */
+			return;
+	}
+	return;
 }
 
 
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
index f40f2b20c7..d6573ac2de 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
@@ -170,7 +170,7 @@ static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
 static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan) 
 { 
 	return  __sangoma_open_tdmapi_span_chan(span, chan);
-}                        
+}
 #endif
 
 static ftdm_io_interface_t wanpipe_interface;
@@ -759,6 +759,49 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
 	return FTDM_SUCCESS;
 }
 
+static void wanpipe_read_stats(ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats)
+{
+	ftdmchan->iostats.s.rx.error_flags = 0;
+	if (rx_stats->rx_hdr_errors) {
+		wanpipe_reset_stats(ftdmchan);
+		ftdm_log_chan_msg_throttle(ftdmchan, "IO errors\n");
+	}
+
+	ftdmchan->iostats.s.rx_queue_size = rx_stats->rx_h.rx_h.max_rx_queue_length;
+	ftdmchan->iostats.s.rx_queue_len = rx_stats->rx_h.current_number_of_frames_in_rx_queue;
+	
+	if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_ABORT_ERROR_BIT)) {
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_ABORT);
+	}
+	if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_DMA_ERROR_BIT)) {
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_DMA);
+	}
+	if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_FIFO_ERROR_BIT)) {
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FIFO);
+	}
+	if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_CRC_ERROR_BIT)) {
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_CRC);
+	}
+	if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_FRAME_ERROR_BIT)) {
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FRAME);
+	}
+
+	if (ftdmchan->iostats.s.rx_queue_len >= (0.8*ftdmchan->iostats.s.rx_queue_size)) {
+		ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded threshold (%d/%d)\n",
+					  								ftdmchan->iostats.s.rx_queue_len, ftdmchan->iostats.s.rx_queue_size);
+		
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
+	}
+	
+	if (ftdmchan->iostats.s.rx_queue_len >= ftdmchan->iostats.s.rx_queue_size) {
+		ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n",
+					  ftdmchan->iostats.s.rx_queue_len, ftdmchan->iostats.s.rx_queue_size);
+		
+		ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
+	}
+	return;
+}
+
 /**
  * \brief Reads data from a Wanpipe channel
  * \param ftdmchan Channel to read from
@@ -787,9 +830,11 @@ static FIO_READ_FUNCTION(wanpipe_read)
 		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 		ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read from sangoma device: %s (%d)\n", strerror(errno), rx_len);
 		return FTDM_FAIL;
-	} 
-
+	}
 
+	if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
+		wanpipe_read_stats(ftdmchan, &hdrframe);
+	}
 	return FTDM_SUCCESS;
 }
 
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index c5f3c4b821..6cbf589044 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -357,6 +357,7 @@ typedef struct {
 } ftdm_dtmf_debug_t;
 #endif
 
+
 typedef struct {
 	const char *file;
 	const char *func;
@@ -366,6 +367,33 @@ typedef struct {
 	ftdm_time_t time;
 } ftdm_channel_history_entry_t;
 
+typedef enum {
+	FTDM_IOSTATS_ERROR_CRC			= (1<<0),
+	FTDM_IOSTATS_ERROR_FRAME		= (1<<1),
+	FTDM_IOSTATS_ERROR_ABORT 		= (1<<2),
+	FTDM_IOSTATS_ERROR_FIFO 		= (1<<3),
+	FTDM_IOSTATS_ERROR_DMA			= (1<<4),
+	FTDM_IOSTATS_ERROR_QUEUE_THRES	= (1<<5), /* Queue reached high threshold */
+	FTDM_IOSTATS_ERROR_QUEUE_FULL	= (1<<6), /* Queue is full */
+} ftdm_iostats_error_type_t;
+
+typedef struct {
+	union {
+		struct {
+			uint32_t	errors;
+			uint16_t	flags;
+			uint8_t		rx_queue_size;	/* max queue size configured */
+			uint8_t		rx_queue_len;	/* Current number of elements in queue */
+		} rx;
+		struct {
+			uint32_t	errors;
+			uint16_t	flags;
+			uint8_t		tx_queue_size;	/* max queue size configured */
+			uint8_t		tx_queue_len;	/* Current number of elements in queue */
+		} tx;
+	} s;
+} ftdm_channel_iostats_t;
+
 /* 2^8 table size, one for each byte (sample) value */
 #define FTDM_GAINS_TABLE_SIZE 256
 struct ftdm_channel {
@@ -438,6 +466,7 @@ struct ftdm_channel {
 	int availability_rate;
 	void *user_private;
 	ftdm_timer_id_t hangup_timer;
+	ftdm_channel_iostats_t iostats;
 #ifdef FTDM_DEBUG_DTMF
 	ftdm_dtmf_debug_t dtmfdbg;
 #endif
@@ -632,10 +661,21 @@ FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan);
 
 #define ftdm_channel_lock(chan) ftdm_mutex_lock(chan->mutex)
 #define ftdm_channel_unlock(chan) ftdm_mutex_unlock(chan->mutex)
+
+#define ftdm_log_throttle(level, ...) \
+	time_current_throttle_log = ftdm_current_time_in_ms(); \
+	if (time_current_throttle_log - time_last_throttle_log > FTDM_THROTTLE_LOG_INTERVAL) {\
+		ftdm_log(level, __VA_ARGS__); \
+		time_last_throttle_log = time_current_throttle_log; \
+	} 
+
 #define ftdm_log_chan_ex(fchan, file, func, line, level, format, ...) ftdm_log(file, func, line, level, "[s%dc%d][%d:%d] " format, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, __VA_ARGS__)
 #define ftdm_log_chan(fchan, level, format, ...) ftdm_log(level, "[s%dc%d][%d:%d] " format, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, __VA_ARGS__)
 #define ftdm_log_chan_msg(fchan, level, msg) ftdm_log(level, "[s%dc%d][%d:%d] " msg, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id)
 
+#define ftdm_log_chan_throttle(fchan, level, format, ...) ftdm_log_throttle(level, "[s%dc%d][%d:%d] " format, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, __VA_ARGS__)
+#define ftdm_log_chan_msg_throttle(fchan, level, format, ...) ftdm_log_throttle(level, "[s%dc%d][%d:%d] " format, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, __VA_ARGS__)
+
 #define ftdm_span_lock(span) ftdm_mutex_lock(span->mutex)
 #define ftdm_span_unlock(span) ftdm_mutex_unlock(span->mutex)