Skip to content
Snippets Groups Projects
chan_dahdi.c 593 KiB
Newer Older
Mark Spencer's avatar
Mark Spencer committed
/*
 * Asterisk -- An open source telephony toolkit.
Mark Spencer's avatar
Mark Spencer committed
 *
 * Copyright (C) 1999 - 2008, Digium, Inc.
Mark Spencer's avatar
Mark Spencer committed
 *
 * Mark Spencer <markster@digium.com>
Mark Spencer's avatar
Mark Spencer committed
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
Mark Spencer's avatar
Mark Spencer committed
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

 *
 * \author Mark Spencer <markster@digium.com>
Richard Mudgett's avatar
Richard Mudgett committed
 *
 * Connects to the DAHDI telephony library as well as
Russell Bryant's avatar
Russell Bryant committed
 * libpri. Libpri is optional and needed only if you are
 * going to use ISDN connections.
 *
 * You need to install libraries before you attempt to compile
Russell Bryant's avatar
Russell Bryant committed
 *
 * \ingroup channel_drivers
 * \todo Deprecate the "musiconhold" configuration option post 1.4
/*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
Andrew Latham's avatar
Andrew Latham committed
 * \addtogroup configuration_file
 */

/*! \page chan_dahdi.conf chan_dahdi.conf
 * \verbinclude chan_dahdi.conf.sample
 */

	<use type="module">res_smdi</use>
	<use type="external">pri</use>
	<use type="external">ss7</use>
	<use type="external">openr2</use>
	<support_level>core</support_level>
#if defined(__NetBSD__) || defined(__FreeBSD__)
#include <pthread.h>
Timo Teräs's avatar
Timo Teräs committed
#include <signal.h>
Mark Spencer's avatar
Mark Spencer committed
#include <math.h>
/* Analog signaling is currently still present in chan_dahdi for use with
 * radio. Sig_analog does not currently handle any radio operations. If
 * radio only uses analog signaling, then the radio handling logic could
 * be placed in sig_analog and the duplicated code could be removed.
 */
#ifndef PRI_RESTART
#error "Upgrade your libpri"
Mark Spencer's avatar
Mark Spencer committed
#endif
#endif	/* defined(HAVE_PRI) */
#if defined(HAVE_SS7)
#include "sig_ss7.h"
#if !defined(LIBSS7_ABI_COMPATIBILITY)
#error "Upgrade your libss7"
#elif LIBSS7_ABI_COMPATIBILITY != 2
#error "Your installed libss7 is not compatible"
#endif
#endif	/* defined(HAVE_SS7) */
/* put this here until sig_mfcr2 comes along */
#define SIG_MFCR2_MAX_CHANNELS	672		/*!< No more than a DS3 per trunk group */
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/file.h"
#include "asterisk/ulaw.h"
#include "asterisk/alaw.h"
#include "asterisk/callerid.h"
#include "asterisk/adsi.h"
#include "asterisk/cli.h"
#include "asterisk/pickup.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/say.h"
#include "asterisk/tdd.h"
#include "asterisk/mwi.h"
#include "asterisk/dsp.h"
#include "asterisk/astdb.h"
#include "asterisk/manager.h"
#include "asterisk/causes.h"
#include "asterisk/term.h"
#include "asterisk/utils.h"
#include "asterisk/transcap.h"
#include "asterisk/stringfields.h"
Jeff Peeler's avatar
Jeff Peeler committed
#include "asterisk/devicestate.h"
#include "asterisk/paths.h"
#include "asterisk/ccss.h"
#include "asterisk/features_config.h"
#include "asterisk/bridge.h"
#include "asterisk/stasis_channels.h"
#include "chan_dahdi.h"
#include "dahdi/bridge_native_dahdi.h"
/*** DOCUMENTATION
	<application name="DAHDISendKeypadFacility" language="en_US">
		<synopsis>
			Send digits out of band over a PRI.
		</synopsis>
		<syntax>
			<parameter name="digits" required="true" />
		</syntax>
		<description>
			<para>This application will send the given string of digits in a Keypad
			Facility IE over the current channel.</para>
		</description>
	</application>
	<application name="DAHDISendCallreroutingFacility" language="en_US">
		<synopsis>
			Send an ISDN call rerouting/deflection facility message.
		</synopsis>
			<parameter name="destination" required="true">
Richard Mudgett's avatar
Richard Mudgett committed
				<para>Destination number.</para>
			</parameter>
			<parameter name="original">
				<para>Original called number.</para>
			</parameter>
			<parameter name="reason">
				<para>Diversion reason, if not specified defaults to <literal>unknown</literal></para>
			</parameter>
		</syntax>
		<description>
			<para>This application will send an ISDN switch specific call
			rerouting/deflection facility message over the current channel.
			Supported switches depend upon the version of libpri in use.</para>
		</description>
	</application>
	<application name="DAHDIAcceptR2Call" language="en_US">
		<synopsis>
			Accept an R2 call if its not already accepted (you still need to answer it)
		</synopsis>
		<syntax>
			<parameter name="charge" required="true">
				<para>Yes or No.</para>
				<para>Whether you want to accept the call with charge or without charge.</para>
			</parameter>
		</syntax>
		<description>
			<para>This application will Accept the R2 call either with charge or no charge.</para>
		</description>
	</application>
	<info name="CHANNEL" language="en_US" tech="DAHDI">
		<enumlist>
			<enum name="dahdi_channel">
				<para>R/O DAHDI channel related to this channel.</para>
			</enum>
			<enum name="dahdi_span">
				<para>R/O DAHDI span related to this channel.</para>
			</enum>
			<enum name="dahdi_group">
				<para>R/O DAHDI logical group related to this channel.</para>
			</enum>
			<enum name="dahdi_type">
				<para>R/O DAHDI channel type, one of:</para>
				<enumlist>
					<enum name="analog" />
					<enum name="mfc/r2" />
					<enum name="pri" />
					<enum name="pseudo" />
					<enum name="ss7" />
				</enumlist>
			</enum>
			<enum name="keypad_digits">
				<para>R/O PRI Keypad digits that came in with the SETUP message.</para>
			</enum>
			<enum name="reversecharge">
				<para>R/O PRI Reverse Charging Indication, one of:</para>
				<enumlist>
					<enum name="-1"> <para>None</para></enum>
					<enum name=" 1"> <para>Reverse Charging Requested</para></enum>
				</enumlist>
			</enum>
			<enum name="no_media_path">
				<para>R/O PRI Nonzero if the channel has no B channel.
				The channel is either on hold or a call waiting call.</para>
			</enum>
			<enum name="buffers">
				<para>W/O Change the channel's buffer policy (for the current call only)</para>
				<para>This option takes two arguments:</para>
				<para>	Number of buffers,</para>
				<para>	Buffer policy being one of:</para>
				<para>	    <literal>full</literal></para>
				<para>	    <literal>immediate</literal></para>
				<para>	    <literal>half</literal></para>
			</enum>
			<enum name="echocan_mode">
				<para>W/O Change the configuration of the active echo
				canceller on the channel (if any), for the current call
				only.</para>
				<para>Possible values are:</para>
				<para>	<literal>on</literal>	Normal mode (the echo canceller is actually reinitalized)</para>
				<para>	<literal>off</literal>	Disabled</para>
				<para>	<literal>fax</literal>	FAX/data mode (NLP disabled if possible, otherwise
					completely disabled)</para>
				<para>	<literal>voice</literal>	Voice mode (returns from FAX mode, reverting the changes that were made)</para>
			</enum>
		</enumlist>
	</info>
	<manager name="DAHDITransfer" language="en_US">
		<synopsis>
			Transfer DAHDI Channel.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="DAHDIChannel" required="true">
				<para>DAHDI channel number to transfer.</para>
			<para>Simulate a flash hook event by the user connected to the channel.</para>
			<note><para>Valid only for analog channels.</para></note>
		</description>
	</manager>
	<manager name="DAHDIHangup" language="en_US">
		<synopsis>
			Hangup DAHDI Channel.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="DAHDIChannel" required="true">
				<para>DAHDI channel number to hangup.</para>
			<para>Simulate an on-hook event by the user connected to the channel.</para>
			<note><para>Valid only for analog channels.</para></note>
		</description>
	</manager>
	<manager name="DAHDIDialOffhook" language="en_US">
		<synopsis>
			Dial over DAHDI channel while offhook.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="DAHDIChannel" required="true">
				<para>DAHDI channel number to dial digits.</para>
			</parameter>
			<parameter name="Number" required="true">
				<para>Digits to dial.</para>
			</parameter>
			<para>Generate DTMF control frames to the bridged peer.</para>
		</description>
	</manager>
	<manager name="DAHDIDNDon" language="en_US">
		<synopsis>
			Toggle DAHDI channel Do Not Disturb status ON.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="DAHDIChannel" required="true">
				<para>DAHDI channel number to set DND on.</para>
			</parameter>
			<para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> on".</para>
			<note><para>Feature only supported by analog channels.</para></note>
		</description>
	</manager>
	<manager name="DAHDIDNDoff" language="en_US">
		<synopsis>
			Toggle DAHDI channel Do Not Disturb status OFF.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="DAHDIChannel" required="true">
				<para>DAHDI channel number to set DND off.</para>
			</parameter>
			<para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> off".</para>
			<note><para>Feature only supported by analog channels.</para></note>
		</description>
	</manager>
	<manager name="DAHDIShowChannels" language="en_US">
		<synopsis>
			Show status of DAHDI channels.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="DAHDIChannel">
				<para>Specify the specific channel number to show.  Show all channels if zero or not present.</para>
			<para>Similar to the CLI command "dahdi show channels".</para>
		</description>
	</manager>
	<manager name="DAHDIRestart" language="en_US">
		<synopsis>
			Fully Restart DAHDI channels (terminates calls).
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
		</syntax>
		<description>
			<para>Equivalent to the CLI command "dahdi restart".</para>
	<manager name="PRIShowSpans" language="en_US">
		<synopsis>
			Show status of PRI spans.
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="Span">
				<para>Specify the specific span to show.  Show all spans if zero or not present.</para>
			</parameter>
		</syntax>
		<description>
			<para>Similar to the CLI command "pri show spans".</para>
		</description>
	</manager>
	<manager name="PRIDebugSet" language="en_US">
		<synopsis>
			Set PRI debug levels for a span
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="Span" required="true">
				<para>Which span to affect.</para>
			</parameter>
			<parameter name="Level" required="true">
				<para>What debug level to set. May be a numerical value or a text value from the list below</para>
				<enumlist>
					<enum name="off" />
					<enum name="on" />
					<enum name="hex" />
					<enum name="intense" />
				</enumlist>
			</parameter>
		</syntax>
		<description>
			<para>Equivalent to the CLI command "pri set debug &lt;level&gt; span &lt;span&gt;".</para>
		</description>
	</manager>
	<manager name="PRIDebugFileSet" language="en_US">
		<synopsis>
			Set the file used for PRI debug message output
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
			<parameter name="File" required="true">
				<para>Path of file to write debug output.</para>
			</parameter>
		</syntax>
		<description>
			<para>Equivalent to the CLI command "pri set debug file &lt;output-file&gt;"</para>
		</description>
	</manager>
	<manager name="PRIDebugFileUnset" language="en_US">
		<synopsis>
			Disables file output for PRI debug messages
		</synopsis>
		<syntax>
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
		</syntax>
	</manager>
	<managerEvent language="en_US" name="AlarmClear">
		<managerEventInstance class="EVENT_FLAG_SYSTEM">
			<synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
			<syntax>
				<parameter name="DAHDIChannel">
					<para>The DAHDI channel on which the alarm was cleared.</para>
					<note><para>This is not an Asterisk channel identifier.</para></note>
				</parameter>
			</syntax>
		</managerEventInstance>
	</managerEvent>
	<managerEvent language="en_US" name="SpanAlarmClear">
		<managerEventInstance class="EVENT_FLAG_SYSTEM">
			<synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
			<syntax>
				<parameter name="Span">
					<para>The span on which the alarm was cleared.</para>
				</parameter>
			</syntax>
		</managerEventInstance>
	</managerEvent>
	<managerEvent language="en_US" name="DNDState">
		<managerEventInstance class="EVENT_FLAG_SYSTEM">
			<synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
			<syntax>
				<parameter name="DAHDIChannel">
					<para>The DAHDI channel on which DND status changed.</para>
					<note><para>This is not an Asterisk channel identifier.</para></note>
				</parameter>
				<parameter name="Status">
					<enumlist>
						<enum name="enabled"/>
						<enum name="disabled"/>
					</enumlist>
				</parameter>
			</syntax>
		</managerEventInstance>
	</managerEvent>
	<managerEvent language="en_US" name="Alarm">
		<managerEventInstance class="EVENT_FLAG_SYSTEM">
			<synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
			<syntax>
				<parameter name="DAHDIChannel">
					<para>The channel on which the alarm occurred.</para>
					<note><para>This is not an Asterisk channel identifier.</para></note>
				</parameter>
				<parameter name="Alarm">
					<para>A textual description of the alarm that occurred.</para>
				</parameter>
			</syntax>
		</managerEventInstance>
	</managerEvent>
	<managerEvent language="en_US" name="SpanAlarm">
		<managerEventInstance class="EVENT_FLAG_SYSTEM">
			<synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
			<syntax>
				<parameter name="Span">
					<para>The span on which the alarm occurred.</para>
				</parameter>
				<parameter name="Alarm">
					<para>A textual description of the alarm that occurred.</para>
				</parameter>
			</syntax>
		</managerEventInstance>
	</managerEvent>
	<managerEvent language="en_US" name="DAHDIChannel">
		<managerEventInstance class="EVENT_FLAG_CALL">
			<synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
			<syntax>
				<channel_snapshot/>
				<parameter name="DAHDIGroup">
					<para>The DAHDI logical group associated with this channel.</para>
				</parameter>
				<parameter name="DAHDISpan">
					<para>The DAHDI span associated with this channel.</para>
				</parameter>
				<parameter name="DAHDIChannel">
					<para>The DAHDI channel associated with this channel.</para>
				</parameter>
			</syntax>
		</managerEventInstance>
	</managerEvent>
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
static const char * const lbostr[] = {
"0 db (CSU)/0-133 feet (DSX-1)",
"133-266 feet (DSX-1)",
"266-399 feet (DSX-1)",
"399-533 feet (DSX-1)",
"533-655 feet (DSX-1)",
"-7.5db (CSU)",
"-15db (CSU)",
"-22.5db (CSU)"
};

/*! Global jitterbuffer configuration - by default, jb is disabled
 *  \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
static struct ast_jb_conf default_jbconf =
{
	.flags = 0,
	.max_size = 200,
	.resync_threshold = 1000,
	.impl = "fixed",
	.target_extra = 40,
Richard Mudgett's avatar
Richard Mudgett committed
/*!
Russell Bryant's avatar
Russell Bryant committed
 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
Mark Spencer's avatar
Mark Spencer committed
 * the user hangs up to reset the state machine so ring works properly.
 * This is used to be able to support kewlstart by putting the zhone in
 * groundstart mode since their forward disconnect supervision is entirely
 * broken even though their documentation says it isn't and their support
 * is entirely unwilling to provide any assistance with their channel banks
 * even though their web site says they support their products for life.
 */
Mark Spencer's avatar
Mark Spencer committed
/* #define ZHONE_HACK */
Russell Bryant's avatar
Russell Bryant committed
/*! \brief Typically, how many rings before we should send Caller*ID */
Mark Spencer's avatar
Mark Spencer committed
#define DEFAULT_CIDRINGS 1

#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
Russell Bryant's avatar
Russell Bryant committed
/*! \brief Signaling types that need to use MF detection should be placed in this macro */
Richard Mudgett's avatar
Richard Mudgett committed
#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
static const char tdesc[] = "DAHDI Telephony"
#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
	" w/"
	#if defined(HAVE_PRI)
		"PRI"
	#endif	/* defined(HAVE_PRI) */
	#if defined(HAVE_SS7)
		#if defined(HAVE_PRI)
		" & "
		#endif	/* defined(HAVE_PRI) */
		"SS7"
	#endif	/* defined(HAVE_SS7) */
	#if defined(HAVE_OPENR2)
		#if defined(HAVE_PRI) || defined(HAVE_SS7)
		" & "
		#endif	/* defined(HAVE_PRI) || defined(HAVE_SS7) */
		"MFC/R2"
	#endif	/* defined(HAVE_OPENR2) */
#endif	/* defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2) */
static const char config[] = "chan_dahdi.conf";

Mark Spencer's avatar
Mark Spencer committed

#define CHAN_PSEUDO	-2
#define CALLPROGRESS_PROGRESS		1
#define CALLPROGRESS_FAX_OUTGOING	2
#define CALLPROGRESS_FAX_INCOMING	4
#define CALLPROGRESS_FAX		(CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)

#define NUM_CADENCE_MAX 25
static int num_cadence = 4;
static int user_has_defined_cadences = 0;

static int has_pseudo;

static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
	{ { 125, 125, 2000, 4000 } },			/*!< Quick chirp followed by normal ring */
	{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
	{ { 125, 125, 125, 125, 125, 4000 } },	/*!< Three short bursts */
	{ { 1000, 500, 2500, 5000 } },	/*!< Long ring */
};

/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
 * is 1, the second pause is 2 and so on.
 */

static int cidrings[NUM_CADENCE_MAX] = {
	2,										/*!< Right after first long ring */
	4,										/*!< Right after long part */
	3,										/*!< After third chirp */
	2,										/*!< Second spell */
};

/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};

#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
			(p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))

#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)

static char defaultcic[64] = "";
static char defaultozz[64] = "";
/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
static char mwimonitornotify[PATH_MAX] = "";
#ifndef HAVE_DAHDI_LINEREVERSE_VMWI
static char progzone[10] = "";
static int usedistinctiveringdetection = 0;
static int distinctiveringaftercid = 0;
static int numbufs = 4;

static int dtmfcid_level = 256;
#define REPORT_SPAN_ALARMS    2
static int report_alarms = REPORT_CHANNEL_ALARMS;

static int pridebugfd = -1;
static char pridebugfilename[1024] = "";
/*! \brief Protect the interface list (of dahdi_pvt's) */
AST_MUTEX_DEFINE_STATIC(iflock);
static int ifcount = 0;

Russell Bryant's avatar
Russell Bryant committed
/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
Mark Spencer's avatar
Mark Spencer committed
   when it's doing something critical. */
AST_MUTEX_DEFINE_STATIC(monlock);
Russell Bryant's avatar
Russell Bryant committed
/*! \brief This is the thread for the monitor which checks for input on the channels
   which are not currently in use. */
static pthread_t monitor_thread = AST_PTHREADT_NULL;
static ast_cond_t ss_thread_complete;
AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
AST_MUTEX_DEFINE_STATIC(restart_lock);
static int ss_thread_count = 0;
static int num_restart_pending = 0;
Mark Spencer's avatar
Mark Spencer committed

static int restart_monitor(void);

static int dahdi_sendtext(struct ast_channel *c, const char *text);
/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
static inline int dahdi_get_event(int fd)
Mark Spencer's avatar
Mark Spencer committed
{
	int j;
	if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
Mark Spencer's avatar
Mark Spencer committed
	return j;
}

/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
static inline int dahdi_wait_event(int fd)
Mark Spencer's avatar
Mark Spencer committed
{
	i = DAHDI_IOMUX_SIGEVENT;
	if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
	if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
Mark Spencer's avatar
Mark Spencer committed
	return j;
}

/*! Chunk size to read -- we use 20ms chunks to make things happy. */
Mark Spencer's avatar
Mark Spencer committed
#define READ_SIZE 160
Russell Bryant's avatar
Russell Bryant committed
#define MASK_AVAIL		(1 << 0)	/*!< Channel available for PRI use */
#define MASK_INUSE		(1 << 1)	/*!< Channel currently in use */
#define CALLWAITING_SILENT_SAMPLES		((300 * 8) / READ_SIZE) /*!< 300 ms */
#define CALLWAITING_REPEAT_SAMPLES		((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
#define CALLWAITING_SUPPRESS_SAMPLES	((100 * 8) / READ_SIZE) /*!< 100 ms */
#define CIDCW_EXPIRE_SAMPLES			((500 * 8) / READ_SIZE) /*!< 500 ms */
#define MIN_MS_SINCE_FLASH				((2000) )	/*!< 2000 ms */
#define DEFAULT_RINGT 					((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
Richard Mudgett's avatar
Richard Mudgett committed
/*!
 * \brief Configured ring timeout base.
 * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
 */
static int ringt_base = DEFAULT_RINGT;
#if defined(HAVE_SS7)
	struct sig_ss7_linkset ss7;
static struct dahdi_ss7 linksets[NUM_SPANS];
static int cur_slc = -1;
static int cur_linkset = -1;
static int cur_pointcode = -1;
static int cur_cicbeginswith = -1;
static int cur_adjpointcode = -1;
static int cur_networkindicator = -1;
static int cur_defaultdpc = -1;
#endif	/* defined(HAVE_SS7) */
#ifdef HAVE_OPENR2
struct dahdi_mfcr2_conf {
	openr2_variant_t variant;
	int mfback_timeout;
	int metering_pulse_timeout;
	int max_ani;
	int max_dnis;
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
	int dtmf_time_on;
	int dtmf_time_off;
#endif
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
	int dtmf_end_timeout;
#endif
	signed int get_ani_first:2;
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
	signed int skip_category_request:2;
	unsigned int call_files:1;
	unsigned int allow_collect_calls:1;
	unsigned int charge_calls:1;
	unsigned int accept_on_offer:1;
	unsigned int forced_release:1;
	unsigned int double_answer:1;
	signed int immediate_accept:2;
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
	signed int dtmf_dialing:2;
	signed int dtmf_detection:2;
#endif
	char logdir[OR2_MAX_PATH];
	char r2proto_file[OR2_MAX_PATH];
	openr2_log_level_t loglevel;
	openr2_calling_party_category_t category;
};

/* MFC-R2 pseudo-link structure */
struct dahdi_mfcr2 {
	pthread_t r2master;		       /*!< Thread of master */
	openr2_context_t *protocol_context;    /*!< OpenR2 context handle */
	struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS];     /*!< Member channel pvt structs */
	int numchans;                          /*!< Number of channels in this R2 block */
	struct dahdi_mfcr2_conf conf;         /*!< Configuration used to setup this pseudo-link */
};

/* malloc'd array of malloc'd r2links */
/* how many r2links have been malloc'd */

#endif /* HAVE_OPENR2 */

	int dchannels[SIG_PRI_NUM_DCHANS];		/*!< What channel are the dchannels on */
	int mastertrunkgroup;					/*!< What trunk group is our master */
Russell Bryant's avatar
Russell Bryant committed
	int prilogicalspan;						/*!< Logical span number within trunk group */
static struct dahdi_pri pris[NUM_SPANS];
#if defined(HAVE_PRI_CCSS)
/*! DAHDI PRI CCSS agent and monitor type name. */
static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
#endif	/* defined(HAVE_PRI_CCSS) */

Russell Bryant's avatar
Russell Bryant committed
/*! Shut up the compiler */
Mark Spencer's avatar
Mark Spencer committed
#endif

/* Polarity states */
#define POLARITY_IDLE   0
#define POLARITY_REV    1

Mark Spencer's avatar
Mark Spencer committed
	"Real",
	"Callwait",
	"Threeway"
};

static struct dahdi_pvt *iflist = NULL;	/*!< Main interface list start */
static struct dahdi_pvt *ifend = NULL;	/*!< Main interface list end */
struct doomed_pri {
	struct sig_pri_span *pri;
	AST_LIST_ENTRY(doomed_pri) list;
};
static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);

static void pri_destroy_span(struct sig_pri_span *pri);

static struct dahdi_parms_pseudo {
	int buf_no;					/*!< Number of buffers */
	int buf_policy;				/*!< Buffer policy */
	int faxbuf_no;              /*!< Number of Fax buffers */
	int faxbuf_policy;          /*!< Fax buffer policy */
} dahdi_pseudo_parms;
#endif	/* defined(HAVE_PRI) */

/*! \brief Channel configuration from chan_dahdi.conf .
 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
 * Generally there is a field here for every possible configuration item.
 *
 * The state of fields is saved along the parsing and whenever a 'channel'
Richard Mudgett's avatar
Richard Mudgett committed
 * statement is reached, the current dahdi_chan_conf is used to configure the
 * \see dahdi_chan_init for the default values.
struct dahdi_chan_conf {
	struct dahdi_pvt chan;
#if defined(HAVE_SS7)
#endif	/* defined(HAVE_SS7) */

#ifdef HAVE_OPENR2
	struct dahdi_mfcr2_conf mfcr2;
#endif
	int is_sig_auto; /*!< Use channel signalling from DAHDI? */
	/*! Continue configuration even if a channel is not there. */
	int ignore_failed_channels;
Richard Mudgett's avatar
Richard Mudgett committed
	/*!
	 * \brief The serial port to listen for SMDI data on
	 * \note Set from the "smdiport" string read in from chan_dahdi.conf
	 */
	char smdi_port[SMDI_MAX_FILENAME_LEN];

	/*!
	 * \brief Don't create channels below this number
	 * \note by default is 0 (no limit)
	 */
	int wanted_channels_start;

	/*!
	 * \brief Don't create channels above this number (infinity by default)
	 * \note by default is 0 (special value that means "no limit").
	 */
	int wanted_channels_end;
/*! returns a new dahdi_chan_conf with default values (by-value) */
Richard Mudgett's avatar
Richard Mudgett committed
static struct dahdi_chan_conf dahdi_chan_conf_default(void)
{
	/* recall that if a field is not included here it is initialized
	 * to 0 or equivalent
	 */
			.nsf = PRI_NSF_NONE,
			.switchtype = PRI_SWITCH_NI2,
			.localdialplan = PRI_NATIONAL_ISDN + 1,
			.nodetype = PRI_CPE,
			.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
#if defined(HAVE_PRI_CCSS)
			.cc_ptmp_recall_mode = 1,/* specificRecall */
			.cc_qsig_signaling_link_req = 1,/* retain */
			.cc_qsig_signaling_link_rsp = 1,/* retain */
#endif	/* defined(HAVE_PRI_CCSS) */

			.minunused = 2,
			.idleext = "",
			.idledial = "",
			.internationalprefix = "",
			.nationalprefix = "",
			.localprefix = "",
			.privateprefix = "",
			.unknownprefix = "",
#if defined(HAVE_SS7)
		.ss7.ss7 = {
			.called_nai = SS7_NAI_NATIONAL,
			.calling_nai = SS7_NAI_NATIONAL,
			.internationalprefix = "",
			.nationalprefix = "",
			.subscriberprefix = "",
			.unknownprefix = "",
			.networkroutedprefix = ""
#endif	/* defined(HAVE_SS7) */
#ifdef HAVE_OPENR2
		.mfcr2 = {
			.variant = OR2_VAR_ITU,
			.mfback_timeout = -1,
			.metering_pulse_timeout = -1,
			.max_ani = 10,
			.max_dnis = 4,
			.get_ani_first = -1,
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
			.call_files = 0,
			.allow_collect_calls = 0,
			.charge_calls = 1,
			.accept_on_offer = 1,
			.forced_release = 0,
			.double_answer = 0,
			.immediate_accept = -1,
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
			.dtmf_dialing = -1,
			.dtmf_detection = -1,
			.dtmf_time_on = OR2_DEFAULT_DTMF_ON,
			.dtmf_time_off = OR2_DEFAULT_DTMF_OFF,
#endif
#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
			.dtmf_end_timeout = -1,
#endif
			.logdir = "",
			.r2proto_file = "",
			.loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
			.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
		},
		.chan = {
			.context = "default",
			.cid_num = "",
			.cid_name = "",
			.mohinterpret = "default",
			.mohsuggest = "",
Jeff Peeler's avatar
Jeff Peeler committed
			.parkinglot = "",
			.transfertobusy = 1,

			.cid_signalling = CID_SIG_BELL,
			.cid_start = CID_START_RING,
			.use_callerid = 1,
			.sig = -1,
			.outsigmod = -1,


			.busycount = 3,

			.accountcode = "",

			.mailbox = "",

#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
			.mwisend_fsk = 1,
			.polarityonanswerdelay = 600,

			.sendcalleridafter = DEFAULT_CIDRINGS,
			.buf_policy = DAHDI_POLICY_IMMEDIATE,
			.buf_no = numbufs,
			.usefaxbuffers = 0,
			.cc_params = ast_cc_config_params_init(),
			.firstdigit_timeout = ANALOG_FIRST_DIGIT_TIMEOUT,
			.interdigit_timeout = ANALOG_INTER_DIGIT_TIMEOUT,
			.matchdigit_timeout = ANALOG_MATCH_DIGIT_TIMEOUT,
		},
		.timing = {
			.prewinktime = -1,
			.preflashtime = -1,
			.winktime = -1,
			.flashtime = -1,
			.starttime = -1,
			.rxwinktime = -1,
			.rxflashtime = -1,
			.debouncetime = -1
		},
		.ignore_failed_channels = 1,
		.smdi_port = "/dev/ttyS0",
	};

	return conf;
}