Newer
Older
* Asterisk -- An open source telephony toolkit.
* Copyright (C) 1999 - 2006, Digium, Inc.
* 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.
*
* 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.
*/
*
* \brief DAHDI for Pseudo TDM
*
* \author Mark Spencer <markster@digium.com>
*
* Connects to the DAHDI telephony library as well as
* 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
* and install the DAHDI channel.
* \arg \ref Config_dahdi
Olle Johansson
committed
*
Kevin P. Fleming
committed
* \todo Deprecate the "musiconhold" configuration option post 1.4
Kevin P. Fleming
committed
/*** MODULEINFO
<depend>dahdi</depend>
<depend>tonezone</depend>
<use>pri</use>
<use>ss7</use>
Kevin P. Fleming
committed
***/
Kevin P. Fleming
committed
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#ifdef __NetBSD__
#include <pthread.h>
#include <signal.h>
#else
#include <dahdi/user.h>
#include <dahdi/tonezone.h>
Kevin P. Fleming
committed
#ifdef HAVE_SS7
#include <libss7.h>
#endif
Kevin P. Fleming
committed
#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/cdr.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/say.h"
#include "asterisk/tdd.h"
#include "asterisk/app.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"
Russell Bryant
committed
#include "asterisk/abstract_jb.h"
Matthew Fredrickson
committed
#include "asterisk/smdi.h"
#include "asterisk/astobj.h"
Matthew Fredrickson
committed
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
Kevin P. Fleming
committed
#ifdef DAHDI_SPANINFO_HAS_LINECONFIG
static const char *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)"
};
#endif
Russell Bryant
committed
/*! Global jitterbuffer configuration - by default, jb is disabled */
Russell Bryant
committed
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = ""
};
static struct ast_jb_conf global_jbconf;
/* define this to send PRI user-user information elements */
#undef SUPPORT_USERUSER
/*!
* \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
* 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.
*/
* Define if you want to check the hook state for an FXO (FXS signalled) interface
* before dialing on it. Certain FXO interfaces always think they're out of
* service with this method however.
*/
/* #define DAHDI_CHECK_HOOKSTATE */
/*! \brief Typically, how many rings before we should send Caller*ID */
#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
Kevin P. Fleming
committed
/*! \brief Signaling types that need to use MF detection should be placed in this macro */
#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 Driver"
#ifdef HAVE_SS7
" w/SS7"
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
static const char config[] = "chan_dahdi.conf";
#define SIG_EM DAHDI_SIG_EM
#define SIG_EMWINK (0x0100000 | DAHDI_SIG_EM)
#define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
#define SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
#define SIG_FEATB (0x0800000 | DAHDI_SIG_EM)
#define SIG_E911 (0x1000000 | DAHDI_SIG_EM)
#define SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
#define SIG_FGC_CAMA (0x4000000 | DAHDI_SIG_EM)
#define SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
#define SIG_FXSLS DAHDI_SIG_FXSLS
#define SIG_FXSGS DAHDI_SIG_FXSGS
#define SIG_FXSKS DAHDI_SIG_FXSKS
#define SIG_FXOLS DAHDI_SIG_FXOLS
#define SIG_FXOGS DAHDI_SIG_FXOGS
#define SIG_FXOKS DAHDI_SIG_FXOKS
#define SIG_PRI DAHDI_SIG_CLEAR
#define SIG_BRI (0x2000000 | DAHDI_SIG_CLEAR)
#define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
#define SIG_SS7 (0x1000000 | DAHDI_SIG_CLEAR)
#define SIG_SF DAHDI_SIG_SF
#define SIG_SFWINK (0x0100000 | DAHDI_SIG_SF)
#define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
#define SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
#define SIG_SF_FEATB (0x0800000 | DAHDI_SIG_SF)
#define SIG_EM_E1 DAHDI_SIG_EM_E1
#define SIG_GR303FXOKS (0x0100000 | DAHDI_SIG_FXOKS)
#define SIG_GR303FXSKS (0x0100000 | DAHDI_SIG_FXSKS)
Tilghman Lesher
committed
#ifdef LOTS_OF_SPANS
#define NUM_SPANS DAHDI_MAX_SPANS
Tilghman Lesher
committed
#else
#define NUM_SPANS 32
Tilghman Lesher
committed
#endif
#define NUM_DCHANS 4 /*!< No more than 4 d-channels */
#define MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
#define DCHAN_PROVISIONED (1 << 0)
#define DCHAN_NOTINALARM (1 << 1)
#define DCHAN_UP (1 << 2)
#define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
/* Overlap dialing option types */
#define DAHDI_OVERLAPDIAL_NONE 0
#define DAHDI_OVERLAPDIAL_OUTGOING 1
#define DAHDI_OVERLAPDIAL_INCOMING 2
#define DAHDI_OVERLAPDIAL_BOTH (DAHDI_OVERLAPDIAL_INCOMING|DAHDI_OVERLAPDIAL_OUTGOING)
Tilghman Lesher
committed
#define CALLPROGRESS_PROGRESS 1
#define CALLPROGRESS_FAX_OUTGOING 2
#define CALLPROGRESS_FAX_INCOMING 4
#define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
Matthew Fredrickson
committed
static char defaultcic[64] = "";
static char defaultozz[64] = "";
static char parkinglot[AST_MAX_EXTENSION] = ""; /*!< Default parking lot for this channel */
/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
static char mwimonitornotify[PATH_MAX] = "";
static int mwisend_rpas = 0;
static char progzone[10] = "";
static int usedistinctiveringdetection = 0;
Joshua Colp
committed
static int distinctiveringaftercid = 0;
Kevin P. Fleming
committed
static int mwilevel = 512;
static struct ast_channel inuse;
#ifdef PRI_GETSET_TIMERS
static int pritimers[PRI_MAX_TIMERS];
static char pridebugfilename[1024] = "";
#endif
/*! \brief Wait up to 16 seconds for first digit (FXO logic) */
/*! \brief How long to wait for following digits (FXO logic) */
/*! \brief How long to wait for an extra digit, if there is an ambiguous match */
/*! \brief Protect the interface list (of dahdi_pvt's) */
Matthew Fredrickson
committed
Matthew Fredrickson
committed
AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
Matthew Fredrickson
committed
/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
AST_MUTEX_DEFINE_STATIC(monlock);
/*! \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 enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
static int dahdi_sendtext(struct ast_channel *c, const char *text);
static void mwi_event_cb(const struct ast_event *event, void *userdata)
{
/* This module does not handle MWI in an event-based manner. However, it
* subscribes to MWI for each mailbox that is configured so that the core
* knows that we care about it. Then, chan_dahdi will get the MWI from the
* event cache instead of checking the mailbox directly. */
}
/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
static inline int dahdi_get_event(int fd)
if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
static inline int dahdi_wait_event(int fd)
i = DAHDI_IOMUX_SIGEVENT;
if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
/*! Chunk size to read -- we use 20ms chunks to make things happy. */
#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 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 */
struct dahdi_pvt;
static int ringt_base = DEFAULT_RINGT;
#ifdef HAVE_SS7
#define LINKSTATE_INALARM (1 << 0)
#define LINKSTATE_STARTING (1 << 1)
#define LINKSTATE_UP (1 << 2)
#define LINKSTATE_DOWN (1 << 3)
Matthew Fredrickson
committed
#define SS7_NAI_DYNAMIC -1
struct dahdi_ss7 {
pthread_t master; /*!< Thread of master */
ast_mutex_t lock;
int fds[NUM_DCHANS];
int numsigchans;
int linkstate[NUM_DCHANS];
int numchans;
int type;
Matthew Fredrickson
committed
enum {
LINKSET_STATE_DOWN = 0,
LINKSET_STATE_UP
} state;
Matthew Fredrickson
committed
char called_nai; /*!< Called Nature of Address Indicator */
char calling_nai; /*!< Calling Nature of Address Indicator */
char internationalprefix[10]; /*!< country access code ('00' for european dialplans) */
char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
char subscriberprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
char unknownprefix[20]; /*!< for unknown dialplans */
struct ss7 *ss7;
struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */
static struct dahdi_ss7 linksets[NUM_SPANS];
static int cur_ss7type = -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 /* HAVE_SS7 */
Mark Spencer
committed
#define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
Mark Spencer
committed
#define PRI_CHANNEL(p) ((p) & 0xff)
#define PRI_SPAN(p) (((p) >> 8) & 0xff)
#define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
Mark Spencer
committed
struct dahdi_pri {
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
pthread_t master; /*!< Thread of master */
ast_mutex_t lock; /*!< Mutex */
char idleext[AST_MAX_EXTENSION]; /*!< Where to idle extra calls */
char idlecontext[AST_MAX_CONTEXT]; /*!< What context to use for idle */
char idledial[AST_MAX_EXTENSION]; /*!< What to dial before dumping */
int minunused; /*!< Min # of channels to keep empty */
int minidle; /*!< Min # of "idling" calls to keep active */
int nodetype; /*!< Node type */
int switchtype; /*!< Type of switch to emulate */
int nsf; /*!< Network-Specific Facilities */
int dialplan; /*!< Dialing plan */
int localdialplan; /*!< Local dialing plan */
char internationalprefix[10]; /*!< country access code ('00' for european dialplans) */
char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
char localprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
char privateprefix[20]; /*!< for private dialplans */
char unknownprefix[20]; /*!< for unknown dialplans */
int dchannels[NUM_DCHANS]; /*!< What channel are the dchannels on */
int trunkgroup; /*!< What our trunkgroup is */
int mastertrunkgroup; /*!< What trunk group is our master */
int prilogicalspan; /*!< Logical span number within trunk group */
int numchans; /*!< Num of channels we represent */
int overlapdial; /*!< In overlap dialing mode */
int facilityenable; /*!< Enable facility IEs */
struct pri *dchans[NUM_DCHANS]; /*!< Actual d-channels */
int dchanavail[NUM_DCHANS]; /*!< Whether each channel is available */
struct pri *pri; /*!< Currently active D-channel */
Mark Spencer
committed
int resetpos;
time_t lastreset; /*!< time when unused channels were last reset */
long resetinterval; /*!< Interval (in seconds) for resetting unused channels */
struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */
struct dahdi_pvt *crvs; /*!< Member CRV structs */
struct dahdi_pvt *crvend; /*!< Pointer to end of CRV structs */
static struct dahdi_pri pris[NUM_SPANS];
#define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
#else
#define DEFAULT_PRI_DEBUG 0
#endif
static inline void pri_rel(struct dahdi_pri *pri)
ast_mutex_unlock(&pri->lock);
struct dahdi_pri;
#define SUB_REAL 0 /*!< Active call */
#define SUB_CALLWAIT 1 /*!< Call-Waiting call on hold */
#define SUB_THREEWAY 2 /*!< Three-way call */
/* Polarity states */
#define POLARITY_IDLE 0
#define POLARITY_REV 1
struct distRingData {
int ring[3];
char contextData[AST_MAX_CONTEXT];
struct dahdi_distRings {
struct distRingData ringnum[3];
struct ringContextData ringContext[3];
};
static char *subnames[] = {
"Real",
"Callwait",
"Threeway"
};
struct dahdi_subchannel {
int zfd;
struct ast_channel *owner;
int chan;
short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
struct ast_frame f; /*!< One frame for each channel. How did this ever work before? */
unsigned int needringing:1;
unsigned int needbusy:1;
unsigned int needcongestion:1;
unsigned int needcallerid:1;
unsigned int needanswer:1;
unsigned int needflash:1;
Mark Spencer
committed
unsigned int needhold:1;
unsigned int needunhold:1;
unsigned int linear:1;
unsigned int inthreeway:1;
DAHDI_CONFINFO curconf;
};
#define CONF_USER_REAL (1 << 0)
#define CONF_USER_THIRDCALL (1 << 1)
#define MAX_SLAVES 4
static struct dahdi_pvt {
ast_mutex_t lock;
struct ast_channel *owner; /*!< Our current active owner (if applicable) */
/*!< Up to three channels can be associated with this call */
struct dahdi_subchannel sub_unused; /*!< Just a safety precaution */
struct dahdi_subchannel subs[3]; /*!< Sub-channels */
struct dahdi_confinfo saveconf; /*!< Saved conference info */
struct dahdi_pvt *slaves[MAX_SLAVES]; /*!< Slave to us (follows our conferencing) */
struct dahdi_pvt *master; /*!< Master to us (we follow their conferencing) */
int inconference; /*!< If our real should be in the conference */
int sig; /*!< Signalling style */
int radio; /*!< radio type */
int outsigmod; /*!< Outbound Signalling style (modifier) */
int oprmode; /*!< "Operator Services" mode */
struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
Doug Bailey
committed
float cid_rxgain; /*!< "Gain to apply during caller id */
int tonezone; /*!< tone zone for this chan, or -1 for default */
struct dahdi_pvt *next; /*!< Next channel in list */
struct dahdi_pvt *prev; /*!< Prev channel in list */
/* flags */
unsigned int adsi:1;
unsigned int answeronpolarityswitch:1;
unsigned int busydetect:1;
unsigned int callreturn:1;
unsigned int callwaiting:1;
unsigned int callwaitingcallerid:1;
unsigned int cancallforward:1;
unsigned int canpark:1;
unsigned int confirmanswer:1; /*!< Wait for '#' to confirm answer */
unsigned int destroy:1;
unsigned int didtdd:1; /*!< flag to say its done it once */
unsigned int dialednone:1;
unsigned int dialing:1;
unsigned int digital:1;
unsigned int dnd:1;
unsigned int echobreak:1;
unsigned int echocanbridged:1;
unsigned int echocanon:1;
unsigned int faxhandled:1; /*!< Has a fax tone already been handled? */
unsigned int firstradio:1;
unsigned int hanguponpolarityswitch:1;
unsigned int hardwaredtmf:1;
Matthew Fredrickson
committed
unsigned int hidecallerid:1;
unsigned int hidecalleridname:1; /*!< Hide just the name not the number for legacy PBX use */
unsigned int ignoredtmf:1;
unsigned int immediate:1; /*!< Answer before getting digits? */
unsigned int inalarm:1;
unsigned int outgoing:1;
/* unsigned int overlapdial:1; unused and potentially confusing */
unsigned int permcallwaiting:1;
unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */
unsigned int priindication_oob:1;
Matthew Fredrickson
committed
unsigned int priexclusive:1;
unsigned int pulse:1;
unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */
unsigned int restrictcid:1; /*!< Whether restrict the callerid -> only send ANI */
unsigned int threewaycalling:1;
unsigned int transfer:1;
unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
unsigned int use_callingpres:1; /*!< Whether to use the callingpres the calling switch sends */
unsigned int usedistinctiveringdetection:1;
unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */
unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
unsigned int mwimonitor_neon:1; /*!< monitor this FXO port for neon type MWI indication from other end */
unsigned int mwimonitor_fsk:1; /*!< monitor this FXO port for fsk MWI indication from other end */
Kevin P. Fleming
committed
unsigned int mwimonitoractive:1; /*!< an MWI monitor thread is currently active */
unsigned int mwisendactive:1; /*!< a MWI message sending thread is active */
Matthew Fredrickson
committed
/* Channel state or unavilability flags */
unsigned int inservice:1;
unsigned int locallyblocked:1;
unsigned int remotelyblocked:1;
#if defined(HAVE_PRI) || defined(HAVE_SS7)
Matthew Fredrickson
committed
unsigned int rlt:1;
unsigned int alerting:1;
unsigned int alreadyhungup:1;
unsigned int isidlecall:1;
Matthew Fredrickson
committed
unsigned int proceeding:1;
unsigned int progress:1;
unsigned int resetting:1;
unsigned int setup_ack:1;
#endif
Matthew Fredrickson
committed
unsigned int use_smdi:1; /* Whether to use SMDI on this channel */
struct ast_smdi_interface *smdi_iface; /* The serial port to listen for SMDI data on */
struct dahdi_distRings drings;
Russell Bryant
committed
char context[AST_MAX_CONTEXT];
char defcontext[AST_MAX_CONTEXT];
char exten[AST_MAX_EXTENSION];
char language[MAX_LANGUAGE];
Kevin P. Fleming
committed
char mohinterpret[MAX_MUSICCLASS];
char mohsuggest[MAX_MUSICCLASS];
char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
#if defined(PRI_ANI) || defined(HAVE_SS7)
Russell Bryant
committed
char cid_ani[AST_MAX_EXTENSION];
Russell Bryant
committed
char cid_num[AST_MAX_EXTENSION];
Russell Bryant
committed
char cid_name[AST_MAX_EXTENSION];
char lastcid_num[AST_MAX_EXTENSION];
char lastcid_name[AST_MAX_EXTENSION];
char *origcid_num; /*!< malloced original callerid */
char *origcid_name; /*!< malloced original callerid */
Russell Bryant
committed
char callwait_num[AST_MAX_EXTENSION];
char callwait_name[AST_MAX_EXTENSION];
Russell Bryant
committed
char dnid[AST_MAX_EXTENSION];
int confno; /*!< Our conference */
int confusers; /*!< Who is using our conference */
int propconfno; /*!< Propagated conference number */
ast_group_t callgroup;
ast_group_t pickupgroup;
Joshua Colp
committed
struct ast_variable *vars;
int channel; /*!< Channel Number or CRV */
int span; /*!< Span number */
time_t guardtime; /*!< Must wait this much time before using for new call */
int cid_signalling; /*!< CID signalling type bell202 or v23 */
int cid_start; /*!< CID start indicator, polarity or ring */
int callingpres; /*!< The value of callling presentation that we're going to use when placing a PRI call */
int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */
int cidcwexpire; /*!< When to expire our muting for CID/CW */
unsigned char *cidspill;
int cidpos;
int cidlen;
int ringt;
int ringt_base;
int stripmsd;
int callwaitcas;
int callwaitrings;
Kevin P. Fleming
committed
struct {
struct dahdi_echocanparams head;
struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
Kevin P. Fleming
committed
} echocancel;
int echotraining;
int busy_tonelength;
int busy_quietlength;
DAHDI_DIAL_OPERATION dop;
int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */
Russell Bryant
committed
char finaldial[64];
char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
int amaflags; /*!< AMA Flags */
struct tdd_state *tdd; /*!< TDD flag */
Russell Bryant
committed
char call_forward[AST_MAX_EXTENSION];
char mailbox[AST_MAX_EXTENSION];
struct ast_event_sub *mwi_event_sub;
int distinctivering; /*!< Which distinctivering to use */
int cidrings; /*!< Which ring to deliver CID on */
int dtmfrelax; /*!< whether to run in relaxed DTMF mode */
Martin Pycko
committed
int fake_event;
int polarityonanswerdelay;
struct timeval polaritydelaytv;
struct dahdi_pri *pri;
struct dahdi_pvt *bearer;
struct dahdi_pvt *realcall;
int polarity;
#ifdef HAVE_SS7
struct dahdi_ss7 *ss7;
struct isup_call *ss7call;
char charge_number[50];
Matthew Fredrickson
committed
char gen_dig_number[50];
Matthew Fredrickson
committed
char orig_called_num[50];
Matthew Fredrickson
committed
char redirecting_num[50];
char generic_name[50];
unsigned char gen_add_num_plan;
unsigned char gen_add_nai;
unsigned char gen_add_pres_ind;
unsigned char gen_add_type;
Matthew Fredrickson
committed
unsigned char gen_dig_type;
unsigned char gen_dig_scheme;
char jip_number[50];
unsigned char lspi_type;
unsigned char lspi_scheme;
unsigned char lspi_context;
char lspi_ident[50];
unsigned int call_ref_ident;
unsigned int call_ref_pc;
unsigned char calling_party_cat;
int transcap;
int cic; /*!< CIC associated with channel */
unsigned int dpc; /*!< CIC's DPC */
char begindigit;
} *iflist = NULL, *ifend = NULL;
/*! \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'
* statement is reached, the current dahdi_chan_conf is used to configure the
* channel (struct dahdi_pvt)
* \see dahdi_chan_init for the default values.
struct dahdi_chan_conf {
struct dahdi_pvt chan;
struct dahdi_pri pri;
Matthew Fredrickson
committed
#ifdef HAVE_SS7
struct dahdi_ss7 ss7;
Matthew Fredrickson
committed
#endif
DAHDI_PARAMS timing;
int is_sig_auto; /*!< Use channel signalling from DAHDI? */
char smdi_port[SMDI_MAX_FILENAME_LEN];
};
/*! returns a new dahdi_chan_conf with default values (by-value) */
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
*/
struct dahdi_chan_conf conf = {
.nsf = PRI_NSF_NONE,
.switchtype = PRI_SWITCH_NI2,
Tilghman Lesher
committed
.dialplan = PRI_UNKNOWN + 1,
.localdialplan = PRI_NATIONAL_ISDN + 1,
.nodetype = PRI_CPE,
.minunused = 2,
.idleext = "",
.idledial = "",
.internationalprefix = "",
.nationalprefix = "",
.localprefix = "",
.privateprefix = "",
.unknownprefix = "",
.resetinterval = -1,
Matthew Fredrickson
committed
#endif
#ifdef HAVE_SS7
.ss7 = {
.called_nai = SS7_NAI_NATIONAL,
.calling_nai = SS7_NAI_NATIONAL,
.internationalprefix = "",
.nationalprefix = "",
.subscriberprefix = "",
.unknownprefix = ""
},
.chan = {
.context = "default",
.cid_num = "",
.cid_name = "",
.mohinterpret = "default",
.mohsuggest = "",
.transfertobusy = 1,
.cid_signalling = CID_SIG_BELL,
.cid_start = CID_START_RING,
.dahditrcallerid = 0,
.use_callerid = 1,
.sig = -1,
.outsigmod = -1,
Doug Bailey
committed
.cid_rxgain = +5.0,
Kevin P. Fleming
committed
.echocancel.head.tap_length = 1,
.busycount = 3,
.accountcode = "",
.mailbox = "",
.polarityonanswerdelay = 600,
.sendcalleridafter = DEFAULT_CIDRINGS
},
.timing = {
.prewinktime = -1,
.preflashtime = -1,
.winktime = -1,
.flashtime = -1,
.starttime = -1,
.rxwinktime = -1,
.rxflashtime = -1,
.debouncetime = -1
},
.smdi_port = "/dev/ttyS0",
};
return conf;
}
static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause);
static int dahdi_digit_begin(struct ast_channel *ast, char digit);
static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
static int dahdi_sendtext(struct ast_channel *c, const char *text);
static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout);
static int dahdi_hangup(struct ast_channel *ast);
static int dahdi_answer(struct ast_channel *ast);
static struct ast_frame *dahdi_read(struct ast_channel *ast);
static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
static struct ast_frame *dahdi_exception(struct ast_channel *ast);
static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
static int handle_init_event(struct dahdi_pvt *i, int event);
static const struct ast_channel_tech dahdi_tech = {
.type = "DAHDI",
.description = tdesc,
.capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
.requester = dahdi_request,
.send_digit_begin = dahdi_digit_begin,
.send_digit_end = dahdi_digit_end,
.send_text = dahdi_sendtext,
.call = dahdi_call,
.hangup = dahdi_hangup,
.answer = dahdi_answer,
.read = dahdi_read,
.write = dahdi_write,
.bridge = dahdi_bridge,
.exception = dahdi_exception,
.indicate = dahdi_indicate,
.fixup = dahdi_fixup,
.setoption = dahdi_setoption,
.func_channel_read = dahdi_func_read,
};
#define GET_CHANNEL(p) ((p)->bearer ? (p)->bearer->channel : p->channel)
#else
#define GET_CHANNEL(p) ((p)->channel)
#endif
struct dahdi_pvt *round_robin[32];
Martin Pycko
committed
static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
{
int res;
/* Grab the lock first */
do {
DEADLOCK_AVOIDANCE(&pvt->lock);
} while (res);
pthread_kill(pri->master, SIGURG);
return 0;
}
#endif
#ifdef HAVE_SS7
static inline void ss7_rel(struct dahdi_ss7 *ss7)
{
ast_mutex_unlock(&ss7->lock);
}
static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
{
int res;
/* Grab the lock first */
do {
res = ast_mutex_trylock(&pri->lock);
if (res) {
Tilghman Lesher
committed
DEADLOCK_AVOIDANCE(&pvt->lock);
}
} while (res);
/* Then break the poll */
pthread_kill(pri->master, SIGURG);
return 0;
}
#endif
#define NUM_CADENCE_MAX 25
static int num_cadence = 4;
static int user_has_defined_cadences = 0;
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) || \
#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 int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
if (p->subs[0].owner == ast)
res = 0;
else if (p->subs[1].owner == ast)
res = 1;
else if (p->subs[2].owner == ast)
res = 2;
else {
res = -1;
if (!nullok)
ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
}
return res;
}
static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri)
Mark Spencer
committed
#else
static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri)
Mark Spencer
committed
#endif
Mark Spencer
committed
if (pri)
ast_mutex_unlock(&pri->lock);
#endif
Russell Bryant
committed
if (ast_channel_trylock(p->subs[a].owner)) {
DEADLOCK_AVOIDANCE(&p->lock);
ast_queue_frame(p->subs[a].owner, &ast_null_frame);
Russell Bryant
committed
ast_channel_unlock(p->subs[a].owner);
Mark Spencer
committed
if (pri)
ast_mutex_lock(&pri->lock);
#endif
static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *data)
struct dahdi_pri *pri = (struct dahdi_pri*) data;
#endif
#ifdef HAVE_SS7
struct dahdi_ss7 *ss7 = (struct dahdi_ss7*) data;
Mark Spencer
committed
#endif
/* We must unlock the PRI to avoid the possibility of a deadlock */
#if defined(HAVE_PRI) || defined(HAVE_SS7)
if (data) {
switch (p->sig) {