From 54c7bbecef1802157df32d521c17c09a435e12dc Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 21 Apr 2009 23:06:05 +0000 Subject: [PATCH] _patches git-svn-id: http://svn.openzap.org/svn/openzap/trunk@718 a93c3328-9c30-0410-af19-c9cd2b2d52af --- libs/openzap/patches/oz.diff | 1110 ++++++++++++++++++++++++++++++++++ 1 file changed, 1110 insertions(+) create mode 100644 libs/openzap/patches/oz.diff diff --git a/libs/openzap/patches/oz.diff b/libs/openzap/patches/oz.diff new file mode 100644 index 0000000000..2b8fa60012 --- /dev/null +++ b/libs/openzap/patches/oz.diff @@ -0,0 +1,1110 @@ +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 + #include + +@@ -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 + #include +-#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 \