Merged revisions 140566 via svnmerge from
[asterisk-bristuff.git] / channels / chan_dahdi.c
blob0b21723b054582d4bec736525c421030f5cc774a
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief DAHDI for Pseudo TDM
23 * \author Mark Spencer <markster@digium.com>
25 * Connects to the DAHDI telephony library as well as
26 * libpri. Libpri is optional and needed only if you are
27 * going to use ISDN connections.
29 * You need to install libraries before you attempt to compile
30 * and install the DAHDI channel.
32 * \par See also
33 * \arg \ref Config_dahdi
35 * \ingroup channel_drivers
37 * \todo Deprecate the "musiconhold" configuration option post 1.4
40 /*** MODULEINFO
41 <depend>res_smdi</depend>
42 <depend>dahdi</depend>
43 <depend>tonezone</depend>
44 <use>pri</use>
45 <use>ss7</use>
46 ***/
48 #include "asterisk.h"
50 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
52 #ifdef __NetBSD__
53 #include <pthread.h>
54 #include <signal.h>
55 #else
56 #include <sys/signal.h>
57 #endif
58 #include <sys/ioctl.h>
59 #include <math.h>
60 #include <ctype.h>
62 #include <dahdi/user.h>
63 #include <dahdi/tonezone.h>
65 #ifdef HAVE_PRI
66 #include <libpri.h>
67 #endif
69 #ifdef HAVE_SS7
70 #include <libss7.h>
71 #endif
73 #include "asterisk/lock.h"
74 #include "asterisk/channel.h"
75 #include "asterisk/config.h"
76 #include "asterisk/module.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/file.h"
79 #include "asterisk/ulaw.h"
80 #include "asterisk/alaw.h"
81 #include "asterisk/callerid.h"
82 #include "asterisk/adsi.h"
83 #include "asterisk/cli.h"
84 #include "asterisk/cdr.h"
85 #include "asterisk/features.h"
86 #include "asterisk/musiconhold.h"
87 #include "asterisk/say.h"
88 #include "asterisk/tdd.h"
89 #include "asterisk/app.h"
90 #include "asterisk/dsp.h"
91 #include "asterisk/astdb.h"
92 #include "asterisk/manager.h"
93 #include "asterisk/causes.h"
94 #include "asterisk/term.h"
95 #include "asterisk/utils.h"
96 #include "asterisk/transcap.h"
97 #include "asterisk/stringfields.h"
98 #include "asterisk/abstract_jb.h"
99 #include "asterisk/smdi.h"
100 #include "asterisk/astobj.h"
101 #include "asterisk/event.h"
102 #include "asterisk/devicestate.h"
104 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
106 static const char *lbostr[] = {
107 "0 db (CSU)/0-133 feet (DSX-1)",
108 "133-266 feet (DSX-1)",
109 "266-399 feet (DSX-1)",
110 "399-533 feet (DSX-1)",
111 "533-655 feet (DSX-1)",
112 "-7.5db (CSU)",
113 "-15db (CSU)",
114 "-22.5db (CSU)"
117 /*! Global jitterbuffer configuration - by default, jb is disabled */
118 static struct ast_jb_conf default_jbconf =
120 .flags = 0,
121 .max_size = -1,
122 .resync_threshold = -1,
123 .impl = ""
125 static struct ast_jb_conf global_jbconf;
127 /* define this to send PRI user-user information elements */
128 #undef SUPPORT_USERUSER
130 /*!
131 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
132 * the user hangs up to reset the state machine so ring works properly.
133 * This is used to be able to support kewlstart by putting the zhone in
134 * groundstart mode since their forward disconnect supervision is entirely
135 * broken even though their documentation says it isn't and their support
136 * is entirely unwilling to provide any assistance with their channel banks
137 * even though their web site says they support their products for life.
139 /* #define ZHONE_HACK */
141 /*! \note
142 * Define if you want to check the hook state for an FXO (FXS signalled) interface
143 * before dialing on it. Certain FXO interfaces always think they're out of
144 * service with this method however.
146 /* #define DAHDI_CHECK_HOOKSTATE */
148 /*! \brief Typically, how many rings before we should send Caller*ID */
149 #define DEFAULT_CIDRINGS 1
151 #define CHANNEL_PSEUDO -12
153 #define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
156 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
157 #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))
159 static const char tdesc[] = "DAHDI Telephony Driver"
160 #ifdef HAVE_PRI
161 " w/PRI"
162 #endif
163 #ifdef HAVE_SS7
164 " w/SS7"
165 #endif
168 static const char config[] = "chan_dahdi.conf";
170 #define SIG_EM DAHDI_SIG_EM
171 #define SIG_EMWINK (0x0100000 | DAHDI_SIG_EM)
172 #define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
173 #define SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
174 #define SIG_FEATB (0x0800000 | DAHDI_SIG_EM)
175 #define SIG_E911 (0x1000000 | DAHDI_SIG_EM)
176 #define SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
177 #define SIG_FGC_CAMA (0x4000000 | DAHDI_SIG_EM)
178 #define SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
179 #define SIG_FXSLS DAHDI_SIG_FXSLS
180 #define SIG_FXSGS DAHDI_SIG_FXSGS
181 #define SIG_FXSKS DAHDI_SIG_FXSKS
182 #define SIG_FXOLS DAHDI_SIG_FXOLS
183 #define SIG_FXOGS DAHDI_SIG_FXOGS
184 #define SIG_FXOKS DAHDI_SIG_FXOKS
185 #define SIG_PRI DAHDI_SIG_CLEAR
186 #define SIG_BRI (0x2000000 | DAHDI_SIG_CLEAR)
187 #define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
188 #define SIG_SS7 (0x1000000 | DAHDI_SIG_CLEAR)
189 #define SIG_SF DAHDI_SIG_SF
190 #define SIG_SFWINK (0x0100000 | DAHDI_SIG_SF)
191 #define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
192 #define SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
193 #define SIG_SF_FEATB (0x0800000 | DAHDI_SIG_SF)
194 #define SIG_EM_E1 DAHDI_SIG_EM_E1
195 #define SIG_GR303FXOKS (0x0100000 | DAHDI_SIG_FXOKS)
196 #define SIG_GR303FXSKS (0x0100000 | DAHDI_SIG_FXSKS)
198 #ifdef LOTS_OF_SPANS
199 #define NUM_SPANS DAHDI_MAX_SPANS
200 #else
201 #define NUM_SPANS 32
202 #endif
203 #define NUM_DCHANS 4 /*!< No more than 4 d-channels */
204 #define MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
206 #define CHAN_PSEUDO -2
208 #define DCHAN_PROVISIONED (1 << 0)
209 #define DCHAN_NOTINALARM (1 << 1)
210 #define DCHAN_UP (1 << 2)
212 #define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
214 /* Overlap dialing option types */
215 #define DAHDI_OVERLAPDIAL_NONE 0
216 #define DAHDI_OVERLAPDIAL_OUTGOING 1
217 #define DAHDI_OVERLAPDIAL_INCOMING 2
218 #define DAHDI_OVERLAPDIAL_BOTH (DAHDI_OVERLAPDIAL_INCOMING|DAHDI_OVERLAPDIAL_OUTGOING)
221 #define CALLPROGRESS_PROGRESS 1
222 #define CALLPROGRESS_FAX_OUTGOING 2
223 #define CALLPROGRESS_FAX_INCOMING 4
224 #define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
226 static char defaultcic[64] = "";
227 static char defaultozz[64] = "";
229 static char parkinglot[AST_MAX_EXTENSION] = ""; /*!< Default parking lot for this channel */
231 /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
232 static char mwimonitornotify[PATH_MAX] = "";
233 static int mwisend_rpas = 0;
235 static char progzone[10] = "";
237 static int usedistinctiveringdetection = 0;
238 static int distinctiveringaftercid = 0;
240 static int numbufs = 4;
242 static int mwilevel = 512;
244 #ifdef HAVE_PRI
245 static struct ast_channel inuse;
246 #ifdef PRI_GETSET_TIMERS
247 static int pritimers[PRI_MAX_TIMERS];
248 #endif
249 static int pridebugfd = -1;
250 static char pridebugfilename[1024] = "";
251 #endif
253 /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
254 static int firstdigittimeout = 16000;
256 /*! \brief How long to wait for following digits (FXO logic) */
257 static int gendigittimeout = 8000;
259 /*! \brief How long to wait for an extra digit, if there is an ambiguous match */
260 static int matchdigittimeout = 3000;
262 /*! \brief Protect the interface list (of dahdi_pvt's) */
263 AST_MUTEX_DEFINE_STATIC(iflock);
266 static int ifcount = 0;
268 #ifdef HAVE_PRI
269 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
270 #endif
272 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
273 when it's doing something critical. */
274 AST_MUTEX_DEFINE_STATIC(monlock);
276 /*! \brief This is the thread for the monitor which checks for input on the channels
277 which are not currently in use. */
278 static pthread_t monitor_thread = AST_PTHREADT_NULL;
279 static ast_cond_t mwi_thread_complete;
280 static ast_cond_t ss_thread_complete;
281 AST_MUTEX_DEFINE_STATIC(mwi_thread_lock);
282 AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
283 AST_MUTEX_DEFINE_STATIC(restart_lock);
284 static int mwi_thread_count = 0;
285 static int ss_thread_count = 0;
286 static int num_restart_pending = 0;
288 static int restart_monitor(void);
290 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);
292 static int dahdi_sendtext(struct ast_channel *c, const char *text);
294 static void mwi_event_cb(const struct ast_event *event, void *userdata)
296 /* This module does not handle MWI in an event-based manner. However, it
297 * subscribes to MWI for each mailbox that is configured so that the core
298 * knows that we care about it. Then, chan_dahdi will get the MWI from the
299 * event cache instead of checking the mailbox directly. */
302 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
303 static inline int dahdi_get_event(int fd)
305 int j;
306 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
307 return -1;
308 return j;
311 /*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
312 static inline int dahdi_wait_event(int fd)
314 int i, j = 0;
315 i = DAHDI_IOMUX_SIGEVENT;
316 if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
317 return -1;
318 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
319 return -1;
320 return j;
323 /*! Chunk size to read -- we use 20ms chunks to make things happy. */
324 #define READ_SIZE 160
326 #define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
327 #define MASK_INUSE (1 << 1) /*!< Channel currently in use */
329 #define CALLWAITING_SILENT_SAMPLES ( (300 * 8) / READ_SIZE) /*!< 300 ms */
330 #define CALLWAITING_REPEAT_SAMPLES ( (10000 * 8) / READ_SIZE) /*!< 10,000 ms */
331 #define CIDCW_EXPIRE_SAMPLES ( (500 * 8) / READ_SIZE) /*!< 500 ms */
332 #define MIN_MS_SINCE_FLASH ( (2000) ) /*!< 2000 ms */
333 #define DEFAULT_RINGT ( (8000 * 8) / READ_SIZE) /*!< 8,000 ms */
335 struct dahdi_pvt;
337 static int ringt_base = DEFAULT_RINGT;
339 #ifdef HAVE_SS7
341 #define LINKSTATE_INALARM (1 << 0)
342 #define LINKSTATE_STARTING (1 << 1)
343 #define LINKSTATE_UP (1 << 2)
344 #define LINKSTATE_DOWN (1 << 3)
346 #define SS7_NAI_DYNAMIC -1
348 #define LINKSET_FLAG_EXPLICITACM (1 << 0)
350 struct dahdi_ss7 {
351 pthread_t master; /*!< Thread of master */
352 ast_mutex_t lock;
353 int fds[NUM_DCHANS];
354 int numsigchans;
355 int linkstate[NUM_DCHANS];
356 int numchans;
357 int type;
358 enum {
359 LINKSET_STATE_DOWN = 0,
360 LINKSET_STATE_UP
361 } state;
362 char called_nai; /*!< Called Nature of Address Indicator */
363 char calling_nai; /*!< Calling Nature of Address Indicator */
364 char internationalprefix[10]; /*!< country access code ('00' for european dialplans) */
365 char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
366 char subscriberprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
367 char unknownprefix[20]; /*!< for unknown dialplans */
368 struct ss7 *ss7;
369 struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */
370 int flags; /*!< Linkset flags */
373 static struct dahdi_ss7 linksets[NUM_SPANS];
375 static int cur_ss7type = -1;
376 static int cur_linkset = -1;
377 static int cur_pointcode = -1;
378 static int cur_cicbeginswith = -1;
379 static int cur_adjpointcode = -1;
380 static int cur_networkindicator = -1;
381 static int cur_defaultdpc = -1;
382 #endif /* HAVE_SS7 */
384 #ifdef HAVE_PRI
386 #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
387 #define PRI_CHANNEL(p) ((p) & 0xff)
388 #define PRI_SPAN(p) (((p) >> 8) & 0xff)
389 #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
391 struct dahdi_pri {
392 pthread_t master; /*!< Thread of master */
393 ast_mutex_t lock; /*!< Mutex */
394 char idleext[AST_MAX_EXTENSION]; /*!< Where to idle extra calls */
395 char idlecontext[AST_MAX_CONTEXT]; /*!< What context to use for idle */
396 char idledial[AST_MAX_EXTENSION]; /*!< What to dial before dumping */
397 int minunused; /*!< Min # of channels to keep empty */
398 int minidle; /*!< Min # of "idling" calls to keep active */
399 int nodetype; /*!< Node type */
400 int switchtype; /*!< Type of switch to emulate */
401 int nsf; /*!< Network-Specific Facilities */
402 int dialplan; /*!< Dialing plan */
403 int localdialplan; /*!< Local dialing plan */
404 char internationalprefix[10]; /*!< country access code ('00' for european dialplans) */
405 char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
406 char localprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
407 char privateprefix[20]; /*!< for private dialplans */
408 char unknownprefix[20]; /*!< for unknown dialplans */
409 int dchannels[NUM_DCHANS]; /*!< What channel are the dchannels on */
410 int trunkgroup; /*!< What our trunkgroup is */
411 int mastertrunkgroup; /*!< What trunk group is our master */
412 int prilogicalspan; /*!< Logical span number within trunk group */
413 int numchans; /*!< Num of channels we represent */
414 int overlapdial; /*!< In overlap dialing mode */
415 int facilityenable; /*!< Enable facility IEs */
416 struct pri *dchans[NUM_DCHANS]; /*!< Actual d-channels */
417 int dchanavail[NUM_DCHANS]; /*!< Whether each channel is available */
418 struct pri *pri; /*!< Currently active D-channel */
419 int debug;
420 int fds[NUM_DCHANS]; /*!< FD's for d-channels */
421 int offset;
422 int span;
423 int resetting;
424 int resetpos;
425 #ifdef HAVE_PRI_INBANDDISCONNECT
426 unsigned int inbanddisconnect:1; /*!< Should we support inband audio after receiving DISCONNECT? */
427 #endif
428 time_t lastreset; /*!< time when unused channels were last reset */
429 long resetinterval; /*!< Interval (in seconds) for resetting unused channels */
430 int sig;
431 struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */
432 struct dahdi_pvt *crvs; /*!< Member CRV structs */
433 struct dahdi_pvt *crvend; /*!< Pointer to end of CRV structs */
437 static struct dahdi_pri pris[NUM_SPANS];
439 #if 0
440 #define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
441 #else
442 #define DEFAULT_PRI_DEBUG 0
443 #endif
445 static inline void pri_rel(struct dahdi_pri *pri)
447 ast_mutex_unlock(&pri->lock);
450 #else
451 /*! Shut up the compiler */
452 struct dahdi_pri;
453 #endif
455 #define SUB_REAL 0 /*!< Active call */
456 #define SUB_CALLWAIT 1 /*!< Call-Waiting call on hold */
457 #define SUB_THREEWAY 2 /*!< Three-way call */
459 /* Polarity states */
460 #define POLARITY_IDLE 0
461 #define POLARITY_REV 1
464 struct distRingData {
465 int ring[3];
466 int range;
468 struct ringContextData {
469 char contextData[AST_MAX_CONTEXT];
471 struct dahdi_distRings {
472 struct distRingData ringnum[3];
473 struct ringContextData ringContext[3];
476 static char *subnames[] = {
477 "Real",
478 "Callwait",
479 "Threeway"
482 struct dahdi_subchannel {
483 int dfd;
484 struct ast_channel *owner;
485 int chan;
486 short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
487 struct ast_frame f; /*!< One frame for each channel. How did this ever work before? */
488 unsigned int needringing:1;
489 unsigned int needbusy:1;
490 unsigned int needcongestion:1;
491 unsigned int needcallerid:1;
492 unsigned int needanswer:1;
493 unsigned int needflash:1;
494 unsigned int needhold:1;
495 unsigned int needunhold:1;
496 unsigned int linear:1;
497 unsigned int inthreeway:1;
498 struct dahdi_confinfo curconf;
501 #define CONF_USER_REAL (1 << 0)
502 #define CONF_USER_THIRDCALL (1 << 1)
504 #define MAX_SLAVES 4
506 static struct dahdi_pvt {
507 ast_mutex_t lock;
508 struct ast_channel *owner; /*!< Our current active owner (if applicable) */
509 /*!< Up to three channels can be associated with this call */
511 struct dahdi_subchannel sub_unused; /*!< Just a safety precaution */
512 struct dahdi_subchannel subs[3]; /*!< Sub-channels */
513 struct dahdi_confinfo saveconf; /*!< Saved conference info */
515 struct dahdi_pvt *slaves[MAX_SLAVES]; /*!< Slave to us (follows our conferencing) */
516 struct dahdi_pvt *master; /*!< Master to us (we follow their conferencing) */
517 int inconference; /*!< If our real should be in the conference */
519 int buf_no; /*!< Number of buffers */
520 int buf_policy; /*!< Buffer policy */
521 int sig; /*!< Signalling style */
522 int radio; /*!< radio type */
523 int outsigmod; /*!< Outbound Signalling style (modifier) */
524 int oprmode; /*!< "Operator Services" mode */
525 struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
526 float cid_rxgain; /*!< "Gain to apply during caller id */
527 float rxgain;
528 float txgain;
529 int tonezone; /*!< tone zone for this chan, or -1 for default */
530 struct dahdi_pvt *next; /*!< Next channel in list */
531 struct dahdi_pvt *prev; /*!< Prev channel in list */
533 /* flags */
534 unsigned int adsi:1;
535 unsigned int answeronpolarityswitch:1;
536 unsigned int busydetect:1;
537 unsigned int callreturn:1;
538 unsigned int callwaiting:1;
539 unsigned int callwaitingcallerid:1;
540 unsigned int cancallforward:1;
541 unsigned int canpark:1;
542 unsigned int confirmanswer:1; /*!< Wait for '#' to confirm answer */
543 unsigned int destroy:1;
544 unsigned int didtdd:1; /*!< flag to say its done it once */
545 unsigned int dialednone:1;
546 unsigned int dialing:1;
547 unsigned int digital:1;
548 unsigned int dnd:1;
549 unsigned int echobreak:1;
550 unsigned int echocanbridged:1;
551 unsigned int echocanon:1;
552 unsigned int faxhandled:1; /*!< Has a fax tone already been handled? */
553 unsigned int firstradio:1;
554 unsigned int hanguponpolarityswitch:1;
555 unsigned int hardwaredtmf:1;
556 unsigned int hidecallerid:1;
557 unsigned int hidecalleridname:1; /*!< Hide just the name not the number for legacy PBX use */
558 unsigned int ignoredtmf:1;
559 unsigned int immediate:1; /*!< Answer before getting digits? */
560 unsigned int inalarm:1;
561 unsigned int mate:1; /*!< flag to say its in MATE mode */
562 unsigned int outgoing:1;
563 /* unsigned int overlapdial:1; unused and potentially confusing */
564 unsigned int permcallwaiting:1;
565 unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */
566 unsigned int priindication_oob:1;
567 unsigned int priexclusive:1;
568 unsigned int pulse:1;
569 unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */
570 unsigned int restartpending:1; /*!< flag to ensure counted only once for restart */
571 unsigned int restrictcid:1; /*!< Whether restrict the callerid -> only send ANI */
572 unsigned int threewaycalling:1;
573 unsigned int transfer:1;
574 unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
575 unsigned int use_callingpres:1; /*!< Whether to use the callingpres the calling switch sends */
576 unsigned int usedistinctiveringdetection:1;
577 unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */
578 unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
579 unsigned int mwimonitor_neon:1; /*!< monitor this FXO port for neon type MWI indication from other end */
580 unsigned int mwimonitor_fsk:1; /*!< monitor this FXO port for fsk MWI indication from other end */
581 unsigned int mwimonitoractive:1; /*!< an MWI monitor thread is currently active */
582 unsigned int mwisendactive:1; /*!< a MWI message sending thread is active */
583 /* Channel state or unavilability flags */
584 unsigned int inservice:1;
585 unsigned int locallyblocked:1;
586 unsigned int remotelyblocked:1;
587 #if defined(HAVE_PRI) || defined(HAVE_SS7)
588 unsigned int rlt:1;
589 unsigned int alerting:1;
590 unsigned int alreadyhungup:1;
591 unsigned int isidlecall:1;
592 unsigned int proceeding:1;
593 unsigned int progress:1;
594 unsigned int resetting:1;
595 unsigned int setup_ack:1;
596 #endif
597 unsigned int use_smdi:1; /* Whether to use SMDI on this channel */
598 struct ast_smdi_interface *smdi_iface; /* The serial port to listen for SMDI data on */
600 struct dahdi_distRings drings;
602 char context[AST_MAX_CONTEXT];
603 char defcontext[AST_MAX_CONTEXT];
604 char exten[AST_MAX_EXTENSION];
605 char language[MAX_LANGUAGE];
606 char mohinterpret[MAX_MUSICCLASS];
607 char mohsuggest[MAX_MUSICCLASS];
608 char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
609 #if defined(PRI_ANI) || defined(HAVE_SS7)
610 char cid_ani[AST_MAX_EXTENSION];
611 #endif
612 int cid_ani2;
613 char cid_num[AST_MAX_EXTENSION];
614 int cid_ton; /*!< Type Of Number (TON) */
615 char cid_name[AST_MAX_EXTENSION];
616 char lastcid_num[AST_MAX_EXTENSION];
617 char lastcid_name[AST_MAX_EXTENSION];
618 char *origcid_num; /*!< malloced original callerid */
619 char *origcid_name; /*!< malloced original callerid */
620 char callwait_num[AST_MAX_EXTENSION];
621 char callwait_name[AST_MAX_EXTENSION];
622 char rdnis[AST_MAX_EXTENSION];
623 char dnid[AST_MAX_EXTENSION];
624 ast_group_t group;
625 int law;
626 int confno; /*!< Our conference */
627 int confusers; /*!< Who is using our conference */
628 int propconfno; /*!< Propagated conference number */
629 ast_group_t callgroup;
630 ast_group_t pickupgroup;
631 struct ast_variable *vars;
632 int channel; /*!< Channel Number or CRV */
633 int span; /*!< Span number */
634 time_t guardtime; /*!< Must wait this much time before using for new call */
635 int cid_signalling; /*!< CID signalling type bell202 or v23 */
636 int cid_start; /*!< CID start indicator, polarity or ring */
637 int callingpres; /*!< The value of callling presentation that we're going to use when placing a PRI call */
638 int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */
639 int cidcwexpire; /*!< When to expire our muting for CID/CW */
640 unsigned char *cidspill;
641 int cidpos;
642 int cidlen;
643 int ringt;
644 int ringt_base;
645 int stripmsd;
646 int callwaitcas;
647 int callwaitrings;
648 struct {
649 struct dahdi_echocanparams head;
650 struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
651 } echocancel;
652 int echotraining;
653 char echorest[20];
654 int busycount;
655 int busy_tonelength;
656 int busy_quietlength;
657 int callprogress;
658 struct timeval flashtime; /*!< Last flash-hook time */
659 struct ast_dsp *dsp;
660 int cref; /*!< Call reference number */
661 struct dahdi_dialoperation dop;
662 int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */
663 char finaldial[64];
664 char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
665 int amaflags; /*!< AMA Flags */
666 struct tdd_state *tdd; /*!< TDD flag */
667 char call_forward[AST_MAX_EXTENSION];
668 char mailbox[AST_MAX_EXTENSION];
669 struct ast_event_sub *mwi_event_sub;
670 char dialdest[256];
671 int onhooktime;
672 int msgstate;
673 int distinctivering; /*!< Which distinctivering to use */
674 int cidrings; /*!< Which ring to deliver CID on */
675 int dtmfrelax; /*!< whether to run in relaxed DTMF mode */
676 int fake_event;
677 int polarityonanswerdelay;
678 struct timeval polaritydelaytv;
679 int sendcalleridafter;
680 #ifdef HAVE_PRI
681 struct dahdi_pri *pri;
682 struct dahdi_pvt *bearer;
683 struct dahdi_pvt *realcall;
684 q931_call *call;
685 int prioffset;
686 int logicalspan;
687 #endif
688 int polarity;
689 int dsp_features;
690 #ifdef HAVE_SS7
691 struct dahdi_ss7 *ss7;
692 struct isup_call *ss7call;
693 char charge_number[50];
694 char gen_add_number[50];
695 char gen_dig_number[50];
696 char orig_called_num[50];
697 char redirecting_num[50];
698 char generic_name[50];
699 unsigned char gen_add_num_plan;
700 unsigned char gen_add_nai;
701 unsigned char gen_add_pres_ind;
702 unsigned char gen_add_type;
703 unsigned char gen_dig_type;
704 unsigned char gen_dig_scheme;
705 char jip_number[50];
706 unsigned char lspi_type;
707 unsigned char lspi_scheme;
708 unsigned char lspi_context;
709 char lspi_ident[50];
710 unsigned int call_ref_ident;
711 unsigned int call_ref_pc;
712 unsigned char calling_party_cat;
713 int transcap;
714 int cic; /*!< CIC associated with channel */
715 unsigned int dpc; /*!< CIC's DPC */
716 unsigned int loopedback:1;
717 #endif
718 char begindigit;
719 int muting;
720 } *iflist = NULL, *ifend = NULL;
722 /*! \brief Channel configuration from chan_dahdi.conf .
723 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
724 * Generally there is a field here for every possible configuration item.
726 * The state of fields is saved along the parsing and whenever a 'channel'
727 * statement is reached, the current dahdi_chan_conf is used to configure the
728 * channel (struct dahdi_pvt)
730 * \see dahdi_chan_init for the default values.
732 struct dahdi_chan_conf {
733 struct dahdi_pvt chan;
734 #ifdef HAVE_PRI
735 struct dahdi_pri pri;
736 #endif
738 #ifdef HAVE_SS7
739 struct dahdi_ss7 ss7;
740 #endif
741 struct dahdi_params timing;
742 int is_sig_auto; /*!< Use channel signalling from DAHDI? */
744 char smdi_port[SMDI_MAX_FILENAME_LEN];
747 /*! returns a new dahdi_chan_conf with default values (by-value) */
748 static struct dahdi_chan_conf dahdi_chan_conf_default(void) {
749 /* recall that if a field is not included here it is initialized
750 * to 0 or equivalent
752 struct dahdi_chan_conf conf = {
753 #ifdef HAVE_PRI
754 .pri = {
755 .nsf = PRI_NSF_NONE,
756 .switchtype = PRI_SWITCH_NI2,
757 .dialplan = PRI_UNKNOWN + 1,
758 .localdialplan = PRI_NATIONAL_ISDN + 1,
759 .nodetype = PRI_CPE,
761 .minunused = 2,
762 .idleext = "",
763 .idledial = "",
764 .internationalprefix = "",
765 .nationalprefix = "",
766 .localprefix = "",
767 .privateprefix = "",
768 .unknownprefix = "",
769 .resetinterval = -1,
771 #endif
772 #ifdef HAVE_SS7
773 .ss7 = {
774 .called_nai = SS7_NAI_NATIONAL,
775 .calling_nai = SS7_NAI_NATIONAL,
776 .internationalprefix = "",
777 .nationalprefix = "",
778 .subscriberprefix = "",
779 .unknownprefix = ""
781 #endif
782 .chan = {
783 .context = "default",
784 .cid_num = "",
785 .cid_name = "",
786 .mohinterpret = "default",
787 .mohsuggest = "",
788 .parkinglot = "",
789 .transfertobusy = 1,
791 .cid_signalling = CID_SIG_BELL,
792 .cid_start = CID_START_RING,
793 .dahditrcallerid = 0,
794 .use_callerid = 1,
795 .sig = -1,
796 .outsigmod = -1,
798 .cid_rxgain = +5.0,
800 .tonezone = -1,
802 .echocancel.head.tap_length = 1,
804 .busycount = 3,
806 .accountcode = "",
808 .mailbox = "",
811 .polarityonanswerdelay = 600,
813 .sendcalleridafter = DEFAULT_CIDRINGS,
815 .buf_policy = DAHDI_POLICY_IMMEDIATE,
816 .buf_no = numbufs
818 .timing = {
819 .prewinktime = -1,
820 .preflashtime = -1,
821 .winktime = -1,
822 .flashtime = -1,
823 .starttime = -1,
824 .rxwinktime = -1,
825 .rxflashtime = -1,
826 .debouncetime = -1
828 .is_sig_auto = 1,
829 .smdi_port = "/dev/ttyS0",
832 return conf;
836 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause);
837 static int dahdi_digit_begin(struct ast_channel *ast, char digit);
838 static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
839 static int dahdi_sendtext(struct ast_channel *c, const char *text);
840 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout);
841 static int dahdi_hangup(struct ast_channel *ast);
842 static int dahdi_answer(struct ast_channel *ast);
843 static struct ast_frame *dahdi_read(struct ast_channel *ast);
844 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
845 static struct ast_frame *dahdi_exception(struct ast_channel *ast);
846 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
847 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
848 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
849 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
850 static int handle_init_event(struct dahdi_pvt *i, int event);
852 static const struct ast_channel_tech dahdi_tech = {
853 .type = "DAHDI",
854 .description = tdesc,
855 .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
856 .requester = dahdi_request,
857 .send_digit_begin = dahdi_digit_begin,
858 .send_digit_end = dahdi_digit_end,
859 .send_text = dahdi_sendtext,
860 .call = dahdi_call,
861 .hangup = dahdi_hangup,
862 .answer = dahdi_answer,
863 .read = dahdi_read,
864 .write = dahdi_write,
865 .bridge = dahdi_bridge,
866 .exception = dahdi_exception,
867 .indicate = dahdi_indicate,
868 .fixup = dahdi_fixup,
869 .setoption = dahdi_setoption,
870 .func_channel_read = dahdi_func_read,
873 #ifdef HAVE_PRI
874 #define GET_CHANNEL(p) ((p)->bearer ? (p)->bearer->channel : p->channel)
875 #else
876 #define GET_CHANNEL(p) ((p)->channel)
877 #endif
879 struct dahdi_pvt *round_robin[32];
881 #ifdef HAVE_PRI
882 static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
884 int res;
885 /* Grab the lock first */
886 do {
887 res = ast_mutex_trylock(&pri->lock);
888 if (res) {
889 DEADLOCK_AVOIDANCE(&pvt->lock);
891 } while (res);
892 /* Then break the poll */
893 if (pri->master != AST_PTHREADT_NULL)
894 pthread_kill(pri->master, SIGURG);
895 return 0;
897 #endif
899 #ifdef HAVE_SS7
900 static inline void ss7_rel(struct dahdi_ss7 *ss7)
902 ast_mutex_unlock(&ss7->lock);
905 static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
907 int res;
908 /* Grab the lock first */
909 do {
910 res = ast_mutex_trylock(&pri->lock);
911 if (res) {
912 DEADLOCK_AVOIDANCE(&pvt->lock);
914 } while (res);
915 /* Then break the poll */
916 if (pri->master != AST_PTHREADT_NULL)
917 pthread_kill(pri->master, SIGURG);
918 return 0;
920 #endif
921 #define NUM_CADENCE_MAX 25
922 static int num_cadence = 4;
923 static int user_has_defined_cadences = 0;
925 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
926 { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
927 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
928 { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
929 { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
932 /*! \brief cidrings says in which pause to transmit the cid information, where the first pause
933 * is 1, the second pause is 2 and so on.
936 static int cidrings[NUM_CADENCE_MAX] = {
937 2, /*!< Right after first long ring */
938 4, /*!< Right after long part */
939 3, /*!< After third chirp */
940 2, /*!< Second spell */
943 /* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
944 static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
946 #define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
947 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
949 #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
950 #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
952 static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
954 int res;
955 if (p->subs[SUB_REAL].owner == ast)
956 res = 0;
957 else if (p->subs[SUB_CALLWAIT].owner == ast)
958 res = 1;
959 else if (p->subs[SUB_THREEWAY].owner == ast)
960 res = 2;
961 else {
962 res = -1;
963 if (!nullok)
964 ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
966 return res;
969 #ifdef HAVE_PRI
970 static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri)
971 #else
972 static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri)
973 #endif
975 #ifdef HAVE_PRI
976 if (pri)
977 ast_mutex_unlock(&pri->lock);
978 #endif
979 for (;;) {
980 if (p->subs[a].owner) {
981 if (ast_channel_trylock(p->subs[a].owner)) {
982 DEADLOCK_AVOIDANCE(&p->lock);
983 } else {
984 ast_queue_frame(p->subs[a].owner, &ast_null_frame);
985 ast_channel_unlock(p->subs[a].owner);
986 break;
988 } else
989 break;
991 #ifdef HAVE_PRI
992 if (pri)
993 ast_mutex_lock(&pri->lock);
994 #endif
997 static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *data)
999 #ifdef HAVE_PRI
1000 struct dahdi_pri *pri = (struct dahdi_pri*) data;
1001 #endif
1002 #ifdef HAVE_SS7
1003 struct dahdi_ss7 *ss7 = (struct dahdi_ss7*) data;
1004 #endif
1005 /* We must unlock the PRI to avoid the possibility of a deadlock */
1006 #if defined(HAVE_PRI) || defined(HAVE_SS7)
1007 if (data) {
1008 switch (p->sig) {
1009 #ifdef HAVE_PRI
1010 case SIG_BRI:
1011 case SIG_BRI_PTMP:
1012 case SIG_PRI:
1013 ast_mutex_unlock(&pri->lock);
1014 break;
1015 #endif
1016 #ifdef HAVE_SS7
1017 case SIG_SS7:
1018 ast_mutex_unlock(&ss7->lock);
1019 break;
1020 #endif
1021 default:
1022 break;
1025 #endif
1026 for (;;) {
1027 if (p->owner) {
1028 if (ast_channel_trylock(p->owner)) {
1029 DEADLOCK_AVOIDANCE(&p->lock);
1030 } else {
1031 ast_queue_frame(p->owner, f);
1032 ast_channel_unlock(p->owner);
1033 break;
1035 } else
1036 break;
1038 #if defined(HAVE_PRI) || defined(HAVE_SS7)
1039 if (data) {
1040 switch (p->sig) {
1041 #ifdef HAVE_PRI
1042 case SIG_BRI:
1043 case SIG_BRI_PTMP:
1044 case SIG_PRI:
1045 ast_mutex_lock(&pri->lock);
1046 break;
1047 #endif
1048 #ifdef HAVE_SS7
1049 case SIG_SS7:
1050 ast_mutex_lock(&ss7->lock);
1051 break;
1052 #endif
1053 default:
1054 break;
1058 #endif
1061 static int restore_gains(struct dahdi_pvt *p);
1063 static void swap_subs(struct dahdi_pvt *p, int a, int b)
1065 int tchan;
1066 int tinthreeway;
1067 struct ast_channel *towner;
1069 ast_debug(1, "Swapping %d and %d\n", a, b);
1071 tchan = p->subs[a].chan;
1072 towner = p->subs[a].owner;
1073 tinthreeway = p->subs[a].inthreeway;
1075 p->subs[a].chan = p->subs[b].chan;
1076 p->subs[a].owner = p->subs[b].owner;
1077 p->subs[a].inthreeway = p->subs[b].inthreeway;
1079 p->subs[b].chan = tchan;
1080 p->subs[b].owner = towner;
1081 p->subs[b].inthreeway = tinthreeway;
1083 if (p->subs[a].owner)
1084 ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
1085 if (p->subs[b].owner)
1086 ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
1087 wakeup_sub(p, a, NULL);
1088 wakeup_sub(p, b, NULL);
1091 static int dahdi_open(char *fn)
1093 int fd;
1094 int isnum;
1095 int chan = 0;
1096 int bs;
1097 int x;
1098 isnum = 1;
1099 for (x = 0; x < strlen(fn); x++) {
1100 if (!isdigit(fn[x])) {
1101 isnum = 0;
1102 break;
1105 if (isnum) {
1106 chan = atoi(fn);
1107 if (chan < 1) {
1108 ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
1109 return -1;
1111 fn = "/dev/dahdi/channel";
1113 fd = open(fn, O_RDWR | O_NONBLOCK);
1114 if (fd < 0) {
1115 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
1116 return -1;
1118 if (chan) {
1119 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
1120 x = errno;
1121 close(fd);
1122 errno = x;
1123 ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
1124 return -1;
1127 bs = READ_SIZE;
1128 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
1129 ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs, strerror(errno));
1130 x = errno;
1131 close(fd);
1132 errno = x;
1133 return -1;
1135 return fd;
1138 static void dahdi_close(int fd)
1140 if (fd > 0)
1141 close(fd);
1144 static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
1146 dahdi_close(chan_pvt->subs[sub_num].dfd);
1147 chan_pvt->subs[sub_num].dfd = -1;
1150 #ifdef HAVE_PRI
1151 static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
1153 dahdi_close(pri->fds[fd_num]);
1154 pri->fds[fd_num] = -1;
1156 #endif
1158 #ifdef HAVE_SS7
1159 static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
1161 dahdi_close(ss7->fds[fd_num]);
1162 ss7->fds[fd_num] = -1;
1164 #endif
1166 static int dahdi_setlinear(int dfd, int linear)
1168 int res;
1169 res = ioctl(dfd, DAHDI_SETLINEAR, &linear);
1170 if (res)
1171 return res;
1172 return 0;
1176 static int alloc_sub(struct dahdi_pvt *p, int x)
1178 struct dahdi_bufferinfo bi;
1179 int res;
1180 if (p->subs[x].dfd >= 0) {
1181 ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
1182 return -1;
1185 p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
1186 if (p->subs[x].dfd <= -1) {
1187 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
1188 return -1;
1191 res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
1192 if (!res) {
1193 bi.txbufpolicy = p->buf_policy;
1194 bi.rxbufpolicy = p->buf_policy;
1195 bi.numbufs = p->buf_no;
1196 res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
1197 if (res < 0) {
1198 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
1200 } else
1201 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
1203 if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
1204 ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
1205 dahdi_close_sub(p, x);
1206 p->subs[x].dfd = -1;
1207 return -1;
1209 ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
1210 return 0;
1213 static int unalloc_sub(struct dahdi_pvt *p, int x)
1215 if (!x) {
1216 ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
1217 return -1;
1219 ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
1220 dahdi_close_sub(p, x);
1221 p->subs[x].linear = 0;
1222 p->subs[x].chan = 0;
1223 p->subs[x].owner = NULL;
1224 p->subs[x].inthreeway = 0;
1225 p->polarity = POLARITY_IDLE;
1226 memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
1227 return 0;
1230 static int digit_to_dtmfindex(char digit)
1232 if (isdigit(digit))
1233 return DAHDI_TONE_DTMF_BASE + (digit - '0');
1234 else if (digit >= 'A' && digit <= 'D')
1235 return DAHDI_TONE_DTMF_A + (digit - 'A');
1236 else if (digit >= 'a' && digit <= 'd')
1237 return DAHDI_TONE_DTMF_A + (digit - 'a');
1238 else if (digit == '*')
1239 return DAHDI_TONE_DTMF_s;
1240 else if (digit == '#')
1241 return DAHDI_TONE_DTMF_p;
1242 else
1243 return -1;
1246 static int dahdi_digit_begin(struct ast_channel *chan, char digit)
1248 struct dahdi_pvt *pvt;
1249 int idx;
1250 int dtmf = -1;
1252 pvt = chan->tech_pvt;
1254 ast_mutex_lock(&pvt->lock);
1256 idx = dahdi_get_index(chan, pvt, 0);
1258 if ((idx != SUB_REAL) || !pvt->owner)
1259 goto out;
1261 #ifdef HAVE_PRI
1262 if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP))
1263 && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
1264 if (pvt->setup_ack) {
1265 if (!pri_grab(pvt, pvt->pri)) {
1266 pri_information(pvt->pri->pri, pvt->call, digit);
1267 pri_rel(pvt->pri);
1268 } else
1269 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
1270 } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
1271 int res;
1272 ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit);
1273 res = strlen(pvt->dialdest);
1274 pvt->dialdest[res++] = digit;
1275 pvt->dialdest[res] = '\0';
1277 goto out;
1279 #endif
1280 if ((dtmf = digit_to_dtmfindex(digit)) == -1)
1281 goto out;
1283 if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
1284 int res;
1285 struct dahdi_dialoperation zo = {
1286 .op = DAHDI_DIAL_OP_APPEND,
1289 zo.dialstr[0] = 'T';
1290 zo.dialstr[1] = digit;
1291 zo.dialstr[2] = '\0';
1292 if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
1293 ast_log(LOG_WARNING, "Couldn't dial digit %c: %s\n", digit, strerror(errno));
1294 else
1295 pvt->dialing = 1;
1296 } else {
1297 ast_debug(1, "Started VLDTMF digit '%c'\n", digit);
1298 pvt->dialing = 1;
1299 pvt->begindigit = digit;
1302 out:
1303 ast_mutex_unlock(&pvt->lock);
1305 return 0;
1308 static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
1310 struct dahdi_pvt *pvt;
1311 int res = 0;
1312 int idx;
1313 int x;
1315 pvt = chan->tech_pvt;
1317 ast_mutex_lock(&pvt->lock);
1319 idx = dahdi_get_index(chan, pvt, 0);
1321 if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
1322 goto out;
1324 #ifdef HAVE_PRI
1325 /* This means that the digit was already sent via PRI signalling */
1326 if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP))
1327 && !pvt->begindigit)
1328 goto out;
1329 #endif
1331 if (pvt->begindigit) {
1332 x = -1;
1333 ast_debug(1, "Ending VLDTMF digit '%c'\n", digit);
1334 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
1335 pvt->dialing = 0;
1336 pvt->begindigit = 0;
1339 out:
1340 ast_mutex_unlock(&pvt->lock);
1342 return res;
1345 static char *events[] = {
1346 "No event",
1347 "On hook",
1348 "Ring/Answered",
1349 "Wink/Flash",
1350 "Alarm",
1351 "No more alarm",
1352 "HDLC Abort",
1353 "HDLC Overrun",
1354 "HDLC Bad FCS",
1355 "Dial Complete",
1356 "Ringer On",
1357 "Ringer Off",
1358 "Hook Transition Complete",
1359 "Bits Changed",
1360 "Pulse Start",
1361 "Timer Expired",
1362 "Timer Ping",
1363 "Polarity Reversal",
1364 "Ring Begin",
1367 static struct {
1368 int alarm;
1369 char *name;
1370 } alarms[] = {
1371 { DAHDI_ALARM_RED, "Red Alarm" },
1372 { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
1373 { DAHDI_ALARM_BLUE, "Blue Alarm" },
1374 { DAHDI_ALARM_RECOVER, "Recovering" },
1375 { DAHDI_ALARM_LOOPBACK, "Loopback" },
1376 { DAHDI_ALARM_NOTOPEN, "Not Open" },
1377 { DAHDI_ALARM_NONE, "None" },
1380 static char *alarm2str(int alm)
1382 int x;
1383 for (x = 0; x < ARRAY_LEN(alarms); x++) {
1384 if (alarms[x].alarm & alm)
1385 return alarms[x].name;
1387 return alm ? "Unknown Alarm" : "No Alarm";
1390 static char *event2str(int event)
1392 static char buf[256];
1393 if ((event < (ARRAY_LEN(events))) && (event > -1))
1394 return events[event];
1395 sprintf(buf, "Event %d", event); /* safe */
1396 return buf;
1399 #ifdef HAVE_PRI
1400 static char *dialplan2str(int dialplan)
1402 if (dialplan == -1 || dialplan == -2) {
1403 return("Dynamically set dialplan in ISDN");
1405 return (pri_plan2str(dialplan));
1407 #endif
1409 static char *dahdi_sig2str(int sig)
1411 static char buf[256];
1412 switch (sig) {
1413 case SIG_EM:
1414 return "E & M Immediate";
1415 case SIG_EMWINK:
1416 return "E & M Wink";
1417 case SIG_EM_E1:
1418 return "E & M E1";
1419 case SIG_FEATD:
1420 return "Feature Group D (DTMF)";
1421 case SIG_FEATDMF:
1422 return "Feature Group D (MF)";
1423 case SIG_FEATDMF_TA:
1424 return "Feature Groud D (MF) Tandem Access";
1425 case SIG_FEATB:
1426 return "Feature Group B (MF)";
1427 case SIG_E911:
1428 return "E911 (MF)";
1429 case SIG_FGC_CAMA:
1430 return "FGC/CAMA (Dialpulse)";
1431 case SIG_FGC_CAMAMF:
1432 return "FGC/CAMA (MF)";
1433 case SIG_FXSLS:
1434 return "FXS Loopstart";
1435 case SIG_FXSGS:
1436 return "FXS Groundstart";
1437 case SIG_FXSKS:
1438 return "FXS Kewlstart";
1439 case SIG_FXOLS:
1440 return "FXO Loopstart";
1441 case SIG_FXOGS:
1442 return "FXO Groundstart";
1443 case SIG_FXOKS:
1444 return "FXO Kewlstart";
1445 case SIG_PRI:
1446 return "ISDN PRI";
1447 case SIG_BRI:
1448 return "ISDN BRI Point to Point";
1449 case SIG_BRI_PTMP:
1450 return "ISDN BRI Point to MultiPoint";
1451 case SIG_SS7:
1452 return "SS7";
1453 case SIG_SF:
1454 return "SF (Tone) Immediate";
1455 case SIG_SFWINK:
1456 return "SF (Tone) Wink";
1457 case SIG_SF_FEATD:
1458 return "SF (Tone) with Feature Group D (DTMF)";
1459 case SIG_SF_FEATDMF:
1460 return "SF (Tone) with Feature Group D (MF)";
1461 case SIG_SF_FEATB:
1462 return "SF (Tone) with Feature Group B (MF)";
1463 case SIG_GR303FXOKS:
1464 return "GR-303 with FXOKS";
1465 case SIG_GR303FXSKS:
1466 return "GR-303 with FXSKS";
1467 case 0:
1468 return "Pseudo";
1469 default:
1470 snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
1471 return buf;
1475 #define sig2str dahdi_sig2str
1477 static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
1479 /* If the conference already exists, and we're already in it
1480 don't bother doing anything */
1481 struct dahdi_confinfo zi;
1483 memset(&zi, 0, sizeof(zi));
1484 zi.chan = 0;
1486 if (slavechannel > 0) {
1487 /* If we have only one slave, do a digital mon */
1488 zi.confmode = DAHDI_CONF_DIGITALMON;
1489 zi.confno = slavechannel;
1490 } else {
1491 if (!idx) {
1492 /* Real-side and pseudo-side both participate in conference */
1493 zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
1494 DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
1495 } else
1496 zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
1497 zi.confno = p->confno;
1499 if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
1500 return 0;
1501 if (c->dfd < 0)
1502 return 0;
1503 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
1504 ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
1505 return -1;
1507 if (slavechannel < 1) {
1508 p->confno = zi.confno;
1510 memcpy(&c->curconf, &zi, sizeof(c->curconf));
1511 ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
1512 return 0;
1515 static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
1517 /* If they're listening to our channel, they're ours */
1518 if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
1519 return 1;
1520 /* If they're a talker on our (allocated) conference, they're ours */
1521 if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
1522 return 1;
1523 return 0;
1526 static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
1528 struct dahdi_confinfo zi;
1529 if (/* Can't delete if there's no dfd */
1530 (c->dfd < 0) ||
1531 /* Don't delete from the conference if it's not our conference */
1532 !isourconf(p, c)
1533 /* Don't delete if we don't think it's conferenced at all (implied) */
1534 ) return 0;
1535 memset(&zi, 0, sizeof(zi));
1536 zi.chan = 0;
1537 zi.confno = 0;
1538 zi.confmode = 0;
1539 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
1540 ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
1541 return -1;
1543 ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
1544 memcpy(&c->curconf, &zi, sizeof(c->curconf));
1545 return 0;
1548 static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
1550 int x;
1551 int useslavenative;
1552 struct dahdi_pvt *slave = NULL;
1553 /* Start out optimistic */
1554 useslavenative = 1;
1555 /* Update conference state in a stateless fashion */
1556 for (x = 0; x < 3; x++) {
1557 /* Any three-way calling makes slave native mode *definitely* out
1558 of the question */
1559 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
1560 useslavenative = 0;
1562 /* If we don't have any 3-way calls, check to see if we have
1563 precisely one slave */
1564 if (useslavenative) {
1565 for (x = 0; x < MAX_SLAVES; x++) {
1566 if (p->slaves[x]) {
1567 if (slave) {
1568 /* Whoops already have a slave! No
1569 slave native and stop right away */
1570 slave = NULL;
1571 useslavenative = 0;
1572 break;
1573 } else {
1574 /* We have one slave so far */
1575 slave = p->slaves[x];
1580 /* If no slave, slave native definitely out */
1581 if (!slave)
1582 useslavenative = 0;
1583 else if (slave->law != p->law) {
1584 useslavenative = 0;
1585 slave = NULL;
1587 if (out)
1588 *out = slave;
1589 return useslavenative;
1592 static int reset_conf(struct dahdi_pvt *p)
1594 struct dahdi_confinfo zi;
1595 memset(&zi, 0, sizeof(zi));
1596 p->confno = -1;
1597 memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
1598 if (p->subs[SUB_REAL].dfd > -1) {
1599 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
1600 ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
1602 return 0;
1605 static int update_conf(struct dahdi_pvt *p)
1607 int needconf = 0;
1608 int x;
1609 int useslavenative;
1610 struct dahdi_pvt *slave = NULL;
1612 useslavenative = isslavenative(p, &slave);
1613 /* Start with the obvious, general stuff */
1614 for (x = 0; x < 3; x++) {
1615 /* Look for three way calls */
1616 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
1617 conf_add(p, &p->subs[x], x, 0);
1618 needconf++;
1619 } else {
1620 conf_del(p, &p->subs[x], x);
1623 /* If we have a slave, add him to our conference now. or DAX
1624 if this is slave native */
1625 for (x = 0; x < MAX_SLAVES; x++) {
1626 if (p->slaves[x]) {
1627 if (useslavenative)
1628 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
1629 else {
1630 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
1631 needconf++;
1635 /* If we're supposed to be in there, do so now */
1636 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
1637 if (useslavenative)
1638 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
1639 else {
1640 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
1641 needconf++;
1644 /* If we have a master, add ourselves to his conference */
1645 if (p->master) {
1646 if (isslavenative(p->master, NULL)) {
1647 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
1648 } else {
1649 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
1652 if (!needconf) {
1653 /* Nobody is left (or should be left) in our conference.
1654 Kill it. */
1655 p->confno = -1;
1657 ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
1658 return 0;
1661 static void dahdi_enable_ec(struct dahdi_pvt *p)
1663 int x;
1664 int res;
1665 if (!p)
1666 return;
1667 if (p->echocanon) {
1668 ast_debug(1, "Echo cancellation already on\n");
1669 return;
1671 if (p->digital) {
1672 ast_debug(1, "Echo cancellation isn't required on digital connection\n");
1673 return;
1675 if (p->echocancel.head.tap_length) {
1676 if ((p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP) || (p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
1677 x = 1;
1678 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
1679 if (res)
1680 ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n", p->channel, strerror(errno));
1682 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
1683 if (res) {
1684 ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
1685 } else {
1686 p->echocanon = 1;
1687 ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
1689 } else
1690 ast_debug(1, "No echo cancellation requested\n");
1693 static void dahdi_train_ec(struct dahdi_pvt *p)
1695 int x;
1696 int res;
1698 if (p && p->echocanon && p->echotraining) {
1699 x = p->echotraining;
1700 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
1701 if (res)
1702 ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
1703 else
1704 ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
1705 } else {
1706 ast_debug(1, "No echo training requested\n");
1710 static void dahdi_disable_ec(struct dahdi_pvt *p)
1712 int res;
1714 if (p->echocanon) {
1715 struct dahdi_echocanparams ecp = { .tap_length = 0 };
1717 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
1719 if (res)
1720 ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
1721 else
1722 ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
1725 p->echocanon = 0;
1728 static void fill_txgain(struct dahdi_gains *g, float gain, int law)
1730 int j;
1731 int k;
1732 float linear_gain = pow(10.0, gain / 20.0);
1734 switch (law) {
1735 case DAHDI_LAW_ALAW:
1736 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
1737 if (gain) {
1738 k = (int) (((float) AST_ALAW(j)) * linear_gain);
1739 if (k > 32767) k = 32767;
1740 if (k < -32767) k = -32767;
1741 g->txgain[j] = AST_LIN2A(k);
1742 } else {
1743 g->txgain[j] = j;
1746 break;
1747 case DAHDI_LAW_MULAW:
1748 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
1749 if (gain) {
1750 k = (int) (((float) AST_MULAW(j)) * linear_gain);
1751 if (k > 32767) k = 32767;
1752 if (k < -32767) k = -32767;
1753 g->txgain[j] = AST_LIN2MU(k);
1754 } else {
1755 g->txgain[j] = j;
1758 break;
1762 static void fill_rxgain(struct dahdi_gains *g, float gain, int law)
1764 int j;
1765 int k;
1766 float linear_gain = pow(10.0, gain / 20.0);
1768 switch (law) {
1769 case DAHDI_LAW_ALAW:
1770 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
1771 if (gain) {
1772 k = (int) (((float) AST_ALAW(j)) * linear_gain);
1773 if (k > 32767) k = 32767;
1774 if (k < -32767) k = -32767;
1775 g->rxgain[j] = AST_LIN2A(k);
1776 } else {
1777 g->rxgain[j] = j;
1780 break;
1781 case DAHDI_LAW_MULAW:
1782 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
1783 if (gain) {
1784 k = (int) (((float) AST_MULAW(j)) * linear_gain);
1785 if (k > 32767) k = 32767;
1786 if (k < -32767) k = -32767;
1787 g->rxgain[j] = AST_LIN2MU(k);
1788 } else {
1789 g->rxgain[j] = j;
1792 break;
1796 static int set_actual_txgain(int fd, int chan, float gain, int law)
1798 struct dahdi_gains g;
1799 int res;
1801 memset(&g, 0, sizeof(g));
1802 g.chan = chan;
1803 res = ioctl(fd, DAHDI_GETGAINS, &g);
1804 if (res) {
1805 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
1806 return res;
1809 fill_txgain(&g, gain, law);
1811 return ioctl(fd, DAHDI_SETGAINS, &g);
1814 static int set_actual_rxgain(int fd, int chan, float gain, int law)
1816 struct dahdi_gains g;
1817 int res;
1819 memset(&g, 0, sizeof(g));
1820 g.chan = chan;
1821 res = ioctl(fd, DAHDI_GETGAINS, &g);
1822 if (res) {
1823 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
1824 return res;
1827 fill_rxgain(&g, gain, law);
1829 return ioctl(fd, DAHDI_SETGAINS, &g);
1832 static int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law)
1834 return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law);
1837 static int bump_gains(struct dahdi_pvt *p)
1839 int res;
1841 /* Bump receive gain by value stored in cid_rxgain */
1842 res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->law);
1843 if (res) {
1844 ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
1845 return -1;
1848 return 0;
1851 static int restore_gains(struct dahdi_pvt *p)
1853 int res;
1855 res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
1856 if (res) {
1857 ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
1858 return -1;
1861 return 0;
1864 static inline int dahdi_set_hook(int fd, int hs)
1866 int x, res;
1868 x = hs;
1869 res = ioctl(fd, DAHDI_HOOK, &x);
1871 if (res < 0) {
1872 if (errno == EINPROGRESS)
1873 return 0;
1874 ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
1875 /* will expectedly fail if phone is off hook during operation, such as during a restart */
1878 return res;
1881 static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
1883 int x, y, res;
1884 x = muted;
1885 if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
1886 y = 1;
1887 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
1888 if (res)
1889 ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n", p->channel, strerror(errno));
1891 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
1892 if (res < 0)
1893 ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
1894 return res;
1897 static int save_conference(struct dahdi_pvt *p)
1899 struct dahdi_confinfo c;
1900 int res;
1901 if (p->saveconf.confmode) {
1902 ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
1903 return -1;
1905 p->saveconf.chan = 0;
1906 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
1907 if (res) {
1908 ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
1909 p->saveconf.confmode = 0;
1910 return -1;
1912 c.chan = 0;
1913 c.confno = 0;
1914 c.confmode = DAHDI_CONF_NORMAL;
1915 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
1916 if (res) {
1917 ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
1918 return -1;
1920 ast_debug(1, "Disabled conferencing\n");
1921 return 0;
1925 * \brief Send MWI state change
1927 * \arg mailbox_full This is the mailbox associated with the FXO line that the
1928 * MWI state has changed on.
1929 * \arg thereornot This argument should simply be set to 1 or 0, to indicate
1930 * whether there are messages waiting or not.
1932 * \return nothing
1934 * This function does two things:
1936 * 1) It generates an internal Asterisk event notifying any other module that
1937 * cares about MWI that the state of a mailbox has changed.
1939 * 2) It runs the script specified by the mwimonitornotify option to allow
1940 * some custom handling of the state change.
1942 static void notify_message(char *mailbox_full, int thereornot)
1944 char s[sizeof(mwimonitornotify) + 80];
1945 struct ast_event *event;
1946 char *mailbox, *context;
1948 /* Strip off @default */
1949 context = mailbox = ast_strdupa(mailbox_full);
1950 strsep(&context, "@");
1951 if (ast_strlen_zero(context))
1952 context = "default";
1954 if (!(event = ast_event_new(AST_EVENT_MWI,
1955 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
1956 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
1957 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
1958 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
1959 AST_EVENT_IE_END))) {
1960 return;
1963 ast_event_queue_and_cache(event,
1964 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR,
1965 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR,
1966 AST_EVENT_IE_END);
1968 if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
1969 snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
1970 ast_safe_system(s);
1974 static int restore_conference(struct dahdi_pvt *p)
1976 int res;
1977 if (p->saveconf.confmode) {
1978 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
1979 p->saveconf.confmode = 0;
1980 if (res) {
1981 ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
1982 return -1;
1985 ast_debug(1, "Restored conferencing\n");
1986 return 0;
1989 static int send_callerid(struct dahdi_pvt *p);
1991 static int send_cwcidspill(struct dahdi_pvt *p)
1993 p->callwaitcas = 0;
1994 p->cidcwexpire = 0;
1995 if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
1996 return -1;
1997 p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
1998 /* Make sure we account for the end */
1999 p->cidlen += READ_SIZE * 4;
2000 p->cidpos = 0;
2001 send_callerid(p);
2002 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
2003 return 0;
2006 static int has_voicemail(struct dahdi_pvt *p)
2008 int new_msgs;
2009 struct ast_event *event;
2010 char *mailbox, *context;
2012 mailbox = context = ast_strdupa(p->mailbox);
2013 strsep(&context, "@");
2014 if (ast_strlen_zero(context))
2015 context = "default";
2017 event = ast_event_get_cached(AST_EVENT_MWI,
2018 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
2019 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
2020 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
2021 AST_EVENT_IE_END);
2023 if (event) {
2024 new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
2025 ast_event_destroy(event);
2026 } else
2027 new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
2029 return new_msgs;
2032 static int send_callerid(struct dahdi_pvt *p)
2034 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
2035 int res;
2036 /* Take out of linear mode if necessary */
2037 if (p->subs[SUB_REAL].linear) {
2038 p->subs[SUB_REAL].linear = 0;
2039 dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
2041 while (p->cidpos < p->cidlen) {
2042 res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
2043 if (res < 0) {
2044 if (errno == EAGAIN)
2045 return 0;
2046 else {
2047 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
2048 return -1;
2051 if (!res)
2052 return 0;
2053 p->cidpos += res;
2055 ast_free(p->cidspill);
2056 p->cidspill = NULL;
2057 if (p->callwaitcas) {
2058 /* Wait for CID/CW to expire */
2059 p->cidcwexpire = CIDCW_EXPIRE_SAMPLES;
2060 } else
2061 restore_conference(p);
2062 return 0;
2065 static int dahdi_callwait(struct ast_channel *ast)
2067 struct dahdi_pvt *p = ast->tech_pvt;
2068 p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
2069 if (p->cidspill) {
2070 ast_log(LOG_WARNING, "Spill already exists?!?\n");
2071 ast_free(p->cidspill);
2073 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
2074 return -1;
2075 save_conference(p);
2076 /* Silence */
2077 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
2078 if (!p->callwaitrings && p->callwaitingcallerid) {
2079 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
2080 p->callwaitcas = 1;
2081 p->cidlen = 2400 + 680 + READ_SIZE * 4;
2082 } else {
2083 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
2084 p->callwaitcas = 0;
2085 p->cidlen = 2400 + READ_SIZE * 4;
2087 p->cidpos = 0;
2088 send_callerid(p);
2090 return 0;
2093 #ifdef HAVE_SS7
2094 static unsigned char cid_pres2ss7pres(int cid_pres)
2096 return (cid_pres >> 5) & 0x03;
2099 static unsigned char cid_pres2ss7screen(int cid_pres)
2101 return cid_pres & 0x03;
2103 #endif
2105 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
2107 struct dahdi_pvt *p = ast->tech_pvt;
2108 int x, res, idx,mysig;
2109 char *c, *n, *l;
2110 #ifdef HAVE_PRI
2111 char *s = NULL;
2112 #endif
2113 char dest[256]; /* must be same length as p->dialdest */
2114 ast_mutex_lock(&p->lock);
2115 ast_copy_string(dest, rdest, sizeof(dest));
2116 ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
2117 if ((ast->_state == AST_STATE_BUSY)) {
2118 p->subs[SUB_REAL].needbusy = 1;
2119 ast_mutex_unlock(&p->lock);
2120 return 0;
2122 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
2123 ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast->name);
2124 ast_mutex_unlock(&p->lock);
2125 return -1;
2127 p->dialednone = 0;
2128 if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
2130 /* Special pseudo -- automatically up */
2131 ast_setstate(ast, AST_STATE_UP);
2132 ast_mutex_unlock(&p->lock);
2133 return 0;
2135 x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
2136 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
2137 if (res)
2138 ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
2139 p->outgoing = 1;
2141 set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
2143 mysig = p->sig;
2144 if (p->outsigmod > -1)
2145 mysig = p->outsigmod;
2147 switch (mysig) {
2148 case SIG_FXOLS:
2149 case SIG_FXOGS:
2150 case SIG_FXOKS:
2151 if (p->owner == ast) {
2152 /* Normal ring, on hook */
2154 /* Don't send audio while on hook, until the call is answered */
2155 p->dialing = 1;
2156 if (p->use_callerid) {
2157 /* Generate the Caller-ID spill if desired */
2158 if (p->cidspill) {
2159 ast_log(LOG_WARNING, "cidspill already exists??\n");
2160 ast_free(p->cidspill);
2162 p->callwaitcas = 0;
2163 if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
2164 p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p));
2165 p->cidpos = 0;
2166 send_callerid(p);
2169 /* Choose proper cadence */
2170 if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
2171 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
2172 ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
2173 p->cidrings = cidrings[p->distinctivering - 1];
2174 } else {
2175 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
2176 ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
2177 p->cidrings = p->sendcalleridafter;
2180 /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
2181 c = strchr(dest, '/');
2182 if (c)
2183 c++;
2184 if (c && (strlen(c) < p->stripmsd)) {
2185 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
2186 c = NULL;
2188 if (c) {
2189 p->dop.op = DAHDI_DIAL_OP_REPLACE;
2190 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
2191 ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
2192 } else {
2193 p->dop.dialstr[0] = '\0';
2195 x = DAHDI_RING;
2196 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x) && (errno != EINPROGRESS)) {
2197 ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
2198 ast_mutex_unlock(&p->lock);
2199 return -1;
2201 p->dialing = 1;
2202 } else {
2203 /* Call waiting call */
2204 p->callwaitrings = 0;
2205 if (ast->cid.cid_num)
2206 ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num));
2207 else
2208 p->callwait_num[0] = '\0';
2209 if (ast->cid.cid_name)
2210 ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name));
2211 else
2212 p->callwait_name[0] = '\0';
2213 /* Call waiting tone instead */
2214 if (dahdi_callwait(ast)) {
2215 ast_mutex_unlock(&p->lock);
2216 return -1;
2218 /* Make ring-back */
2219 if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE))
2220 ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
2223 n = ast->cid.cid_name;
2224 l = ast->cid.cid_num;
2225 if (l)
2226 ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
2227 else
2228 p->lastcid_num[0] = '\0';
2229 if (n)
2230 ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
2231 else
2232 p->lastcid_name[0] = '\0';
2233 ast_setstate(ast, AST_STATE_RINGING);
2234 idx = dahdi_get_index(ast, p, 0);
2235 if (idx > -1) {
2236 p->subs[idx].needringing = 1;
2238 break;
2239 case SIG_FXSLS:
2240 case SIG_FXSGS:
2241 case SIG_FXSKS:
2242 case SIG_EMWINK:
2243 case SIG_EM:
2244 case SIG_EM_E1:
2245 case SIG_FEATD:
2246 case SIG_FEATDMF:
2247 case SIG_E911:
2248 case SIG_FGC_CAMA:
2249 case SIG_FGC_CAMAMF:
2250 case SIG_FEATB:
2251 case SIG_SFWINK:
2252 case SIG_SF:
2253 case SIG_SF_FEATD:
2254 case SIG_SF_FEATDMF:
2255 case SIG_FEATDMF_TA:
2256 case SIG_SF_FEATB:
2257 c = strchr(dest, '/');
2258 if (c)
2259 c++;
2260 else
2261 c = "";
2262 if (strlen(c) < p->stripmsd) {
2263 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
2264 ast_mutex_unlock(&p->lock);
2265 return -1;
2267 #ifdef HAVE_PRI
2268 /* Start the trunk, if not GR-303 */
2269 if (!p->pri) {
2270 #endif
2271 x = DAHDI_START;
2272 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
2273 if (res < 0) {
2274 if (errno != EINPROGRESS) {
2275 ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
2276 ast_mutex_unlock(&p->lock);
2277 return -1;
2280 #ifdef HAVE_PRI
2282 #endif
2283 ast_debug(1, "Dialing '%s'\n", c);
2284 p->dop.op = DAHDI_DIAL_OP_REPLACE;
2286 c += p->stripmsd;
2288 switch (mysig) {
2289 case SIG_FEATD:
2290 l = ast->cid.cid_num;
2291 if (l)
2292 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
2293 else
2294 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
2295 break;
2296 case SIG_FEATDMF:
2297 l = ast->cid.cid_num;
2298 if (l)
2299 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
2300 else
2301 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c);
2302 break;
2303 case SIG_FEATDMF_TA:
2305 const char *cic, *ozz;
2307 /* If you have to go through a Tandem Access point you need to use this */
2308 ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
2309 if (!ozz)
2310 ozz = defaultozz;
2311 cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
2312 if (!cic)
2313 cic = defaultcic;
2314 if (!ozz || !cic) {
2315 ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
2316 ast_mutex_unlock(&p->lock);
2317 return -1;
2319 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
2320 snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
2321 p->whichwink = 0;
2323 break;
2324 case SIG_E911:
2325 ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
2326 break;
2327 case SIG_FGC_CAMA:
2328 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
2329 break;
2330 case SIG_FGC_CAMAMF:
2331 case SIG_FEATB:
2332 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
2333 break;
2334 default:
2335 if (p->pulse)
2336 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
2337 else
2338 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
2339 break;
2342 if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
2343 memset(p->echorest, 'w', sizeof(p->echorest) - 1);
2344 strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
2345 p->echorest[sizeof(p->echorest) - 1] = '\0';
2346 p->echobreak = 1;
2347 p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
2348 } else
2349 p->echobreak = 0;
2350 if (!res) {
2351 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
2352 int saveerr = errno;
2354 x = DAHDI_ONHOOK;
2355 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
2356 ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
2357 ast_mutex_unlock(&p->lock);
2358 return -1;
2360 } else
2361 ast_debug(1, "Deferring dialing...\n");
2363 p->dialing = 1;
2364 if (ast_strlen_zero(c))
2365 p->dialednone = 1;
2366 ast_setstate(ast, AST_STATE_DIALING);
2367 break;
2368 case 0:
2369 /* Special pseudo -- automatically up*/
2370 ast_setstate(ast, AST_STATE_UP);
2371 break;
2372 case SIG_PRI:
2373 case SIG_BRI:
2374 case SIG_BRI_PTMP:
2375 case SIG_SS7:
2376 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
2377 p->dialdest[0] = '\0';
2378 break;
2379 default:
2380 ast_debug(1, "not yet implemented\n");
2381 ast_mutex_unlock(&p->lock);
2382 return -1;
2384 #ifdef HAVE_SS7
2385 if (p->ss7) {
2386 char ss7_called_nai;
2387 int called_nai_strip;
2388 char ss7_calling_nai;
2389 int calling_nai_strip;
2390 const char *charge_str = NULL;
2391 const char *gen_address = NULL;
2392 const char *gen_digits = NULL;
2393 const char *gen_dig_type = NULL;
2394 const char *gen_dig_scheme = NULL;
2395 const char *gen_name = NULL;
2396 const char *jip_digits = NULL;
2397 const char *lspi_ident = NULL;
2398 const char *rlt_flag = NULL;
2399 const char *call_ref_id = NULL;
2400 const char *call_ref_pc = NULL;
2401 const char *send_far = NULL;
2403 c = strchr(dest, '/');
2404 if (c)
2405 c++;
2406 else
2407 c = dest;
2409 if (!p->hidecallerid) {
2410 l = ast->cid.cid_num;
2411 } else {
2412 l = NULL;
2415 if (ss7_grab(p, p->ss7)) {
2416 ast_log(LOG_WARNING, "Failed to grab SS7!\n");
2417 ast_mutex_unlock(&p->lock);
2418 return -1;
2420 p->digital = IS_DIGITAL(ast->transfercapability);
2421 p->ss7call = isup_new_call(p->ss7->ss7);
2423 if (!p->ss7call) {
2424 ss7_rel(p->ss7);
2425 ast_mutex_unlock(&p->lock);
2426 ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
2427 return -1;
2430 called_nai_strip = 0;
2431 ss7_called_nai = p->ss7->called_nai;
2432 if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
2433 if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
2434 called_nai_strip = strlen(p->ss7->internationalprefix);
2435 ss7_called_nai = SS7_NAI_INTERNATIONAL;
2436 } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
2437 called_nai_strip = strlen(p->ss7->nationalprefix);
2438 ss7_called_nai = SS7_NAI_NATIONAL;
2439 } else {
2440 ss7_called_nai = SS7_NAI_SUBSCRIBER;
2443 isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
2445 calling_nai_strip = 0;
2446 ss7_calling_nai = p->ss7->calling_nai;
2447 if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
2448 if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
2449 calling_nai_strip = strlen(p->ss7->internationalprefix);
2450 ss7_calling_nai = SS7_NAI_INTERNATIONAL;
2451 } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
2452 calling_nai_strip = strlen(p->ss7->nationalprefix);
2453 ss7_calling_nai = SS7_NAI_NATIONAL;
2454 } else {
2455 ss7_calling_nai = SS7_NAI_SUBSCRIBER;
2458 isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
2459 p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
2460 p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
2462 isup_set_oli(p->ss7call, ast->cid.cid_ani2);
2463 isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
2465 ast_channel_lock(ast);
2466 /* Set the charge number if it is set */
2467 charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
2468 if (charge_str)
2469 isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
2471 gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
2472 if (gen_address)
2473 isup_set_gen_address(p->ss7call, gen_address, p->gen_add_nai,p->gen_add_pres_ind, p->gen_add_num_plan,p->gen_add_type); /* need to add some types here for NAI,PRES,TYPE */
2475 gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS");
2476 gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE");
2477 gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME");
2478 if (gen_digits)
2479 isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme));
2481 gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME");
2482 if (gen_name)
2483 isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED);
2485 jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP");
2486 if (jip_digits)
2487 isup_set_jip_digits(p->ss7call, jip_digits);
2489 lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT");
2490 if (lspi_ident)
2491 isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00);
2493 rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON");
2494 if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) {
2495 isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00); /* Setting for Nortel DMS-250/500 */
2498 call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT");
2499 call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC");
2500 if (call_ref_id && call_ref_pc) {
2501 isup_set_callref(p->ss7call, atoi(call_ref_id),
2502 call_ref_pc ? atoi(call_ref_pc) : 0);
2505 send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
2506 if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
2507 (isup_far(p->ss7->ss7, p->ss7call));
2509 ast_channel_unlock(ast);
2511 isup_iam(p->ss7->ss7, p->ss7call);
2512 ast_setstate(ast, AST_STATE_DIALING);
2513 ss7_rel(p->ss7);
2515 #endif /* HAVE_SS7 */
2516 #ifdef HAVE_PRI
2517 if (p->pri) {
2518 struct pri_sr *sr;
2519 #ifdef SUPPORT_USERUSER
2520 const char *useruser;
2521 #endif
2522 int pridialplan;
2523 int dp_strip;
2524 int prilocaldialplan;
2525 int ldp_strip;
2526 int exclusive;
2527 const char *rr_str;
2528 int redirect_reason;
2530 c = strchr(dest, '/');
2531 if (c)
2532 c++;
2533 else
2534 c = dest;
2536 l = NULL;
2537 n = NULL;
2539 if (!p->hidecallerid) {
2540 l = ast->cid.cid_num;
2541 if (!p->hidecalleridname) {
2542 n = ast->cid.cid_name;
2546 if (strlen(c) < p->stripmsd) {
2547 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
2548 ast_mutex_unlock(&p->lock);
2549 return -1;
2551 if (mysig != SIG_FXSKS) {
2552 p->dop.op = DAHDI_DIAL_OP_REPLACE;
2553 s = strchr(c + p->stripmsd, 'w');
2554 if (s) {
2555 if (strlen(s) > 1)
2556 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%s", s);
2557 else
2558 p->dop.dialstr[0] = '\0';
2559 *s = '\0';
2560 } else {
2561 p->dop.dialstr[0] = '\0';
2564 if (pri_grab(p, p->pri)) {
2565 ast_log(LOG_WARNING, "Failed to grab PRI!\n");
2566 ast_mutex_unlock(&p->lock);
2567 return -1;
2569 if (!(p->call = pri_new_call(p->pri->pri))) {
2570 ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
2571 pri_rel(p->pri);
2572 ast_mutex_unlock(&p->lock);
2573 return -1;
2575 if (!(sr = pri_sr_new())) {
2576 ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
2577 pri_rel(p->pri);
2578 ast_mutex_unlock(&p->lock);
2580 if (p->bearer || (mysig == SIG_FXSKS)) {
2581 if (p->bearer) {
2582 ast_debug(1, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
2583 p->bearer->call = p->call;
2584 } else
2585 ast_debug(1, "I'm being setup with no bearer right now...\n");
2587 pri_set_crv(p->pri->pri, p->call, p->channel, 0);
2589 p->digital = IS_DIGITAL(ast->transfercapability);
2590 /* Add support for exclusive override */
2591 if (p->priexclusive)
2592 exclusive = 1;
2593 else {
2594 /* otherwise, traditional behavior */
2595 if (p->pri->nodetype == PRI_NETWORK)
2596 exclusive = 0;
2597 else
2598 exclusive = 1;
2601 pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1);
2602 pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability,
2603 (p->digital ? -1 :
2604 ((p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)));
2605 if (p->pri->facilityenable)
2606 pri_facility_enable(p->pri->pri);
2608 ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
2609 dp_strip = 0;
2610 pridialplan = p->pri->dialplan - 1;
2611 if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
2612 if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
2613 if (pridialplan == -2) {
2614 dp_strip = strlen(p->pri->internationalprefix);
2616 pridialplan = PRI_INTERNATIONAL_ISDN;
2617 } else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
2618 if (pridialplan == -2) {
2619 dp_strip = strlen(p->pri->nationalprefix);
2621 pridialplan = PRI_NATIONAL_ISDN;
2622 } else {
2623 pridialplan = PRI_LOCAL_ISDN;
2626 while (c[p->stripmsd] > '9' && c[p->stripmsd] != '*' && c[p->stripmsd] != '#') {
2627 switch (c[p->stripmsd]) {
2628 case 'U':
2629 pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
2630 break;
2631 case 'I':
2632 pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
2633 break;
2634 case 'N':
2635 pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
2636 break;
2637 case 'L':
2638 pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
2639 break;
2640 case 'S':
2641 pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
2642 break;
2643 case 'V':
2644 pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
2645 break;
2646 case 'R':
2647 pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
2648 break;
2649 case 'u':
2650 pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
2651 break;
2652 case 'e':
2653 pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
2654 break;
2655 case 'x':
2656 pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
2657 break;
2658 case 'f':
2659 pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
2660 break;
2661 case 'n':
2662 pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
2663 break;
2664 case 'p':
2665 pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
2666 break;
2667 case 'r':
2668 pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
2669 break;
2670 default:
2671 if (isalpha(*c))
2672 ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c);
2674 c++;
2676 pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
2678 ldp_strip = 0;
2679 prilocaldialplan = p->pri->localdialplan - 1;
2680 if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
2681 if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
2682 if (prilocaldialplan == -2) {
2683 ldp_strip = strlen(p->pri->internationalprefix);
2685 prilocaldialplan = PRI_INTERNATIONAL_ISDN;
2686 } else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
2687 if (prilocaldialplan == -2) {
2688 ldp_strip = strlen(p->pri->nationalprefix);
2690 prilocaldialplan = PRI_NATIONAL_ISDN;
2691 } else {
2692 prilocaldialplan = PRI_LOCAL_ISDN;
2695 if (l != NULL) {
2696 while (*l > '9' && *l != '*' && *l != '#') {
2697 switch (*l) {
2698 case 'U':
2699 prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
2700 break;
2701 case 'I':
2702 prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
2703 break;
2704 case 'N':
2705 prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
2706 break;
2707 case 'L':
2708 prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
2709 break;
2710 case 'S':
2711 prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
2712 break;
2713 case 'V':
2714 prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
2715 break;
2716 case 'R':
2717 prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
2718 break;
2719 case 'u':
2720 prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
2721 break;
2722 case 'e':
2723 prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
2724 break;
2725 case 'x':
2726 prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
2727 break;
2728 case 'f':
2729 prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
2730 break;
2731 case 'n':
2732 prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
2733 break;
2734 case 'p':
2735 prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
2736 break;
2737 case 'r':
2738 prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
2739 break;
2740 default:
2741 if (isalpha(*l))
2742 ast_log(LOG_WARNING, "Unrecognized prilocaldialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c);
2744 l++;
2747 pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
2748 p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
2749 if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
2750 if (!strcasecmp(rr_str, "UNKNOWN"))
2751 redirect_reason = 0;
2752 else if (!strcasecmp(rr_str, "BUSY"))
2753 redirect_reason = 1;
2754 else if (!strcasecmp(rr_str, "NO_REPLY"))
2755 redirect_reason = 2;
2756 else if (!strcasecmp(rr_str, "UNCONDITIONAL"))
2757 redirect_reason = 15;
2758 else
2759 redirect_reason = PRI_REDIR_UNCONDITIONAL;
2760 } else
2761 redirect_reason = PRI_REDIR_UNCONDITIONAL;
2762 pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason);
2764 #ifdef SUPPORT_USERUSER
2765 /* User-user info */
2766 useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO");
2768 if (useruser)
2769 pri_sr_set_useruser(sr, useruser);
2770 #endif
2772 if (pri_setup(p->pri->pri, p->call, sr)) {
2773 ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n",
2774 c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan));
2775 pri_rel(p->pri);
2776 ast_mutex_unlock(&p->lock);
2777 pri_sr_free(sr);
2778 return -1;
2780 pri_sr_free(sr);
2781 ast_setstate(ast, AST_STATE_DIALING);
2782 pri_rel(p->pri);
2784 #endif
2785 ast_mutex_unlock(&p->lock);
2786 return 0;
2789 static void destroy_dahdi_pvt(struct dahdi_pvt **pvt)
2791 struct dahdi_pvt *p = *pvt;
2792 /* Remove channel from the list */
2793 if (p->prev)
2794 p->prev->next = p->next;
2795 if (p->next)
2796 p->next->prev = p->prev;
2797 if (p->use_smdi)
2798 ast_smdi_interface_unref(p->smdi_iface);
2799 if (p->mwi_event_sub)
2800 ast_event_unsubscribe(p->mwi_event_sub);
2801 if (p->vars)
2802 ast_variables_destroy(p->vars);
2803 ast_mutex_destroy(&p->lock);
2804 dahdi_close_sub(p, SUB_REAL);
2805 if (p->owner)
2806 p->owner->tech_pvt = NULL;
2807 free(p);
2808 *pvt = NULL;
2811 static int destroy_channel(struct dahdi_pvt *prev, struct dahdi_pvt *cur, int now)
2813 int owned = 0;
2814 int i = 0;
2816 if (!now) {
2817 if (cur->owner) {
2818 owned = 1;
2821 for (i = 0; i < 3; i++) {
2822 if (cur->subs[i].owner) {
2823 owned = 1;
2826 if (!owned) {
2827 if (prev) {
2828 prev->next = cur->next;
2829 if (prev->next)
2830 prev->next->prev = prev;
2831 else
2832 ifend = prev;
2833 } else {
2834 iflist = cur->next;
2835 if (iflist)
2836 iflist->prev = NULL;
2837 else
2838 ifend = NULL;
2840 destroy_dahdi_pvt(&cur);
2842 } else {
2843 if (prev) {
2844 prev->next = cur->next;
2845 if (prev->next)
2846 prev->next->prev = prev;
2847 else
2848 ifend = prev;
2849 } else {
2850 iflist = cur->next;
2851 if (iflist)
2852 iflist->prev = NULL;
2853 else
2854 ifend = NULL;
2856 destroy_dahdi_pvt(&cur);
2858 return 0;
2861 static void destroy_all_channels(void)
2863 int x;
2864 struct dahdi_pvt *p, *pl;
2866 while (num_restart_pending) {
2867 usleep(1);
2870 ast_mutex_lock(&iflock);
2871 /* Destroy all the interfaces and free their memory */
2872 p = iflist;
2873 while (p) {
2874 /* Free any callerid */
2875 if (p->cidspill)
2876 ast_free(p->cidspill);
2877 pl = p;
2878 p = p->next;
2879 x = pl->channel;
2880 /* Free associated memory */
2881 if (pl)
2882 destroy_dahdi_pvt(&pl);
2883 if (option_verbose > 2)
2884 ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x);
2886 iflist = NULL;
2887 ifcount = 0;
2888 ast_mutex_unlock(&iflock);
2891 #ifdef HAVE_PRI
2892 static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
2894 static char *dahdi_send_keypad_facility_synopsis = "Send digits out of band over a PRI";
2896 static char *dahdi_send_keypad_facility_descrip =
2897 " DAHDISendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n"
2898 " IE over the current channel.\n";
2900 static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data)
2902 /* Data will be our digit string */
2903 struct dahdi_pvt *p;
2904 char *digits = (char *) data;
2906 if (ast_strlen_zero(digits)) {
2907 ast_debug(1, "No digit string sent to application!\n");
2908 return -1;
2911 p = (struct dahdi_pvt *)chan->tech_pvt;
2913 if (!p) {
2914 ast_debug(1, "Unable to find technology private\n");
2915 return -1;
2918 ast_mutex_lock(&p->lock);
2920 if (!p->pri || !p->call) {
2921 ast_debug(1, "Unable to find pri or call on channel!\n");
2922 ast_mutex_unlock(&p->lock);
2923 return -1;
2926 if (!pri_grab(p, p->pri)) {
2927 pri_keypad_facility(p->pri->pri, p->call, digits);
2928 pri_rel(p->pri);
2929 } else {
2930 ast_debug(1, "Unable to grab pri to send keypad facility!\n");
2931 ast_mutex_unlock(&p->lock);
2932 return -1;
2935 ast_mutex_unlock(&p->lock);
2937 return 0;
2940 static int pri_is_up(struct dahdi_pri *pri)
2942 int x;
2943 for (x = 0; x < NUM_DCHANS; x++) {
2944 if (pri->dchanavail[x] == DCHAN_AVAILABLE)
2945 return 1;
2947 return 0;
2950 static int pri_assign_bearer(struct dahdi_pvt *crv, struct dahdi_pri *pri, struct dahdi_pvt *bearer)
2952 bearer->owner = &inuse;
2953 bearer->realcall = crv;
2954 crv->subs[SUB_REAL].dfd = bearer->subs[SUB_REAL].dfd;
2955 if (crv->subs[SUB_REAL].owner)
2956 ast_channel_set_fd(crv->subs[SUB_REAL].owner, 0, crv->subs[SUB_REAL].dfd);
2957 crv->bearer = bearer;
2958 crv->call = bearer->call;
2959 crv->pri = pri;
2960 return 0;
2963 static char *pri_order(int level)
2965 switch (level) {
2966 case 0:
2967 return "Primary";
2968 case 1:
2969 return "Secondary";
2970 case 2:
2971 return "Tertiary";
2972 case 3:
2973 return "Quaternary";
2974 default:
2975 return "<Unknown>";
2979 /* Returns fd of the active dchan */
2980 static int pri_active_dchan_fd(struct dahdi_pri *pri)
2982 int x = -1;
2984 for (x = 0; x < NUM_DCHANS; x++) {
2985 if ((pri->dchans[x] == pri->pri))
2986 break;
2989 return pri->fds[x];
2992 static int pri_find_dchan(struct dahdi_pri *pri)
2994 int oldslot = -1;
2995 struct pri *old;
2996 int newslot = -1;
2997 int x;
2998 old = pri->pri;
2999 for (x = 0; x < NUM_DCHANS; x++) {
3000 if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
3001 newslot = x;
3002 if (pri->dchans[x] == old) {
3003 oldslot = x;
3006 if (newslot < 0) {
3007 newslot = 0;
3008 ast_log(LOG_WARNING, "No D-channels available! Using Primary channel %d as D-channel anyway!\n",
3009 pri->dchannels[newslot]);
3011 if (old && (oldslot != newslot))
3012 ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
3013 pri->dchannels[oldslot], pri->dchannels[newslot]);
3014 pri->pri = pri->dchans[newslot];
3015 return 0;
3017 #endif
3019 static int dahdi_hangup(struct ast_channel *ast)
3021 int res;
3022 int idx,x, law;
3023 /*static int restore_gains(struct dahdi_pvt *p);*/
3024 struct dahdi_pvt *p = ast->tech_pvt;
3025 struct dahdi_pvt *tmp = NULL;
3026 struct dahdi_pvt *prev = NULL;
3027 struct dahdi_params par;
3029 ast_debug(1, "dahdi_hangup(%s)\n", ast->name);
3030 if (!ast->tech_pvt) {
3031 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
3032 return 0;
3035 ast_mutex_lock(&p->lock);
3037 idx = dahdi_get_index(ast, p, 1);
3039 if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
3040 x = 1;
3041 ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
3044 x = 0;
3045 dahdi_confmute(p, 0);
3046 p->muting = 0;
3047 restore_gains(p);
3048 if (p->origcid_num) {
3049 ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
3050 ast_free(p->origcid_num);
3051 p->origcid_num = NULL;
3053 if (p->origcid_name) {
3054 ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
3055 ast_free(p->origcid_name);
3056 p->origcid_name = NULL;
3058 if (p->dsp)
3059 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
3060 if (p->exten)
3061 p->exten[0] = '\0';
3063 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
3064 p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
3065 p->ignoredtmf = 0;
3067 if (idx > -1) {
3068 /* Real channel, do some fixup */
3069 p->subs[idx].owner = NULL;
3070 p->subs[idx].needanswer = 0;
3071 p->subs[idx].needflash = 0;
3072 p->subs[idx].needringing = 0;
3073 p->subs[idx].needbusy = 0;
3074 p->subs[idx].needcongestion = 0;
3075 p->subs[idx].linear = 0;
3076 p->subs[idx].needcallerid = 0;
3077 p->polarity = POLARITY_IDLE;
3078 dahdi_setlinear(p->subs[idx].dfd, 0);
3079 if (idx == SUB_REAL) {
3080 if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
3081 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
3082 if (p->subs[SUB_CALLWAIT].inthreeway) {
3083 /* We had flipped over to answer a callwait and now it's gone */
3084 ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
3085 /* Move to the call-wait, but un-own us until they flip back. */
3086 swap_subs(p, SUB_CALLWAIT, SUB_REAL);
3087 unalloc_sub(p, SUB_CALLWAIT);
3088 p->owner = NULL;
3089 } else {
3090 /* The three way hung up, but we still have a call wait */
3091 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
3092 swap_subs(p, SUB_THREEWAY, SUB_REAL);
3093 unalloc_sub(p, SUB_THREEWAY);
3094 if (p->subs[SUB_REAL].inthreeway) {
3095 /* This was part of a three way call. Immediately make way for
3096 another call */
3097 ast_debug(1, "Call was complete, setting owner to former third call\n");
3098 p->owner = p->subs[SUB_REAL].owner;
3099 } else {
3100 /* This call hasn't been completed yet... Set owner to NULL */
3101 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
3102 p->owner = NULL;
3104 p->subs[SUB_REAL].inthreeway = 0;
3106 } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
3107 /* Move to the call-wait and switch back to them. */
3108 swap_subs(p, SUB_CALLWAIT, SUB_REAL);
3109 unalloc_sub(p, SUB_CALLWAIT);
3110 p->owner = p->subs[SUB_REAL].owner;
3111 if (p->owner->_state != AST_STATE_UP)
3112 p->subs[SUB_REAL].needanswer = 1;
3113 if (ast_bridged_channel(p->subs[SUB_REAL].owner))
3114 ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
3115 } else if (p->subs[SUB_THREEWAY].dfd > -1) {
3116 swap_subs(p, SUB_THREEWAY, SUB_REAL);
3117 unalloc_sub(p, SUB_THREEWAY);
3118 if (p->subs[SUB_REAL].inthreeway) {
3119 /* This was part of a three way call. Immediately make way for
3120 another call */
3121 ast_debug(1, "Call was complete, setting owner to former third call\n");
3122 p->owner = p->subs[SUB_REAL].owner;
3123 } else {
3124 /* This call hasn't been completed yet... Set owner to NULL */
3125 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
3126 p->owner = NULL;
3128 p->subs[SUB_REAL].inthreeway = 0;
3130 } else if (idx == SUB_CALLWAIT) {
3131 /* Ditch the holding callwait call, and immediately make it availabe */
3132 if (p->subs[SUB_CALLWAIT].inthreeway) {
3133 /* This is actually part of a three way, placed on hold. Place the third part
3134 on music on hold now */
3135 if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
3136 ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
3137 S_OR(p->mohsuggest, NULL),
3138 !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
3140 p->subs[SUB_THREEWAY].inthreeway = 0;
3141 /* Make it the call wait now */
3142 swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
3143 unalloc_sub(p, SUB_THREEWAY);
3144 } else
3145 unalloc_sub(p, SUB_CALLWAIT);
3146 } else if (idx == SUB_THREEWAY) {
3147 if (p->subs[SUB_CALLWAIT].inthreeway) {
3148 /* The other party of the three way call is currently in a call-wait state.
3149 Start music on hold for them, and take the main guy out of the third call */
3150 if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
3151 ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
3152 S_OR(p->mohsuggest, NULL),
3153 !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
3155 p->subs[SUB_CALLWAIT].inthreeway = 0;
3157 p->subs[SUB_REAL].inthreeway = 0;
3158 /* If this was part of a three way call index, let us make
3159 another three way call */
3160 unalloc_sub(p, SUB_THREEWAY);
3161 } else {
3162 /* This wasn't any sort of call, but how are we an index? */
3163 ast_log(LOG_WARNING, "Index found but not any type of call?\n");
3167 if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
3168 p->owner = NULL;
3169 p->ringt = 0;
3170 p->distinctivering = 0;
3171 p->confirmanswer = 0;
3172 p->cidrings = 1;
3173 p->outgoing = 0;
3174 p->digital = 0;
3175 p->faxhandled = 0;
3176 p->pulsedial = 0;
3177 p->onhooktime = time(NULL);
3178 #if defined(HAVE_PRI) || defined(HAVE_SS7)
3179 p->proceeding = 0;
3180 p->progress = 0;
3181 p->alerting = 0;
3182 p->setup_ack = 0;
3183 p->rlt = 0;
3184 #endif
3185 if (p->dsp) {
3186 ast_dsp_free(p->dsp);
3187 p->dsp = NULL;
3190 law = DAHDI_LAW_DEFAULT;
3191 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
3192 if (res < 0)
3193 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
3194 /* Perform low level hangup if no owner left */
3195 #ifdef HAVE_SS7
3196 if (p->ss7) {
3197 if (p->ss7call) {
3198 if (!ss7_grab(p, p->ss7)) {
3199 if (!p->alreadyhungup) {
3200 const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
3201 int icause = ast->hangupcause ? ast->hangupcause : -1;
3203 if (cause) {
3204 if (atoi(cause))
3205 icause = atoi(cause);
3207 isup_rel(p->ss7->ss7, p->ss7call, icause);
3208 ss7_rel(p->ss7);
3209 p->alreadyhungup = 1;
3210 } else
3211 ast_log(LOG_WARNING, "Trying to hangup twice!\n");
3212 } else {
3213 ast_log(LOG_WARNING, "Unable to grab SS7 on CIC %d\n", p->cic);
3214 res = -1;
3218 #endif
3219 #ifdef HAVE_PRI
3220 if (p->pri) {
3221 #ifdef SUPPORT_USERUSER
3222 const char *useruser = pbx_builtin_getvar_helper(ast,"USERUSERINFO");
3223 #endif
3225 /* Make sure we have a call (or REALLY have a call in the case of a PRI) */
3226 if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
3227 if (!pri_grab(p, p->pri)) {
3228 if (p->alreadyhungup) {
3229 ast_debug(1, "Already hungup... Calling hangup once, and clearing call\n");
3231 #ifdef SUPPORT_USERUSER
3232 pri_call_set_useruser(p->call, useruser);
3233 #endif
3235 pri_hangup(p->pri->pri, p->call, -1);
3236 p->call = NULL;
3237 if (p->bearer)
3238 p->bearer->call = NULL;
3239 } else {
3240 const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
3241 int icause = ast->hangupcause ? ast->hangupcause : -1;
3242 ast_debug(1, "Not yet hungup... Calling hangup once with icause, and clearing call\n");
3244 #ifdef SUPPORT_USERUSER
3245 pri_call_set_useruser(p->call, useruser);
3246 #endif
3248 p->alreadyhungup = 1;
3249 if (p->bearer)
3250 p->bearer->alreadyhungup = 1;
3251 if (cause) {
3252 if (atoi(cause))
3253 icause = atoi(cause);
3255 pri_hangup(p->pri->pri, p->call, icause);
3257 if (res < 0)
3258 ast_log(LOG_WARNING, "pri_disconnect failed\n");
3259 pri_rel(p->pri);
3260 } else {
3261 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
3262 res = -1;
3264 } else {
3265 if (p->bearer)
3266 ast_debug(1, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
3267 p->call = NULL;
3268 res = 0;
3271 #endif
3272 if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7) && (p->sig != SIG_BRI) && (p->sig != SIG_BRI_PTMP)))
3273 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
3274 if (res < 0) {
3275 ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
3277 switch (p->sig) {
3278 case SIG_FXOGS:
3279 case SIG_FXOLS:
3280 case SIG_FXOKS:
3281 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
3282 if (!res) {
3283 #if 0
3284 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
3285 #endif
3286 /* If they're off hook, try playing congestion */
3287 if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
3288 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
3289 else
3290 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
3292 break;
3293 case SIG_FXSGS:
3294 case SIG_FXSLS:
3295 case SIG_FXSKS:
3296 /* Make sure we're not made available for at least two seconds assuming
3297 we were actually used for an inbound or outbound call. */
3298 if (ast->_state != AST_STATE_RESERVED) {
3299 time(&p->guardtime);
3300 p->guardtime += 2;
3302 break;
3303 default:
3304 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
3306 if (p->cidspill)
3307 ast_free(p->cidspill);
3308 if (p->sig)
3309 dahdi_disable_ec(p);
3310 x = 0;
3311 ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
3312 ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
3313 p->didtdd = 0;
3314 p->cidspill = NULL;
3315 p->callwaitcas = 0;
3316 p->callwaiting = p->permcallwaiting;
3317 p->hidecallerid = p->permhidecallerid;
3318 p->dialing = 0;
3319 p->rdnis[0] = '\0';
3320 update_conf(p);
3321 reset_conf(p);
3322 /* Restore data mode */
3323 if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
3324 x = 0;
3325 ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
3327 #ifdef HAVE_PRI
3328 if (p->bearer) {
3329 ast_debug(1, "Freeing up bearer channel %d\n", p->bearer->channel);
3330 /* Free up the bearer channel as well, and
3331 don't use its file descriptor anymore */
3332 update_conf(p->bearer);
3333 reset_conf(p->bearer);
3334 p->bearer->owner = NULL;
3335 p->bearer->realcall = NULL;
3336 p->bearer = NULL;
3337 p->subs[SUB_REAL].dfd = -1;
3338 p->pri = NULL;
3340 #endif
3341 if (num_restart_pending == 0)
3342 restart_monitor();
3345 p->callwaitingrepeat = 0;
3346 p->cidcwexpire = 0;
3347 p->oprmode = 0;
3348 ast->tech_pvt = NULL;
3349 ast_mutex_unlock(&p->lock);
3350 ast_module_unref(ast_module_info->self);
3351 ast_verb(3, "Hungup '%s'\n", ast->name);
3353 ast_mutex_lock(&iflock);
3355 if (p->restartpending) {
3356 num_restart_pending--;
3359 tmp = iflist;
3360 prev = NULL;
3361 if (p->destroy) {
3362 while (tmp) {
3363 if (tmp == p) {
3364 destroy_channel(prev, tmp, 0);
3365 break;
3366 } else {
3367 prev = tmp;
3368 tmp = tmp->next;
3372 ast_mutex_unlock(&iflock);
3373 return 0;
3376 static int dahdi_answer(struct ast_channel *ast)
3378 struct dahdi_pvt *p = ast->tech_pvt;
3379 int res = 0;
3380 int idx;
3381 int oldstate = ast->_state;
3382 ast_setstate(ast, AST_STATE_UP);
3383 ast_mutex_lock(&p->lock);
3384 idx = dahdi_get_index(ast, p, 0);
3385 if (idx < 0)
3386 idx = SUB_REAL;
3387 /* nothing to do if a radio channel */
3388 if ((p->radio || (p->oprmode < 0))) {
3389 ast_mutex_unlock(&p->lock);
3390 return 0;
3392 switch (p->sig) {
3393 case SIG_FXSLS:
3394 case SIG_FXSGS:
3395 case SIG_FXSKS:
3396 p->ringt = 0;
3397 /* Fall through */
3398 case SIG_EM:
3399 case SIG_EM_E1:
3400 case SIG_EMWINK:
3401 case SIG_FEATD:
3402 case SIG_FEATDMF:
3403 case SIG_FEATDMF_TA:
3404 case SIG_E911:
3405 case SIG_FGC_CAMA:
3406 case SIG_FGC_CAMAMF:
3407 case SIG_FEATB:
3408 case SIG_SF:
3409 case SIG_SFWINK:
3410 case SIG_SF_FEATD:
3411 case SIG_SF_FEATDMF:
3412 case SIG_SF_FEATB:
3413 case SIG_FXOLS:
3414 case SIG_FXOGS:
3415 case SIG_FXOKS:
3416 /* Pick up the line */
3417 ast_debug(1, "Took %s off hook\n", ast->name);
3418 if (p->hanguponpolarityswitch) {
3419 p->polaritydelaytv = ast_tvnow();
3421 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
3422 tone_zone_play_tone(p->subs[idx].dfd, -1);
3423 p->dialing = 0;
3424 if ((idx == SUB_REAL) && p->subs[SUB_THREEWAY].inthreeway) {
3425 if (oldstate == AST_STATE_RINGING) {
3426 ast_debug(1, "Finally swapping real and threeway\n");
3427 tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, -1);
3428 swap_subs(p, SUB_THREEWAY, SUB_REAL);
3429 p->owner = p->subs[SUB_REAL].owner;
3432 if (p->sig & __DAHDI_SIG_FXS) {
3433 dahdi_enable_ec(p);
3434 dahdi_train_ec(p);
3436 break;
3437 #ifdef HAVE_PRI
3438 case SIG_BRI:
3439 case SIG_BRI_PTMP:
3440 case SIG_PRI:
3441 /* Send a pri acknowledge */
3442 if (!pri_grab(p, p->pri)) {
3443 p->proceeding = 1;
3444 res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
3445 pri_rel(p->pri);
3446 } else {
3447 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
3448 res = -1;
3450 break;
3451 #endif
3452 #ifdef HAVE_SS7
3453 case SIG_SS7:
3454 if (!ss7_grab(p, p->ss7)) {
3455 p->proceeding = 1;
3456 res = isup_anm(p->ss7->ss7, p->ss7call);
3457 ss7_rel(p->ss7);
3458 } else {
3459 ast_log(LOG_WARNING, "Unable to grab SS7 on span %d\n", p->span);
3460 res = -1;
3462 break;
3463 #endif
3464 case 0:
3465 ast_mutex_unlock(&p->lock);
3466 return 0;
3467 default:
3468 ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
3469 res = -1;
3471 ast_mutex_unlock(&p->lock);
3472 return res;
3475 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
3477 char *cp;
3478 signed char *scp;
3479 int x;
3480 int idx;
3481 struct dahdi_pvt *p = chan->tech_pvt, *pp;
3482 struct oprmode *oprmode;
3485 /* all supported options require data */
3486 if (!data || (datalen < 1)) {
3487 errno = EINVAL;
3488 return -1;
3491 switch (option) {
3492 case AST_OPTION_TXGAIN:
3493 scp = (signed char *) data;
3494 idx = dahdi_get_index(chan, p, 0);
3495 if (idx < 0) {
3496 ast_log(LOG_WARNING, "No index in TXGAIN?\n");
3497 return -1;
3499 ast_debug(1, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
3500 return set_actual_txgain(p->subs[idx].dfd, 0, p->txgain + (float) *scp, p->law);
3501 case AST_OPTION_RXGAIN:
3502 scp = (signed char *) data;
3503 idx = dahdi_get_index(chan, p, 0);
3504 if (idx < 0) {
3505 ast_log(LOG_WARNING, "No index in RXGAIN?\n");
3506 return -1;
3508 ast_debug(1, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
3509 return set_actual_rxgain(p->subs[idx].dfd, 0, p->rxgain + (float) *scp, p->law);
3510 case AST_OPTION_TONE_VERIFY:
3511 if (!p->dsp)
3512 break;
3513 cp = (char *) data;
3514 switch (*cp) {
3515 case 1:
3516 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
3517 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */
3518 break;
3519 case 2:
3520 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
3521 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */
3522 break;
3523 default:
3524 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
3525 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */
3526 break;
3528 break;
3529 case AST_OPTION_TDD:
3530 /* turn on or off TDD */
3531 cp = (char *) data;
3532 p->mate = 0;
3533 if (!*cp) { /* turn it off */
3534 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
3535 if (p->tdd)
3536 tdd_free(p->tdd);
3537 p->tdd = 0;
3538 break;
3540 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
3541 (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
3542 dahdi_disable_ec(p);
3543 /* otherwise, turn it on */
3544 if (!p->didtdd) { /* if havent done it yet */
3545 unsigned char mybuf[41000], *buf;
3546 int size, res, fd, len;
3547 struct pollfd fds[1];
3549 buf = mybuf;
3550 memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
3551 ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */
3552 len = 40000;
3553 idx = dahdi_get_index(chan, p, 0);
3554 if (idx < 0) {
3555 ast_log(LOG_WARNING, "No index in TDD?\n");
3556 return -1;
3558 fd = p->subs[idx].dfd;
3559 while (len) {
3560 if (ast_check_hangup(chan))
3561 return -1;
3562 size = len;
3563 if (size > READ_SIZE)
3564 size = READ_SIZE;
3565 fds[0].fd = fd;
3566 fds[0].events = POLLPRI | POLLOUT;
3567 fds[0].revents = 0;
3568 res = poll(fds, 1, -1);
3569 if (!res) {
3570 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
3571 continue;
3573 /* if got exception */
3574 if (fds[0].revents & POLLPRI)
3575 return -1;
3576 if (!(fds[0].revents & POLLOUT)) {
3577 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
3578 continue;
3580 res = write(fd, buf, size);
3581 if (res != size) {
3582 if (res == -1) return -1;
3583 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
3584 break;
3586 len -= size;
3587 buf += size;
3589 p->didtdd = 1; /* set to have done it now */
3591 if (*cp == 2) { /* Mate mode */
3592 if (p->tdd)
3593 tdd_free(p->tdd);
3594 p->tdd = 0;
3595 p->mate = 1;
3596 break;
3598 if (!p->tdd) { /* if we dont have one yet */
3599 p->tdd = tdd_new(); /* allocate one */
3601 break;
3602 case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */
3603 if (!p->dsp)
3604 break;
3605 cp = (char *) data;
3606 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
3607 *cp ? "ON" : "OFF", (int) *cp, chan->name);
3608 ast_dsp_set_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax);
3609 break;
3610 case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */
3611 cp = (char *) data;
3612 if (!*cp) {
3613 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
3614 x = 0;
3615 dahdi_disable_ec(p);
3616 } else {
3617 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
3618 x = 1;
3620 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
3621 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
3622 break;
3623 case AST_OPTION_OPRMODE: /* Operator services mode */
3624 oprmode = (struct oprmode *) data;
3625 pp = oprmode->peer->tech_pvt;
3626 p->oprmode = pp->oprmode = 0;
3627 /* setup peers */
3628 p->oprpeer = pp;
3629 pp->oprpeer = p;
3630 /* setup modes, if any */
3631 if (oprmode->mode)
3633 pp->oprmode = oprmode->mode;
3634 p->oprmode = -oprmode->mode;
3636 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
3637 oprmode->mode, chan->name,oprmode->peer->name);
3638 break;
3639 case AST_OPTION_ECHOCAN:
3640 cp = (char *) data;
3641 if (*cp) {
3642 ast_debug(1, "Enabling echo cancelation on %s\n", chan->name);
3643 dahdi_enable_ec(p);
3644 } else {
3645 ast_debug(1, "Disabling echo cancelation on %s\n", chan->name);
3646 dahdi_disable_ec(p);
3648 break;
3650 errno = 0;
3652 return 0;
3655 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
3657 struct dahdi_pvt *p = chan->tech_pvt;
3659 if (!strcasecmp(data, "rxgain")) {
3660 ast_mutex_lock(&p->lock);
3661 snprintf(buf, len, "%f", p->rxgain);
3662 ast_mutex_unlock(&p->lock);
3663 } else if (!strcasecmp(data, "txgain")) {
3664 ast_mutex_lock(&p->lock);
3665 snprintf(buf, len, "%f", p->txgain);
3666 ast_mutex_unlock(&p->lock);
3667 } else {
3668 ast_copy_string(buf, "", len);
3670 return 0;
3674 static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
3676 /* Unlink a specific slave or all slaves/masters from a given master */
3677 int x;
3678 int hasslaves;
3679 if (!master)
3680 return;
3681 if (needlock) {
3682 ast_mutex_lock(&master->lock);
3683 if (slave) {
3684 while (ast_mutex_trylock(&slave->lock)) {
3685 DEADLOCK_AVOIDANCE(&master->lock);
3689 hasslaves = 0;
3690 for (x = 0; x < MAX_SLAVES; x++) {
3691 if (master->slaves[x]) {
3692 if (!slave || (master->slaves[x] == slave)) {
3693 /* Take slave out of the conference */
3694 ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
3695 conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
3696 conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
3697 master->slaves[x]->master = NULL;
3698 master->slaves[x] = NULL;
3699 } else
3700 hasslaves = 1;
3702 if (!hasslaves)
3703 master->inconference = 0;
3705 if (!slave) {
3706 if (master->master) {
3707 /* Take master out of the conference */
3708 conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
3709 conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
3710 hasslaves = 0;
3711 for (x = 0; x < MAX_SLAVES; x++) {
3712 if (master->master->slaves[x] == master)
3713 master->master->slaves[x] = NULL;
3714 else if (master->master->slaves[x])
3715 hasslaves = 1;
3717 if (!hasslaves)
3718 master->master->inconference = 0;
3720 master->master = NULL;
3722 update_conf(master);
3723 if (needlock) {
3724 if (slave)
3725 ast_mutex_unlock(&slave->lock);
3726 ast_mutex_unlock(&master->lock);
3730 static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
3731 int x;
3732 if (!slave || !master) {
3733 ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
3734 return;
3736 for (x = 0; x < MAX_SLAVES; x++) {
3737 if (!master->slaves[x]) {
3738 master->slaves[x] = slave;
3739 break;
3742 if (x >= MAX_SLAVES) {
3743 ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
3744 master->slaves[MAX_SLAVES - 1] = slave;
3746 if (slave->master)
3747 ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
3748 slave->master = master;
3750 ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
3753 static void disable_dtmf_detect(struct dahdi_pvt *p)
3755 int val;
3757 p->ignoredtmf = 1;
3759 val = 0;
3760 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
3762 if (!p->hardwaredtmf && p->dsp) {
3763 p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
3764 ast_dsp_set_features(p->dsp, p->dsp_features);
3768 static void enable_dtmf_detect(struct dahdi_pvt *p)
3770 int val;
3772 if (p->channel == CHAN_PSEUDO)
3773 return;
3775 p->ignoredtmf = 0;
3777 val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
3778 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
3780 if (!p->hardwaredtmf && p->dsp) {
3781 p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3782 ast_dsp_set_features(p->dsp, p->dsp_features);
3786 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)
3788 struct ast_channel *who;
3789 struct dahdi_pvt *p0, *p1, *op0, *op1;
3790 struct dahdi_pvt *master = NULL, *slave = NULL;
3791 struct ast_frame *f;
3792 int inconf = 0;
3793 int nothingok = 1;
3794 int ofd0, ofd1;
3795 int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
3796 int os0 = -1, os1 = -1;
3797 int priority = 0;
3798 struct ast_channel *oc0, *oc1;
3799 enum ast_bridge_result res;
3801 #ifdef PRI_2BCT
3802 int triedtopribridge = 0;
3803 q931_call *q931c0 = NULL, *q931c1 = NULL;
3804 #endif
3806 /* For now, don't attempt to native bridge if either channel needs DTMF detection.
3807 There is code below to handle it properly until DTMF is actually seen,
3808 but due to currently unresolved issues it's ignored...
3811 if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
3812 return AST_BRIDGE_FAILED_NOWARN;
3814 ast_channel_lock(c0);
3815 while (ast_channel_trylock(c1)) {
3816 CHANNEL_DEADLOCK_AVOIDANCE(c0);
3819 p0 = c0->tech_pvt;
3820 p1 = c1->tech_pvt;
3821 /* cant do pseudo-channels here */
3822 if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
3823 ast_channel_unlock(c0);
3824 ast_channel_unlock(c1);
3825 return AST_BRIDGE_FAILED_NOWARN;
3828 oi0 = dahdi_get_index(c0, p0, 0);
3829 oi1 = dahdi_get_index(c1, p1, 0);
3830 if ((oi0 < 0) || (oi1 < 0)) {
3831 ast_channel_unlock(c0);
3832 ast_channel_unlock(c1);
3833 return AST_BRIDGE_FAILED;
3836 op0 = p0 = c0->tech_pvt;
3837 op1 = p1 = c1->tech_pvt;
3838 ofd0 = c0->fds[0];
3839 ofd1 = c1->fds[0];
3840 oc0 = p0->owner;
3841 oc1 = p1->owner;
3843 if (ast_mutex_trylock(&p0->lock)) {
3844 /* Don't block, due to potential for deadlock */
3845 ast_channel_unlock(c0);
3846 ast_channel_unlock(c1);
3847 ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
3848 return AST_BRIDGE_RETRY;
3850 if (ast_mutex_trylock(&p1->lock)) {
3851 /* Don't block, due to potential for deadlock */
3852 ast_mutex_unlock(&p0->lock);
3853 ast_channel_unlock(c0);
3854 ast_channel_unlock(c1);
3855 ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
3856 return AST_BRIDGE_RETRY;
3859 if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
3860 if (p0->owner && p1->owner) {
3861 /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
3862 if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
3863 master = p0;
3864 slave = p1;
3865 inconf = 1;
3866 } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
3867 master = p1;
3868 slave = p0;
3869 inconf = 1;
3870 } else {
3871 ast_log(LOG_WARNING, "Huh? Both calls are callwaits or 3-ways? That's clever...?\n");
3872 ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
3873 p0->channel,
3874 oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
3875 p0->subs[SUB_REAL].inthreeway, p0->channel,
3876 oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
3877 p1->subs[SUB_REAL].inthreeway);
3879 nothingok = 0;
3881 } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
3882 if (p1->subs[SUB_THREEWAY].inthreeway) {
3883 master = p1;
3884 slave = p0;
3885 nothingok = 0;
3887 } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
3888 if (p0->subs[SUB_THREEWAY].inthreeway) {
3889 master = p0;
3890 slave = p1;
3891 nothingok = 0;
3893 } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
3894 /* We have a real and a call wait. If we're in a three way call, put us in it, otherwise,
3895 don't put us in anything */
3896 if (p1->subs[SUB_CALLWAIT].inthreeway) {
3897 master = p1;
3898 slave = p0;
3899 nothingok = 0;
3901 } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
3902 /* Same as previous */
3903 if (p0->subs[SUB_CALLWAIT].inthreeway) {
3904 master = p0;
3905 slave = p1;
3906 nothingok = 0;
3909 ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
3910 master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
3911 if (master && slave) {
3912 /* Stop any tones, or play ringtone as appropriate. If they're bridged
3913 in an active threeway call with a channel that is ringing, we should
3914 indicate ringing. */
3915 if ((oi1 == SUB_THREEWAY) &&
3916 p1->subs[SUB_THREEWAY].inthreeway &&
3917 p1->subs[SUB_REAL].owner &&
3918 p1->subs[SUB_REAL].inthreeway &&
3919 (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
3920 ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
3921 tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
3922 os1 = p1->subs[SUB_REAL].owner->_state;
3923 } else {
3924 ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
3925 tone_zone_play_tone(p0->subs[oi0].dfd, -1);
3927 if ((oi0 == SUB_THREEWAY) &&
3928 p0->subs[SUB_THREEWAY].inthreeway &&
3929 p0->subs[SUB_REAL].owner &&
3930 p0->subs[SUB_REAL].inthreeway &&
3931 (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
3932 ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
3933 tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
3934 os0 = p0->subs[SUB_REAL].owner->_state;
3935 } else {
3936 ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
3937 tone_zone_play_tone(p1->subs[oi0].dfd, -1);
3939 if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
3940 if (!p0->echocanbridged || !p1->echocanbridged) {
3941 /* Disable echo cancellation if appropriate */
3942 dahdi_disable_ec(p0);
3943 dahdi_disable_ec(p1);
3946 dahdi_link(slave, master);
3947 master->inconference = inconf;
3948 } else if (!nothingok)
3949 ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
3951 update_conf(p0);
3952 update_conf(p1);
3953 t0 = p0->subs[SUB_REAL].inthreeway;
3954 t1 = p1->subs[SUB_REAL].inthreeway;
3956 ast_mutex_unlock(&p0->lock);
3957 ast_mutex_unlock(&p1->lock);
3959 ast_channel_unlock(c0);
3960 ast_channel_unlock(c1);
3962 /* Native bridge failed */
3963 if ((!master || !slave) && !nothingok) {
3964 dahdi_enable_ec(p0);
3965 dahdi_enable_ec(p1);
3966 return AST_BRIDGE_FAILED;
3969 ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
3971 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
3972 disable_dtmf_detect(op0);
3974 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
3975 disable_dtmf_detect(op1);
3977 for (;;) {
3978 struct ast_channel *c0_priority[2] = {c0, c1};
3979 struct ast_channel *c1_priority[2] = {c1, c0};
3981 /* Here's our main loop... Start by locking things, looking for private parts,
3982 and then balking if anything is wrong */
3984 ast_channel_lock(c0);
3985 while (ast_channel_trylock(c1)) {
3986 CHANNEL_DEADLOCK_AVOIDANCE(c0);
3989 p0 = c0->tech_pvt;
3990 p1 = c1->tech_pvt;
3992 if (op0 == p0)
3993 i0 = dahdi_get_index(c0, p0, 1);
3994 if (op1 == p1)
3995 i1 = dahdi_get_index(c1, p1, 1);
3997 ast_channel_unlock(c0);
3998 ast_channel_unlock(c1);
4000 if (!timeoutms ||
4001 (op0 != p0) ||
4002 (op1 != p1) ||
4003 (ofd0 != c0->fds[0]) ||
4004 (ofd1 != c1->fds[0]) ||
4005 (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) ||
4006 (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) ||
4007 (oc0 != p0->owner) ||
4008 (oc1 != p1->owner) ||
4009 (t0 != p0->subs[SUB_REAL].inthreeway) ||
4010 (t1 != p1->subs[SUB_REAL].inthreeway) ||
4011 (oi0 != i0) ||
4012 (oi1 != i1)) {
4013 ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
4014 op0->channel, oi0, op1->channel, oi1);
4015 res = AST_BRIDGE_RETRY;
4016 goto return_from_bridge;
4019 #ifdef PRI_2BCT
4020 q931c0 = p0->call;
4021 q931c1 = p1->call;
4022 if (p0->transfer && p1->transfer
4023 && q931c0 && q931c1
4024 && !triedtopribridge) {
4025 pri_channel_bridge(q931c0, q931c1);
4026 triedtopribridge = 1;
4028 #endif
4030 who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
4031 if (!who) {
4032 ast_debug(1, "Ooh, empty read...\n");
4033 continue;
4035 f = ast_read(who);
4036 if (!f || (f->frametype == AST_FRAME_CONTROL)) {
4037 *fo = f;
4038 *rc = who;
4039 res = AST_BRIDGE_COMPLETE;
4040 goto return_from_bridge;
4042 if (f->frametype == AST_FRAME_DTMF) {
4043 if ((who == c0) && p0->pulsedial) {
4044 ast_write(c1, f);
4045 } else if ((who == c1) && p1->pulsedial) {
4046 ast_write(c0, f);
4047 } else {
4048 *fo = f;
4049 *rc = who;
4050 res = AST_BRIDGE_COMPLETE;
4051 goto return_from_bridge;
4054 ast_frfree(f);
4056 /* Swap who gets priority */
4057 priority = !priority;
4060 return_from_bridge:
4061 if (op0 == p0)
4062 dahdi_enable_ec(p0);
4064 if (op1 == p1)
4065 dahdi_enable_ec(p1);
4067 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
4068 enable_dtmf_detect(op0);
4070 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
4071 enable_dtmf_detect(op1);
4073 dahdi_unlink(slave, master, 1);
4075 return res;
4078 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
4080 struct dahdi_pvt *p = newchan->tech_pvt;
4081 int x;
4082 ast_mutex_lock(&p->lock);
4083 ast_debug(1, "New owner for channel %d is %s\n", p->channel, newchan->name);
4084 if (p->owner == oldchan) {
4085 p->owner = newchan;
4087 for (x = 0; x < 3; x++)
4088 if (p->subs[x].owner == oldchan) {
4089 if (!x)
4090 dahdi_unlink(NULL, p, 0);
4091 p->subs[x].owner = newchan;
4093 if (newchan->_state == AST_STATE_RINGING)
4094 dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
4095 update_conf(p);
4096 ast_mutex_unlock(&p->lock);
4097 return 0;
4100 static int dahdi_ring_phone(struct dahdi_pvt *p)
4102 int x;
4103 int res;
4104 /* Make sure our transmit state is on hook */
4105 x = 0;
4106 x = DAHDI_ONHOOK;
4107 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
4108 do {
4109 x = DAHDI_RING;
4110 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
4111 if (res) {
4112 switch (errno) {
4113 case EBUSY:
4114 case EINTR:
4115 /* Wait just in case */
4116 usleep(10000);
4117 continue;
4118 case EINPROGRESS:
4119 res = 0;
4120 break;
4121 default:
4122 ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
4123 res = 0;
4126 } while (res);
4127 return res;
4130 static void *ss_thread(void *data);
4132 static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
4134 static int attempt_transfer(struct dahdi_pvt *p)
4136 /* In order to transfer, we need at least one of the channels to
4137 actually be in a call bridge. We can't conference two applications
4138 together (but then, why would we want to?) */
4139 if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
4140 /* The three-way person we're about to transfer to could still be in MOH, so
4141 stop if now if appropriate */
4142 if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
4143 ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
4144 if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
4145 ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
4147 if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
4148 tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
4150 if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
4151 ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
4152 ast_bridged_channel(p->subs[SUB_REAL].owner)->name, p->subs[SUB_THREEWAY].owner->name);
4153 return -1;
4155 /* Orphan the channel after releasing the lock */
4156 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4157 unalloc_sub(p, SUB_THREEWAY);
4158 } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
4159 ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
4160 if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
4161 ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
4163 if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
4164 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
4166 if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
4167 ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
4168 ast_bridged_channel(p->subs[SUB_THREEWAY].owner)->name, p->subs[SUB_REAL].owner->name);
4169 return -1;
4171 /* Three-way is now the REAL */
4172 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4173 ast_channel_unlock(p->subs[SUB_REAL].owner);
4174 unalloc_sub(p, SUB_THREEWAY);
4175 /* Tell the caller not to hangup */
4176 return 1;
4177 } else {
4178 ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
4179 p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
4180 p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
4181 return -1;
4183 return 0;
4186 static int check_for_conference(struct dahdi_pvt *p)
4188 struct dahdi_confinfo ci;
4189 /* Fine if we already have a master, etc */
4190 if (p->master || (p->confno > -1))
4191 return 0;
4192 memset(&ci, 0, sizeof(ci));
4193 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
4194 ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
4195 return 0;
4197 /* If we have no master and don't have a confno, then
4198 if we're in a conference, it's probably a MeetMe room or
4199 some such, so don't let us 3-way out! */
4200 if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
4201 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
4202 return 1;
4204 return 0;
4207 /*! Checks channel for alarms
4208 * \param p a channel to check for alarms.
4209 * \returns the alarms on the span to which the channel belongs, or alarms on
4210 * the channel if no span alarms.
4212 static int get_alarms(struct dahdi_pvt *p)
4214 int res;
4215 struct dahdi_spaninfo zi;
4216 struct dahdi_params params;
4218 memset(&zi, 0, sizeof(zi));
4219 zi.spanno = p->span;
4221 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
4222 if (zi.alarms != DAHDI_ALARM_NONE)
4223 return zi.alarms;
4224 } else {
4225 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
4226 return 0;
4229 /* No alarms on the span. Check for channel alarms. */
4230 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
4231 return params.chan_alarms;
4233 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
4235 return DAHDI_ALARM_NONE;
4238 static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_frame **dest)
4240 struct dahdi_pvt *p = ast->tech_pvt;
4241 struct ast_frame *f = *dest;
4243 ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
4245 if (p->confirmanswer) {
4246 ast_debug(1, "Confirm answer on %s!\n", ast->name);
4247 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
4248 of a DTMF digit */
4249 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4250 p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
4251 *dest = &p->subs[idx].f;
4252 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
4253 p->confirmanswer = 0;
4254 } else if (p->callwaitcas) {
4255 if ((f->subclass == 'A') || (f->subclass == 'D')) {
4256 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
4257 if (p->cidspill)
4258 ast_free(p->cidspill);
4259 send_cwcidspill(p);
4261 p->callwaitcas = 0;
4262 p->subs[idx].f.frametype = AST_FRAME_NULL;
4263 p->subs[idx].f.subclass = 0;
4264 *dest = &p->subs[idx].f;
4265 } else if (f->subclass == 'f') {
4266 /* Fax tone -- Handle and return NULL */
4267 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
4268 p->faxhandled++;
4269 if (strcmp(ast->exten, "fax")) {
4270 const char *target_context = S_OR(ast->macrocontext, ast->context);
4272 if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
4273 ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
4274 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
4275 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
4276 if (ast_async_goto(ast, target_context, "fax", 1))
4277 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
4278 } else
4279 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
4280 } else
4281 ast_debug(1, "Already in a fax extension, not redirecting\n");
4282 } else
4283 ast_debug(1, "Fax already handled\n");
4284 dahdi_confmute(p, 0);
4285 p->subs[idx].f.frametype = AST_FRAME_NULL;
4286 p->subs[idx].f.subclass = 0;
4287 *dest = &p->subs[idx].f;
4291 static void handle_alarms(struct dahdi_pvt *p, int alms)
4293 const char *alarm_str = alarm2str(alms);
4295 ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
4296 manager_event(EVENT_FLAG_SYSTEM, "Alarm",
4297 "Alarm: %s\r\n"
4298 "Channel: %d\r\n",
4299 alarm_str, p->channel);
4302 static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
4304 int res, x;
4305 int idx, mysig;
4306 char *c;
4307 struct dahdi_pvt *p = ast->tech_pvt;
4308 pthread_t threadid;
4309 struct ast_channel *chan;
4310 struct ast_frame *f;
4312 idx = dahdi_get_index(ast, p, 0);
4313 mysig = p->sig;
4314 if (p->outsigmod > -1)
4315 mysig = p->outsigmod;
4316 p->subs[idx].f.frametype = AST_FRAME_NULL;
4317 p->subs[idx].f.subclass = 0;
4318 p->subs[idx].f.datalen = 0;
4319 p->subs[idx].f.samples = 0;
4320 p->subs[idx].f.mallocd = 0;
4321 p->subs[idx].f.offset = 0;
4322 p->subs[idx].f.src = "dahdi_handle_event";
4323 p->subs[idx].f.data.ptr = NULL;
4324 f = &p->subs[idx].f;
4326 if (idx < 0)
4327 return &p->subs[idx].f;
4328 if (p->fake_event) {
4329 res = p->fake_event;
4330 p->fake_event = 0;
4331 } else
4332 res = dahdi_get_event(p->subs[idx].dfd);
4334 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
4336 if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
4337 p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
4338 ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
4339 #ifdef HAVE_PRI
4340 if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
4341 /* absorb event */
4342 } else {
4343 #endif
4344 p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
4345 p->subs[idx].f.subclass = res & 0xff;
4346 #ifdef HAVE_PRI
4348 #endif
4349 dahdi_handle_dtmfup(ast, idx, &f);
4350 return f;
4353 if (res & DAHDI_EVENT_DTMFDOWN) {
4354 ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
4355 /* Mute conference */
4356 dahdi_confmute(p, 1);
4357 p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
4358 p->subs[idx].f.subclass = res & 0xff;
4359 return &p->subs[idx].f;
4362 switch (res) {
4363 case DAHDI_EVENT_EC_DISABLED:
4364 ast_verb(3, "Channel %d echo canceler disabled due to CED detection\n", p->channel);
4365 p->echocanon = 0;
4366 break;
4367 case DAHDI_EVENT_BITSCHANGED:
4368 ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
4369 case DAHDI_EVENT_PULSE_START:
4370 /* Stop tone if there's a pulse start and the PBX isn't started */
4371 if (!ast->pbx)
4372 tone_zone_play_tone(p->subs[idx].dfd, -1);
4373 break;
4374 case DAHDI_EVENT_DIALCOMPLETE:
4375 if (p->inalarm) break;
4376 if ((p->radio || (p->oprmode < 0))) break;
4377 if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
4378 ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
4379 return NULL;
4381 if (!x) { /* if not still dialing in driver */
4382 dahdi_enable_ec(p);
4383 if (p->echobreak) {
4384 dahdi_train_ec(p);
4385 ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
4386 p->dop.op = DAHDI_DIAL_OP_REPLACE;
4387 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
4388 p->echobreak = 0;
4389 } else {
4390 p->dialing = 0;
4391 if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
4392 /* if thru with dialing after offhook */
4393 if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
4394 ast_setstate(ast, AST_STATE_UP);
4395 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4396 p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
4397 break;
4398 } else { /* if to state wait for offhook to dial rest */
4399 /* we now wait for off hook */
4400 ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
4403 if (ast->_state == AST_STATE_DIALING) {
4404 if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
4405 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
4406 } else if (p->confirmanswer || (!p->dialednone && ((mysig == SIG_EM) || (mysig == SIG_EM_E1) || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD) || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF) || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB) || (mysig == SIG_SF) || (mysig == SIG_SFWINK) || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF) || (mysig == SIG_SF_FEATB)))) {
4407 ast_setstate(ast, AST_STATE_RINGING);
4408 } else if (!p->answeronpolarityswitch) {
4409 ast_setstate(ast, AST_STATE_UP);
4410 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4411 p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
4412 /* If aops=0 and hops=1, this is necessary */
4413 p->polarity = POLARITY_REV;
4414 } else {
4415 /* Start clean, so we can catch the change to REV polarity when party answers */
4416 p->polarity = POLARITY_IDLE;
4421 break;
4422 case DAHDI_EVENT_ALARM:
4423 #ifdef HAVE_PRI
4424 if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
4425 if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
4426 /* T309 is not enabled : hangup calls when alarm occurs */
4427 if (p->call) {
4428 if (p->pri && p->pri->pri) {
4429 if (!pri_grab(p, p->pri)) {
4430 pri_hangup(p->pri->pri, p->call, -1);
4431 pri_destroycall(p->pri->pri, p->call);
4432 p->call = NULL;
4433 pri_rel(p->pri);
4434 } else
4435 ast_log(LOG_WARNING, "Failed to grab PRI!\n");
4436 } else
4437 ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
4439 if (p->owner)
4440 p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
4443 if (p->bearer)
4444 p->bearer->inalarm = 1;
4445 else
4446 #endif
4447 p->inalarm = 1;
4448 res = get_alarms(p);
4449 handle_alarms(p, res);
4450 #ifdef HAVE_PRI
4451 if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
4452 /* fall through intentionally */
4453 } else {
4454 break;
4456 #endif
4457 #ifdef HAVE_SS7
4458 if (p->sig == SIG_SS7)
4459 break;
4460 #endif
4461 case DAHDI_EVENT_ONHOOK:
4462 if (p->radio) {
4463 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4464 p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
4465 break;
4467 if (p->oprmode < 0)
4469 if (p->oprmode != -1) break;
4470 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
4472 /* Make sure it starts ringing */
4473 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
4474 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
4475 save_conference(p->oprpeer);
4476 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
4478 break;
4480 switch (p->sig) {
4481 case SIG_FXOLS:
4482 case SIG_FXOGS:
4483 case SIG_FXOKS:
4484 p->onhooktime = time(NULL);
4485 p->msgstate = -1;
4486 /* Check for some special conditions regarding call waiting */
4487 if (idx == SUB_REAL) {
4488 /* The normal line was hung up */
4489 if (p->subs[SUB_CALLWAIT].owner) {
4490 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
4491 swap_subs(p, SUB_CALLWAIT, SUB_REAL);
4492 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
4493 unalloc_sub(p, SUB_CALLWAIT);
4494 #if 0
4495 p->subs[idx].needanswer = 0;
4496 p->subs[idx].needringing = 0;
4497 #endif
4498 p->callwaitingrepeat = 0;
4499 p->cidcwexpire = 0;
4500 p->owner = NULL;
4501 /* Don't start streaming audio yet if the incoming call isn't up yet */
4502 if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
4503 p->dialing = 1;
4504 dahdi_ring_phone(p);
4505 } else if (p->subs[SUB_THREEWAY].owner) {
4506 unsigned int mssinceflash;
4507 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
4508 the private structure -- not especially easy or clean */
4509 while (p->subs[SUB_THREEWAY].owner && ast_channel_trylock(p->subs[SUB_THREEWAY].owner)) {
4510 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
4511 DLA_UNLOCK(&p->lock);
4512 CHANNEL_DEADLOCK_AVOIDANCE(ast);
4513 /* We can grab ast and p in that order, without worry. We should make sure
4514 nothing seriously bad has happened though like some sort of bizarre double
4515 masquerade! */
4516 DLA_LOCK(&p->lock);
4517 if (p->owner != ast) {
4518 ast_log(LOG_WARNING, "This isn't good...\n");
4519 return NULL;
4522 if (!p->subs[SUB_THREEWAY].owner) {
4523 ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
4524 return NULL;
4526 mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
4527 ast_debug(1, "Last flash was %d ms ago\n", mssinceflash);
4528 if (mssinceflash < MIN_MS_SINCE_FLASH) {
4529 /* It hasn't been long enough since the last flashook. This is probably a bounce on
4530 hanging up. Hangup both channels now */
4531 if (p->subs[SUB_THREEWAY].owner)
4532 ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
4533 p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
4534 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
4535 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4536 } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
4537 if (p->transfer) {
4538 /* In any case this isn't a threeway call anymore */
4539 p->subs[SUB_REAL].inthreeway = 0;
4540 p->subs[SUB_THREEWAY].inthreeway = 0;
4541 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
4542 if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
4543 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4544 /* Swap subs and dis-own channel */
4545 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4546 p->owner = NULL;
4547 /* Ring the phone */
4548 dahdi_ring_phone(p);
4549 } else {
4550 if ((res = attempt_transfer(p)) < 0) {
4551 p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
4552 if (p->subs[SUB_THREEWAY].owner)
4553 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4554 } else if (res) {
4555 /* Don't actually hang up at this point */
4556 if (p->subs[SUB_THREEWAY].owner)
4557 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4558 break;
4561 } else {
4562 p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
4563 if (p->subs[SUB_THREEWAY].owner)
4564 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4566 } else {
4567 ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
4568 /* Swap subs and dis-own channel */
4569 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4570 p->owner = NULL;
4571 /* Ring the phone */
4572 dahdi_ring_phone(p);
4575 } else {
4576 ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
4578 /* Fall through */
4579 default:
4580 dahdi_disable_ec(p);
4581 return NULL;
4583 break;
4584 case DAHDI_EVENT_RINGOFFHOOK:
4585 if (p->inalarm) break;
4586 if (p->oprmode < 0)
4588 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
4590 /* Make sure it stops ringing */
4591 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
4592 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
4593 restore_conference(p->oprpeer);
4595 break;
4597 if (p->radio)
4599 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4600 p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
4601 break;
4603 /* for E911, its supposed to wait for offhook then dial
4604 the second half of the dial string */
4605 if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
4606 c = strchr(p->dialdest, '/');
4607 if (c)
4608 c++;
4609 else
4610 c = p->dialdest;
4611 if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
4612 else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
4613 if (strlen(p->dop.dialstr) > 4) {
4614 memset(p->echorest, 'w', sizeof(p->echorest) - 1);
4615 strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
4616 p->echorest[sizeof(p->echorest) - 1] = '\0';
4617 p->echobreak = 1;
4618 p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
4619 } else
4620 p->echobreak = 0;
4621 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
4622 int saveerr = errno;
4624 x = DAHDI_ONHOOK;
4625 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
4626 ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
4627 return NULL;
4629 p->dialing = 1;
4630 return &p->subs[idx].f;
4632 switch (p->sig) {
4633 case SIG_FXOLS:
4634 case SIG_FXOGS:
4635 case SIG_FXOKS:
4636 switch (ast->_state) {
4637 case AST_STATE_RINGING:
4638 dahdi_enable_ec(p);
4639 dahdi_train_ec(p);
4640 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4641 p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
4642 /* Make sure it stops ringing */
4643 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
4644 ast_debug(1, "channel %d answered\n", p->channel);
4645 if (p->cidspill) {
4646 /* Cancel any running CallerID spill */
4647 ast_free(p->cidspill);
4648 p->cidspill = NULL;
4650 p->dialing = 0;
4651 p->callwaitcas = 0;
4652 if (p->confirmanswer) {
4653 /* Ignore answer if "confirm answer" is enabled */
4654 p->subs[idx].f.frametype = AST_FRAME_NULL;
4655 p->subs[idx].f.subclass = 0;
4656 } else if (!ast_strlen_zero(p->dop.dialstr)) {
4657 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
4658 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
4659 if (res < 0) {
4660 ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
4661 p->dop.dialstr[0] = '\0';
4662 return NULL;
4663 } else {
4664 ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
4665 p->subs[idx].f.frametype = AST_FRAME_NULL;
4666 p->subs[idx].f.subclass = 0;
4667 p->dialing = 1;
4669 p->dop.dialstr[0] = '\0';
4670 ast_setstate(ast, AST_STATE_DIALING);
4671 } else
4672 ast_setstate(ast, AST_STATE_UP);
4673 return &p->subs[idx].f;
4674 case AST_STATE_DOWN:
4675 ast_setstate(ast, AST_STATE_RING);
4676 ast->rings = 1;
4677 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4678 p->subs[idx].f.subclass = AST_CONTROL_OFFHOOK;
4679 ast_debug(1, "channel %d picked up\n", p->channel);
4680 return &p->subs[idx].f;
4681 case AST_STATE_UP:
4682 /* Make sure it stops ringing */
4683 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
4684 /* Okay -- probably call waiting*/
4685 if (ast_bridged_channel(p->owner))
4686 ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
4687 p->subs[idx].needunhold = 1;
4688 break;
4689 case AST_STATE_RESERVED:
4690 /* Start up dialtone */
4691 if (has_voicemail(p))
4692 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
4693 else
4694 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
4695 break;
4696 default:
4697 ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
4699 break;
4700 case SIG_FXSLS:
4701 case SIG_FXSGS:
4702 case SIG_FXSKS:
4703 if (ast->_state == AST_STATE_RING) {
4704 p->ringt = p->ringt_base;
4707 /* If we get a ring then we cannot be in
4708 * reversed polarity. So we reset to idle */
4709 ast_debug(1, "Setting IDLE polarity due "
4710 "to ring. Old polarity was %d\n",
4711 p->polarity);
4712 p->polarity = POLARITY_IDLE;
4714 /* Fall through */
4715 case SIG_EM:
4716 case SIG_EM_E1:
4717 case SIG_EMWINK:
4718 case SIG_FEATD:
4719 case SIG_FEATDMF:
4720 case SIG_FEATDMF_TA:
4721 case SIG_E911:
4722 case SIG_FGC_CAMA:
4723 case SIG_FGC_CAMAMF:
4724 case SIG_FEATB:
4725 case SIG_SF:
4726 case SIG_SFWINK:
4727 case SIG_SF_FEATD:
4728 case SIG_SF_FEATDMF:
4729 case SIG_SF_FEATB:
4730 if (ast->_state == AST_STATE_PRERING)
4731 ast_setstate(ast, AST_STATE_RING);
4732 if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
4733 ast_debug(1, "Ring detected\n");
4734 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4735 p->subs[idx].f.subclass = AST_CONTROL_RING;
4736 } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
4737 ast_debug(1, "Line answered\n");
4738 if (p->confirmanswer) {
4739 p->subs[idx].f.frametype = AST_FRAME_NULL;
4740 p->subs[idx].f.subclass = 0;
4741 } else {
4742 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4743 p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
4744 ast_setstate(ast, AST_STATE_UP);
4746 } else if (ast->_state != AST_STATE_RING)
4747 ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
4748 break;
4749 default:
4750 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
4752 break;
4753 case DAHDI_EVENT_RINGBEGIN:
4754 switch (p->sig) {
4755 case SIG_FXSLS:
4756 case SIG_FXSGS:
4757 case SIG_FXSKS:
4758 if (ast->_state == AST_STATE_RING) {
4759 p->ringt = p->ringt_base;
4761 break;
4763 break;
4764 case DAHDI_EVENT_RINGEROFF:
4765 if (p->inalarm) break;
4766 if ((p->radio || (p->oprmode < 0))) break;
4767 ast->rings++;
4768 if ((ast->rings > p->cidrings) && (p->cidspill)) {
4769 ast_log(LOG_WARNING, "Didn't finish Caller-ID spill. Cancelling.\n");
4770 ast_free(p->cidspill);
4771 p->cidspill = NULL;
4772 p->callwaitcas = 0;
4774 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
4775 p->subs[idx].f.subclass = AST_CONTROL_RINGING;
4776 break;
4777 case DAHDI_EVENT_RINGERON:
4778 break;
4779 case DAHDI_EVENT_NOALARM:
4780 p->inalarm = 0;
4781 #ifdef HAVE_PRI
4782 /* Extremely unlikely but just in case */
4783 if (p->bearer)
4784 p->bearer->inalarm = 0;
4785 #endif
4786 ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
4787 manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
4788 "Channel: %d\r\n", p->channel);
4789 break;
4790 case DAHDI_EVENT_WINKFLASH:
4791 if (p->inalarm) break;
4792 if (p->radio) break;
4793 if (p->oprmode < 0) break;
4794 if (p->oprmode > 1)
4796 struct dahdi_params par;
4798 if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
4800 if (!par.rxisoffhook)
4802 /* Make sure it stops ringing */
4803 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
4804 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
4805 save_conference(p);
4806 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
4809 break;
4811 /* Remember last time we got a flash-hook */
4812 p->flashtime = ast_tvnow();
4813 switch (mysig) {
4814 case SIG_FXOLS:
4815 case SIG_FXOGS:
4816 case SIG_FXOKS:
4817 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
4818 idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
4819 p->callwaitcas = 0;
4821 if (idx != SUB_REAL) {
4822 ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
4823 goto winkflashdone;
4826 if (p->subs[SUB_CALLWAIT].owner) {
4827 /* Swap to call-wait */
4828 swap_subs(p, SUB_REAL, SUB_CALLWAIT);
4829 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
4830 p->owner = p->subs[SUB_REAL].owner;
4831 ast_debug(1, "Making %s the new owner\n", p->owner->name);
4832 if (p->owner->_state == AST_STATE_RINGING) {
4833 ast_setstate(p->owner, AST_STATE_UP);
4834 p->subs[SUB_REAL].needanswer = 1;
4836 p->callwaitingrepeat = 0;
4837 p->cidcwexpire = 0;
4838 /* Start music on hold if appropriate */
4839 if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
4840 ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
4841 S_OR(p->mohsuggest, NULL),
4842 !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
4844 p->subs[SUB_CALLWAIT].needhold = 1;
4845 if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
4846 ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
4847 S_OR(p->mohsuggest, NULL),
4848 !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
4850 p->subs[SUB_REAL].needunhold = 1;
4851 } else if (!p->subs[SUB_THREEWAY].owner) {
4852 char cid_num[256];
4853 char cid_name[256];
4855 if (!p->threewaycalling) {
4856 /* Just send a flash if no 3-way calling */
4857 p->subs[SUB_REAL].needflash = 1;
4858 goto winkflashdone;
4859 } else if (!check_for_conference(p)) {
4860 if (p->dahditrcallerid && p->owner) {
4861 if (p->owner->cid.cid_num)
4862 ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num));
4863 if (p->owner->cid.cid_name)
4864 ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
4866 /* XXX This section needs much more error checking!!! XXX */
4867 /* Start a 3-way call if feasible */
4868 if (!((ast->pbx) ||
4869 (ast->_state == AST_STATE_UP) ||
4870 (ast->_state == AST_STATE_RING))) {
4871 ast_debug(1, "Flash when call not up or ringing\n");
4872 goto winkflashdone;
4874 if (alloc_sub(p, SUB_THREEWAY)) {
4875 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
4876 goto winkflashdone;
4878 /* Make new channel */
4879 chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
4880 if (p->dahditrcallerid) {
4881 if (!p->origcid_num)
4882 p->origcid_num = ast_strdup(p->cid_num);
4883 if (!p->origcid_name)
4884 p->origcid_name = ast_strdup(p->cid_name);
4885 ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
4886 ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
4888 /* Swap things around between the three-way and real call */
4889 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4890 /* Disable echo canceller for better dialing */
4891 dahdi_disable_ec(p);
4892 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
4893 if (res)
4894 ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
4895 p->owner = chan;
4896 if (!chan) {
4897 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
4898 } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
4899 ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
4900 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
4901 dahdi_enable_ec(p);
4902 ast_hangup(chan);
4903 } else {
4904 struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
4905 int way3bridge = 0, cdr3way = 0;
4907 if (!other) {
4908 other = ast_bridged_channel(p->subs[SUB_REAL].owner);
4909 } else
4910 way3bridge = 1;
4912 if (p->subs[SUB_THREEWAY].owner->cdr)
4913 cdr3way = 1;
4915 ast_verb(3, "Started three way call on channel %d\n", p->channel);
4917 /* Start music on hold if appropriate */
4918 if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
4919 ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
4920 S_OR(p->mohsuggest, NULL),
4921 !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
4923 p->subs[SUB_THREEWAY].needhold = 1;
4926 } else {
4927 /* Already have a 3 way call */
4928 if (p->subs[SUB_THREEWAY].inthreeway) {
4929 /* Call is already up, drop the last person */
4930 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
4931 /* If the primary call isn't answered yet, use it */
4932 if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
4933 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
4934 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4935 p->owner = p->subs[SUB_REAL].owner;
4937 /* Drop the last call and stop the conference */
4938 ast_verb(3, "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
4939 p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
4940 p->subs[SUB_REAL].inthreeway = 0;
4941 p->subs[SUB_THREEWAY].inthreeway = 0;
4942 } else {
4943 /* Lets see what we're up to */
4944 if (((ast->pbx) || (ast->_state == AST_STATE_UP)) &&
4945 (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) {
4946 int otherindex = SUB_THREEWAY;
4947 struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
4948 int way3bridge = 0, cdr3way = 0;
4950 if (!other) {
4951 other = ast_bridged_channel(p->subs[SUB_REAL].owner);
4952 } else
4953 way3bridge = 1;
4955 if (p->subs[SUB_THREEWAY].owner->cdr)
4956 cdr3way = 1;
4958 ast_verb(3, "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
4959 /* Put them in the threeway, and flip */
4960 p->subs[SUB_THREEWAY].inthreeway = 1;
4961 p->subs[SUB_REAL].inthreeway = 1;
4962 if (ast->_state == AST_STATE_UP) {
4963 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4964 otherindex = SUB_REAL;
4966 if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
4967 ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
4968 p->subs[otherindex].needunhold = 1;
4969 p->owner = p->subs[SUB_REAL].owner;
4970 if (ast->_state == AST_STATE_RINGING) {
4971 ast_debug(1, "Enabling ringtone on real and threeway\n");
4972 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
4973 res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
4975 } else {
4976 ast_verb(3, "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
4977 swap_subs(p, SUB_THREEWAY, SUB_REAL);
4978 p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
4979 p->owner = p->subs[SUB_REAL].owner;
4980 if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
4981 ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
4982 p->subs[SUB_REAL].needunhold = 1;
4983 dahdi_enable_ec(p);
4988 winkflashdone:
4989 update_conf(p);
4990 break;
4991 case SIG_EM:
4992 case SIG_EM_E1:
4993 case SIG_EMWINK:
4994 case SIG_FEATD:
4995 case SIG_SF:
4996 case SIG_SFWINK:
4997 case SIG_SF_FEATD:
4998 case SIG_FXSLS:
4999 case SIG_FXSGS:
5000 if (option_debug) {
5001 if (p->dialing)
5002 ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
5003 else
5004 ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
5006 break;
5007 case SIG_FEATDMF_TA:
5008 switch (p->whichwink) {
5009 case 0:
5010 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
5011 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
5012 break;
5013 case 1:
5014 ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
5015 break;
5016 case 2:
5017 ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
5018 return NULL;
5020 p->whichwink++;
5021 /* Fall through */
5022 case SIG_FEATDMF:
5023 case SIG_E911:
5024 case SIG_FGC_CAMAMF:
5025 case SIG_FGC_CAMA:
5026 case SIG_FEATB:
5027 case SIG_SF_FEATDMF:
5028 case SIG_SF_FEATB:
5029 /* FGD MF *Must* wait for wink */
5030 if (!ast_strlen_zero(p->dop.dialstr)) {
5031 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
5032 if (res < 0) {
5033 ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
5034 p->dop.dialstr[0] = '\0';
5035 return NULL;
5036 } else
5037 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
5039 p->dop.dialstr[0] = '\0';
5040 break;
5041 default:
5042 ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
5044 break;
5045 case DAHDI_EVENT_HOOKCOMPLETE:
5046 if (p->inalarm) break;
5047 if ((p->radio || (p->oprmode < 0))) break;
5048 switch (mysig) {
5049 case SIG_FXSLS: /* only interesting for FXS */
5050 case SIG_FXSGS:
5051 case SIG_FXSKS:
5052 case SIG_EM:
5053 case SIG_EM_E1:
5054 case SIG_EMWINK:
5055 case SIG_FEATD:
5056 case SIG_SF:
5057 case SIG_SFWINK:
5058 case SIG_SF_FEATD:
5059 if (!ast_strlen_zero(p->dop.dialstr)) {
5060 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
5061 if (res < 0) {
5062 ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
5063 p->dop.dialstr[0] = '\0';
5064 return NULL;
5065 } else
5066 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
5068 p->dop.dialstr[0] = '\0';
5069 p->dop.op = DAHDI_DIAL_OP_REPLACE;
5070 break;
5071 case SIG_FEATDMF:
5072 case SIG_FEATDMF_TA:
5073 case SIG_E911:
5074 case SIG_FGC_CAMA:
5075 case SIG_FGC_CAMAMF:
5076 case SIG_FEATB:
5077 case SIG_SF_FEATDMF:
5078 case SIG_SF_FEATB:
5079 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
5080 break;
5081 default:
5082 break;
5084 break;
5085 case DAHDI_EVENT_POLARITY:
5087 * If we get a Polarity Switch event, check to see
5088 * if we should change the polarity state and
5089 * mark the channel as UP or if this is an indication
5090 * of remote end disconnect.
5092 if (p->polarity == POLARITY_IDLE) {
5093 p->polarity = POLARITY_REV;
5094 if (p->answeronpolarityswitch &&
5095 ((ast->_state == AST_STATE_DIALING) ||
5096 (ast->_state == AST_STATE_RINGING))) {
5097 ast_debug(1, "Answering on polarity switch!\n");
5098 ast_setstate(p->owner, AST_STATE_UP);
5099 if (p->hanguponpolarityswitch) {
5100 p->polaritydelaytv = ast_tvnow();
5102 } else
5103 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
5106 /* Removed else statement from here as it was preventing hangups from ever happening*/
5107 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
5108 if (p->hanguponpolarityswitch &&
5109 (p->polarityonanswerdelay > 0) &&
5110 (p->polarity == POLARITY_REV) &&
5111 ((ast->_state == AST_STATE_UP) || (ast->_state == AST_STATE_RING)) ) {
5112 /* Added log_debug information below to provide a better indication of what is going on */
5113 ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
5115 if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
5116 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
5117 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
5118 p->polarity = POLARITY_IDLE;
5119 } else
5120 ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
5122 } else {
5123 p->polarity = POLARITY_IDLE;
5124 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
5126 /* Added more log_debug information below to provide a better indication of what is going on */
5127 ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
5128 break;
5129 default:
5130 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
5132 return &p->subs[idx].f;
5135 static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
5137 struct dahdi_pvt *p = ast->tech_pvt;
5138 int res;
5139 int usedindex=-1;
5140 int idx;
5141 struct ast_frame *f;
5144 idx = dahdi_get_index(ast, p, 1);
5146 p->subs[idx].f.frametype = AST_FRAME_NULL;
5147 p->subs[idx].f.datalen = 0;
5148 p->subs[idx].f.samples = 0;
5149 p->subs[idx].f.mallocd = 0;
5150 p->subs[idx].f.offset = 0;
5151 p->subs[idx].f.subclass = 0;
5152 p->subs[idx].f.delivery = ast_tv(0,0);
5153 p->subs[idx].f.src = "dahdi_exception";
5154 p->subs[idx].f.data.ptr = NULL;
5157 if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
5158 /* If nobody owns us, absorb the event appropriately, otherwise
5159 we loop indefinitely. This occurs when, during call waiting, the
5160 other end hangs up our channel so that it no longer exists, but we
5161 have neither FLASH'd nor ONHOOK'd to signify our desire to
5162 change to the other channel. */
5163 if (p->fake_event) {
5164 res = p->fake_event;
5165 p->fake_event = 0;
5166 } else
5167 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
5168 /* Switch to real if there is one and this isn't something really silly... */
5169 if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
5170 (res != DAHDI_EVENT_HOOKCOMPLETE)) {
5171 ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
5172 p->owner = p->subs[SUB_REAL].owner;
5173 if (p->owner && ast_bridged_channel(p->owner))
5174 ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
5175 p->subs[SUB_REAL].needunhold = 1;
5177 switch (res) {
5178 case DAHDI_EVENT_ONHOOK:
5179 dahdi_disable_ec(p);
5180 if (p->owner) {
5181 ast_verb(3, "Channel %s still has call, ringing phone\n", p->owner->name);
5182 dahdi_ring_phone(p);
5183 p->callwaitingrepeat = 0;
5184 p->cidcwexpire = 0;
5185 } else
5186 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
5187 update_conf(p);
5188 break;
5189 case DAHDI_EVENT_RINGOFFHOOK:
5190 dahdi_enable_ec(p);
5191 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
5192 if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
5193 p->subs[SUB_REAL].needanswer = 1;
5194 p->dialing = 0;
5196 break;
5197 case DAHDI_EVENT_HOOKCOMPLETE:
5198 case DAHDI_EVENT_RINGERON:
5199 case DAHDI_EVENT_RINGEROFF:
5200 /* Do nothing */
5201 break;
5202 case DAHDI_EVENT_WINKFLASH:
5203 p->flashtime = ast_tvnow();
5204 if (p->owner) {
5205 ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
5206 if (p->owner->_state != AST_STATE_UP) {
5207 /* Answer if necessary */
5208 usedindex = dahdi_get_index(p->owner, p, 0);
5209 if (usedindex > -1) {
5210 p->subs[usedindex].needanswer = 1;
5212 ast_setstate(p->owner, AST_STATE_UP);
5214 p->callwaitingrepeat = 0;
5215 p->cidcwexpire = 0;
5216 if (ast_bridged_channel(p->owner))
5217 ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
5218 p->subs[SUB_REAL].needunhold = 1;
5219 } else
5220 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
5221 update_conf(p);
5222 break;
5223 default:
5224 ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
5226 f = &p->subs[idx].f;
5227 return f;
5229 if (!(p->radio || (p->oprmode < 0)))
5230 ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
5231 /* If it's not us, return NULL immediately */
5232 if (ast != p->owner) {
5233 ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
5234 f = &p->subs[idx].f;
5235 return f;
5237 f = dahdi_handle_event(ast);
5238 return f;
5241 static struct ast_frame *dahdi_exception(struct ast_channel *ast)
5243 struct dahdi_pvt *p = ast->tech_pvt;
5244 struct ast_frame *f;
5245 ast_mutex_lock(&p->lock);
5246 f = __dahdi_exception(ast);
5247 ast_mutex_unlock(&p->lock);
5248 return f;
5251 static struct ast_frame *dahdi_read(struct ast_channel *ast)
5253 struct dahdi_pvt *p = ast->tech_pvt;
5254 int res;
5255 int idx;
5256 void *readbuf;
5257 struct ast_frame *f;
5259 while (ast_mutex_trylock(&p->lock)) {
5260 CHANNEL_DEADLOCK_AVOIDANCE(ast);
5263 idx = dahdi_get_index(ast, p, 0);
5265 /* Hang up if we don't really exist */
5266 if (idx < 0) {
5267 ast_log(LOG_WARNING, "We dont exist?\n");
5268 ast_mutex_unlock(&p->lock);
5269 return NULL;
5272 if ((p->radio || (p->oprmode < 0)) && p->inalarm) return NULL;
5274 p->subs[idx].f.frametype = AST_FRAME_NULL;
5275 p->subs[idx].f.datalen = 0;
5276 p->subs[idx].f.samples = 0;
5277 p->subs[idx].f.mallocd = 0;
5278 p->subs[idx].f.offset = 0;
5279 p->subs[idx].f.subclass = 0;
5280 p->subs[idx].f.delivery = ast_tv(0,0);
5281 p->subs[idx].f.src = "dahdi_read";
5282 p->subs[idx].f.data.ptr = NULL;
5284 /* make sure it sends initial key state as first frame */
5285 if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
5287 struct dahdi_params ps;
5289 ps.channo = p->channel;
5290 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
5291 ast_mutex_unlock(&p->lock);
5292 return NULL;
5294 p->firstradio = 1;
5295 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5296 if (ps.rxisoffhook)
5298 p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
5300 else
5302 p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
5304 ast_mutex_unlock(&p->lock);
5305 return &p->subs[idx].f;
5307 if (p->ringt == 1) {
5308 ast_mutex_unlock(&p->lock);
5309 return NULL;
5311 else if (p->ringt > 0)
5312 p->ringt--;
5314 if (p->subs[idx].needringing) {
5315 /* Send ringing frame if requested */
5316 p->subs[idx].needringing = 0;
5317 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5318 p->subs[idx].f.subclass = AST_CONTROL_RINGING;
5319 ast_setstate(ast, AST_STATE_RINGING);
5320 ast_mutex_unlock(&p->lock);
5321 return &p->subs[idx].f;
5324 if (p->subs[idx].needbusy) {
5325 /* Send busy frame if requested */
5326 p->subs[idx].needbusy = 0;
5327 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5328 p->subs[idx].f.subclass = AST_CONTROL_BUSY;
5329 ast_mutex_unlock(&p->lock);
5330 return &p->subs[idx].f;
5333 if (p->subs[idx].needcongestion) {
5334 /* Send congestion frame if requested */
5335 p->subs[idx].needcongestion = 0;
5336 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5337 p->subs[idx].f.subclass = AST_CONTROL_CONGESTION;
5338 ast_mutex_unlock(&p->lock);
5339 return &p->subs[idx].f;
5342 if (p->subs[idx].needcallerid) {
5343 ast_set_callerid(ast, S_OR(p->lastcid_num, NULL),
5344 S_OR(p->lastcid_name, NULL),
5345 S_OR(p->lastcid_num, NULL)
5347 p->subs[idx].needcallerid = 0;
5350 if (p->subs[idx].needanswer) {
5351 /* Send answer frame if requested */
5352 p->subs[idx].needanswer = 0;
5353 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5354 p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
5355 ast_mutex_unlock(&p->lock);
5356 return &p->subs[idx].f;
5359 if (p->subs[idx].needflash) {
5360 /* Send answer frame if requested */
5361 p->subs[idx].needflash = 0;
5362 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5363 p->subs[idx].f.subclass = AST_CONTROL_FLASH;
5364 ast_mutex_unlock(&p->lock);
5365 return &p->subs[idx].f;
5368 if (p->subs[idx].needhold) {
5369 /* Send answer frame if requested */
5370 p->subs[idx].needhold = 0;
5371 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5372 p->subs[idx].f.subclass = AST_CONTROL_HOLD;
5373 ast_mutex_unlock(&p->lock);
5374 ast_debug(1, "Sending hold on '%s'\n", ast->name);
5375 return &p->subs[idx].f;
5378 if (p->subs[idx].needunhold) {
5379 /* Send answer frame if requested */
5380 p->subs[idx].needunhold = 0;
5381 p->subs[idx].f.frametype = AST_FRAME_CONTROL;
5382 p->subs[idx].f.subclass = AST_CONTROL_UNHOLD;
5383 ast_mutex_unlock(&p->lock);
5384 ast_debug(1, "Sending unhold on '%s'\n", ast->name);
5385 return &p->subs[idx].f;
5388 if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
5389 if (!p->subs[idx].linear) {
5390 p->subs[idx].linear = 1;
5391 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
5392 if (res)
5393 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
5395 } else if ((ast->rawreadformat == AST_FORMAT_ULAW) ||
5396 (ast->rawreadformat == AST_FORMAT_ALAW)) {
5397 if (p->subs[idx].linear) {
5398 p->subs[idx].linear = 0;
5399 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
5400 if (res)
5401 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
5403 } else {
5404 ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast->rawreadformat));
5405 ast_mutex_unlock(&p->lock);
5406 return NULL;
5408 readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
5409 CHECK_BLOCKING(ast);
5410 res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
5411 ast_clear_flag(ast, AST_FLAG_BLOCKING);
5412 /* Check for hangup */
5413 if (res < 0) {
5414 f = NULL;
5415 if (res == -1) {
5416 if (errno == EAGAIN) {
5417 /* Return "NULL" frame if there is nobody there */
5418 ast_mutex_unlock(&p->lock);
5419 return &p->subs[idx].f;
5420 } else if (errno == ELAST) {
5421 f = __dahdi_exception(ast);
5422 } else
5423 ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
5425 ast_mutex_unlock(&p->lock);
5426 return f;
5428 if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
5429 ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
5430 f = __dahdi_exception(ast);
5431 ast_mutex_unlock(&p->lock);
5432 return f;
5434 if (p->tdd) { /* if in TDD mode, see if we receive that */
5435 int c;
5437 c = tdd_feed(p->tdd,readbuf,READ_SIZE);
5438 if (c < 0) {
5439 ast_debug(1,"tdd_feed failed\n");
5440 ast_mutex_unlock(&p->lock);
5441 return NULL;
5443 if (c) { /* if a char to return */
5444 p->subs[idx].f.subclass = 0;
5445 p->subs[idx].f.frametype = AST_FRAME_TEXT;
5446 p->subs[idx].f.mallocd = 0;
5447 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
5448 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
5449 p->subs[idx].f.datalen = 1;
5450 *((char *) p->subs[idx].f.data.ptr) = c;
5451 ast_mutex_unlock(&p->lock);
5452 return &p->subs[idx].f;
5455 /* Ensure the CW timer decrements only on a single subchannel */
5456 if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
5457 p->callwaitingrepeat--;
5459 if (p->cidcwexpire)
5460 p->cidcwexpire--;
5461 /* Repeat callwaiting */
5462 if (p->callwaitingrepeat == 1) {
5463 p->callwaitrings++;
5464 dahdi_callwait(ast);
5466 /* Expire CID/CW */
5467 if (p->cidcwexpire == 1) {
5468 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
5469 restore_conference(p);
5471 if (p->subs[idx].linear) {
5472 p->subs[idx].f.datalen = READ_SIZE * 2;
5473 } else
5474 p->subs[idx].f.datalen = READ_SIZE;
5476 /* Handle CallerID Transmission */
5477 if ((p->owner == ast) && p->cidspill &&((ast->_state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
5478 send_callerid(p);
5481 p->subs[idx].f.frametype = AST_FRAME_VOICE;
5482 p->subs[idx].f.subclass = ast->rawreadformat;
5483 p->subs[idx].f.samples = READ_SIZE;
5484 p->subs[idx].f.mallocd = 0;
5485 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
5486 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
5487 #if 0
5488 ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
5489 #endif
5490 if (p->dialing || /* Transmitting something */
5491 (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
5492 ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
5494 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
5495 don't send anything */
5496 p->subs[idx].f.frametype = AST_FRAME_NULL;
5497 p->subs[idx].f.subclass = 0;
5498 p->subs[idx].f.samples = 0;
5499 p->subs[idx].f.mallocd = 0;
5500 p->subs[idx].f.offset = 0;
5501 p->subs[idx].f.data.ptr = NULL;
5502 p->subs[idx].f.datalen= 0;
5504 if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !idx) {
5505 /* Perform busy detection. etc on the dahdi line */
5506 int mute;
5508 f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
5510 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
5511 mute = ast_dsp_was_muted(p->dsp);
5512 if (p->muting != mute) {
5513 p->muting = mute;
5514 dahdi_confmute(p, mute);
5517 if (f) {
5518 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) {
5519 if ((ast->_state == AST_STATE_UP) && !p->outgoing) {
5520 /* Treat this as a "hangup" instead of a "busy" on the assumption that
5521 a busy */
5522 f = NULL;
5524 } else if (f->frametype == AST_FRAME_DTMF) {
5525 #ifdef HAVE_PRI
5526 if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri &&
5527 ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) ||
5528 (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
5529 /* Don't accept in-band DTMF when in overlap dial mode */
5530 f->frametype = AST_FRAME_NULL;
5531 f->subclass = 0;
5533 #endif
5534 /* DSP clears us of being pulse */
5535 p->pulsedial = 0;
5538 } else
5539 f = &p->subs[idx].f;
5541 if (f && (f->frametype == AST_FRAME_DTMF))
5542 dahdi_handle_dtmfup(ast, idx, &f);
5544 /* If we have a fake_event, trigger exception to handle it */
5545 if (p->fake_event)
5546 ast_set_flag(ast, AST_FLAG_EXCEPTION);
5548 ast_mutex_unlock(&p->lock);
5549 return f;
5552 static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
5554 int sent=0;
5555 int size;
5556 int res;
5557 int fd;
5558 fd = p->subs[idx].dfd;
5559 while (len) {
5560 size = len;
5561 if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
5562 size = (linear ? READ_SIZE * 2 : READ_SIZE);
5563 res = write(fd, buf, size);
5564 if (res != size) {
5565 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
5566 return sent;
5568 len -= size;
5569 buf += size;
5571 return sent;
5574 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
5576 struct dahdi_pvt *p = ast->tech_pvt;
5577 int res;
5578 int idx;
5579 idx = dahdi_get_index(ast, p, 0);
5580 if (idx < 0) {
5581 ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast->name);
5582 return -1;
5585 #if 0
5586 #ifdef HAVE_PRI
5587 ast_mutex_lock(&p->lock);
5588 if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
5589 if (p->pri->pri) {
5590 if (!pri_grab(p, p->pri)) {
5591 pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
5592 pri_rel(p->pri);
5593 } else
5594 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5596 p->proceeding=1;
5598 ast_mutex_unlock(&p->lock);
5599 #endif
5600 #endif
5601 /* Write a frame of (presumably voice) data */
5602 if (frame->frametype != AST_FRAME_VOICE) {
5603 if (frame->frametype != AST_FRAME_IMAGE)
5604 ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
5605 return 0;
5607 if ((frame->subclass != AST_FORMAT_SLINEAR) &&
5608 (frame->subclass != AST_FORMAT_ULAW) &&
5609 (frame->subclass != AST_FORMAT_ALAW)) {
5610 ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
5611 return -1;
5613 if (p->dialing) {
5614 ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
5615 return 0;
5617 if (!p->owner) {
5618 ast_debug(1, "Dropping frame since there is no active owner on %s...\n",ast->name);
5619 return 0;
5621 if (p->cidspill) {
5622 ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
5623 return 0;
5625 /* Return if it's not valid data */
5626 if (!frame->data.ptr || !frame->datalen)
5627 return 0;
5629 if (frame->subclass == AST_FORMAT_SLINEAR) {
5630 if (!p->subs[idx].linear) {
5631 p->subs[idx].linear = 1;
5632 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
5633 if (res)
5634 ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
5636 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
5637 } else {
5638 /* x-law already */
5639 if (p->subs[idx].linear) {
5640 p->subs[idx].linear = 0;
5641 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
5642 if (res)
5643 ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
5645 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
5647 if (res < 0) {
5648 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
5649 return -1;
5651 return 0;
5654 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
5656 struct dahdi_pvt *p = chan->tech_pvt;
5657 int res=-1;
5658 int idx;
5659 int func = DAHDI_FLASH;
5660 ast_mutex_lock(&p->lock);
5661 idx = dahdi_get_index(chan, p, 0);
5662 ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
5663 if (idx == SUB_REAL) {
5664 switch (condition) {
5665 case AST_CONTROL_BUSY:
5666 #ifdef HAVE_PRI
5667 if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
5668 chan->hangupcause = AST_CAUSE_USER_BUSY;
5669 chan->_softhangup |= AST_SOFTHANGUP_DEV;
5670 res = 0;
5671 } else if (!p->progress &&
5672 ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
5673 && p->pri && !p->outgoing) {
5674 if (p->pri->pri) {
5675 if (!pri_grab(p, p->pri)) {
5676 pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
5677 pri_rel(p->pri);
5679 else
5680 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5682 p->progress = 1;
5683 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
5684 } else
5685 #endif
5686 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
5687 break;
5688 case AST_CONTROL_RINGING:
5689 #ifdef HAVE_PRI
5690 if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
5691 && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
5692 if (p->pri->pri) {
5693 if (!pri_grab(p, p->pri)) {
5694 pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
5695 pri_rel(p->pri);
5697 else
5698 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5700 p->alerting = 1;
5703 #endif
5704 #ifdef HAVE_SS7
5705 if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) {
5706 if (p->ss7->ss7) {
5707 ss7_grab(p, p->ss7);
5709 if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
5710 p->rlt = 1;
5711 if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */
5712 isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
5713 p->alerting = 1;
5714 ss7_rel(p->ss7);
5717 #endif
5719 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
5721 if (chan->_state != AST_STATE_UP) {
5722 if ((chan->_state != AST_STATE_RING) ||
5723 ((p->sig != SIG_FXSKS) &&
5724 (p->sig != SIG_FXSLS) &&
5725 (p->sig != SIG_FXSGS)))
5726 ast_setstate(chan, AST_STATE_RINGING);
5728 break;
5729 case AST_CONTROL_PROCEEDING:
5730 ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
5731 #ifdef HAVE_PRI
5732 if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
5733 && p->pri && !p->outgoing) {
5734 if (p->pri->pri) {
5735 if (!pri_grab(p, p->pri)) {
5736 pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
5737 pri_rel(p->pri);
5739 else
5740 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5742 p->proceeding = 1;
5744 #endif
5745 #ifdef HAVE_SS7
5746 /* This IF sends the FAR for an answered ALEG call */
5747 if (chan->_state == AST_STATE_UP && (p->rlt != 1) && (p->sig == SIG_SS7)){
5748 if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
5749 p->rlt = 1;
5752 if (!p->proceeding && p->sig == SIG_SS7 && p->ss7 && !p->outgoing) {
5753 if (p->ss7->ss7) {
5754 ss7_grab(p, p->ss7);
5755 isup_acm(p->ss7->ss7, p->ss7call);
5756 p->proceeding = 1;
5757 ss7_rel(p->ss7);
5761 #endif
5762 /* don't continue in ast_indicate */
5763 res = 0;
5764 break;
5765 case AST_CONTROL_PROGRESS:
5766 ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
5767 #ifdef HAVE_PRI
5768 p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */
5769 if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
5770 && p->pri && !p->outgoing) {
5771 if (p->pri->pri) {
5772 if (!pri_grab(p, p->pri)) {
5773 pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
5774 pri_rel(p->pri);
5776 else
5777 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5779 p->progress = 1;
5781 #endif
5782 #ifdef HAVE_SS7
5783 if (!p->progress && p->sig==SIG_SS7 && p->ss7 && !p->outgoing) {
5784 if (p->ss7->ss7) {
5785 ss7_grab(p, p->ss7);
5786 isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
5787 p->progress = 1;
5788 ss7_rel(p->ss7);
5789 /* enable echo canceler here on SS7 calls */
5790 dahdi_enable_ec(p);
5794 #endif
5795 /* don't continue in ast_indicate */
5796 res = 0;
5797 break;
5798 case AST_CONTROL_CONGESTION:
5799 chan->hangupcause = AST_CAUSE_CONGESTION;
5800 #ifdef HAVE_PRI
5801 if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
5802 chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
5803 chan->_softhangup |= AST_SOFTHANGUP_DEV;
5804 res = 0;
5805 } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
5806 && p->pri && !p->outgoing) {
5807 if (p->pri) {
5808 if (!pri_grab(p, p->pri)) {
5809 pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
5810 pri_rel(p->pri);
5811 } else
5812 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5814 p->progress = 1;
5815 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
5816 } else
5817 #endif
5818 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
5819 break;
5820 case AST_CONTROL_HOLD:
5821 #ifdef HAVE_PRI
5822 if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
5823 if (!pri_grab(p, p->pri)) {
5824 res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
5825 pri_rel(p->pri);
5826 } else
5827 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5828 } else
5829 #endif
5830 ast_moh_start(chan, data, p->mohinterpret);
5831 break;
5832 case AST_CONTROL_UNHOLD:
5833 #ifdef HAVE_PRI
5834 if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
5835 if (!pri_grab(p, p->pri)) {
5836 res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
5837 pri_rel(p->pri);
5838 } else
5839 ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
5840 } else
5841 #endif
5842 ast_moh_stop(chan);
5843 break;
5844 case AST_CONTROL_RADIO_KEY:
5845 if (p->radio)
5846 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
5847 res = 0;
5848 break;
5849 case AST_CONTROL_RADIO_UNKEY:
5850 if (p->radio)
5851 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
5852 res = 0;
5853 break;
5854 case AST_CONTROL_FLASH:
5855 /* flash hookswitch */
5856 if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
5857 /* Clear out the dial buffer */
5858 p->dop.dialstr[0] = '\0';
5859 if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
5860 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
5861 chan->name, strerror(errno));
5862 } else
5863 res = 0;
5864 } else
5865 res = 0;
5866 break;
5867 case AST_CONTROL_SRCUPDATE:
5868 res = 0;
5869 break;
5870 case -1:
5871 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
5872 break;
5874 } else
5875 res = 0;
5876 ast_mutex_unlock(&p->lock);
5877 return res;
5880 static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, int transfercapability)
5882 struct ast_channel *tmp;
5883 int deflaw;
5884 int res;
5885 int x,y;
5886 int features;
5887 struct ast_str *chan_name;
5888 struct ast_variable *v;
5889 struct dahdi_params ps;
5890 if (i->subs[idx].owner) {
5891 ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
5892 return NULL;
5894 y = 1;
5895 chan_name = ast_str_alloca(32);
5896 do {
5897 #ifdef HAVE_PRI
5898 if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
5899 ast_str_set(&chan_name, 0, "%d:%d-%d", i->pri->trunkgroup, i->channel, y);
5900 else
5901 #endif
5902 if (i->channel == CHAN_PSEUDO)
5903 ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
5904 else
5905 ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
5906 for (x = 0; x < 3; x++) {
5907 if ((idx != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name + 6))
5908 break;
5910 y++;
5911 } while (x < 3);
5912 tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "DAHDI/%s", chan_name->str);
5913 if (!tmp)
5914 return NULL;
5915 tmp->tech = &dahdi_tech;
5916 ps.channo = i->channel;
5917 res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
5918 if (res) {
5919 ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW: %s\n", strerror(errno));
5920 ps.curlaw = DAHDI_LAW_MULAW;
5922 if (ps.curlaw == DAHDI_LAW_ALAW)
5923 deflaw = AST_FORMAT_ALAW;
5924 else
5925 deflaw = AST_FORMAT_ULAW;
5926 if (law) {
5927 if (law == DAHDI_LAW_ALAW)
5928 deflaw = AST_FORMAT_ALAW;
5929 else
5930 deflaw = AST_FORMAT_ULAW;
5932 ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
5933 tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
5934 /* Start out assuming ulaw since it's smaller :) */
5935 tmp->rawreadformat = deflaw;
5936 tmp->readformat = deflaw;
5937 tmp->rawwriteformat = deflaw;
5938 tmp->writeformat = deflaw;
5939 i->subs[idx].linear = 0;
5940 dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
5941 features = 0;
5942 if (idx == SUB_REAL) {
5943 if (i->busydetect && CANBUSYDETECT(i))
5944 features |= DSP_FEATURE_BUSY_DETECT;
5945 if ((i->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(i))
5946 features |= DSP_FEATURE_CALL_PROGRESS;
5947 if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
5948 (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) {
5949 features |= DSP_FEATURE_FAX_DETECT;
5951 x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
5952 if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
5953 i->hardwaredtmf = 0;
5954 features |= DSP_FEATURE_DIGIT_DETECT;
5955 } else if (NEED_MFDETECT(i)) {
5956 i->hardwaredtmf = 1;
5957 features |= DSP_FEATURE_DIGIT_DETECT;
5960 if (features) {
5961 if (i->dsp) {
5962 ast_debug(1, "Already have a dsp on %s?\n", tmp->name);
5963 } else {
5964 if (i->channel != CHAN_PSEUDO)
5965 i->dsp = ast_dsp_new();
5966 else
5967 i->dsp = NULL;
5968 if (i->dsp) {
5969 i->dsp_features = features;
5970 #if defined(HAVE_PRI) || defined(HAVE_SS7)
5971 /* We cannot do progress detection until receives PROGRESS message */
5972 if (i->outgoing && ((i->sig == SIG_PRI) || (i->sig == SIG_BRI) || (i->sig == SIG_BRI_PTMP) || (i->sig == SIG_SS7))) {
5973 /* Remember requested DSP features, don't treat
5974 talking as ANSWER */
5975 i->dsp_features = features & ~DSP_PROGRESS_TALK;
5976 features = 0;
5978 #endif
5979 ast_dsp_set_features(i->dsp, features);
5980 ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_DTMF | i->dtmfrelax);
5981 if (!ast_strlen_zero(progzone))
5982 ast_dsp_set_call_progress_zone(i->dsp, progzone);
5983 if (i->busydetect && CANBUSYDETECT(i)) {
5984 ast_dsp_set_busy_count(i->dsp, i->busycount);
5985 ast_dsp_set_busy_pattern(i->dsp, i->busy_tonelength, i->busy_quietlength);
5991 if (state == AST_STATE_RING)
5992 tmp->rings = 1;
5993 tmp->tech_pvt = i;
5994 if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
5995 /* Only FXO signalled stuff can be picked up */
5996 tmp->callgroup = i->callgroup;
5997 tmp->pickupgroup = i->pickupgroup;
5999 if (!ast_strlen_zero(i->parkinglot))
6000 ast_string_field_set(tmp, parkinglot, i->parkinglot);
6001 if (!ast_strlen_zero(i->language))
6002 ast_string_field_set(tmp, language, i->language);
6003 if (!i->owner)
6004 i->owner = tmp;
6005 if (!ast_strlen_zero(i->accountcode))
6006 ast_string_field_set(tmp, accountcode, i->accountcode);
6007 if (i->amaflags)
6008 tmp->amaflags = i->amaflags;
6009 i->subs[idx].owner = tmp;
6010 ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
6011 ast_string_field_set(tmp, call_forward, i->call_forward);
6012 /* If we've been told "no ADSI" then enforce it */
6013 if (!i->adsi)
6014 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
6015 if (!ast_strlen_zero(i->exten))
6016 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
6017 if (!ast_strlen_zero(i->rdnis))
6018 tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
6019 if (!ast_strlen_zero(i->dnid))
6020 tmp->cid.cid_dnid = ast_strdup(i->dnid);
6022 /* Don't use ast_set_callerid() here because it will
6023 * generate a needless NewCallerID event */
6024 #ifdef PRI_ANI
6025 if (!ast_strlen_zero(i->cid_ani))
6026 tmp->cid.cid_ani = ast_strdup(i->cid_ani);
6027 else
6028 tmp->cid.cid_ani = ast_strdup(i->cid_num);
6029 #else
6030 tmp->cid.cid_ani = ast_strdup(i->cid_num);
6031 #endif
6032 tmp->cid.cid_pres = i->callingpres;
6033 tmp->cid.cid_ton = i->cid_ton;
6034 tmp->cid.cid_ani2 = i->cid_ani2;
6035 #if defined(HAVE_PRI) || defined(HAVE_SS7)
6036 tmp->transfercapability = transfercapability;
6037 pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
6038 if (transfercapability & AST_TRANS_CAP_DIGITAL)
6039 i->digital = 1;
6040 /* Assume calls are not idle calls unless we're told differently */
6041 i->isidlecall = 0;
6042 i->alreadyhungup = 0;
6043 #endif
6044 /* clear the fake event in case we posted one before we had ast_channel */
6045 i->fake_event = 0;
6046 /* Assure there is no confmute on this channel */
6047 dahdi_confmute(i, 0);
6048 i->muting = 0;
6049 /* Configure the new channel jb */
6050 ast_jb_configure(tmp, &global_jbconf);
6052 ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name);
6054 for (v = i->vars ; v ; v = v->next)
6055 pbx_builtin_setvar_helper(tmp, v->name, v->value);
6057 if (startpbx) {
6058 if (ast_pbx_start(tmp)) {
6059 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
6060 ast_hangup(tmp);
6061 i->owner = NULL;
6062 return NULL;
6066 ast_module_ref(ast_module_info->self);
6067 return tmp;
6071 static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
6073 char c;
6075 *str = 0; /* start with empty output buffer */
6076 for (;;)
6078 /* Wait for the first digit (up to specified ms). */
6079 c = ast_waitfordigit(chan, ms);
6080 /* if timeout, hangup or error, return as such */
6081 if (c < 1)
6082 return c;
6083 *str++ = c;
6084 *str = 0;
6085 if (strchr(term, c))
6086 return 1;
6090 static int dahdi_wink(struct dahdi_pvt *p, int idx)
6092 int j;
6093 dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
6094 for (;;)
6096 /* set bits of interest */
6097 j = DAHDI_IOMUX_SIGEVENT;
6098 /* wait for some happening */
6099 if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
6100 /* exit loop if we have it */
6101 if (j & DAHDI_IOMUX_SIGEVENT) break;
6103 /* get the event info */
6104 if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
6105 return 0;
6108 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
6109 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
6110 * \param on 1 to enable, 0 to disable
6112 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
6113 * DAHDI channel). Use this to enable or disable it.
6115 * \bug the use of the word "channel" for those dahdichans is really confusing.
6117 static void dahdi_dnd(struct dahdi_pvt *dahdichan, int on)
6119 /* Do not disturb */
6120 dahdichan->dnd = on;
6121 ast_verb(3, "%s DND on channel %d\n",
6122 on? "Enabled" : "Disabled",
6123 dahdichan->channel);
6124 manager_event(EVENT_FLAG_SYSTEM, "DNDState",
6125 "Channel: DAHDI/%d\r\n"
6126 "Status: %s\r\n", dahdichan->channel,
6127 on? "enabled" : "disabled");
6130 static void *ss_thread(void *data)
6132 struct ast_channel *chan = data;
6133 struct dahdi_pvt *p = chan->tech_pvt;
6134 char exten[AST_MAX_EXTENSION] = "";
6135 char exten2[AST_MAX_EXTENSION] = "";
6136 unsigned char buf[256];
6137 char dtmfcid[300];
6138 char dtmfbuf[300];
6139 struct callerid_state *cs = NULL;
6140 char *name = NULL, *number = NULL;
6141 int distMatches;
6142 int curRingData[3];
6143 int receivedRingT;
6144 int counter1;
6145 int counter;
6146 int samples = 0;
6147 struct ast_smdi_md_message *smdi_msg = NULL;
6148 int flags;
6149 int i;
6150 int timeout;
6151 int getforward = 0;
6152 char *s1, *s2;
6153 int len = 0;
6154 int res;
6155 int idx;
6157 ast_mutex_lock(&ss_thread_lock);
6158 ss_thread_count++;
6159 ast_mutex_unlock(&ss_thread_lock);
6160 /* in the bizarre case where the channel has become a zombie before we
6161 even get started here, abort safely
6163 if (!p) {
6164 ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
6165 ast_hangup(chan);
6166 goto quit;
6168 ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
6169 idx = dahdi_get_index(chan, p, 1);
6170 if (idx < 0) {
6171 ast_log(LOG_WARNING, "Huh?\n");
6172 ast_hangup(chan);
6173 goto quit;
6175 if (p->dsp)
6176 ast_dsp_digitreset(p->dsp);
6177 switch (p->sig) {
6178 #ifdef HAVE_PRI
6179 case SIG_PRI:
6180 case SIG_BRI:
6181 case SIG_BRI_PTMP:
6182 /* Now loop looking for an extension */
6183 ast_copy_string(exten, p->exten, sizeof(exten));
6184 len = strlen(exten);
6185 res = 0;
6186 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
6187 if (len && !ast_ignore_pattern(chan->context, exten))
6188 tone_zone_play_tone(p->subs[idx].dfd, -1);
6189 else
6190 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
6191 if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
6192 timeout = matchdigittimeout;
6193 else
6194 timeout = gendigittimeout;
6195 res = ast_waitfordigit(chan, timeout);
6196 if (res < 0) {
6197 ast_debug(1, "waitfordigit returned < 0...\n");
6198 ast_hangup(chan);
6199 goto quit;
6200 } else if (res) {
6201 exten[len++] = res;
6202 exten[len] = '\0';
6203 } else
6204 break;
6206 /* if no extension was received ('unspecified') on overlap call, use the 's' extension */
6207 if (ast_strlen_zero(exten)) {
6208 ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
6209 exten[0] = 's';
6210 exten[1] = '\0';
6212 tone_zone_play_tone(p->subs[idx].dfd, -1);
6213 if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) {
6214 /* Start the real PBX */
6215 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
6216 if (p->dsp) ast_dsp_digitreset(p->dsp);
6217 dahdi_enable_ec(p);
6218 ast_setstate(chan, AST_STATE_RING);
6219 res = ast_pbx_run(chan);
6220 if (res) {
6221 ast_log(LOG_WARNING, "PBX exited non-zero!\n");
6223 } else {
6224 ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
6225 chan->hangupcause = AST_CAUSE_UNALLOCATED;
6226 ast_hangup(chan);
6227 p->exten[0] = '\0';
6228 /* Since we send release complete here, we won't get one */
6229 p->call = NULL;
6231 goto quit;
6232 break;
6233 #endif
6234 case SIG_FEATD:
6235 case SIG_FEATDMF:
6236 case SIG_FEATDMF_TA:
6237 case SIG_E911:
6238 case SIG_FGC_CAMAMF:
6239 case SIG_FEATB:
6240 case SIG_EMWINK:
6241 case SIG_SF_FEATD:
6242 case SIG_SF_FEATDMF:
6243 case SIG_SF_FEATB:
6244 case SIG_SFWINK:
6245 if (dahdi_wink(p, idx))
6246 goto quit;
6247 /* Fall through */
6248 case SIG_EM:
6249 case SIG_EM_E1:
6250 case SIG_SF:
6251 case SIG_FGC_CAMA:
6252 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
6253 if (p->dsp)
6254 ast_dsp_digitreset(p->dsp);
6255 /* set digit mode appropriately */
6256 if (p->dsp) {
6257 if (NEED_MFDETECT(p))
6258 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
6259 else
6260 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
6262 memset(dtmfbuf, 0, sizeof(dtmfbuf));
6263 /* Wait for the first digit only if immediate=no */
6264 if (!p->immediate)
6265 /* Wait for the first digit (up to 5 seconds). */
6266 res = ast_waitfordigit(chan, 5000);
6267 else
6268 res = 0;
6269 if (res > 0) {
6270 /* save first char */
6271 dtmfbuf[0] = res;
6272 switch (p->sig) {
6273 case SIG_FEATD:
6274 case SIG_SF_FEATD:
6275 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
6276 if (res > 0)
6277 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
6278 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
6279 break;
6280 case SIG_FEATDMF_TA:
6281 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
6282 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
6283 if (dahdi_wink(p, idx)) goto quit;
6284 dtmfbuf[0] = 0;
6285 /* Wait for the first digit (up to 5 seconds). */
6286 res = ast_waitfordigit(chan, 5000);
6287 if (res <= 0) break;
6288 dtmfbuf[0] = res;
6289 /* fall through intentionally */
6290 case SIG_FEATDMF:
6291 case SIG_E911:
6292 case SIG_FGC_CAMAMF:
6293 case SIG_SF_FEATDMF:
6294 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
6295 /* if international caca, do it again to get real ANO */
6296 if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
6298 if (dahdi_wink(p, idx)) goto quit;
6299 dtmfbuf[0] = 0;
6300 /* Wait for the first digit (up to 5 seconds). */
6301 res = ast_waitfordigit(chan, 5000);
6302 if (res <= 0) break;
6303 dtmfbuf[0] = res;
6304 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
6306 if (res > 0) {
6307 /* if E911, take off hook */
6308 if (p->sig == SIG_E911)
6309 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
6310 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
6312 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
6313 break;
6314 case SIG_FEATB:
6315 case SIG_SF_FEATB:
6316 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
6317 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
6318 break;
6319 case SIG_EMWINK:
6320 /* if we received a '*', we are actually receiving Feature Group D
6321 dial syntax, so use that mode; otherwise, fall through to normal
6322 mode
6324 if (res == '*') {
6325 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
6326 if (res > 0)
6327 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
6328 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
6329 break;
6331 default:
6332 /* If we got the first digit, get the rest */
6333 len = 1;
6334 dtmfbuf[len] = '\0';
6335 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
6336 if (ast_exists_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
6337 timeout = matchdigittimeout;
6338 } else {
6339 timeout = gendigittimeout;
6341 res = ast_waitfordigit(chan, timeout);
6342 if (res < 0) {
6343 ast_debug(1, "waitfordigit returned < 0...\n");
6344 ast_hangup(chan);
6345 goto quit;
6346 } else if (res) {
6347 dtmfbuf[len++] = res;
6348 dtmfbuf[len] = '\0';
6349 } else {
6350 break;
6353 break;
6356 if (res == -1) {
6357 ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
6358 ast_hangup(chan);
6359 goto quit;
6360 } else if (res < 0) {
6361 ast_debug(1, "Got hung up before digits finished\n");
6362 ast_hangup(chan);
6363 goto quit;
6366 if (p->sig == SIG_FGC_CAMA) {
6367 char anibuf[100];
6369 if (ast_safe_sleep(chan,1000) == -1) {
6370 ast_hangup(chan);
6371 goto quit;
6373 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
6374 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
6375 res = my_getsigstr(chan, anibuf, "#", 10000);
6376 if ((res > 0) && (strlen(anibuf) > 2)) {
6377 if (anibuf[strlen(anibuf) - 1] == '#')
6378 anibuf[strlen(anibuf) - 1] = 0;
6379 ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
6381 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
6384 ast_copy_string(exten, dtmfbuf, sizeof(exten));
6385 if (ast_strlen_zero(exten))
6386 ast_copy_string(exten, "s", sizeof(exten));
6387 if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
6388 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
6389 if (exten[0] == '*') {
6390 char *stringp=NULL;
6391 ast_copy_string(exten2, exten, sizeof(exten2));
6392 /* Parse out extension and callerid */
6393 stringp=exten2 +1;
6394 s1 = strsep(&stringp, "*");
6395 s2 = strsep(&stringp, "*");
6396 if (s2) {
6397 if (!ast_strlen_zero(p->cid_num))
6398 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
6399 else
6400 ast_set_callerid(chan, s1, NULL, s1);
6401 ast_copy_string(exten, s2, sizeof(exten));
6402 } else
6403 ast_copy_string(exten, s1, sizeof(exten));
6404 } else if (p->sig == SIG_FEATD)
6405 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
6407 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
6408 if (exten[0] == '*') {
6409 char *stringp=NULL;
6410 ast_copy_string(exten2, exten, sizeof(exten2));
6411 /* Parse out extension and callerid */
6412 stringp=exten2 +1;
6413 s1 = strsep(&stringp, "#");
6414 s2 = strsep(&stringp, "#");
6415 if (s2) {
6416 if (!ast_strlen_zero(p->cid_num))
6417 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
6418 else
6419 if (*(s1 + 2))
6420 ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
6421 ast_copy_string(exten, s2 + 1, sizeof(exten));
6422 } else
6423 ast_copy_string(exten, s1 + 2, sizeof(exten));
6424 } else
6425 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
6427 if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
6428 if (exten[0] == '*') {
6429 char *stringp=NULL;
6430 ast_copy_string(exten2, exten, sizeof(exten2));
6431 /* Parse out extension and callerid */
6432 stringp=exten2 +1;
6433 s1 = strsep(&stringp, "#");
6434 s2 = strsep(&stringp, "#");
6435 if (s2 && (*(s2 + 1) == '0')) {
6436 if (*(s2 + 2))
6437 ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
6439 if (s1) ast_copy_string(exten, s1, sizeof(exten));
6440 else ast_copy_string(exten, "911", sizeof(exten));
6441 } else
6442 ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
6444 if (p->sig == SIG_FEATB) {
6445 if (exten[0] == '*') {
6446 char *stringp=NULL;
6447 ast_copy_string(exten2, exten, sizeof(exten2));
6448 /* Parse out extension and callerid */
6449 stringp=exten2 +1;
6450 s1 = strsep(&stringp, "#");
6451 ast_copy_string(exten, exten2 + 1, sizeof(exten));
6452 } else
6453 ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
6455 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
6456 dahdi_wink(p, idx);
6457 /* some switches require a minimum guard time between
6458 the last FGD wink and something that answers
6459 immediately. This ensures it */
6460 if (ast_safe_sleep(chan,100)) goto quit;
6462 dahdi_enable_ec(p);
6463 if (NEED_MFDETECT(p)) {
6464 if (p->dsp) {
6465 if (!p->hardwaredtmf)
6466 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
6467 else {
6468 ast_dsp_free(p->dsp);
6469 p->dsp = NULL;
6474 if (ast_exists_extension(chan, chan->context, exten, 1, chan->cid.cid_num)) {
6475 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
6476 if (p->dsp) ast_dsp_digitreset(p->dsp);
6477 res = ast_pbx_run(chan);
6478 if (res) {
6479 ast_log(LOG_WARNING, "PBX exited non-zero\n");
6480 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
6482 goto quit;
6483 } else {
6484 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, chan->context);
6485 sleep(2);
6486 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
6487 if (res < 0)
6488 ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
6489 else
6490 sleep(1);
6491 res = ast_streamfile(chan, "ss-noservice", chan->language);
6492 if (res >= 0)
6493 ast_waitstream(chan, "");
6494 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
6495 ast_hangup(chan);
6496 goto quit;
6498 break;
6499 case SIG_FXOLS:
6500 case SIG_FXOGS:
6501 case SIG_FXOKS:
6502 /* Read the first digit */
6503 timeout = firstdigittimeout;
6504 /* If starting a threeway call, never timeout on the first digit so someone
6505 can use flash-hook as a "hold" feature */
6506 if (p->subs[SUB_THREEWAY].owner)
6507 timeout = 999999;
6508 while (len < AST_MAX_EXTENSION-1) {
6509 /* Read digit unless it's supposed to be immediate, in which case the
6510 only answer is 's' */
6511 if (p->immediate)
6512 res = 's';
6513 else
6514 res = ast_waitfordigit(chan, timeout);
6515 timeout = 0;
6516 if (res < 0) {
6517 ast_debug(1, "waitfordigit returned < 0...\n");
6518 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
6519 ast_hangup(chan);
6520 goto quit;
6521 } else if (res) {
6522 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
6523 exten[len++]=res;
6524 exten[len] = '\0';
6526 if (!ast_ignore_pattern(chan->context, exten))
6527 tone_zone_play_tone(p->subs[idx].dfd, -1);
6528 else
6529 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
6530 if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
6531 if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
6532 if (getforward) {
6533 /* Record this as the forwarding extension */
6534 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
6535 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
6536 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6537 if (res)
6538 break;
6539 usleep(500000);
6540 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
6541 sleep(1);
6542 memset(exten, 0, sizeof(exten));
6543 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
6544 len = 0;
6545 getforward = 0;
6546 } else {
6547 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
6548 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
6549 if (!ast_strlen_zero(p->cid_num)) {
6550 if (!p->hidecallerid)
6551 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
6552 else
6553 ast_set_callerid(chan, NULL, NULL, p->cid_num);
6555 if (!ast_strlen_zero(p->cid_name)) {
6556 if (!p->hidecallerid)
6557 ast_set_callerid(chan, NULL, p->cid_name, NULL);
6559 ast_setstate(chan, AST_STATE_RING);
6560 dahdi_enable_ec(p);
6561 res = ast_pbx_run(chan);
6562 if (res) {
6563 ast_log(LOG_WARNING, "PBX exited non-zero\n");
6564 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
6566 goto quit;
6568 } else {
6569 /* It's a match, but they just typed a digit, and there is an ambiguous match,
6570 so just set the timeout to matchdigittimeout and wait some more */
6571 timeout = matchdigittimeout;
6573 } else if (res == 0) {
6574 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
6575 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
6576 dahdi_wait_event(p->subs[idx].dfd);
6577 ast_hangup(chan);
6578 goto quit;
6579 } else if (p->callwaiting && !strcmp(exten, "*70")) {
6580 ast_verb(3, "Disabling call waiting on %s\n", chan->name);
6581 /* Disable call waiting if enabled */
6582 p->callwaiting = 0;
6583 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6584 if (res) {
6585 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
6586 chan->name, strerror(errno));
6588 len = 0;
6589 ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
6590 memset(exten, 0, sizeof(exten));
6591 timeout = firstdigittimeout;
6593 } else if (!strcmp(exten,ast_pickup_ext())) {
6594 /* Scan all channels and see if there are any
6595 * ringing channels that have call groups
6596 * that equal this channels pickup group
6598 if (idx == SUB_REAL) {
6599 /* Switch us from Third call to Call Wait */
6600 if (p->subs[SUB_THREEWAY].owner) {
6601 /* If you make a threeway call and the *8# a call, it should actually
6602 look like a callwait */
6603 alloc_sub(p, SUB_CALLWAIT);
6604 swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
6605 unalloc_sub(p, SUB_THREEWAY);
6607 dahdi_enable_ec(p);
6608 if (ast_pickup_call(chan)) {
6609 ast_debug(1, "No call pickup possible...\n");
6610 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
6611 dahdi_wait_event(p->subs[idx].dfd);
6613 ast_hangup(chan);
6614 goto quit;
6615 } else {
6616 ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
6617 ast_hangup(chan);
6618 goto quit;
6621 } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
6622 ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
6623 /* Disable Caller*ID if enabled */
6624 p->hidecallerid = 1;
6625 if (chan->cid.cid_num)
6626 ast_free(chan->cid.cid_num);
6627 chan->cid.cid_num = NULL;
6628 if (chan->cid.cid_name)
6629 ast_free(chan->cid.cid_name);
6630 chan->cid.cid_name = NULL;
6631 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6632 if (res) {
6633 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
6634 chan->name, strerror(errno));
6636 len = 0;
6637 memset(exten, 0, sizeof(exten));
6638 timeout = firstdigittimeout;
6639 } else if (p->callreturn && !strcmp(exten, "*69")) {
6640 res = 0;
6641 if (!ast_strlen_zero(p->lastcid_num)) {
6642 res = ast_say_digit_str(chan, p->lastcid_num, "", chan->language);
6644 if (!res)
6645 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6646 break;
6647 } else if (!strcmp(exten, "*78")) {
6648 dahdi_dnd(p, 1);
6649 /* Do not disturb */
6650 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6651 getforward = 0;
6652 memset(exten, 0, sizeof(exten));
6653 len = 0;
6654 } else if (!strcmp(exten, "*79")) {
6655 dahdi_dnd(p, 0);
6656 /* Do not disturb */
6657 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6658 getforward = 0;
6659 memset(exten, 0, sizeof(exten));
6660 len = 0;
6661 } else if (p->cancallforward && !strcmp(exten, "*72")) {
6662 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6663 getforward = 1;
6664 memset(exten, 0, sizeof(exten));
6665 len = 0;
6666 } else if (p->cancallforward && !strcmp(exten, "*73")) {
6667 ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
6668 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6669 memset(p->call_forward, 0, sizeof(p->call_forward));
6670 getforward = 0;
6671 memset(exten, 0, sizeof(exten));
6672 len = 0;
6673 } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) &&
6674 p->subs[SUB_THREEWAY].owner &&
6675 ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
6676 /* This is a three way call, the main call being a real channel,
6677 and we're parking the first call. */
6678 ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
6679 ast_verb(3, "Parking call to '%s'\n", chan->name);
6680 break;
6681 } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
6682 ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);
6683 res = ast_db_put("blacklist", p->lastcid_num, "1");
6684 if (!res) {
6685 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6686 memset(exten, 0, sizeof(exten));
6687 len = 0;
6689 } else if (p->hidecallerid && !strcmp(exten, "*82")) {
6690 ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
6691 /* Enable Caller*ID if enabled */
6692 p->hidecallerid = 0;
6693 if (chan->cid.cid_num)
6694 ast_free(chan->cid.cid_num);
6695 chan->cid.cid_num = NULL;
6696 if (chan->cid.cid_name)
6697 ast_free(chan->cid.cid_name);
6698 chan->cid.cid_name = NULL;
6699 ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
6700 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
6701 if (res) {
6702 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
6703 chan->name, strerror(errno));
6705 len = 0;
6706 memset(exten, 0, sizeof(exten));
6707 timeout = firstdigittimeout;
6708 } else if (!strcmp(exten, "*0")) {
6709 struct ast_channel *nbridge =
6710 p->subs[SUB_THREEWAY].owner;
6711 struct dahdi_pvt *pbridge = NULL;
6712 /* set up the private struct of the bridged one, if any */
6713 if (nbridge && ast_bridged_channel(nbridge))
6714 pbridge = ast_bridged_channel(nbridge)->tech_pvt;
6715 if (nbridge && pbridge &&
6716 (nbridge->tech == &dahdi_tech) &&
6717 (ast_bridged_channel(nbridge)->tech == &dahdi_tech) &&
6718 ISTRUNK(pbridge)) {
6719 int func = DAHDI_FLASH;
6720 /* Clear out the dial buffer */
6721 p->dop.dialstr[0] = '\0';
6722 /* flash hookswitch */
6723 if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
6724 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
6725 nbridge->name, strerror(errno));
6727 swap_subs(p, SUB_REAL, SUB_THREEWAY);
6728 unalloc_sub(p, SUB_THREEWAY);
6729 p->owner = p->subs[SUB_REAL].owner;
6730 if (ast_bridged_channel(p->subs[SUB_REAL].owner))
6731 ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
6732 ast_hangup(chan);
6733 goto quit;
6734 } else {
6735 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
6736 dahdi_wait_event(p->subs[idx].dfd);
6737 tone_zone_play_tone(p->subs[idx].dfd, -1);
6738 swap_subs(p, SUB_REAL, SUB_THREEWAY);
6739 unalloc_sub(p, SUB_THREEWAY);
6740 p->owner = p->subs[SUB_REAL].owner;
6741 ast_hangup(chan);
6742 goto quit;
6744 } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
6745 ((exten[0] != '*') || (strlen(exten) > 2))) {
6746 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
6747 break;
6749 if (!timeout)
6750 timeout = gendigittimeout;
6751 if (len && !ast_ignore_pattern(chan->context, exten))
6752 tone_zone_play_tone(p->subs[idx].dfd, -1);
6754 break;
6755 case SIG_FXSLS:
6756 case SIG_FXSGS:
6757 case SIG_FXSKS:
6758 #ifdef HAVE_PRI
6759 if (p->pri) {
6760 /* This is a GR-303 trunk actually. Wait for the first ring... */
6761 struct ast_frame *f;
6762 int res;
6763 time_t start;
6765 time(&start);
6766 ast_setstate(chan, AST_STATE_RING);
6767 while (time(NULL) < start + 3) {
6768 res = ast_waitfor(chan, 1000);
6769 if (res) {
6770 f = ast_read(chan);
6771 if (!f) {
6772 ast_log(LOG_WARNING, "Whoa, hangup while waiting for first ring!\n");
6773 ast_hangup(chan);
6774 goto quit;
6775 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
6776 res = 1;
6777 } else
6778 res = 0;
6779 ast_frfree(f);
6780 if (res) {
6781 ast_debug(1, "Got ring!\n");
6782 res = 0;
6783 break;
6788 #endif
6789 /* check for SMDI messages */
6790 if (p->use_smdi && p->smdi_iface) {
6791 smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT);
6793 if (smdi_msg != NULL) {
6794 ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten));
6796 if (smdi_msg->type == 'B')
6797 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
6798 else if (smdi_msg->type == 'N')
6799 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
6801 ast_debug(1, "Recieved SMDI message on %s\n", chan->name);
6802 } else {
6803 ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
6807 if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
6808 number = smdi_msg->calling_st;
6810 /* If we want caller id, we're in a prering state due to a polarity reversal
6811 * and we're set to use a polarity reversal to trigger the start of caller id,
6812 * grab the caller id and wait for ringing to start... */
6813 } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN))) {
6814 /* If set to use DTMF CID signalling, listen for DTMF */
6815 if (p->cid_signalling == CID_SIG_DTMF) {
6816 int k = 0;
6817 cs = NULL;
6818 ast_debug(1, "Receiving DTMF cid on "
6819 "channel %s\n", chan->name);
6820 dahdi_setlinear(p->subs[idx].dfd, 0);
6821 res = 2000;
6822 for (;;) {
6823 struct ast_frame *f;
6824 res = ast_waitfor(chan, res);
6825 if (res <= 0) {
6826 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
6827 "Exiting simple switch\n");
6828 ast_hangup(chan);
6829 goto quit;
6831 f = ast_read(chan);
6832 if (!f)
6833 break;
6834 if (f->frametype == AST_FRAME_DTMF) {
6835 dtmfbuf[k++] = f->subclass;
6836 ast_debug(1, "CID got digit '%c'\n", f->subclass);
6837 res = 2000;
6839 ast_frfree(f);
6840 if (chan->_state == AST_STATE_RING ||
6841 chan->_state == AST_STATE_RINGING)
6842 break; /* Got ring */
6844 dtmfbuf[k] = '\0';
6845 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
6846 /* Got cid and ring. */
6847 ast_debug(1, "CID got string '%s'\n", dtmfbuf);
6848 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
6849 ast_debug(1, "CID is '%s', flags %d\n",
6850 dtmfcid, flags);
6851 /* If first byte is NULL, we have no cid */
6852 if (!ast_strlen_zero(dtmfcid))
6853 number = dtmfcid;
6854 else
6855 number = NULL;
6856 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
6857 } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
6858 cs = callerid_new(p->cid_signalling);
6859 if (cs) {
6860 samples = 0;
6861 #if 1
6862 bump_gains(p);
6863 #endif
6864 /* Take out of linear mode for Caller*ID processing */
6865 dahdi_setlinear(p->subs[idx].dfd, 0);
6867 /* First we wait and listen for the Caller*ID */
6868 for (;;) {
6869 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
6870 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
6871 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
6872 callerid_free(cs);
6873 ast_hangup(chan);
6874 goto quit;
6876 if (i & DAHDI_IOMUX_SIGEVENT) {
6877 res = dahdi_get_event(p->subs[idx].dfd);
6878 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
6880 if (p->cid_signalling == CID_SIG_V23_JP) {
6881 if (res == DAHDI_EVENT_RINGBEGIN) {
6882 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
6883 usleep(1);
6885 } else {
6886 res = 0;
6887 break;
6889 } else if (i & DAHDI_IOMUX_READ) {
6890 res = read(p->subs[idx].dfd, buf, sizeof(buf));
6891 if (res < 0) {
6892 if (errno != ELAST) {
6893 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
6894 callerid_free(cs);
6895 ast_hangup(chan);
6896 goto quit;
6898 break;
6900 samples += res;
6902 if (p->cid_signalling == CID_SIG_V23_JP) {
6903 res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
6904 } else {
6905 res = callerid_feed(cs, buf, res, AST_LAW(p));
6908 if (res < 0) {
6909 ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
6910 break;
6911 } else if (res)
6912 break;
6913 else if (samples > (8000 * 10))
6914 break;
6917 if (res == 1) {
6918 callerid_get(cs, &name, &number, &flags);
6919 ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
6922 if (p->cid_signalling == CID_SIG_V23_JP) {
6923 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
6924 usleep(1);
6925 res = 4000;
6926 } else {
6928 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
6929 res = 2000;
6932 for (;;) {
6933 struct ast_frame *f;
6934 res = ast_waitfor(chan, res);
6935 if (res <= 0) {
6936 ast_log(LOG_WARNING, "CID timed out waiting for ring. "
6937 "Exiting simple switch\n");
6938 ast_hangup(chan);
6939 goto quit;
6941 if (!(f = ast_read(chan))) {
6942 ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
6943 ast_hangup(chan);
6944 goto quit;
6946 ast_frfree(f);
6947 if (chan->_state == AST_STATE_RING ||
6948 chan->_state == AST_STATE_RINGING)
6949 break; /* Got ring */
6952 /* We must have a ring by now, so, if configured, lets try to listen for
6953 * distinctive ringing */
6954 if (p->usedistinctiveringdetection == 1) {
6955 len = 0;
6956 distMatches = 0;
6957 /* Clear the current ring data array so we dont have old data in it. */
6958 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
6959 curRingData[receivedRingT] = 0;
6960 receivedRingT = 0;
6961 counter = 0;
6962 counter1 = 0;
6963 /* Check to see if context is what it should be, if not set to be. */
6964 if (strcmp(p->context,p->defcontext) != 0) {
6965 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
6966 ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
6969 for (;;) {
6970 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
6971 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
6972 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
6973 callerid_free(cs);
6974 ast_hangup(chan);
6975 goto quit;
6977 if (i & DAHDI_IOMUX_SIGEVENT) {
6978 res = dahdi_get_event(p->subs[idx].dfd);
6979 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
6980 res = 0;
6981 /* Let us detect distinctive ring */
6983 curRingData[receivedRingT] = p->ringt;
6985 if (p->ringt < p->ringt_base/2)
6986 break;
6987 /* Increment the ringT counter so we can match it against
6988 values in chan_dahdi.conf for distinctive ring */
6989 if (++receivedRingT == ARRAY_LEN(curRingData))
6990 break;
6991 } else if (i & DAHDI_IOMUX_READ) {
6992 res = read(p->subs[idx].dfd, buf, sizeof(buf));
6993 if (res < 0) {
6994 if (errno != ELAST) {
6995 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
6996 callerid_free(cs);
6997 ast_hangup(chan);
6998 goto quit;
7000 break;
7002 if (p->ringt)
7003 p->ringt--;
7004 if (p->ringt == 1) {
7005 res = -1;
7006 break;
7010 /* this only shows up if you have n of the dring patterns filled in */
7011 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
7012 for (counter = 0; counter < 3; counter++) {
7013 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
7014 channel */
7015 distMatches = 0;
7016 for (counter1 = 0; counter1 < 3; counter1++) {
7017 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
7018 if (p->drings.ringnum[counter].ring[counter1] == -1) {
7019 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
7020 curRingData[counter1]);
7021 distMatches++;
7023 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
7024 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
7025 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
7026 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
7027 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
7028 distMatches++;
7032 if (distMatches == 3) {
7033 /* The ring matches, set the context to whatever is for distinctive ring.. */
7034 ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
7035 ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
7036 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
7037 break;
7041 /* Restore linear mode (if appropriate) for Caller*ID processing */
7042 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
7043 #if 1
7044 restore_gains(p);
7045 #endif
7046 } else
7047 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
7048 } else {
7049 ast_log(LOG_WARNING, "Channel %s in prering "
7050 "state, but I have nothing to do. "
7051 "Terminating simple switch, should be "
7052 "restarted by the actual ring.\n",
7053 chan->name);
7054 ast_hangup(chan);
7055 goto quit;
7057 } else if (p->use_callerid && p->cid_start == CID_START_RING) {
7058 if (p->cid_signalling == CID_SIG_DTMF) {
7059 int k = 0;
7060 cs = NULL;
7061 dahdi_setlinear(p->subs[idx].dfd, 0);
7062 res = 2000;
7063 for (;;) {
7064 struct ast_frame *f;
7065 res = ast_waitfor(chan, res);
7066 if (res <= 0) {
7067 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
7068 "Exiting simple switch\n");
7069 ast_hangup(chan);
7070 return NULL;
7072 f = ast_read(chan);
7073 if (f->frametype == AST_FRAME_DTMF) {
7074 dtmfbuf[k++] = f->subclass;
7075 ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
7076 res = 2000;
7078 ast_frfree(f);
7080 if (p->ringt_base == p->ringt)
7081 break;
7084 dtmfbuf[k] = '\0';
7085 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
7086 /* Got cid and ring. */
7087 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
7088 ast_log(LOG_DEBUG, "CID is '%s', flags %d\n",
7089 dtmfcid, flags);
7090 /* If first byte is NULL, we have no cid */
7091 if (!ast_strlen_zero(dtmfcid))
7092 number = dtmfcid;
7093 else
7094 number = NULL;
7095 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
7096 } else {
7097 /* FSK Bell202 callerID */
7098 cs = callerid_new(p->cid_signalling);
7099 if (cs) {
7100 #if 1
7101 bump_gains(p);
7102 #endif
7103 samples = 0;
7104 len = 0;
7105 distMatches = 0;
7106 /* Clear the current ring data array so we dont have old data in it. */
7107 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
7108 curRingData[receivedRingT] = 0;
7109 receivedRingT = 0;
7110 counter = 0;
7111 counter1 = 0;
7112 /* Check to see if context is what it should be, if not set to be. */
7113 if (strcmp(p->context,p->defcontext) != 0) {
7114 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
7115 ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
7118 /* Take out of linear mode for Caller*ID processing */
7119 dahdi_setlinear(p->subs[idx].dfd, 0);
7120 for (;;) {
7121 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
7122 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
7123 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
7124 callerid_free(cs);
7125 ast_hangup(chan);
7126 goto quit;
7128 if (i & DAHDI_IOMUX_SIGEVENT) {
7129 res = dahdi_get_event(p->subs[idx].dfd);
7130 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
7131 /* If we get a PR event, they hung up while processing calerid */
7132 if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
7133 ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
7134 p->polarity = POLARITY_IDLE;
7135 callerid_free(cs);
7136 ast_hangup(chan);
7137 goto quit;
7139 res = 0;
7140 /* Let us detect callerid when the telco uses distinctive ring */
7142 curRingData[receivedRingT] = p->ringt;
7144 if (p->ringt < p->ringt_base/2)
7145 break;
7146 /* Increment the ringT counter so we can match it against
7147 values in chan_dahdi.conf for distinctive ring */
7148 if (++receivedRingT == ARRAY_LEN(curRingData))
7149 break;
7150 } else if (i & DAHDI_IOMUX_READ) {
7151 res = read(p->subs[idx].dfd, buf, sizeof(buf));
7152 if (res < 0) {
7153 if (errno != ELAST) {
7154 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
7155 callerid_free(cs);
7156 ast_hangup(chan);
7157 goto quit;
7159 break;
7161 if (p->ringt)
7162 p->ringt--;
7163 if (p->ringt == 1) {
7164 res = -1;
7165 break;
7167 samples += res;
7168 res = callerid_feed(cs, buf, res, AST_LAW(p));
7169 if (res < 0) {
7170 ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
7171 break;
7172 } else if (res)
7173 break;
7174 else if (samples > (8000 * 10))
7175 break;
7178 if (res == 1) {
7179 callerid_get(cs, &name, &number, &flags);
7180 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
7182 if (distinctiveringaftercid == 1) {
7183 /* Clear the current ring data array so we dont have old data in it. */
7184 for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
7185 curRingData[receivedRingT] = 0;
7187 receivedRingT = 0;
7188 ast_verb(3, "Detecting post-CID distinctive ring\n");
7189 for (;;) {
7190 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
7191 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
7192 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
7193 callerid_free(cs);
7194 ast_hangup(chan);
7195 goto quit;
7197 if (i & DAHDI_IOMUX_SIGEVENT) {
7198 res = dahdi_get_event(p->subs[idx].dfd);
7199 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
7200 res = 0;
7201 /* Let us detect callerid when the telco uses distinctive ring */
7203 curRingData[receivedRingT] = p->ringt;
7205 if (p->ringt < p->ringt_base/2)
7206 break;
7207 /* Increment the ringT counter so we can match it against
7208 values in chan_dahdi.conf for distinctive ring */
7209 if (++receivedRingT == ARRAY_LEN(curRingData))
7210 break;
7211 } else if (i & DAHDI_IOMUX_READ) {
7212 res = read(p->subs[idx].dfd, buf, sizeof(buf));
7213 if (res < 0) {
7214 if (errno != ELAST) {
7215 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
7216 callerid_free(cs);
7217 ast_hangup(chan);
7218 goto quit;
7220 break;
7222 if (p->ringt)
7223 p->ringt--;
7224 if (p->ringt == 1) {
7225 res = -1;
7226 break;
7231 if (p->usedistinctiveringdetection == 1) {
7232 /* this only shows up if you have n of the dring patterns filled in */
7233 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
7235 for (counter = 0; counter < 3; counter++) {
7236 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
7237 channel */
7238 /* this only shows up if you have n of the dring patterns filled in */
7239 ast_verb(3, "Checking %d,%d,%d\n",
7240 p->drings.ringnum[counter].ring[0],
7241 p->drings.ringnum[counter].ring[1],
7242 p->drings.ringnum[counter].ring[2]);
7243 distMatches = 0;
7244 for (counter1 = 0; counter1 < 3; counter1++) {
7245 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
7246 if (p->drings.ringnum[counter].ring[counter1] == -1) {
7247 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
7248 curRingData[counter1]);
7249 distMatches++;
7251 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
7252 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
7253 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
7254 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
7255 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
7256 distMatches++;
7259 if (distMatches == 3) {
7260 /* The ring matches, set the context to whatever is for distinctive ring.. */
7261 ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
7262 ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
7263 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
7264 break;
7268 /* Restore linear mode (if appropriate) for Caller*ID processing */
7269 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
7270 #if 1
7271 restore_gains(p);
7272 #endif
7273 if (res < 0) {
7274 ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
7276 } else
7277 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
7280 else
7281 cs = NULL;
7283 if (number)
7284 ast_shrink_phone_number(number);
7285 ast_set_callerid(chan, number, name, number);
7287 if (smdi_msg)
7288 ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
7290 if (cs)
7291 callerid_free(cs);
7292 /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
7293 if (flags & CID_MSGWAITING) {
7294 ast_log(LOG_NOTICE, "MWI: Channel %d message waiting!\n", p->channel);
7295 notify_message(p->mailbox, 1);
7296 ast_hangup(chan);
7297 return NULL;
7298 } else if (flags & CID_NOMSGWAITING) {
7299 ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting!\n", p->channel);
7300 notify_message(p->mailbox, 0);
7301 ast_hangup(chan);
7302 return NULL;
7305 ast_setstate(chan, AST_STATE_RING);
7306 chan->rings = 1;
7307 p->ringt = p->ringt_base;
7308 res = ast_pbx_run(chan);
7309 if (res) {
7310 ast_hangup(chan);
7311 ast_log(LOG_WARNING, "PBX exited non-zero\n");
7313 goto quit;
7314 default:
7315 ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
7316 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
7317 if (res < 0)
7318 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
7320 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
7321 if (res < 0)
7322 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
7323 ast_hangup(chan);
7324 quit:
7325 ast_mutex_lock(&ss_thread_lock);
7326 ss_thread_count--;
7327 ast_cond_signal(&ss_thread_complete);
7328 ast_mutex_unlock(&ss_thread_lock);
7329 return NULL;
7332 struct mwi_thread_data {
7333 struct dahdi_pvt *pvt;
7334 unsigned char buf[READ_SIZE];
7335 size_t len;
7338 static int calc_energy(const unsigned char *buf, int len, int law)
7340 int x;
7341 int sum = 0;
7343 if (!len)
7344 return 0;
7346 for (x = 0; x < len; x++)
7347 sum += abs(law == AST_FORMAT_ULAW ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
7349 return sum / len;
7352 static void *mwi_thread(void *data)
7354 struct mwi_thread_data *mtd = data;
7355 struct callerid_state *cs;
7356 pthread_t threadid;
7357 int samples = 0;
7358 char *name, *number;
7359 int flags;
7360 int i, res;
7361 unsigned int spill_done = 0;
7362 int spill_result = -1;
7364 if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
7365 mtd->pvt->mwimonitoractive = 0;
7367 return NULL;
7370 callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
7372 bump_gains(mtd->pvt);
7374 for (;;) {
7375 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
7376 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
7377 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
7378 goto quit;
7381 if (i & DAHDI_IOMUX_SIGEVENT) {
7382 struct ast_channel *chan;
7384 /* If we get an event, screen out events that we do not act on.
7385 * Otherwise, cancel and go to the simple switch to let it deal with it.
7387 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
7389 switch (res) {
7390 case DAHDI_EVENT_NEONMWI_ACTIVE:
7391 case DAHDI_EVENT_NEONMWI_INACTIVE:
7392 case DAHDI_EVENT_NONE:
7393 case DAHDI_EVENT_BITSCHANGED:
7394 break;
7395 case DAHDI_EVENT_NOALARM:
7396 mtd->pvt->inalarm = 0;
7397 ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", mtd->pvt->channel);
7398 manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
7399 "Channel: %d\r\n", mtd->pvt->channel);
7400 break;
7401 case DAHDI_EVENT_ALARM:
7402 mtd->pvt->inalarm = 1;
7403 res = get_alarms(mtd->pvt);
7404 handle_alarms(mtd->pvt, res);
7405 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
7406 default:
7407 ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to ss_thread\n", res, event2str(res));
7408 callerid_free(cs);
7410 restore_gains(mtd->pvt);
7411 mtd->pvt->ringt = mtd->pvt->ringt_base;
7413 if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, 0))) {
7414 if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
7415 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
7416 res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
7417 if (res < 0)
7418 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
7419 ast_hangup(chan);
7420 goto quit;
7422 goto quit_no_clean;
7424 } else {
7425 ast_log(LOG_WARNING, "Could not create channel to handle call\n");
7428 } else if (i & DAHDI_IOMUX_READ) {
7429 if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
7430 if (errno != ELAST) {
7431 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
7432 goto quit;
7434 break;
7436 samples += res;
7437 if (!spill_done) {
7438 if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
7439 ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
7440 break;
7441 } else if (spill_result) {
7442 spill_done = 1;
7444 } else {
7445 /* keep reading data until the energy level drops below the threshold
7446 so we don't get another 'trigger' on the remaining carrier signal
7448 if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
7449 break;
7451 if (samples > (8000 * 4)) /*Termination case - time to give up*/
7452 break;
7456 if (spill_result == 1) {
7457 callerid_get(cs, &name, &number, &flags);
7458 if (flags & CID_MSGWAITING) {
7459 ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
7460 notify_message(mtd->pvt->mailbox, 1);
7461 } else if (flags & CID_NOMSGWAITING) {
7462 ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
7463 notify_message(mtd->pvt->mailbox, 0);
7464 } else {
7465 ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
7470 quit:
7471 callerid_free(cs);
7473 restore_gains(mtd->pvt);
7475 quit_no_clean:
7476 mtd->pvt->mwimonitoractive = 0;
7478 ast_free(mtd);
7480 return NULL;
7483 /* States for sending MWI message
7484 * First three states are required for send Ring Pulse Alert Signal
7486 enum mwisend_states {
7487 MWI_SEND_SA,
7488 MWI_SEND_SA_WAIT,
7489 MWI_SEND_PAUSE,
7490 MWI_SEND_SPILL,
7491 MWI_SEND_CLEANUP,
7492 MWI_SEND_DONE
7495 static void *mwi_send_thread(void *data)
7497 struct mwi_thread_data *mtd = data;
7498 struct timeval timeout_basis, suspend, now;
7499 int x, i, res;
7500 int num_read;
7501 enum mwisend_states mwi_send_state = MWI_SEND_SPILL; /*Assume FSK only */
7503 ast_mutex_lock(&mwi_thread_lock);
7504 mwi_thread_count++;
7505 ast_mutex_unlock(&mwi_thread_lock);
7507 /* Determine how this spill is to be sent */
7508 if(mwisend_rpas) {
7509 mwi_send_state = MWI_SEND_SA;
7512 gettimeofday(&timeout_basis, NULL);
7514 mtd->pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE);
7515 if (!mtd->pvt->cidspill) {
7516 mtd->pvt->mwisendactive = 0;
7517 ast_free(mtd);
7518 return NULL;
7520 x = DAHDI_FLUSH_BOTH;
7521 res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
7522 x = 3000;
7523 ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
7524 mtd->pvt->cidlen = vmwi_generate(mtd->pvt->cidspill, has_voicemail(mtd->pvt), CID_MWI_TYPE_MDMF_FULL,
7525 AST_LAW(mtd->pvt), mtd->pvt->cid_name, mtd->pvt->cid_num, 0);
7526 mtd->pvt->cidpos = 0;
7528 while (MWI_SEND_DONE != mwi_send_state) {
7529 num_read = 0;
7530 gettimeofday(&now, NULL);
7531 if ( 10 < (now.tv_sec - timeout_basis.tv_sec)) {
7532 ast_log(LOG_WARNING, "MWI Send TIMEOUT in state %d\n", mwi_send_state);
7533 goto quit;
7536 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
7537 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
7538 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
7539 goto quit;
7542 if (i & DAHDI_IOMUX_SIGEVENT) {
7543 /* If we get an event, screen out events that we do not act on.
7544 * Otherwise, let handle_init_event determine what is needed
7546 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
7547 switch (res) {
7548 case DAHDI_EVENT_RINGEROFF:
7549 if(mwi_send_state == MWI_SEND_SA_WAIT) {
7550 if (dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
7551 ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s\n", strerror(errno));
7552 goto quit;
7554 mwi_send_state = MWI_SEND_PAUSE;
7555 gettimeofday(&suspend, NULL);
7557 break;
7558 case DAHDI_EVENT_RINGERON:
7559 case DAHDI_EVENT_HOOKCOMPLETE:
7560 break;
7561 default:
7562 /* Got to the default init event handler */
7563 if (0 < handle_init_event(mtd->pvt, res)) {
7564 /* I've spawned a thread, get out */
7565 goto quit;
7567 break;
7569 } else if (i & DAHDI_IOMUX_READ) {
7570 if ((num_read = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
7571 if (errno != ELAST) {
7572 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
7573 goto quit;
7575 break;
7578 /* Perform mwi send action */
7579 switch ( mwi_send_state) {
7580 case MWI_SEND_SA:
7581 /* Send the Ring Pulse Signal Alert */
7582 res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
7583 if (res) {
7584 ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
7585 goto quit;
7587 dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RING);
7588 mwi_send_state = MWI_SEND_SA_WAIT;
7589 break;
7590 case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */
7591 break;
7592 case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/
7593 gettimeofday(&now, NULL);
7594 if ((int)(now.tv_sec - suspend.tv_sec) * 1000000 + (int)now.tv_usec - (int)suspend.tv_usec > 500000) {
7595 mwi_send_state = MWI_SEND_SPILL;
7597 break;
7598 case MWI_SEND_SPILL:
7599 /* We read some number of bytes. Write an equal amount of data */
7600 if(0 < num_read) {
7601 if (num_read > mtd->pvt->cidlen - mtd->pvt->cidpos)
7602 num_read = mtd->pvt->cidlen - mtd->pvt->cidpos;
7603 res = write(mtd->pvt->subs[SUB_REAL].dfd, mtd->pvt->cidspill + mtd->pvt->cidpos, num_read);
7604 if (res > 0) {
7605 mtd->pvt->cidpos += res;
7606 if (mtd->pvt->cidpos >= mtd->pvt->cidlen) {
7607 ast_free(mtd->pvt->cidspill);
7608 mtd->pvt->cidspill = NULL;
7609 mtd->pvt->cidpos = 0;
7610 mtd->pvt->cidlen = 0;
7611 mwi_send_state = MWI_SEND_CLEANUP;
7613 } else {
7614 ast_log(LOG_WARNING, "MWI Send Write failed: %s\n", strerror(errno));
7615 goto quit;
7618 break;
7619 case MWI_SEND_CLEANUP:
7620 /* For now, do nothing */
7621 mwi_send_state = MWI_SEND_DONE;
7622 break;
7623 default:
7624 /* Should not get here, punt*/
7625 goto quit;
7626 break;
7630 quit:
7631 if(mtd->pvt->cidspill) {
7632 ast_free(mtd->pvt->cidspill);
7633 mtd->pvt->cidspill = NULL;
7635 mtd->pvt->mwisendactive = 0;
7636 ast_free(mtd);
7638 ast_mutex_lock(&mwi_thread_lock);
7639 mwi_thread_count--;
7640 ast_cond_signal(&mwi_thread_complete);
7641 ast_mutex_unlock(&mwi_thread_lock);
7643 return NULL;
7647 /* destroy a DAHDI channel, identified by its number */
7648 static int dahdi_destroy_channel_bynum(int channel)
7650 struct dahdi_pvt *tmp = NULL;
7651 struct dahdi_pvt *prev = NULL;
7653 tmp = iflist;
7654 while (tmp) {
7655 if (tmp->channel == channel) {
7656 int x = DAHDI_FLASH;
7657 ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */
7658 destroy_channel(prev, tmp, 1);
7659 ast_module_unref(ast_module_info->self);
7660 return RESULT_SUCCESS;
7662 prev = tmp;
7663 tmp = tmp->next;
7665 return RESULT_FAILURE;
7668 /* returns < 0 = error, 0 event handled, >0 event handled and thread spawned */
7669 static int handle_init_event(struct dahdi_pvt *i, int event)
7671 int res;
7672 int thread_spawned = 0;
7673 pthread_t threadid;
7674 struct ast_channel *chan;
7676 /* Handle an event on a given channel for the monitor thread. */
7678 switch (event) {
7679 case DAHDI_EVENT_NONE:
7680 case DAHDI_EVENT_BITSCHANGED:
7681 break;
7682 case DAHDI_EVENT_WINKFLASH:
7683 case DAHDI_EVENT_RINGOFFHOOK:
7684 if (i->inalarm) break;
7685 if (i->radio) break;
7686 /* Got a ring/answer. What kind of channel are we? */
7687 switch (i->sig) {
7688 case SIG_FXOLS:
7689 case SIG_FXOGS:
7690 case SIG_FXOKS:
7691 res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
7692 if (res && (errno == EBUSY))
7693 break;
7694 if (i->cidspill) {
7695 /* Cancel VMWI spill */
7696 ast_free(i->cidspill);
7697 i->cidspill = NULL;
7699 if (i->immediate) {
7700 dahdi_enable_ec(i);
7701 /* The channel is immediately up. Start right away */
7702 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
7703 chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, 0);
7704 if (!chan) {
7705 ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
7706 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
7707 if (res < 0)
7708 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
7710 } else {
7711 /* Check for callerid, digits, etc */
7712 chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, 0);
7713 if (chan) {
7714 if (has_voicemail(i))
7715 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
7716 else
7717 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
7718 if (res < 0)
7719 ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
7720 if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
7721 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
7722 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
7723 if (res < 0)
7724 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
7725 ast_hangup(chan);
7726 } else {
7727 thread_spawned = 1;
7729 } else
7730 ast_log(LOG_WARNING, "Unable to create channel\n");
7732 break;
7733 case SIG_FXSLS:
7734 case SIG_FXSGS:
7735 case SIG_FXSKS:
7736 i->ringt = i->ringt_base;
7737 /* Fall through */
7738 case SIG_EMWINK:
7739 case SIG_FEATD:
7740 case SIG_FEATDMF:
7741 case SIG_FEATDMF_TA:
7742 case SIG_E911:
7743 case SIG_FGC_CAMA:
7744 case SIG_FGC_CAMAMF:
7745 case SIG_FEATB:
7746 case SIG_EM:
7747 case SIG_EM_E1:
7748 case SIG_SFWINK:
7749 case SIG_SF_FEATD:
7750 case SIG_SF_FEATDMF:
7751 case SIG_SF_FEATB:
7752 case SIG_SF:
7753 /* Check for callerid, digits, etc */
7754 if (i->cid_start == CID_START_POLARITY_IN) {
7755 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
7756 } else {
7757 chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
7760 if (!chan) {
7761 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
7762 } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
7763 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
7764 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
7765 if (res < 0) {
7766 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
7768 ast_hangup(chan);
7769 } else {
7770 thread_spawned = 1;
7772 break;
7773 default:
7774 ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
7775 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
7776 if (res < 0)
7777 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
7778 return -1;
7780 break;
7781 case DAHDI_EVENT_NOALARM:
7782 i->inalarm = 0;
7783 ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
7784 manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
7785 "Channel: %d\r\n", i->channel);
7786 break;
7787 case DAHDI_EVENT_ALARM:
7788 i->inalarm = 1;
7789 res = get_alarms(i);
7790 handle_alarms(i, res);
7791 /* fall thru intentionally */
7792 case DAHDI_EVENT_ONHOOK:
7793 if (i->radio)
7794 break;
7795 /* Back on hook. Hang up. */
7796 switch (i->sig) {
7797 case SIG_FXOLS:
7798 case SIG_FXOGS:
7799 case SIG_FEATD:
7800 case SIG_FEATDMF:
7801 case SIG_FEATDMF_TA:
7802 case SIG_E911:
7803 case SIG_FGC_CAMA:
7804 case SIG_FGC_CAMAMF:
7805 case SIG_FEATB:
7806 case SIG_EM:
7807 case SIG_EM_E1:
7808 case SIG_EMWINK:
7809 case SIG_SF_FEATD:
7810 case SIG_SF_FEATDMF:
7811 case SIG_SF_FEATB:
7812 case SIG_SF:
7813 case SIG_SFWINK:
7814 case SIG_FXSLS:
7815 case SIG_FXSGS:
7816 case SIG_FXSKS:
7817 case SIG_GR303FXSKS:
7818 dahdi_disable_ec(i);
7819 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
7820 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
7821 break;
7822 case SIG_GR303FXOKS:
7823 case SIG_FXOKS:
7824 dahdi_disable_ec(i);
7825 /* Diddle the battery for the zhone */
7826 #ifdef ZHONE_HACK
7827 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
7828 usleep(1);
7829 #endif
7830 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
7831 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
7832 break;
7833 case SIG_PRI:
7834 case SIG_SS7:
7835 case SIG_BRI:
7836 case SIG_BRI_PTMP:
7837 dahdi_disable_ec(i);
7838 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
7839 break;
7840 default:
7841 ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
7842 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
7843 return -1;
7845 break;
7846 case DAHDI_EVENT_POLARITY:
7847 switch (i->sig) {
7848 case SIG_FXSLS:
7849 case SIG_FXSKS:
7850 case SIG_FXSGS:
7851 /* We have already got a PR before the channel was
7852 created, but it wasn't handled. We need polarity
7853 to be REV for remote hangup detection to work.
7854 At least in Spain */
7855 if (i->hanguponpolarityswitch)
7856 i->polarity = POLARITY_REV;
7857 if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) {
7858 i->polarity = POLARITY_REV;
7859 ast_verb(2, "Starting post polarity "
7860 "CID detection on channel %d\n",
7861 i->channel);
7862 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
7863 if (!chan) {
7864 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
7865 } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
7866 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
7867 } else {
7868 thread_spawned = 1;
7871 break;
7872 default:
7873 ast_log(LOG_WARNING, "handle_init_event detected "
7874 "polarity reversal on non-FXO (SIG_FXS) "
7875 "interface %d\n", i->channel);
7877 break;
7878 case DAHDI_EVENT_REMOVED: /* destroy channel */
7879 ast_log(LOG_NOTICE,
7880 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
7881 i->channel);
7882 dahdi_destroy_channel_bynum(i->channel);
7883 break;
7884 case DAHDI_EVENT_NEONMWI_ACTIVE:
7885 if (i->mwimonitor_neon) {
7886 notify_message(i->mailbox, 1);
7887 ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
7889 break;
7890 case DAHDI_EVENT_NEONMWI_INACTIVE:
7891 if (i->mwimonitor_neon) {
7892 notify_message(i->mailbox, 0);
7893 ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
7895 break;
7897 return thread_spawned;
7900 static void *do_monitor(void *data)
7902 int count, res, res2, spoint, pollres=0;
7903 struct dahdi_pvt *i;
7904 struct dahdi_pvt *last = NULL;
7905 time_t thispass = 0, lastpass = 0;
7906 int found;
7907 char buf[1024];
7908 struct pollfd *pfds=NULL;
7909 int lastalloc = -1;
7910 /* This thread monitors all the frame relay interfaces which are not yet in use
7911 (and thus do not have a separate thread) indefinitely */
7912 /* From here on out, we die whenever asked */
7913 #if 0
7914 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
7915 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
7916 return NULL;
7918 ast_debug(1, "Monitor starting...\n");
7919 #endif
7920 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
7922 for (;;) {
7923 /* Lock the interface list */
7924 ast_mutex_lock(&iflock);
7925 if (!pfds || (lastalloc != ifcount)) {
7926 if (pfds) {
7927 ast_free(pfds);
7928 pfds = NULL;
7930 if (ifcount) {
7931 if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
7932 ast_mutex_unlock(&iflock);
7933 return NULL;
7936 lastalloc = ifcount;
7938 /* Build the stuff we're going to poll on, that is the socket of every
7939 dahdi_pvt that does not have an associated owner channel */
7940 count = 0;
7941 i = iflist;
7942 while (i) {
7943 if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
7944 if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive && !i->mwisendactive) {
7945 /* This needs to be watched, as it lacks an owner */
7946 pfds[count].fd = i->subs[SUB_REAL].dfd;
7947 pfds[count].events = POLLPRI;
7948 pfds[count].revents = 0;
7949 /* If we are monitoring for VMWI or sending CID, we need to
7950 read from the channel as well */
7951 if (i->cidspill || i->mwimonitor_fsk)
7952 pfds[count].events |= POLLIN;
7953 count++;
7956 i = i->next;
7958 /* Okay, now that we know what to do, release the interface lock */
7959 ast_mutex_unlock(&iflock);
7961 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
7962 pthread_testcancel();
7963 /* Wait at least a second for something to happen */
7964 res = poll(pfds, count, 1000);
7965 pthread_testcancel();
7966 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
7968 /* Okay, poll has finished. Let's see what happened. */
7969 if (res < 0) {
7970 if ((errno != EAGAIN) && (errno != EINTR))
7971 ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
7972 continue;
7974 /* Alright, lock the interface list again, and let's look and see what has
7975 happened */
7976 ast_mutex_lock(&iflock);
7977 found = 0;
7978 spoint = 0;
7979 lastpass = thispass;
7980 thispass = time(NULL);
7981 i = iflist;
7982 while (i) {
7983 if (thispass != lastpass) {
7984 if (!found && ((i == last) || ((i == iflist) && !last))) {
7985 last = i;
7986 if (last) {
7987 if (!last->mwisendactive && last->sig & __DAHDI_SIG_FXO) {
7988 res = has_voicemail(last);
7989 if (last->msgstate != res) {
7991 /* This channel has a new voicemail state,
7992 * initiate a thread to send an MWI message
7994 pthread_attr_t attr;
7995 pthread_t threadid;
7996 struct mwi_thread_data *mtd;
7997 res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, res);
7998 if (res2) {
7999 ast_log(LOG_DEBUG, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
8001 pthread_attr_init(&attr);
8002 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
8003 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
8004 last->msgstate = res;
8005 mtd->pvt = last;
8006 last->mwisendactive = 1;
8007 if (ast_pthread_create_background(&threadid, &attr, mwi_send_thread, mtd)) {
8008 ast_log(LOG_WARNING, "Unable to start mwi send thread on channel %d\n", last->channel);
8009 ast_free(mtd);
8010 last->mwisendactive = 0;
8013 found ++;
8016 last = last->next;
8020 if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
8021 if (i->radio && !i->owner)
8023 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
8024 if (res)
8026 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
8027 /* Don't hold iflock while handling init events */
8028 ast_mutex_unlock(&iflock);
8029 handle_init_event(i, res);
8030 ast_mutex_lock(&iflock);
8032 i = i->next;
8033 continue;
8035 pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
8036 if (pollres & POLLIN) {
8037 if (i->owner || i->subs[SUB_REAL].owner) {
8038 #ifdef HAVE_PRI
8039 if (!i->pri)
8040 #endif
8041 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
8042 i = i->next;
8043 continue;
8045 if (!i->cidspill && !i->mwimonitor_fsk) {
8046 ast_log(LOG_WARNING, "Whoa.... I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
8047 i = i->next;
8048 continue;
8050 res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
8051 if (res > 0) {
8052 if (i->mwimonitor_fsk) {
8053 if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
8054 pthread_attr_t attr;
8055 pthread_t threadid;
8056 struct mwi_thread_data *mtd;
8058 pthread_attr_init(&attr);
8059 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
8061 ast_log(LOG_DEBUG, "Maybe some MWI on port %d!\n", i->channel);
8062 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
8063 mtd->pvt = i;
8064 memcpy(mtd->buf, buf, res);
8065 mtd->len = res;
8066 if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
8067 ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
8068 ast_free(mtd);
8070 i->mwimonitoractive = 1;
8074 } else {
8075 ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
8078 if (pollres & POLLPRI) {
8079 if (i->owner || i->subs[SUB_REAL].owner) {
8080 #ifdef HAVE_PRI
8081 if (!i->pri)
8082 #endif
8083 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
8084 i = i->next;
8085 continue;
8087 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
8088 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
8089 /* Don't hold iflock while handling init events */
8090 ast_mutex_unlock(&iflock);
8091 handle_init_event(i, res);
8092 ast_mutex_lock(&iflock);
8095 i=i->next;
8097 ast_mutex_unlock(&iflock);
8099 /* Never reached */
8100 return NULL;
8104 static int restart_monitor(void)
8106 /* If we're supposed to be stopped -- stay stopped */
8107 if (monitor_thread == AST_PTHREADT_STOP)
8108 return 0;
8109 ast_mutex_lock(&monlock);
8110 if (monitor_thread == pthread_self()) {
8111 ast_mutex_unlock(&monlock);
8112 ast_log(LOG_WARNING, "Cannot kill myself\n");
8113 return -1;
8115 if (monitor_thread != AST_PTHREADT_NULL) {
8116 /* Wake up the thread */
8117 pthread_kill(monitor_thread, SIGURG);
8118 } else {
8119 /* Start a new monitor */
8120 if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
8121 ast_mutex_unlock(&monlock);
8122 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
8123 return -1;
8126 ast_mutex_unlock(&monlock);
8127 return 0;
8130 #ifdef HAVE_PRI
8131 static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
8133 int x;
8134 int trunkgroup;
8135 /* Get appropriate trunk group if there is one */
8136 trunkgroup = pris[*span].mastertrunkgroup;
8137 if (trunkgroup) {
8138 /* Select a specific trunk group */
8139 for (x = 0; x < NUM_SPANS; x++) {
8140 if (pris[x].trunkgroup == trunkgroup) {
8141 *span = x;
8142 return 0;
8145 ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
8146 *span = -1;
8147 } else {
8148 if (pris[*span].trunkgroup) {
8149 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is trunk group %d (please use spanmap)\n", *span, pris[*span].trunkgroup);
8150 *span = -1;
8151 } else if (pris[*span].mastertrunkgroup) {
8152 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
8153 *span = -1;
8154 } else {
8155 if (si->totalchans == 31) {
8156 /* E1 */
8157 pris[*span].dchannels[0] = 16 + offset;
8158 } else if (si->totalchans == 24) {
8159 /* T1 or J1 */
8160 pris[*span].dchannels[0] = 24 + offset;
8161 } else if (si->totalchans == 3) {
8162 /* BRI */
8163 pris[*span].dchannels[0] = 3 + offset;
8164 } else {
8165 ast_log(LOG_WARNING, "Unable to use span %d, since the D-channel cannot be located (unexpected span size of %d channels)\n", *span, si->totalchans);
8166 *span = -1;
8167 return 0;
8169 pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
8170 pris[*span].offset = offset;
8171 pris[*span].span = *span + 1;
8174 return 0;
8177 static int pri_create_trunkgroup(int trunkgroup, int *channels)
8179 struct dahdi_spaninfo si;
8180 struct dahdi_params p;
8181 int fd;
8182 int span;
8183 int ospan=0;
8184 int x,y;
8185 for (x = 0; x < NUM_SPANS; x++) {
8186 if (pris[x].trunkgroup == trunkgroup) {
8187 ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
8188 return -1;
8191 for (y = 0; y < NUM_DCHANS; y++) {
8192 if (!channels[y])
8193 break;
8194 memset(&si, 0, sizeof(si));
8195 memset(&p, 0, sizeof(p));
8196 fd = open("/dev/dahdi/channel", O_RDWR);
8197 if (fd < 0) {
8198 ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
8199 return -1;
8201 x = channels[y];
8202 if (ioctl(fd, DAHDI_SPECIFY, &x)) {
8203 ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
8204 close(fd);
8205 return -1;
8207 if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
8208 ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
8209 return -1;
8211 if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
8212 ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
8213 close(fd);
8214 return -1;
8216 span = p.spanno - 1;
8217 if (pris[span].trunkgroup) {
8218 ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
8219 close(fd);
8220 return -1;
8222 if (pris[span].pvts[0]) {
8223 ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
8224 close(fd);
8225 return -1;
8227 if (!y) {
8228 pris[span].trunkgroup = trunkgroup;
8229 pris[span].offset = channels[y] - p.chanpos;
8230 ospan = span;
8232 pris[ospan].dchannels[y] = channels[y];
8233 pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
8234 pris[span].span = span + 1;
8235 close(fd);
8237 return 0;
8240 static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
8242 if (pris[span].mastertrunkgroup) {
8243 ast_log(LOG_WARNING, "Span %d is already part of trunk group %d, cannot add to trunk group %d\n", span + 1, pris[span].mastertrunkgroup, trunkgroup);
8244 return -1;
8246 pris[span].mastertrunkgroup = trunkgroup;
8247 pris[span].prilogicalspan = logicalspan;
8248 return 0;
8251 #endif
8253 #ifdef HAVE_SS7
8255 static unsigned int parse_pointcode(const char *pcstring)
8257 unsigned int code1, code2, code3;
8258 int numvals;
8260 numvals = sscanf(pcstring, "%d-%d-%d", &code1, &code2, &code3);
8261 if (numvals == 1)
8262 return code1;
8263 if (numvals == 3)
8264 return (code1 << 16) | (code2 << 8) | code3;
8266 return 0;
8269 static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
8271 if ((linkset < 0) || (linkset >= NUM_SPANS))
8272 return NULL;
8273 else
8274 return &linksets[linkset - 1];
8276 #endif /* HAVE_SS7 */
8278 /* converts a DAHDI sigtype to signalling as can be configured from
8279 * chan_dahdi.conf.
8280 * While both have basically the same values, this will later be the
8281 * place to add filters and sanity checks
8283 static int sigtype_to_signalling(int sigtype)
8285 return sigtype;
8288 static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, struct dahdi_pri *pri, int reloading)
8290 /* Make a dahdi_pvt structure for this interface (or CRV if "pri" is specified) */
8291 struct dahdi_pvt *tmp = NULL, *tmp2, *prev = NULL;
8292 char fn[80];
8293 struct dahdi_bufferinfo bi;
8295 int res;
8296 int span = 0;
8297 int here = 0;
8298 int x;
8299 struct dahdi_pvt **wlist;
8300 struct dahdi_pvt **wend;
8301 struct dahdi_params p;
8303 wlist = &iflist;
8304 wend = &ifend;
8306 #ifdef HAVE_PRI
8307 if (pri) {
8308 wlist = &pri->crvs;
8309 wend = &pri->crvend;
8311 #endif
8313 tmp2 = *wlist;
8314 prev = NULL;
8316 while (tmp2) {
8317 if (!tmp2->destroy) {
8318 if (tmp2->channel == channel) {
8319 tmp = tmp2;
8320 here = 1;
8321 break;
8323 if (tmp2->channel > channel) {
8324 break;
8327 prev = tmp2;
8328 tmp2 = tmp2->next;
8331 if (!here && reloading != 1) {
8332 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
8333 if (tmp)
8334 free(tmp);
8335 return NULL;
8337 ast_mutex_init(&tmp->lock);
8338 ifcount++;
8339 for (x = 0; x < 3; x++)
8340 tmp->subs[x].dfd = -1;
8341 tmp->channel = channel;
8344 if (tmp) {
8345 int chan_sig = conf->chan.sig;
8346 if (!here) {
8347 if ((channel != CHAN_PSEUDO) && !pri) {
8348 int count = 0;
8349 snprintf(fn, sizeof(fn), "%d", channel);
8350 /* Open non-blocking */
8351 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
8352 while (tmp->subs[SUB_REAL].dfd < 0 && reloading == 2 && count < 1000) { /* the kernel may not call dahdi_release fast enough for the open flagbit to be cleared in time */
8353 usleep(1);
8354 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
8355 count++;
8357 /* Allocate a DAHDI structure */
8358 if (tmp->subs[SUB_REAL].dfd < 0) {
8359 ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel);
8360 destroy_dahdi_pvt(&tmp);
8361 return NULL;
8363 memset(&p, 0, sizeof(p));
8364 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
8365 if (res < 0) {
8366 ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
8367 destroy_dahdi_pvt(&tmp);
8368 return NULL;
8370 if (conf->is_sig_auto)
8371 chan_sig = sigtype_to_signalling(p.sigtype);
8372 if (p.sigtype != (chan_sig & 0x3ffff)) {
8373 ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(chan_sig), sig2str(p.sigtype));
8374 destroy_dahdi_pvt(&tmp);
8375 return NULL;
8377 tmp->law = p.curlaw;
8378 tmp->span = p.spanno;
8379 span = p.spanno - 1;
8380 } else {
8381 if (channel == CHAN_PSEUDO)
8382 chan_sig = 0;
8383 else if ((chan_sig != SIG_FXOKS) && (chan_sig != SIG_FXSKS)) {
8384 ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
8385 return NULL;
8388 #ifdef HAVE_SS7
8389 if (chan_sig == SIG_SS7) {
8390 struct dahdi_ss7 *ss7;
8391 int clear = 0;
8392 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
8393 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
8394 destroy_dahdi_pvt(&tmp);
8395 return NULL;
8398 ss7 = ss7_resolve_linkset(cur_linkset);
8399 if (!ss7) {
8400 ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
8401 destroy_dahdi_pvt(&tmp);
8402 return NULL;
8404 if (cur_cicbeginswith < 0) {
8405 ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
8406 destroy_dahdi_pvt(&tmp);
8407 return NULL;
8410 tmp->cic = cur_cicbeginswith++;
8412 /* DB: Add CIC's DPC information */
8413 tmp->dpc = cur_defaultdpc;
8415 tmp->ss7 = ss7;
8416 tmp->ss7call = NULL;
8417 ss7->pvts[ss7->numchans++] = tmp;
8419 ast_copy_string(linksets[span].internationalprefix, conf->ss7.internationalprefix, sizeof(linksets[span].internationalprefix));
8420 ast_copy_string(linksets[span].nationalprefix, conf->ss7.nationalprefix, sizeof(linksets[span].nationalprefix));
8421 ast_copy_string(linksets[span].subscriberprefix, conf->ss7.subscriberprefix, sizeof(linksets[span].subscriberprefix));
8422 ast_copy_string(linksets[span].unknownprefix, conf->ss7.unknownprefix, sizeof(linksets[span].unknownprefix));
8424 linksets[span].called_nai = conf->ss7.called_nai;
8425 linksets[span].calling_nai = conf->ss7.calling_nai;
8427 #endif
8428 #ifdef HAVE_PRI
8429 if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_GR303FXOKS) || (chan_sig == SIG_GR303FXSKS)) {
8430 int offset;
8431 int myswitchtype;
8432 int matchesdchan;
8433 int x,y;
8434 offset = 0;
8435 if (((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP))
8436 && ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
8437 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
8438 destroy_dahdi_pvt(&tmp);
8439 return NULL;
8441 if (span >= NUM_SPANS) {
8442 ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
8443 destroy_dahdi_pvt(&tmp);
8444 return NULL;
8445 } else {
8446 struct dahdi_spaninfo si;
8447 si.spanno = 0;
8448 if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
8449 ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
8450 destroy_dahdi_pvt(&tmp);
8451 return NULL;
8453 /* Store the logical span first based upon the real span */
8454 tmp->logicalspan = pris[span].prilogicalspan;
8455 pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
8456 if (span < 0) {
8457 ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
8458 destroy_dahdi_pvt(&tmp);
8459 return NULL;
8461 if ((chan_sig == SIG_PRI) ||
8462 (chan_sig == SIG_BRI) ||
8463 (chan_sig == SIG_BRI_PTMP))
8464 myswitchtype = conf->pri.switchtype;
8465 else
8466 myswitchtype = PRI_SWITCH_GR303_TMC;
8467 /* Make sure this isn't a d-channel */
8468 matchesdchan=0;
8469 for (x = 0; x < NUM_SPANS; x++) {
8470 for (y = 0; y < NUM_DCHANS; y++) {
8471 if (pris[x].dchannels[y] == tmp->channel) {
8472 matchesdchan = 1;
8473 break;
8477 offset = p.chanpos;
8478 if (!matchesdchan) {
8479 if (pris[span].nodetype && (pris[span].nodetype != conf->pri.nodetype)) {
8480 ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
8481 destroy_dahdi_pvt(&tmp);
8482 return NULL;
8484 if (pris[span].switchtype && (pris[span].switchtype != myswitchtype)) {
8485 ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].switchtype));
8486 destroy_dahdi_pvt(&tmp);
8487 return NULL;
8489 if ((pris[span].dialplan) && (pris[span].dialplan != conf->pri.dialplan)) {
8490 ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, dialplan2str(pris[span].dialplan));
8491 destroy_dahdi_pvt(&tmp);
8492 return NULL;
8494 if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, conf->pri.idledial)) {
8495 ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.idledial);
8496 destroy_dahdi_pvt(&tmp);
8497 return NULL;
8499 if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, conf->pri.idleext)) {
8500 ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.idleext);
8501 destroy_dahdi_pvt(&tmp);
8502 return NULL;
8504 if (pris[span].minunused && (pris[span].minunused != conf->pri.minunused)) {
8505 ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.minunused);
8506 destroy_dahdi_pvt(&tmp);
8507 return NULL;
8509 if (pris[span].minidle && (pris[span].minidle != conf->pri.minidle)) {
8510 ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.minidle);
8511 destroy_dahdi_pvt(&tmp);
8512 return NULL;
8514 if (pris[span].numchans >= MAX_CHANNELS) {
8515 ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
8516 pris[span].trunkgroup);
8517 destroy_dahdi_pvt(&tmp);
8518 return NULL;
8521 pris[span].sig = chan_sig;
8522 pris[span].nodetype = conf->pri.nodetype;
8523 pris[span].switchtype = myswitchtype;
8524 pris[span].nsf = conf->pri.nsf;
8525 pris[span].dialplan = conf->pri.dialplan;
8526 pris[span].localdialplan = conf->pri.localdialplan;
8527 pris[span].pvts[pris[span].numchans++] = tmp;
8528 pris[span].minunused = conf->pri.minunused;
8529 pris[span].minidle = conf->pri.minidle;
8530 pris[span].overlapdial = conf->pri.overlapdial;
8531 #ifdef HAVE_PRI_INBANDDISCONNECT
8532 pris[span].inbanddisconnect = conf->pri.inbanddisconnect;
8533 #endif
8534 pris[span].facilityenable = conf->pri.facilityenable;
8535 ast_copy_string(pris[span].idledial, conf->pri.idledial, sizeof(pris[span].idledial));
8536 ast_copy_string(pris[span].idleext, conf->pri.idleext, sizeof(pris[span].idleext));
8537 ast_copy_string(pris[span].internationalprefix, conf->pri.internationalprefix, sizeof(pris[span].internationalprefix));
8538 ast_copy_string(pris[span].nationalprefix, conf->pri.nationalprefix, sizeof(pris[span].nationalprefix));
8539 ast_copy_string(pris[span].localprefix, conf->pri.localprefix, sizeof(pris[span].localprefix));
8540 ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix));
8541 ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix));
8542 pris[span].resetinterval = conf->pri.resetinterval;
8544 tmp->pri = &pris[span];
8545 tmp->prioffset = offset;
8546 tmp->call = NULL;
8547 } else {
8548 ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
8549 destroy_dahdi_pvt(&tmp);
8550 return NULL;
8553 } else {
8554 tmp->prioffset = 0;
8556 #endif
8557 } else {
8558 chan_sig = tmp->sig;
8559 memset(&p, 0, sizeof(p));
8560 if (tmp->subs[SUB_REAL].dfd > -1)
8561 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
8563 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
8564 switch (chan_sig) {
8565 case SIG_FXSKS:
8566 case SIG_FXSLS:
8567 case SIG_EM:
8568 case SIG_EM_E1:
8569 case SIG_EMWINK:
8570 case SIG_FEATD:
8571 case SIG_FEATDMF:
8572 case SIG_FEATDMF_TA:
8573 case SIG_FEATB:
8574 case SIG_E911:
8575 case SIG_SF:
8576 case SIG_SFWINK:
8577 case SIG_FGC_CAMA:
8578 case SIG_FGC_CAMAMF:
8579 case SIG_SF_FEATD:
8580 case SIG_SF_FEATDMF:
8581 case SIG_SF_FEATB:
8582 p.starttime = 250;
8583 break;
8586 if (tmp->radio) {
8587 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
8588 p.channo = channel;
8589 p.rxwinktime = 1;
8590 p.rxflashtime = 1;
8591 p.starttime = 1;
8592 p.debouncetime = 5;
8594 if (!tmp->radio) {
8595 p.channo = channel;
8596 /* Override timing settings based on config file */
8597 if (conf->timing.prewinktime >= 0)
8598 p.prewinktime = conf->timing.prewinktime;
8599 if (conf->timing.preflashtime >= 0)
8600 p.preflashtime = conf->timing.preflashtime;
8601 if (conf->timing.winktime >= 0)
8602 p.winktime = conf->timing.winktime;
8603 if (conf->timing.flashtime >= 0)
8604 p.flashtime = conf->timing.flashtime;
8605 if (conf->timing.starttime >= 0)
8606 p.starttime = conf->timing.starttime;
8607 if (conf->timing.rxwinktime >= 0)
8608 p.rxwinktime = conf->timing.rxwinktime;
8609 if (conf->timing.rxflashtime >= 0)
8610 p.rxflashtime = conf->timing.rxflashtime;
8611 if (conf->timing.debouncetime >= 0)
8612 p.debouncetime = conf->timing.debouncetime;
8615 /* dont set parms on a pseudo-channel (or CRV) */
8616 if (tmp->subs[SUB_REAL].dfd >= 0)
8618 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
8619 if (res < 0) {
8620 ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
8621 destroy_dahdi_pvt(&tmp);
8622 return NULL;
8625 #if 1
8626 if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
8627 memset(&bi, 0, sizeof(bi));
8628 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
8629 if (!res) {
8630 bi.txbufpolicy = conf->chan.buf_policy;
8631 bi.rxbufpolicy = conf->chan.buf_policy;
8632 bi.numbufs = conf->chan.buf_no;
8633 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
8634 if (res < 0) {
8635 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
8637 } else
8638 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
8640 #endif
8641 tmp->immediate = conf->chan.immediate;
8642 tmp->transfertobusy = conf->chan.transfertobusy;
8643 if (chan_sig & __DAHDI_SIG_FXS) {
8644 tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
8645 tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
8647 tmp->sig = chan_sig;
8648 tmp->outsigmod = conf->chan.outsigmod;
8649 tmp->ringt_base = ringt_base;
8650 tmp->firstradio = 0;
8651 if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
8652 tmp->permcallwaiting = conf->chan.callwaiting;
8653 else
8654 tmp->permcallwaiting = 0;
8655 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
8656 tmp->destroy = 0;
8657 tmp->drings = conf->chan.drings;
8659 /* 10 is a nice default. */
8660 if (tmp->drings.ringnum[0].range == 0)
8661 tmp->drings.ringnum[0].range = 10;
8662 if (tmp->drings.ringnum[1].range == 0)
8663 tmp->drings.ringnum[1].range = 10;
8664 if (tmp->drings.ringnum[2].range == 0)
8665 tmp->drings.ringnum[2].range = 10;
8667 tmp->usedistinctiveringdetection = usedistinctiveringdetection;
8668 tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
8669 tmp->threewaycalling = conf->chan.threewaycalling;
8670 tmp->adsi = conf->chan.adsi;
8671 tmp->use_smdi = conf->chan.use_smdi;
8672 tmp->permhidecallerid = conf->chan.hidecallerid;
8673 tmp->callreturn = conf->chan.callreturn;
8674 tmp->echocancel = conf->chan.echocancel;
8675 tmp->echotraining = conf->chan.echotraining;
8676 tmp->pulse = conf->chan.pulse;
8677 if (tmp->echocancel.head.tap_length) {
8678 tmp->echocanbridged = conf->chan.echocanbridged;
8679 } else {
8680 if (conf->chan.echocanbridged)
8681 ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
8682 tmp->echocanbridged = 0;
8684 tmp->busydetect = conf->chan.busydetect;
8685 tmp->busycount = conf->chan.busycount;
8686 tmp->busy_tonelength = conf->chan.busy_tonelength;
8687 tmp->busy_quietlength = conf->chan.busy_quietlength;
8688 tmp->callprogress = conf->chan.callprogress;
8689 tmp->cancallforward = conf->chan.cancallforward;
8690 tmp->dtmfrelax = conf->chan.dtmfrelax;
8691 tmp->callwaiting = tmp->permcallwaiting;
8692 tmp->hidecallerid = tmp->permhidecallerid;
8693 tmp->channel = channel;
8694 tmp->stripmsd = conf->chan.stripmsd;
8695 tmp->use_callerid = conf->chan.use_callerid;
8696 tmp->cid_signalling = conf->chan.cid_signalling;
8697 tmp->cid_start = conf->chan.cid_start;
8698 tmp->dahditrcallerid = conf->chan.dahditrcallerid;
8699 tmp->restrictcid = conf->chan.restrictcid;
8700 tmp->use_callingpres = conf->chan.use_callingpres;
8701 tmp->priindication_oob = conf->chan.priindication_oob;
8702 tmp->priexclusive = conf->chan.priexclusive;
8703 if (tmp->usedistinctiveringdetection) {
8704 if (!tmp->use_callerid) {
8705 ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
8706 tmp->use_callerid = 1;
8710 if (tmp->cid_signalling == CID_SIG_SMDI) {
8711 if (!tmp->use_smdi) {
8712 ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
8713 tmp->use_smdi = 1;
8716 if (tmp->use_smdi) {
8717 tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
8718 if (!(tmp->smdi_iface)) {
8719 ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
8720 tmp->use_smdi = 0;
8724 ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
8725 tmp->amaflags = conf->chan.amaflags;
8726 if (!here) {
8727 tmp->confno = -1;
8728 tmp->propconfno = -1;
8730 tmp->canpark = conf->chan.canpark;
8731 tmp->transfer = conf->chan.transfer;
8732 ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
8733 ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
8734 ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
8735 ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
8736 ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
8737 ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
8738 ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
8739 tmp->cid_ton = 0;
8740 ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
8741 ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
8742 if (!ast_strlen_zero(tmp->mailbox)) {
8743 char *mailbox, *context;
8744 mailbox = context = ast_strdupa(tmp->mailbox);
8745 strsep(&context, "@");
8746 if (ast_strlen_zero(context))
8747 context = "default";
8748 tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
8749 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
8750 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
8751 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
8752 AST_EVENT_IE_END);
8754 tmp->msgstate = -1;
8755 tmp->group = conf->chan.group;
8756 tmp->callgroup = conf->chan.callgroup;
8757 tmp->pickupgroup= conf->chan.pickupgroup;
8758 if (conf->chan.vars) {
8759 tmp->vars = conf->chan.vars;
8761 tmp->cid_rxgain = conf->chan.cid_rxgain;
8762 tmp->rxgain = conf->chan.rxgain;
8763 tmp->txgain = conf->chan.txgain;
8764 tmp->tonezone = conf->chan.tonezone;
8765 tmp->onhooktime = time(NULL);
8766 if (tmp->subs[SUB_REAL].dfd > -1) {
8767 set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
8768 if (tmp->dsp)
8769 ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
8770 update_conf(tmp);
8771 if (!here) {
8772 if ((chan_sig != SIG_BRI) && (chan_sig != SIG_BRI_PTMP) && (chan_sig != SIG_PRI) && (chan_sig != SIG_SS7))
8773 /* Hang it up to be sure it's good */
8774 dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
8776 ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
8777 #ifdef HAVE_PRI
8778 /* the dchannel is down so put the channel in alarm */
8779 if (tmp->pri && !pri_is_up(tmp->pri))
8780 tmp->inalarm = 1;
8781 #endif
8782 if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
8783 tmp->inalarm = 1;
8784 handle_alarms(tmp, res);
8788 tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
8789 tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
8790 tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
8791 tmp->sendcalleridafter = conf->chan.sendcalleridafter;
8792 if (!here) {
8793 tmp->locallyblocked = tmp->remotelyblocked = 0;
8794 if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_SS7))
8795 tmp->inservice = 0;
8796 else /* We default to in service on protocols that don't have a reset */
8797 tmp->inservice = 1;
8800 if (tmp && !here) {
8801 /* nothing on the iflist */
8802 if (!*wlist) {
8803 *wlist = tmp;
8804 tmp->prev = NULL;
8805 tmp->next = NULL;
8806 *wend = tmp;
8807 } else {
8808 /* at least one member on the iflist */
8809 struct dahdi_pvt *working = *wlist;
8811 /* check if we maybe have to put it on the begining */
8812 if (working->channel > tmp->channel) {
8813 tmp->next = *wlist;
8814 tmp->prev = NULL;
8815 (*wlist)->prev = tmp;
8816 *wlist = tmp;
8817 } else {
8818 /* go through all the members and put the member in the right place */
8819 while (working) {
8820 /* in the middle */
8821 if (working->next) {
8822 if (working->channel < tmp->channel && working->next->channel > tmp->channel) {
8823 tmp->next = working->next;
8824 tmp->prev = working;
8825 working->next->prev = tmp;
8826 working->next = tmp;
8827 break;
8829 } else {
8830 /* the last */
8831 if (working->channel < tmp->channel) {
8832 working->next = tmp;
8833 tmp->next = NULL;
8834 tmp->prev = working;
8835 *wend = tmp;
8836 break;
8839 working = working->next;
8844 return tmp;
8847 static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
8849 int res;
8850 struct dahdi_params par;
8852 /* First, check group matching */
8853 if (groupmatch) {
8854 if ((p->group & groupmatch) != groupmatch)
8855 return 0;
8856 *groupmatched = 1;
8858 /* Check to see if we have a channel match */
8859 if (channelmatch != -1) {
8860 if (p->channel != channelmatch)
8861 return 0;
8862 *channelmatched = 1;
8864 /* We're at least busy at this point */
8865 if (busy) {
8866 if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
8867 *busy = 1;
8869 /* If do not disturb, definitely not */
8870 if (p->dnd)
8871 return 0;
8872 /* If guard time, definitely not */
8873 if (p->guardtime && (time(NULL) < p->guardtime))
8874 return 0;
8876 if (p->locallyblocked || p->remotelyblocked)
8877 return 0;
8879 /* If no owner definitely available */
8880 if (!p->owner) {
8881 #ifdef HAVE_PRI
8882 /* Trust PRI */
8883 if (p->pri) {
8884 if (p->resetting || p->call)
8885 return 0;
8886 else
8887 return 1;
8889 #endif
8890 #ifdef HAVE_SS7
8891 /* Trust SS7 */
8892 if (p->ss7) {
8893 if (p->ss7call)
8894 return 0;
8895 else
8896 return 1;
8898 #endif
8899 if (!(p->radio || (p->oprmode < 0)))
8901 if (!p->sig || (p->sig == SIG_FXSLS))
8902 return 1;
8903 /* Check hook state */
8904 if (p->subs[SUB_REAL].dfd > -1)
8905 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
8906 else {
8907 /* Assume not off hook on CVRS */
8908 res = 0;
8909 par.rxisoffhook = 0;
8911 if (res) {
8912 ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
8913 } else if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
8914 /* When "onhook" that means no battery on the line, and thus
8915 it is out of service..., if it's on a TDM card... If it's a channel
8916 bank, there is no telling... */
8917 if (par.rxbits > -1)
8918 return 1;
8919 if (par.rxisoffhook)
8920 return 1;
8921 else
8922 return 0;
8923 } else if (par.rxisoffhook) {
8924 ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
8925 /* Not available when the other end is off hook */
8926 return 0;
8929 return 1;
8932 /* If it's not an FXO, forget about call wait */
8933 if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS))
8934 return 0;
8936 if (!p->callwaiting) {
8937 /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
8938 return 0;
8941 if (p->subs[SUB_CALLWAIT].dfd > -1) {
8942 /* If there is already a call waiting call, then we can't take a second one */
8943 return 0;
8946 if ((p->owner->_state != AST_STATE_UP) &&
8947 ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
8948 /* If the current call is not up, then don't allow the call */
8949 return 0;
8951 if ((p->subs[SUB_THREEWAY].owner) && (!p->subs[SUB_THREEWAY].inthreeway)) {
8952 /* Can't take a call wait when the three way calling hasn't been merged yet. */
8953 return 0;
8955 /* We're cool */
8956 return 1;
8959 static struct dahdi_pvt *chandup(struct dahdi_pvt *src)
8961 struct dahdi_pvt *p;
8962 struct dahdi_bufferinfo bi;
8963 int res;
8965 if ((p = ast_malloc(sizeof(*p)))) {
8966 memcpy(p, src, sizeof(struct dahdi_pvt));
8967 ast_mutex_init(&p->lock);
8968 p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
8969 /* Allocate a dahdi structure */
8970 if (p->subs[SUB_REAL].dfd < 0) {
8971 ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
8972 destroy_dahdi_pvt(&p);
8973 return NULL;
8975 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
8976 if (!res) {
8977 bi.txbufpolicy = src->buf_policy;
8978 bi.rxbufpolicy = src->buf_policy;
8979 bi.numbufs = src->buf_no;
8980 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
8981 if (res < 0) {
8982 ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
8984 } else
8985 ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
8987 p->destroy = 1;
8988 p->next = iflist;
8989 p->prev = NULL;
8990 iflist = p;
8991 if (iflist->next)
8992 iflist->next->prev = p;
8993 return p;
8997 #ifdef HAVE_PRI
8998 static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
9000 int x;
9001 if (backwards)
9002 x = pri->numchans;
9003 else
9004 x = 0;
9005 for (;;) {
9006 if (backwards && (x < 0))
9007 break;
9008 if (!backwards && (x >= pri->numchans))
9009 break;
9010 if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
9011 ast_debug(1, "Found empty available channel %d/%d\n",
9012 pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
9013 return x;
9015 if (backwards)
9016 x--;
9017 else
9018 x++;
9020 return -1;
9022 #endif
9024 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause)
9026 ast_group_t groupmatch = 0;
9027 int channelmatch = -1;
9028 int roundrobin = 0;
9029 int callwait = 0;
9030 int busy = 0;
9031 struct dahdi_pvt *p;
9032 struct ast_channel *tmp = NULL;
9033 char *dest=NULL;
9034 int x;
9035 char *s;
9036 char opt=0;
9037 int res=0, y=0;
9038 int backwards = 0;
9039 #ifdef HAVE_PRI
9040 int crv;
9041 int bearer = -1;
9042 int trunkgroup;
9043 struct dahdi_pri *pri=NULL;
9044 #endif
9045 struct dahdi_pvt *exitpvt, *start, *end;
9046 ast_mutex_t *lock;
9047 int channelmatched = 0;
9048 int groupmatched = 0;
9050 /* Assume we're locking the iflock */
9051 lock = &iflock;
9052 start = iflist;
9053 end = ifend;
9054 if (data) {
9055 dest = ast_strdupa((char *)data);
9056 } else {
9057 ast_log(LOG_WARNING, "Channel requested with no data\n");
9058 return NULL;
9060 if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
9061 /* Retrieve the group number */
9062 char *stringp=NULL;
9063 stringp=dest + 1;
9064 s = strsep(&stringp, "/");
9065 if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
9066 ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
9067 return NULL;
9069 groupmatch = ((ast_group_t) 1 << x);
9070 if (toupper(dest[0]) == 'G') {
9071 if (dest[0] == 'G') {
9072 backwards = 1;
9073 p = ifend;
9074 } else
9075 p = iflist;
9076 } else {
9077 if (dest[0] == 'R') {
9078 backwards = 1;
9079 p = round_robin[x]?round_robin[x]->prev:ifend;
9080 if (!p)
9081 p = ifend;
9082 } else {
9083 p = round_robin[x]?round_robin[x]->next:iflist;
9084 if (!p)
9085 p = iflist;
9087 roundrobin = 1;
9089 } else {
9090 char *stringp=NULL;
9091 stringp=dest;
9092 s = strsep(&stringp, "/");
9093 p = iflist;
9094 if (!strcasecmp(s, "pseudo")) {
9095 /* Special case for pseudo */
9096 x = CHAN_PSEUDO;
9097 channelmatch = x;
9099 #ifdef HAVE_PRI
9100 else if ((res = sscanf(s, "%d:%d%c%d", &trunkgroup, &crv, &opt, &y)) > 1) {
9101 if ((trunkgroup < 1) || (crv < 1)) {
9102 ast_log(LOG_WARNING, "Unable to determine trunk group and CRV for data %s\n", (char *)data);
9103 return NULL;
9105 res--;
9106 for (x = 0; x < NUM_SPANS; x++) {
9107 if (pris[x].trunkgroup == trunkgroup) {
9108 pri = pris + x;
9109 lock = &pri->lock;
9110 start = pri->crvs;
9111 end = pri->crvend;
9112 break;
9115 if (!pri) {
9116 ast_log(LOG_WARNING, "Unable to find trunk group %d\n", trunkgroup);
9117 return NULL;
9119 channelmatch = crv;
9120 p = pris[x].crvs;
9122 #endif
9123 else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
9124 ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
9125 return NULL;
9126 } else {
9127 channelmatch = x;
9130 /* Search for an unowned channel */
9131 ast_mutex_lock(lock);
9132 exitpvt = p;
9133 while (p && !tmp) {
9134 if (roundrobin)
9135 round_robin[x] = p;
9136 #if 0
9137 ast_verbose("name = %s, %d, %d, %d\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
9138 #endif
9140 if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
9141 ast_debug(1, "Using channel %d\n", p->channel);
9142 if (p->inalarm)
9143 goto next;
9145 callwait = (p->owner != NULL);
9146 #ifdef HAVE_PRI
9147 if (pri && (p->subs[SUB_REAL].dfd < 0)) {
9148 if (p->sig != SIG_FXSKS) {
9149 /* Gotta find an actual channel to use for this
9150 CRV if this isn't a callwait */
9151 bearer = pri_find_empty_chan(pri, 0);
9152 if (bearer < 0) {
9153 ast_log(LOG_NOTICE, "Out of bearer channels on span %d for call to CRV %d:%d\n", pri->span, trunkgroup, crv);
9154 p = NULL;
9155 break;
9157 pri_assign_bearer(p, pri, pri->pvts[bearer]);
9158 } else {
9159 if (alloc_sub(p, 0)) {
9160 ast_log(LOG_NOTICE, "Failed to allocate place holder pseudo channel!\n");
9161 p = NULL;
9162 break;
9163 } else
9164 ast_debug(1, "Allocated placeholder pseudo channel\n");
9166 p->pri = pri;
9169 #endif
9170 if (p->channel == CHAN_PSEUDO) {
9171 p = chandup(p);
9172 if (!p) {
9173 break;
9176 if (p->owner) {
9177 if (alloc_sub(p, SUB_CALLWAIT)) {
9178 p = NULL;
9179 break;
9182 p->outgoing = 1;
9183 tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
9184 #ifdef HAVE_PRI
9185 if (p->bearer) {
9186 /* Log owner to bearer channel, too */
9187 p->bearer->owner = tmp;
9189 #endif
9190 /* Make special notes */
9191 if (res > 1) {
9192 if (opt == 'c') {
9193 /* Confirm answer */
9194 p->confirmanswer = 1;
9195 } else if (opt == 'r') {
9196 /* Distinctive ring */
9197 if (res < 3)
9198 ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", (char *)data);
9199 else
9200 p->distinctivering = y;
9201 } else if (opt == 'd') {
9202 /* If this is an ISDN call, make it digital */
9203 p->digital = 1;
9204 if (tmp)
9205 tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
9206 } else {
9207 ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
9210 /* Note if the call is a call waiting call */
9211 if (tmp && callwait)
9212 tmp->cdrflags |= AST_CDR_CALLWAIT;
9213 break;
9215 next:
9216 if (backwards) {
9217 p = p->prev;
9218 if (!p)
9219 p = end;
9220 } else {
9221 p = p->next;
9222 if (!p)
9223 p = start;
9225 /* stop when you roll to the one that we started from */
9226 if (p == exitpvt)
9227 break;
9229 ast_mutex_unlock(lock);
9230 restart_monitor();
9231 if (callwait)
9232 *cause = AST_CAUSE_BUSY;
9233 else if (!tmp) {
9234 if (channelmatched) {
9235 if (busy)
9236 *cause = AST_CAUSE_BUSY;
9237 } else if (groupmatched) {
9238 *cause = AST_CAUSE_CONGESTION;
9242 return tmp;
9245 #if defined(HAVE_PRI) || defined(HAVE_SS7)
9246 static int dahdi_setlaw(int dfd, int law)
9248 return ioctl(dfd, DAHDI_SETLAW, &law);
9250 #endif
9252 #ifdef HAVE_SS7
9254 static int ss7_find_cic(struct dahdi_ss7 *linkset, int cic, unsigned int dpc)
9256 int i;
9257 int winner = -1;
9258 for (i = 0; i < linkset->numchans; i++) {
9259 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && linkset->pvts[i]->cic == cic)) {
9260 winner = i;
9261 break;
9264 return winner;
9267 static void ss7_handle_cqm(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
9269 unsigned char status[32];
9270 struct dahdi_pvt *p = NULL;
9271 int i, offset;
9273 for (i = 0; i < linkset->numchans; i++) {
9274 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
9275 p = linkset->pvts[i];
9276 offset = p->cic - startcic;
9277 status[offset] = 0;
9278 if (p->locallyblocked)
9279 status[offset] |= (1 << 0) | (1 << 4);
9280 if (p->remotelyblocked)
9281 status[offset] |= (1 << 1) | (1 << 5);
9282 if (p->ss7call) {
9283 if (p->outgoing)
9284 status[offset] |= (1 << 3);
9285 else
9286 status[offset] |= (1 << 2);
9287 } else
9288 status[offset] |= 0x3 << 2;
9292 if (p)
9293 isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
9294 else
9295 ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
9299 static inline void ss7_block_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
9301 int i;
9303 for (i = 0; i < linkset->numchans; i++) {
9304 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
9305 if (state) {
9306 if (state[i])
9307 linkset->pvts[i]->remotelyblocked = block;
9308 } else
9309 linkset->pvts[i]->remotelyblocked = block;
9314 static void ss7_inservice(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
9316 int i;
9318 for (i = 0; i < linkset->numchans; i++) {
9319 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
9320 linkset->pvts[i]->inservice = 1;
9324 static void ss7_reset_linkset(struct dahdi_ss7 *linkset)
9326 int i, startcic = -1, endcic, dpc;
9328 if (linkset->numchans <= 0)
9329 return;
9331 startcic = linkset->pvts[0]->cic;
9332 /* DB: CIC's DPC fix */
9333 dpc = linkset->pvts[0]->dpc;
9335 for (i = 0; i < linkset->numchans; i++) {
9336 if (linkset->pvts[i+1] && linkset->pvts[i+1]->dpc == dpc && ((linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) && (linkset->pvts[i]->cic - startcic < 31)) {
9337 continue;
9338 } else {
9339 endcic = linkset->pvts[i]->cic;
9340 ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
9341 isup_grs(linkset->ss7, startcic, endcic, dpc);
9343 /* DB: CIC's DPC fix */
9344 if (linkset->pvts[i+1]) {
9345 startcic = linkset->pvts[i+1]->cic;
9346 dpc = linkset->pvts[i+1]->dpc;
9352 static void dahdi_loopback(struct dahdi_pvt *p, int enable)
9354 if (p->loopedback != enable) {
9355 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
9356 ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel, strerror(errno));
9357 return;
9359 p->loopedback = enable;
9363 /* XXX: This function is assumed to be called with the private channel lock and linkset lock held */
9364 static void ss7_start_call(struct dahdi_pvt *p, struct dahdi_ss7 *linkset)
9366 struct ss7 *ss7 = linkset->ss7;
9367 int res;
9368 int law = 1;
9369 struct ast_channel *c;
9370 char tmp[256];
9372 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
9373 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, law, strerror(errno));
9375 if (linkset->type == SS7_ITU)
9376 law = DAHDI_LAW_ALAW;
9377 else
9378 law = DAHDI_LAW_MULAW;
9380 res = dahdi_setlaw(p->subs[SUB_REAL].dfd, law);
9381 if (res < 0)
9382 ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel);
9384 if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
9385 p->proceeding = 1;
9386 isup_acm(ss7, p->ss7call);
9389 ast_mutex_unlock(&linkset->lock);
9390 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, law, 0);
9392 if (!c) {
9393 ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
9394 /* Holding this lock is assumed entering the function */
9395 ast_mutex_lock(&linkset->lock);
9396 return;
9397 } else
9398 ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
9400 dahdi_enable_ec(p);
9402 /* We only reference these variables in the context of the ss7_linkset function
9403 * when receiving either and IAM or a COT message. Since they are only accessed
9404 * from this context, we should be safe to unlock around them */
9406 ast_mutex_unlock(&p->lock);
9408 if (!ast_strlen_zero(p->charge_number)) {
9409 pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
9410 /* Clear this after we set it */
9411 p->charge_number[0] = 0;
9413 if (!ast_strlen_zero(p->gen_add_number)) {
9414 pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
9415 /* Clear this after we set it */
9416 p->gen_add_number[0] = 0;
9418 if (!ast_strlen_zero(p->jip_number)) {
9419 pbx_builtin_setvar_helper(c, "SS7_JIP", p->jip_number);
9420 /* Clear this after we set it */
9421 p->jip_number[0] = 0;
9423 if (!ast_strlen_zero(p->gen_dig_number)) {
9424 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGITS", p->gen_dig_number);
9425 /* Clear this after we set it */
9426 p->gen_dig_number[0] = 0;
9428 if (!ast_strlen_zero(p->orig_called_num)) {
9429 pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
9430 /* Clear this after we set it */
9431 p->orig_called_num[0] = 0;
9434 snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
9435 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
9436 /* Clear this after we set it */
9437 p->gen_dig_type = 0;
9439 snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_scheme);
9440 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGSCHEME", tmp);
9441 /* Clear this after we set it */
9442 p->gen_dig_scheme = 0;
9444 if (!ast_strlen_zero(p->lspi_ident)) {
9445 pbx_builtin_setvar_helper(c, "SS7_LSPI_IDENT", p->lspi_ident);
9446 /* Clear this after we set it */
9447 p->lspi_ident[0] = 0;
9450 snprintf(tmp, sizeof(tmp), "%d", p->call_ref_ident);
9451 pbx_builtin_setvar_helper(c, "SS7_CALLREF_IDENT", tmp);
9452 /* Clear this after we set it */
9453 p->call_ref_ident = 0;
9455 snprintf(tmp, sizeof(tmp), "%d", p->call_ref_pc);
9456 pbx_builtin_setvar_helper(c, "SS7_CALLREF_PC", tmp);
9457 /* Clear this after we set it */
9458 p->call_ref_pc = 0;
9460 snprintf(tmp, sizeof(tmp), "%d", p->calling_party_cat);
9461 pbx_builtin_setvar_helper(c, "SS7_CALLING_PARTY_CATEGORY", tmp);
9462 /* Clear this after we set it */
9463 p->calling_party_cat = 0;
9465 if (!ast_strlen_zero(p->redirecting_num)) {
9466 pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
9467 /* Clear this after we set it */
9468 p->redirecting_num[0] = 0;
9470 if (!ast_strlen_zero(p->generic_name)) {
9471 pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
9472 /* Clear this after we set it */
9473 p->generic_name[0] = 0;
9476 ast_mutex_lock(&p->lock);
9477 ast_mutex_lock(&linkset->lock);
9480 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct dahdi_ss7 *ss7, const char *number, const unsigned nai)
9482 switch (nai) {
9483 case SS7_NAI_INTERNATIONAL:
9484 snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
9485 break;
9486 case SS7_NAI_NATIONAL:
9487 snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
9488 break;
9489 case SS7_NAI_SUBSCRIBER:
9490 snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
9491 break;
9492 case SS7_NAI_UNKNOWN:
9493 snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
9494 break;
9495 default:
9496 snprintf(buf, size, "%s", number);
9497 break;
9500 static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
9502 return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
9505 static void *ss7_linkset(void *data)
9507 int res, i;
9508 struct timeval *next = NULL, tv;
9509 struct dahdi_ss7 *linkset = (struct dahdi_ss7 *) data;
9510 struct ss7 *ss7 = linkset->ss7;
9511 ss7_event *e = NULL;
9512 struct dahdi_pvt *p;
9513 int chanpos;
9514 struct pollfd pollers[NUM_DCHANS];
9515 int cic;
9516 unsigned int dpc;
9517 int nextms = 0;
9519 ss7_start(ss7);
9521 while(1) {
9522 ast_mutex_lock(&linkset->lock);
9523 if ((next = ss7_schedule_next(ss7))) {
9524 tv = ast_tvnow();
9525 tv.tv_sec = next->tv_sec - tv.tv_sec;
9526 tv.tv_usec = next->tv_usec - tv.tv_usec;
9527 if (tv.tv_usec < 0) {
9528 tv.tv_usec += 1000000;
9529 tv.tv_sec -= 1;
9531 if (tv.tv_sec < 0) {
9532 tv.tv_sec = 0;
9533 tv.tv_usec = 0;
9535 nextms = tv.tv_sec * 1000;
9536 nextms += tv.tv_usec / 1000;
9538 ast_mutex_unlock(&linkset->lock);
9540 for (i = 0; i < linkset->numsigchans; i++) {
9541 pollers[i].fd = linkset->fds[i];
9542 pollers[i].events = ss7_pollflags(ss7, linkset->fds[i]);
9543 pollers[i].revents = 0;
9546 res = poll(pollers, linkset->numsigchans, nextms);
9547 if ((res < 0) && (errno != EINTR)) {
9548 ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
9549 } else if (!res) {
9550 ast_mutex_lock(&linkset->lock);
9551 ss7_schedule_run(ss7);
9552 ast_mutex_unlock(&linkset->lock);
9553 continue;
9556 ast_mutex_lock(&linkset->lock);
9557 for (i = 0; i < linkset->numsigchans; i++) {
9558 if (pollers[i].revents & POLLPRI) {
9559 int x;
9560 if (ioctl(pollers[i].fd, DAHDI_GETEVENT, &x)) {
9561 ast_log(LOG_ERROR, "Error in exception retrieval!\n");
9563 switch (x) {
9564 case DAHDI_EVENT_OVERRUN:
9565 ast_debug(1, "Overrun detected!\n");
9566 break;
9567 case DAHDI_EVENT_BADFCS:
9568 ast_debug(1, "Bad FCS\n");
9569 break;
9570 case DAHDI_EVENT_ABORT:
9571 ast_debug(1, "HDLC Abort\n");
9572 break;
9573 case DAHDI_EVENT_ALARM:
9574 ast_log(LOG_ERROR, "Alarm on link!\n");
9575 linkset->linkstate[i] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
9576 linkset->linkstate[i] &= ~LINKSTATE_UP;
9577 ss7_link_alarm(ss7, pollers[i].fd);
9578 break;
9579 case DAHDI_EVENT_NOALARM:
9580 ast_log(LOG_ERROR, "Alarm cleared on link\n");
9581 linkset->linkstate[i] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
9582 linkset->linkstate[i] |= LINKSTATE_STARTING;
9583 ss7_link_noalarm(ss7, pollers[i].fd);
9584 break;
9585 default:
9586 ast_log(LOG_ERROR, "Got exception %d!\n", x);
9587 break;
9591 if (pollers[i].revents & POLLIN) {
9592 ast_mutex_lock(&linkset->lock);
9593 res = ss7_read(ss7, pollers[i].fd);
9594 ast_mutex_unlock(&linkset->lock);
9597 if (pollers[i].revents & POLLOUT) {
9598 ast_mutex_lock(&linkset->lock);
9599 res = ss7_write(ss7, pollers[i].fd);
9600 ast_mutex_unlock(&linkset->lock);
9601 if (res < 0) {
9602 ast_debug(1, "Error in write %s\n", strerror(errno));
9607 while ((e = ss7_check_event(ss7))) {
9608 switch (e->e) {
9609 case SS7_EVENT_UP:
9610 if (linkset->state != LINKSET_STATE_UP) {
9611 ast_verbose("--- SS7 Up ---\n");
9612 ss7_reset_linkset(linkset);
9614 linkset->state = LINKSET_STATE_UP;
9615 break;
9616 case SS7_EVENT_DOWN:
9617 ast_verbose("--- SS7 Down ---\n");
9618 linkset->state = LINKSET_STATE_DOWN;
9619 for (i = 0; i < linkset->numchans; i++) {
9620 struct dahdi_pvt *p = linkset->pvts[i];
9621 if (p)
9622 p->inalarm = 1;
9624 break;
9625 case MTP2_LINK_UP:
9626 ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
9627 break;
9628 case MTP2_LINK_DOWN:
9629 ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
9630 break;
9631 case ISUP_EVENT_CPG:
9632 chanpos = ss7_find_cic(linkset, e->cpg.cic, e->cpg.opc);
9633 if (chanpos < 0) {
9634 ast_log(LOG_WARNING, "CPG on unconfigured CIC %d\n", e->cpg.cic);
9635 break;
9637 p = linkset->pvts[chanpos];
9638 ast_mutex_lock(&p->lock);
9639 switch (e->cpg.event) {
9640 case CPG_EVENT_ALERTING:
9641 p->alerting = 1;
9642 p->subs[SUB_REAL].needringing = 1;
9643 break;
9644 case CPG_EVENT_PROGRESS:
9645 case CPG_EVENT_INBANDINFO:
9647 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
9648 ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
9649 dahdi_queue_frame(p, &f, linkset);
9650 p->progress = 1;
9651 if (p->dsp && p->dsp_features) {
9652 ast_dsp_set_features(p->dsp, p->dsp_features);
9653 p->dsp_features = 0;
9656 break;
9657 default:
9658 ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
9661 ast_mutex_unlock(&p->lock);
9662 break;
9663 case ISUP_EVENT_RSC:
9664 ast_verbose("Resetting CIC %d\n", e->rsc.cic);
9665 chanpos = ss7_find_cic(linkset, e->rsc.cic, e->rsc.opc);
9666 if (chanpos < 0) {
9667 ast_log(LOG_WARNING, "RSC on unconfigured CIC %d\n", e->rsc.cic);
9668 break;
9670 p = linkset->pvts[chanpos];
9671 ast_mutex_lock(&p->lock);
9672 p->inservice = 1;
9673 p->remotelyblocked = 0;
9674 dpc = p->dpc;
9675 isup_set_call_dpc(e->rsc.call, dpc);
9676 if (p->ss7call)
9677 p->ss7call = NULL;
9678 if (p->owner)
9679 p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
9680 ast_mutex_unlock(&p->lock);
9681 isup_rlc(ss7, e->rsc.call);
9682 break;
9683 case ISUP_EVENT_GRS:
9684 ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
9685 chanpos = ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
9686 if (chanpos < 0) {
9687 ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic);
9688 break;
9690 p = linkset->pvts[chanpos];
9691 isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
9692 ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
9693 break;
9694 case ISUP_EVENT_CQM:
9695 ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
9696 ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
9697 break;
9698 case ISUP_EVENT_GRA:
9699 ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
9700 ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
9701 ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
9702 break;
9703 case ISUP_EVENT_IAM:
9704 ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
9705 chanpos = ss7_find_cic(linkset, e->iam.cic, e->iam.opc);
9706 if (chanpos < 0) {
9707 ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
9708 isup_rel(ss7, e->iam.call, -1);
9709 break;
9711 p = linkset->pvts[chanpos];
9712 ast_mutex_lock(&p->lock);
9713 if (p->owner) {
9714 if (p->ss7call == e->iam.call) {
9715 ast_mutex_unlock(&p->lock);
9716 ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic);
9717 break;
9718 } else {
9719 ast_mutex_unlock(&p->lock);
9720 ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic);
9721 break;
9725 dpc = p->dpc;
9726 p->ss7call = e->iam.call;
9727 isup_set_call_dpc(p->ss7call, dpc);
9729 if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
9730 ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
9731 p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
9732 } else
9733 p->cid_num[0] = 0;
9735 if (p->immediate) {
9736 p->exten[0] = 's';
9737 p->exten[1] = '\0';
9738 } else if (!ast_strlen_zero(e->iam.called_party_num)) {
9739 char *st;
9740 ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
9741 st = strchr(p->exten, '#');
9742 if (st)
9743 *st = '\0';
9744 } else
9745 p->exten[0] = '\0';
9747 p->cid_ani[0] = '\0';
9748 if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
9749 ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
9750 else
9751 p->cid_name[0] = '\0';
9753 p->cid_ani2 = e->iam.oli_ani2;
9754 p->cid_ton = 0;
9755 ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
9756 ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
9757 p->gen_add_type = e->iam.gen_add_type;
9758 p->gen_add_nai = e->iam.gen_add_nai;
9759 p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
9760 p->gen_add_num_plan = e->iam.gen_add_num_plan;
9761 ast_copy_string(p->gen_dig_number, e->iam.gen_dig_number, sizeof(p->gen_dig_number));
9762 p->gen_dig_type = e->iam.gen_dig_type;
9763 p->gen_dig_scheme = e->iam.gen_dig_scheme;
9764 ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
9765 ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
9766 ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
9767 ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
9768 p->calling_party_cat = e->iam.calling_party_cat;
9770 /* Set DNID */
9771 if (!ast_strlen_zero(e->iam.called_party_num))
9772 ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai);
9774 if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
9776 if (e->iam.cot_check_required) {
9777 dahdi_loopback(p, 1);
9778 } else
9779 ss7_start_call(p, linkset);
9780 } else {
9781 ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
9782 isup_rel(ss7, e->iam.call, -1);
9784 ast_mutex_unlock(&p->lock);
9785 break;
9786 case ISUP_EVENT_COT:
9787 chanpos = ss7_find_cic(linkset, e->cot.cic, e->cot.opc);
9788 if (chanpos < 0) {
9789 ast_log(LOG_WARNING, "COT on unconfigured CIC %d\n", e->cot.cic);
9790 isup_rel(ss7, e->cot.call, -1);
9791 break;
9793 p = linkset->pvts[chanpos];
9795 ast_mutex_lock(&p->lock);
9797 if (p->loopedback) {
9798 dahdi_loopback(p, 0);
9799 ss7_start_call(p, linkset);
9802 ast_mutex_unlock(&p->lock);
9804 break;
9805 case ISUP_EVENT_CCR:
9806 ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
9807 chanpos = ss7_find_cic(linkset, e->ccr.cic, e->ccr.opc);
9808 if (chanpos < 0) {
9809 ast_log(LOG_WARNING, "CCR on unconfigured CIC %d\n", e->ccr.cic);
9810 break;
9813 p = linkset->pvts[chanpos];
9815 ast_mutex_lock(&p->lock);
9816 dahdi_loopback(p, 1);
9817 ast_mutex_unlock(&p->lock);
9819 isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
9820 break;
9821 case ISUP_EVENT_CVT:
9822 ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
9823 chanpos = ss7_find_cic(linkset, e->cvt.cic, e->cvt.opc);
9824 if (chanpos < 0) {
9825 ast_log(LOG_WARNING, "CVT on unconfigured CIC %d\n", e->cvt.cic);
9826 break;
9829 p = linkset->pvts[chanpos];
9831 ast_mutex_lock(&p->lock);
9832 dahdi_loopback(p, 1);
9833 ast_mutex_unlock(&p->lock);
9835 isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
9836 break;
9837 case ISUP_EVENT_REL:
9838 chanpos = ss7_find_cic(linkset, e->rel.cic, e->rel.opc);
9839 if (chanpos < 0) {
9840 ast_log(LOG_WARNING, "REL on unconfigured CIC %d\n", e->rel.cic);
9841 break;
9843 p = linkset->pvts[chanpos];
9844 ast_mutex_lock(&p->lock);
9845 if (p->owner) {
9846 p->owner->hangupcause = e->rel.cause;
9847 p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
9848 } else if (!p->restartpending)
9849 ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
9851 /* End the loopback if we have one */
9852 dahdi_loopback(p, 0);
9854 isup_rlc(ss7, e->rel.call);
9855 p->ss7call = NULL;
9857 ast_mutex_unlock(&p->lock);
9858 break;
9859 case ISUP_EVENT_ACM:
9860 chanpos = ss7_find_cic(linkset, e->acm.cic, e->acm.opc);
9861 if (chanpos < 0) {
9862 ast_log(LOG_WARNING, "ACM on unconfigured CIC %d\n", e->acm.cic);
9863 isup_rel(ss7, e->acm.call, -1);
9864 break;
9865 } else {
9866 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
9868 p = linkset->pvts[chanpos];
9870 ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
9872 if (e->acm.call_ref_ident > 0) {
9873 p->rlt = 1; /* Setting it but not using it here*/
9876 ast_mutex_lock(&p->lock);
9877 dahdi_queue_frame(p, &f, linkset);
9878 p->proceeding = 1;
9879 /* Send alerting if subscriber is free */
9880 if (e->acm.called_party_status_ind == 1) {
9881 p->alerting = 1;
9882 p->subs[SUB_REAL].needringing = 1;
9884 ast_mutex_unlock(&p->lock);
9886 break;
9887 case ISUP_EVENT_CGB:
9888 chanpos = ss7_find_cic(linkset, e->cgb.startcic, e->cgb.opc);
9889 if (chanpos < 0) {
9890 ast_log(LOG_WARNING, "CGB on unconfigured CIC %d\n", e->cgb.startcic);
9891 break;
9893 p = linkset->pvts[chanpos];
9894 ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
9895 isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
9896 break;
9897 case ISUP_EVENT_CGU:
9898 chanpos = ss7_find_cic(linkset, e->cgu.startcic, e->cgu.opc);
9899 if (chanpos < 0) {
9900 ast_log(LOG_WARNING, "CGU on unconfigured CIC %d\n", e->cgu.startcic);
9901 break;
9903 p = linkset->pvts[chanpos];
9904 ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
9905 isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
9906 break;
9907 case ISUP_EVENT_UCIC:
9908 chanpos = ss7_find_cic(linkset, e->ucic.cic, e->ucic.opc);
9909 if (chanpos < 0) {
9910 ast_log(LOG_WARNING, "UCIC on unconfigured CIC %d\n", e->ucic.cic);
9911 break;
9913 p = linkset->pvts[chanpos];
9914 ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
9915 ast_mutex_lock(&p->lock);
9916 p->remotelyblocked = 1;
9917 p->inservice = 0;
9918 ast_mutex_unlock(&p->lock); //doesn't require a SS7 acknowledgement
9919 break;
9920 case ISUP_EVENT_BLO:
9921 chanpos = ss7_find_cic(linkset, e->blo.cic, e->blo.opc);
9922 if (chanpos < 0) {
9923 ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
9924 break;
9926 p = linkset->pvts[chanpos];
9927 ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
9928 ast_mutex_lock(&p->lock);
9929 p->remotelyblocked = 1;
9930 ast_mutex_unlock(&p->lock);
9931 isup_bla(linkset->ss7, e->blo.cic, p->dpc);
9932 break;
9933 case ISUP_EVENT_BLA:
9934 chanpos = ss7_find_cic(linkset, e->bla.cic, e->bla.opc);
9935 if (chanpos < 0) {
9936 ast_log(LOG_WARNING, "BLA on unconfigured CIC %d\n", e->bla.cic);
9937 break;
9939 ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
9940 p = linkset->pvts[chanpos];
9941 ast_mutex_lock(&p->lock);
9942 p->locallyblocked = 1;
9943 ast_mutex_unlock(&p->lock);
9944 break;
9945 case ISUP_EVENT_UBL:
9946 chanpos = ss7_find_cic(linkset, e->ubl.cic, e->ubl.opc);
9947 if (chanpos < 0) {
9948 ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
9949 break;
9951 p = linkset->pvts[chanpos];
9952 ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
9953 ast_mutex_lock(&p->lock);
9954 p->remotelyblocked = 0;
9955 ast_mutex_unlock(&p->lock);
9956 isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
9957 break;
9958 case ISUP_EVENT_UBA:
9959 chanpos = ss7_find_cic(linkset, e->uba.cic, e->uba.opc);
9960 if (chanpos < 0) {
9961 ast_log(LOG_WARNING, "UBA on unconfigured CIC %d\n", e->uba.cic);
9962 break;
9964 p = linkset->pvts[chanpos];
9965 ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
9966 ast_mutex_lock(&p->lock);
9967 p->locallyblocked = 0;
9968 ast_mutex_unlock(&p->lock);
9969 break;
9970 case ISUP_EVENT_CON:
9971 case ISUP_EVENT_ANM:
9972 if (e->e == ISUP_EVENT_CON)
9973 cic = e->con.cic;
9974 else
9975 cic = e->anm.cic;
9977 chanpos = ss7_find_cic(linkset, cic, (e->e == ISUP_EVENT_ANM) ? e->anm.opc : e->con.opc);
9978 if (chanpos < 0) {
9979 ast_log(LOG_WARNING, "ANM/CON on unconfigured CIC %d\n", cic);
9980 isup_rel(ss7, (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call, -1);
9981 break;
9982 } else {
9983 p = linkset->pvts[chanpos];
9984 ast_mutex_lock(&p->lock);
9985 p->subs[SUB_REAL].needanswer = 1;
9986 if (p->dsp && p->dsp_features) {
9987 ast_dsp_set_features(p->dsp, p->dsp_features);
9988 p->dsp_features = 0;
9990 dahdi_enable_ec(p);
9991 ast_mutex_unlock(&p->lock);
9993 break;
9994 case ISUP_EVENT_RLC:
9995 chanpos = ss7_find_cic(linkset, e->rlc.cic, e->rlc.opc);
9996 if (chanpos < 0) {
9997 ast_log(LOG_WARNING, "RLC on unconfigured CIC %d\n", e->rlc.cic);
9998 break;
9999 } else {
10000 p = linkset->pvts[chanpos];
10001 ast_mutex_lock(&p->lock);
10002 if (p->alreadyhungup)
10003 p->ss7call = NULL;
10004 else
10005 ast_log(LOG_NOTICE, "Received RLC out and we haven't sent REL. Ignoring.\n");
10006 ast_mutex_unlock(&p->lock);
10008 break;
10009 case ISUP_EVENT_FAA:
10010 chanpos = ss7_find_cic(linkset, e->faa.cic, e->faa.opc);
10011 if (chanpos < 0) {
10012 ast_log(LOG_WARNING, "FAA on unconfigured CIC %d\n", e->faa.cic);
10013 break;
10014 } else {
10015 p = linkset->pvts[chanpos];
10016 ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
10017 ast_mutex_lock(&p->lock);
10018 if (p->alreadyhungup){
10019 p->ss7call = NULL;
10020 ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR. Ignoring.\n");
10022 ast_mutex_unlock(&p->lock);
10024 break;
10025 default:
10026 ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
10027 break;
10030 ast_mutex_unlock(&linkset->lock);
10033 return 0;
10036 static void dahdi_ss7_message(struct ss7 *ss7, char *s)
10038 #if 0
10039 int i;
10041 for (i = 0; i < NUM_SPANS; i++)
10042 if (linksets[i].ss7 == ss7)
10043 break;
10045 ast_verbose("[%d] %s", i+1, s);
10046 #else
10047 ast_verbose("%s", s);
10048 #endif
10051 static void dahdi_ss7_error(struct ss7 *ss7, char *s)
10053 #if 0
10054 int i;
10056 for (i = 0; i < NUM_SPANS; i++)
10057 if (linksets[i].ss7 == ss7)
10058 break;
10060 #else
10061 ast_log(LOG_ERROR, "%s", s);
10062 #endif
10065 #endif /* HAVE_SS7 */
10067 #ifdef HAVE_PRI
10068 static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
10070 struct dahdi_pvt *p;
10071 p = pri->crvs;
10072 while (p) {
10073 if (p->channel == crv)
10074 return p;
10075 p = p->next;
10077 return NULL;
10081 static int pri_find_principle(struct dahdi_pri *pri, int channel)
10083 int x;
10084 int span = PRI_SPAN(channel);
10085 int spanfd;
10086 struct dahdi_params param;
10087 int principle = -1;
10088 int explicit = PRI_EXPLICIT(channel);
10089 channel = PRI_CHANNEL(channel);
10091 if (!explicit) {
10092 spanfd = pri_active_dchan_fd(pri);
10093 if (ioctl(spanfd, DAHDI_GET_PARAMS, &param))
10094 return -1;
10095 span = pris[param.spanno - 1].prilogicalspan;
10098 for (x = 0; x < pri->numchans; x++) {
10099 if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
10100 principle = x;
10101 break;
10105 return principle;
10108 static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c)
10110 int x;
10111 struct dahdi_pvt *crv;
10112 if (!c) {
10113 if (principle < 0)
10114 return -1;
10115 return principle;
10117 if ((principle > -1) &&
10118 (principle < pri->numchans) &&
10119 (pri->pvts[principle]) &&
10120 (pri->pvts[principle]->call == c))
10121 return principle;
10122 /* First, check for other bearers */
10123 for (x = 0; x < pri->numchans; x++) {
10124 if (!pri->pvts[x])
10125 continue;
10126 if (pri->pvts[x]->call == c) {
10127 /* Found our call */
10128 if (principle != x) {
10129 struct dahdi_pvt *new = pri->pvts[principle], *old = pri->pvts[x];
10131 ast_verb(3, "Moving call from channel %d to channel %d\n",
10132 old->channel, new->channel);
10133 if (new->owner) {
10134 ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
10135 old->channel, new->channel, new->channel);
10136 return -1;
10138 /* Fix it all up now */
10139 new->owner = old->owner;
10140 old->owner = NULL;
10141 if (new->owner) {
10142 ast_string_field_build(new->owner, name,
10143 "DAHDI/%d:%d-%d", pri->trunkgroup,
10144 new->channel, 1);
10145 new->owner->tech_pvt = new;
10146 ast_channel_set_fd(new->owner, 0, new->subs[SUB_REAL].dfd);
10147 new->subs[SUB_REAL].owner = old->subs[SUB_REAL].owner;
10148 old->subs[SUB_REAL].owner = NULL;
10149 } else
10150 ast_log(LOG_WARNING, "Whoa, there's no owner, and we're having to fix up channel %d to channel %d\n", old->channel, new->channel);
10151 new->call = old->call;
10152 old->call = NULL;
10154 /* Copy any DSP that may be present */
10155 new->dsp = old->dsp;
10156 new->dsp_features = old->dsp_features;
10157 old->dsp = NULL;
10158 old->dsp_features = 0;
10160 return principle;
10163 /* Now check for a CRV with no bearer */
10164 crv = pri->crvs;
10165 while (crv) {
10166 if (crv->call == c) {
10167 /* This is our match... Perform some basic checks */
10168 if (crv->bearer)
10169 ast_log(LOG_WARNING, "Trying to fix up call which already has a bearer which isn't the one we think it is\n");
10170 else if (pri->pvts[principle]->owner)
10171 ast_log(LOG_WARNING, "Tring to fix up a call to a bearer which already has an owner!\n");
10172 else {
10173 /* Looks good. Drop the pseudo channel now, clear up the assignment, and
10174 wakeup the potential sleeper */
10175 dahdi_close_sub(crv, SUB_REAL);
10176 pri->pvts[principle]->call = crv->call;
10177 pri_assign_bearer(crv, pri, pri->pvts[principle]);
10178 ast_debug(1, "Assigning bearer %d/%d to CRV %d:%d\n",
10179 pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
10180 pri->trunkgroup, crv->channel);
10181 wakeup_sub(crv, SUB_REAL, pri);
10183 return principle;
10185 crv = crv->next;
10187 ast_log(LOG_WARNING, "Call specified, but not found?\n");
10188 return -1;
10191 static void *do_idle_thread(void *vchan)
10193 struct ast_channel *chan = vchan;
10194 struct dahdi_pvt *pvt = chan->tech_pvt;
10195 struct ast_frame *f;
10196 char ex[80];
10197 /* Wait up to 30 seconds for an answer */
10198 int newms, ms = 30000;
10199 ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
10200 snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
10201 if (ast_call(chan, ex, 0)) {
10202 ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", chan->name, ex);
10203 ast_hangup(chan);
10204 return NULL;
10206 while ((newms = ast_waitfor(chan, ms)) > 0) {
10207 f = ast_read(chan);
10208 if (!f) {
10209 /* Got hangup */
10210 break;
10212 if (f->frametype == AST_FRAME_CONTROL) {
10213 switch (f->subclass) {
10214 case AST_CONTROL_ANSWER:
10215 /* Launch the PBX */
10216 ast_copy_string(chan->exten, pvt->pri->idleext, sizeof(chan->exten));
10217 ast_copy_string(chan->context, pvt->pri->idlecontext, sizeof(chan->context));
10218 chan->priority = 1;
10219 ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", chan->name, chan->exten, chan->context);
10220 ast_pbx_run(chan);
10221 /* It's already hungup, return immediately */
10222 return NULL;
10223 case AST_CONTROL_BUSY:
10224 ast_verb(4, "Idle channel '%s' busy, waiting...\n", chan->name);
10225 break;
10226 case AST_CONTROL_CONGESTION:
10227 ast_verb(4, "Idle channel '%s' congested, waiting...\n", chan->name);
10228 break;
10231 ast_frfree(f);
10232 ms = newms;
10234 /* Hangup the channel since nothing happend */
10235 ast_hangup(chan);
10236 return NULL;
10239 #ifndef PRI_RESTART
10240 #error "Upgrade your libpri"
10241 #endif
10242 static void dahdi_pri_message(struct pri *pri, char *s)
10244 int x, y;
10245 int dchan = -1, span = -1;
10246 int dchancount = 0;
10248 if (pri) {
10249 for (x = 0; x < NUM_SPANS; x++) {
10250 for (y = 0; y < NUM_DCHANS; y++) {
10251 if (pris[x].dchans[y])
10252 dchancount++;
10254 if (pris[x].dchans[y] == pri)
10255 dchan = y;
10257 if (dchan >= 0) {
10258 span = x;
10259 break;
10261 dchancount = 0;
10263 if (dchancount > 1 && (span > -1))
10264 ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
10265 else
10266 ast_verbose("%s", s);
10267 } else
10268 ast_verbose("%s", s);
10270 ast_mutex_lock(&pridebugfdlock);
10272 if (pridebugfd >= 0)
10273 write(pridebugfd, s, strlen(s));
10275 ast_mutex_unlock(&pridebugfdlock);
10278 static void dahdi_pri_error(struct pri *pri, char *s)
10280 int x, y;
10281 int dchan = -1, span = -1;
10282 int dchancount = 0;
10284 if (pri) {
10285 for (x = 0; x < NUM_SPANS; x++) {
10286 for (y = 0; y < NUM_DCHANS; y++) {
10287 if (pris[x].dchans[y])
10288 dchancount++;
10290 if (pris[x].dchans[y] == pri)
10291 dchan = y;
10293 if (dchan >= 0) {
10294 span = x;
10295 break;
10297 dchancount = 0;
10299 if ((dchancount > 1) && (span > -1))
10300 ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
10301 else
10302 ast_log(LOG_ERROR, "%s", s);
10303 } else
10304 ast_log(LOG_ERROR, "%s", s);
10306 ast_mutex_lock(&pridebugfdlock);
10308 if (pridebugfd >= 0)
10309 write(pridebugfd, s, strlen(s));
10311 ast_mutex_unlock(&pridebugfdlock);
10314 static int pri_check_restart(struct dahdi_pri *pri)
10316 do {
10317 pri->resetpos++;
10318 } while ((pri->resetpos < pri->numchans) &&
10319 (!pri->pvts[pri->resetpos] ||
10320 pri->pvts[pri->resetpos]->call ||
10321 pri->pvts[pri->resetpos]->resetting));
10322 if (pri->resetpos < pri->numchans) {
10323 /* Mark the channel as resetting and restart it */
10324 pri->pvts[pri->resetpos]->resetting = 1;
10325 pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
10326 } else {
10327 pri->resetting = 0;
10328 time(&pri->lastreset);
10330 return 0;
10333 static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri)
10335 int x;
10336 int redo;
10337 ast_mutex_unlock(&pri->lock);
10338 ast_mutex_lock(&p->lock);
10339 do {
10340 redo = 0;
10341 for (x = 0; x < 3; x++) {
10342 while (p->subs[x].owner && ast_channel_trylock(p->subs[x].owner)) {
10343 redo++;
10344 DEADLOCK_AVOIDANCE(&p->lock);
10346 if (p->subs[x].owner) {
10347 ast_queue_hangup_with_cause(p->subs[x].owner, AST_CAUSE_PRE_EMPTED);
10348 ast_channel_unlock(p->subs[x].owner);
10351 } while (redo);
10352 ast_mutex_unlock(&p->lock);
10353 ast_mutex_lock(&pri->lock);
10354 return 0;
10357 static char * redirectingreason2str(int redirectingreason)
10359 switch (redirectingreason) {
10360 case 0:
10361 return "UNKNOWN";
10362 case 1:
10363 return "BUSY";
10364 case 2:
10365 return "NO_REPLY";
10366 case 0xF:
10367 return "UNCONDITIONAL";
10368 default:
10369 return "NOREDIRECT";
10373 static void apply_plan_to_number(char *buf, size_t size, const struct dahdi_pri *pri, const char *number, const int plan)
10375 if (pri->dialplan == -2) { /* autodetect the TON but leave the number untouched */
10376 snprintf(buf, size, "%s", number);
10377 return;
10379 switch (plan) {
10380 case PRI_INTERNATIONAL_ISDN: /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
10381 snprintf(buf, size, "%s%s", pri->internationalprefix, number);
10382 break;
10383 case PRI_NATIONAL_ISDN: /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
10384 snprintf(buf, size, "%s%s", pri->nationalprefix, number);
10385 break;
10386 case PRI_LOCAL_ISDN: /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
10387 snprintf(buf, size, "%s%s", pri->localprefix, number);
10388 break;
10389 case PRI_PRIVATE: /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
10390 snprintf(buf, size, "%s%s", pri->privateprefix, number);
10391 break;
10392 case PRI_UNKNOWN: /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
10393 snprintf(buf, size, "%s%s", pri->unknownprefix, number);
10394 break;
10395 default: /* other Q.931 dialplan => don't twiddle with callingnum */
10396 snprintf(buf, size, "%s", number);
10397 break;
10402 static void *pri_dchannel(void *vpri)
10404 struct dahdi_pri *pri = vpri;
10405 pri_event *e;
10406 struct pollfd fds[NUM_DCHANS];
10407 int res;
10408 int chanpos = 0;
10409 int x;
10410 int haveidles;
10411 int activeidles;
10412 int nextidle = -1;
10413 struct ast_channel *c;
10414 struct timeval tv, lowest, *next;
10415 struct timeval lastidle = ast_tvnow();
10416 int doidling=0;
10417 char *cc;
10418 char idlen[80];
10419 struct ast_channel *idle;
10420 pthread_t p;
10421 time_t t;
10422 int i, which=-1;
10423 int numdchans;
10424 int cause=0;
10425 struct dahdi_pvt *crv;
10426 pthread_t threadid;
10427 char ani2str[6];
10428 char plancallingnum[256];
10429 char plancallingani[256];
10430 char calledtonstr[10];
10432 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
10434 gettimeofday(&lastidle, NULL);
10435 if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
10436 /* Need to do idle dialing, check to be sure though */
10437 cc = strchr(pri->idleext, '@');
10438 if (cc) {
10439 *cc = '\0';
10440 cc++;
10441 ast_copy_string(pri->idlecontext, cc, sizeof(pri->idlecontext));
10442 #if 0
10443 /* Extensions may not be loaded yet */
10444 if (!ast_exists_extension(NULL, pri->idlecontext, pri->idleext, 1, NULL))
10445 ast_log(LOG_WARNING, "Extension '%s @ %s' does not exist\n", pri->idleext, pri->idlecontext);
10446 else
10447 #endif
10448 doidling = 1;
10449 } else
10450 ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
10452 for (;;) {
10453 for (i = 0; i < NUM_DCHANS; i++) {
10454 if (!pri->dchannels[i])
10455 break;
10456 fds[i].fd = pri->fds[i];
10457 fds[i].events = POLLIN | POLLPRI;
10458 fds[i].revents = 0;
10460 numdchans = i;
10461 time(&t);
10462 ast_mutex_lock(&pri->lock);
10463 if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) {
10464 if (pri->resetting && pri_is_up(pri)) {
10465 if (pri->resetpos < 0)
10466 pri_check_restart(pri);
10467 } else {
10468 if (!pri->resetting && (t - pri->lastreset) >= pri->resetinterval) {
10469 pri->resetting = 1;
10470 pri->resetpos = -1;
10474 /* Look for any idle channels if appropriate */
10475 if (doidling && pri_is_up(pri)) {
10476 nextidle = -1;
10477 haveidles = 0;
10478 activeidles = 0;
10479 for (x = pri->numchans; x >= 0; x--) {
10480 if (pri->pvts[x] && !pri->pvts[x]->owner &&
10481 !pri->pvts[x]->call) {
10482 if (haveidles < pri->minunused) {
10483 haveidles++;
10484 } else if (!pri->pvts[x]->resetting) {
10485 nextidle = x;
10486 break;
10488 } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
10489 activeidles++;
10491 if (nextidle > -1) {
10492 if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
10493 /* Don't create a new idle call more than once per second */
10494 snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
10495 idle = dahdi_request("DAHDI", AST_FORMAT_ULAW, idlen, &cause);
10496 if (idle) {
10497 pri->pvts[nextidle]->isidlecall = 1;
10498 if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
10499 ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
10500 dahdi_hangup(idle);
10502 } else
10503 ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
10504 lastidle = ast_tvnow();
10506 } else if ((haveidles < pri->minunused) &&
10507 (activeidles > pri->minidle)) {
10508 /* Mark something for hangup if there is something
10509 that can be hungup */
10510 for (x = pri->numchans; x >= 0; x--) {
10511 /* find a candidate channel */
10512 if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
10513 pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10514 haveidles++;
10515 /* Stop if we have enough idle channels or
10516 can't spare any more active idle ones */
10517 if ((haveidles >= pri->minunused) ||
10518 (activeidles <= pri->minidle))
10519 break;
10524 /* Start with reasonable max */
10525 lowest = ast_tv(60, 0);
10526 for (i = 0; i < NUM_DCHANS; i++) {
10527 /* Find lowest available d-channel */
10528 if (!pri->dchannels[i])
10529 break;
10530 if ((next = pri_schedule_next(pri->dchans[i]))) {
10531 /* We need relative time here */
10532 tv = ast_tvsub(*next, ast_tvnow());
10533 if (tv.tv_sec < 0) {
10534 tv = ast_tv(0,0);
10536 if (doidling || pri->resetting) {
10537 if (tv.tv_sec > 1) {
10538 tv = ast_tv(1, 0);
10540 } else {
10541 if (tv.tv_sec > 60) {
10542 tv = ast_tv(60, 0);
10545 } else if (doidling || pri->resetting) {
10546 /* Make sure we stop at least once per second if we're
10547 monitoring idle channels */
10548 tv = ast_tv(1,0);
10549 } else {
10550 /* Don't poll for more than 60 seconds */
10551 tv = ast_tv(60, 0);
10553 if (!i || ast_tvcmp(tv, lowest) < 0) {
10554 lowest = tv;
10557 ast_mutex_unlock(&pri->lock);
10559 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
10560 pthread_testcancel();
10561 e = NULL;
10562 res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
10563 pthread_testcancel();
10564 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
10566 ast_mutex_lock(&pri->lock);
10567 if (!res) {
10568 for (which = 0; which < NUM_DCHANS; which++) {
10569 if (!pri->dchans[which])
10570 break;
10571 /* Just a timeout, run the scheduler */
10572 e = pri_schedule_run(pri->dchans[which]);
10573 if (e)
10574 break;
10576 } else if (res > -1) {
10577 for (which = 0; which < NUM_DCHANS; which++) {
10578 if (!pri->dchans[which])
10579 break;
10580 if (fds[which].revents & POLLPRI) {
10581 /* Check for an event */
10582 x = 0;
10583 res = ioctl(pri->fds[which], DAHDI_GETEVENT, &x);
10584 if (x) {
10585 ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span);
10586 manager_event(EVENT_FLAG_SYSTEM, "PRIEvent",
10587 "PRIEvent: %s\r\n"
10588 "PRIEventCode: %d\r\n"
10589 "D-channel: %s\r\n"
10590 "Span: %d\r\n",
10591 event2str(x),
10593 pri_order(which),
10594 pri->span
10597 /* Keep track of alarm state */
10598 if (x == DAHDI_EVENT_ALARM) {
10599 pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
10600 pri_find_dchan(pri);
10601 } else if (x == DAHDI_EVENT_NOALARM) {
10602 pri->dchanavail[which] |= DCHAN_NOTINALARM;
10603 pri_restart(pri->dchans[which]);
10606 ast_debug(1, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
10607 } else if (fds[which].revents & POLLIN) {
10608 e = pri_check_event(pri->dchans[which]);
10610 if (e)
10611 break;
10613 } else if (errno != EINTR)
10614 ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
10616 if (e) {
10617 if (pri->debug)
10618 pri_dump_event(pri->dchans[which], e);
10620 if (e->e != PRI_EVENT_DCHAN_DOWN) {
10621 if (!(pri->dchanavail[which] & DCHAN_UP)) {
10622 ast_verb(2, "%s D-Channel on span %d up\n", pri_order(which), pri->span);
10624 pri->dchanavail[which] |= DCHAN_UP;
10625 } else {
10626 if (pri->dchanavail[which] & DCHAN_UP) {
10627 ast_verb(2, "%s D-Channel on span %d down\n", pri_order(which), pri->span);
10629 pri->dchanavail[which] &= ~DCHAN_UP;
10632 if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
10633 /* Must be an NFAS group that has the secondary dchan active */
10634 pri->pri = pri->dchans[which];
10636 switch (e->e) {
10637 case PRI_EVENT_DCHAN_UP:
10638 if (!pri->pri) pri_find_dchan(pri);
10640 /* Note presense of D-channel */
10641 time(&pri->lastreset);
10643 /* Restart in 5 seconds */
10644 if (pri->resetinterval > -1) {
10645 pri->lastreset -= pri->resetinterval;
10646 pri->lastreset += 5;
10648 pri->resetting = 0;
10649 /* Take the channels from inalarm condition */
10650 for (i = 0; i < pri->numchans; i++)
10651 if (pri->pvts[i]) {
10652 pri->pvts[i]->inalarm = 0;
10654 break;
10655 case PRI_EVENT_DCHAN_DOWN:
10656 pri_find_dchan(pri);
10657 if (!pri_is_up(pri)) {
10658 pri->resetting = 0;
10659 /* Hangup active channels and put them in alarm mode */
10660 for (i = 0; i < pri->numchans; i++) {
10661 struct dahdi_pvt *p = pri->pvts[i];
10662 if (p) {
10663 if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
10664 /* T309 is not enabled : hangup calls when alarm occurs */
10665 if (p->call) {
10666 if (p->pri && p->pri->pri) {
10667 pri_hangup(p->pri->pri, p->call, -1);
10668 pri_destroycall(p->pri->pri, p->call);
10669 p->call = NULL;
10670 } else
10671 ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
10673 if (p->realcall) {
10674 pri_hangup_all(p->realcall, pri);
10675 } else if (p->owner)
10676 p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10678 p->inalarm = 1;
10682 break;
10683 case PRI_EVENT_RESTART:
10684 if (e->restart.channel > -1) {
10685 chanpos = pri_find_principle(pri, e->restart.channel);
10686 if (chanpos < 0)
10687 ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
10688 PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
10689 else {
10690 ast_verb(3, "B-channel %d/%d restarted on span %d\n",
10691 PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
10692 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10693 if (pri->pvts[chanpos]->call) {
10694 pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
10695 pri->pvts[chanpos]->call = NULL;
10697 /* Force soft hangup if appropriate */
10698 if (pri->pvts[chanpos]->realcall)
10699 pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
10700 else if (pri->pvts[chanpos]->owner)
10701 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10702 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10704 } else {
10705 ast_verb(3, "Restart on requested on entire span %d\n", pri->span);
10706 for (x = 0; x < pri->numchans; x++)
10707 if (pri->pvts[x]) {
10708 ast_mutex_lock(&pri->pvts[x]->lock);
10709 if (pri->pvts[x]->call) {
10710 pri_destroycall(pri->pri, pri->pvts[x]->call);
10711 pri->pvts[x]->call = NULL;
10713 if (pri->pvts[chanpos]->realcall)
10714 pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
10715 else if (pri->pvts[x]->owner)
10716 pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10717 ast_mutex_unlock(&pri->pvts[x]->lock);
10720 break;
10721 case PRI_EVENT_KEYPAD_DIGIT:
10722 chanpos = pri_find_principle(pri, e->digit.channel);
10723 if (chanpos < 0) {
10724 ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
10725 PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
10726 } else {
10727 chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
10728 if (chanpos > -1) {
10729 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10730 /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
10731 if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
10732 /* how to do that */
10733 int digitlen = strlen(e->digit.digits);
10734 char digit;
10735 int i;
10736 for (i = 0; i < digitlen; i++) {
10737 digit = e->digit.digits[i];
10739 struct ast_frame f = { AST_FRAME_DTMF, digit, };
10740 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
10744 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10747 break;
10749 case PRI_EVENT_INFO_RECEIVED:
10750 chanpos = pri_find_principle(pri, e->ring.channel);
10751 if (chanpos < 0) {
10752 ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
10753 PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
10754 } else {
10755 chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
10756 if (chanpos > -1) {
10757 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10758 /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
10759 if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
10760 /* how to do that */
10761 int digitlen = strlen(e->ring.callednum);
10762 char digit;
10763 int i;
10764 for (i = 0; i < digitlen; i++) {
10765 digit = e->ring.callednum[i];
10767 struct ast_frame f = { AST_FRAME_DTMF, digit, };
10768 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
10772 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10775 break;
10776 case PRI_EVENT_RING:
10777 crv = NULL;
10778 if (e->ring.channel == -1)
10779 chanpos = pri_find_empty_chan(pri, 1);
10780 else
10781 chanpos = pri_find_principle(pri, e->ring.channel);
10782 /* if no channel specified find one empty */
10783 if (chanpos < 0) {
10784 ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
10785 PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
10786 } else {
10787 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10788 if (pri->pvts[chanpos]->owner) {
10789 if (pri->pvts[chanpos]->call == e->ring.call) {
10790 ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n",
10791 PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
10792 break;
10793 } else {
10794 /* This is where we handle initial glare */
10795 ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiate channel.\n",
10796 PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
10797 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10798 chanpos = -1;
10801 if (chanpos > -1)
10802 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10804 if ((chanpos < 0) && (e->ring.flexible))
10805 chanpos = pri_find_empty_chan(pri, 1);
10806 if (chanpos > -1) {
10807 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10808 if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
10809 /* Should be safe to lock CRV AFAIK while bearer is still locked */
10810 crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
10811 if (crv)
10812 ast_mutex_lock(&crv->lock);
10813 if (!crv || crv->owner) {
10814 pri->pvts[chanpos]->call = NULL;
10815 if (crv) {
10816 if (crv->owner)
10817 crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10818 ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
10819 } else
10820 ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
10821 pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
10822 if (crv)
10823 ast_mutex_unlock(&crv->lock);
10824 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10825 break;
10828 pri->pvts[chanpos]->call = e->ring.call;
10829 apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
10830 if (pri->pvts[chanpos]->use_callerid) {
10831 ast_shrink_phone_number(plancallingnum);
10832 ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
10833 #ifdef PRI_ANI
10834 if (!ast_strlen_zero(e->ring.callingani)) {
10835 apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
10836 ast_shrink_phone_number(plancallingani);
10837 ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
10838 } else {
10839 pri->pvts[chanpos]->cid_ani[0] = '\0';
10841 #endif
10842 ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
10843 pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
10844 } else {
10845 pri->pvts[chanpos]->cid_num[0] = '\0';
10846 pri->pvts[chanpos]->cid_ani[0] = '\0';
10847 pri->pvts[chanpos]->cid_name[0] = '\0';
10848 pri->pvts[chanpos]->cid_ton = 0;
10850 apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
10851 e->ring.redirectingnum, e->ring.callingplanrdnis);
10852 /* If immediate=yes go to s|1 */
10853 if (pri->pvts[chanpos]->immediate) {
10854 ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
10855 pri->pvts[chanpos]->exten[0] = 's';
10856 pri->pvts[chanpos]->exten[1] = '\0';
10858 /* Get called number */
10859 else if (!ast_strlen_zero(e->ring.callednum)) {
10860 ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
10861 ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
10862 } else if (pri->overlapdial)
10863 pri->pvts[chanpos]->exten[0] = '\0';
10864 else {
10865 /* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
10866 pri->pvts[chanpos]->exten[0] = 's';
10867 pri->pvts[chanpos]->exten[1] = '\0';
10869 /* Set DNID on all incoming calls -- even immediate */
10870 if (!ast_strlen_zero(e->ring.callednum))
10871 ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
10872 /* No number yet, but received "sending complete"? */
10873 if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
10874 ast_verb(3, "Going to extension s|1 because of Complete received\n");
10875 pri->pvts[chanpos]->exten[0] = 's';
10876 pri->pvts[chanpos]->exten[1] = '\0';
10878 /* Make sure extension exists (or in overlap dial mode, can exist) */
10879 if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
10880 ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
10881 /* Setup law */
10882 int law;
10883 if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
10884 /* Set to audio mode at this point */
10885 law = 1;
10886 if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
10887 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
10889 if (e->ring.layer1 == PRI_LAYER_1_ALAW)
10890 law = DAHDI_LAW_ALAW;
10891 else
10892 law = DAHDI_LAW_MULAW;
10893 res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
10894 if (res < 0)
10895 ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
10896 res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
10897 if (res < 0)
10898 ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
10899 if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
10900 /* Just announce proceeding */
10901 pri->pvts[chanpos]->proceeding = 1;
10902 pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
10903 } else {
10904 if (pri->switchtype != PRI_SWITCH_GR303_TMC)
10905 pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
10906 else
10907 pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
10909 /* Get the use_callingpres state */
10910 pri->pvts[chanpos]->callingpres = e->ring.callingpres;
10912 /* Start PBX */
10913 if (!e->ring.complete && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
10914 /* Release the PRI lock while we create the channel */
10915 ast_mutex_unlock(&pri->lock);
10916 if (crv) {
10917 /* Set bearer and such */
10918 pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
10919 c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
10920 pri->pvts[chanpos]->owner = &inuse;
10921 ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
10922 } else {
10923 c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
10926 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10928 if (!ast_strlen_zero(e->ring.callingsubaddr)) {
10929 pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
10931 if (e->ring.ani2 >= 0) {
10932 snprintf(ani2str, 5, "%.2d", e->ring.ani2);
10933 pbx_builtin_setvar_helper(c, "ANI2", ani2str);
10934 pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
10937 #ifdef SUPPORT_USERUSER
10938 if (!ast_strlen_zero(e->ring.useruserinfo)) {
10939 pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
10941 #endif
10943 snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
10944 pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
10945 if (e->ring.redirectingreason >= 0)
10946 pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
10948 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10949 ast_mutex_lock(&pri->lock);
10950 if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
10951 ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
10952 plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
10953 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
10954 } else {
10955 ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
10956 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
10957 if (c)
10958 ast_hangup(c);
10959 else {
10960 pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
10961 pri->pvts[chanpos]->call = NULL;
10964 } else {
10965 ast_mutex_unlock(&pri->lock);
10966 /* Release PRI lock while we create the channel */
10967 c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 1, SUB_REAL, law, e->ring.ctype);
10968 if (c) {
10969 char calledtonstr[10];
10971 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
10973 if (e->ring.ani2 >= 0) {
10974 snprintf(ani2str, 5, "%d", e->ring.ani2);
10975 pbx_builtin_setvar_helper(c, "ANI2", ani2str);
10976 pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
10979 #ifdef SUPPORT_USERUSER
10980 if (!ast_strlen_zero(e->ring.useruserinfo)) {
10981 pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
10983 #endif
10985 if (e->ring.redirectingreason >= 0)
10986 pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
10988 snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
10989 pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
10991 ast_mutex_lock(&pri->pvts[chanpos]->lock);
10992 ast_mutex_lock(&pri->lock);
10994 ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
10995 plancallingnum, pri->pvts[chanpos]->exten,
10996 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
10998 dahdi_enable_ec(pri->pvts[chanpos]);
10999 } else {
11001 ast_mutex_lock(&pri->lock);
11003 ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
11004 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11005 pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11006 pri->pvts[chanpos]->call = NULL;
11009 } else {
11010 ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist. Rejecting call on channel %d/%d, span %d\n",
11011 pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
11012 pri->pvts[chanpos]->prioffset, pri->span);
11013 pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
11014 pri->pvts[chanpos]->call = NULL;
11015 pri->pvts[chanpos]->exten[0] = '\0';
11017 if (crv)
11018 ast_mutex_unlock(&crv->lock);
11019 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11020 } else {
11021 if (e->ring.flexible)
11022 pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
11023 else
11024 pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
11026 break;
11027 case PRI_EVENT_RINGING:
11028 chanpos = pri_find_principle(pri, e->ringing.channel);
11029 if (chanpos < 0) {
11030 ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n",
11031 PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11032 } else {
11033 chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
11034 if (chanpos < 0) {
11035 ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n",
11036 PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11037 } else {
11038 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11039 if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11040 dahdi_enable_ec(pri->pvts[chanpos]);
11041 pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
11042 pri->pvts[chanpos]->alerting = 1;
11043 } else
11044 ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n");
11046 #ifdef PRI_PROGRESS_MASK
11047 if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11048 #else
11049 if (e->ringing.progress == 8) {
11050 #endif
11051 /* Now we can do call progress detection */
11052 if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11053 /* RINGING detection isn't required because we got ALERTING signal */
11054 ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features & ~DSP_PROGRESS_RINGING);
11055 pri->pvts[chanpos]->dsp_features = 0;
11059 #ifdef SUPPORT_USERUSER
11060 if (!ast_strlen_zero(e->ringing.useruserinfo)) {
11061 struct ast_channel *owner = pri->pvts[chanpos]->owner;
11062 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11063 pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->ringing.useruserinfo);
11064 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11066 #endif
11068 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11071 break;
11072 case PRI_EVENT_PROGRESS:
11073 /* Get chan value if e->e is not PRI_EVNT_RINGING */
11074 chanpos = pri_find_principle(pri, e->proceeding.channel);
11075 if (chanpos > -1) {
11076 #ifdef PRI_PROGRESS_MASK
11077 if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
11078 #else
11079 if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progress == 8)) {
11080 #endif
11081 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
11083 if (e->proceeding.cause > -1) {
11084 ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
11086 /* Work around broken, out of spec USER_BUSY cause in a progress message */
11087 if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
11088 if (pri->pvts[chanpos]->owner) {
11089 ast_verb(3, "PROGRESS with 'user busy' received, signalling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
11091 pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
11092 f.subclass = AST_CONTROL_BUSY;
11097 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11098 ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
11099 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11100 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11101 #ifdef PRI_PROGRESS_MASK
11102 if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11103 #else
11104 if (e->proceeding.progress == 8) {
11105 #endif
11106 /* Now we can do call progress detection */
11107 if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11108 ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11109 pri->pvts[chanpos]->dsp_features = 0;
11112 pri->pvts[chanpos]->progress = 1;
11113 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11116 break;
11117 case PRI_EVENT_PROCEEDING:
11118 chanpos = pri_find_principle(pri, e->proceeding.channel);
11119 if (chanpos > -1) {
11120 if (!pri->pvts[chanpos]->proceeding) {
11121 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
11123 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11124 ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
11125 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11126 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11127 #ifdef PRI_PROGRESS_MASK
11128 if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11129 #else
11130 if (e->proceeding.progress == 8) {
11131 #endif
11132 /* Now we can do call progress detection */
11133 if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11134 ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11135 pri->pvts[chanpos]->dsp_features = 0;
11137 /* Bring voice path up */
11138 f.subclass = AST_CONTROL_PROGRESS;
11139 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11141 pri->pvts[chanpos]->proceeding = 1;
11142 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11145 break;
11146 case PRI_EVENT_FACNAME:
11147 chanpos = pri_find_principle(pri, e->facname.channel);
11148 if (chanpos < 0) {
11149 ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n",
11150 PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11151 } else {
11152 chanpos = pri_fixup_principle(pri, chanpos, e->facname.call);
11153 if (chanpos < 0) {
11154 ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n",
11155 PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11156 } else {
11157 /* Re-use *69 field for PRI */
11158 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11159 ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num));
11160 ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name));
11161 pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1;
11162 dahdi_enable_ec(pri->pvts[chanpos]);
11163 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11166 break;
11167 case PRI_EVENT_ANSWER:
11168 chanpos = pri_find_principle(pri, e->answer.channel);
11169 if (chanpos < 0) {
11170 ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n",
11171 PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11172 } else {
11173 chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
11174 if (chanpos < 0) {
11175 ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n",
11176 PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11177 } else {
11178 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11179 /* Now we can do call progress detection */
11181 /* We changed this so it turns on the DSP no matter what... progress or no progress.
11182 * By this time, we need DTMF detection and other features that were previously disabled
11183 * -- Matt F */
11184 if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11185 ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11186 pri->pvts[chanpos]->dsp_features = 0;
11188 if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) {
11189 ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n");
11190 x = DAHDI_START;
11191 res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11192 if (res < 0) {
11193 if (errno != EINPROGRESS) {
11194 ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
11197 } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11198 pri->pvts[chanpos]->dialing = 1;
11199 /* Send any "w" waited stuff */
11200 res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop);
11201 if (res < 0) {
11202 ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
11203 pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11204 } else
11205 ast_debug(1, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
11207 pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11208 } else if (pri->pvts[chanpos]->confirmanswer) {
11209 ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
11210 } else {
11211 pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
11212 /* Enable echo cancellation if it's not on already */
11213 dahdi_enable_ec(pri->pvts[chanpos]);
11216 #ifdef SUPPORT_USERUSER
11217 if (!ast_strlen_zero(e->answer.useruserinfo)) {
11218 struct ast_channel *owner = pri->pvts[chanpos]->owner;
11219 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11220 pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo);
11221 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11223 #endif
11225 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11228 break;
11229 case PRI_EVENT_HANGUP:
11230 chanpos = pri_find_principle(pri, e->hangup.channel);
11231 if (chanpos < 0) {
11232 ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n",
11233 PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11234 } else {
11235 chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11236 if (chanpos > -1) {
11237 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11238 if (!pri->pvts[chanpos]->alreadyhungup) {
11239 /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
11240 pri->pvts[chanpos]->alreadyhungup = 1;
11241 if (pri->pvts[chanpos]->realcall)
11242 pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11243 else if (pri->pvts[chanpos]->owner) {
11244 /* Queue a BUSY instead of a hangup if our cause is appropriate */
11245 pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11246 if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
11247 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11248 else {
11249 switch (e->hangup.cause) {
11250 case PRI_CAUSE_USER_BUSY:
11251 pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11252 break;
11253 case PRI_CAUSE_CALL_REJECTED:
11254 case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11255 case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11256 case PRI_CAUSE_SWITCH_CONGESTION:
11257 case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11258 case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11259 pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11260 break;
11261 default:
11262 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11266 ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
11267 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
11268 } else {
11269 pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11270 pri->pvts[chanpos]->call = NULL;
11272 if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11273 ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
11274 PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11275 pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11276 pri->pvts[chanpos]->resetting = 1;
11278 if (e->hangup.aoc_units > -1)
11279 ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11280 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11282 #ifdef SUPPORT_USERUSER
11283 if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) {
11284 struct ast_channel *owner = pri->pvts[chanpos]->owner;
11285 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11286 pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11287 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11289 #endif
11291 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11292 } else {
11293 ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n",
11294 PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11297 break;
11298 #ifndef PRI_EVENT_HANGUP_REQ
11299 #error please update libpri
11300 #endif
11301 case PRI_EVENT_HANGUP_REQ:
11302 chanpos = pri_find_principle(pri, e->hangup.channel);
11303 if (chanpos < 0) {
11304 ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
11305 PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11306 } else {
11307 chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11308 if (chanpos > -1) {
11309 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11310 if (pri->pvts[chanpos]->realcall)
11311 pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11312 else if (pri->pvts[chanpos]->owner) {
11313 pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11314 if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
11315 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11316 else {
11317 switch (e->hangup.cause) {
11318 case PRI_CAUSE_USER_BUSY:
11319 pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11320 break;
11321 case PRI_CAUSE_CALL_REJECTED:
11322 case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11323 case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11324 case PRI_CAUSE_SWITCH_CONGESTION:
11325 case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11326 case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11327 pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11328 break;
11329 default:
11330 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11333 ast_verb(3, "Channel %d/%d, span %d got hangup request, cause %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause);
11334 if (e->hangup.aoc_units > -1)
11335 ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11336 pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11337 } else {
11338 pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11339 pri->pvts[chanpos]->call = NULL;
11341 if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11342 ast_verb(3, "Forcing restart of channel %d/%d span %d since channel reported in use\n",
11343 PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11344 pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11345 pri->pvts[chanpos]->resetting = 1;
11348 #ifdef SUPPORT_USERUSER
11349 if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11350 struct ast_channel *owner = pri->pvts[chanpos]->owner;
11351 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11352 pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11353 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11355 #endif
11357 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11358 } else {
11359 ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11362 break;
11363 case PRI_EVENT_HANGUP_ACK:
11364 chanpos = pri_find_principle(pri, e->hangup.channel);
11365 if (chanpos < 0) {
11366 ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n",
11367 PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11368 } else {
11369 chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11370 if (chanpos > -1) {
11371 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11372 pri->pvts[chanpos]->call = NULL;
11373 pri->pvts[chanpos]->resetting = 0;
11374 if (pri->pvts[chanpos]->owner) {
11375 ast_verb(3, "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11378 #ifdef SUPPORT_USERUSER
11379 if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11380 struct ast_channel *owner = pri->pvts[chanpos]->owner;
11381 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11382 pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11383 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11385 #endif
11387 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11390 break;
11391 case PRI_EVENT_CONFIG_ERR:
11392 ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
11393 break;
11394 case PRI_EVENT_RESTART_ACK:
11395 chanpos = pri_find_principle(pri, e->restartack.channel);
11396 if (chanpos < 0) {
11397 /* Sometime switches (e.g. I421 / British Telecom) don't give us the
11398 channel number, so we have to figure it out... This must be why
11399 everybody resets exactly a channel at a time. */
11400 for (x = 0; x < pri->numchans; x++) {
11401 if (pri->pvts[x] && pri->pvts[x]->resetting) {
11402 chanpos = x;
11403 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11404 ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan,
11405 pri->pvts[chanpos]->prioffset, pri->span);
11406 if (pri->pvts[chanpos]->realcall)
11407 pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11408 else if (pri->pvts[chanpos]->owner) {
11409 ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan,
11410 pri->pvts[chanpos]->prioffset, pri->span);
11411 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11413 pri->pvts[chanpos]->resetting = 0;
11414 ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11415 pri->pvts[chanpos]->prioffset, pri->span);
11416 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11417 if (pri->resetting)
11418 pri_check_restart(pri);
11419 break;
11422 if (chanpos < 0) {
11423 ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n",
11424 PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11426 } else {
11427 if (pri->pvts[chanpos]) {
11428 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11429 if (pri->pvts[chanpos]->realcall)
11430 pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11431 else if (pri->pvts[chanpos]->owner) {
11432 ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
11433 PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11434 pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11436 pri->pvts[chanpos]->resetting = 0;
11437 pri->pvts[chanpos]->inservice = 1;
11438 ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11439 pri->pvts[chanpos]->prioffset, pri->span);
11440 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11441 if (pri->resetting)
11442 pri_check_restart(pri);
11445 break;
11446 case PRI_EVENT_SETUP_ACK:
11447 chanpos = pri_find_principle(pri, e->setup_ack.channel);
11448 if (chanpos < 0) {
11449 ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n",
11450 PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
11451 } else {
11452 chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
11453 if (chanpos > -1) {
11454 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11455 pri->pvts[chanpos]->setup_ack = 1;
11456 /* Send any queued digits */
11457 for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
11458 ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
11459 pri_information(pri->pri, pri->pvts[chanpos]->call,
11460 pri->pvts[chanpos]->dialdest[x]);
11462 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11463 } else
11464 ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
11466 break;
11467 case PRI_EVENT_NOTIFY:
11468 chanpos = pri_find_principle(pri, e->notify.channel);
11469 if (chanpos < 0) {
11470 ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
11471 PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
11472 } else {
11473 struct ast_frame f = { AST_FRAME_CONTROL, };
11474 ast_mutex_lock(&pri->pvts[chanpos]->lock);
11475 switch (e->notify.info) {
11476 case PRI_NOTIFY_REMOTE_HOLD:
11477 f.subclass = AST_CONTROL_HOLD;
11478 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11479 break;
11480 case PRI_NOTIFY_REMOTE_RETRIEVAL:
11481 f.subclass = AST_CONTROL_UNHOLD;
11482 dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11483 break;
11485 ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11487 break;
11488 default:
11489 ast_debug(1, "Event: %d\n", e->e);
11492 ast_mutex_unlock(&pri->lock);
11494 /* Never reached */
11495 return NULL;
11498 static int start_pri(struct dahdi_pri *pri)
11500 int res, x;
11501 struct dahdi_params p;
11502 struct dahdi_bufferinfo bi;
11503 struct dahdi_spaninfo si;
11504 int i;
11506 for (i = 0; i < NUM_DCHANS; i++) {
11507 if (!pri->dchannels[i])
11508 break;
11509 pri->fds[i] = open("/dev/dahdi/channel", O_RDWR);
11510 x = pri->dchannels[i];
11511 if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],DAHDI_SPECIFY,&x) == -1)) {
11512 ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
11513 return -1;
11515 res = ioctl(pri->fds[i], DAHDI_GET_PARAMS, &p);
11516 if (res) {
11517 dahdi_close_pri_fd(pri, i);
11518 ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
11519 return -1;
11521 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
11522 dahdi_close_pri_fd(pri, i);
11523 ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
11524 return -1;
11526 memset(&si, 0, sizeof(si));
11527 res = ioctl(pri->fds[i], DAHDI_SPANSTAT, &si);
11528 if (res) {
11529 dahdi_close_pri_fd(pri, i);
11530 ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
11532 if (!si.alarms)
11533 pri->dchanavail[i] |= DCHAN_NOTINALARM;
11534 else
11535 pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
11536 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
11537 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
11538 bi.numbufs = 32;
11539 bi.bufsize = 1024;
11540 if (ioctl(pri->fds[i], DAHDI_SET_BUFINFO, &bi)) {
11541 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
11542 dahdi_close_pri_fd(pri, i);
11543 return -1;
11545 switch (pri->sig) {
11546 case SIG_BRI:
11547 pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype);
11548 break;
11549 case SIG_BRI_PTMP:
11550 pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype);
11551 break;
11552 default:
11553 pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
11555 /* Force overlap dial if we're doing GR-303! */
11556 if (pri->switchtype == PRI_SWITCH_GR303_TMC)
11557 pri->overlapdial |= DAHDI_OVERLAPDIAL_BOTH;
11558 pri_set_overlapdial(pri->dchans[i],(pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)?1:0);
11559 #ifdef HAVE_PRI_INBANDDISCONNECT
11560 pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
11561 #endif
11562 /* Enslave to master if appropriate */
11563 if (i)
11564 pri_enslave(pri->dchans[0], pri->dchans[i]);
11565 if (!pri->dchans[i]) {
11566 dahdi_close_pri_fd(pri, i);
11567 ast_log(LOG_ERROR, "Unable to create PRI structure\n");
11568 return -1;
11570 pri_set_debug(pri->dchans[i], DEFAULT_PRI_DEBUG);
11571 pri_set_nsf(pri->dchans[i], pri->nsf);
11572 #ifdef PRI_GETSET_TIMERS
11573 for (x = 0; x < PRI_MAX_TIMERS; x++) {
11574 if (pritimers[x] != 0)
11575 pri_set_timer(pri->dchans[i], x, pritimers[x]);
11577 #endif
11579 /* Assume primary is the one we use */
11580 pri->pri = pri->dchans[0];
11581 pri->resetpos = -1;
11582 if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
11583 for (i = 0; i < NUM_DCHANS; i++) {
11584 if (!pri->dchannels[i])
11585 break;
11586 dahdi_close_pri_fd(pri, i);
11588 ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
11589 return -1;
11591 return 0;
11594 static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
11596 int which, span;
11597 char *ret = NULL;
11599 if (pos != rpos)
11600 return ret;
11602 for (which = span = 0; span < NUM_SPANS; span++) {
11603 if (pris[span].pri && ++which > state) {
11604 asprintf(&ret, "%d", span + 1); /* user indexes start from 1 */
11605 break;
11608 return ret;
11611 static char *complete_span_4(const char *line, const char *word, int pos, int state)
11613 return complete_span_helper(line,word,pos,state,3);
11616 static char *complete_span_5(const char *line, const char *word, int pos, int state)
11618 return complete_span_helper(line,word,pos,state,4);
11621 static char *handle_pri_unset_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11623 switch (cmd) {
11624 case CLI_INIT:
11625 e->command = "pri unset debug file";
11626 e->usage = "Usage: pri unset debug file\n"
11627 " Stop sending debug output to the previously \n"
11628 " specified file\n";
11629 return NULL;
11630 case CLI_GENERATE:
11631 return NULL;
11633 /* Assume it is unset */
11634 ast_mutex_lock(&pridebugfdlock);
11635 close(pridebugfd);
11636 pridebugfd = -1;
11637 ast_cli(a->fd, "PRI debug output to file disabled\n");
11638 ast_mutex_unlock(&pridebugfdlock);
11639 return CLI_SUCCESS;
11642 static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11644 int myfd;
11645 switch (cmd) {
11646 case CLI_INIT:
11647 e->command = "pri set debug file";
11648 e->usage = "Usage: pri set debug file [output-file]\n"
11649 " Sends PRI debug output to the specified output file\n";
11650 return NULL;
11651 case CLI_GENERATE:
11652 return NULL;
11654 if (a->argc < 5)
11655 return CLI_SHOWUSAGE;
11657 if (ast_strlen_zero(a->argv[4]))
11658 return CLI_SHOWUSAGE;
11660 myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
11661 if (myfd < 0) {
11662 ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
11663 return CLI_SUCCESS;
11666 ast_mutex_lock(&pridebugfdlock);
11668 if (pridebugfd >= 0)
11669 close(pridebugfd);
11671 pridebugfd = myfd;
11672 ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
11673 ast_mutex_unlock(&pridebugfdlock);
11674 ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
11675 return CLI_SUCCESS;
11678 static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11680 int span;
11681 int x;
11682 switch (cmd) {
11683 case CLI_INIT:
11684 e->command = "pri debug span";
11685 e->usage =
11686 "Usage: pri debug span <span>\n"
11687 " Enables debugging on a given PRI span\n";
11688 return NULL;
11689 case CLI_GENERATE:
11690 return complete_span_4(a->line, a->word, a->pos, a->n);
11692 if (a->argc < 4) {
11693 return CLI_SHOWUSAGE;
11695 span = atoi(a->argv[3]);
11696 if ((span < 1) || (span > NUM_SPANS)) {
11697 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
11698 return CLI_SUCCESS;
11700 if (!pris[span-1].pri) {
11701 ast_cli(a->fd, "No PRI running on span %d\n", span);
11702 return CLI_SUCCESS;
11704 for (x = 0; x < NUM_DCHANS; x++) {
11705 if (pris[span-1].dchans[x])
11706 pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
11707 PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
11708 PRI_DEBUG_Q921_STATE);
11710 ast_cli(a->fd, "Enabled debugging on span %d\n", span);
11711 return CLI_SUCCESS;
11716 static char *handle_pri_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11718 int span;
11719 int x;
11720 switch (cmd) {
11721 case CLI_INIT:
11722 e->command = "pri no debug span";
11723 e->usage =
11724 "Usage: pri no debug span <span>\n"
11725 " Disables debugging on a given PRI span\n";
11726 return NULL;
11727 case CLI_GENERATE:
11728 return complete_span_5(a->line, a->word, a->pos, a->n);
11730 if (a->argc < 5)
11731 return CLI_SHOWUSAGE;
11733 span = atoi(a->argv[4]);
11734 if ((span < 1) || (span > NUM_SPANS)) {
11735 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
11736 return CLI_SUCCESS;
11738 if (!pris[span-1].pri) {
11739 ast_cli(a->fd, "No PRI running on span %d\n", span);
11740 return CLI_SUCCESS;
11742 for (x = 0; x < NUM_DCHANS; x++) {
11743 if (pris[span-1].dchans[x])
11744 pri_set_debug(pris[span-1].dchans[x], 0);
11746 ast_cli(a->fd, "Disabled debugging on span %d\n", span);
11747 return CLI_SUCCESS;
11750 static char *handle_pri_really_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11752 int span;
11753 int x;
11754 switch (cmd) {
11755 case CLI_INIT:
11756 e->command = "pri intensive debug span";
11757 e->usage =
11758 "Usage: pri intensive debug span <span>\n"
11759 " Enables debugging down to the Q.921 level\n";
11760 return NULL;
11761 case CLI_GENERATE:
11762 return complete_span_5(a->line, a->word, a->pos, a->n);
11765 if (a->argc < 5)
11766 return CLI_SHOWUSAGE;
11767 span = atoi(a->argv[4]);
11768 if ((span < 1) || (span > NUM_SPANS)) {
11769 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
11770 return CLI_SUCCESS;
11772 if (!pris[span-1].pri) {
11773 ast_cli(a->fd, "No PRI running on span %d\n", span);
11774 return CLI_SUCCESS;
11776 for (x = 0; x < NUM_DCHANS; x++) {
11777 if (pris[span-1].dchans[x])
11778 pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
11779 PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
11780 PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE);
11782 ast_cli(a->fd, "Enabled EXTENSIVE debugging on span %d\n", span);
11783 return CLI_SUCCESS;
11786 static void build_status(char *s, size_t len, int status, int active)
11788 if (!s || len < 1) {
11789 return;
11791 s[0] = '\0';
11792 if (status & DCHAN_PROVISIONED)
11793 strncat(s, "Provisioned, ", len - strlen(s) - 1);
11794 if (!(status & DCHAN_NOTINALARM))
11795 strncat(s, "In Alarm, ", len - strlen(s) - 1);
11796 if (status & DCHAN_UP)
11797 strncat(s, "Up", len - strlen(s) - 1);
11798 else
11799 strncat(s, "Down", len - strlen(s) - 1);
11800 if (active)
11801 strncat(s, ", Active", len - strlen(s) - 1);
11802 else
11803 strncat(s, ", Standby", len - strlen(s) - 1);
11804 s[len - 1] = '\0';
11807 static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11809 int span;
11810 int x;
11811 char status[256];
11813 switch (cmd) {
11814 case CLI_INIT:
11815 e->command = "pri show spans";
11816 e->usage =
11817 "Usage: pri show spans\n"
11818 " Displays PRI Information\n";
11819 return NULL;
11820 case CLI_GENERATE:
11821 return NULL;
11824 if (a->argc != 3)
11825 return CLI_SHOWUSAGE;
11827 for (span = 0; span < NUM_SPANS; span++) {
11828 if (pris[span].pri) {
11829 for (x = 0; x < NUM_DCHANS; x++) {
11830 if (pris[span].dchannels[x]) {
11831 build_status(status, sizeof(status), pris[span].dchanavail[x], pris[span].dchans[x] == pris[span].pri);
11832 ast_cli(a->fd, "PRI span %d/%d: %s\n", span + 1, x, status);
11837 return CLI_SUCCESS;
11840 static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11842 int span;
11843 int x;
11844 char status[256];
11845 switch (cmd) {
11846 case CLI_INIT:
11847 e->command = "pri show span";
11848 e->usage =
11849 "Usage: pri show span <span>\n"
11850 " Displays PRI Information on a given PRI span\n";
11851 return NULL;
11852 case CLI_GENERATE:
11853 return complete_span_4(a->line, a->word, a->pos, a->n);
11856 if (a->argc < 4)
11857 return CLI_SHOWUSAGE;
11858 span = atoi(a->argv[3]);
11859 if ((span < 1) || (span > NUM_SPANS)) {
11860 ast_cli(a->fd, "Invalid span '%s'. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
11861 return CLI_SUCCESS;
11863 if (!pris[span-1].pri) {
11864 ast_cli(a->fd, "No PRI running on span %d\n", span);
11865 return CLI_SUCCESS;
11867 for (x = 0; x < NUM_DCHANS; x++) {
11868 if (pris[span-1].dchannels[x]) {
11869 #ifdef PRI_DUMP_INFO_STR
11870 char *info_str = NULL;
11871 #endif
11872 ast_cli(a->fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
11873 build_status(status, sizeof(status), pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
11874 ast_cli(a->fd, "Status: %s\n", status);
11875 #ifdef PRI_DUMP_INFO_STR
11876 info_str = pri_dump_info_str(pris[span-1].pri);
11877 if (info_str) {
11878 ast_cli(a->fd, "%s", info_str);
11879 ast_free(info_str);
11881 #else
11882 pri_dump_info(pris[span-1].pri);
11883 #endif
11884 ast_cli(a->fd, "Overlap Recv: %s\n\n", (pris[span-1].overlapdial & DAHDI_OVERLAPDIAL_INCOMING)?"Yes":"No");
11887 return CLI_SUCCESS;
11890 static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11892 int x;
11893 int span;
11894 int count=0;
11895 int debug=0;
11897 switch (cmd) {
11898 case CLI_INIT:
11899 e->command = "pri show debug";
11900 return NULL;
11901 case CLI_GENERATE:
11902 return NULL;
11905 for (span = 0; span < NUM_SPANS; span++) {
11906 if (pris[span].pri) {
11907 for (x = 0; x < NUM_DCHANS; x++) {
11908 debug = 0;
11909 if (pris[span].dchans[x]) {
11910 debug = pri_get_debug(pris[span].dchans[x]);
11911 ast_cli(a->fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" );
11912 count++;
11918 ast_mutex_lock(&pridebugfdlock);
11919 if (pridebugfd >= 0)
11920 ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
11921 ast_mutex_unlock(&pridebugfdlock);
11923 if (!count)
11924 ast_cli(a->fd, "No debug set or no PRI running\n");
11925 return CLI_SUCCESS;
11928 static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11930 switch (cmd) {
11931 case CLI_INIT:
11932 e->command = "pri show version";
11933 return NULL;
11934 case CLI_GENERATE:
11935 return NULL;
11938 ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
11940 return CLI_SUCCESS;
11943 static struct ast_cli_entry dahdi_pri_cli[] = {
11944 AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
11945 AST_CLI_DEFINE(handle_pri_no_debug, "Disables PRI debugging on a span"),
11946 AST_CLI_DEFINE(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"),
11947 AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI Information"),
11948 AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI Information"),
11949 AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
11950 AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
11951 AST_CLI_DEFINE(handle_pri_unset_debug_file, "Ends PRI debug output to file"),
11952 AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
11955 #endif /* HAVE_PRI */
11957 static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11959 int channel;
11960 int ret;
11961 switch (cmd) {
11962 case CLI_INIT:
11963 e->command = "dahdi destroy channel";
11964 e->usage =
11965 "Usage: dahdi destroy channel <chan num>\n"
11966 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
11967 return NULL;
11968 case CLI_GENERATE:
11969 return NULL;
11971 if (a->argc != 4)
11972 return CLI_SHOWUSAGE;
11974 channel = atoi(a->argv[3]);
11975 ret = dahdi_destroy_channel_bynum(channel);
11976 return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
11979 static void dahdi_softhangup_all(void)
11981 struct dahdi_pvt *p;
11982 retry:
11983 ast_mutex_lock(&iflock);
11984 for (p = iflist; p; p = p->next) {
11985 ast_mutex_lock(&p->lock);
11986 if (p->owner && !p->restartpending) {
11987 if (ast_channel_trylock(p->owner)) {
11988 if (option_debug > 2)
11989 ast_verbose("Avoiding deadlock\n");
11990 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
11991 ast_mutex_unlock(&p->lock);
11992 ast_mutex_unlock(&iflock);
11993 goto retry;
11995 if (option_debug > 2)
11996 ast_verbose("Softhanging up on %s\n", p->owner->name);
11997 ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_EXPLICIT);
11998 p->restartpending = 1;
11999 num_restart_pending++;
12000 ast_channel_unlock(p->owner);
12002 ast_mutex_unlock(&p->lock);
12004 ast_mutex_unlock(&iflock);
12007 static int setup_dahdi(int reload);
12008 static int dahdi_restart(void)
12010 #if defined(HAVE_PRI) || defined(HAVE_SS7)
12011 int i, j;
12012 #endif
12013 int cancel_code;
12014 struct dahdi_pvt *p;
12016 ast_mutex_lock(&restart_lock);
12018 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
12019 dahdi_softhangup_all();
12020 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
12022 #if defined(HAVE_PRI)
12023 for (i = 0; i < NUM_SPANS; i++) {
12024 if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
12025 cancel_code = pthread_cancel(pris[i].master);
12026 pthread_kill(pris[i].master, SIGURG);
12027 ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) pris[i].master, cancel_code);
12028 pthread_join(pris[i].master, NULL);
12029 ast_debug(4, "Joined thread of span %d\n", i);
12032 #endif
12034 #if defined(HAVE_SS7)
12035 for (i = 0; i < NUM_SPANS; i++) {
12036 if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) {
12037 cancel_code = pthread_cancel(linksets[i].master);
12038 pthread_kill(linksets[i].master, SIGURG);
12039 ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) linksets[i].master, cancel_code);
12040 pthread_join(linksets[i].master, NULL);
12041 ast_debug(4, "Joined thread of span %d\n", i);
12044 #endif
12046 ast_mutex_lock(&monlock);
12047 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
12048 cancel_code = pthread_cancel(monitor_thread);
12049 pthread_kill(monitor_thread, SIGURG);
12050 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
12051 pthread_join(monitor_thread, NULL);
12052 ast_debug(4, "Joined monitor thread\n");
12054 monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
12056 ast_mutex_lock(&mwi_thread_lock);
12057 while (mwi_thread_count > 0) {
12058 ast_debug(3, "Waiting on %d mwi_send_thread(s) to finish\n", mwi_thread_count);
12059 ast_cond_wait(&mwi_thread_complete, &mwi_thread_lock);
12061 ast_mutex_unlock(&mwi_thread_lock);
12062 ast_mutex_lock(&ss_thread_lock);
12063 while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
12064 int x = DAHDI_FLASH;
12065 ast_debug(3, "Waiting on %d ss_thread(s) to finish\n", ss_thread_count);
12067 for (p = iflist; p; p = p->next) {
12068 if (p->owner)
12069 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */
12071 ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
12074 /* ensure any created channels before monitor threads were stopped are hungup */
12075 dahdi_softhangup_all();
12076 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
12077 destroy_all_channels();
12078 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
12080 ast_mutex_unlock(&monlock);
12082 #ifdef HAVE_PRI
12083 for (i = 0; i < NUM_SPANS; i++) {
12084 for (j = 0; j < NUM_DCHANS; j++)
12085 dahdi_close_pri_fd(&(pris[i]), j);
12088 memset(pris, 0, sizeof(pris));
12089 for (i = 0; i < NUM_SPANS; i++) {
12090 ast_mutex_init(&pris[i].lock);
12091 pris[i].offset = -1;
12092 pris[i].master = AST_PTHREADT_NULL;
12093 for (j = 0; j < NUM_DCHANS; j++)
12094 pris[i].fds[j] = -1;
12096 pri_set_error(dahdi_pri_error);
12097 pri_set_message(dahdi_pri_message);
12098 #endif
12099 #ifdef HAVE_SS7
12100 for (i = 0; i < NUM_SPANS; i++) {
12101 for (j = 0; j < NUM_DCHANS; j++)
12102 dahdi_close_ss7_fd(&(linksets[i]), j);
12105 memset(linksets, 0, sizeof(linksets));
12106 for (i = 0; i < NUM_SPANS; i++) {
12107 ast_mutex_init(&linksets[i].lock);
12108 linksets[i].master = AST_PTHREADT_NULL;
12109 for (j = 0; j < NUM_DCHANS; j++)
12110 linksets[i].fds[j] = -1;
12112 ss7_set_error(dahdi_ss7_error);
12113 ss7_set_message(dahdi_ss7_message);
12114 #endif
12116 if (setup_dahdi(2) != 0) {
12117 ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
12118 ast_mutex_unlock(&ss_thread_lock);
12119 return 1;
12121 ast_mutex_unlock(&ss_thread_lock);
12122 ast_mutex_unlock(&restart_lock);
12123 return 0;
12126 static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12128 switch (cmd) {
12129 case CLI_INIT:
12130 e->command = "dahdi restart";
12131 e->usage =
12132 "Usage: dahdi restart\n"
12133 " Restarts the DAHDI channels: destroys them all and then\n"
12134 " re-reads them from chan_dahdi.conf.\n"
12135 " Note that this will STOP any running CALL on DAHDI channels.\n"
12137 return NULL;
12138 case CLI_GENERATE:
12139 return NULL;
12141 if (a->argc != 2)
12142 return CLI_SHOWUSAGE;
12144 if (dahdi_restart() != 0)
12145 return CLI_FAILURE;
12146 return CLI_SUCCESS;
12149 static int action_dahdirestart(struct mansession *s, const struct message *m)
12151 if (dahdi_restart() != 0) {
12152 astman_send_error(s, m, "Failed rereading DAHDI configuration");
12153 return 1;
12155 astman_send_ack(s, m, "DAHDIRestart: Success");
12156 return 0;
12159 static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12161 #define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12162 #define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12163 unsigned int targetnum = 0;
12164 int filtertype = 0;
12165 struct dahdi_pvt *tmp = NULL;
12166 char tmps[20] = "";
12167 char statestr[20] = "";
12168 char blockstr[20] = "";
12169 ast_mutex_t *lock;
12170 struct dahdi_pvt *start;
12171 #ifdef HAVE_PRI
12172 int trunkgroup;
12173 struct dahdi_pri *pri = NULL;
12174 int x;
12175 #endif
12176 switch (cmd) {
12177 case CLI_INIT:
12178 e->command = "dahdi show channels [trunkgroup|group|context]";
12179 e->usage =
12180 "Usage: dahdi show channels [ trunkgroup <trunkgroup> | group <group> | context <context> ]\n"
12181 " Shows a list of available channels with optional filtering\n"
12182 " <group> must be a number between 0 and 63\n";
12183 return NULL;
12184 case CLI_GENERATE:
12185 return NULL;
12188 lock = &iflock;
12189 start = iflist;
12191 /* syntax: dahdi show channels [ group <group> | context <context> | trunkgroup <trunkgroup> ] */
12193 if (!((a->argc == 3) || (a->argc == 5)))
12194 return CLI_SHOWUSAGE;
12196 if (a->argc == 5) {
12197 #ifdef HAVE_PRI
12198 if (!strcasecmp(a->argv[3], "trunkgroup")) {
12199 /* this option requires no special handling, so leave filtertype to zero */
12200 if ((trunkgroup = atoi(a->argv[4])) < 1)
12201 return CLI_SHOWUSAGE;
12202 for (x = 0; x < NUM_SPANS; x++) {
12203 if (pris[x].trunkgroup == trunkgroup) {
12204 pri = pris + x;
12205 break;
12208 if (pri) {
12209 start = pri->crvs;
12210 lock = &pri->lock;
12211 } else {
12212 ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12213 return CLI_FAILURE;
12215 } else
12216 #endif
12217 if (!strcasecmp(a->argv[3], "group")) {
12218 targetnum = atoi(a->argv[4]);
12219 if ((targetnum < 0) || (targetnum > 63))
12220 return CLI_SHOWUSAGE;
12221 targetnum = 1 << targetnum;
12222 filtertype = 1;
12223 } else if (!strcasecmp(a->argv[3], "context")) {
12224 filtertype = 2;
12228 ast_mutex_lock(lock);
12229 #ifdef HAVE_PRI
12230 ast_cli(a->fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12231 #else
12232 ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12233 #endif
12235 tmp = start;
12236 while (tmp) {
12237 if (filtertype) {
12238 switch(filtertype) {
12239 case 1: /* dahdi show channels group <group> */
12240 if (tmp->group != targetnum) {
12241 tmp = tmp->next;
12242 continue;
12244 break;
12245 case 2: /* dahdi show channels context <context> */
12246 if (strcasecmp(tmp->context, a->argv[4])) {
12247 tmp = tmp->next;
12248 continue;
12250 break;
12251 default:
12255 if (tmp->channel > 0) {
12256 snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
12257 } else
12258 ast_copy_string(tmps, "pseudo", sizeof(tmps));
12260 if (tmp->locallyblocked)
12261 blockstr[0] = 'L';
12262 else
12263 blockstr[0] = ' ';
12265 if (tmp->remotelyblocked)
12266 blockstr[1] = 'R';
12267 else
12268 blockstr[1] = ' ';
12270 blockstr[2] = '\0';
12272 snprintf(statestr, sizeof(statestr), "%s", "In Service");
12274 ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
12275 tmp = tmp->next;
12277 ast_mutex_unlock(lock);
12278 return CLI_SUCCESS;
12279 #undef FORMAT
12280 #undef FORMAT2
12283 static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12285 int channel;
12286 struct dahdi_pvt *tmp = NULL;
12287 struct dahdi_confinfo ci;
12288 struct dahdi_params ps;
12289 int x;
12290 ast_mutex_t *lock;
12291 struct dahdi_pvt *start;
12292 #ifdef HAVE_PRI
12293 char *c;
12294 int trunkgroup;
12295 struct dahdi_pri *pri=NULL;
12296 #endif
12297 switch (cmd) {
12298 case CLI_INIT:
12299 e->command = "dahdi show channel";
12300 e->usage =
12301 "Usage: dahdi show channel <chan num>\n"
12302 " Detailed information about a given channel\n";
12303 return NULL;
12304 case CLI_GENERATE:
12305 return NULL;
12308 lock = &iflock;
12309 start = iflist;
12311 if (a->argc != 4)
12312 return CLI_SHOWUSAGE;
12313 #ifdef HAVE_PRI
12314 if ((c = strchr(a->argv[3], ':'))) {
12315 if (sscanf(a->argv[3], "%d:%d", &trunkgroup, &channel) != 2)
12316 return CLI_SHOWUSAGE;
12317 if ((trunkgroup < 1) || (channel < 1))
12318 return CLI_SHOWUSAGE;
12319 for (x = 0; x < NUM_SPANS; x++) {
12320 if (pris[x].trunkgroup == trunkgroup) {
12321 pri = pris + x;
12322 break;
12325 if (pri) {
12326 start = pri->crvs;
12327 lock = &pri->lock;
12328 } else {
12329 ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12330 return CLI_FAILURE;
12332 } else
12333 #endif
12334 channel = atoi(a->argv[3]);
12336 ast_mutex_lock(lock);
12337 tmp = start;
12338 while (tmp) {
12339 if (tmp->channel == channel) {
12340 #ifdef HAVE_PRI
12341 if (pri)
12342 ast_cli(a->fd, "Trunk/CRV: %d/%d\n", trunkgroup, tmp->channel);
12343 else
12344 #endif
12345 ast_cli(a->fd, "Channel: %d\n", tmp->channel);
12346 ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
12347 ast_cli(a->fd, "Span: %d\n", tmp->span);
12348 ast_cli(a->fd, "Extension: %s\n", tmp->exten);
12349 ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
12350 ast_cli(a->fd, "Context: %s\n", tmp->context);
12351 ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
12352 ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
12353 ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
12354 ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
12355 if (tmp->vars) {
12356 struct ast_variable *v;
12357 ast_cli(a->fd, "Variables:\n");
12358 for (v = tmp->vars ; v ; v = v->next)
12359 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
12361 ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
12362 ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
12363 ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
12364 ast_cli(a->fd, "Radio: %d\n", tmp->radio);
12365 ast_cli(a->fd, "Owner: %s\n", tmp->owner ? tmp->owner->name : "<None>");
12366 ast_cli(a->fd, "Real: %s%s%s\n", tmp->subs[SUB_REAL].owner ? tmp->subs[SUB_REAL].owner->name : "<None>", tmp->subs[SUB_REAL].inthreeway ? " (Confed)" : "", tmp->subs[SUB_REAL].linear ? " (Linear)" : "");
12367 ast_cli(a->fd, "Callwait: %s%s%s\n", tmp->subs[SUB_CALLWAIT].owner ? tmp->subs[SUB_CALLWAIT].owner->name : "<None>", tmp->subs[SUB_CALLWAIT].inthreeway ? " (Confed)" : "", tmp->subs[SUB_CALLWAIT].linear ? " (Linear)" : "");
12368 ast_cli(a->fd, "Threeway: %s%s%s\n", tmp->subs[SUB_THREEWAY].owner ? tmp->subs[SUB_THREEWAY].owner->name : "<None>", tmp->subs[SUB_THREEWAY].inthreeway ? " (Confed)" : "", tmp->subs[SUB_THREEWAY].linear ? " (Linear)" : "");
12369 ast_cli(a->fd, "Confno: %d\n", tmp->confno);
12370 ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
12371 ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
12372 ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
12373 ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
12374 if (tmp->busydetect) {
12375 #if defined(BUSYDETECT_TONEONLY)
12376 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
12377 #elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
12378 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
12379 #endif
12380 #ifdef BUSYDETECT_DEBUG
12381 ast_cli(a->fd, " Busy Detector Debug: Enabled\n");
12382 #endif
12383 ast_cli(a->fd, " Busy Count: %d\n", tmp->busycount);
12384 ast_cli(a->fd, " Busy Pattern: %d,%d\n", tmp->busy_tonelength, tmp->busy_quietlength);
12386 ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
12387 ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
12388 ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
12389 ast_cli(a->fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown");
12390 ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
12391 ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
12392 ast_cli(a->fd, "DND: %s\n", tmp->dnd ? "yes" : "no");
12393 ast_cli(a->fd, "Echo Cancellation:\n");
12395 if (tmp->echocancel.head.tap_length) {
12396 ast_cli(a->fd, "\t%d taps\n", tmp->echocancel.head.tap_length);
12397 for (x = 0; x < tmp->echocancel.head.param_count; x++) {
12398 ast_cli(a->fd, "\t\t%s: %ud\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
12400 ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
12401 } else {
12402 ast_cli(a->fd, "\tnone\n");
12404 if (tmp->master)
12405 ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
12406 for (x = 0; x < MAX_SLAVES; x++) {
12407 if (tmp->slaves[x])
12408 ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
12410 #ifdef HAVE_SS7
12411 if (tmp->ss7) {
12412 ast_cli(a->fd, "CIC: %d\n", tmp->cic);
12414 #endif
12415 #ifdef HAVE_PRI
12416 if (tmp->pri) {
12417 ast_cli(a->fd, "PRI Flags: ");
12418 if (tmp->resetting)
12419 ast_cli(a->fd, "Resetting ");
12420 if (tmp->call)
12421 ast_cli(a->fd, "Call ");
12422 if (tmp->bearer)
12423 ast_cli(a->fd, "Bearer ");
12424 ast_cli(a->fd, "\n");
12425 if (tmp->logicalspan)
12426 ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
12427 else
12428 ast_cli(a->fd, "PRI Logical Span: Implicit\n");
12431 #endif
12432 memset(&ci, 0, sizeof(ci));
12433 ps.channo = tmp->channel;
12434 if (tmp->subs[SUB_REAL].dfd > -1) {
12435 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
12436 ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, ci.confmode);
12438 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
12439 ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
12441 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
12442 ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
12443 } else {
12444 ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
12447 ast_mutex_unlock(lock);
12448 return CLI_SUCCESS;
12450 tmp = tmp->next;
12453 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
12454 ast_mutex_unlock(lock);
12455 return CLI_FAILURE;
12458 static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12460 int i, j;
12461 switch (cmd) {
12462 case CLI_INIT:
12463 e->command = "dahdi show cadences";
12464 e->usage =
12465 "Usage: dahdi show cadences\n"
12466 " Shows all cadences currently defined\n";
12467 return NULL;
12468 case CLI_GENERATE:
12469 return NULL;
12471 for (i = 0; i < num_cadence; i++) {
12472 char output[1024];
12473 char tmp[16], tmp2[64];
12474 snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
12475 term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
12477 for (j = 0; j < 16; j++) {
12478 if (cadences[i].ringcadence[j] == 0)
12479 break;
12480 snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
12481 if (cidrings[i] * 2 - 1 == j)
12482 term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
12483 else
12484 term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
12485 if (j != 0)
12486 strncat(output, ",", sizeof(output) - strlen(output) - 1);
12487 strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
12489 ast_cli(a->fd,"%s\n",output);
12491 return CLI_SUCCESS;
12494 /* Based on irqmiss.c */
12495 static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12497 #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
12498 #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
12499 int span;
12500 int res;
12501 char alarmstr[50];
12503 int ctl;
12504 struct dahdi_spaninfo s;
12506 switch (cmd) {
12507 case CLI_INIT:
12508 e->command = "dahdi show status";
12509 e->usage =
12510 "Usage: dahdi show status\n"
12511 " Shows a list of DAHDI cards with status\n";
12512 return NULL;
12513 case CLI_GENERATE:
12514 return NULL;
12516 ctl = open("/dev/dahdi/ctl", O_RDWR);
12517 if (ctl < 0) {
12518 ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
12519 return CLI_FAILURE;
12521 ast_cli(a->fd, FORMAT2, "Description", "Alarms", "IRQ", "bpviol", "CRC4", "Framing", "Coding", "Options", "LBO");
12523 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
12524 s.spanno = span;
12525 res = ioctl(ctl, DAHDI_SPANSTAT, &s);
12526 if (res) {
12527 continue;
12529 alarmstr[0] = '\0';
12530 if (s.alarms > 0) {
12531 if (s.alarms & DAHDI_ALARM_BLUE)
12532 strcat(alarmstr, "BLU/");
12533 if (s.alarms & DAHDI_ALARM_YELLOW)
12534 strcat(alarmstr, "YEL/");
12535 if (s.alarms & DAHDI_ALARM_RED)
12536 strcat(alarmstr, "RED/");
12537 if (s.alarms & DAHDI_ALARM_LOOPBACK)
12538 strcat(alarmstr, "LB/");
12539 if (s.alarms & DAHDI_ALARM_RECOVER)
12540 strcat(alarmstr, "REC/");
12541 if (s.alarms & DAHDI_ALARM_NOTOPEN)
12542 strcat(alarmstr, "NOP/");
12543 if (!strlen(alarmstr))
12544 strcat(alarmstr, "UUU/");
12545 if (strlen(alarmstr)) {
12546 /* Strip trailing / */
12547 alarmstr[strlen(alarmstr) - 1] = '\0';
12549 } else {
12550 if (s.numchans)
12551 strcpy(alarmstr, "OK");
12552 else
12553 strcpy(alarmstr, "UNCONFIGURED");
12556 ast_cli(a->fd, FORMAT, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count
12557 , s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
12558 s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
12559 s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
12560 "CAS"
12561 , s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
12562 s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
12563 s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
12564 "Unk"
12565 , s.lineconfig & DAHDI_CONFIG_CRC4 ?
12566 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : "YEL"
12567 , lbostr[s.lbo]
12570 close(ctl);
12572 return CLI_SUCCESS;
12573 #undef FORMAT
12574 #undef FORMAT2
12577 static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12579 int pseudo_fd = -1;
12580 struct dahdi_versioninfo vi;
12582 switch (cmd) {
12583 case CLI_INIT:
12584 e->command = "dahdi show version";
12585 e->usage =
12586 "Usage: dahdi show version\n"
12587 " Shows the DAHDI version in use\n";
12588 return NULL;
12589 case CLI_GENERATE:
12590 return NULL;
12592 if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
12593 ast_cli(a->fd, "Failed to open control file to get version.\n");
12594 return CLI_SUCCESS;
12597 strcpy(vi.version, "Unknown");
12598 strcpy(vi.echo_canceller, "Unknown");
12600 if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
12601 ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
12602 else
12603 ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
12605 close(pseudo_fd);
12607 return CLI_SUCCESS;
12610 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12612 int channel;
12613 int gain;
12614 int tx;
12615 struct dahdi_hwgain hwgain;
12616 struct dahdi_pvt *tmp = NULL;
12618 switch (cmd) {
12619 case CLI_INIT:
12620 e->command = "dahdi set hwgain";
12621 e->usage =
12622 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
12623 " Sets the hardware gain on a a given channel, overriding the\n"
12624 " value provided at module loadtime, whether the channel is in\n"
12625 " use or not. Changes take effect immediately.\n"
12626 " <rx|tx> which direction do you want to change (relative to our module)\n"
12627 " <chan num> is the channel number relative to the device\n"
12628 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
12629 return NULL;
12630 case CLI_GENERATE:
12631 return NULL;
12634 if (a->argc != 6)
12635 return CLI_SHOWUSAGE;
12637 if (!strcasecmp("rx", a->argv[3]))
12638 tx = 0; /* rx */
12639 else if (!strcasecmp("tx", a->argv[3]))
12640 tx = 1; /* tx */
12641 else
12642 return CLI_SHOWUSAGE;
12644 channel = atoi(a->argv[4]);
12645 gain = atof(a->argv[5])*10.0;
12647 ast_mutex_lock(&iflock);
12649 for (tmp = iflist; tmp; tmp = tmp->next) {
12651 if (tmp->channel != channel)
12652 continue;
12654 if (tmp->subs[SUB_REAL].dfd == -1)
12655 break;
12657 hwgain.newgain = gain;
12658 hwgain.tx = tx;
12659 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
12660 ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
12661 ast_mutex_unlock(&iflock);
12662 return CLI_FAILURE;
12664 ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
12665 tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
12666 break;
12669 ast_mutex_unlock(&iflock);
12671 if (tmp)
12672 return CLI_SUCCESS;
12674 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
12675 return CLI_FAILURE;
12679 static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12681 int channel;
12682 float gain;
12683 int tx;
12684 int res;
12685 ast_mutex_t *lock;
12686 struct dahdi_pvt *tmp = NULL;
12688 switch (cmd) {
12689 case CLI_INIT:
12690 e->command = "dahdi set swgain";
12691 e->usage =
12692 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
12693 " Sets the software gain on a a given channel, overriding the\n"
12694 " value provided at module loadtime, whether the channel is in\n"
12695 " use or not. Changes take effect immediately.\n"
12696 " <rx|tx> which direction do you want to change (relative to our module)\n"
12697 " <chan num> is the channel number relative to the device\n"
12698 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
12699 return NULL;
12700 case CLI_GENERATE:
12701 return NULL;
12704 lock = &iflock;
12706 if (a->argc != 6)
12707 return CLI_SHOWUSAGE;
12709 if (!strcasecmp("rx", a->argv[3]))
12710 tx = 0; /* rx */
12711 else if (!strcasecmp("tx", a->argv[3]))
12712 tx = 1; /* tx */
12713 else
12714 return CLI_SHOWUSAGE;
12716 channel = atoi(a->argv[4]);
12717 gain = atof(a->argv[5]);
12719 ast_mutex_lock(lock);
12720 for (tmp = iflist; tmp; tmp = tmp->next) {
12722 if (tmp->channel != channel)
12723 continue;
12725 if (tmp->subs[SUB_REAL].dfd == -1)
12726 break;
12728 if (tx)
12729 res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
12730 else
12731 res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
12733 if (res) {
12734 ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
12735 ast_mutex_unlock(lock);
12736 return CLI_FAILURE;
12739 ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
12740 tx ? "tx" : "rx", gain, channel);
12741 break;
12743 ast_mutex_unlock(lock);
12745 if (tmp)
12746 return CLI_SUCCESS;
12748 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
12749 return CLI_FAILURE;
12753 static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12755 int channel;
12756 int on;
12757 struct dahdi_pvt *dahdi_chan = NULL;
12759 switch (cmd) {
12760 case CLI_INIT:
12761 e->command = "dahdi set dnd";
12762 e->usage =
12763 "Usage: dahdi set dnd <chan#> <on|off>\n"
12764 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
12765 " Changes take effect immediately.\n"
12766 " <chan num> is the channel number\n"
12767 " <on|off> Enable or disable DND mode?\n"
12769 return NULL;
12770 case CLI_GENERATE:
12771 return NULL;
12774 if (a->argc != 5)
12775 return CLI_SHOWUSAGE;
12777 if ((channel = atoi(a->argv[3])) <= 0) {
12778 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
12779 return CLI_SHOWUSAGE;
12782 if (ast_true(a->argv[4]))
12783 on = 1;
12784 else if (ast_false(a->argv[4]))
12785 on = 0;
12786 else {
12787 ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
12788 return CLI_SHOWUSAGE;
12791 ast_mutex_lock(&iflock);
12792 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
12793 if (dahdi_chan->channel != channel)
12794 continue;
12796 /* Found the channel. Actually set it */
12797 dahdi_dnd(dahdi_chan, on);
12798 break;
12800 ast_mutex_unlock(&iflock);
12802 if (!dahdi_chan) {
12803 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
12804 return CLI_FAILURE;
12807 return CLI_SUCCESS;
12810 static struct ast_cli_entry dahdi_cli[] = {
12811 AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
12812 AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
12813 AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
12814 AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
12815 AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
12816 AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
12817 AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
12818 AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
12819 AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
12820 AST_CLI_DEFINE(dahdi_set_dnd, "Set software gain on a channel"),
12823 #define TRANSFER 0
12824 #define HANGUP 1
12826 static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
12828 if (p) {
12829 switch (mode) {
12830 case TRANSFER:
12831 p->fake_event = DAHDI_EVENT_WINKFLASH;
12832 break;
12833 case HANGUP:
12834 p->fake_event = DAHDI_EVENT_ONHOOK;
12835 break;
12836 default:
12837 ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name);
12840 return 0;
12842 static struct dahdi_pvt *find_channel(int channel)
12844 struct dahdi_pvt *p = iflist;
12845 while (p) {
12846 if (p->channel == channel) {
12847 break;
12849 p = p->next;
12851 return p;
12854 static int action_dahdidndon(struct mansession *s, const struct message *m)
12856 struct dahdi_pvt *p = NULL;
12857 const char *channel = astman_get_header(m, "DAHDIChannel");
12859 if (ast_strlen_zero(channel)) {
12860 astman_send_error(s, m, "No channel specified");
12861 return 0;
12863 p = find_channel(atoi(channel));
12864 if (!p) {
12865 astman_send_error(s, m, "No such channel");
12866 return 0;
12868 p->dnd = 1;
12869 astman_send_ack(s, m, "DND Enabled");
12870 return 0;
12873 static int action_dahdidndoff(struct mansession *s, const struct message *m)
12875 struct dahdi_pvt *p = NULL;
12876 const char *channel = astman_get_header(m, "DAHDIChannel");
12878 if (ast_strlen_zero(channel)) {
12879 astman_send_error(s, m, "No channel specified");
12880 return 0;
12882 p = find_channel(atoi(channel));
12883 if (!p) {
12884 astman_send_error(s, m, "No such channel");
12885 return 0;
12887 p->dnd = 0;
12888 astman_send_ack(s, m, "DND Disabled");
12889 return 0;
12892 static int action_transfer(struct mansession *s, const struct message *m)
12894 struct dahdi_pvt *p = NULL;
12895 const char *channel = astman_get_header(m, "DAHDIChannel");
12897 if (ast_strlen_zero(channel)) {
12898 astman_send_error(s, m, "No channel specified");
12899 return 0;
12901 p = find_channel(atoi(channel));
12902 if (!p) {
12903 astman_send_error(s, m, "No such channel");
12904 return 0;
12906 dahdi_fake_event(p,TRANSFER);
12907 astman_send_ack(s, m, "DAHDITransfer");
12908 return 0;
12911 static int action_transferhangup(struct mansession *s, const struct message *m)
12913 struct dahdi_pvt *p = NULL;
12914 const char *channel = astman_get_header(m, "DAHDIChannel");
12916 if (ast_strlen_zero(channel)) {
12917 astman_send_error(s, m, "No channel specified");
12918 return 0;
12920 p = find_channel(atoi(channel));
12921 if (!p) {
12922 astman_send_error(s, m, "No such channel");
12923 return 0;
12925 dahdi_fake_event(p,HANGUP);
12926 astman_send_ack(s, m, "DAHDIHangup");
12927 return 0;
12930 static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
12932 struct dahdi_pvt *p = NULL;
12933 const char *channel = astman_get_header(m, "DAHDIChannel");
12934 const char *number = astman_get_header(m, "Number");
12935 int i;
12937 if (ast_strlen_zero(channel)) {
12938 astman_send_error(s, m, "No channel specified");
12939 return 0;
12941 if (ast_strlen_zero(number)) {
12942 astman_send_error(s, m, "No number specified");
12943 return 0;
12945 p = find_channel(atoi(channel));
12946 if (!p) {
12947 astman_send_error(s, m, "No such channel");
12948 return 0;
12950 if (!p->owner) {
12951 astman_send_error(s, m, "Channel does not have it's owner");
12952 return 0;
12954 for (i = 0; i < strlen(number); i++) {
12955 struct ast_frame f = { AST_FRAME_DTMF, number[i] };
12956 dahdi_queue_frame(p, &f, NULL);
12958 astman_send_ack(s, m, "DAHDIDialOffhook");
12959 return 0;
12962 static int action_dahdishowchannels(struct mansession *s, const struct message *m)
12964 struct dahdi_pvt *tmp = NULL;
12965 const char *id = astman_get_header(m, "ActionID");
12966 const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
12967 char idText[256] = "";
12968 int channels = 0;
12969 int dahdichanquery = -1;
12970 if (!ast_strlen_zero(dahdichannel)) {
12971 dahdichanquery = atoi(dahdichannel);
12974 astman_send_ack(s, m, "DAHDI channel status will follow");
12975 if (!ast_strlen_zero(id))
12976 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
12978 ast_mutex_lock(&iflock);
12980 tmp = iflist;
12981 while (tmp) {
12982 if (tmp->channel > 0) {
12983 int alm = get_alarms(tmp);
12985 /* If a specific channel is queried for, only deliver status for that channel */
12986 if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
12987 continue;
12989 channels++;
12990 if (tmp->owner) {
12991 /* Add data if we have a current call */
12992 astman_append(s,
12993 "Event: DAHDIShowChannels\r\n"
12994 "DAHDIChannel: %d\r\n"
12995 "Channel: %s\r\n"
12996 "Uniqueid: %s\r\n"
12997 "AccountCode: %s\r\n"
12998 "Signalling: %s\r\n"
12999 "SignallingCode: %d\r\n"
13000 "Context: %s\r\n"
13001 "DND: %s\r\n"
13002 "Alarm: %s\r\n"
13003 "%s"
13004 "\r\n",
13005 tmp->channel,
13006 tmp->owner->name,
13007 tmp->owner->uniqueid,
13008 tmp->owner->accountcode,
13009 sig2str(tmp->sig),
13010 tmp->sig,
13011 tmp->context,
13012 tmp->dnd ? "Enabled" : "Disabled",
13013 alarm2str(alm), idText);
13014 } else {
13015 astman_append(s,
13016 "Event: DAHDIShowChannels\r\n"
13017 "DAHDIChannel: %d\r\n"
13018 "Signalling: %s\r\n"
13019 "SignallingCode: %d\r\n"
13020 "Context: %s\r\n"
13021 "DND: %s\r\n"
13022 "Alarm: %s\r\n"
13023 "%s"
13024 "\r\n",
13025 tmp->channel, sig2str(tmp->sig), tmp->sig,
13026 tmp->context,
13027 tmp->dnd ? "Enabled" : "Disabled",
13028 alarm2str(alm), idText);
13032 tmp = tmp->next;
13035 ast_mutex_unlock(&iflock);
13037 astman_append(s,
13038 "Event: DAHDIShowChannelsComplete\r\n"
13039 "%s"
13040 "Items: %d\r\n"
13041 "\r\n",
13042 idText,
13043 channels);
13044 return 0;
13047 #ifdef HAVE_SS7
13048 static int linkset_addsigchan(int sigchan)
13050 struct dahdi_ss7 *link;
13051 int res;
13052 int curfd;
13053 struct dahdi_params p;
13054 struct dahdi_bufferinfo bi;
13055 struct dahdi_spaninfo si;
13058 link = ss7_resolve_linkset(cur_linkset);
13059 if (!link) {
13060 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
13061 return -1;
13064 if (cur_ss7type < 0) {
13065 ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
13066 return -1;
13069 if (!link->ss7)
13070 link->ss7 = ss7_new(cur_ss7type);
13072 if (!link->ss7) {
13073 ast_log(LOG_ERROR, "Can't create new SS7!\n");
13074 return -1;
13077 link->type = cur_ss7type;
13079 if (cur_pointcode < 0) {
13080 ast_log(LOG_ERROR, "Unspecified pointcode!\n");
13081 return -1;
13082 } else
13083 ss7_set_pc(link->ss7, cur_pointcode);
13085 if (sigchan < 0) {
13086 ast_log(LOG_ERROR, "Invalid sigchan!\n");
13087 return -1;
13088 } else {
13089 if (link->numsigchans >= NUM_DCHANS) {
13090 ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
13091 return -1;
13093 curfd = link->numsigchans;
13095 link->fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
13096 if ((link->fds[curfd] < 0) || (ioctl(link->fds[curfd],DAHDI_SPECIFY,&sigchan) == -1)) {
13097 ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan, strerror(errno));
13098 return -1;
13100 res = ioctl(link->fds[curfd], DAHDI_GET_PARAMS, &p);
13101 if (res) {
13102 dahdi_close_ss7_fd(link, curfd);
13103 ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan, strerror(errno));
13104 return -1;
13106 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC) && (p.sigtype != DAHDI_SIG_MTP2)) {
13107 dahdi_close_ss7_fd(link, curfd);
13108 ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
13109 return -1;
13112 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
13113 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
13114 bi.numbufs = 32;
13115 bi.bufsize = 512;
13117 if (ioctl(link->fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
13118 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", sigchan, strerror(errno));
13119 dahdi_close_ss7_fd(link, curfd);
13120 return -1;
13123 if (p.sigtype == DAHDI_SIG_MTP2)
13124 ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIMTP2, link->fds[curfd]);
13125 else
13126 ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIDCHAN, link->fds[curfd]);
13128 link->numsigchans++;
13130 memset(&si, 0, sizeof(si));
13131 res = ioctl(link->fds[curfd], DAHDI_SPANSTAT, &si);
13132 if (res) {
13133 dahdi_close_ss7_fd(link, curfd);
13134 ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan, strerror(errno));
13137 if (!si.alarms) {
13138 link->linkstate[curfd] = LINKSTATE_DOWN;
13139 ss7_link_noalarm(link->ss7, link->fds[curfd]);
13140 } else {
13141 link->linkstate[curfd] = LINKSTATE_DOWN | LINKSTATE_INALARM;
13142 ss7_link_alarm(link->ss7, link->fds[curfd]);
13146 if (cur_adjpointcode < 0) {
13147 ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
13148 return -1;
13149 } else {
13150 ss7_set_adjpc(link->ss7, link->fds[curfd], cur_adjpointcode);
13153 if (cur_defaultdpc < 0) {
13154 ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
13155 return -1;
13158 if (cur_networkindicator < 0) {
13159 ast_log(LOG_ERROR, "Invalid networkindicator!\n");
13160 return -1;
13161 } else
13162 ss7_set_network_ind(link->ss7, cur_networkindicator);
13164 return 0;
13167 static char *handle_ss7_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13169 int span;
13170 switch (cmd) {
13171 case CLI_INIT:
13172 e->command = "ss7 no debug linkset";
13173 e->usage =
13174 "Usage: ss7 no debug linkset <span>\n"
13175 " Disables debugging on a given SS7 linkset\n";
13176 return NULL;
13177 case CLI_GENERATE:
13178 return NULL;
13180 if (a->argc < 5)
13181 return CLI_SHOWUSAGE;
13182 span = atoi(a->argv[4]);
13183 if ((span < 1) || (span > NUM_SPANS)) {
13184 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[4], 1, NUM_SPANS);
13185 return CLI_SUCCESS;
13187 if (!linksets[span-1].ss7) {
13188 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13189 return CLI_SUCCESS;
13191 if (linksets[span-1].ss7)
13192 ss7_set_debug(linksets[span-1].ss7, 0);
13194 ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
13195 return CLI_SUCCESS;
13198 static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13200 int span;
13201 switch (cmd) {
13202 case CLI_INIT:
13203 e->command = "ss7 debug linkset";
13204 e->usage =
13205 "Usage: ss7 debug linkset <linkset>\n"
13206 " Enables debugging on a given SS7 linkset\n";
13207 return NULL;
13208 case CLI_GENERATE:
13209 return NULL;
13211 if (a->argc < 4)
13212 return CLI_SHOWUSAGE;
13213 span = atoi(a->argv[3]);
13214 if ((span < 1) || (span > NUM_SPANS)) {
13215 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
13216 return CLI_SUCCESS;
13218 if (!linksets[span-1].ss7) {
13219 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13220 return CLI_SUCCESS;
13222 if (linksets[span-1].ss7)
13223 ss7_set_debug(linksets[span-1].ss7, SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP);
13225 ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
13226 return CLI_SUCCESS;
13229 static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13231 int linkset, cic;
13232 int blocked = -1, i;
13233 switch (cmd) {
13234 case CLI_INIT:
13235 e->command = "ss7 block cic";
13236 e->usage =
13237 "Usage: ss7 block cic <linkset> <CIC>\n"
13238 " Sends a remote blocking request for the given CIC on the specified linkset\n";
13239 return NULL;
13240 case CLI_GENERATE:
13241 return NULL;
13243 if (a->argc == 5)
13244 linkset = atoi(a->argv[3]);
13245 else
13246 return CLI_SHOWUSAGE;
13248 if ((linkset < 1) || (linkset > NUM_SPANS)) {
13249 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13250 return CLI_SUCCESS;
13253 if (!linksets[linkset-1].ss7) {
13254 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13255 return CLI_SUCCESS;
13258 cic = atoi(a->argv[4]);
13260 if (cic < 1) {
13261 ast_cli(a->fd, "Invalid CIC specified!\n");
13262 return CLI_SUCCESS;
13265 for (i = 0; i < linksets[linkset-1].numchans; i++) {
13266 if (linksets[linkset-1].pvts[i]->cic == cic) {
13267 blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13268 if (!blocked) {
13269 ast_mutex_lock(&linksets[linkset-1].lock);
13270 isup_blo(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13271 ast_mutex_unlock(&linksets[linkset-1].lock);
13276 if (blocked < 0) {
13277 ast_cli(a->fd, "Invalid CIC specified!\n");
13278 return CLI_SUCCESS;
13281 if (!blocked)
13282 ast_cli(a->fd, "Sent blocking request for linkset %d on CIC %d\n", linkset, cic);
13283 else
13284 ast_cli(a->fd, "CIC %d already locally blocked\n", cic);
13286 /* Break poll on the linkset so it sends our messages */
13287 pthread_kill(linksets[linkset-1].master, SIGURG);
13289 return CLI_SUCCESS;
13292 static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13294 int linkset;
13295 int i;
13296 switch (cmd) {
13297 case CLI_INIT:
13298 e->command = "ss7 block linkset";
13299 e->usage =
13300 "Usage: ss7 block linkset <linkset number>\n"
13301 " Sends a remote blocking request for all CICs on the given linkset\n";
13302 return NULL;
13303 case CLI_GENERATE:
13304 return NULL;
13306 if (a->argc == 4)
13307 linkset = atoi(a->argv[3]);
13308 else
13309 return CLI_SHOWUSAGE;
13311 if ((linkset < 1) || (linkset > NUM_SPANS)) {
13312 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13313 return CLI_SUCCESS;
13316 if (!linksets[linkset-1].ss7) {
13317 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13318 return CLI_SUCCESS;
13321 for (i = 0; i < linksets[linkset-1].numchans; i++) {
13322 ast_cli(a->fd, "Sending remote blocking request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13323 ast_mutex_lock(&linksets[linkset-1].lock);
13324 isup_blo(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13325 ast_mutex_unlock(&linksets[linkset-1].lock);
13328 /* Break poll on the linkset so it sends our messages */
13329 pthread_kill(linksets[linkset-1].master, SIGURG);
13331 return CLI_SUCCESS;
13334 static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13336 int linkset, cic;
13337 int i, blocked = -1;
13338 switch (cmd) {
13339 case CLI_INIT:
13340 e->command = "ss7 unblock cic";
13341 e->usage =
13342 "Usage: ss7 unblock cic <linkset> <CIC>\n"
13343 " Sends a remote unblocking request for the given CIC on the specified linkset\n";
13344 return NULL;
13345 case CLI_GENERATE:
13346 return NULL;
13349 if (a->argc == 5)
13350 linkset = atoi(a->argv[3]);
13351 else
13352 return CLI_SHOWUSAGE;
13354 if ((linkset < 1) || (linkset > NUM_SPANS)) {
13355 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13356 return CLI_SUCCESS;
13359 if (!linksets[linkset-1].ss7) {
13360 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13361 return CLI_SUCCESS;
13364 cic = atoi(a->argv[4]);
13366 if (cic < 1) {
13367 ast_cli(a->fd, "Invalid CIC specified!\n");
13368 return CLI_SUCCESS;
13371 for (i = 0; i < linksets[linkset-1].numchans; i++) {
13372 if (linksets[linkset-1].pvts[i]->cic == cic) {
13373 blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13374 if (blocked) {
13375 ast_mutex_lock(&linksets[linkset-1].lock);
13376 isup_ubl(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13377 ast_mutex_unlock(&linksets[linkset-1].lock);
13382 if (blocked > 0)
13383 ast_cli(a->fd, "Sent unblocking request for linkset %d on CIC %d\n", linkset, cic);
13385 /* Break poll on the linkset so it sends our messages */
13386 pthread_kill(linksets[linkset-1].master, SIGURG);
13388 return CLI_SUCCESS;
13391 static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13393 int linkset;
13394 int i;
13395 switch (cmd) {
13396 case CLI_INIT:
13397 e->command = "ss7 unblock linkset";
13398 e->usage =
13399 "Usage: ss7 unblock linkset <linkset number>\n"
13400 " Sends a remote unblocking request for all CICs on the specified linkset\n";
13401 return NULL;
13402 case CLI_GENERATE:
13403 return NULL;
13406 if (a->argc == 4)
13407 linkset = atoi(a->argv[3]);
13408 else
13409 return CLI_SHOWUSAGE;
13411 if ((linkset < 1) || (linkset > NUM_SPANS)) {
13412 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13413 return CLI_SUCCESS;
13416 if (!linksets[linkset-1].ss7) {
13417 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13418 return CLI_SUCCESS;
13421 for (i = 0; i < linksets[linkset-1].numchans; i++) {
13422 ast_cli(a->fd, "Sending remote unblock request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13423 ast_mutex_lock(&linksets[linkset-1].lock);
13424 isup_ubl(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13425 ast_mutex_unlock(&linksets[linkset-1].lock);
13428 /* Break poll on the linkset so it sends our messages */
13429 pthread_kill(linksets[linkset-1].master, SIGURG);
13431 return CLI_SUCCESS;
13434 static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13436 int linkset;
13437 struct dahdi_ss7 *ss7;
13438 switch (cmd) {
13439 case CLI_INIT:
13440 e->command = "ss7 show linkset";
13441 e->usage =
13442 "Usage: ss7 show linkset <span>\n"
13443 " Shows the status of an SS7 linkset.\n";
13444 return NULL;
13445 case CLI_GENERATE:
13446 return NULL;
13449 if (a->argc < 4)
13450 return CLI_SHOWUSAGE;
13451 linkset = atoi(a->argv[3]);
13452 if ((linkset < 1) || (linkset > NUM_SPANS)) {
13453 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13454 return CLI_SUCCESS;
13456 if (!linksets[linkset-1].ss7) {
13457 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13458 return CLI_SUCCESS;
13460 if (linksets[linkset-1].ss7)
13461 ss7 = &linksets[linkset-1];
13463 ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
13465 return CLI_SUCCESS;
13468 static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13470 switch (cmd) {
13471 case CLI_INIT:
13472 e->command = "ss7 show version";
13473 return NULL;
13474 case CLI_GENERATE:
13475 return NULL;
13478 ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
13480 return CLI_SUCCESS;
13483 static struct ast_cli_entry dahdi_ss7_cli[] = {
13484 AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
13485 AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"),
13486 AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"),
13487 AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"),
13488 AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
13489 AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
13490 AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
13491 AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
13493 #endif /* HAVE_SS7 */
13495 static int __unload_module(void)
13497 struct dahdi_pvt *p;
13498 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13499 int i, j;
13500 #endif
13502 #ifdef HAVE_PRI
13503 for (i = 0; i < NUM_SPANS; i++) {
13504 if (pris[i].master != AST_PTHREADT_NULL)
13505 pthread_cancel(pris[i].master);
13507 ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
13508 ast_unregister_application(dahdi_send_keypad_facility_app);
13509 #endif
13510 #if defined(HAVE_SS7)
13511 for (i = 0; i < NUM_SPANS; i++) {
13512 if (linksets[i].master != AST_PTHREADT_NULL)
13513 pthread_cancel(linksets[i].master);
13515 ast_cli_unregister_multiple(dahdi_ss7_cli, sizeof(dahdi_ss7_cli) / sizeof(struct ast_cli_entry));
13516 #endif
13518 ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
13519 ast_manager_unregister( "DAHDIDialOffhook" );
13520 ast_manager_unregister( "DAHDIHangup" );
13521 ast_manager_unregister( "DAHDITransfer" );
13522 ast_manager_unregister( "DAHDIDNDoff" );
13523 ast_manager_unregister( "DAHDIDNDon" );
13524 ast_manager_unregister("DAHDIShowChannels");
13525 ast_manager_unregister("DAHDIRestart");
13526 ast_channel_unregister(&dahdi_tech);
13527 ast_mutex_lock(&iflock);
13528 /* Hangup all interfaces if they have an owner */
13529 p = iflist;
13530 while (p) {
13531 if (p->owner)
13532 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
13533 p = p->next;
13535 ast_mutex_unlock(&iflock);
13536 ast_mutex_lock(&monlock);
13537 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
13538 pthread_cancel(monitor_thread);
13539 pthread_kill(monitor_thread, SIGURG);
13540 pthread_join(monitor_thread, NULL);
13542 monitor_thread = AST_PTHREADT_STOP;
13543 ast_mutex_unlock(&monlock);
13545 destroy_all_channels();
13547 #if defined(HAVE_PRI)
13548 for (i = 0; i < NUM_SPANS; i++) {
13549 if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL))
13550 pthread_join(pris[i].master, NULL);
13551 for (j = 0; j < NUM_DCHANS; j++) {
13552 dahdi_close_pri_fd(&(pris[i]), j);
13555 #endif
13557 #if defined(HAVE_SS7)
13558 for (i = 0; i < NUM_SPANS; i++) {
13559 if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL))
13560 pthread_join(linksets[i].master, NULL);
13561 for (j = 0; j < NUM_DCHANS; j++) {
13562 dahdi_close_ss7_fd(&(linksets[i]), j);
13565 #endif
13567 ast_cond_destroy(&mwi_thread_complete);
13568 ast_cond_destroy(&ss_thread_complete);
13569 return 0;
13572 static int unload_module(void)
13574 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13575 int y;
13576 #endif
13577 #ifdef HAVE_PRI
13578 for (y = 0; y < NUM_SPANS; y++)
13579 ast_mutex_destroy(&pris[y].lock);
13580 #endif
13581 #ifdef HAVE_SS7
13582 for (y = 0; y < NUM_SPANS; y++)
13583 ast_mutex_destroy(&linksets[y].lock);
13584 #endif /* HAVE_SS7 */
13585 return __unload_module();
13588 static int build_channels(struct dahdi_chan_conf *conf, int iscrv, const char *value, int reload, int lineno, int *found_pseudo)
13590 char *c, *chan;
13591 int x, start, finish;
13592 struct dahdi_pvt *tmp;
13593 #ifdef HAVE_PRI
13594 struct dahdi_pri *pri;
13595 int trunkgroup, y;
13596 #endif
13598 if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
13599 ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
13600 return -1;
13603 c = ast_strdupa(value);
13605 #ifdef HAVE_PRI
13606 pri = NULL;
13607 if (iscrv) {
13608 if (sscanf(c, "%d:%n", &trunkgroup, &y) != 1) {
13609 ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d.\n", lineno);
13610 return -1;
13612 if (trunkgroup < 1) {
13613 ast_log(LOG_WARNING, "CRV trunk group must be a positive number at line %d.\n", lineno);
13614 return -1;
13616 c += y;
13617 for (y = 0; y < NUM_SPANS; y++) {
13618 if (pris[y].trunkgroup == trunkgroup) {
13619 pri = pris + y;
13620 break;
13623 if (!pri) {
13624 ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d.\n", trunkgroup, lineno);
13625 return -1;
13628 #endif
13630 while ((chan = strsep(&c, ","))) {
13631 if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
13632 /* Range */
13633 } else if (sscanf(chan, "%d", &start)) {
13634 /* Just one */
13635 finish = start;
13636 } else if (!strcasecmp(chan, "pseudo")) {
13637 finish = start = CHAN_PSEUDO;
13638 if (found_pseudo)
13639 *found_pseudo = 1;
13640 } else {
13641 ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
13642 return -1;
13644 if (finish < start) {
13645 ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
13646 x = finish;
13647 finish = start;
13648 start = x;
13651 for (x = start; x <= finish; x++) {
13652 #ifdef HAVE_PRI
13653 tmp = mkintf(x, conf, pri, reload);
13654 #else
13655 tmp = mkintf(x, conf, NULL, reload);
13656 #endif
13658 if (tmp) {
13659 #ifdef HAVE_PRI
13660 if (pri)
13661 ast_verb(3, "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig));
13662 else
13663 #endif
13664 ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
13665 } else {
13666 ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
13667 (reload == 1) ? "reconfigure" : "register", value);
13668 return -1;
13673 return 0;
13676 /** The length of the parameters list of 'dahdichan'.
13677 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
13678 #define MAX_CHANLIST_LEN 80
13680 static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
13682 char *parse = ast_strdupa(data);
13683 char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
13684 unsigned int param_count;
13685 unsigned int x;
13687 if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
13688 return;
13690 memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
13692 /* first parameter is tap length, process it here */
13694 x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
13696 if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
13697 confp->chan.echocancel.head.tap_length = x;
13698 else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
13699 confp->chan.echocancel.head.tap_length = 128;
13701 /* now process any remaining parameters */
13703 for (x = 1; x < param_count; x++) {
13704 struct {
13705 char *name;
13706 char *value;
13707 } param;
13709 if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
13710 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, params[x]);
13711 continue;
13714 if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
13715 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, param.name);
13716 continue;
13719 strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
13721 if (param.value) {
13722 if (sscanf(param.value, "%d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
13723 ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %d: '%s'\n", line, param.value);
13724 continue;
13727 confp->chan.echocancel.head.param_count++;
13731 /*! process_dahdi() - ignore keyword 'channel' and similar */
13732 #define PROC_DAHDI_OPT_NOCHAN (1 << 0)
13733 /*! process_dahdi() - No warnings on non-existing cofiguration keywords */
13734 #define PROC_DAHDI_OPT_NOWARN (1 << 1)
13736 static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
13738 struct dahdi_pvt *tmp;
13739 int y;
13740 int found_pseudo = 0;
13741 char dahdichan[MAX_CHANLIST_LEN] = {};
13743 for (; v; v = v->next) {
13744 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
13745 continue;
13747 /* must have parkinglot in confp before build_channels is called */
13748 if (!strcasecmp(v->name, "parkinglot")) {
13749 ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
13752 /* Create the interface list */
13753 if (!strcasecmp(v->name, "channel")
13754 #ifdef HAVE_PRI
13755 || !strcasecmp(v->name, "crv")
13756 #endif
13758 int iscrv;
13759 if (options && PROC_DAHDI_OPT_NOCHAN)
13760 continue;
13761 iscrv = !strcasecmp(v->name, "crv");
13762 if (build_channels(confp, iscrv, v->value, reload, v->lineno, &found_pseudo))
13763 return -1;
13764 } else if (!strcasecmp(v->name, "buffers")) {
13765 int res;
13766 char policy[8] = "";
13767 res = sscanf(v->value, "%d,%s", &confp->chan.buf_no, policy);
13768 if (res != 2) {
13769 ast_log(LOG_WARNING, "Parsing buffers option data failed, using defaults.\n");
13770 confp->chan.buf_no = numbufs;
13771 continue;
13773 if (confp->chan.buf_no < 0)
13774 confp->chan.buf_no = numbufs;
13775 if (!strcasecmp(policy, "full")) {
13776 confp->chan.buf_policy = DAHDI_POLICY_WHEN_FULL;
13777 } else if (!strcasecmp(policy, "half")) {
13778 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE /*HALF_FULL*/;
13779 } else if (!strcasecmp(policy, "immediate")) {
13780 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
13781 } else {
13782 ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy);
13784 } else if (!strcasecmp(v->name, "dahdichan")) {
13785 ast_copy_string(dahdichan, v->value, sizeof(dahdichan));
13786 } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
13787 usedistinctiveringdetection = ast_true(v->value);
13788 } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
13789 distinctiveringaftercid = ast_true(v->value);
13790 } else if (!strcasecmp(v->name, "dring1context")) {
13791 ast_copy_string(confp->chan.drings.ringContext[0].contextData,v->value,sizeof(confp->chan.drings.ringContext[0].contextData));
13792 } else if (!strcasecmp(v->name, "dring2context")) {
13793 ast_copy_string(confp->chan.drings.ringContext[1].contextData,v->value,sizeof(confp->chan.drings.ringContext[1].contextData));
13794 } else if (!strcasecmp(v->name, "dring3context")) {
13795 ast_copy_string(confp->chan.drings.ringContext[2].contextData,v->value,sizeof(confp->chan.drings.ringContext[2].contextData));
13796 } else if (!strcasecmp(v->name, "dring1range")) {
13797 confp->chan.drings.ringnum[0].range = atoi(v->value);
13798 } else if (!strcasecmp(v->name, "dring2range")) {
13799 confp->chan.drings.ringnum[1].range = atoi(v->value);
13800 } else if (!strcasecmp(v->name, "dring3range")) {
13801 confp->chan.drings.ringnum[2].range = atoi(v->value);
13802 } else if (!strcasecmp(v->name, "dring1")) {
13803 sscanf(v->value, "%d,%d,%d", &confp->chan.drings.ringnum[0].ring[0], &confp->chan.drings.ringnum[0].ring[1], &confp->chan.drings.ringnum[0].ring[2]);
13804 } else if (!strcasecmp(v->name, "dring2")) {
13805 sscanf(v->value,"%d,%d,%d", &confp->chan.drings.ringnum[1].ring[0], &confp->chan.drings.ringnum[1].ring[1], &confp->chan.drings.ringnum[1].ring[2]);
13806 } else if (!strcasecmp(v->name, "dring3")) {
13807 sscanf(v->value, "%d,%d,%d", &confp->chan.drings.ringnum[2].ring[0], &confp->chan.drings.ringnum[2].ring[1], &confp->chan.drings.ringnum[2].ring[2]);
13808 } else if (!strcasecmp(v->name, "usecallerid")) {
13809 confp->chan.use_callerid = ast_true(v->value);
13810 } else if (!strcasecmp(v->name, "cidsignalling")) {
13811 if (!strcasecmp(v->value, "bell"))
13812 confp->chan.cid_signalling = CID_SIG_BELL;
13813 else if (!strcasecmp(v->value, "v23"))
13814 confp->chan.cid_signalling = CID_SIG_V23;
13815 else if (!strcasecmp(v->value, "dtmf"))
13816 confp->chan.cid_signalling = CID_SIG_DTMF;
13817 else if (!strcasecmp(v->value, "smdi"))
13818 confp->chan.cid_signalling = CID_SIG_SMDI;
13819 else if (!strcasecmp(v->value, "v23_jp"))
13820 confp->chan.cid_signalling = CID_SIG_V23_JP;
13821 else if (ast_true(v->value))
13822 confp->chan.cid_signalling = CID_SIG_BELL;
13823 } else if (!strcasecmp(v->name, "cidstart")) {
13824 if (!strcasecmp(v->value, "ring"))
13825 confp->chan.cid_start = CID_START_RING;
13826 else if (!strcasecmp(v->value, "polarity_in"))
13827 confp->chan.cid_start = CID_START_POLARITY_IN;
13828 else if (!strcasecmp(v->value, "polarity"))
13829 confp->chan.cid_start = CID_START_POLARITY;
13830 else if (ast_true(v->value))
13831 confp->chan.cid_start = CID_START_RING;
13832 } else if (!strcasecmp(v->name, "threewaycalling")) {
13833 confp->chan.threewaycalling = ast_true(v->value);
13834 } else if (!strcasecmp(v->name, "cancallforward")) {
13835 confp->chan.cancallforward = ast_true(v->value);
13836 } else if (!strcasecmp(v->name, "relaxdtmf")) {
13837 if (ast_true(v->value))
13838 confp->chan.dtmfrelax = DSP_DIGITMODE_RELAXDTMF;
13839 else
13840 confp->chan.dtmfrelax = 0;
13841 } else if (!strcasecmp(v->name, "mailbox")) {
13842 ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
13843 } else if (!strcasecmp(v->name, "hasvoicemail")) {
13844 if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
13845 ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
13847 } else if (!strcasecmp(v->name, "adsi")) {
13848 confp->chan.adsi = ast_true(v->value);
13849 } else if (!strcasecmp(v->name, "usesmdi")) {
13850 confp->chan.use_smdi = ast_true(v->value);
13851 } else if (!strcasecmp(v->name, "smdiport")) {
13852 ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
13853 } else if (!strcasecmp(v->name, "transfer")) {
13854 confp->chan.transfer = ast_true(v->value);
13855 } else if (!strcasecmp(v->name, "canpark")) {
13856 confp->chan.canpark = ast_true(v->value);
13857 } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
13858 confp->chan.echocanbridged = ast_true(v->value);
13859 } else if (!strcasecmp(v->name, "busydetect")) {
13860 confp->chan.busydetect = ast_true(v->value);
13861 } else if (!strcasecmp(v->name, "busycount")) {
13862 confp->chan.busycount = atoi(v->value);
13863 } else if (!strcasecmp(v->name, "busypattern")) {
13864 if (sscanf(v->value, "%d,%d", &confp->chan.busy_tonelength, &confp->chan.busy_quietlength) != 2) {
13865 ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength at line %d.\n", v->lineno);
13867 } else if (!strcasecmp(v->name, "callprogress")) {
13868 confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
13869 if (ast_true(v->value))
13870 confp->chan.callprogress |= CALLPROGRESS_PROGRESS;
13871 } else if (!strcasecmp(v->name, "faxdetect")) {
13872 confp->chan.callprogress &= ~CALLPROGRESS_FAX;
13873 if (!strcasecmp(v->value, "incoming")) {
13874 confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING;
13875 } else if (!strcasecmp(v->value, "outgoing")) {
13876 confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING;
13877 } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
13878 confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING;
13879 } else if (!strcasecmp(v->name, "echocancel")) {
13880 process_echocancel(confp, v->value, v->lineno);
13881 } else if (!strcasecmp(v->name, "echotraining")) {
13882 if (sscanf(v->value, "%d", &y) == 1) {
13883 if ((y < 10) || (y > 4000)) {
13884 ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);
13885 } else {
13886 confp->chan.echotraining = y;
13888 } else if (ast_true(v->value)) {
13889 confp->chan.echotraining = 400;
13890 } else
13891 confp->chan.echotraining = 0;
13892 } else if (!strcasecmp(v->name, "hidecallerid")) {
13893 confp->chan.hidecallerid = ast_true(v->value);
13894 } else if (!strcasecmp(v->name, "hidecalleridname")) {
13895 confp->chan.hidecalleridname = ast_true(v->value);
13896 } else if (!strcasecmp(v->name, "pulsedial")) {
13897 confp->chan.pulse = ast_true(v->value);
13898 } else if (!strcasecmp(v->name, "callreturn")) {
13899 confp->chan.callreturn = ast_true(v->value);
13900 } else if (!strcasecmp(v->name, "callwaiting")) {
13901 confp->chan.callwaiting = ast_true(v->value);
13902 } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
13903 confp->chan.callwaitingcallerid = ast_true(v->value);
13904 } else if (!strcasecmp(v->name, "context")) {
13905 ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
13906 } else if (!strcasecmp(v->name, "language")) {
13907 ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
13908 } else if (!strcasecmp(v->name, "progzone")) {
13909 ast_copy_string(progzone, v->value, sizeof(progzone));
13910 } else if (!strcasecmp(v->name, "mohinterpret")
13911 ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
13912 ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
13913 } else if (!strcasecmp(v->name, "mohsuggest")) {
13914 ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
13915 } else if (!strcasecmp(v->name, "parkinglot")) {
13916 ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
13917 } else if (!strcasecmp(v->name, "stripmsd")) {
13918 ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
13919 confp->chan.stripmsd = atoi(v->value);
13920 } else if (!strcasecmp(v->name, "jitterbuffers")) {
13921 numbufs = atoi(v->value);
13922 } else if (!strcasecmp(v->name, "group")) {
13923 confp->chan.group = ast_get_group(v->value);
13924 } else if (!strcasecmp(v->name, "callgroup")) {
13925 if (!strcasecmp(v->value, "none"))
13926 confp->chan.callgroup = 0;
13927 else
13928 confp->chan.callgroup = ast_get_group(v->value);
13929 } else if (!strcasecmp(v->name, "pickupgroup")) {
13930 if (!strcasecmp(v->value, "none"))
13931 confp->chan.pickupgroup = 0;
13932 else
13933 confp->chan.pickupgroup = ast_get_group(v->value);
13934 } else if (!strcasecmp(v->name, "setvar")) {
13935 char *varname = ast_strdupa(v->value), *varval = NULL;
13936 struct ast_variable *tmpvar;
13937 if (varname && (varval = strchr(varname, '='))) {
13938 *varval++ = '\0';
13939 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
13940 tmpvar->next = confp->chan.vars;
13941 confp->chan.vars = tmpvar;
13944 } else if (!strcasecmp(v->name, "immediate")) {
13945 confp->chan.immediate = ast_true(v->value);
13946 } else if (!strcasecmp(v->name, "transfertobusy")) {
13947 confp->chan.transfertobusy = ast_true(v->value);
13948 } else if (!strcasecmp(v->name, "mwimonitor")) {
13949 if (!strcasecmp(v->value, "neon")) {
13950 confp->chan.mwimonitor_neon = 1;
13951 confp->chan.mwimonitor_fsk = 0;
13952 } else {
13953 confp->chan.mwimonitor_neon = 0;
13954 if (!strcasecmp(v->value, "fsk"))
13955 confp->chan.mwimonitor_fsk = 1;
13956 else
13957 confp->chan.mwimonitor_fsk = ast_true(v->value) ? 1 : 0;
13959 } else if (!strcasecmp(v->name, "cid_rxgain")) {
13960 if (sscanf(v->value, "%f", &confp->chan.cid_rxgain) != 1) {
13961 ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
13963 } else if (!strcasecmp(v->name, "rxgain")) {
13964 if (sscanf(v->value, "%f", &confp->chan.rxgain) != 1) {
13965 ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
13967 } else if (!strcasecmp(v->name, "txgain")) {
13968 if (sscanf(v->value, "%f", &confp->chan.txgain) != 1) {
13969 ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
13971 } else if (!strcasecmp(v->name, "tonezone")) {
13972 if (sscanf(v->value, "%d", &confp->chan.tonezone) != 1) {
13973 ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
13975 } else if (!strcasecmp(v->name, "callerid")) {
13976 if (!strcasecmp(v->value, "asreceived")) {
13977 confp->chan.cid_num[0] = '\0';
13978 confp->chan.cid_name[0] = '\0';
13979 } else {
13980 ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
13982 } else if (!strcasecmp(v->name, "fullname")) {
13983 ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
13984 } else if (!strcasecmp(v->name, "cid_number")) {
13985 ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
13986 } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
13987 confp->chan.dahditrcallerid = ast_true(v->value);
13988 } else if (!strcasecmp(v->name, "restrictcid")) {
13989 confp->chan.restrictcid = ast_true(v->value);
13990 } else if (!strcasecmp(v->name, "usecallingpres")) {
13991 confp->chan.use_callingpres = ast_true(v->value);
13992 } else if (!strcasecmp(v->name, "accountcode")) {
13993 ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
13994 } else if (!strcasecmp(v->name, "amaflags")) {
13995 y = ast_cdr_amaflags2int(v->value);
13996 if (y < 0)
13997 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
13998 else
13999 confp->chan.amaflags = y;
14000 } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
14001 confp->chan.polarityonanswerdelay = atoi(v->value);
14002 } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
14003 confp->chan.answeronpolarityswitch = ast_true(v->value);
14004 } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
14005 confp->chan.hanguponpolarityswitch = ast_true(v->value);
14006 } else if (!strcasecmp(v->name, "sendcalleridafter")) {
14007 confp->chan.sendcalleridafter = atoi(v->value);
14008 } else if (!strcasecmp(v->name, "mwimonitornotify")) {
14009 ast_copy_string(mwimonitornotify, v->value, sizeof(mwimonitornotify));
14010 } else if (!strcasecmp(v->name, "mwisendtype")) {
14011 if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
14012 mwisend_rpas = 1;
14013 } else {
14014 mwisend_rpas = 0;
14016 } else if (reload != 1) {
14017 if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
14018 int orig_radio = confp->chan.radio;
14019 int orig_outsigmod = confp->chan.outsigmod;
14020 int orig_auto = confp->is_sig_auto;
14022 confp->chan.radio = 0;
14023 confp->chan.outsigmod = -1;
14024 confp->is_sig_auto = 0;
14025 if (!strcasecmp(v->value, "em")) {
14026 confp->chan.sig = SIG_EM;
14027 } else if (!strcasecmp(v->value, "em_e1")) {
14028 confp->chan.sig = SIG_EM_E1;
14029 } else if (!strcasecmp(v->value, "em_w")) {
14030 confp->chan.sig = SIG_EMWINK;
14031 } else if (!strcasecmp(v->value, "fxs_ls")) {
14032 confp->chan.sig = SIG_FXSLS;
14033 } else if (!strcasecmp(v->value, "fxs_gs")) {
14034 confp->chan.sig = SIG_FXSGS;
14035 } else if (!strcasecmp(v->value, "fxs_ks")) {
14036 confp->chan.sig = SIG_FXSKS;
14037 } else if (!strcasecmp(v->value, "fxo_ls")) {
14038 confp->chan.sig = SIG_FXOLS;
14039 } else if (!strcasecmp(v->value, "fxo_gs")) {
14040 confp->chan.sig = SIG_FXOGS;
14041 } else if (!strcasecmp(v->value, "fxo_ks")) {
14042 confp->chan.sig = SIG_FXOKS;
14043 } else if (!strcasecmp(v->value, "fxs_rx")) {
14044 confp->chan.sig = SIG_FXSKS;
14045 confp->chan.radio = 1;
14046 } else if (!strcasecmp(v->value, "fxo_rx")) {
14047 confp->chan.sig = SIG_FXOLS;
14048 confp->chan.radio = 1;
14049 } else if (!strcasecmp(v->value, "fxs_tx")) {
14050 confp->chan.sig = SIG_FXSLS;
14051 confp->chan.radio = 1;
14052 } else if (!strcasecmp(v->value, "fxo_tx")) {
14053 confp->chan.sig = SIG_FXOGS;
14054 confp->chan.radio = 1;
14055 } else if (!strcasecmp(v->value, "em_rx")) {
14056 confp->chan.sig = SIG_EM;
14057 confp->chan.radio = 1;
14058 } else if (!strcasecmp(v->value, "em_tx")) {
14059 confp->chan.sig = SIG_EM;
14060 confp->chan.radio = 1;
14061 } else if (!strcasecmp(v->value, "em_rxtx")) {
14062 confp->chan.sig = SIG_EM;
14063 confp->chan.radio = 2;
14064 } else if (!strcasecmp(v->value, "em_txrx")) {
14065 confp->chan.sig = SIG_EM;
14066 confp->chan.radio = 2;
14067 } else if (!strcasecmp(v->value, "sf")) {
14068 confp->chan.sig = SIG_SF;
14069 } else if (!strcasecmp(v->value, "sf_w")) {
14070 confp->chan.sig = SIG_SFWINK;
14071 } else if (!strcasecmp(v->value, "sf_featd")) {
14072 confp->chan.sig = SIG_FEATD;
14073 } else if (!strcasecmp(v->value, "sf_featdmf")) {
14074 confp->chan.sig = SIG_FEATDMF;
14075 } else if (!strcasecmp(v->value, "sf_featb")) {
14076 confp->chan.sig = SIG_SF_FEATB;
14077 } else if (!strcasecmp(v->value, "sf")) {
14078 confp->chan.sig = SIG_SF;
14079 } else if (!strcasecmp(v->value, "sf_rx")) {
14080 confp->chan.sig = SIG_SF;
14081 confp->chan.radio = 1;
14082 } else if (!strcasecmp(v->value, "sf_tx")) {
14083 confp->chan.sig = SIG_SF;
14084 confp->chan.radio = 1;
14085 } else if (!strcasecmp(v->value, "sf_rxtx")) {
14086 confp->chan.sig = SIG_SF;
14087 confp->chan.radio = 2;
14088 } else if (!strcasecmp(v->value, "sf_txrx")) {
14089 confp->chan.sig = SIG_SF;
14090 confp->chan.radio = 2;
14091 } else if (!strcasecmp(v->value, "featd")) {
14092 confp->chan.sig = SIG_FEATD;
14093 } else if (!strcasecmp(v->value, "featdmf")) {
14094 confp->chan.sig = SIG_FEATDMF;
14095 } else if (!strcasecmp(v->value, "featdmf_ta")) {
14096 confp->chan.sig = SIG_FEATDMF_TA;
14097 } else if (!strcasecmp(v->value, "e911")) {
14098 confp->chan.sig = SIG_E911;
14099 } else if (!strcasecmp(v->value, "fgccama")) {
14100 confp->chan.sig = SIG_FGC_CAMA;
14101 } else if (!strcasecmp(v->value, "fgccamamf")) {
14102 confp->chan.sig = SIG_FGC_CAMAMF;
14103 } else if (!strcasecmp(v->value, "featb")) {
14104 confp->chan.sig = SIG_FEATB;
14105 #ifdef HAVE_PRI
14106 } else if (!strcasecmp(v->value, "pri_net")) {
14107 confp->chan.sig = SIG_PRI;
14108 confp->pri.nodetype = PRI_NETWORK;
14109 } else if (!strcasecmp(v->value, "pri_cpe")) {
14110 confp->chan.sig = SIG_PRI;
14111 confp->pri.nodetype = PRI_CPE;
14112 } else if (!strcasecmp(v->value, "bri_cpe")) {
14113 confp->chan.sig = SIG_BRI;
14114 confp->pri.nodetype = PRI_CPE;
14115 } else if (!strcasecmp(v->value, "bri_net")) {
14116 confp->chan.sig = SIG_BRI;
14117 confp->pri.nodetype = PRI_NETWORK;
14118 } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
14119 confp->chan.sig = SIG_BRI_PTMP;
14120 confp->pri.nodetype = PRI_CPE;
14121 } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
14122 ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v->lineno);
14123 } else if (!strcasecmp(v->value, "gr303fxoks_net")) {
14124 confp->chan.sig = SIG_GR303FXOKS;
14125 confp->pri.nodetype = PRI_NETWORK;
14126 } else if (!strcasecmp(v->value, "gr303fxsks_cpe")) {
14127 confp->chan.sig = SIG_GR303FXSKS;
14128 confp->pri.nodetype = PRI_CPE;
14129 #endif
14130 #ifdef HAVE_SS7
14131 } else if (!strcasecmp(v->value, "ss7")) {
14132 confp->chan.sig = SIG_SS7;
14133 #endif
14134 } else if (!strcasecmp(v->value, "auto")) {
14135 confp->is_sig_auto = 1;
14136 } else {
14137 confp->chan.outsigmod = orig_outsigmod;
14138 confp->chan.radio = orig_radio;
14139 confp->is_sig_auto = orig_auto;
14140 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14142 } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
14143 if (!strcasecmp(v->value, "em")) {
14144 confp->chan.outsigmod = SIG_EM;
14145 } else if (!strcasecmp(v->value, "em_e1")) {
14146 confp->chan.outsigmod = SIG_EM_E1;
14147 } else if (!strcasecmp(v->value, "em_w")) {
14148 confp->chan.outsigmod = SIG_EMWINK;
14149 } else if (!strcasecmp(v->value, "sf")) {
14150 confp->chan.outsigmod = SIG_SF;
14151 } else if (!strcasecmp(v->value, "sf_w")) {
14152 confp->chan.outsigmod = SIG_SFWINK;
14153 } else if (!strcasecmp(v->value, "sf_featd")) {
14154 confp->chan.outsigmod = SIG_FEATD;
14155 } else if (!strcasecmp(v->value, "sf_featdmf")) {
14156 confp->chan.outsigmod = SIG_FEATDMF;
14157 } else if (!strcasecmp(v->value, "sf_featb")) {
14158 confp->chan.outsigmod = SIG_SF_FEATB;
14159 } else if (!strcasecmp(v->value, "sf")) {
14160 confp->chan.outsigmod = SIG_SF;
14161 } else if (!strcasecmp(v->value, "featd")) {
14162 confp->chan.outsigmod = SIG_FEATD;
14163 } else if (!strcasecmp(v->value, "featdmf")) {
14164 confp->chan.outsigmod = SIG_FEATDMF;
14165 } else if (!strcasecmp(v->value, "featdmf_ta")) {
14166 confp->chan.outsigmod = SIG_FEATDMF_TA;
14167 } else if (!strcasecmp(v->value, "e911")) {
14168 confp->chan.outsigmod = SIG_E911;
14169 } else if (!strcasecmp(v->value, "fgccama")) {
14170 confp->chan.outsigmod = SIG_FGC_CAMA;
14171 } else if (!strcasecmp(v->value, "fgccamamf")) {
14172 confp->chan.outsigmod = SIG_FGC_CAMAMF;
14173 } else if (!strcasecmp(v->value, "featb")) {
14174 confp->chan.outsigmod = SIG_FEATB;
14175 } else {
14176 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14178 #ifdef HAVE_PRI
14179 } else if (!strcasecmp(v->name, "pridialplan")) {
14180 if (!strcasecmp(v->value, "national")) {
14181 confp->pri.dialplan = PRI_NATIONAL_ISDN + 1;
14182 } else if (!strcasecmp(v->value, "unknown")) {
14183 confp->pri.dialplan = PRI_UNKNOWN + 1;
14184 } else if (!strcasecmp(v->value, "private")) {
14185 confp->pri.dialplan = PRI_PRIVATE + 1;
14186 } else if (!strcasecmp(v->value, "international")) {
14187 confp->pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
14188 } else if (!strcasecmp(v->value, "local")) {
14189 confp->pri.dialplan = PRI_LOCAL_ISDN + 1;
14190 } else if (!strcasecmp(v->value, "dynamic")) {
14191 confp->pri.dialplan = -1;
14192 } else if (!strcasecmp(v->value, "redundant")) {
14193 confp->pri.dialplan = -2;
14194 } else {
14195 ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
14197 } else if (!strcasecmp(v->name, "prilocaldialplan")) {
14198 if (!strcasecmp(v->value, "national")) {
14199 confp->pri.localdialplan = PRI_NATIONAL_ISDN + 1;
14200 } else if (!strcasecmp(v->value, "unknown")) {
14201 confp->pri.localdialplan = PRI_UNKNOWN + 1;
14202 } else if (!strcasecmp(v->value, "private")) {
14203 confp->pri.localdialplan = PRI_PRIVATE + 1;
14204 } else if (!strcasecmp(v->value, "international")) {
14205 confp->pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
14206 } else if (!strcasecmp(v->value, "local")) {
14207 confp->pri.localdialplan = PRI_LOCAL_ISDN + 1;
14208 } else if (!strcasecmp(v->value, "dynamic")) {
14209 confp->pri.localdialplan = -1;
14210 } else if (!strcasecmp(v->value, "redundant")) {
14211 confp->pri.localdialplan = -2;
14212 } else {
14213 ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
14215 } else if (!strcasecmp(v->name, "switchtype")) {
14216 if (!strcasecmp(v->value, "national"))
14217 confp->pri.switchtype = PRI_SWITCH_NI2;
14218 else if (!strcasecmp(v->value, "ni1"))
14219 confp->pri.switchtype = PRI_SWITCH_NI1;
14220 else if (!strcasecmp(v->value, "dms100"))
14221 confp->pri.switchtype = PRI_SWITCH_DMS100;
14222 else if (!strcasecmp(v->value, "4ess"))
14223 confp->pri.switchtype = PRI_SWITCH_ATT4ESS;
14224 else if (!strcasecmp(v->value, "5ess"))
14225 confp->pri.switchtype = PRI_SWITCH_LUCENT5E;
14226 else if (!strcasecmp(v->value, "euroisdn"))
14227 confp->pri.switchtype = PRI_SWITCH_EUROISDN_E1;
14228 else if (!strcasecmp(v->value, "qsig"))
14229 confp->pri.switchtype = PRI_SWITCH_QSIG;
14230 else {
14231 ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
14232 return -1;
14234 } else if (!strcasecmp(v->name, "nsf")) {
14235 if (!strcasecmp(v->value, "sdn"))
14236 confp->pri.nsf = PRI_NSF_SDN;
14237 else if (!strcasecmp(v->value, "megacom"))
14238 confp->pri.nsf = PRI_NSF_MEGACOM;
14239 else if (!strcasecmp(v->value, "tollfreemegacom"))
14240 confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
14241 else if (!strcasecmp(v->value, "accunet"))
14242 confp->pri.nsf = PRI_NSF_ACCUNET;
14243 else if (!strcasecmp(v->value, "none"))
14244 confp->pri.nsf = PRI_NSF_NONE;
14245 else {
14246 ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
14247 confp->pri.nsf = PRI_NSF_NONE;
14249 } else if (!strcasecmp(v->name, "priindication")) {
14250 if (!strcasecmp(v->value, "outofband"))
14251 confp->chan.priindication_oob = 1;
14252 else if (!strcasecmp(v->value, "inband"))
14253 confp->chan.priindication_oob = 0;
14254 else
14255 ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
14256 v->value, v->lineno);
14257 } else if (!strcasecmp(v->name, "priexclusive")) {
14258 confp->chan.priexclusive = ast_true(v->value);
14259 } else if (!strcasecmp(v->name, "internationalprefix")) {
14260 ast_copy_string(confp->pri.internationalprefix, v->value, sizeof(confp->pri.internationalprefix));
14261 } else if (!strcasecmp(v->name, "nationalprefix")) {
14262 ast_copy_string(confp->pri.nationalprefix, v->value, sizeof(confp->pri.nationalprefix));
14263 } else if (!strcasecmp(v->name, "localprefix")) {
14264 ast_copy_string(confp->pri.localprefix, v->value, sizeof(confp->pri.localprefix));
14265 } else if (!strcasecmp(v->name, "privateprefix")) {
14266 ast_copy_string(confp->pri.privateprefix, v->value, sizeof(confp->pri.privateprefix));
14267 } else if (!strcasecmp(v->name, "unknownprefix")) {
14268 ast_copy_string(confp->pri.unknownprefix, v->value, sizeof(confp->pri.unknownprefix));
14269 } else if (!strcasecmp(v->name, "resetinterval")) {
14270 if (!strcasecmp(v->value, "never"))
14271 confp->pri.resetinterval = -1;
14272 else if (atoi(v->value) >= 60)
14273 confp->pri.resetinterval = atoi(v->value);
14274 else
14275 ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
14276 v->value, v->lineno);
14277 } else if (!strcasecmp(v->name, "minunused")) {
14278 confp->pri.minunused = atoi(v->value);
14279 } else if (!strcasecmp(v->name, "minidle")) {
14280 confp->pri.minidle = atoi(v->value);
14281 } else if (!strcasecmp(v->name, "idleext")) {
14282 ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext));
14283 } else if (!strcasecmp(v->name, "idledial")) {
14284 ast_copy_string(confp->pri.idledial, v->value, sizeof(confp->pri.idledial));
14285 } else if (!strcasecmp(v->name, "overlapdial")) {
14286 if (ast_true(v->value)) {
14287 confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14288 } else if (!strcasecmp(v->value, "incoming")) {
14289 confp->pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
14290 } else if (!strcasecmp(v->value, "outgoing")) {
14291 confp->pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
14292 } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
14293 confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14294 } else {
14295 confp->pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
14297 #ifdef HAVE_PRI_INBANDDISCONNECT
14298 } else if (!strcasecmp(v->name, "inbanddisconnect")) {
14299 confp->pri.inbanddisconnect = ast_true(v->value);
14300 #endif
14301 } else if (!strcasecmp(v->name, "pritimer")) {
14302 #ifdef PRI_GETSET_TIMERS
14303 char tmp[20], *timerc, *c = tmp;
14304 int timer, timeridx;
14305 ast_copy_string(tmp, v->value, sizeof(tmp));
14306 timerc = strsep(&c, ",");
14307 if (timerc) {
14308 timer = atoi(c);
14309 if (!timer)
14310 ast_log(LOG_WARNING, "'%s' is not a valid value for an ISDN timer at line %d.\n", timerc, v->lineno);
14311 else {
14312 if ((timeridx = pri_timer2idx(timerc)) >= 0)
14313 pritimers[timeridx] = timer;
14314 else
14315 ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer at line %d.\n", timerc, v->lineno);
14317 } else
14318 ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer configuration string at line %d.\n", v->value, v->lineno);
14320 } else if (!strcasecmp(v->name, "facilityenable")) {
14321 confp->pri.facilityenable = ast_true(v->value);
14322 #endif /* PRI_GETSET_TIMERS */
14323 #endif /* HAVE_PRI */
14324 #ifdef HAVE_SS7
14325 } else if (!strcasecmp(v->name, "ss7type")) {
14326 if (!strcasecmp(v->value, "itu")) {
14327 cur_ss7type = SS7_ITU;
14328 } else if (!strcasecmp(v->value, "ansi")) {
14329 cur_ss7type = SS7_ANSI;
14330 } else
14331 ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
14332 } else if (!strcasecmp(v->name, "linkset")) {
14333 cur_linkset = atoi(v->value);
14334 } else if (!strcasecmp(v->name, "pointcode")) {
14335 cur_pointcode = parse_pointcode(v->value);
14336 } else if (!strcasecmp(v->name, "adjpointcode")) {
14337 cur_adjpointcode = parse_pointcode(v->value);
14338 } else if (!strcasecmp(v->name, "defaultdpc")) {
14339 cur_defaultdpc = parse_pointcode(v->value);
14340 } else if (!strcasecmp(v->name, "cicbeginswith")) {
14341 cur_cicbeginswith = atoi(v->value);
14342 } else if (!strcasecmp(v->name, "networkindicator")) {
14343 if (!strcasecmp(v->value, "national"))
14344 cur_networkindicator = SS7_NI_NAT;
14345 else if (!strcasecmp(v->value, "national_spare"))
14346 cur_networkindicator = SS7_NI_NAT_SPARE;
14347 else if (!strcasecmp(v->value, "international"))
14348 cur_networkindicator = SS7_NI_INT;
14349 else if (!strcasecmp(v->value, "international_spare"))
14350 cur_networkindicator = SS7_NI_INT_SPARE;
14351 else
14352 cur_networkindicator = -1;
14353 } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
14354 ast_copy_string(confp->ss7.internationalprefix, v->value, sizeof(confp->ss7.internationalprefix));
14355 } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
14356 ast_copy_string(confp->ss7.nationalprefix, v->value, sizeof(confp->ss7.nationalprefix));
14357 } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
14358 ast_copy_string(confp->ss7.subscriberprefix, v->value, sizeof(confp->ss7.subscriberprefix));
14359 } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
14360 ast_copy_string(confp->ss7.unknownprefix, v->value, sizeof(confp->ss7.unknownprefix));
14361 } else if (!strcasecmp(v->name, "ss7_called_nai")) {
14362 if (!strcasecmp(v->value, "national")) {
14363 confp->ss7.called_nai = SS7_NAI_NATIONAL;
14364 } else if (!strcasecmp(v->value, "international")) {
14365 confp->ss7.called_nai = SS7_NAI_INTERNATIONAL;
14366 } else if (!strcasecmp(v->value, "subscriber")) {
14367 confp->ss7.called_nai = SS7_NAI_SUBSCRIBER;
14368 } else if (!strcasecmp(v->value, "dynamic")) {
14369 confp->ss7.called_nai = SS7_NAI_DYNAMIC;
14370 } else {
14371 ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
14373 } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
14374 if (!strcasecmp(v->value, "national")) {
14375 confp->ss7.calling_nai = SS7_NAI_NATIONAL;
14376 } else if (!strcasecmp(v->value, "international")) {
14377 confp->ss7.calling_nai = SS7_NAI_INTERNATIONAL;
14378 } else if (!strcasecmp(v->value, "subscriber")) {
14379 confp->ss7.calling_nai = SS7_NAI_SUBSCRIBER;
14380 } else if (!strcasecmp(v->value, "dynamic")) {
14381 confp->ss7.calling_nai = SS7_NAI_DYNAMIC;
14382 } else {
14383 ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
14385 } else if (!strcasecmp(v->name, "sigchan")) {
14386 int sigchan, res;
14387 sigchan = atoi(v->value);
14388 res = linkset_addsigchan(sigchan);
14389 if (res < 0)
14390 return -1;
14392 } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
14393 struct dahdi_ss7 *link;
14394 link = ss7_resolve_linkset(cur_linkset);
14395 if (!link) {
14396 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
14397 return -1;
14399 if (ast_true(v->value))
14400 link->flags |= LINKSET_FLAG_EXPLICITACM;
14402 #endif /* HAVE_SS7 */
14403 } else if (!strcasecmp(v->name, "cadence")) {
14404 /* setup to scan our argument */
14405 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
14406 int i;
14407 struct dahdi_ring_cadence new_cadence;
14408 int cid_location = -1;
14409 int firstcadencepos = 0;
14410 char original_args[80];
14411 int cadence_is_ok = 1;
14413 ast_copy_string(original_args, v->value, sizeof(original_args));
14414 /* 16 cadences allowed (8 pairs) */
14415 element_count = sscanf(v->value, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12], &c[13], &c[14], &c[15]);
14417 /* Cadence must be even (on/off) */
14418 if (element_count % 2 == 1) {
14419 ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
14420 cadence_is_ok = 0;
14423 /* Ring cadences cannot be negative */
14424 for (i = 0; i < element_count; i++) {
14425 if (c[i] == 0) {
14426 ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
14427 cadence_is_ok = 0;
14428 break;
14429 } else if (c[i] < 0) {
14430 if (i % 2 == 1) {
14431 /* Silence duration, negative possibly okay */
14432 if (cid_location == -1) {
14433 cid_location = i;
14434 c[i] *= -1;
14435 } else {
14436 ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
14437 cadence_is_ok = 0;
14438 break;
14440 } else {
14441 if (firstcadencepos == 0) {
14442 firstcadencepos = i; /* only recorded to avoid duplicate specification */
14443 /* duration will be passed negative to the DAHDI driver */
14444 } else {
14445 ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
14446 cadence_is_ok = 0;
14447 break;
14453 /* Substitute our scanned cadence */
14454 for (i = 0; i < 16; i++) {
14455 new_cadence.ringcadence[i] = c[i];
14458 if (cadence_is_ok) {
14459 /* ---we scanned it without getting annoyed; now some sanity checks--- */
14460 if (element_count < 2) {
14461 ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
14462 } else {
14463 if (cid_location == -1) {
14464 /* user didn't say; default to first pause */
14465 cid_location = 1;
14466 } else {
14467 /* convert element_index to cidrings value */
14468 cid_location = (cid_location + 1) / 2;
14470 /* ---we like their cadence; try to install it--- */
14471 if (!user_has_defined_cadences++)
14472 /* this is the first user-defined cadence; clear the default user cadences */
14473 num_cadence = 0;
14474 if ((num_cadence+1) >= NUM_CADENCE_MAX)
14475 ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
14476 else {
14477 cadences[num_cadence] = new_cadence;
14478 cidrings[num_cadence++] = cid_location;
14479 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
14483 } else if (!strcasecmp(v->name, "ringtimeout")) {
14484 ringt_base = (atoi(v->value) * 8) / READ_SIZE;
14485 } else if (!strcasecmp(v->name, "prewink")) {
14486 confp->timing.prewinktime = atoi(v->value);
14487 } else if (!strcasecmp(v->name, "preflash")) {
14488 confp->timing.preflashtime = atoi(v->value);
14489 } else if (!strcasecmp(v->name, "wink")) {
14490 confp->timing.winktime = atoi(v->value);
14491 } else if (!strcasecmp(v->name, "flash")) {
14492 confp->timing.flashtime = atoi(v->value);
14493 } else if (!strcasecmp(v->name, "start")) {
14494 confp->timing.starttime = atoi(v->value);
14495 } else if (!strcasecmp(v->name, "rxwink")) {
14496 confp->timing.rxwinktime = atoi(v->value);
14497 } else if (!strcasecmp(v->name, "rxflash")) {
14498 confp->timing.rxflashtime = atoi(v->value);
14499 } else if (!strcasecmp(v->name, "debounce")) {
14500 confp->timing.debouncetime = atoi(v->value);
14501 } else if (!strcasecmp(v->name, "toneduration")) {
14502 int toneduration;
14503 int ctlfd;
14504 int res;
14505 struct dahdi_dialparams dps;
14507 ctlfd = open("/dev/dahdi/ctl", O_RDWR);
14508 if (ctlfd == -1) {
14509 ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
14510 return -1;
14513 toneduration = atoi(v->value);
14514 if (toneduration > -1) {
14515 memset(&dps, 0, sizeof(dps));
14517 dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
14518 res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
14519 if (res < 0) {
14520 ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
14521 return -1;
14524 close(ctlfd);
14525 } else if (!strcasecmp(v->name, "defaultcic")) {
14526 ast_copy_string(defaultcic, v->value, sizeof(defaultcic));
14527 } else if (!strcasecmp(v->name, "defaultozz")) {
14528 ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
14529 } else if (!strcasecmp(v->name, "mwilevel")) {
14530 mwilevel = atoi(v->value);
14532 } else if (!(options && PROC_DAHDI_OPT_NOWARN) )
14533 ast_log(LOG_WARNING, "Ignoring %s at line %d.\n", v->name, v->lineno);
14535 if (dahdichan[0]) {
14536 /* The user has set 'dahdichan' */
14537 /*< \todo pass proper line number instead of 0 */
14538 if (build_channels(confp, 0, dahdichan, reload, 0, &found_pseudo)) {
14539 return -1;
14542 /*< \todo why check for the pseudo in the per-channel section.
14543 * Any actual use for manual setup of the pseudo channel? */
14544 if (!found_pseudo && reload == 0) {
14545 /* Make sure pseudo isn't a member of any groups if
14546 we're automatically making it. */
14548 confp->chan.group = 0;
14549 confp->chan.callgroup = 0;
14550 confp->chan.pickupgroup = 0;
14552 tmp = mkintf(CHAN_PSEUDO, confp, NULL, reload);
14554 if (tmp) {
14555 ast_verb(3, "Automatically generated pseudo channel\n");
14556 } else {
14557 ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
14560 return 0;
14563 static int setup_dahdi(int reload)
14565 struct ast_config *cfg, *ucfg;
14566 struct ast_variable *v;
14567 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
14568 struct dahdi_chan_conf conf;
14569 struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
14570 const char *cat;
14571 int res;
14573 #ifdef HAVE_PRI
14574 char *c;
14575 int spanno;
14576 int i;
14577 int logicalspan;
14578 int trunkgroup;
14579 int dchannels[NUM_DCHANS];
14580 #endif
14582 cfg = ast_config_load(config, config_flags);
14584 /* Error if we have no config file */
14585 if (!cfg) {
14586 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
14587 return 0;
14588 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
14589 ucfg = ast_config_load("users.conf", config_flags);
14590 if (ucfg == CONFIG_STATUS_FILEUNCHANGED)
14591 return 0;
14592 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
14593 cfg = ast_config_load(config, config_flags);
14594 } else {
14595 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
14596 ucfg = ast_config_load("users.conf", config_flags);
14599 /* It's a little silly to lock it, but we mind as well just to be sure */
14600 ast_mutex_lock(&iflock);
14601 #ifdef HAVE_PRI
14602 if (reload != 1) {
14603 /* Process trunkgroups first */
14604 v = ast_variable_browse(cfg, "trunkgroups");
14605 while (v) {
14606 if (!strcasecmp(v->name, "trunkgroup")) {
14607 trunkgroup = atoi(v->value);
14608 if (trunkgroup > 0) {
14609 if ((c = strchr(v->value, ','))) {
14610 i = 0;
14611 memset(dchannels, 0, sizeof(dchannels));
14612 while (c && (i < NUM_DCHANS)) {
14613 dchannels[i] = atoi(c + 1);
14614 if (dchannels[i] < 0) {
14615 ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
14616 } else
14617 i++;
14618 c = strchr(c + 1, ',');
14620 if (i) {
14621 if (pri_create_trunkgroup(trunkgroup, dchannels)) {
14622 ast_log(LOG_WARNING, "Unable to create trunk group %d with Primary D-channel %d at line %d of chan_dahdi.conf\n", trunkgroup, dchannels[0], v->lineno);
14623 } else
14624 ast_verb(2, "Created trunk group %d with Primary D-channel %d and %d backup%s\n", trunkgroup, dchannels[0], i - 1, (i == 1) ? "" : "s");
14625 } else
14626 ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
14627 } else
14628 ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
14629 } else
14630 ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
14631 } else if (!strcasecmp(v->name, "spanmap")) {
14632 spanno = atoi(v->value);
14633 if (spanno > 0) {
14634 if ((c = strchr(v->value, ','))) {
14635 trunkgroup = atoi(c + 1);
14636 if (trunkgroup > 0) {
14637 if ((c = strchr(c + 1, ',')))
14638 logicalspan = atoi(c + 1);
14639 else
14640 logicalspan = 0;
14641 if (logicalspan >= 0) {
14642 if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
14643 ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
14644 } else
14645 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
14646 } else
14647 ast_log(LOG_WARNING, "Logical span must be a postive number, or '0' (for unspecified) at line %d of chan_dahdi.conf\n", v->lineno);
14648 } else
14649 ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v->lineno);
14650 } else
14651 ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
14652 } else
14653 ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v->lineno);
14654 } else {
14655 ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
14657 v = v->next;
14660 #endif
14662 /* Copy the default jb config over global_jbconf */
14663 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
14665 mwimonitornotify[0] = '\0';
14667 v = ast_variable_browse(cfg, "channels");
14668 if ((res = process_dahdi(&base_conf, "", v, reload, 0))) {
14669 ast_mutex_unlock(&iflock);
14670 ast_config_destroy(cfg);
14671 if (ucfg) {
14672 ast_config_destroy(ucfg);
14674 return res;
14677 /* Now get configuration from all normal sections in chan_dahdi.conf: */
14678 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
14679 /* [channels] and [trunkgroups] are used. Let's also reserve
14680 * [globals] and [general] for future use
14682 if (!strcasecmp(cat, "general") ||
14683 !strcasecmp(cat, "trunkgroups") ||
14684 !strcasecmp(cat, "globals") ||
14685 !strcasecmp(cat, "channels")) {
14686 continue;
14689 memcpy(&conf, &base_conf, sizeof(conf));
14691 if ((res = process_dahdi(&conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
14692 ast_mutex_unlock(&iflock);
14693 ast_config_destroy(cfg);
14694 if (ucfg) {
14695 ast_config_destroy(cfg);
14697 return res;
14701 ast_config_destroy(cfg);
14703 if (ucfg) {
14704 const char *chans;
14706 process_dahdi(&base_conf, "", ast_variable_browse(ucfg, "general"), 1, 0);
14708 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
14709 if (!strcasecmp(cat, "general")) {
14710 continue;
14713 chans = ast_variable_retrieve(ucfg, cat, "dahdichan");
14715 if (ast_strlen_zero(chans)) {
14716 continue;
14719 memcpy(&conf, &base_conf, sizeof(conf));
14721 if ((res = process_dahdi(&conf, cat, ast_variable_browse(ucfg, cat), reload, PROC_DAHDI_OPT_NOCHAN | PROC_DAHDI_OPT_NOWARN))) {
14722 ast_config_destroy(ucfg);
14723 ast_mutex_unlock(&iflock);
14724 return res;
14727 ast_config_destroy(ucfg);
14729 ast_mutex_unlock(&iflock);
14731 #ifdef HAVE_PRI
14732 if (reload != 1) {
14733 int x;
14734 for (x = 0; x < NUM_SPANS; x++) {
14735 if (pris[x].pvts[0]) {
14736 if (start_pri(pris + x)) {
14737 ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
14738 return -1;
14739 } else
14740 ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
14744 #endif
14745 #ifdef HAVE_SS7
14746 if (reload != 1) {
14747 int x;
14748 for (x = 0; x < NUM_SPANS; x++) {
14749 if (linksets[x].ss7) {
14750 if (ast_pthread_create(&linksets[x].master, NULL, ss7_linkset, &linksets[x])) {
14751 ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
14752 return -1;
14753 } else
14754 ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
14758 #endif
14759 /* And start the monitor for the first time */
14760 restart_monitor();
14761 return 0;
14764 static int load_module(void)
14766 int res;
14767 #if defined(HAVE_PRI) || defined(HAVE_SS7)
14768 int y, i;
14769 #endif
14771 #ifdef HAVE_PRI
14772 memset(pris, 0, sizeof(pris));
14773 for (y = 0; y < NUM_SPANS; y++) {
14774 ast_mutex_init(&pris[y].lock);
14775 pris[y].offset = -1;
14776 pris[y].master = AST_PTHREADT_NULL;
14777 for (i = 0; i < NUM_DCHANS; i++)
14778 pris[y].fds[i] = -1;
14780 pri_set_error(dahdi_pri_error);
14781 pri_set_message(dahdi_pri_message);
14782 ast_register_application(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec,
14783 dahdi_send_keypad_facility_synopsis, dahdi_send_keypad_facility_descrip);
14784 #endif
14785 #ifdef HAVE_SS7
14786 memset(linksets, 0, sizeof(linksets));
14787 for (y = 0; y < NUM_SPANS; y++) {
14788 ast_mutex_init(&linksets[y].lock);
14789 linksets[y].master = AST_PTHREADT_NULL;
14790 for (i = 0; i < NUM_DCHANS; i++)
14791 linksets[y].fds[i] = -1;
14793 ss7_set_error(dahdi_ss7_error);
14794 ss7_set_message(dahdi_ss7_message);
14795 #endif /* HAVE_SS7 */
14796 res = setup_dahdi(0);
14797 /* Make sure we can register our DAHDI channel type */
14798 if (res)
14799 return AST_MODULE_LOAD_DECLINE;
14800 if (ast_channel_register(&dahdi_tech)) {
14801 ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
14802 __unload_module();
14803 return AST_MODULE_LOAD_FAILURE;
14805 #ifdef HAVE_PRI
14806 ast_string_field_init(&inuse, 16);
14807 ast_string_field_set(&inuse, name, "GR-303InUse");
14808 ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
14809 #endif
14810 #ifdef HAVE_SS7
14811 ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
14812 #endif
14814 ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
14816 memset(round_robin, 0, sizeof(round_robin));
14817 ast_manager_register( "DAHDITransfer", 0, action_transfer, "Transfer DAHDI Channel" );
14818 ast_manager_register( "DAHDIHangup", 0, action_transferhangup, "Hangup DAHDI Channel" );
14819 ast_manager_register( "DAHDIDialOffhook", 0, action_dahdidialoffhook, "Dial over DAHDI channel while offhook" );
14820 ast_manager_register( "DAHDIDNDon", 0, action_dahdidndon, "Toggle DAHDI channel Do Not Disturb status ON" );
14821 ast_manager_register( "DAHDIDNDoff", 0, action_dahdidndoff, "Toggle DAHDI channel Do Not Disturb status OFF" );
14822 ast_manager_register("DAHDIShowChannels", 0, action_dahdishowchannels, "Show status DAHDI channels");
14823 ast_manager_register("DAHDIRestart", 0, action_dahdirestart, "Fully Restart DAHDI channels (terminates calls)");
14825 ast_cond_init(&mwi_thread_complete, NULL);
14826 ast_cond_init(&ss_thread_complete, NULL);
14828 return res;
14831 static int dahdi_sendtext(struct ast_channel *c, const char *text)
14833 #define END_SILENCE_LEN 400
14834 #define HEADER_MS 50
14835 #define TRAILER_MS 5
14836 #define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
14837 #define ASCII_BYTES_PER_CHAR 80
14839 unsigned char *buf,*mybuf;
14840 struct dahdi_pvt *p = c->tech_pvt;
14841 struct pollfd fds[1];
14842 int size,res,fd,len,x;
14843 int bytes=0;
14844 /* Initial carrier (imaginary) */
14845 float cr = 1.0;
14846 float ci = 0.0;
14847 float scont = 0.0;
14848 int idx;
14850 idx = dahdi_get_index(c, p, 0);
14851 if (idx < 0) {
14852 ast_log(LOG_WARNING, "Huh? I don't exist?\n");
14853 return -1;
14855 if (!text[0]) return(0); /* if nothing to send, dont */
14856 if ((!p->tdd) && (!p->mate)) return(0); /* if not in TDD mode, just return */
14857 if (p->mate)
14858 buf = ast_malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN);
14859 else
14860 buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
14861 if (!buf)
14862 return -1;
14863 mybuf = buf;
14864 if (p->mate) {
14865 int codec = AST_LAW(p);
14866 for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
14867 PUT_CLID_MARKMS;
14869 /* Put actual message */
14870 for (x = 0; text[x]; x++) {
14871 PUT_CLID(text[x]);
14873 for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
14874 PUT_CLID_MARKMS;
14876 len = bytes;
14877 buf = mybuf;
14878 } else {
14879 len = tdd_generate(p->tdd, buf, text);
14880 if (len < 1) {
14881 ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
14882 ast_free(mybuf);
14883 return -1;
14886 memset(buf + len, 0x7f, END_SILENCE_LEN);
14887 len += END_SILENCE_LEN;
14888 fd = p->subs[idx].dfd;
14889 while (len) {
14890 if (ast_check_hangup(c)) {
14891 ast_free(mybuf);
14892 return -1;
14894 size = len;
14895 if (size > READ_SIZE)
14896 size = READ_SIZE;
14897 fds[0].fd = fd;
14898 fds[0].events = POLLOUT | POLLPRI;
14899 fds[0].revents = 0;
14900 res = poll(fds, 1, -1);
14901 if (!res) {
14902 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
14903 continue;
14905 /* if got exception */
14906 if (fds[0].revents & POLLPRI) {
14907 ast_free(mybuf);
14908 return -1;
14910 if (!(fds[0].revents & POLLOUT)) {
14911 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
14912 continue;
14914 res = write(fd, buf, size);
14915 if (res != size) {
14916 if (res == -1) {
14917 ast_free(mybuf);
14918 return -1;
14920 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
14921 break;
14923 len -= size;
14924 buf += size;
14926 ast_free(mybuf);
14927 return(0);
14931 static int reload(void)
14933 int res = 0;
14935 res = setup_dahdi(1);
14936 if (res) {
14937 ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
14938 return -1;
14940 return 0;
14943 /* This is a workaround so that menuselect displays a proper description
14944 * AST_MODULE_INFO(, , "DAHDI Telephony"
14947 #ifdef HAVE_PRI
14948 #ifdef HAVE_SS7
14949 #define tdesc "DAHDI Telephony w/PRI & SS7"
14950 #else
14951 #define tdesc "DAHDI Telephony w/PRI"
14952 #endif
14953 #else
14954 #ifdef HAVE_SS7
14955 #define tdesc "DAHDI Telephony w/SS7"
14956 #else
14957 #define tdesc "DAHDI Telephony"
14958 #endif
14959 #endif
14961 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
14962 .load = load_module,
14963 .unload = unload_module,
14964 .reload = reload,