diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index d14013ab9b..33e287fa79 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -161,7 +161,7 @@ testanalog_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) # # ftmod modules # -mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_analog.la ftmod_analog_em.la #ftmod_isdn.la +mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_analog.la ftmod_analog_em.la if HAVE_SCTP @@ -209,32 +209,13 @@ ftmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma ftmod_wanpipe_la_LIBADD = $(MYLIB) endif -#ftmod_isdn_la_SOURCES = \ -#$(SRC)/isdn/EuroISDNStateNT.c \ -#$(SRC)/isdn/EuroISDNStateTE.c \ -#$(SRC)/isdn/mfifo.c \ -#$(SRC)/isdn/Q921.c \ -#$(SRC)/isdn/Q931api.c \ -#$(SRC)/isdn/Q931.c \ -#$(SRC)/isdn/Q931ie.c \ -#$(SRC)/isdn/Q931mes.c \ -#$(SRC)/isdn/Q931StateNT.c \ -#$(SRC)/isdn/Q931StateTE.c \ -#$(SRC)/isdn/nationalmes.c \ -#$(SRC)/isdn/nationalStateNT.c \ -#$(SRC)/isdn/nationalStateTE.c \ -#$(SRC)/isdn/DMSmes.c \ -#$(SRC)/isdn/DMSStateNT.c \ -#$(SRC)/isdn/DMSStateTE.c \ -#$(SRC)/isdn/5ESSmes.c \ -#$(SRC)/isdn/5ESSStateNT.c \ -#$(SRC)/isdn/5ESSStateTE.c \ -#$(SRC)/isdn/Q932mes.c \ -#$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c - -#ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE -#ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version -#ftmod_isdn_la_LIBADD = $(MYLIB) +if HAVE_LIBISDN +mod_LTLIBRARIES += ftmod_isdn.la +ftmod_isdn_la_SOURCES = $(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c +ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE $(LIBISDN_CPPFLAGS) $(PCAP_CPPFLAGS) +ftmod_isdn_la_LDFLAGS = -shared -module -avoid-version $(LIBISDN_LDFLAGS) $(PCAP_LDFLAGS) +ftmod_isdn_la_LIBADD = $(MYLIB) $(LIBISDN_LIBS) $(PCAP_LIBS) +endif ftmod_analog_la_SOURCES = $(SRC)/ftmod/ftmod_analog/ftmod_analog.c ftmod_analog_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) diff --git a/libs/freetdm/build/libpcap.m4 b/libs/freetdm/build/libpcap.m4 index c20d345ca6..ea7581e69b 100644 --- a/libs/freetdm/build/libpcap.m4 +++ b/libs/freetdm/build/libpcap.m4 @@ -2,6 +2,10 @@ dnl libpcap.m4--PCAP libraries and includes dnl Derrick Brashear dnl from KTH krb and Arla dnl $Id: libpcap.m4,v 1.4 2006/01/20 20:21:09 snsimon Exp $ +dnl 2010/10/31 (stkn): +dnl rename: PCAP_INC_FLAGS -> PCAP_CPPFLAGS +dnl rename: PCAP_LIB_FLAGS -> PCAP_LDFLAGS (-L flags only) +dnl add: PCAP_LIBS (libs only) AC_DEFUN([PCAP_INC_WHERE1], [ ac_cv_found_pcap_inc=no @@ -129,12 +133,14 @@ AC_ARG_WITH(pcap-include, AC_MSG_RESULT(yes) PCAP_INC_DIR=$ac_cv_pcap_where_inc PCAP_LIB_DIR=$ac_cv_pcap_where_lib - PCAP_INC_FLAGS="-I${PCAP_INC_DIR}" - PCAP_LIB_FLAGS="-L${PCAP_LIB_DIR} -lpcap" + PCAP_CPPFLAGS="-I${PCAP_INC_DIR}" + PCAP_LDFLAGS="-L${PCAP_LIB_DIR}" + PCAP_LIBS="-lpcap" AC_SUBST(PCAP_INC_DIR) AC_SUBST(PCAP_LIB_DIR) - AC_SUBST(PCAP_INC_FLAGS) - AC_SUBST(PCAP_LIB_FLAGS) + AC_SUBST(PCAP_CPPFLAGS) + AC_SUBST(PCAP_LDFLAGS) + AC_SUBST(PCAP_LIBS) AC_DEFINE([HAVE_LIBPCAP],[1],[libpcap]) else ac_cv_found_pcap=no diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 18f83d8f1d..457e5259e4 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -12,6 +12,7 @@ AM_INIT_AUTOMAKE(libfreetdm,0.1) AC_PROG_CC AC_PROG_MAKE_SET AM_PROG_CC_C_O +PKG_PROG_PKG_CONFIG AC_PREFIX_DEFAULT(/usr/local/freetdm) # AC_PREFIX_DEFAULT does not get expanded until too late so we need to do this to use prefix in this script @@ -217,8 +218,63 @@ if test "${have_sng_ss7}" = "yes"; then fi fi +## +# libisdn +# +HAVE_LIBISDN="no" +AC_ARG_WITH([libisdn], + [AS_HELP_STRING([--with-libisdn], [Install ftmod_isdn (libisdn stack)])], + [case "${withval}" in + no) with_libisdn="no" ;; + *) with_libisdn="yes" ;; + esac + ], + [with_libisdn="no"] +) +if test "${with_libisdn}" != "no" +then + AC_MSG_RESULT([${as_nl}<<>> ftmod_isdn (libisdn stack)]) + PKG_CHECK_MODULES([libisdn], + [libisdn >= 0.0.1], + [AC_MSG_CHECKING([libisdn version]) + LIBISDN_VERSION="`${PKG_CONFIG} --modversion libisdn`" + if test -z "${LIBISDN_VERSION}"; then + AC_MSG_ERROR([Failed to retrieve libisdn version]) + fi + AC_MSG_RESULT([${LIBISDN_VERSION}]) + + # check features + AC_MSG_CHECKING([for new experimental API]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [#include + #if !LIBISDN_FEATURE(API2) + #error "libisdn API v2 not available" + #endif + ], + [;] + )], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])] + ) + + HAVE_LIBISDN="yes" + AC_DEFINE([HAVE_LIBISDN], [1], [libisdn support]) + AC_SUBST([LIBISDN_CFLAGS], [${libisdn_CFLAGS}]) + AC_SUBST([LIBISDN_CPPFLAGS],[${libisdn_CPPFLAGS}]) + AC_SUBST([LIBISDN_LDFLAGS], [${libisdn_LDFLAGS}]) + AC_SUBST([LIBISDN_LIBS], [${libisdn_LIBS}]) + AC_SUBST([LIBISDN_VERSION]) + ], + [AC_MSG_ERROR([Need libisdn-0.0.1 or higher])] + ) +fi +AM_CONDITIONAL([HAVE_LIBISDN], [test "${HAVE_LIBISDN}" = "yes"]) + COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS" AC_SUBST(COMP_VENDOR_CFLAGS) + +AC_MSG_RESULT([${as_nl}<<>> Creating output files]) AC_CONFIG_FILES([Makefile freetdm.pc mod_freetdm/Makefile]) diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c index 3715e9844c..7a2810757c 100644 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c @@ -1,23 +1,23 @@ /* * Copyright (c) 2007, Anthony Minessale II * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * * Neither the name of the original author; nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * - * + * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -30,267 +30,268 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * Workaround for missing u_int / u_short types on solaris - */ -#if defined(HAVE_LIBPCAP) && defined(__SunOS) -#define __EXTENSIONS__ +#ifdef HAVE_CONFIG_H +#include "config.h" #endif +#include +#include +#include -#include "private/ftdm_core.h" -#include "Q931.h" -#include "Q921.h" #ifdef WIN32 #include #else #include #endif -#include "ftdm_isdn.h" +#include "ftmod_isdn.h" #define LINE "--------------------------------------------------------------------------------" -//#define IODEBUG /* helper macros */ #define FTDM_SPAN_IS_BRI(x) ((x)->trunk_type == FTDM_TRUNK_BRI || (x)->trunk_type == FTDM_TRUNK_BRI_PTMP) #define FTDM_SPAN_IS_NT(x) (((ftdm_isdn_data_t *)(x)->signal_data)->mode == Q921_NT) +#define DEFAULT_NATIONAL_PREFIX "0" +#define DEFAULT_INTERNATIONAL_PREFIX "00" -#ifdef HAVE_LIBPCAP -/*-------------------------------------------------------------------------*/ -/*Q931ToPcap functions*/ +/***************************************************************************************** + * PCAP + * Based on Helmut Kuper's () implementation, + * but using a different approach (needs a recent libpcap + wireshark) + *****************************************************************************************/ +#ifdef HAVE_PCAP +#include /* htons() */ #include -#endif -#define SNAPLEN 1522 -#define MAX_ETHER_PAYLOAD_SIZE 1500 -#define MIN_ETHER_PAYLOAD_SIZE 42 -#define SIZE_ETHERNET 18 -#define VLANID_OFFSET 15 -#define SIZE_IP 20 -#define SIZE_TCP 20 -#define SIZE_TPKT 4 -#define SIZE_ETHERNET_CRC 4 -#define OVERHEAD SIZE_ETHERNET+SIZE_IP+SIZE_TCP+SIZE_TPKT -#define MAX_Q931_SIZE MAX_ETHER_PAYLOAD_SIZE-SIZE_IP-SIZE_TCP-SIZE_TPKT -#define TPKT_SIZE_OFFSET SIZE_ETHERNET+SIZE_IP+SIZE_TCP+2 -#define IP_SIZE_OFFSET SIZE_ETHERNET+2 -#define TCP_SEQ_OFFSET SIZE_ETHERNET+SIZE_IP+4 +#define PCAP_SNAPLEN 1500 -#ifdef HAVE_LIBPCAP -/*Some globals*/ -unsigned long pcapfilesize = 0; -unsigned long tcp_next_seq_no_send = 0; -unsigned long tcp_next_seq_no_rec = 0; -pcap_dumper_t *pcapfile = NULL; -struct pcap_pkthdr pcaphdr; -pcap_t *pcaphandle = NULL; -char *pcapfn = NULL; -int do_q931ToPcap= 0; +struct pcap_context { + pcap_dumper_t *dump; /*!< pcap file handle */ + pcap_t *handle; /*!< pcap lib context */ + char *filename; /*!< capture file name */ +}; -/*Predefined Ethernet Frame with Q931-over-IP encapsulated - From remote TDM host to FreeSWITCH*/ -L3UCHAR recFrame[SNAPLEN]= { - /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/ - 2,0,1,0xAA,0xAA,0xAA,2,0,1,0xBB,0xBB,0xBB,0x81,0,0xE0,0,0x08,0, - /*IPv4 Header (minimal size; no options)*/ - 0x45,0,0,44,0,0,0,0,64,6,0,0,2,2,2,2,1,1,1,1, - /*TCP-Header*/ - 0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0, - /*TPKT-Header RFC 1006*/ - 3,0,0,0 - }; - -/*Predefined Ethernet Frame with Q931-over-IP encapsulated - Frome FreeSWITCH to remote TDM host*/ -L3UCHAR sendFrame[SNAPLEN]= { - /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/ - 2,0,1,0xBB,0xBB,0xBB,2,0,1,0xAA,0xAA,0xAA,0x81,0,0xE0,0,0x08,0, - /*IPv4 Header (minimal size; no options)*/ - 0x45,0,0,44,0,0,0,0,64,6,0,0,1,1,1,1,2,2,2,2, - /*TCP-Header*/ - 0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0, - /*TPKT-Header RFC 1006*/ - 3,0,0,0 - }; - -/** - * \brief Opens a pcap file for capture - * \return Success or failure - */ -static ftdm_status_t openPcapFile(void) +static inline ftdm_status_t isdn_pcap_is_open(struct ftdm_isdn_data *isdn) { - if(!pcaphandle) - { - pcaphandle = pcap_open_dead(DLT_EN10MB, SNAPLEN); - if (!pcaphandle) - { - ftdm_log(FTDM_LOG_ERROR, "Can't open pcap session: (%s)\n", pcap_geterr(pcaphandle)); - return FTDM_FAIL; - } - } - - if(!pcapfile){ - /* Open the dump file */ - if(!(pcapfile=pcap_dump_open(pcaphandle, pcapfn))){ - ftdm_log(FTDM_LOG_ERROR, "Error opening output file (%s)\n", pcap_geterr(pcaphandle)); - return FTDM_FAIL; - } - } - else{ - ftdm_log(FTDM_LOG_WARNING, "Pcap file is already open!\n"); - return FTDM_FAIL; - } - - ftdm_log(FTDM_LOG_DEBUG, "Pcap file '%s' successfully opened!\n", pcapfn); - - pcaphdr.ts.tv_sec = 0; - pcaphdr.ts.tv_usec = 0; - pcapfilesize = 24; /*current pcap file header seems to be 24 bytes*/ - tcp_next_seq_no_send = 0; - tcp_next_seq_no_rec = 0; - - return FTDM_SUCCESS; + return (isdn->pcap) ? 1 : 0; } -/** - * \brief Closes a pcap file - * \return Success - */ -static ftdm_status_t closePcapFile(void) +static inline ftdm_status_t isdn_pcap_capture_both(struct ftdm_isdn_data *isdn) { - if (pcapfile) { - pcap_dump_close(pcapfile); - if (pcaphandle) pcap_close(pcaphandle); + return ((isdn->flags & (FTDM_ISDN_CAPTURE | FTDM_ISDN_CAPTURE_L3ONLY)) == FTDM_ISDN_CAPTURE) ? 1 : 0; +} - ftdm_log(FTDM_LOG_DEBUG, "Pcap file closed! File size is %lu bytes.\n", pcapfilesize); +static inline ftdm_status_t isdn_pcap_capture_l3only(struct ftdm_isdn_data *isdn) +{ + return ((isdn->flags & FTDM_ISDN_CAPTURE) && (isdn->flags & FTDM_ISDN_CAPTURE_L3ONLY)) ? 1 : 0; +} - pcaphdr.ts.tv_sec = 0; - pcaphdr.ts.tv_usec = 0; - pcapfile = NULL; - pcaphandle = NULL; - pcapfilesize = 0; - tcp_next_seq_no_send = 0; - tcp_next_seq_no_rec = 0; +static ftdm_status_t isdn_pcap_open(struct ftdm_isdn_data *isdn, char *filename) +{ + struct pcap_context *pcap = NULL; + + if (!isdn) { + return FTDM_FAIL; } - /*We have allways success with this? I think so*/ + if (ftdm_strlen_zero(filename)) { + return FTDM_FAIL; + } + + pcap = malloc(sizeof(struct pcap_context)); + if (!pcap) { + ftdm_log(FTDM_LOG_ERROR, "Failed to allocate isdn pcap context\n"); + return FTDM_FAIL; + } + + memset(pcap, 0, sizeof(struct pcap_context)); + + pcap->filename = strdup(filename); + + pcap->handle = pcap_open_dead(DLT_LINUX_LAPD, PCAP_SNAPLEN); + if (!pcap->handle) { + ftdm_log(FTDM_LOG_ERROR, "Failed to open pcap handle\n"); + goto error; + } + + pcap->dump = pcap_dump_open(pcap->handle, pcap->filename); + if (!pcap->dump) { + ftdm_log(FTDM_LOG_ERROR, "Failed to open capture file: %s\n", pcap_geterr(pcap->handle)); + goto error; + } + + ftdm_log(FTDM_LOG_INFO, "Capture file \"%s\" opened\n", pcap->filename); + + isdn->pcap = pcap; + + return FTDM_SUCCESS; + +error: + if (pcap->handle) { + pcap_close(pcap->handle); + } + if (pcap->filename) { + free(pcap->filename); + } + + free(pcap); + + return FTDM_FAIL; +} + +static ftdm_status_t isdn_pcap_close(struct ftdm_isdn_data *isdn) +{ + struct pcap_context *pcap = NULL; + long size; + + if (!isdn || !isdn->pcap) { + return FTDM_FAIL; + } + pcap = isdn->pcap; + + isdn->flags &= ~(FTDM_ISDN_CAPTURE | FTDM_ISDN_CAPTURE_L3ONLY); + isdn->pcap = NULL; + + pcap_dump_flush(pcap->dump); + + size = pcap_dump_ftell(pcap->dump); + ftdm_log(FTDM_LOG_INFO, "File \"%s\" captured %ld bytes of data\n", pcap->filename, size); + + pcap_dump_close(pcap->dump); + pcap_close(pcap->handle); + + free(pcap->filename); + free(pcap); + return FTDM_SUCCESS; } -/** - * \brief Writes a Q931 packet to a pcap file - * \return Success or failure - */ -static ftdm_status_t writeQ931PacketToPcap(L3UCHAR* q931buf, L3USHORT q931size, L3ULONG span_id, L3USHORT direction) +static inline void isdn_pcap_start(struct ftdm_isdn_data *isdn) { - L3UCHAR *frame = NULL; - struct timeval ts; - u_char spanid = (u_char)span_id; - unsigned long *tcp_next_seq_no = NULL; + if (!isdn->pcap) + return; - spanid=span_id; - - /*The total length of the ethernet frame generated by this function has a min length of 66 - so we don't have to care about padding :)*/ + isdn->flags |= FTDM_ISDN_CAPTURE; +} +static inline void isdn_pcap_stop(struct ftdm_isdn_data *isdn) +{ + isdn->flags &= ~FTDM_ISDN_CAPTURE; +} - /*FS is sending the packet*/ - if(direction==0){ - frame=sendFrame; - tcp_next_seq_no = &tcp_next_seq_no_send; - } - /*FS is receiving the packet*/ - else{ - frame=recFrame; - tcp_next_seq_no = &tcp_next_seq_no_rec; +#ifndef ETH_P_LAPD +#define ETH_P_LAPD 0x0030 +#endif + +struct isdn_sll_hdr { + uint16_t slltype; + uint16_t sllhatype; + uint16_t slladdrlen; + uint8_t slladdr[8]; + uint16_t sllproto; +}; + +/* Fake Q.921 I-frame */ +//static const char q921_fake_frame[] = { 0x00, 0x00, 0x00, 0x00 }; + +enum { + ISDN_PCAP_INCOMING = 0, + ISDN_PCAP_INCOMING_BCAST = 1, + ISDN_PCAP_OUTGOING = 4, +}; + +static ftdm_status_t isdn_pcap_write(struct ftdm_isdn_data *isdn, unsigned char *buf, ftdm_ssize_t len, int direction) +{ + unsigned char frame[PCAP_SNAPLEN]; + struct pcap_context *pcap; + struct isdn_sll_hdr *sll_hdr = (struct isdn_sll_hdr *)frame; + struct pcap_pkthdr hdr; + int offset = sizeof(struct isdn_sll_hdr); + int nbytes; + + if (!isdn || !isdn->pcap || !buf || !len) { + return FTDM_FAIL; } - /*Set spanid in VLAN-ID tag*/ - frame[VLANID_OFFSET] = spanid; + pcap = isdn->pcap; - /*** Write sent packet ***/ - if(q931size > MAX_Q931_SIZE) - { - /*WARNING*/ - ftdm_log(FTDM_LOG_WARNING, "Q931 packet size is too big (%u)! Ignoring it!\n", q931size); - return FTDM_FAIL; - } - - /*Copy q931 buffer into frame*/ - memcpy(frame+OVERHEAD,q931buf,q931size); - - /*Store TCP sequence number in TCP header*/ - frame[TCP_SEQ_OFFSET]=(*tcp_next_seq_no>>24)&0xFF; - frame[TCP_SEQ_OFFSET+1]=(*tcp_next_seq_no>>16)&0xFF; - frame[TCP_SEQ_OFFSET+2]=(*tcp_next_seq_no>>8)&0xFF; - frame[TCP_SEQ_OFFSET+3]=*tcp_next_seq_no & 0xFF; - - /*Store size of TPKT packet*/ - q931size+=4; - frame[TPKT_SIZE_OFFSET]=(q931size>>8)&0xFF; - frame[TPKT_SIZE_OFFSET+1]=q931size&0xFF; - - /*Calc next TCP sequence number*/ - *tcp_next_seq_no+=q931size; - - /*Store size of IP packet*/ - q931size+=SIZE_IP+SIZE_TCP; - frame[IP_SIZE_OFFSET]=(q931size>>8)&0xFF; - frame[IP_SIZE_OFFSET+1]=q931size&0xFF; - - pcaphdr.caplen = SIZE_ETHERNET+SIZE_ETHERNET_CRC+q931size; - pcaphdr.len = pcaphdr.caplen; - - /* Set Timestamp */ - /* Get Time in ms. usecs would be better ... */ - gettimeofday(&ts, NULL); - /*Write it into packet header*/ - pcaphdr.ts.tv_sec = ts.tv_sec; - pcaphdr.ts.tv_usec = ts.tv_usec; - - pcap_dump((u_char*)pcapfile, &pcaphdr, frame); - pcap_dump_flush(pcapfile); - - /*Maintain pcap file size*/ - pcapfilesize+=pcaphdr.caplen; - pcapfilesize+=sizeof(struct pcap_pkthdr); - - ftdm_log(FTDM_LOG_DEBUG, "Added %u bytes to pcap file. File size is now %lu, \n", q931size, pcapfilesize); - - return FTDM_SUCCESS; -} + /* Update SLL header */ + sll_hdr->slltype = htons(direction); + sll_hdr->sllhatype = 0; + sll_hdr->slladdrlen = 1; + sll_hdr->slladdr[0] = (isdn->mode == Q921_NT) ? 1 : 0; /* TODO: NT/TE */ + sll_hdr->sllproto = htons(ETH_P_LAPD); +#if 0 + /* Q.931-only mode: copy fake Q.921 header */ + if (isdn->flags & FTDM_ISDN_CAPTURE_L3ONLY) { + /* copy fake q921 header */ + memcpy(frame + offset, q921_fake_frame, sizeof(q921_fake_frame)); + offset += sizeof(q921_fake_frame); + } #endif -/** - * \brief Unloads pcap IO - * \return Success or failure - */ -static FIO_IO_UNLOAD_FUNCTION(close_pcap) -{ -#ifdef HAVE_LIBPCAP - return closePcapFile(); -#else + /* Copy data */ + nbytes = (len > (PCAP_SNAPLEN - offset)) ? (PCAP_SNAPLEN - offset) : len; + memcpy(frame + offset, buf, nbytes); + + /* Update timestamp */ + memset(&hdr, 0, sizeof(struct pcap_pkthdr)); + gettimeofday(&hdr.ts, NULL); + hdr.caplen = offset + nbytes; + hdr.len = hdr.caplen; + + /* Write packet */ + pcap_dump((unsigned char *)pcap->dump, &hdr, frame); + return FTDM_SUCCESS; -#endif } +#endif /* HAVE_PCAP */ -/*Q931ToPcap functions DONE*/ -/*-------------------------------------------------------------------------*/ -/** - * \brief Gets current time - * \return Current time (in ms) - */ static L2ULONG ftdm_time_now(void) { return (L2ULONG)ftdm_current_time_in_ms(); } /** - * \brief Initialises an ISDN channel (outgoing call) - * \param ftdmchan Channel to initiate call on - * \return Success or failure + * \brief Returns the signalling status on a channel + * \param ftdmchan Channel to get status on + * \param status Pointer to set signalling status + * \return Success or failure + */ +static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(isdn_get_channel_sig_status) +{ + *status = FTDM_SIG_STATE_DOWN; + + ftdm_isdn_data_t *isdn_data = ftdmchan->span->signal_data; + if (ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) { + *status = FTDM_SIG_STATE_UP; + } + return FTDM_SUCCESS; +} + +/** + * \brief Returns the signalling status on a span + * \param span Span to get status on + * \param status Pointer to set signalling status + * \return Success or failure + */ +static FIO_SPAN_GET_SIG_STATUS_FUNCTION(isdn_get_span_sig_status) +{ + *status = FTDM_SIG_STATE_DOWN; + + ftdm_isdn_data_t *isdn_data = span->signal_data; + if (ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) { + *status = FTDM_SIG_STATE_UP; + } + return FTDM_SUCCESS; +} + +/** + * \brief Create outgoing channel + * \param ftdmchan Channel to create outgoing call on + * \return Success or failure */ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call) { @@ -301,14 +302,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call) } /** - * \brief Requests an ISDN channel on a span (outgoing call) - * \param span Span where to get a channel - * \param chan_id Specific channel to get (0 for any) - * \param direction Call direction (inbound, outbound) - * \param caller_data Caller information - * \param ftdmchan Channel to initialise - * \return Success or failure + * \brief Create outgoing channel, let module select the channel to use + * \param span Span to create outgoing call on + * \param caller_data + * \return Success or failure */ +#ifdef __TODO__ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) { Q931mes_Generic *gen = (Q931mes_Generic *) caller_data->raw_data; @@ -348,7 +347,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) BearerCap.ITR = Q931_ITR_64K; /* 64k */ BearerCap.Layer1Ident = 1; BearerCap.UIL1Prot = (codec == FTDM_CODEC_ALAW) ? Q931_UIL1P_G711A : Q931_UIL1P_G711U; /* U-law = 2, A-law = 3 */ - gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap); + gen->BearerCap = Q931AppendIE(gen, (L3UCHAR *) &BearerCap); /* * Channel ID IE @@ -356,20 +355,20 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) Q931InitIEChanID(&ChanID); ChanID.IntType = FTDM_SPAN_IS_BRI(span) ? 0 : 1; /* PRI = 1, BRI = 0 */ - if(!FTDM_SPAN_IS_NT(span)) { + if (!FTDM_SPAN_IS_NT(span)) { ChanID.PrefExcl = (isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL) ? 0 : 1; /* 0 = preferred, 1 exclusive */ } else { ChanID.PrefExcl = 1; /* always exclusive in NT-mode */ } - if(ChanID.IntType) { + if (ChanID.IntType) { ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */ ChanID.ChanMapType = 3; /* B-Chan */ ChanID.ChanSlot = (unsigned char)chan_id; } else { ChanID.InfoChanSel = (unsigned char)chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */ } - gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID); + gen->ChanID = Q931AppendIE(gen, (L3UCHAR *) &ChanID); /* * Progress IE @@ -378,15 +377,15 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) Progress.CodStand = Q931_CODING_ITU; /* 0 = ITU */ Progress.Location = 0; /* 0 = User, 1 = Private Network */ Progress.ProgDesc = 3; /* 1 = Not end-to-end ISDN */ - gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress); + gen->ProgInd = Q931AppendIE(gen, (L3UCHAR *)&Progress); /* * Display IE */ - if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE)) { + if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE) && FTDM_SPAN_IS_NT(span)) { Q931InitIEDisplay(&Display); Display.Size = Display.Size + (unsigned char)strlen(caller_data->cid_name); - gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display); + gen->Display = Q931AppendIE(gen, (L3UCHAR *) &Display); ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf); ftdm_copy_string((char *)ptrDisplay->Display, caller_data->cid_name, strlen(caller_data->cid_name)+1); } @@ -400,7 +399,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) CallingNum.PresInd = Q931_PRES_ALLOWED; CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED; CallingNum.Size = CallingNum.Size + (unsigned char)strlen(caller_data->cid_num.digits); - gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum); + gen->CallingNum = Q931AppendIE(gen, (L3UCHAR *) &CallingNum); ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf); ftdm_copy_string((char *)ptrCallingNum->Digit, caller_data->cid_num.digits, strlen(caller_data->cid_num.digits)+1); @@ -411,10 +410,10 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) Q931InitIECalledNum(&CalledNum); CalledNum.TypNum = Q931_TON_UNKNOWN; CalledNum.NumPlanID = Q931_NUMPLAN_E164; - CalledNum.Size = CalledNum.Size + (unsigned char)strlen(caller_data->dnis.digits); - gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum); + CalledNum.Size = CalledNum.Size + (unsigned char)strlen(caller_data->ani.digits); + gen->CalledNum = Q931AppendIE(gen, (L3UCHAR *) &CalledNum); ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf); - ftdm_copy_string((char *)ptrCalledNum->Digit, caller_data->dnis.digits, strlen(caller_data->dnis.digits)+1); + ftdm_copy_string((char *)ptrCalledNum->Digit, caller_data->ani.digits, strlen(caller_data->ani.digits)+1); /* * High-Layer Compatibility IE (Note: Required for AVM FritzBox) @@ -424,28 +423,28 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) HLComp.Interpret = 4; /* only possible value */ HLComp.PresMeth = 1; /* High-layer protocol profile */ HLComp.HLCharID = 1; /* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */ - gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp); + gen->HLComp = Q931AppendIE(gen, (L3UCHAR *) &HLComp); caller_data->call_state = FTDM_CALLER_STATE_DIALING; - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); - + Q931Rx43(&isdn_data->q931, gen, gen->Size); + isdn_data->outbound_crv[gen->CRV] = caller_data; //isdn_data->channels_local_crv[gen->CRV] = ftdmchan; while(ftdm_running() && caller_data->call_state == FTDM_CALLER_STATE_DIALING) { ftdm_sleep(1); - + if (!--sanity) { caller_data->call_state = FTDM_CALLER_STATE_FAIL; break; } } isdn_data->outbound_crv[gen->CRV] = NULL; - + if (caller_data->call_state == FTDM_CALLER_STATE_SUCCESS) { ftdm_channel_t *new_chan = NULL; int fail = 1; - + new_chan = NULL; if (caller_data->chan_id < FTDM_MAX_CHANNELS_SPAN && caller_data->chan_id <= span->chan_count) { new_chan = span->channels[caller_data->chan_id]; @@ -456,7 +455,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) if (new_chan->state == FTDM_CHANNEL_STATE_DOWN || new_chan->state >= FTDM_CHANNEL_STATE_TERMINATING) { int x = 0; ftdm_log(FTDM_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n"); - + for (x = 0; x < 200; x++) { if (!ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE)) { break; @@ -493,9 +492,9 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) } fail = 0; - } + } } - + if (!fail) { *ftdmchan = new_chan; return FTDM_SUCCESS; @@ -510,13 +509,13 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) //should we be casting here.. or do we need to translate value? cause.Value = (unsigned char) FTDM_CAUSE_WRONG_CALL_STATE; *cause.Diag = '\0'; - gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause); - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + gen->Cause = Q931AppendIE(gen, (L3UCHAR *) &cause); + Q931Rx43(&isdn_data->q931, gen, gen->Size); if (gen->CRV) { Q931ReleaseCRV(&isdn_data->q931, gen->CRV); } - + if (new_chan) { ftdm_log(FTDM_LOG_CRIT, "Channel is busy\n"); } else { @@ -524,20 +523,13 @@ static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request) } } } - + *ftdmchan = NULL; return FTDM_FAIL; } +#endif /* __TODO__ */ -/** - * \brief Handler for Q931 error - * \param pvt Private structure (span?) - * \param id Error number - * \param p1 ?? - * \param p2 ?? - * \return 0 - */ static L3INT ftdm_isdn_931_err(void *pvt, L3INT id, L3INT p1, L3INT p2) { ftdm_log(FTDM_LOG_ERROR, "ERROR: [%s] [%d] [%d]\n", q931_error_to_name(id), p1, p2); @@ -545,21 +537,218 @@ static L3INT ftdm_isdn_931_err(void *pvt, L3INT id, L3INT p1, L3INT p2) } /** - * \brief Handler for Q931 event message - * \param pvt Span to handle - * \param msg Message string - * \param mlen Message string length - * \return 0 + * \brief The new call event handler + * \note W000t!!! \o/ ;D + * \todo A lot */ -static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) +static void ftdm_isdn_call_event(struct Q931_Call *call, struct Q931_CallEvent *event, void *priv) +{ + Q931_TrunkInfo_t *trunk = NULL; + ftdm_isdn_data_t *isdn_data = NULL; + ftdm_span_t *zspan = NULL; + assert(call); + assert(event); + + trunk = Q931CallGetTrunk(call); + assert(trunk); + + zspan = Q931CallGetPrivate(call); + if (!zspan) { + zspan = priv; + Q931CallSetPrivate(call, zspan); + } + assert(zspan); + + isdn_data = zspan->signal_data; + + if (Q931CallIsGlobal(call)) { + /* + * Global event + */ + + ftdm_log(FTDM_LOG_DEBUG, "Received global event from Q.931\n"); + } + else { + ftdm_channel_t *ftdmchan = NULL; + ftdm_sigmsg_t sig; + int call_crv = Q931CallGetCRV(call); + int type; + + /* + * Call-specific event + */ + ftdm_log(FTDM_LOG_DEBUG, "Received call-specific event from Q.931 for call %d [%hu]\n", Q931CallGetCRV(call), Q931CallGetCRV(call)); + + /* + * Try to get associated zap channel + * and init sigmsg struct if there is one + */ + ftdmchan = Q931CallIsOutgoing(call) ? isdn_data->channels_local_crv[call_crv] : isdn_data->channels_remote_crv[call_crv]; + if (ftdmchan) { + memset(&sig, 0, sizeof(ftdm_sigmsg_t)); + sig.chan_id = ftdmchan->chan_id; + sig.span_id = ftdmchan->span_id; + sig.channel = ftdmchan; + } + + type = Q931CallEventGetType(event); + + if (type == Q931_EVENT_TYPE_CRV) { + + ftdm_log(FTDM_LOG_DEBUG, "\tCRV event\n"); + + switch (Q931CallEventGetId(event)) { + case Q931_EVENT_RELEASE_CRV: + { + /* WARNING contains old interface code, yuck! */ + if (!ftdmchan) { + ftdm_log(FTDM_LOG_DEBUG, "Call %d [0x%x] not associated to zap channel\n", call_crv, call_crv); + return; + } + + if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d not in DOWN state, cleaning up\n", + ftdmchan->span_id, ftdmchan->chan_id); + + /* + * Send hangup signal to mod_openzap + */ + if (!sig.channel->caller_data.hangup_cause) { + sig.channel->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; + } + + sig.event_id = FTDM_SIGEVENT_STOP; + isdn_data->sig_cb(&sig); + + /* Release zap channel */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } + return; + } + break; + default: + ftdm_log(FTDM_LOG_ERROR, "Unknown CRV event: %d\n", Q931CallEventGetId(event)); + return; + } + } + else if (type == Q931_EVENT_TYPE_TIMER) { + struct Q931_CallTimerEvent *timer_evt = Q931CallEventGetData(event); + + ftdm_log(FTDM_LOG_DEBUG, "\tTimer event\n"); + assert(timer_evt->id); + + switch (timer_evt->id) { + case Q931_TIMER_T303: + /* + * SETUP timeout + * + * TE-mode: Q931_EVENT_SETUP_CONFIRM (error) + * NT-mode: Q931_EVENT_RELEASE_INDICATION + */ + { + /* WARNING contains old interface code, yuck! */ + if (!ftdmchan) { + ftdm_log(FTDM_LOG_ERROR, "Call %d [0x%x] not associated to zap channel\n", call_crv, call_crv); + return; + } + + ftdm_log(FTDM_LOG_DEBUG, "Call setup failed on channel %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id); + + /* + * Send signal to mod_openzap + */ + sig.channel->caller_data.hangup_cause = FTDM_CAUSE_NETWORK_OUT_OF_ORDER; + + sig.event_id = FTDM_SIGEVENT_STOP; + isdn_data->sig_cb(&sig); + + /* Release zap channel */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + return; + } + break; + + default: + ftdm_log(FTDM_LOG_ERROR, "Unhandled timer event %d\n", timer_evt->id); + } + } + else if (type == Q931_EVENT_TYPE_MESSAGE) { + struct Q931_CallMessageEvent *msg_evt = Q931CallEventGetData(event); + + ftdm_log(FTDM_LOG_DEBUG, "\tMessage event\n"); + assert(msg_evt); + + /* + * Slowly move stuff from the old event handler into this part... + */ + switch (Q931CallEventGetId(event)) { + case Q931_EVENT_SETUP_CONFIRM: + case Q931_EVENT_SETUP_COMPLETE_INDICATION: /* CONNECT */ + { + /* WARNING contains old interface code, yuck! */ + if (!ftdmchan) { + ftdm_log(FTDM_LOG_ERROR, "Call %d [0x%x] not associated to zap channel\n", call_crv, call_crv); + return; + } + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + } + break; + + default: + ftdm_log(FTDM_LOG_DEBUG, "Not yet handled message event %d\n", Q931CallEventGetId(event)); + } + } + else { + ftdm_log(FTDM_LOG_ERROR, "Unknown event type %d\n", type); + } + } +} + +/** + * Copy callednum, readding prefix as needed + */ +static void __isdn_get_number(const char *digits, const int ton, char *buf, int size) +{ + int offset = 0; + + if (!digits || !buf || size <= 0) { + return; + } + + switch (ton) { + case Q931_TON_NATIONAL: + offset = strlen(DEFAULT_NATIONAL_PREFIX); + memcpy(buf, DEFAULT_NATIONAL_PREFIX, offset); + break; + case Q931_TON_INTERNATIONAL: + offset = strlen(DEFAULT_INTERNATIONAL_PREFIX); + memcpy(buf, DEFAULT_INTERNATIONAL_PREFIX, offset); + break; + default: + break; + } + + strncpy(&buf[offset], digits, size - (offset + 1)); + buf[size - 1] = '\0'; +} + +#define isdn_get_number(num, buf) \ + __isdn_get_number((const char *)(num)->Digit, (num)->TypNum, (char *)buf, sizeof(buf)) + + +/** + * \brief The old call event handler (err, call message handler) + * \todo This one must die! + */ +static L3INT ftdm_isdn_931_34(void *pvt, struct Q931_Call *call, Q931mes_Generic *msg, int mlen) { ftdm_span_t *span = (ftdm_span_t *) pvt; ftdm_isdn_data_t *isdn_data = span->signal_data; Q931mes_Generic *gen = (Q931mes_Generic *) msg; - uint32_t chan_id = 0; + int chan_id = 0; int chan_hunt = 0; ftdm_channel_t *ftdmchan = NULL; - ftdm_caller_data_t *caller_data = NULL; +// ftdm_caller_data_t *caller_data = NULL; if (Q931IsIEPresent(gen->ChanID)) { Q931ie_ChanID *chanid = Q931GetIEPtr(gen->ChanID, gen->buf); @@ -580,9 +769,30 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) assert(span != NULL); assert(isdn_data != NULL); - + + /* + * Support code for the new event handling system + * Remove this as soon as we have the new api to set up calls + */ +#ifdef __OLD__ + if (gen->CRV) { + struct Q931_Call *call; + + call = Q931GetCallByCRV(&isdn_data->q931, gen->CRV); + if (call && !Q931CallGetPrivate(call)) { + ftdm_log(FTDM_LOG_DEBUG, "Storing reference to current span in call %d [0x%x]\n", gen->CRV, gen->CRV); + Q931CallSetPrivate(call, span); + } + } +#else + if (call && !Q931CallGetPrivate(call)) { + ftdm_log(FTDM_LOG_DEBUG, "Storing reference to current span in call %d [0x%x]\n", gen->CRV, gen->CRV); + Q931CallSetPrivate(call, span); + } +#endif ftdm_log(FTDM_LOG_DEBUG, "Yay I got an event! Type:[%02x] Size:[%d] CRV: %d (%#hx, CTX: %s)\n", gen->MesType, gen->Size, gen->CRV, gen->CRV, gen->CRVFlag ? "Terminator" : "Originator"); +#ifdef __TODO_OR_REMOVE__ if (gen->CRVFlag && (caller_data = isdn_data->outbound_crv[gen->CRV])) { if (chan_id) { caller_data->chan_id = chan_id; @@ -603,9 +813,10 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) caller_data->call_state = FTDM_CALLER_STATE_FAIL; break; } - + return 0; } +#endif if (gen->CRVFlag) { ftdmchan = isdn_data->channels_local_crv[gen->CRV]; @@ -630,7 +841,7 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); } break; - case 1: + case 1: { /* change status to "maintenance" */ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -664,7 +875,12 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); } else { uint32_t i; + for (i = 1; i < span->chan_count; i++) { + /* Skip channels that are down and D-Channels (#OpenZAP-39) */ + if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) + continue; + ftdm_set_state_locked((span->channels[i]), FTDM_CHANNEL_STATE_RESTART); } } @@ -699,7 +915,7 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) sig.channel->caller_data.hangup_cause = (cause) ? cause->Value : FTDM_CAUSE_NORMAL_UNSPECIFIED; sig.event_id = FTDM_SIGEVENT_STOP; - status = ftdm_span_send_signal(ftdmchan->span, &sig); + status = isdn_data->sig_cb(&sig); ftdm_log(FTDM_LOG_DEBUG, "Received %s in state %s, requested hangup for channel %d:%d\n", what, ftdm_channel_state2str(ftdmchan->state), ftdmchan->span_id, chan_id); } @@ -741,17 +957,21 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) } break; case Q931mes_CONNECT: +#if 0 /* Handled by new event code */ { if (ftdmchan) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); +#if 0 /* Auto-Ack is enabled, we actually don't need this */ gen->MesType = Q931mes_CONNECT_ACKNOWLEDGE; gen->CRVFlag = 0; /* outbound */ - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); +#endif } else { ftdm_log(FTDM_LOG_CRIT, "Received Connect with no matching channel %d\n", chan_id); } } +#endif break; case Q931mes_SETUP: { @@ -771,13 +991,13 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) ftdm_channel_state2str(ftdmchan->state)); break; } - + ftdmchan = NULL; /* * Channel selection for incoming calls: */ if (FTDM_SPAN_IS_NT(span) && chan_hunt) { - uint32_t x; + int x; /* * In NT-mode with channel selection "any", @@ -865,14 +1085,21 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) memset(ftdmchan->mod_data, 0, sizeof(ftdm_isdn_bchan_data_t)); } - ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)callingnum->Digit); - ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)callingnum->Digit); - ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)callingnum->Digit); - if (!overlap_dial) { - ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)callednum->Digit); - } + /* copy number readd prefix as needed */ + isdn_get_number(callingnum, ftdmchan->caller_data.cid_num.digits); + isdn_get_number(callingnum, ftdmchan->caller_data.cid_name); + isdn_get_number(callingnum, ftdmchan->caller_data.ani.digits); +// ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)callingnum->Digit); +// ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)callingnum->Digit); +// ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)callingnum->Digit); + if (!overlap_dial) { +// ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)callednum->Digit); + isdn_get_number(callednum, ftdmchan->caller_data.dnis.digits); + } +#ifdef __TODO_OR_REMOVE__ ftdmchan->caller_data.CRV = gen->CRV; +#endif if (cplen > sizeof(ftdmchan->caller_data.raw_data)) { cplen = sizeof(ftdmchan->caller_data.raw_data); } @@ -880,8 +1107,8 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) memcpy(ftdmchan->caller_data.raw_data, msg, cplen); ftdmchan->caller_data.raw_data_len = cplen; fail = 0; - } - } + } + } if (fail) { Q931ie_Cause cause; @@ -895,8 +1122,8 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) //should we be casting here.. or do we need to translate value? cause.Value = (unsigned char)((fail_cause) ? fail_cause : FTDM_CAUSE_WRONG_CALL_STATE); *cause.Diag = '\0'; - gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause); - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + gen->Cause = Q931AppendIE(gen, (L3UCHAR *) &cause); + Q931Rx43(&isdn_data->q931, gen, gen->Size); if (gen->CRV) { Q931ReleaseCRV(&isdn_data->q931, gen->CRV); @@ -907,7 +1134,7 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) } else { ftdm_log(FTDM_LOG_CRIT, "Failed to open channel for new setup message\n"); } - + } else { Q931ie_ChanID ChanID; @@ -924,7 +1151,7 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) } else { ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */ } - gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID); + gen->ChanID = Q931AppendIE(gen, (L3UCHAR *) &ChanID); if (overlap_dial) { Q931ie_ProgInd progress; @@ -934,17 +1161,17 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) */ progress.IEId = Q931ie_PROGRESS_INDICATOR; progress.Size = sizeof(Q931ie_ProgInd); - progress.CodStand = Q931_CODING_ITU; /* ITU */ + progress.CodStand = Q931_CODING_ITU; /* ITU */ progress.Location = 1; /* private network serving the local user */ progress.ProgDesc = 8; /* call is not end-to-end isdn = 1, in-band information available = 8 */ - gen->ProgInd = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &progress); + gen->ProgInd = Q931AppendIE(gen, (L3UCHAR *) &progress); /* * Send SETUP ACK */ gen->MesType = Q931mes_SETUP_ACKNOWLEDGE; gen->CRVFlag = 1; /* inbound call */ - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALTONE); } else { @@ -999,7 +1226,7 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) } /* TODO: make this more safe with strncat() */ - pos = (int)strlen(ftdmchan->caller_data.dnis.digits); + pos = strlen(ftdmchan->caller_data.dnis.digits); strcat(&ftdmchan->caller_data.dnis.digits[pos], (char *)callednum->Digit); /* update timer */ @@ -1020,61 +1247,6 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) } break; - case Q931mes_STATUS_ENQUIRY: - { - /* - * !! HACK ALERT !! - * - * Map FreeTDM channel states to Q.931 states - */ - Q931ie_CallState state; - Q931ie_Cause cause; - - gen->MesType = Q931mes_STATUS; - gen->CRVFlag = gen->CRVFlag ? 0 : 1; - - state.CodStand = Q931_CODING_ITU; /* ITU-T */ - state.CallState = Q931_U0; /* Default: Null */ - - cause.IEId = Q931ie_CAUSE; - cause.Size = sizeof(Q931ie_Cause); - cause.CodStand = Q931_CODING_ITU; /* ITU */ - cause.Location = 1; /* private network */ - cause.Recom = 1; /* */ - *cause.Diag = '\0'; - - if(ftdmchan) { - switch(ftdmchan->state) { - case FTDM_CHANNEL_STATE_UP: - state.CallState = Q931_U10; /* Active */ - break; - case FTDM_CHANNEL_STATE_RING: - state.CallState = Q931_U6; /* Call present */ - break; - case FTDM_CHANNEL_STATE_DIALING: - state.CallState = Q931_U1; /* Call initiated */ - break; - case FTDM_CHANNEL_STATE_DIALTONE: - state.CallState = Q931_U25; /* Overlap receiving */ - break; - - /* TODO: map missing states */ - - default: - state.CallState = Q931_U0; - } - - cause.Value = 30; /* response to STATUS ENQUIRY */ - } else { - cause.Value = 98; /* */ - } - - gen->CallState = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &state); - gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause); - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); - } - break; - default: ftdm_log(FTDM_LOG_CRIT, "Received unhandled message %d (%#x)\n", (int)gen->MesType, (int)gen->MesType); break; @@ -1084,17 +1256,10 @@ static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen) return 0; } -/** - * \brief Handler for Q921 read event - * \param pvt Span were message is coming from - * \param ind Q921 indication - * \param tei Terminal Endpoint Identifier - * \param msg Message string - * \param mlen Message string length - * \return 0 on success, 1 on failure - */ static int ftdm_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *msg, L2INT mlen) { + ftdm_span_t *span = pvt; + ftdm_isdn_data_t *isdn_data = span->signal_data; int ret, offset = (ind == Q921_DL_DATA) ? 4 : 3; char bb[4096] = ""; @@ -1102,20 +1267,14 @@ static int ftdm_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *ms case Q921_DL_DATA: case Q921_DL_UNIT_DATA: print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb)); -#ifdef HAVE_LIBPCAP - /*Q931ToPcap*/ - if(do_q931ToPcap==1){ - ftdm_span_t *span = (ftdm_span_t *) pvt; - if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 1) != FTDM_SUCCESS){ - ftdm_log(FTDM_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n"); - } - } - /*Q931ToPcap done*/ + ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)mlen - offset, LINE, bb); +#ifdef HAVE_PCAP + if (isdn_pcap_capture_l3only(isdn_data)) { + isdn_pcap_write(isdn_data, msg, mlen, (ind == Q921_DL_UNIT_DATA) ? ISDN_PCAP_INCOMING_BCAST : ISDN_PCAP_INCOMING); + } #endif - ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n\n", (int)mlen - offset, LINE, bb); - default: - ret = Q931Rx23(pvt, ind, tei, msg, mlen); + ret = Q931Rx23(&isdn_data->q931, ind, tei, msg, mlen); if (ret != 0) ftdm_log(FTDM_LOG_DEBUG, "931 parse error [%d] [%s]\n", ret, q931_error_to_name(ret)); break; @@ -1124,35 +1283,22 @@ static int ftdm_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *ms return ((ret >= 0) ? 1 : 0); } -/** - * \brief Handler for Q921 write event - * \param pvt Span were message is coming from - * \param msg Message string - * \param mlen Message string length - * \return 0 on success, -1 on failure - */ static int ftdm_isdn_921_21(void *pvt, L2UCHAR *msg, L2INT mlen) { ftdm_span_t *span = (ftdm_span_t *) pvt; ftdm_size_t len = (ftdm_size_t) mlen; ftdm_isdn_data_t *isdn_data = span->signal_data; -#ifdef IODEBUG - char bb[4096] = ""; - print_hex_bytes(msg, len, bb, sizeof(bb)); - print_bits(msg, (int)len, bb, sizeof(bb), FTDM_ENDIAN_LITTLE, 0); - ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)len, LINE, bb); - -#endif - assert(span != NULL); + +#ifdef HAVE_PCAP + if (isdn_pcap_capture_both(isdn_data)) { + isdn_pcap_write(isdn_data, msg, mlen, ISDN_PCAP_OUTGOING); + } +#endif return ftdm_channel_write(isdn_data->dchan, msg, len, &len) == FTDM_SUCCESS ? 0 : -1; } -/** - * \brief Handler for channel state change - * \param ftdmchan Channel to handle - */ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { Q931mes_Generic *gen = (Q931mes_Generic *) ftdmchan->caller_data.raw_data; @@ -1160,7 +1306,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) ftdm_sigmsg_t sig; ftdm_status_t status; - ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", + ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state)); memset(&sig, 0, sizeof(sig)); @@ -1186,11 +1332,15 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { sig.event_id = FTDM_SIGEVENT_PROGRESS; - if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) { + if ((status = isdn_data->sig_cb(&sig) != FTDM_SUCCESS)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); } } else { + int crv = gen->CRV; + + Q931InitMesGeneric(gen); gen->MesType = Q931mes_CALL_PROCEEDING; + gen->CRV = crv; gen->CRVFlag = 1; /* inbound */ if (FTDM_SPAN_IS_NT(ftdmchan->span)) { @@ -1210,10 +1360,10 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) } else { ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */ } - gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID); + gen->ChanID = Q931AppendIE(gen, (L3UCHAR *) &ChanID); } - Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); } } break; @@ -1230,7 +1380,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { sig.event_id = FTDM_SIGEVENT_START; - if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) { + if ((status = isdn_data->sig_cb(&sig) != FTDM_SUCCESS)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); } } @@ -1240,7 +1390,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED; sig.event_id = FTDM_SIGEVENT_RESTART; - status = ftdm_span_send_signal(ftdmchan->span, &sig); + status = isdn_data->sig_cb(&sig); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } break; @@ -1248,7 +1398,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; - if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) { + if ((status = isdn_data->sig_cb(&sig) != FTDM_SUCCESS)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); } } else { @@ -1260,7 +1410,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) } gen->MesType = Q931mes_ALERTING; gen->CRVFlag = 1; /* inbound call */ - Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); } } break; @@ -1268,7 +1418,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { sig.event_id = FTDM_SIGEVENT_UP; - if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) { + if ((status = isdn_data->sig_cb(&sig) != FTDM_SUCCESS)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); } } else { @@ -1281,7 +1431,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) gen->MesType = Q931mes_CONNECT; gen->BearerCap = 0; gen->CRVFlag = 1; /* inbound call */ - Q931Rx43(&isdn_data->q931, (void *)gen, ftdmchan->caller_data.raw_data_len); + Q931Rx43(&isdn_data->q931, gen, ftdmchan->caller_data.raw_data_len); } } break; @@ -1305,7 +1455,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) /* * Q.931 Setup Message - */ + */ Q931InitMesGeneric(gen); gen->MesType = Q931mes_SETUP; gen->CRVFlag = 0; /* outbound(?) */ @@ -1320,7 +1470,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) BearerCap.ITR = Q931_ITR_64K; /* 64k = 16, Packet mode = 0 */ BearerCap.Layer1Ident = 1; BearerCap.UIL1Prot = (codec == FTDM_CODEC_ALAW) ? 3 : 2; /* U-law = 2, A-law = 3 */ - gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap); + gen->BearerCap = Q931AppendIE(gen, (L3UCHAR *) &BearerCap); /* * ChannelID IE @@ -1335,7 +1485,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) } else { ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */ } - gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID); + gen->ChanID = Q931AppendIE(gen, (L3UCHAR *) &ChanID); /* * Progress IE @@ -1344,29 +1494,29 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) Progress.CodStand = Q931_CODING_ITU; /* 0 = ITU */ Progress.Location = 0; /* 0 = User, 1 = Private Network */ Progress.ProgDesc = 3; /* 1 = Not end-to-end ISDN */ - gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress); + gen->ProgInd = Q931AppendIE(gen, (L3UCHAR *)&Progress); /* * Display IE */ - if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE)) { + if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE) && FTDM_SPAN_IS_NT(ftdmchan->span)) { Q931InitIEDisplay(&Display); Display.Size = Display.Size + (unsigned char)strlen(ftdmchan->caller_data.cid_name); - gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display); + gen->Display = Q931AppendIE(gen, (L3UCHAR *) &Display); ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf); ftdm_copy_string((char *)ptrDisplay->Display, ftdmchan->caller_data.cid_name, strlen(ftdmchan->caller_data.cid_name)+1); } /* * CallingNum IE - */ + */ Q931InitIECallingNum(&CallingNum); CallingNum.TypNum = ftdmchan->caller_data.ani.type; CallingNum.NumPlanID = Q931_NUMPLAN_E164; CallingNum.PresInd = Q931_PRES_ALLOWED; CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED; CallingNum.Size = CallingNum.Size + (unsigned char)strlen(ftdmchan->caller_data.cid_num.digits); - gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum); + gen->CallingNum = Q931AppendIE(gen, (L3UCHAR *) &CallingNum); ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf); ftdm_copy_string((char *)ptrCallingNum->Digit, ftdmchan->caller_data.cid_num.digits, strlen(ftdmchan->caller_data.cid_num.digits)+1); @@ -1374,12 +1524,12 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) * CalledNum IE */ Q931InitIECalledNum(&CalledNum); - CalledNum.TypNum = ftdmchan->caller_data.dnis.type; + CalledNum.TypNum = Q931_TON_UNKNOWN; CalledNum.NumPlanID = Q931_NUMPLAN_E164; - CalledNum.Size = CalledNum.Size + (unsigned char)strlen(ftdmchan->caller_data.dnis.digits); - gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum); + CalledNum.Size = CalledNum.Size + (unsigned char)strlen(ftdmchan->caller_data.ani.digits); + gen->CalledNum = Q931AppendIE(gen, (L3UCHAR *) &CalledNum); ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf); - ftdm_copy_string((char *)ptrCalledNum->Digit, ftdmchan->caller_data.dnis.digits, strlen(ftdmchan->caller_data.dnis.digits)+1); + ftdm_copy_string((char *)ptrCalledNum->Digit, ftdmchan->caller_data.ani.digits, strlen(ftdmchan->caller_data.ani.digits)+1); /* * High-Layer Compatibility IE (Note: Required for AVM FritzBox) @@ -1389,10 +1539,24 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) HLComp.Interpret = 4; /* only possible value */ HLComp.PresMeth = 1; /* High-layer protocol profile */ HLComp.HLCharID = Q931_HLCHAR_TELEPHONY; /* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */ /* TODO: make accessible from user layer */ - gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp); + gen->HLComp = Q931AppendIE(gen, (L3UCHAR *) &HLComp); - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); isdn_data->channels_local_crv[gen->CRV] = ftdmchan; + + /* + * Support code for the new event handling system + * Remove this as soon as we have the new api to set up calls + */ + if (gen->CRV) { + struct Q931_Call *call; + + call = Q931GetCallByCRV(&isdn_data->q931, gen->CRV); + if (call) { + ftdm_log(FTDM_LOG_DEBUG, "Storing reference to current span in call %d [0x%x]\n", gen->CRV, gen->CRV); + Q931CallSetPrivate(call, ftdmchan->span); + } + } } break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: @@ -1401,7 +1565,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) if(ftdmchan->last_state == FTDM_CHANNEL_STATE_HANGUP) { gen->MesType = Q931mes_RELEASE_COMPLETE; - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); } ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } @@ -1434,8 +1598,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) //cause.Value = (unsigned char) FTDM_CAUSE_UNALLOCATED; cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause; *cause.Diag = '\0'; - gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause); - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + gen->Cause = Q931AppendIE(gen, (L3UCHAR *) &cause); + Q931Rx43(&isdn_data->q931, gen, gen->Size); /* we're done, release channel */ //ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); @@ -1449,8 +1613,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause; *cause.Diag = '\0'; - gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause); - Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size); + gen->Cause = Q931AppendIE(gen, (L3UCHAR *) &cause); + Q931Rx43(&isdn_data->q931, gen, gen->Size); /* this will be triggered by the RELEASE_COMPLETE reply */ /* ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); */ @@ -1463,8 +1627,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause; *cause.Diag = '\0'; - gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause); - Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size); + gen->Cause = Q931AppendIE(gen, (L3UCHAR *) &cause); + Q931Rx43(&isdn_data->q931, gen, gen->Size); } } break; @@ -1473,20 +1637,16 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) ftdm_log(FTDM_LOG_DEBUG, "Terminating: Direction %s\n", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound"); sig.event_id = FTDM_SIGEVENT_STOP; - status = ftdm_span_send_signal(ftdmchan->span, &sig); + status = isdn_data->sig_cb(&sig); gen->MesType = Q931mes_RELEASE; gen->CRVFlag = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? 0 : 1; - Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size); + Q931Rx43(&isdn_data->q931, gen, gen->Size); } default: break; } } -/** - * \brief Checks current state on a span - * \param span Span to check status on - */ static __inline__ void check_state(ftdm_span_t *span) { if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) { @@ -1504,56 +1664,79 @@ static __inline__ void check_state(ftdm_span_t *span) } } -/** - * \brief Processes FreeTDM event on a span - * \param span Span to process event on - * \param event Event to process - * \return Success or failure - */ + static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event) { - ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", + ftdm_isdn_data_t *isdn_data = span->signal_data; + ftdm_alarm_flag_t alarmbits; + ftdm_sigmsg_t sig; + + memset(&sig, 0, sizeof(sig)); + sig.chan_id = event->channel->chan_id; + sig.span_id = event->channel->span_id; + sig.channel = event->channel; + + ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state)); switch(event->enum_id) { case FTDM_OOB_ALARM_TRAP: { + sig.event_id = FTDM_OOB_ALARM_TRAP; if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) { - if (event->channel->type == FTDM_CHAN_TYPE_B) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART); - } + ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART); } - - ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED); - - - ftdm_channel_get_alarms(event->channel); - ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n", - event->channel->span_id, event->channel->chan_id, - event->channel->physical_span_id, event->channel->physical_chan_id, + ftdm_channel_get_alarms(event->channel, &alarmbits); + isdn_data->sig_cb(&sig); + ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms [%s]\n", + event->channel->span_id, event->channel->chan_id, + event->channel->physical_span_id, event->channel->physical_chan_id, event->channel->last_error); } break; case FTDM_OOB_ALARM_CLEAR: { - - ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id, - event->channel->physical_span_id, event->channel->physical_chan_id); - + sig.event_id = FTDM_OOB_ALARM_CLEAR; ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED); - ftdm_channel_get_alarms(event->channel); + ftdm_channel_get_alarms(event->channel, &alarmbits); + isdn_data->sig_cb(&sig); } break; +#ifdef __BROKEN_BY_FREETDM_CONVERSION__ + case FTDM_OOB_DTMF: /* Taken from ozmod_analog, minus the CALLWAITING state handling */ + { + const char * digit_str = (const char *)event->data; + + if(digit_str) { + fio_event_cb_t event_callback = NULL; + + ftdm_channel_queue_dtmf(event->channel, digit_str); + if (span->event_callback) { + event_callback = span->event_callback; + } else if (event->channel->event_callback) { + event_callback = event->channel->event_callback; + } + + if (event_callback) { + event->channel->event_header.channel = event->channel; + event->channel->event_header.e_type = FTDM_EVENT_DTMF; + event->channel->event_header.data = (void *)digit_str; + event_callback(event->channel, &event->channel->event_header); + event->channel->event_header.e_type = FTDM_EVENT_NONE; + event->channel->event_header.data = NULL; + } + ftdm_safe_free(event->data); + } + } + break; +#endif } return FTDM_SUCCESS; } -/** - * \brief Checks for events on a span - * \param span Span to check for events - */ + static __inline__ void check_events(ftdm_span_t *span) { ftdm_status_t status; @@ -1584,12 +1767,7 @@ static __inline__ void check_events(ftdm_span_t *span) } } -/** - * \brief Retrieves tone generation output to be sent - * \param ts Teletone generator - * \param map Tone map - * \return -1 on error, 0 on success - */ + static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map) { ftdm_buffer_t *dt_buffer = ts->user_data; @@ -1603,20 +1781,14 @@ static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map return 0; } -/** - * \brief Main thread function for tone generation on a span - * \param me Current thread - * \param obj Span to generate tones on - */ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) { ftdm_span_t *span = (ftdm_span_t *) obj; ftdm_isdn_data_t *isdn_data = span->signal_data; ftdm_buffer_t *dt_buffer = NULL; - teletone_generation_session_t ts = {{{{0}}}}; + teletone_generation_session_t ts = {{{{0}}}};; unsigned char frame[1024]; - uint32_t x; - int interval = 0; + int x, interval; int offset = 0; ftdm_log(FTDM_LOG_DEBUG, "ISDN tones thread starting.\n"); @@ -1647,7 +1819,7 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) ts.duration = ts.rate; /* main loop */ - while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_TONES_RUNNING) && !ftdm_test_flag(isdn_data, FTDM_ISDN_STOP)) { + while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) { ftdm_wait_flag_t flags; ftdm_status_t status; int last_chan_state = 0; @@ -1799,11 +1971,6 @@ done: return NULL; } -/** - * \brief Main thread function for an ISDN span - * \param me Current thread - * \param obj Span to monitor - */ static void *ftdm_isdn_run(ftdm_thread_t *me, void *obj) { ftdm_span_t *span = (ftdm_span_t *) obj; @@ -1813,15 +1980,16 @@ static void *ftdm_isdn_run(ftdm_thread_t *me, void *obj) int errs = 0; #ifdef WIN32 - timeBeginPeriod(1); + timeBeginPeriod(1); #endif ftdm_log(FTDM_LOG_DEBUG, "ISDN thread starting.\n"); ftdm_set_flag(isdn_data, FTDM_ISDN_RUNNING); Q921Start(&isdn_data->q921); + Q931Start(&isdn_data->q931); - while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING) && !ftdm_test_flag(isdn_data, FTDM_ISDN_STOP)) { + while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) { ftdm_wait_flag_t flags = FTDM_READ; ftdm_status_t status = ftdm_channel_wait(isdn_data->dchan, &flags, 100); @@ -1853,20 +2021,13 @@ static void *ftdm_isdn_run(ftdm_thread_t *me, void *obj) { errs = 0; if (flags & FTDM_READ) { - - if (ftdm_test_flag(isdn_data->dchan, FTDM_CHANNEL_SUSPENDED)) { - ftdm_clear_flag_all(span, FTDM_CHANNEL_SUSPENDED); - } len = sizeof(frame); if (ftdm_channel_read(isdn_data->dchan, frame, &len) == FTDM_SUCCESS) { -#ifdef IODEBUG - char bb[4096] = ""; - print_hex_bytes(frame, len, bb, sizeof(bb)); - - print_bits(frame, (int)len, bb, sizeof(bb), FTDM_ENDIAN_LITTLE, 0); - ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)len, LINE, bb); +#ifdef HAVE_PCAP + if (isdn_pcap_capture_both(isdn_data)) { + isdn_pcap_write(isdn_data, frame, len, ISDN_PCAP_INCOMING); + } #endif - Q921QueueHDLCFrame(&isdn_data->q921, frame, (int)len); Q921Rx12(&isdn_data->q921); } @@ -1877,45 +2038,28 @@ static void *ftdm_isdn_run(ftdm_thread_t *me, void *obj) break; } } - - done: + +done: ftdm_channel_close(&isdn_data->dchans[0]); ftdm_channel_close(&isdn_data->dchans[1]); ftdm_clear_flag(isdn_data, FTDM_ISDN_RUNNING); #ifdef WIN32 - timeEndPeriod(1); + timeEndPeriod(1); +#endif +#ifdef HAVE_PCAP + if (isdn_pcap_is_open(isdn_data)) { + isdn_pcap_close(isdn_data); + } #endif - ftdm_log(FTDM_LOG_DEBUG, "ISDN thread ended.\n"); return NULL; } -/** - * \brief FreeTDM ISDN signaling module initialisation - * \return Success - */ -static FIO_SIG_LOAD_FUNCTION(ftdm_isdn_init) -{ - Q931Initialize(); - - Q921SetGetTimeCB(ftdm_time_now); - Q931SetGetTimeCB(ftdm_time_now); - - return FTDM_SUCCESS; -} - -/** - * \brief Receives a Q931 indication message - * \param pvt Span were message is coming from - * \param ind Q931 indication - * \param tei Terminal Endpoint Identifier - * \param msg Message string - * \param mlen Message string length - * \return 0 on success - */ static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3INT mlen) { + ftdm_span_t *span = pvt; + ftdm_isdn_data_t *isdn_data = span->signal_data; int offset = 4; char bb[4096] = ""; @@ -1925,16 +2069,6 @@ static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3I case Q921_DL_DATA: print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb)); -#ifdef HAVE_LIBPCAP - /*Q931ToPcap*/ - if(do_q931ToPcap==1){ - ftdm_span_t *span = (ftdm_span_t *) pvt; - if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 0) != FTDM_SUCCESS){ - ftdm_log(FTDM_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n"); - } - } - /*Q931ToPcap done*/ -#endif ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)mlen - offset, LINE, bb); break; @@ -1942,17 +2076,14 @@ static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3I break; } - return Q921Rx32(pvt, ind, tei, msg, mlen); +#ifdef HAVE_PCAP + if (isdn_pcap_capture_l3only(isdn_data)) { + isdn_pcap_write(isdn_data, msg, mlen, ISDN_PCAP_OUTGOING); + } +#endif + return Q921Rx32(&isdn_data->q921, ind, tei, msg, mlen); } -/** - * \brief Logs Q921 message - * \param pvt Span were message is coming from - * \param level Q921 log level - * \param msg Message string - * \param size Message string length - * \return 0 - */ static int ftdm_isdn_q921_log(void *pvt, Q921LogLevel_t level, char *msg, L2INT size) { ftdm_span_t *span = (ftdm_span_t *) pvt; @@ -1961,14 +2092,6 @@ static int ftdm_isdn_q921_log(void *pvt, Q921LogLevel_t level, char *msg, L2INT return 0; } -/** - * \brief Logs Q931 message - * \param pvt Span were message is coming from - * \param level Q931 log level - * \param msg Message string - * \param size Message string length - * \return 0 - */ static L3INT ftdm_isdn_q931_log(void *pvt, Q931LogLevel_t level, char *msg, L3INT size) { ftdm_span_t *span = (ftdm_span_t *) pvt; @@ -1976,9 +2099,7 @@ static L3INT ftdm_isdn_q931_log(void *pvt, Q931LogLevel_t level, char *msg, L3IN ftdm_log("Span", "Q.931", span->span_id, (int)level, "%s", msg); return 0; } -/** - * \brief ISDN state map - */ + static ftdm_state_map_t isdn_state_map = { { { @@ -2003,7 +2124,7 @@ static ftdm_state_map_t isdn_state_map = { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_DIALING, FTDM_END}, - {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { ZSD_OUTBOUND, @@ -2077,7 +2198,7 @@ static ftdm_state_map_t isdn_state_map = { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, - {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END}, }, { @@ -2086,17 +2207,11 @@ static ftdm_state_map_t isdn_state_map = { {FTDM_CHANNEL_STATE_UP, FTDM_END}, {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, }, - - } }; /** - * \brief Stops an ISDN span - * \param span Span to halt - * \return Success - * - * Sets a stop flag and waits for the threads to end + * \brief Stop signalling on span */ static ftdm_status_t ftdm_isdn_stop(ftdm_span_t *span) { @@ -2105,9 +2220,9 @@ static ftdm_status_t ftdm_isdn_stop(ftdm_span_t *span) if (!ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) { return FTDM_FAIL; } - + ftdm_set_flag(isdn_data, FTDM_ISDN_STOP); - + while(ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) { ftdm_sleep(100); } @@ -2117,15 +2232,10 @@ static ftdm_status_t ftdm_isdn_stop(ftdm_span_t *span) } return FTDM_SUCCESS; - } /** - * \brief Starts an ISDN span - * \param span Span to halt - * \return Success or failure - * - * Launches a thread to monitor the span and a thread to generate tones on the span + * \brief Start signalling on span */ static ftdm_status_t ftdm_isdn_start(ftdm_span_t *span) { @@ -2149,19 +2259,46 @@ static ftdm_status_t ftdm_isdn_start(ftdm_span_t *span) return ret; } -/** - * \brief Parses an option string to flags - * \param in String to parse for configuration options - * \return Flags - */ + +/*###################################################################* + * (text) value parsing / translation + *###################################################################*/ + +static int32_t parse_loglevel(const char *level) +{ + if (!level) { + return -1; + } + + if (!strcasecmp(level, "debug")) { + return FTDM_LOG_LEVEL_DEBUG; + } else if (!strcasecmp(level, "info")) { + return FTDM_LOG_LEVEL_INFO; + } else if (!strcasecmp(level, "notice")) { + return FTDM_LOG_LEVEL_NOTICE; + } else if (!strcasecmp(level, "warning")) { + return FTDM_LOG_LEVEL_WARNING; + } else if (!strcasecmp(level, "error")) { + return FTDM_LOG_LEVEL_ERROR; + } else if (!strcasecmp(level, "alert")) { + return FTDM_LOG_LEVEL_ALERT; + } else if (!strcasecmp(level, "crit")) { + return FTDM_LOG_LEVEL_CRIT; + } else if (!strcasecmp(level, "emerg")) { + return FTDM_LOG_LEVEL_EMERG; + } else { + return -1; + } +} + static uint32_t parse_opts(const char *in) { uint32_t flags = 0; - + if (!in) { return 0; } - + if (strstr(in, "suggest_channel")) { flags |= FTDM_ISDN_OPT_SUGGEST_CHANNEL; } @@ -2177,17 +2314,259 @@ static uint32_t parse_opts(const char *in) return flags; } +static uint32_t parse_dialect(const char *in) +{ + if (!in) { + return Q931_Dialect_Count; + } + +#if __UNSUPPORTED__ + if (!strcasecmp(in, "national")) { + return Q931_Dialect_National; + } + if (!strcasecmp(in, "dms")) { + return Q931_Dialect_DMS; + } +#endif + if (!strcasecmp(in, "5ess")) { + return Q931_Dialect_5ESS; + } + if (!strcasecmp(in, "dss1")) { + return Q931_Dialect_DSS1; + } + if (!strcasecmp(in, "q931")) { + return Q931_Dialect_Q931; + } + return Q931_Dialect_Count; +} + + +/*###################################################################* + * API commands + *###################################################################*/ + +static const char isdn_api_usage[] = +#ifdef HAVE_PCAP + "isdn capture [q931only]\n" + "isdn capture \n" +#endif + "isdn loglevel \n" + "isdn dump calls\n" + "isdn help"; + + /** - * \brief Initialises an ISDN span from configuration variables - * \param span Span to configure - * \param sig_cb Callback function for event signals - * \param ap List of configuration variables - * \return Success or failure + * isdn_api */ -static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) +static FIO_API_FUNCTION(isdn_api) +{ + char *mycmd = NULL, *argv[10] = { 0 }; + int argc = 0; + + if (data) { + mycmd = strdup(data); + argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (!argc || !strcasecmp(argv[0], "help")) { + stream->write_function(stream, "%s\n", isdn_api_usage); + goto done; + } + else if (!strcasecmp(argv[0], "dump")) { + ftdm_isdn_data_t *isdn_data = NULL; + ftdm_span_t *span = NULL; + int span_id = 0; + + /* dump calls */ + + if (argc < 3) { + stream->write_function(stream, "-ERR not enough arguments.\n"); + goto done; + } + + span_id = atoi(argv[1]); + + if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { + isdn_data = span->signal_data; + } else { + stream->write_function(stream, "-ERR invalid span.\n"); + goto done; + } + + if (!strcasecmp(argv[2], "calls")) { + /* dump all calls to log */ + Q931DumpAllCalls(&isdn_data->q931); + stream->write_function(stream, "+OK call information dumped to log\n"); + goto done; + } + } + else if (!strcasecmp(argv[0], "loglevel")) { + ftdm_isdn_data_t *isdn_data = NULL; + ftdm_span_t *span = NULL; + int span_id = 0; + int layer = 0; + int level = 0; + + /* loglevel [level] */ + + if (argc < 3) { + stream->write_function(stream, "-ERR not enough arguments.\n"); + goto done; + } + + span_id = atoi(argv[1]); + + if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { + isdn_data = span->signal_data; + } else { + stream->write_function(stream, "-ERR invalid span.\n"); + goto done; + } + + if (!strcasecmp(argv[2], "q921")) { + layer = 0x01; + } else if(!strcasecmp(argv[2], "q931")) { + layer = 0x02; + } else if (!strcasecmp(argv[2], "all")) { + layer = 0x03; + } else { + stream->write_function(stream, "-ERR invalid layer\n"); + goto done; + } + + if (argc > 3) { + /* set loglevel */ + if ((level = parse_loglevel(argv[3])) < 0) { + stream->write_function(stream, "-ERR invalid loglevel\n"); + goto done; + } + + if (layer & 0x01) { /* q921 */ + Q921SetLogLevel(&isdn_data->q921, (Q921LogLevel_t)level); + } + if (layer & 0x02) { /* q931 */ + Q931SetLogLevel(&isdn_data->q931, (Q931LogLevel_t)level); + } + stream->write_function(stream, "+OK loglevel set"); + } else { + /* get loglevel */ + if (layer & 0x01) { + stream->write_function(stream, "Q.921 loglevel: %s\n", + Q921GetLogLevelName(&isdn_data->q921)); + } + if (layer & 0x02) { + stream->write_function(stream, "Q.931 loglevel: %s\n", + Q931GetLogLevelName(&isdn_data->q931)); + } + stream->write_function(stream, "+OK"); + } + goto done; + } +#ifdef HAVE_PCAP + else if (!strcasecmp(argv[0], "capture")) { + ftdm_isdn_data_t *isdn_data = NULL; + ftdm_span_t *span = NULL; + int span_id = 0; + + /* capture [q931only] */ + /* capture */ + + if (argc < 3) { + stream->write_function(stream, "-ERR not enough arguments.\n"); + goto done; + } + + span_id = atoi(argv[1]); + + if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { + isdn_data = span->signal_data; + } else { + stream->write_function(stream, "-ERR invalid span.\n"); + goto done; + } + + if (!strcasecmp(argv[2], "start")) { + char *filename = NULL; + + if (argc < 4) { + stream->write_function(stream, "-ERR not enough parameters.\n"); + goto done; + } + + if (isdn_pcap_is_open(isdn_data)) { + stream->write_function(stream, "-ERR capture is already running.\n"); + goto done; + } + + filename = argv[3]; + + if (isdn_pcap_open(isdn_data, filename) != FTDM_SUCCESS) { + stream->write_function(stream, "-ERR failed to open capture file.\n"); + goto done; + } + + if (argc > 4 && !strcasecmp(argv[4], "q931only")) { + isdn_data->flags |= FTDM_ISDN_CAPTURE_L3ONLY; + } + isdn_pcap_start(isdn_data); + + stream->write_function(stream, "+OK capture started.\n"); + goto done; + } + else if(!strcasecmp(argv[2], "stop")) { + + if (!isdn_pcap_is_open(isdn_data)) { + stream->write_function(stream, "-ERR capture is not running.\n"); + goto done; + } + + isdn_pcap_stop(isdn_data); + isdn_pcap_close(isdn_data); + + stream->write_function(stream, "+OK capture stopped.\n"); + goto done; + } + else if(!strcasecmp(argv[2], "suspend")) { + + if (!isdn_pcap_is_open(isdn_data)) { + stream->write_function(stream, "-ERR capture is not running.\n"); + goto done; + } + isdn_pcap_stop(isdn_data); + + stream->write_function(stream, "+OK capture suspended.\n"); + goto done; + } + else if(!strcasecmp(argv[2], "resume")) { + + if (!isdn_pcap_is_open(isdn_data)) { + stream->write_function(stream, "-ERR capture is not running.\n"); + goto done; + } + isdn_pcap_start(isdn_data); + + stream->write_function(stream, "+OK capture resumed.\n"); + goto done; + } + else { + stream->write_function(stream, "-ERR wrong action.\n"); + goto done; + } + } +#endif + else { + stream->write_function(stream, "-ERR invalid command.\n"); + } +done: + ftdm_safe_free(mycmd); + + return FTDM_SUCCESS; +} + +static FIO_SIG_CONFIGURE_FUNCTION(isdn_configure_span) { uint32_t i, x = 0; - ftdm_channel_t *dchans[2] = {0}; + ftdm_channel_t *dchans[2] = { 0 }; ftdm_isdn_data_t *isdn_data; const char *tonemap = "us"; char *var, *val; @@ -2195,40 +2574,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) int32_t digit_timeout = 0; int q921loglevel = -1; int q931loglevel = -1; -#ifdef HAVE_LIBPCAP - int q931topcap = -1; /*Q931ToPcap*/ - int openPcap = 0; /*Flag: open Pcap file please*/ -#endif if (span->signal_type) { -#ifdef HAVE_LIBPCAP - /*Q931ToPcap: Get the content of the q931topcap and pcapfilename args given by mod_freetdm */ - while((var = va_arg(ap, char *))) { - if (!strcasecmp(var, "q931topcap")) { - q931topcap = va_arg(ap, int); - if(q931topcap==1) { - /*PCAP on*/; - openPcap=1; - } else if (q931topcap==0) { - /*PCAP off*/ - if (closePcapFile() != FTDM_SUCCESS) return FTDM_FAIL; - do_q931ToPcap=0; - return FTDM_SUCCESS; - } - } - if (!strcasecmp(var, "pcapfilename")) { - /*Put filename into global var*/ - pcapfn = va_arg(ap, char*); - } - } - /*We know now, that user wants to enable Q931ToPcap and what file name he wants, so open it please*/ - if(openPcap==1){ - if(openPcapFile() != FTDM_SUCCESS) return FTDM_FAIL; - do_q931ToPcap=1; - return FTDM_SUCCESS; - } - /*Q931ToPcap done*/ -#endif snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling [%d].", span->signal_type); return FTDM_FAIL; } @@ -2237,34 +2584,33 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type)); span->trunk_type = FTDM_TRUNK_T1; } - + for(i = 1; i <= span->chan_count; i++) { if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) { if (x > 1) { snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!"); return FTDM_FAIL; - } else { - if (ftdm_channel_open(span->span_id, i, &dchans[x]) == FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id); - dchans[x]->state = FTDM_CHANNEL_STATE_UP; - x++; - } + } + + if (ftdm_channel_open(span->span_id, i, &dchans[x]) == FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id); + dchans[x]->state = FTDM_CHANNEL_STATE_UP; + x++; } } } - if (!x) { snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!"); return FTDM_FAIL; } - isdn_data = ftdm_malloc(sizeof(*isdn_data)); + isdn_data = malloc(sizeof(*isdn_data)); assert(isdn_data != NULL); memset(isdn_data, 0, sizeof(*isdn_data)); - + isdn_data->mode = Q931_TE; - dialect = Q931_Dialect_National; - + dialect = Q931_Dialect_Q931; + while((var = va_arg(ap, char *))) { if (!strcasecmp(var, "mode")) { if (!(val = va_arg(ap, char *))) { @@ -2275,8 +2621,9 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) if (!(val = va_arg(ap, char *))) { break; } - dialect = q931_str2Q931Dialect_type(val); + dialect = parse_dialect(val); if (dialect == Q931_Dialect_Count) { + snprintf(span->last_error, sizeof(span->last_error), "Invalid/unknown dialect [%s]!", val); return FTDM_FAIL; } } else if (!strcasecmp(var, "opts")) { @@ -2315,7 +2662,6 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) } } - if (!digit_timeout) { digit_timeout = DEFAULT_DIGIT_TIMEOUT; } @@ -2328,7 +2674,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) if (isdn_data->mode == Q931_NT) { ftdm_isdn_bchan_data_t *data; - data = ftdm_malloc((span->chan_count - 1) * sizeof(ftdm_isdn_bchan_data_t)); + data = malloc(span->chan_count * sizeof(ftdm_isdn_bchan_data_t)); if (!data) { return FTDM_FAIL; } @@ -2340,15 +2686,13 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) } } } - - span->start = ftdm_isdn_start; - span->stop = ftdm_isdn_stop; - span->signal_cb = sig_cb; + + isdn_data->sig_cb = sig_cb; isdn_data->dchans[0] = dchans[0]; isdn_data->dchans[1] = dchans[1]; - isdn_data->dchan = isdn_data->dchans[0]; + isdn_data->dchan = isdn_data->dchans[0]; isdn_data->digit_timeout = digit_timeout; - + Q921_InitTrunk(&isdn_data->q921, 0, 0, @@ -2358,55 +2702,104 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span) ftdm_isdn_921_21, (Q921Tx23CB_t)ftdm_isdn_921_23, span, - &isdn_data->q931); + span); - Q921SetLogCB(&isdn_data->q921, &ftdm_isdn_q921_log, isdn_data); + Q921SetLogCB(&isdn_data->q921, &ftdm_isdn_q921_log, span); Q921SetLogLevel(&isdn_data->q921, (Q921LogLevel_t)q921loglevel); - - Q931Api_InitTrunk(&isdn_data->q931, + + Q931InitTrunk(&isdn_data->q931, dialect, isdn_data->mode, span->trunk_type, ftdm_isdn_931_34, (Q931Tx32CB_t)q931_rx_32, ftdm_isdn_931_err, - &isdn_data->q921, + span, span); - Q931SetLogCB(&isdn_data->q931, &ftdm_isdn_q931_log, isdn_data); + Q931SetLogCB(&isdn_data->q931, &ftdm_isdn_q931_log, span); Q931SetLogLevel(&isdn_data->q931, (Q931LogLevel_t)q931loglevel); - isdn_data->q931.autoRestartAck = 1; - isdn_data->q931.autoConnectAck = 0; - isdn_data->q931.autoServiceAck = 1; - span->signal_data = isdn_data; - span->signal_type = FTDM_SIGTYPE_ISDN; + /* Register new event hander CB */ + Q931SetCallEventCB(&isdn_data->q931, ftdm_isdn_call_event, span); + + /* TODO: hmm, maybe drop the "Trunk" prefix */ + Q931TrunkSetAutoRestartAck(&isdn_data->q931, 1); + Q931TrunkSetAutoConnectAck(&isdn_data->q931, 1); + Q931TrunkSetAutoServiceAck(&isdn_data->q931, 1); + Q931TrunkSetStatusEnquiry(&isdn_data->q931, 0); + + span->state_map = &isdn_state_map; + span->signal_data = isdn_data; + span->signal_type = FTDM_SIGTYPE_ISDN; + span->start = ftdm_isdn_start; + span->stop = ftdm_isdn_stop; span->outgoing_call = isdn_outgoing_call; + span->get_channel_sig_status = isdn_get_channel_sig_status; + span->get_span_sig_status = isdn_get_span_sig_status; + +#ifdef __TODO__ if ((isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) { span->channel_request = isdn_channel_request; - ftdm_set_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID); + span->flags |= FTDM_SPAN_SUGGEST_CHAN_ID; } - span->state_map = &isdn_state_map; - +#endif ftdm_span_load_tones(span, tonemap); return FTDM_SUCCESS; } /** - * \brief FreeTDM ISDN signaling module definition + * ISDN module io interface + * \note This is really ugly... */ -EX_DECLARE_DATA ftdm_module_t ftdm_module = { - "isdn", - NULL, - close_pcap, - ftdm_isdn_init, - ftdm_isdn_configure_span, - NULL +static ftdm_io_interface_t isdn_interface = { + .name = "isdn", + .api = isdn_api }; +/** + * \brief ISDN module io interface init callback + */ +static FIO_IO_LOAD_FUNCTION(isdn_io_load) +{ + assert(fio != NULL); + *fio = &isdn_interface; + + return FTDM_SUCCESS; +} + +/** + * \brief ISDN module load callback + */ +static FIO_SIG_LOAD_FUNCTION(isdn_load) +{ + Q931Initialize(); + + Q921SetGetTimeCB(ftdm_time_now); + Q931SetGetTimeCB(ftdm_time_now); + + return FTDM_SUCCESS; +} + +/** + * \brief ISDN module shutdown callback + */ +static FIO_SIG_UNLOAD_FUNCTION(isdn_unload) +{ + return FTDM_SUCCESS; +}; + +ftdm_module_t ftdm_module = { + .name = "isdn", + .io_load = isdn_io_load, + .io_unload = NULL, + .sig_load = isdn_load, + .sig_unload = isdn_unload, + .sig_configure = isdn_configure_span +}; /* For Emacs: * Local Variables: @@ -2416,5 +2809,5 @@ EX_DECLARE_DATA ftdm_module_t ftdm_module = { * c-basic-offset:4 * End: * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: */ diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.h similarity index 83% rename from libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h rename to libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.h index 7168abeb3b..95eee90887 100644 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.h @@ -1,23 +1,23 @@ /* * Copyright (c) 2007, Anthony Minessale II * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * * Neither the name of the original author; nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * - * + * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -33,7 +33,6 @@ #ifndef FTDM_ISDN_H #define FTDM_ISDN_H -#include "freetdm.h" #define DEFAULT_DIGIT_TIMEOUT 10000 /* default overlap timeout: 10 seconds */ @@ -42,17 +41,23 @@ typedef enum { FTDM_ISDN_OPT_NONE = 0, FTDM_ISDN_OPT_SUGGEST_CHANNEL = (1 << 0), FTDM_ISDN_OPT_OMIT_DISPLAY_IE = (1 << 1), /*!< Do not send Caller name in outgoing SETUP message (= Display IE) */ - FTDM_ISDN_OPT_DISABLE_TONES = (1 << 2), /*!< Disable tone generating thread (NT mode) */ + FTDM_ISDN_OPT_DISABLE_TONES = (1 << 2), /*!< Disable tone generating thread (NT mode) */ FTDM_ISDN_OPT_MAX = (2 << 0) } ftdm_isdn_opts_t; typedef enum { - FTDM_ISDN_RUNNING = (1 << 0), - FTDM_ISDN_TONES_RUNNING = (1 << 1), - FTDM_ISDN_STOP = (1 << 2) + FTDM_ISDN_RUNNING = (1 << 0), + FTDM_ISDN_TONES_RUNNING = (1 << 1), + FTDM_ISDN_STOP = (1 << 2), + + FTDM_ISDN_CAPTURE = (1 << 3), + FTDM_ISDN_CAPTURE_L3ONLY = (1 << 4) } ftdm_isdn_flag_t; +#ifdef HAVE_PCAP +struct pcap_context; +#endif struct ftdm_isdn_data { Q921Data_t q921; @@ -60,6 +65,7 @@ struct ftdm_isdn_data { ftdm_channel_t *dchan; ftdm_channel_t *dchans[2]; struct ftdm_sigmsg sigmsg; + fio_signal_cb_t sig_cb; uint32_t flags; int32_t mode; int32_t digit_timeout; @@ -67,6 +73,9 @@ struct ftdm_isdn_data { ftdm_caller_data_t *outbound_crv[32768]; ftdm_channel_t *channels_local_crv[32768]; ftdm_channel_t *channels_remote_crv[32768]; +#ifdef HAVE_PCAP + struct pcap_context *pcap; +#endif }; typedef struct ftdm_isdn_data ftdm_isdn_data_t; @@ -75,7 +84,7 @@ typedef struct ftdm_isdn_data ftdm_isdn_data_t; /* b-channel private data */ struct ftdm_isdn_bchan_data { - L2ULONG digit_timeout; + int32_t digit_timeout; }; typedef struct ftdm_isdn_bchan_data ftdm_isdn_bchan_data_t; @@ -91,6 +100,6 @@ typedef struct ftdm_isdn_bchan_data ftdm_isdn_bchan_data_t; * c-basic-offset:4 * End: * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: */ diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj deleted file mode 100644 index 5c8d2efc0f..0000000000 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -