--- /dev/null
+Index: src/ozmod/ozmod_ss7_boost/sigboost.h
+===================================================================
+--- src/ozmod/ozmod_ss7_boost/sigboost.h (revision 717)
++++ src/ozmod/ozmod_ss7_boost/sigboost.h (working copy)
+@@ -1,5 +1,5 @@
+ /****************************************************************************
+- * sigboost.h $Revision: 1.5 $
++ * sigboost.h $Revision: 1.13 $
+ *
+ * Definitions for the sigboost interface.
+ *
+@@ -14,6 +14,8 @@
+ #ifndef _SIGBOOST_H_
+ #define _SIGBOOST_H_
+
++#define SIGBOOST_VERSION 100
++
+ #include <stdint.h>
+ #include <sys/time.h>
+
+@@ -48,16 +50,24 @@
+
+ enum e_sigboost_call_setup_ack_nack_cause_values
+ {
+- SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */
+- SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */
+- SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28,
+- /* probable elimination */
+- //SIGBOOST_CALL_SETUP_RESERVED = 0x00,
+- //SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10,
+- //SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11,
+- //SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17,
++ //SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 34, /* Q.850 value - don't use */
++ SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* non Q.850 value indicates local all ckt busy
++ causing sangoma_mgd to perform automatic call
++ gapping*/
++ SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 17, /* Q.850 value */
++ SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28, /* Q.850 value */
++ SIGBOOST_CALL_SETUP_CSUPID_DBL_USE = 200, /* unused Q.850 value */
+ };
+
++
++enum e_sigboost_huntgroup_values
++{
++ SIGBOOST_HUNTGRP_SEQ_ASC = 0x00, /* sequential with lowest available first */
++ SIGBOOST_HUNTGRP_SEQ_DESC = 0x01, /* sequential with highest available first */
++ SIGBOOST_HUNTGRP_RR_ASC = 0x02, /* round-robin with lowest available first */
++ SIGBOOST_HUNTGRP_RR_DESC = 0x03, /* round-robin with highest available first */
++};
++
+ #define MAX_DIALED_DIGITS 31
+
+ /* Next two defines are used to create the range of values for call_setup_id
+@@ -67,63 +77,73 @@
+ #define CORE_MAX_CHAN_PER_SPAN 30
+ #define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+ /* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+-#define SIZE_RDNIS 128
++#define SIZE_RDNIS 900
+
++
+ #pragma pack(1)
++
+ typedef struct
+ {
+- uint32_t event_id;
++ uint8_t capability;
++ uint8_t uil1p;
++}t_sigboost_bearer;
++
++typedef struct
++{
++ uint16_t version;
++ uint32_t event_id;
+ /* delete sequence numbers - SCTP does not need them */
+- uint32_t fseqno;
+- uint32_t bseqno;
+- uint16_t call_setup_id;
+- uint32_t trunk_group;
+- uint8_t span;
+- uint8_t chan;
+- struct timeval tv;
+- uint8_t called_number_digits_count;
+- char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+- uint8_t calling_number_digits_count; /* it's an array */
+- char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
++ uint32_t fseqno;
++ uint32_t bseqno;
++ uint16_t call_setup_id;
++ uint32_t trunk_group;
++ uint8_t span;
++ uint8_t chan;
++ struct timeval tv;
++ uint8_t called_number_digits_count;
++ char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
++ uint8_t calling_number_digits_count; /* it's an array */
++ char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ /* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+- uint8_t calling_number_screening_ind;
+- uint8_t calling_number_presentation;
+- char calling_name[MAX_DIALED_DIGITS + 1];
+- uint16_t redirection_string_size;
+- char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
+- /* redir string format:
+- * http://www.ss7box.com/wiki/tiki-index.php?page=Call+Redirection
+- * */
++ uint8_t calling_number_screening_ind;
++ uint8_t calling_number_presentation;
++ char calling_name[MAX_DIALED_DIGITS + 1];
++ t_sigboost_bearer bearer;
++ uint8_t hunt_group;
++ uint16_t isup_in_rdnis_size;
++ char isup_in_rdnis [SIZE_RDNIS]; /* it's a null terminated string */
+ } t_sigboost_callstart;
+
+-#define MIN_SIZE_CALLSTART_MSG (sizeof(t_sigboost_callstart) - SIZE_RDNIS)
++#define MIN_SIZE_CALLSTART_MSG sizeof(t_sigboost_callstart) - SIZE_RDNIS
+
+ typedef struct
+ {
+- uint32_t event_id;
++ uint16_t version;
++ uint32_t event_id;
+ /* delete sequence numbers - SCTP does not need them */
+- uint32_t fseqno;
+- uint32_t bseqno;
+- uint16_t call_setup_id;
+- uint32_t trunk_group;
+- uint8_t span;
+- uint8_t chan;
+- struct timeval tv;
+- uint8_t release_cause;
++ uint32_t fseqno;
++ uint32_t bseqno;
++ uint16_t call_setup_id;
++ uint32_t trunk_group;
++ uint8_t span;
++ uint8_t chan;
++ struct timeval tv;
++ uint8_t release_cause;
+ } t_sigboost_short;
+ #pragma pack()
+
+ static inline int boost_full_event(int event_id)
+ {
+- switch (event_id) {
+- case SIGBOOST_EVENT_CALL_START:
+- case SIGBOOST_EVENT_DIGIT_IN:
+- return 1;
+- default:
+- return 0;
+- }
++ switch (event_id) {
++ case SIGBOOST_EVENT_CALL_START:
++ case SIGBOOST_EVENT_DIGIT_IN:
++ return 1;
++ default:
++ return 0;
++ }
+
+- return 0;
++ return 0;
+ }
+
++
+ #endif
+Index: src/ozmod/ozmod_ss7_boost/ss7_boost_client.c
+===================================================================
+--- src/ozmod/ozmod_ss7_boost/ss7_boost_client.c (revision 717)
++++ src/ozmod/ozmod_ss7_boost/ss7_boost_client.c (working copy)
+@@ -73,7 +73,7 @@
+ {
+ if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+ return;
+- zap_log(file, func, line, ZAP_LOG_LEVEL_DEBUG, "%s EVENT: %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s]\n",
++ zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "%s EVENT: %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s]\n",
+ dir ? "TX":"RX",
+ ss7bc_event_id_name(event->event_id),
+ event->event_id,
+@@ -91,7 +91,7 @@
+ {
+ if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+ return;
+- zap_log(file, func, line, ZAP_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i \n",
++ zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i \n",
+ dir ? "TX":"RX",
+ priority ? "P":"N",
+ ss7bc_event_id_name(event->event_id),
+@@ -261,6 +261,10 @@
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
+ (struct sockaddr *) &mcon->local_addr, &fromlen);
+
++ if (mcon->event.version != SIGBOOST_VERSION) {
++ zap_log(ZAP_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
++ }
++
+ /* Must check for < 0 cannot rely on bytes > MIN_SIZE_... compiler issue */
+ if (bytes < 0) {
+ msg_ok=0;
+@@ -293,7 +297,7 @@
+ ss7bc_print_event_short(mcon, (ss7bc_short_event_t*)&mcon->event, 0, 0, file, func, line);
+ }
+
+-#if 1
++#if 0
+ /* NC: NOT USED ANY MORE */
+ if (mcon->rxseq_reset) {
+ //if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+@@ -310,15 +314,17 @@
+ mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+ mcon->rxseq++;
+
++#if 0
+ if (mcon->rxseq != mcon->event.fseqno) {
+ zap_log(ZAP_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+ return NULL;
+ }
++#endif
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+- zap_log(ZAP_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
++ zap_log(ZAP_LOG_CRIT, "NC - Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+@@ -332,6 +338,10 @@
+ int bytes = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
++
++ if (mcon->event.version != SIGBOOST_VERSION) {
++ zap_log(ZAP_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
++ }
+
+ if (bytes == sizeof(ss7bc_short_event_t)) {
+
+@@ -356,7 +366,7 @@
+ int __ss7bc_connection_write(ss7bc_connection_t *mcon, ss7bc_event_t *event, const char *file, const char *func, int line)
+ {
+ int err;
+- int event_size=sizeof(ss7bc_event_t);
++ int event_size=MIN_SIZE_CALLSTART_MSG+event->isup_in_rdnis_size;
+
+ if (!event || mcon->socket < 0 || !mcon->mutex) {
+ zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
+@@ -395,6 +405,7 @@
+ event->fseqno = mcon->txseq++;
+ }
+ event->bseqno = mcon->rxseq;
++ event->version = SIGBOOST_VERSION;
+ err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+
+ zap_mutex_unlock(mcon->mutex);
+@@ -432,6 +443,7 @@
+ gettimeofday(&event->tv, NULL);
+
+ zap_mutex_lock(mcon->mutex);
++ event->version = SIGBOOST_VERSION;
+ err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+ zap_mutex_unlock(mcon->mutex);
+
+Index: src/ozmod/ozmod_ss7_boost/ozmod_ss7_boost.c
+===================================================================
+--- src/ozmod/ozmod_ss7_boost/ozmod_ss7_boost.c (revision 717)
++++ src/ozmod/ozmod_ss7_boost/ozmod_ss7_boost.c (working copy)
+@@ -215,7 +215,11 @@
+
+ ss7bc_call_init(&event, caller_data->cid_num.digits, caller_data->ani.digits, r);
+ zap_set_string(event.calling_name, caller_data->cid_name);
+- zap_set_string(event.redirection_string, caller_data->rdnis.digits);
++ zap_set_string(event.isup_in_rdnis, caller_data->rdnis.digits);
++ if (strlen(caller_data->rdnis.digits)) {
++ event.isup_in_rdnis_size = strlen(caller_data->rdnis.digits)+1;
++ }
++
+ event.calling_number_screening_ind = caller_data->screen;
+ event.calling_number_presentation = caller_data->pres;
+
+@@ -483,7 +487,7 @@
+ }
+ zap_set_string(zchan->caller_data.ani.digits, (char *)event->calling_number_digits);
+ zap_set_string(zchan->caller_data.dnis.digits, (char *)event->called_number_digits);
+- zap_set_string(zchan->caller_data.rdnis.digits, (char *)event->redirection_string);
++ zap_set_string(zchan->caller_data.rdnis.digits, (char *)event->isup_in_rdnis);
+ zchan->caller_data.screen = event->calling_number_screening_ind;
+ zchan->caller_data.pres = event->calling_number_presentation;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+@@ -851,7 +855,7 @@
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_ss7_boost_data_t *ss7_boost_data = span->signal_data;
+ ss7bc_connection_t *mcon, *pcon;
+- uint32_t ms = 10, too_long = 20000;
++ uint32_t ms = 10; //, too_long = 20000;
+
+
+ ss7_boost_data->pcon = ss7_boost_data->mcon;
+@@ -942,6 +946,8 @@
+ pcon->hb_elapsed = 0;
+ }
+
++
++#if 0
+ if (pcon->hb_elapsed >= too_long) {
+ zap_log(ZAP_LOG_CRIT, "Lost Heartbeat!\n");
+ zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+@@ -953,6 +959,7 @@
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ }
++#endif
+
+ if (zap_running()) {
+ check_state(span);
+@@ -1094,7 +1101,7 @@
+ {
+ zap_ss7_boost_data_t *ss7_boost_data = NULL;
+ const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
+- int local_port = 5300, remote_port = 5300;
++ int local_port = 53000, remote_port = 53000;
+ char *var, *val;
+ int *intval;
+
+Index: src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+===================================================================
+--- src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (revision 717)
++++ src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (working copy)
+@@ -38,7 +38,7 @@
+ #include "openzap.h"
+ #include <poll.h>
+ #include <sys/socket.h>
+-#include "wanpipe_tdm_api_iface.h"
++#include "libsangoma.h"
+
+ typedef enum {
+ WP_RINGING = (1 << 0)
+@@ -57,196 +57,28 @@
+ ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
+ ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
+
+-#define WP_INVALID_SOCKET -1
+-/* on windows right now, there is no way to specify if we want to read events here or not, we allways get them here */
+-/* we need some what to select if we are reading regular tdm msgs or events */
+-/* need to either have 2 functions, 1 for events, 1 for regural read, or a flag on this function to choose */
+-/* 2 functions preferred. Need implementation for the event function for both nix and windows that is threadsafe */
+-static __inline__ int tdmv_api_readmsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen)
+-{
+- /* What do we need to do here to avoid having to do all */
+- /* the memcpy's on windows and still maintain api compat with nix */
+- uint32_t rx_len=0;
+-#if defined(__WINDOWS__)
+- static RX_DATA_STRUCT rx_data;
+- api_header_t *pri;
+- wp_tdm_api_rx_hdr_t *tdm_api_rx_hdr;
+- wp_tdm_api_rx_hdr_t *user_buf = (wp_tdm_api_rx_hdr_t*)hdrbuf;
+- DWORD ln;
++#define WP_INVALID_SOCKET -1
+
+- if (hdrlen != sizeof(wp_tdm_api_rx_hdr_t)){
+- return -1;
+- }
+-
+- if (!DeviceIoControl(
+- fd,
+- IoctlReadCommand,
+- (LPVOID)NULL,
+- 0L,
+- (LPVOID)&rx_data,
+- sizeof(RX_DATA_STRUCT),
+- (LPDWORD)(&ln),
+- (LPOVERLAPPED)NULL
+- )){
+- return -1;
+- }
+-
+- pri = &rx_data.api_header;
+- tdm_api_rx_hdr = (wp_tdm_api_rx_hdr_t*)rx_data.data;
+-
+- user_buf->wp_tdm_api_event_type = pri->operation_status;
+-
+- switch(pri->operation_status)
+- {
+- case SANG_STATUS_RX_DATA_AVAILABLE:
+- if (pri->data_length > datalen){
+- break;
+- }
+- memcpy(databuf, rx_data.data, pri->data_length);
+- rx_len = pri->data_length;
+- break;
+-
+- default:
+- break;
+- }
+-
+-#else
+- struct msghdr msg;
+- struct iovec iov[2];
+-
+- memset(&msg,0,sizeof(struct msghdr));
+-
+- iov[0].iov_len=hdrlen;
+- iov[0].iov_base=hdrbuf;
+-
+- iov[1].iov_len=datalen;
+- iov[1].iov_base=databuf;
+-
+- msg.msg_iovlen=2;
+- msg.msg_iov=iov;
+-
+- rx_len = read(fd,&msg,datalen+hdrlen);
+-
+- if (rx_len <= sizeof(wp_tdm_api_rx_hdr_t)){
+- return -EINVAL;
+- }
+-
+- rx_len-=sizeof(wp_tdm_api_rx_hdr_t);
+-#endif
+- return rx_len;
+-}
+-
+-static __inline__ int tdmv_api_writemsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen)
+-{
+- /* What do we need to do here to avoid having to do all */
+- /* the memcpy's on windows and still maintain api compat with nix */
+- int bsent = 0;
+-#if defined(__WINDOWS__)
+- static TX_DATA_STRUCT local_tx_data;
+- api_header_t *pri;
+- DWORD ln;
+-
+- /* Are these really not needed or used??? What about for nix?? */
+- (void)hdrbuf;
+- (void)hdrlen;
+-
+- pri = &local_tx_data.api_header;
+-
+- pri->data_length = datalen;
+- memcpy(local_tx_data.data, databuf, pri->data_length);
+-
+- if (!DeviceIoControl(
+- fd,
+- IoctlWriteCommand,
+- (LPVOID)&local_tx_data,
+- (ULONG)sizeof(TX_DATA_STRUCT),
+- (LPVOID)&local_tx_data,
+- sizeof(TX_DATA_STRUCT),
+- (LPDWORD)(&ln),
+- (LPOVERLAPPED)NULL
+- )){
+- return -1;
+- }
+-
+- if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
+- bsent = datalen;
+- }
+-#else
+- struct msghdr msg;
+- struct iovec iov[2];
+-
+- memset(&msg,0,sizeof(struct msghdr));
+-
+- iov[0].iov_len = hdrlen;
+- iov[0].iov_base = hdrbuf;
+-
+- iov[1].iov_len = datalen;
+- iov[1].iov_base = databuf;
+-
+- msg.msg_iovlen = 2;
+- msg.msg_iov = iov;
+-
+- bsent = write(fd, &msg, datalen + hdrlen);
+- if (bsent > 0){
+- bsent -= sizeof(wp_tdm_api_tx_hdr_t);
+- }
+-#endif
+- return bsent;
+-}
+-
+ /* a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog */
+ /* so we can have one analong handler thread that will deal with all the idle analog channels for events */
+ /* the alternative would be for the driver to provide one socket for all of the oob events for all analog channels */
+ static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
+ {
+-#if defined(__WINDOWS__)
+- DWORD ln;
+- API_POLL_STRUCT api_poll;
+-
+- memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
+
+- api_poll.user_flags_bitmap = *flags;
+- api_poll.timeout = timeout;
++#ifdef LIBSANGOMA_VERSION
++ int err;
++ sangoma_wait_obj_t sangoma_wait_obj;
+
+- if (!DeviceIoControl(
+- fd,
+- IoctlApiPoll,
+- (LPVOID)NULL,
+- 0L,
+- (LPVOID)&api_poll,
+- sizeof(API_POLL_STRUCT),
+- (LPDWORD)(&ln),
+- (LPOVERLAPPED)NULL)) {
+- return -1;
+- }
++ sangoma_init_wait_obj(&sangoma_wait_obj, fd, 1, 1, *flags, SANGOMA_WAIT_OBJ);
+
+- *flags = 0;
+-
+- switch(api_poll.operation_status)
+- {
+- case SANG_STATUS_RX_DATA_AVAILABLE:
+- break;
+-
+- case SANG_STATUS_RX_DATA_TIMEOUT:
+- return 0;
+-
+- default:
+- return -1;
+- }
+-
+- if (api_poll.poll_events_bitmap == 0){
+- return -1;
++ err=sangoma_socket_waitfor_many(&sangoma_wait_obj,1 , timeout);
++ if (err > 0) {
++ *flags=sangoma_wait_obj.flags_out;
+ }
++ return err;
+
+- if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
+- return 0;
+- }
+-
+- *flags = api_poll.poll_events_bitmap;
+-
+- return 1;
+ #else
+- struct pollfd pfds[1];
++ struct pollfd pfds[1];
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+@@ -265,87 +97,18 @@
+
+ return res;
+ #endif
++
+ }
+
+-#define FNAME_LEN 128
+ static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
+ {
+- char fname[FNAME_LEN];
+- sng_fd_t fd = WP_INVALID_SOCKET;
+-#if defined(__WINDOWS__)
+- DWORD ln;
+- wan_udp_hdr_t wan_udp;
+-
+- /* NOTE: under Windows Interfaces are zero based but 'chan' is 1 based. */
+- /* Subtract 1 from 'chan'. */
+- _snprintf(fname , FNAME_LEN, "\\\\.\\WANPIPE%d_IF%d", span, chan - 1);
+-
+- fd = CreateFile( fname,
+- GENERIC_READ | GENERIC_WRITE,
+- FILE_SHARE_READ | FILE_SHARE_WRITE,
+- (LPSECURITY_ATTRIBUTES)NULL,
+- OPEN_EXISTING,
+- FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
+- (HANDLE)NULL
+- );
+-
+- /* make sure that we are the only ones who have this chan open */
+- /* is this a threadsafe way to make sure that we are ok and will */
+- /* never return a valid handle to more than one thread for the same channel? */
+-
+- wan_udp.wan_udphdr_command = GET_OPEN_HANDLES_COUNTER;
+- wan_udp.wan_udphdr_data_len = 0;
+-
+- DeviceIoControl(
+- fd,
+- IoctlManagementCommand,
+- (LPVOID)&wan_udp,
+- sizeof(wan_udp_hdr_t),
+- (LPVOID)&wan_udp,
+- sizeof(wan_udp_hdr_t),
+- (LPDWORD)(&ln),
+- (LPOVERLAPPED)NULL
+- );
+-
+- if ((wan_udp.wan_udphdr_return_code) || (*(int*)&wan_udp.wan_udphdr_data[0] != 1)){
+- /* somone already has this channel, or somthing else is not right. */
+- tdmv_api_close_socket(&fd);
+- }
+-
+-#else
+- /* Does this fail if another thread already has this chan open? */
+- /* if not, we need to add some code to make sure it does */
+- snprintf(fname, FNAME_LEN, "/dev/wptdm_s%dc%d",span,chan);
+-
+- fd = open(fname, O_RDWR);
+-
+- if (fd < 0) {
+- fd = WP_INVALID_SOCKET;
+- }
+-
+-#endif
+- return fd;
++ return sangoma_open_tdmapi_span_chan(span, chan);
+ }
+
+
+
+ static zap_io_interface_t wanpipe_interface;
+
+-static zap_status_t wp_tdm_cmd_exec(zap_channel_t *zchan, wanpipe_tdm_api_t *tdm_api)
+-{
+- int err;
+-
+- /* I'm told the 2nd arg is ignored but i send it as the cmd anyway for good measure */
+- err = ioctl(zchan->sockfd, tdm_api->wp_tdm_cmd.cmd, &tdm_api->wp_tdm_cmd);
+-
+- if (err) {
+- snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+- return ZAP_FAIL;
+- }
+-
+- return ZAP_SUCCESS;
+-}
+-
+ static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+ {
+ unsigned char swapped_bits = 0x0;
+@@ -379,43 +142,17 @@
+
+ if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+ wanpipe_tdm_api_t tdm_api;
++ memset(&tdm_api,0,sizeof(tdm_api));
+ zap_log(ZAP_LOG_INFO, "configuring device s%dc%d as OpenZAP device %d:%d fd:%d\n", spanno, x, chan->span_id, chan->chan_id, sockfd);
+ chan->physical_span_id = spanno;
+ chan->physical_chan_id = x;
+ chan->rate = 8000;
+
+- if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+-
+-
+-#if 1
+- if (type == ZAP_CHAN_TYPE_FXO) {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- wp_tdm_cmd_exec(chan, &tdm_api);
+- }
+-#endif
+-
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING_DETECT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- wp_tdm_cmd_exec(chan, &tdm_api);
+-#if 1
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING_TRIP_DETECT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- wp_tdm_cmd_exec(chan, &tdm_api);
+-#endif
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RXHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- wp_tdm_cmd_exec(chan, &tdm_api);
+-
+- }
+-
+ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_B) {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_HW_CODING;
+- wp_tdm_cmd_exec(chan, &tdm_api);
++ int err;
++
++ /* FIXME: Handle Error Conditino Check for return code */
++ err= sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+ if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+ } else {
+@@ -423,10 +160,24 @@
+ }
+ }
+
++#if 0
++ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
++ /* Enable FLASH/Wink Events */
++ int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
++ if (err == 0) {
++ zap_log(ZAP_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
++ } else {
++ zap_log(ZAP_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
++ }
++ }
++#endif
++
+ if (type == ZAP_CHAN_TYPE_CAS) {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_WRITE_RBS_BITS;
+- tdm_api.wp_tdm_cmd.rbs_tx_bits = wanpipe_swap_bits(cas_bits);
+- wp_tdm_cmd_exec(chan, &tdm_api);
++#ifdef LIBSANGOMA_VERSION
++ sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id,wanpipe_swap_bits(cas_bits));
++#else
++ sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,wanpipe_swap_bits(cas_bits));
++#endif
+ }
+
+ if (!zap_strlen_zero(name)) {
+@@ -550,18 +301,31 @@
+ static ZIO_OPEN_FUNCTION(wanpipe_open)
+ {
+
++ int err;
+ wanpipe_tdm_api_t tdm_api;
+
++ memset(&tdm_api,0,sizeof(tdm_api));
++
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
+ zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
+ } else {
+ zchan->effective_codec = zchan->native_codec;
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_CODEC;
+- tdm_api.wp_tdm_cmd.tdm_codec = 0;
+- wp_tdm_cmd_exec(zchan, &tdm_api);
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_USR_PERIOD;
+- tdm_api.wp_tdm_cmd.usr_period = wp_globals.codec_ms;
+- wp_tdm_cmd_exec(zchan, &tdm_api);
++
++ sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, wp_globals.codec_ms);
++
++ err=sangoma_tdm_get_hw_dtmf(zchan->sockfd, &tdm_api);
++ if (err > 0) {
++ err=sangoma_tdm_enable_dtmf_events(zchan->sockfd, &tdm_api);
++ if (err == 0) {
++ //zap_log(ZAP_LOG_DEBUG, "Enabling HW DTMF FEATURE\n");
++ zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT);
++ } else {
++ //zap_log(ZAP_LOG_DEBUG, "NO HW DTMF FEATURE\n");
++ }
++ } else {
++ //zap_log(ZAP_LOG_DEBUG, "NO HW DTMF FEATURE\n");
++ }
++
+ zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
+ zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms;
+ zchan->packet_len = zchan->native_interval * 8;
+@@ -585,10 +349,8 @@
+ switch(command) {
+ case ZAP_COMMAND_OFFHOOK:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_OFFHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
++ err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
+ return ZAP_FAIL;
+ }
+@@ -597,10 +359,8 @@
+ break;
+ case ZAP_COMMAND_ONHOOK:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
++ err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
+ return ZAP_FAIL;
+ }
+@@ -609,9 +369,8 @@
+ break;
+ case ZAP_COMMAND_GENERATE_RING_ON:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_START;
+- if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
++ err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+ return ZAP_FAIL;
+ }
+@@ -622,9 +381,8 @@
+ break;
+ case ZAP_COMMAND_GENERATE_RING_OFF:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_OFFHOOK;
+- if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
++ err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
+ return ZAP_FAIL;
+ }
+@@ -634,27 +392,26 @@
+ break;
+ case ZAP_COMMAND_GET_INTERVAL:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_USR_PERIOD;
+-
+- if (!(err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
+- ZAP_COMMAND_OBJ_INT = tdm_api.wp_tdm_cmd.usr_period;
++ err=sangoma_tdm_get_usr_period(zchan->sockfd, &tdm_api);
++ if (err > 0 ) {
++ ZAP_COMMAND_OBJ_INT = err;
++ err=0;
+ }
+-
+ }
+ break;
+ case ZAP_COMMAND_SET_INTERVAL:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_USR_PERIOD;
+- tdm_api.wp_tdm_cmd.usr_period = ZAP_COMMAND_OBJ_INT;
+- err = wp_tdm_cmd_exec(zchan, &tdm_api);
++ err=sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, ZAP_COMMAND_OBJ_INT);
+ zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+ }
+ break;
+ case ZAP_COMMAND_SET_CAS_BITS:
+ {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_WRITE_RBS_BITS;
+- tdm_api.wp_tdm_cmd.rbs_tx_bits = wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT);
+- err = wp_tdm_cmd_exec(zchan, &tdm_api);
++#ifdef LIBSANGOMA_VERSION
++ err=sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api,zchan->physical_chan_id,wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
++#else
++ err=sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api,wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
++#endif
+ }
+ break;
+ case ZAP_COMMAND_GET_CAS_BITS:
+@@ -683,7 +440,7 @@
+
+ memset(&hdrframe, 0, sizeof(hdrframe));
+
+- rx_len = tdmv_api_readmsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen);
++ rx_len = sangoma_readmsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen,0);
+
+ *datalen = rx_len;
+
+@@ -702,7 +459,7 @@
+
+ /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
+ memset(&hdrframe, 0, sizeof(hdrframe));
+- bsent = tdmv_api_writemsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen));
++ bsent = sangoma_writemsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
+
+ /* should we be checking if bsent == *datalen here? */
+ if (bsent > 0) {
+@@ -759,19 +516,29 @@
+ return ZAP_SUCCESS;
+ }
+
+-#ifndef WIN32
+ ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+ {
++#ifdef LIBSANGOMA_VERSION
++ sangoma_wait_obj_t pfds[ZAP_MAX_CHANNELS_SPAN];
++#else
+ struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
++#endif
++
+ uint32_t i, j = 0, k = 0, l = 0;
++ int objects=0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ zap_channel_t *zchan = span->channels[i];
++
++#ifdef LIBSANGOMA_VERSION
++ sangoma_init_wait_obj(&pfds[j], zchan->sockfd , 1, 1, POLLPRI, SANGOMA_WAIT_OBJ);
++#else
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+-
++#endif
++ objects++;
+ /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+@@ -789,20 +556,16 @@
+ int err;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ if (zap_test_pflag(zchan, WP_RINGING)) {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_OFFHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_DISABLE;
+- if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
++ err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
+ return ZAP_FAIL;
+ }
+ zap_clear_pflag_locked(zchan, WP_RINGING);
+ zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_off_ms;
+ } else {
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_START;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
++ err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+ return ZAP_FAIL;
+ }
+@@ -815,9 +578,12 @@
+ if (l) {
+ ms = l;
+ }
++#ifdef LIBSANGOMA_VERSION
++ r = sangoma_socket_waitfor_many(pfds,objects,ms);
++#else
++ r = poll(pfds, j, ms);
++#endif
+
+- r = poll(pfds, j, ms);
+-
+ if (r == 0) {
+ return l ? ZAP_SUCCESS : ZAP_TIMEOUT;
+ } else if (r < 0) {
+@@ -828,7 +594,11 @@
+ for(i = 1; i <= span->chan_count; i++) {
+ zap_channel_t *zchan = span->channels[i];
+
++#ifdef LIBSANGOMA_VERSION
++ if (pfds[i-1].flags_out & POLLPRI) {
++#else
+ if (pfds[i-1].revents & POLLPRI) {
++#endif
+ zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+ zchan->last_event_time = zap_current_time_in_ms();
+ k++;
+@@ -836,15 +606,43 @@
+ }
+
+
+-
+ return k ? ZAP_SUCCESS : ZAP_FAIL;
+ }
+
++
++static ZIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
++{
++ wanpipe_tdm_api_t tdm_api;
++ unsigned int alarms = 0;
++ int err;
++
++ memset(&tdm_api,0,sizeof(tdm_api));
++
++#ifdef LIBSANGOMA_VERSION
++ if ((err = sangoma_tdm_get_fe_alarms(zchan->sockfd, &tdm_api, &alarms))) {
++ snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
++ snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
++ return ZAP_FAIL;
++ }
++#else
++ if ((err = sangoma_tdm_get_fe_alarms(zchan->sockfd, &tdm_api)) < 0){
++ snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
++ snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
++ return ZAP_FAIL;
++ }
++ alarms = tdm_api.wp_tdm_cmd.fe_alarms;
+ #endif
+
++
++ zchan->alarm_flags = alarms ? ZAP_ALARM_RED : ZAP_ALARM_NONE;
++
++ return ZAP_SUCCESS;
++}
++
++
+ ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+ {
+- uint32_t i;
++ uint32_t i,err;
+ zap_oob_event_t event_id;
+
+ for(i = 1; i <= span->chan_count; i++) {
+@@ -869,29 +667,43 @@
+ event_id = ZAP_OOB_ONHOOK;
+
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
++ zap_channel_t *zchan = span->channels[i];
+ wanpipe_tdm_api_t tdm_api;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- wp_tdm_cmd_exec(span->channels[i], &tdm_api);
++
++ sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+ }
+ goto event;
+ }
+ }
+- }
++ }
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+ wanpipe_tdm_api_t tdm_api;
++ zap_channel_t *zchan = span->channels[i];
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_READ_EVENT;
+- if (wp_tdm_cmd_exec(span->channels[i], &tdm_api) != ZAP_SUCCESS) {
++ err=sangoma_tdm_read_event(zchan->sockfd,&tdm_api);
++ if (err != ZAP_SUCCESS) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
++
++ case WP_TDMAPI_EVENT_LINK_STATUS:
++ {
++ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
++ case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
++ event_id = ZAP_OOB_ALARM_CLEAR;
++ break;
++ default:
++ event_id = ZAP_OOB_ALARM_TRAP;
++ break;
++ };
++ }
++ break;
++
+ case WP_TDMAPI_EVENT_RXHOOK:
+ {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS) {
+@@ -918,11 +730,9 @@
+ continue;
+ } else {
+ int err;
+-
+- tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
+- tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
+- if ((err = wp_tdm_cmd_exec(span->channels[i], &tdm_api))) {
++ zap_channel_t *zchan = span->channels[i];
++ err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
++ if (err) {
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
+ return ZAP_FAIL;
+ }
+@@ -948,6 +758,17 @@
+ span->channels[i]->cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+ }
+ break;
++ case WP_TDMAPI_EVENT_DTMF:
++ {
++ char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
++ event_id = ZAP_OOB_NOOP;
++
++ //zap_log(ZAP_LOG_DEBUG, "%d:%d queue hardware dtmf %s\n", zchan->span_id, zchan->chan_id, tmp_dtmf);
++ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
++ zap_channel_queue_dtmf(zchan, tmp_dtmf);
++ }
++ }
++ break;
+ default:
+ {
+ zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+@@ -1005,6 +826,7 @@
+ #endif
+ wanpipe_interface.next_event = wanpipe_next_event;
+ wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
++ wanpipe_interface.get_alarms = wanpipe_get_alarms;
+ *zio = &wanpipe_interface;
+
+ return ZAP_SUCCESS;
+Index: configure.ac
+===================================================================
+--- configure.ac (revision 717)
++++ configure.ac (working copy)
+@@ -155,6 +155,9 @@
+ [AS_HELP_STRING([--with-libpri], [Install ozmod_libpri])], [enable_libpri="yes"], [enable_libpri="no"])
+ AC_SUBST(enable_libpri)
+
++AC_CHECK_LIB([sangoma], [sangoma_span_chan_toif], [have_libsangoma="yes"])
++AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
++
+ AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
+
+ COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS"
+Index: Makefile.am
+===================================================================
+--- Makefile.am (revision 717)
++++ Makefile.am (working copy)
+@@ -154,10 +154,12 @@
+ ozmod_skel_la_LDFLAGS = -module -avoid-version
+ ozmod_skel_la_LIBADD = $(MYLIB)
+
++if LIBSANGOMA
+ ozmod_wanpipe_la_SOURCES = $(SRC)/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+-ozmod_wanpipe_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+-ozmod_wanpipe_la_LDFLAGS = -module -avoid-version
++ozmod_wanpipe_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe
++ozmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma
+ ozmod_wanpipe_la_LIBADD = $(MYLIB)
++endif
+
+ ozmod_isdn_la_SOURCES = \
+ $(SRC)/isdn/EuroISDNStateNT.c \