2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2008, 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.
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 * \ingroup channel_drivers
34 * \todo Deprecate the "musiconhold" configuration option post 1.4
37 /*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
38 * \addtogroup configuration_file
41 /*! \page chan_dahdi.conf chan_dahdi.conf
42 * \verbinclude chan_dahdi.conf.sample
46 <depend>dahdi</depend>
47 <depend>tonezone</depend>
48 <use type="module">res_smdi</use>
49 <use type="external">pri</use>
50 <use type="external">ss7</use>
51 <use type="external">openr2</use>
52 <support_level>core</support_level>
57 #if defined(__NetBSD__) || defined(__FreeBSD__)
60 #include <sys/sysmacros.h>
66 #include "sig_analog.h"
67 /* Analog signaling is currently still present in chan_dahdi for use with
68 * radio. Sig_analog does not currently handle any radio operations. If
69 * radio only uses analog signaling, then the radio handling logic could
70 * be placed in sig_analog and the duplicated code could be removed.
76 #error "Upgrade your libpri"
78 #endif /* defined(HAVE_PRI) */
82 #if !defined(LIBSS7_ABI_COMPATIBILITY)
83 #error "Upgrade your libss7"
84 #elif LIBSS7_ABI_COMPATIBILITY != 2
85 #error "Your installed libss7 is not compatible"
87 #endif /* defined(HAVE_SS7) */
89 #if defined(HAVE_OPENR2)
90 /* put this here until sig_mfcr2 comes along */
91 #define SIG_MFCR2_MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
92 #endif /* defined(HAVE_OPENR2) */
94 #include "asterisk/lock.h"
95 #include "asterisk/channel.h"
96 #include "asterisk/config.h"
97 #include "asterisk/module.h"
98 #include "asterisk/pbx.h"
99 #include "asterisk/file.h"
100 #include "asterisk/ulaw.h"
101 #include "asterisk/alaw.h"
102 #include "asterisk/callerid.h"
103 #include "asterisk/adsi.h"
104 #include "asterisk/cli.h"
105 #include "asterisk/pickup.h"
106 #include "asterisk/features.h"
107 #include "asterisk/musiconhold.h"
108 #include "asterisk/say.h"
109 #include "asterisk/tdd.h"
110 #include "asterisk/mwi.h"
111 #include "asterisk/dsp.h"
112 #include "asterisk/astdb.h"
113 #include "asterisk/manager.h"
114 #include "asterisk/causes.h"
115 #include "asterisk/term.h"
116 #include "asterisk/utils.h"
117 #include "asterisk/transcap.h"
118 #include "asterisk/stringfields.h"
119 #include "asterisk/abstract_jb.h"
120 #include "asterisk/smdi.h"
121 #include "asterisk/devicestate.h"
122 #include "asterisk/paths.h"
123 #include "asterisk/ccss.h"
124 #include "asterisk/features_config.h"
125 #include "asterisk/bridge.h"
126 #include "asterisk/stasis_channels.h"
127 #include "asterisk/parking.h"
128 #include "asterisk/format_cache.h"
129 #include "chan_dahdi.h"
130 #include "dahdi/bridge_native_dahdi.h"
133 <application name="DAHDISendKeypadFacility" language="en_US">
135 Send digits out of band over a PRI.
138 <parameter name="digits" required="true" />
141 <para>This application will send the given string of digits in a Keypad
142 Facility IE over the current channel.</para>
145 <application name="DAHDISendCallreroutingFacility" language="en_US">
147 Send an ISDN call rerouting/deflection facility message.
150 <parameter name="destination" required="true">
151 <para>Destination number.</para>
153 <parameter name="original">
154 <para>Original called number.</para>
156 <parameter name="reason">
157 <para>Diversion reason, if not specified defaults to <literal>unknown</literal></para>
161 <para>This application will send an ISDN switch specific call
162 rerouting/deflection facility message over the current channel.
163 Supported switches depend upon the version of libpri in use.</para>
166 <application name="DAHDIAcceptR2Call" language="en_US">
168 Accept an R2 call if its not already accepted (you still need to answer it)
171 <parameter name="charge" required="true">
172 <para>Yes or No.</para>
173 <para>Whether you want to accept the call with charge or without charge.</para>
177 <para>This application will Accept the R2 call either with charge or no charge.</para>
180 <function name="POLARITY" language="en_US">
182 Set or get the polarity of a DAHDI channel.
186 <para>The POLARITY function can be used to set the polarity of a DAHDI channel.</para>
187 <para>Applies only to FXS channels (using FXO signalling) with supporting hardware.</para>
188 <para>The polarity can be set to the following numeric or named values:</para>
193 <enum name="reverse" />
195 <para>However, when read, the function will always return 0 or 1.</para>
196 <example title="Set idle polarity">
197 same => n,Set(POLARITY()=0)
199 <example title="Set reverse polarity">
200 same => n,NoOp(Current Polarity: ${POLARITY()})
201 same => n,Set(POLARITY()=reverse)
202 same => n,NoOp(New Polarity: ${POLARITY()})
204 <example title="Reverse the polarity from whatever it is currently">
205 same => n,Set(POLARITY()=${IF($[ "${POLARITY()}" = "1" ]?0:1)})
209 <info name="CHANNEL" language="en_US" tech="DAHDI">
211 <enum name="dahdi_channel">
212 <para>R/O DAHDI channel related to this channel.</para>
214 <enum name="dahdi_span">
215 <para>R/O DAHDI span related to this channel.</para>
217 <enum name="dahdi_group">
218 <para>R/O DAHDI logical group related to this channel.</para>
220 <enum name="dahdi_type">
221 <para>R/O DAHDI channel type, one of:</para>
223 <enum name="analog" />
224 <enum name="mfc/r2" />
226 <enum name="pseudo" />
230 <enum name="keypad_digits">
231 <para>R/O PRI Keypad digits that came in with the SETUP message.</para>
233 <enum name="reversecharge">
234 <para>R/O PRI Reverse Charging Indication, one of:</para>
236 <enum name="-1"> <para>None</para></enum>
237 <enum name=" 1"> <para>Reverse Charging Requested</para></enum>
240 <enum name="no_media_path">
241 <para>R/O PRI Nonzero if the channel has no B channel.
242 The channel is either on hold or a call waiting call.</para>
244 <enum name="buffers">
245 <para>W/O Change the channel's buffer policy (for the current call only)</para>
246 <para>This option takes two arguments:</para>
247 <para> Number of buffers,</para>
248 <para> Buffer policy being one of:</para>
249 <para> <literal>full</literal></para>
250 <para> <literal>immediate</literal></para>
251 <para> <literal>half</literal></para>
253 <enum name="echocan_mode">
254 <para>W/O Change the configuration of the active echo
255 canceller on the channel (if any), for the current call
257 <para>Possible values are:</para>
258 <para> <literal>on</literal> Normal mode (the echo canceller is actually reinitialized)</para>
259 <para> <literal>off</literal> Disabled</para>
260 <para> <literal>fax</literal> FAX/data mode (NLP disabled if possible, otherwise
261 completely disabled)</para>
262 <para> <literal>voice</literal> Voice mode (returns from FAX mode, reverting the changes that were made)</para>
264 <enum name="dialmode">
265 <para>R/W Pulse and tone dialing mode of the channel.</para>
266 <para>Disabling tone dialing using this option will not disable the DSP used for DTMF detection.
267 To do that, also set the <literal>digitdetect</literal> option. If digit detection is disabled,
268 DTMF will not be detected, regardless of the <literal>dialmode</literal> setting.
269 The <literal>digitdetect</literal> setting has no impact on pulse dialing detection.</para>
270 <para>If set, overrides the setting in <literal>chan_dahdi.conf</literal> for that channel.</para>
273 <enum name="pulse" />
281 <info name="Dial_Resource" language="en_US" tech="DAHDI">
282 <para>DAHDI allows several modifiers to be specified as part of the resource.</para>
283 <para>The general syntax is :</para>
284 <para><literal>Dial(DAHDI/pseudo[/extension])</literal></para>
285 <para><literal>Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension])</literal></para>
286 <para><literal>Dial(DAHDI/(g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension])</literal></para>
287 <para>The following modifiers may be used before the channel number:</para>
290 <para>Search forward, dialing on first available channel in group (lowest to highest).</para>
293 <para>Search backward, dialing on first available channel in group (highest to lowest).</para>
296 <para>Round robin search forward, picking up from where last left off (lowest to highest).</para>
299 <para>Round robin search backward, picking up from where last left off (highest to lowest).</para>
302 <para>The following modifiers may be used after the channel number:</para>
305 <para>Wait for DTMF digit <literal>#</literal> before providing answer supervision.</para>
306 <para>This can be useful on outbound calls via FXO ports, as otherwise
307 they would indicate answer immediately.</para>
310 <para>Force bearer capability for ISDN/SS7 call to digital.</para>
313 <para>ISDN span channel restriction.</para>
314 <para>Used by CC to ensure that the CC recall goes out the same span.
315 Also to make ISDN channel names dialable when the sequence number
316 is stripped off. (Used by DTMF attended transfer feature.)</para>
319 <para>Specifies the distinctive ring cadence number to use immediately after
320 specifying this option. There are 4 default built-in cadences, and up to 24
321 total cadences may be configured.</para>
324 <example title="Dial 555-1212 on first available channel in group 1, searching from highest to lowest">
325 same => n,Dial(DAHDI/g1/5551212)
327 <example title="Ringing FXS channel 4 with ring cadence 2">
328 same => n,Dial(DAHDI/4r2)
330 <example title="Dial 555-1212 on channel 3 and require answer confirmation">
331 same => n,Dial(DAHDI/3c/5551212)
334 <manager name="DAHDITransfer" language="en_US">
336 Transfer DAHDI Channel.
339 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
340 <parameter name="DAHDIChannel" required="true">
341 <para>DAHDI channel number to transfer.</para>
345 <para>Simulate a flash hook event by the user connected to the channel.</para>
346 <note><para>Valid only for analog channels.</para></note>
349 <manager name="DAHDIHangup" language="en_US">
351 Hangup DAHDI Channel.
354 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
355 <parameter name="DAHDIChannel" required="true">
356 <para>DAHDI channel number to hangup.</para>
360 <para>Simulate an on-hook event by the user connected to the channel.</para>
361 <note><para>Valid only for analog channels.</para></note>
364 <manager name="DAHDIDialOffhook" language="en_US">
366 Dial over DAHDI channel while offhook.
369 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
370 <parameter name="DAHDIChannel" required="true">
371 <para>DAHDI channel number to dial digits.</para>
373 <parameter name="Number" required="true">
374 <para>Digits to dial.</para>
378 <para>Generate DTMF control frames to the bridged peer.</para>
381 <manager name="DAHDIDNDon" language="en_US">
383 Toggle DAHDI channel Do Not Disturb status ON.
386 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
387 <parameter name="DAHDIChannel" required="true">
388 <para>DAHDI channel number to set DND on.</para>
392 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> on".</para>
393 <note><para>Feature only supported by analog channels.</para></note>
396 <manager name="DAHDIDNDoff" language="en_US">
398 Toggle DAHDI channel Do Not Disturb status OFF.
401 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
402 <parameter name="DAHDIChannel" required="true">
403 <para>DAHDI channel number to set DND off.</para>
407 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> off".</para>
408 <note><para>Feature only supported by analog channels.</para></note>
411 <manager name="DAHDIShowChannels" language="en_US">
413 Show status of DAHDI channels.
416 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
417 <parameter name="DAHDIChannel">
418 <para>Specify the specific channel number to show. Show all channels if zero or not present.</para>
422 <para>Similar to the CLI command "dahdi show channels".</para>
425 <manager name="DAHDIRestart" language="en_US">
427 Fully Restart DAHDI channels (terminates calls).
430 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
433 <para>Equivalent to the CLI command "dahdi restart".</para>
436 <manager name="PRIShowSpans" language="en_US">
438 Show status of PRI spans.
441 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
442 <parameter name="Span">
443 <para>Specify the specific span to show. Show all spans if zero or not present.</para>
447 <para>Similar to the CLI command "pri show spans".</para>
450 <manager name="PRIDebugSet" language="en_US">
452 Set PRI debug levels for a span
455 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
456 <parameter name="Span" required="true">
457 <para>Which span to affect.</para>
459 <parameter name="Level" required="true">
460 <para>What debug level to set. May be a numerical value or a text value from the list below</para>
465 <enum name="intense" />
470 <para>Equivalent to the CLI command "pri set debug <level> span <span>".</para>
473 <manager name="PRIDebugFileSet" language="en_US">
475 Set the file used for PRI debug message output
478 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
479 <parameter name="File" required="true">
480 <para>Path of file to write debug output.</para>
484 <para>Equivalent to the CLI command "pri set debug file <output-file>"</para>
487 <manager name="PRIDebugFileUnset" language="en_US">
489 Disables file output for PRI debug messages
492 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
495 <managerEvent language="en_US" name="AlarmClear">
496 <managerEventInstance class="EVENT_FLAG_SYSTEM">
497 <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
499 <parameter name="DAHDIChannel">
500 <para>The DAHDI channel on which the alarm was cleared.</para>
501 <note><para>This is not an Asterisk channel identifier.</para></note>
504 </managerEventInstance>
506 <managerEvent language="en_US" name="SpanAlarmClear">
507 <managerEventInstance class="EVENT_FLAG_SYSTEM">
508 <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
510 <parameter name="Span">
511 <para>The span on which the alarm was cleared.</para>
514 </managerEventInstance>
516 <managerEvent language="en_US" name="DNDState">
517 <managerEventInstance class="EVENT_FLAG_SYSTEM">
518 <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
520 <parameter name="DAHDIChannel">
521 <para>The DAHDI channel on which DND status changed.</para>
522 <note><para>This is not an Asterisk channel identifier.</para></note>
524 <parameter name="Status">
526 <enum name="enabled"/>
527 <enum name="disabled"/>
531 </managerEventInstance>
533 <managerEvent language="en_US" name="Alarm">
534 <managerEventInstance class="EVENT_FLAG_SYSTEM">
535 <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
537 <parameter name="DAHDIChannel">
538 <para>The channel on which the alarm occurred.</para>
539 <note><para>This is not an Asterisk channel identifier.</para></note>
541 <parameter name="Alarm">
542 <para>A textual description of the alarm that occurred.</para>
545 </managerEventInstance>
547 <managerEvent language="en_US" name="SpanAlarm">
548 <managerEventInstance class="EVENT_FLAG_SYSTEM">
549 <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
551 <parameter name="Span">
552 <para>The span on which the alarm occurred.</para>
554 <parameter name="Alarm">
555 <para>A textual description of the alarm that occurred.</para>
558 </managerEventInstance>
560 <managerEvent language="en_US" name="DAHDIChannel">
561 <managerEventInstance class="EVENT_FLAG_CALL">
562 <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
565 <parameter name="DAHDIGroup">
566 <para>The DAHDI logical group associated with this channel.</para>
568 <parameter name="DAHDISpan">
569 <para>The DAHDI span associated with this channel.</para>
571 <parameter name="DAHDIChannel">
572 <para>The DAHDI channel associated with this channel.</para>
575 </managerEventInstance>
579 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
581 static const char * const lbostr
[] = {
582 "0 db (CSU)/0-133 feet (DSX-1)",
583 "133-266 feet (DSX-1)",
584 "266-399 feet (DSX-1)",
585 "399-533 feet (DSX-1)",
586 "533-655 feet (DSX-1)",
592 /*! Global jitterbuffer configuration - by default, jb is disabled
593 * \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
594 static struct ast_jb_conf default_jbconf
=
598 .resync_threshold
= 1000,
602 static struct ast_jb_conf global_jbconf
;
605 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
606 * the user hangs up to reset the state machine so ring works properly.
607 * This is used to be able to support kewlstart by putting the zhone in
608 * groundstart mode since their forward disconnect supervision is entirely
609 * broken even though their documentation says it isn't and their support
610 * is entirely unwilling to provide any assistance with their channel banks
611 * even though their web site says they support their products for life.
613 /* #define ZHONE_HACK */
615 /*! \brief Typically, how many rings before we should send Caller*ID */
616 #define DEFAULT_CIDRINGS 1
618 #define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
621 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
622 #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))
624 static const char tdesc
[] = "DAHDI Telephony"
625 #if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
627 #if defined(HAVE_PRI)
629 #endif /* defined(HAVE_PRI) */
630 #if defined(HAVE_SS7)
631 #if defined(HAVE_PRI)
633 #endif /* defined(HAVE_PRI) */
635 #endif /* defined(HAVE_SS7) */
636 #if defined(HAVE_OPENR2)
637 #if defined(HAVE_PRI) || defined(HAVE_SS7)
639 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
641 #endif /* defined(HAVE_OPENR2) */
642 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2) */
645 static const char config
[] = "chan_dahdi.conf";
648 #define NUM_SPANS DAHDI_MAX_SPANS
653 #define CHAN_PSEUDO -2
655 #define CALLPROGRESS_PROGRESS 1
656 #define CALLPROGRESS_FAX_OUTGOING 2
657 #define CALLPROGRESS_FAX_INCOMING 4
658 #define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
660 #define NUM_CADENCE_MAX 25
661 static int num_cadence
= 4;
662 static int user_has_defined_cadences
= 0;
664 static int has_pseudo
;
666 static struct dahdi_ring_cadence cadences
[NUM_CADENCE_MAX
] = {
667 { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
668 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
669 { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
670 { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
673 /*! \brief cidrings says in which pause to transmit the cid information, where the first pause
674 * is 1, the second pause is 2 and so on.
677 static int cidrings
[NUM_CADENCE_MAX
] = {
678 2, /*!< Right after first long ring */
679 4, /*!< Right after long part */
680 3, /*!< After third chirp */
681 2, /*!< Second spell */
684 /* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
685 static struct dahdi_ring_cadence AS_RP_cadence
= {{250, 10000}};
687 #define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
688 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
690 #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
691 #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
693 static char defaultcic
[64] = "";
694 static char defaultozz
[64] = "";
696 /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
697 static char mwimonitornotify
[PATH_MAX
] = "";
698 #ifndef HAVE_DAHDI_LINEREVERSE_VMWI
699 static int mwisend_rpas
= 0;
702 static char progzone
[10] = "";
704 static int usedistinctiveringdetection
= 0;
705 static int distinctiveringaftercid
= 0;
707 static int numbufs
= 4;
709 static int mwilevel
= 512;
710 static int dtmfcid_level
= 256;
712 #define REPORT_CHANNEL_ALARMS 1
713 #define REPORT_SPAN_ALARMS 2
714 static int report_alarms
= REPORT_CHANNEL_ALARMS
;
717 static int pridebugfd
= -1;
718 static char pridebugfilename
[1024] = "";
721 /*! \brief Protect the interface list (of dahdi_pvt's) */
722 AST_MUTEX_DEFINE_STATIC(iflock
);
725 static int ifcount
= 0;
728 AST_MUTEX_DEFINE_STATIC(pridebugfdlock
);
731 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
732 when it's doing something critical. */
733 AST_MUTEX_DEFINE_STATIC(monlock
);
735 /*! \brief This is the thread for the monitor which checks for input on the channels
736 which are not currently in use. */
737 static pthread_t monitor_thread
= AST_PTHREADT_NULL
;
738 static ast_cond_t ss_thread_complete
;
739 AST_MUTEX_DEFINE_STATIC(ss_thread_lock
);
740 AST_MUTEX_DEFINE_STATIC(restart_lock
);
741 static int ss_thread_count
= 0;
742 static int num_restart_pending
= 0;
744 static int restart_monitor(void);
746 static int dahdi_sendtext(struct ast_channel
*c
, const char *text
);
748 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
749 static inline int dahdi_get_event(int fd
)
752 if (ioctl(fd
, DAHDI_GETEVENT
, &j
) == -1)
757 /*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
758 static inline int dahdi_wait_event(int fd
)
761 i
= DAHDI_IOMUX_SIGEVENT
;
762 if (ioctl(fd
, DAHDI_IOMUX
, &i
) == -1)
764 if (ioctl(fd
, DAHDI_GETEVENT
, &j
) == -1)
769 /*! Chunk size to read -- we use 20ms chunks to make things happy. */
770 #define READ_SIZE 160
772 #define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
773 #define MASK_INUSE (1 << 1) /*!< Channel currently in use */
775 #define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE) /*!< 300 ms */
776 #define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
777 #define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE) /*!< 100 ms */
778 #define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE) /*!< 500 ms */
779 #define MIN_MS_SINCE_FLASH ((2000) ) /*!< 2000 ms */
780 #define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
781 #define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
784 * \brief Configured ring timeout base.
785 * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
787 static int ringt_base
= DEFAULT_RINGT
;
789 #if defined(HAVE_SS7)
792 struct sig_ss7_linkset ss7
;
795 static struct dahdi_ss7 linksets
[NUM_SPANS
];
797 static int cur_ss7type
= -1;
798 static int cur_slc
= -1;
799 static int cur_linkset
= -1;
800 static int cur_pointcode
= -1;
801 static int cur_cicbeginswith
= -1;
802 static int cur_adjpointcode
= -1;
803 static int cur_networkindicator
= -1;
804 static int cur_defaultdpc
= -1;
805 #endif /* defined(HAVE_SS7) */
808 struct dahdi_mfcr2_conf
{
809 openr2_variant_t variant
;
811 int metering_pulse_timeout
;
814 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
818 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
819 int dtmf_end_timeout
;
821 signed int get_ani_first
:2;
822 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
823 signed int skip_category_request
:2;
825 unsigned int call_files
:1;
826 unsigned int allow_collect_calls
:1;
827 unsigned int charge_calls
:1;
828 unsigned int accept_on_offer
:1;
829 unsigned int forced_release
:1;
830 unsigned int double_answer
:1;
831 signed int immediate_accept
:2;
832 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
833 signed int dtmf_dialing
:2;
834 signed int dtmf_detection
:2;
836 char logdir
[OR2_MAX_PATH
];
837 char r2proto_file
[OR2_MAX_PATH
];
838 openr2_log_level_t loglevel
;
839 openr2_calling_party_category_t category
;
842 /* MFC-R2 pseudo-link structure */
844 int index
; /*!< Unique index for CLI */
845 pthread_t r2master
; /*!< Thread of master */
846 openr2_context_t
*protocol_context
; /*!< OpenR2 context handle */
847 struct dahdi_pvt
*pvts
[SIG_MFCR2_MAX_CHANNELS
]; /*!< Member channel pvt structs */
848 int numchans
; /*!< Number of channels in this R2 block */
849 int live_chans
; /*!< Number of unremoved channels in this R2 block */
850 int nodev
; /*!< Link disconnected? */
851 struct dahdi_mfcr2_conf conf
; /*!< Configuration used to setup this pseudo-link */
854 struct r2link_entry
{
855 struct dahdi_mfcr2 mfcr2
;
856 AST_LIST_ENTRY(r2link_entry
) list
;
858 static AST_LIST_HEAD_STATIC(r2links
, r2link_entry
);
859 static struct r2links nodev_r2links
= AST_LIST_HEAD_INIT_VALUE
;
862 /* how many r2links have been malloc'd */
863 static int r2links_count
= 0;
865 #endif /* HAVE_OPENR2 */
870 int dchannels
[SIG_PRI_NUM_DCHANS
]; /*!< What channel are the dchannels on */
871 int mastertrunkgroup
; /*!< What trunk group is our master */
872 int prilogicalspan
; /*!< Logical span number within trunk group */
873 struct sig_pri_span pri
;
876 static struct dahdi_pri pris
[NUM_SPANS
];
878 #if defined(HAVE_PRI_CCSS)
879 /*! DAHDI PRI CCSS agent and monitor type name. */
880 static const char dahdi_pri_cc_type
[] = "DAHDI/PRI";
881 #endif /* defined(HAVE_PRI_CCSS) */
884 /*! Shut up the compiler */
888 /* Polarity states */
889 #define POLARITY_IDLE 0
890 #define POLARITY_REV 1
892 const char * const subnames
[] = {
898 static struct dahdi_pvt
*iflist
= NULL
; /*!< Main interface list start */
899 static struct dahdi_pvt
*ifend
= NULL
; /*!< Main interface list end */
901 #if defined(HAVE_PRI)
903 struct sig_pri_span
*pri
;
904 AST_LIST_ENTRY(doomed_pri
) list
;
906 static AST_LIST_HEAD_STATIC(doomed_pris
, doomed_pri
);
908 static void pri_destroy_span(struct sig_pri_span
*pri
);
910 static struct dahdi_parms_pseudo
{
911 int buf_no
; /*!< Number of buffers */
912 int buf_policy
; /*!< Buffer policy */
913 int faxbuf_no
; /*!< Number of Fax buffers */
914 int faxbuf_policy
; /*!< Fax buffer policy */
915 } dahdi_pseudo_parms
;
916 #endif /* defined(HAVE_PRI) */
918 /*! \brief Channel configuration from chan_dahdi.conf .
919 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
920 * Generally there is a field here for every possible configuration item.
922 * The state of fields is saved along the parsing and whenever a 'channel'
923 * statement is reached, the current dahdi_chan_conf is used to configure the
924 * channel (struct dahdi_pvt)
926 * \see dahdi_chan_init for the default values.
928 struct dahdi_chan_conf
{
929 struct dahdi_pvt chan
;
931 struct dahdi_pri pri
;
934 #if defined(HAVE_SS7)
935 struct dahdi_ss7 ss7
;
936 #endif /* defined(HAVE_SS7) */
939 struct dahdi_mfcr2_conf mfcr2
;
941 struct dahdi_params timing
;
942 int is_sig_auto
; /*!< Use channel signalling from DAHDI? */
943 /*! Continue configuration even if a channel is not there. */
944 int ignore_failed_channels
;
947 * \brief The serial port to listen for SMDI data on
948 * \note Set from the "smdiport" string read in from chan_dahdi.conf
950 char smdi_port
[SMDI_MAX_FILENAME_LEN
];
953 * \brief Don't create channels below this number
954 * \note by default is 0 (no limit)
956 int wanted_channels_start
;
959 * \brief Don't create channels above this number (infinity by default)
960 * \note by default is 0 (special value that means "no limit").
962 int wanted_channels_end
;
965 /*! returns a new dahdi_chan_conf with default values (by-value) */
966 static struct dahdi_chan_conf
dahdi_chan_conf_default(void)
968 /* recall that if a field is not included here it is initialized
971 struct dahdi_chan_conf conf
= {
975 .switchtype
= PRI_SWITCH_NI2
,
976 .dialplan
= PRI_UNKNOWN
+ 1,
977 .localdialplan
= PRI_NATIONAL_ISDN
+ 1,
979 .qsigchannelmapping
= DAHDI_CHAN_MAPPING_PHYSICAL
,
981 #if defined(HAVE_PRI_CCSS)
982 .cc_ptmp_recall_mode
= 1,/* specificRecall */
983 .cc_qsig_signaling_link_req
= 1,/* retain */
984 .cc_qsig_signaling_link_rsp
= 1,/* retain */
985 #endif /* defined(HAVE_PRI_CCSS) */
990 .internationalprefix
= "",
991 .nationalprefix
= "",
995 .colp_send
= SIG_PRI_COLP_UPDATE
,
999 #if defined(HAVE_SS7)
1001 .called_nai
= SS7_NAI_NATIONAL
,
1002 .calling_nai
= SS7_NAI_NATIONAL
,
1003 .internationalprefix
= "",
1004 .nationalprefix
= "",
1005 .subscriberprefix
= "",
1006 .unknownprefix
= "",
1007 .networkroutedprefix
= ""
1009 #endif /* defined(HAVE_SS7) */
1012 .variant
= OR2_VAR_ITU
,
1013 .mfback_timeout
= -1,
1014 .metering_pulse_timeout
= -1,
1017 .get_ani_first
= -1,
1018 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
1019 .skip_category_request
= -1,
1022 .allow_collect_calls
= 0,
1024 .accept_on_offer
= 1,
1025 .forced_release
= 0,
1027 .immediate_accept
= -1,
1028 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
1030 .dtmf_detection
= -1,
1031 .dtmf_time_on
= OR2_DEFAULT_DTMF_ON
,
1032 .dtmf_time_off
= OR2_DEFAULT_DTMF_OFF
,
1034 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
1035 .dtmf_end_timeout
= -1,
1039 .loglevel
= OR2_LOG_ERROR
| OR2_LOG_WARNING
,
1040 .category
= OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
1044 .context
= "default",
1049 .mohinterpret
= "default",
1052 .transfertobusy
= 1,
1055 .ani_info_digits
= 2,
1056 .ani_wink_time
= 1000,
1057 .ani_timeout
= 10000,
1059 .cid_signalling
= CID_SIG_BELL
,
1060 .cid_start
= CID_START_RING
,
1061 .dahditrcallerid
= 0,
1070 .echocancel
.head
.tap_length
= 1,
1078 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
1081 .polarityonanswerdelay
= 600,
1083 .sendcalleridafter
= DEFAULT_CIDRINGS
,
1085 .buf_policy
= DAHDI_POLICY_IMMEDIATE
,
1088 .cc_params
= ast_cc_config_params_init(),
1089 .firstdigit_timeout
= ANALOG_FIRST_DIGIT_TIMEOUT
,
1090 .interdigit_timeout
= ANALOG_INTER_DIGIT_TIMEOUT
,
1091 .matchdigit_timeout
= ANALOG_MATCH_DIGIT_TIMEOUT
,
1104 .ignore_failed_channels
= 1,
1105 .smdi_port
= "/dev/ttyS0",
1112 static struct ast_channel
*dahdi_request(const char *type
, struct ast_format_cap
*cap
,
1113 const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
,
1114 const char *data
, int *cause
);
1115 static int dahdi_digit_begin(struct ast_channel
*ast
, char digit
);
1116 static int dahdi_digit_end(struct ast_channel
*ast
, char digit
, unsigned int duration
);
1117 static int dahdi_sendtext(struct ast_channel
*c
, const char *text
);
1118 static int dahdi_call(struct ast_channel
*ast
, const char *rdest
, int timeout
);
1119 static int dahdi_hangup(struct ast_channel
*ast
);
1120 static int dahdi_answer(struct ast_channel
*ast
);
1121 static struct ast_frame
*dahdi_read(struct ast_channel
*ast
);
1122 static int dahdi_write(struct ast_channel
*ast
, struct ast_frame
*frame
);
1123 static struct ast_frame
*dahdi_exception(struct ast_channel
*ast
);
1124 static int dahdi_indicate(struct ast_channel
*chan
, int condition
, const void *data
, size_t datalen
);
1125 static int dahdi_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
);
1126 static int dahdi_setoption(struct ast_channel
*chan
, int option
, void *data
, int datalen
);
1127 static int dahdi_queryoption(struct ast_channel
*chan
, int option
, void *data
, int *datalen
);
1128 static int dahdi_func_read(struct ast_channel
*chan
, const char *function
, char *data
, char *buf
, size_t len
);
1129 static int dahdi_func_write(struct ast_channel
*chan
, const char *function
, char *data
, const char *value
);
1130 static int dahdi_devicestate(const char *data
);
1131 static int dahdi_cc_callback(struct ast_channel
*inbound
, const char *dest
, ast_cc_callback_fn callback
);
1133 static struct ast_channel_tech dahdi_tech
= {
1135 .description
= tdesc
,
1136 .requester
= dahdi_request
,
1137 .send_digit_begin
= dahdi_digit_begin
,
1138 .send_digit_end
= dahdi_digit_end
,
1139 .send_text
= dahdi_sendtext
,
1141 .hangup
= dahdi_hangup
,
1142 .answer
= dahdi_answer
,
1144 .write
= dahdi_write
,
1145 .exception
= dahdi_exception
,
1146 .indicate
= dahdi_indicate
,
1147 .fixup
= dahdi_fixup
,
1148 .setoption
= dahdi_setoption
,
1149 .queryoption
= dahdi_queryoption
,
1150 .func_channel_read
= dahdi_func_read
,
1151 .func_channel_write
= dahdi_func_write
,
1152 .devicestate
= dahdi_devicestate
,
1153 .cc_callback
= dahdi_cc_callback
,
1156 #define GET_CHANNEL(p) ((p)->channel)
1158 static enum analog_sigtype
dahdisig_to_analogsig(int sig
)
1162 return ANALOG_SIG_FXOLS
;
1164 return ANALOG_SIG_FXOGS
;
1166 return ANALOG_SIG_FXOKS
;
1168 return ANALOG_SIG_FXSLS
;
1170 return ANALOG_SIG_FXSGS
;
1172 return ANALOG_SIG_FXSKS
;
1174 return ANALOG_SIG_EMWINK
;
1176 return ANALOG_SIG_EM
;
1178 return ANALOG_SIG_EM_E1
;
1180 return ANALOG_SIG_FEATD
;
1182 return ANALOG_SIG_FEATDMF
;
1186 return ANALOG_SIG_FGC_CAMA
;
1187 case SIG_FGC_CAMAMF
:
1188 return ANALOG_SIG_FGC_CAMAMF
;
1190 return ANALOG_SIG_FEATB
;
1192 return ANALOG_SIG_SFWINK
;
1194 return ANALOG_SIG_SF
;
1196 return ANALOG_SIG_SF_FEATD
;
1197 case SIG_SF_FEATDMF
:
1198 return ANALOG_SIG_SF_FEATDMF
;
1199 case SIG_FEATDMF_TA
:
1200 return ANALOG_SIG_FEATDMF_TA
;
1202 return ANALOG_SIG_FEATB
;
1209 static int analog_tone_to_dahditone(enum analog_tone tone
)
1212 case ANALOG_TONE_RINGTONE
:
1213 return DAHDI_TONE_RINGTONE
;
1214 case ANALOG_TONE_STUTTER
:
1215 return DAHDI_TONE_STUTTER
;
1216 case ANALOG_TONE_CONGESTION
:
1217 return DAHDI_TONE_CONGESTION
;
1218 case ANALOG_TONE_DIALTONE
:
1219 return DAHDI_TONE_DIALTONE
;
1220 case ANALOG_TONE_DIALRECALL
:
1221 return DAHDI_TONE_DIALRECALL
;
1222 case ANALOG_TONE_INFO
:
1223 return DAHDI_TONE_INFO
;
1229 static int analogsub_to_dahdisub(enum analog_sub analogsub
)
1233 switch (analogsub
) {
1234 case ANALOG_SUB_REAL
:
1237 case ANALOG_SUB_CALLWAIT
:
1238 index
= SUB_CALLWAIT
;
1240 case ANALOG_SUB_THREEWAY
:
1241 index
= SUB_THREEWAY
;
1244 ast_log(LOG_ERROR
, "Unidentified sub!\n");
1253 * \brief release all members on the doomed pris list
1256 * Called priodically by the monitor threads to release spans marked for
1259 static void release_doomed_pris(void)
1262 struct doomed_pri
*entry
;
1264 AST_LIST_LOCK(&doomed_pris
);
1265 while ((entry
= AST_LIST_REMOVE_HEAD(&doomed_pris
, list
))) {
1266 /* The span destruction must be done with this lock not held */
1267 AST_LIST_UNLOCK(&doomed_pris
);
1268 ast_debug(4, "Destroying span %d from doomed queue.\n",
1270 pri_destroy_span(entry
->pri
);
1272 AST_LIST_LOCK(&doomed_pris
);
1274 AST_LIST_UNLOCK(&doomed_pris
);
1280 * \brief Queue a span for destruction
1283 * \param pri the span to destroy
1285 * Add a span to the list of spans to be destroyed later on
1286 * by the monitor thread. Allows destroying a span while holding its
1289 static void pri_queue_for_destruction(struct sig_pri_span
*pri
)
1291 struct doomed_pri
*entry
;
1293 AST_LIST_LOCK(&doomed_pris
);
1294 AST_LIST_TRAVERSE(&doomed_pris
, entry
, list
) {
1295 if (entry
->pri
== pri
) {
1296 AST_LIST_UNLOCK(&doomed_pris
);
1300 entry
= ast_calloc(sizeof(struct doomed_pri
), 1);
1302 /* Nothing useful to do here. Panic? */
1303 ast_log(LOG_WARNING
, "Failed allocating memory for a doomed_pri.\n");
1304 AST_LIST_UNLOCK(&doomed_pris
);
1308 ast_debug(4, "Queue span %d for destruction.\n", pri
->span
);
1309 AST_LIST_INSERT_TAIL(&doomed_pris
, entry
, list
);
1310 AST_LIST_UNLOCK(&doomed_pris
);
1316 * \brief Send a dial string to DAHDI.
1319 * \param pvt DAHDI private pointer
1320 * \param operation DAHDI dial operation to do to string
1321 * \param dial_str Dial string to send
1323 * \retval 0 on success.
1324 * \retval non-zero on error.
1326 static int dahdi_dial_str(struct dahdi_pvt
*pvt
, int operation
, const char *dial_str
)
1331 struct dahdi_dialoperation zo
= {
1335 /* Convert the W's to ww. */
1337 for (offset
= 0; offset
< sizeof(zo
.dialstr
) - 1; ++offset
) {
1342 /* Convert 'W' to "ww" */
1344 if (offset
>= sizeof(zo
.dialstr
) - 3) {
1345 /* No room to expand */
1348 zo
.dialstr
[offset
] = 'w';
1350 zo
.dialstr
[offset
] = 'w';
1353 zo
.dialstr
[offset
] = *pos
++;
1355 /* The zo initialization has already terminated the dialstr. */
1357 ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
1358 pvt
->channel
, dial_str
, zo
.dialstr
);
1359 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_DIAL
, &zo
);
1361 ast_log(LOG_WARNING
, "Channel %d: Couldn't dial '%s': %s\n",
1362 pvt
->channel
, dial_str
, strerror(errno
));
1368 static enum analog_event
dahdievent_to_analogevent(int event
);
1369 static int bump_gains(struct dahdi_pvt
*p
);
1370 static int dahdi_setlinear(int dfd
, int linear
);
1372 static int my_start_cid_detect(void *pvt
, int cid_signalling
)
1374 struct dahdi_pvt
*p
= pvt
;
1375 int index
= SUB_REAL
;
1376 p
->cs
= callerid_new(cid_signalling
);
1378 ast_log(LOG_ERROR
, "Unable to alloc callerid\n");
1382 dahdi_setlinear(p
->subs
[index
].dfd
, 0);
1387 static int restore_gains(struct dahdi_pvt
*p
);
1389 static int my_stop_cid_detect(void *pvt
)
1391 struct dahdi_pvt
*p
= pvt
;
1392 int index
= SUB_REAL
;
1395 callerid_free(p
->cs
);
1398 /* Restore linear mode after Caller*ID processing */
1399 dahdi_setlinear(p
->subs
[index
].dfd
, p
->subs
[index
].linear
);
1405 static int my_get_callerid(void *pvt
, char *namebuf
, char *numbuf
, enum analog_event
*ev
, size_t timeout
)
1407 struct dahdi_pvt
*p
= pvt
;
1408 struct analog_pvt
*analog_p
= p
->sig_pvt
;
1409 struct pollfd poller
;
1411 int index
= SUB_REAL
;
1413 unsigned char buf
[256];
1416 poller
.fd
= p
->subs
[SUB_REAL
].dfd
;
1417 poller
.events
= POLLPRI
| POLLIN
;
1420 res
= poll(&poller
, 1, timeout
);
1422 if (poller
.revents
& POLLPRI
) {
1423 *ev
= dahdievent_to_analogevent(dahdi_get_event(p
->subs
[SUB_REAL
].dfd
));
1427 if (poller
.revents
& POLLIN
) {
1429 /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
1430 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
1431 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
1432 * a failure and die, and returning 2 means no event was received. */
1433 res
= read(p
->subs
[index
].dfd
, buf
, sizeof(buf
));
1435 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
1439 if (analog_p
->ringt
> 0) {
1440 if (!(--analog_p
->ringt
)) {
1441 /* only return if we timeout from a ring event */
1446 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
1447 res
= callerid_feed_jp(p
->cs
, buf
, res
, AST_LAW(p
));
1449 res
= callerid_feed(p
->cs
, buf
, res
, AST_LAW(p
));
1453 * The previous diagnostic message output likely
1454 * explains why it failed.
1456 ast_log(LOG_WARNING
, "Failed to decode CallerID\n");
1461 callerid_get(p
->cs
, &name
, &num
, &flags
);
1463 ast_copy_string(namebuf
, name
, ANALOG_MAX_CID
);
1465 ast_copy_string(numbuf
, num
, ANALOG_MAX_CID
);
1467 if (flags
& (CID_PRIVATE_NUMBER
| CID_UNKNOWN_NUMBER
)) {
1468 /* If we got a presentation, we must set it on the channel */
1469 struct ast_channel
*chan
= analog_p
->ss_astchan
;
1470 struct ast_party_caller caller
;
1472 ast_party_caller_set_init(&caller
, ast_channel_caller(chan
));
1473 caller
.id
.name
.presentation
= caller
.id
.number
.presentation
= (flags
& CID_PRIVATE_NUMBER
) ?
1474 AST_PRES_RESTRICTED
| AST_PRES_USER_NUMBER_UNSCREENED
: AST_PRES_UNAVAILABLE
| AST_PRES_USER_NUMBER_UNSCREENED
;
1475 ast_party_caller_set(ast_channel_caller(chan
), &caller
, NULL
);
1476 ast_party_caller_free(&caller
);
1479 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", num
, name
, flags
);
1484 *ev
= ANALOG_EVENT_NONE
;
1488 static const char *event2str(int event
);
1490 static int my_distinctive_ring(struct ast_channel
*chan
, void *pvt
, int idx
, int *ringdata
)
1492 unsigned char buf
[256];
1494 int curRingData
[RING_PATTERNS
];
1500 int checkaftercid
= 0;
1501 const char *matched_context
;
1502 struct dahdi_pvt
*p
= pvt
;
1503 struct analog_pvt
*analog_p
= p
->sig_pvt
;
1505 if (ringdata
== NULL
) {
1506 ringdata
= curRingData
;
1511 /* We must have a ring by now so lets try to listen for distinctive ringing */
1512 if ((checkaftercid
&& distinctiveringaftercid
) || !checkaftercid
) {
1513 /* Clear the current ring data array so we don't have old data in it. */
1514 for (receivedRingT
= 0; receivedRingT
< RING_PATTERNS
; receivedRingT
++)
1515 ringdata
[receivedRingT
] = 0;
1518 if (checkaftercid
&& distinctiveringaftercid
) {
1519 ast_verb(3, "Detecting post-CID distinctive ring\n");
1523 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
1524 res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
);
1526 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
1530 if (i
& DAHDI_IOMUX_SIGEVENT
) {
1531 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
1532 ast_debug(3, "Got event %d (%s)...\n", res
, event2str(res
));
1533 if (res
== DAHDI_EVENT_NOALARM
) {
1535 analog_p
->inalarm
= 0;
1536 } else if (res
== DAHDI_EVENT_RINGOFFHOOK
) {
1537 /* Let us detect distinctive ring */
1538 ringdata
[receivedRingT
] = analog_p
->ringt
;
1540 if (analog_p
->ringt
< analog_p
->ringt_base
/ 2) {
1543 /* Increment the ringT counter so we can match it against
1544 values in chan_dahdi.conf for distinctive ring */
1545 if (++receivedRingT
== RING_PATTERNS
) {
1549 } else if (i
& DAHDI_IOMUX_READ
) {
1550 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
1552 if (errno
!= ELAST
) {
1553 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
1559 if (analog_p
->ringt
> 0) {
1560 if (!(--analog_p
->ringt
)) {
1568 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
1569 ast_verb(3, "Detected ring pattern: %d,%d,%d\n", ringdata
[0], ringdata
[1], ringdata
[2]);
1570 matched_context
= p
->defcontext
;
1571 for (counter
= 0; counter
< 3; counter
++) {
1572 int range
= p
->drings
.ringnum
[counter
].range
;
1575 ast_verb(3, "Checking %d,%d,%d with +/- %d range\n",
1576 p
->drings
.ringnum
[counter
].ring
[0],
1577 p
->drings
.ringnum
[counter
].ring
[1],
1578 p
->drings
.ringnum
[counter
].ring
[2],
1580 for (counter1
= 0; counter1
< 3; counter1
++) {
1581 int ring
= p
->drings
.ringnum
[counter
].ring
[counter1
];
1584 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
1585 ringdata
[counter1
]);
1587 } else if (ring
- range
<= ringdata
[counter1
] && ringdata
[counter1
] <= ring
+ range
) {
1588 ast_verb(3, "Ring pattern %d is in range: %d to %d\n",
1589 ringdata
[counter1
], ring
- range
, ring
+ range
);
1592 /* The current dring pattern cannot match. */
1597 if (distMatches
== 3) {
1598 /* The ring matches, set the context to whatever is for distinctive ring.. */
1599 matched_context
= S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
);
1600 ast_verb(3, "Matched Distinctive Ring context %s\n", matched_context
);
1605 /* Set selected distinctive ring context if not already set. */
1606 if (strcmp(p
->context
, matched_context
) != 0) {
1607 ast_copy_string(p
->context
, matched_context
, sizeof(p
->context
));
1608 ast_channel_context_set(chan
, matched_context
);
1614 static int my_stop_callwait(void *pvt
)
1616 struct dahdi_pvt
*p
= pvt
;
1617 p
->callwaitingrepeat
= 0;
1619 p
->cid_suppress_expire
= 0;
1624 static int send_callerid(struct dahdi_pvt
*p
);
1625 static int save_conference(struct dahdi_pvt
*p
);
1626 static int restore_conference(struct dahdi_pvt
*p
);
1628 static int my_callwait(void *pvt
)
1630 struct dahdi_pvt
*p
= pvt
;
1632 p
->callwaitingrepeat
= CALLWAITING_REPEAT_SAMPLES
;
1634 ast_log(LOG_WARNING
, "Spill already exists?!?\n");
1635 ast_free(p
->cidspill
);
1639 * SAS: Subscriber Alert Signal, 440Hz for 300ms
1640 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
1642 if (!(p
->cidspill
= ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE
* 4)))
1646 memset(p
->cidspill
, 0x7f, 2400 + 600 + READ_SIZE
* 4);
1647 if (!p
->callwaitrings
&& p
->callwaitingcallerid
) {
1648 ast_gen_cas(p
->cidspill
, 1, 2400 + 680, AST_LAW(p
));
1650 p
->cidlen
= 2400 + 680 + READ_SIZE
* 4;
1652 ast_gen_cas(p
->cidspill
, 1, 2400, AST_LAW(p
));
1654 p
->cidlen
= 2400 + READ_SIZE
* 4;
1662 static int my_send_callerid(void *pvt
, int cwcid
, struct ast_party_caller
*caller
)
1664 struct dahdi_pvt
*p
= pvt
;
1665 struct analog_pvt
*analog_p
= p
->sig_pvt
;
1667 ast_debug(2, "Starting cid spill\n");
1670 ast_log(LOG_WARNING
, "cidspill already exists??\n");
1671 ast_free(p
->cidspill
);
1674 if ((p
->cidspill
= ast_malloc(MAX_CALLERID_SIZE
))) {
1675 int pres
= ast_party_id_presentation(&caller
->id
);
1677 /* Some CPE support additional parameters for on-hook Caller*ID,
1678 * such as redirecting reason and call qualifier, so send those
1680 * I don't know of any CPE that supports this for Call Waiting (unfortunately),
1681 * so don't send those for call waiting as that will just lengthen the CID spill
1682 * for no good reason.
1684 p
->cidlen
= ast_callerid_full_generate(p
->cidspill
,
1685 caller
->id
.name
.str
,
1686 caller
->id
.number
.str
,
1688 analog_p
->redirecting_reason
,
1690 analog_p
->call_qualifier
,
1694 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
1695 caller
->id
.name
.str
, caller
->id
.number
.str
);
1698 p
->cidlen
= ast_callerid_callwaiting_full_generate(p
->cidspill
,
1699 caller
->id
.name
.str
,
1700 caller
->id
.number
.str
,
1706 p
->cidlen
+= READ_SIZE
* 4;
1709 p
->cid_suppress_expire
= 0;
1715 static int my_dsp_reset_and_flush_digits(void *pvt
)
1717 struct dahdi_pvt
*p
= pvt
;
1719 ast_dsp_digitreset(p
->dsp
);
1724 static int my_dsp_set_digitmode(void *pvt
, enum analog_dsp_digitmode mode
)
1726 struct dahdi_pvt
*p
= pvt
;
1728 if (p
->channel
== CHAN_PSEUDO
)
1729 ast_log(LOG_ERROR
, "You have assumed incorrectly sir!\n");
1731 if (mode
== ANALOG_DIGITMODE_DTMF
) {
1732 /* If we do hardware dtmf, no need for a DSP */
1733 if (p
->hardwaredtmf
) {
1735 ast_dsp_free(p
->dsp
);
1742 p
->dsp
= ast_dsp_new();
1744 ast_log(LOG_ERROR
, "Unable to allocate DSP\n");
1749 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
1750 } else if (mode
== ANALOG_DIGITMODE_MF
) {
1752 p
->dsp
= ast_dsp_new();
1754 ast_log(LOG_ERROR
, "Unable to allocate DSP\n");
1758 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MF
| p
->dtmfrelax
);
1763 static int dahdi_wink(struct dahdi_pvt
*p
, int index
);
1765 static int my_wink(void *pvt
, enum analog_sub sub
)
1767 struct dahdi_pvt
*p
= pvt
;
1768 int index
= analogsub_to_dahdisub(sub
);
1769 if (index
!= SUB_REAL
) {
1770 ast_log(LOG_ERROR
, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
1772 return dahdi_wink(p
, index
);
1775 static void wakeup_sub(struct dahdi_pvt
*p
, int a
);
1777 static int reset_conf(struct dahdi_pvt
*p
);
1779 static inline int dahdi_confmute(struct dahdi_pvt
*p
, int muted
);
1781 static void my_handle_dtmf(void *pvt
, struct ast_channel
*ast
, enum analog_sub analog_index
, struct ast_frame
**dest
)
1783 struct ast_frame
*f
= *dest
;
1784 struct dahdi_pvt
*p
= pvt
;
1785 int idx
= analogsub_to_dahdisub(analog_index
);
1787 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
1788 f
->frametype
== AST_FRAME_DTMF_BEGIN
? "Begin" : "End",
1789 (unsigned)f
->subclass
.integer
, f
->subclass
.integer
, ast_channel_name(ast
));
1791 if (f
->subclass
.integer
== 'f') {
1792 if (f
->frametype
== AST_FRAME_DTMF_END
) {
1793 /* Fax tone -- Handle and return NULL */
1794 if ((p
->callprogress
& CALLPROGRESS_FAX
) && !p
->faxhandled
) {
1795 /* If faxbuffers are configured, use them for the fax transmission */
1796 if (p
->usefaxbuffers
&& !p
->bufferoverrideinuse
) {
1797 struct dahdi_bufferinfo bi
= {
1798 .txbufpolicy
= p
->faxbuf_policy
,
1799 .bufsize
= p
->bufsize
,
1800 .numbufs
= p
->faxbuf_no
1804 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
1805 ast_log(LOG_WARNING
, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast
), strerror(errno
));
1807 p
->bufferoverrideinuse
= 1;
1812 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
1813 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
1814 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast
));
1816 if (strcmp(ast_channel_exten(ast
), "fax")) {
1817 const char *target_context
= ast_channel_context(ast
);
1820 * We need to unlock 'ast' here because ast_exists_extension has the
1821 * potential to start autoservice on the channel. Such action is prone
1822 * to deadlock if the channel is locked.
1824 * ast_async_goto() has its own restriction on not holding the
1827 ast_mutex_unlock(&p
->lock
);
1828 ast_channel_unlock(ast
);
1829 if (ast_exists_extension(ast
, target_context
, "fax", 1,
1830 S_COR(ast_channel_caller(ast
)->id
.number
.valid
, ast_channel_caller(ast
)->id
.number
.str
, NULL
))) {
1831 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast
));
1832 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
1833 pbx_builtin_setvar_helper(ast
, "FAXEXTEN", ast_channel_exten(ast
));
1834 if (ast_async_goto(ast
, target_context
, "fax", 1))
1835 ast_log(LOG_WARNING
, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast
), target_context
);
1837 ast_log(LOG_NOTICE
, "Fax detected, but no fax extension\n");
1839 ast_channel_lock(ast
);
1840 ast_mutex_lock(&p
->lock
);
1842 ast_debug(1, "Already in a fax extension, not redirecting\n");
1845 ast_debug(1, "Fax already handled\n");
1847 dahdi_confmute(p
, 0);
1849 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
1850 p
->subs
[idx
].f
.subclass
.integer
= 0;
1851 *dest
= &p
->subs
[idx
].f
;
1855 static void my_lock_private(void *pvt
)
1857 struct dahdi_pvt
*p
= pvt
;
1858 ast_mutex_lock(&p
->lock
);
1861 static void my_unlock_private(void *pvt
)
1863 struct dahdi_pvt
*p
= pvt
;
1864 ast_mutex_unlock(&p
->lock
);
1867 static void my_deadlock_avoidance_private(void *pvt
)
1869 struct dahdi_pvt
*p
= pvt
;
1871 DEADLOCK_AVOIDANCE(&p
->lock
);
1874 static struct ast_manager_event_blob
*dahdichannel_to_ami(struct stasis_message
*msg
)
1876 RAII_VAR(struct ast_str
*, channel_string
, NULL
, ast_free
);
1877 struct ast_channel_blob
*obj
= stasis_message_data(msg
);
1878 struct ast_json
*group
, *span
, *channel
;
1880 channel_string
= ast_manager_build_channel_state_string(obj
->snapshot
);
1881 if (!channel_string
) {
1885 group
= ast_json_object_get(obj
->blob
, "group");
1886 span
= ast_json_object_get(obj
->blob
, "span");
1887 channel
= ast_json_object_get(obj
->blob
, "channel");
1889 return ast_manager_event_blob_create(EVENT_FLAG_CALL
, "DAHDIChannel",
1891 "DAHDIGroup: %llu\r\n"
1893 "DAHDIChannel: %s\r\n",
1894 ast_str_buffer(channel_string
),
1895 (ast_group_t
)ast_json_integer_get(group
),
1896 (unsigned int)ast_json_integer_get(span
),
1897 ast_json_string_get(channel
));
1900 STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type
,
1901 .to_ami
= dahdichannel_to_ami
,
1904 /*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
1905 static void publish_dahdichannel(struct ast_channel
*chan
, ast_group_t group
, int span
, const char *dahdi_channel
)
1907 RAII_VAR(struct ast_json
*, blob
, NULL
, ast_json_unref
);
1909 ast_assert(dahdi_channel
!= NULL
);
1911 blob
= ast_json_pack("{s: I, s: i, s: s}",
1912 "group", (ast_json_int_t
)group
,
1914 "channel", dahdi_channel
);
1919 ast_channel_lock(chan
);
1920 ast_channel_publish_blob(chan
, dahdichannel_type(), blob
);
1921 ast_channel_unlock(chan
);
1926 * \brief Post an AMI DAHDI channel association event.
1929 * \param p DAHDI private pointer
1930 * \param chan Channel associated with the private pointer
1932 static void dahdi_ami_channel_event(struct dahdi_pvt
*p
, struct ast_channel
*chan
)
1936 if (p
->channel
< CHAN_PSEUDO
) {
1938 snprintf(ch_name
, sizeof(ch_name
), "no-media (%d)", p
->channel
);
1939 } else if (p
->channel
== CHAN_PSEUDO
) {
1940 /* Pseudo channel */
1941 strcpy(ch_name
, "pseudo");
1944 snprintf(ch_name
, sizeof(ch_name
), "%d", p
->channel
);
1946 publish_dahdichannel(chan
, p
->group
, p
->span
, ch_name
);
1952 * \brief Post an AMI DAHDI channel association event.
1955 * \param pvt DAHDI private pointer
1956 * \param chan Channel associated with the private pointer
1958 static void my_ami_channel_event(void *pvt
, struct ast_channel
*chan
)
1960 struct dahdi_pvt
*p
= pvt
;
1962 dahdi_ami_channel_event(p
, chan
);
1966 /* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
1967 * returns the last value of the linear setting
1969 static int my_set_linear_mode(void *pvt
, enum analog_sub sub
, int linear_mode
)
1971 struct dahdi_pvt
*p
= pvt
;
1973 int idx
= analogsub_to_dahdisub(sub
);
1975 dahdi_setlinear(p
->subs
[idx
].dfd
, linear_mode
);
1976 oldval
= p
->subs
[idx
].linear
;
1977 p
->subs
[idx
].linear
= linear_mode
? 1 : 0;
1981 static void my_set_inthreeway(void *pvt
, enum analog_sub sub
, int inthreeway
)
1983 struct dahdi_pvt
*p
= pvt
;
1984 int idx
= analogsub_to_dahdisub(sub
);
1986 p
->subs
[idx
].inthreeway
= inthreeway
;
1989 static int get_alarms(struct dahdi_pvt
*p
);
1990 static void handle_alarms(struct dahdi_pvt
*p
, int alms
);
1991 static void my_get_and_handle_alarms(void *pvt
)
1994 struct dahdi_pvt
*p
= pvt
;
1996 res
= get_alarms(p
);
1997 handle_alarms(p
, res
);
2000 static void *my_get_sigpvt_bridged_channel(struct ast_channel
*chan
)
2002 RAII_VAR(struct ast_channel
*, bridged
, ast_channel_bridge_peer(chan
), ast_channel_cleanup
);
2004 if (bridged
&& ast_channel_tech(bridged
) == &dahdi_tech
) {
2005 struct dahdi_pvt
*p
= ast_channel_tech_pvt(bridged
);
2007 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
2014 static int my_get_sub_fd(void *pvt
, enum analog_sub sub
)
2016 struct dahdi_pvt
*p
= pvt
;
2017 int dahdi_sub
= analogsub_to_dahdisub(sub
);
2018 return p
->subs
[dahdi_sub
].dfd
;
2021 static void my_set_cadence(void *pvt
, int *cid_rings
, struct ast_channel
*ast
)
2023 struct dahdi_pvt
*p
= pvt
;
2025 /* Choose proper cadence */
2026 if ((p
->distinctivering
> 0) && (p
->distinctivering
<= num_cadence
)) {
2027 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETCADENCE
, &cadences
[p
->distinctivering
- 1]))
2028 ast_log(LOG_WARNING
, "Unable to set distinctive ring cadence %d on '%s': %s\n", p
->distinctivering
, ast_channel_name(ast
), strerror(errno
));
2029 *cid_rings
= cidrings
[p
->distinctivering
- 1];
2031 if (p
->distinctivering
> 0) {
2032 ast_log(LOG_WARNING
, "Cadence %d is not defined, falling back to default ring cadence\n", p
->distinctivering
);
2034 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETCADENCE
, NULL
))
2035 ast_log(LOG_WARNING
, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast
), strerror(errno
));
2036 *cid_rings
= p
->sendcalleridafter
;
2040 static void my_set_alarm(void *pvt
, int in_alarm
)
2042 struct dahdi_pvt
*p
= pvt
;
2044 p
->inalarm
= in_alarm
;
2047 static void my_set_dialing(void *pvt
, int is_dialing
)
2049 struct dahdi_pvt
*p
= pvt
;
2051 p
->dialing
= is_dialing
;
2054 static void my_set_outgoing(void *pvt
, int is_outgoing
)
2056 struct dahdi_pvt
*p
= pvt
;
2058 p
->outgoing
= is_outgoing
;
2061 #if defined(HAVE_PRI) || defined(HAVE_SS7)
2062 static void my_set_digital(void *pvt
, int is_digital
)
2064 struct dahdi_pvt
*p
= pvt
;
2066 p
->digital
= is_digital
;
2068 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2070 #if defined(HAVE_SS7)
2071 static void my_set_inservice(void *pvt
, int is_inservice
)
2073 struct dahdi_pvt
*p
= pvt
;
2075 p
->inservice
= is_inservice
;
2077 #endif /* defined(HAVE_SS7) */
2079 #if defined(HAVE_SS7)
2080 static void my_set_locallyblocked(void *pvt
, int is_blocked
)
2082 struct dahdi_pvt
*p
= pvt
;
2084 p
->locallyblocked
= is_blocked
;
2086 #endif /* defined(HAVE_SS7) */
2088 #if defined(HAVE_SS7)
2089 static void my_set_remotelyblocked(void *pvt
, int is_blocked
)
2091 struct dahdi_pvt
*p
= pvt
;
2093 p
->remotelyblocked
= is_blocked
;
2095 #endif /* defined(HAVE_SS7) */
2097 static void my_set_ringtimeout(void *pvt
, int ringt
)
2099 struct dahdi_pvt
*p
= pvt
;
2103 static void my_set_waitingfordt(void *pvt
, struct ast_channel
*ast
)
2105 struct dahdi_pvt
*p
= pvt
;
2107 if (p
->waitfordialtone
&& CANPROGRESSDETECT(p
) && p
->dsp
) {
2108 ast_debug(1, "Defer dialing for %dms or dialtone\n", p
->waitfordialtone
);
2109 gettimeofday(&p
->waitingfordt
, NULL
);
2110 ast_setstate(ast
, AST_STATE_OFFHOOK
);
2114 static int my_check_waitingfordt(void *pvt
)
2116 struct dahdi_pvt
*p
= pvt
;
2118 if (p
->waitingfordt
.tv_sec
) {
2125 static void my_set_confirmanswer(void *pvt
, int flag
)
2127 struct dahdi_pvt
*p
= pvt
;
2128 p
->confirmanswer
= flag
;
2131 static int my_check_confirmanswer(void *pvt
)
2133 struct dahdi_pvt
*p
= pvt
;
2134 if (p
->confirmanswer
) {
2141 static void my_set_callwaiting(void *pvt
, int callwaiting_enable
)
2143 struct dahdi_pvt
*p
= pvt
;
2145 p
->callwaiting
= callwaiting_enable
;
2148 static void my_cancel_cidspill(void *pvt
)
2150 struct dahdi_pvt
*p
= pvt
;
2152 ast_free(p
->cidspill
);
2154 restore_conference(p
);
2157 static int my_confmute(void *pvt
, int mute
)
2159 struct dahdi_pvt
*p
= pvt
;
2160 return dahdi_confmute(p
, mute
);
2163 static void my_set_pulsedial(void *pvt
, int flag
)
2165 struct dahdi_pvt
*p
= pvt
;
2166 p
->pulsedial
= flag
;
2169 static void my_set_new_owner(void *pvt
, struct ast_channel
*new_owner
)
2171 struct dahdi_pvt
*p
= pvt
;
2173 p
->owner
= new_owner
;
2176 static const char *my_get_orig_dialstring(void *pvt
)
2178 struct dahdi_pvt
*p
= pvt
;
2180 return p
->dialstring
;
2183 static void my_increase_ss_count(void)
2185 ast_mutex_lock(&ss_thread_lock
);
2187 ast_mutex_unlock(&ss_thread_lock
);
2190 static void my_decrease_ss_count(void)
2192 ast_mutex_lock(&ss_thread_lock
);
2194 ast_cond_signal(&ss_thread_complete
);
2195 ast_mutex_unlock(&ss_thread_lock
);
2198 static void my_all_subchannels_hungup(void *pvt
)
2200 struct dahdi_pvt
*p
= pvt
;
2207 ast_dsp_free(p
->dsp
);
2211 p
->law
= p
->law_default
;
2212 law
= p
->law_default
;
2213 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
2215 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n", p
->channel
, strerror(errno
));
2217 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
2223 /* Cleanup owners here */
2224 for (i
= 0; i
< 3; i
++) {
2225 p
->subs
[i
].owner
= NULL
;
2231 if (num_restart_pending
== 0) {
2236 static int conf_del(struct dahdi_pvt
*p
, struct dahdi_subchannel
*c
, int index
);
2238 static int my_conf_del(void *pvt
, enum analog_sub sub
)
2240 struct dahdi_pvt
*p
= pvt
;
2241 int x
= analogsub_to_dahdisub(sub
);
2243 return conf_del(p
, &p
->subs
[x
], x
);
2246 static int conf_add(struct dahdi_pvt
*p
, struct dahdi_subchannel
*c
, int index
, int slavechannel
);
2248 static int my_conf_add(void *pvt
, enum analog_sub sub
)
2250 struct dahdi_pvt
*p
= pvt
;
2251 int x
= analogsub_to_dahdisub(sub
);
2253 return conf_add(p
, &p
->subs
[x
], x
, 0);
2256 static int isslavenative(struct dahdi_pvt
*p
, struct dahdi_pvt
**out
);
2258 static int my_complete_conference_update(void *pvt
, int needconference
)
2260 struct dahdi_pvt
*p
= pvt
;
2261 int needconf
= needconference
;
2264 struct dahdi_pvt
*slave
= NULL
;
2266 useslavenative
= isslavenative(p
, &slave
);
2268 /* If we have a slave, add him to our conference now. or DAX
2269 if this is slave native */
2270 for (x
= 0; x
< MAX_SLAVES
; x
++) {
2273 conf_add(p
, &p
->slaves
[x
]->subs
[SUB_REAL
], SUB_REAL
, GET_CHANNEL(p
));
2275 conf_add(p
, &p
->slaves
[x
]->subs
[SUB_REAL
], SUB_REAL
, 0);
2280 /* If we're supposed to be in there, do so now */
2281 if (p
->inconference
&& !p
->subs
[SUB_REAL
].inthreeway
) {
2283 conf_add(p
, &p
->subs
[SUB_REAL
], SUB_REAL
, GET_CHANNEL(slave
));
2285 conf_add(p
, &p
->subs
[SUB_REAL
], SUB_REAL
, 0);
2289 /* If we have a master, add ourselves to his conference */
2291 if (isslavenative(p
->master
, NULL
)) {
2292 conf_add(p
->master
, &p
->subs
[SUB_REAL
], SUB_REAL
, GET_CHANNEL(p
->master
));
2294 conf_add(p
->master
, &p
->subs
[SUB_REAL
], SUB_REAL
, 0);
2298 /* Nobody is left (or should be left) in our conference.
2306 static int check_for_conference(struct dahdi_pvt
*p
);
2308 static int my_check_for_conference(void *pvt
)
2310 struct dahdi_pvt
*p
= pvt
;
2311 return check_for_conference(p
);
2314 static void my_swap_subchannels(void *pvt
, enum analog_sub a
, struct ast_channel
*ast_a
, enum analog_sub b
, struct ast_channel
*ast_b
)
2316 struct dahdi_pvt
*p
= pvt
;
2321 da
= analogsub_to_dahdisub(a
);
2322 db
= analogsub_to_dahdisub(b
);
2324 tchan
= p
->subs
[da
].chan
;
2325 p
->subs
[da
].chan
= p
->subs
[db
].chan
;
2326 p
->subs
[db
].chan
= tchan
;
2328 tinthreeway
= p
->subs
[da
].inthreeway
;
2329 p
->subs
[da
].inthreeway
= p
->subs
[db
].inthreeway
;
2330 p
->subs
[db
].inthreeway
= tinthreeway
;
2332 p
->subs
[da
].owner
= ast_a
;
2333 p
->subs
[db
].owner
= ast_b
;
2336 ast_channel_set_fd(ast_a
, 0, p
->subs
[da
].dfd
);
2338 ast_channel_set_fd(ast_b
, 0, p
->subs
[db
].dfd
);
2348 * \brief performs duties of dahdi_new, but also removes and possibly unbinds (if callid_created is 1) before returning
2349 * \note this variant of dahdi should only be used in conjunction with ast_callid_threadstorage_auto()
2351 * \param callid_created value returned from ast_callid_threadstorage_auto()
2352 * \param i, state, startpbx, idx, law, assignedids, requestor, callid
2354 static struct ast_channel
*dahdi_new_callid_clean(struct dahdi_pvt
*i
, int state
, int startpbx
, int idx
, int law
, const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
, ast_callid callid
, int callid_created
);
2356 static struct ast_channel
*dahdi_new(struct dahdi_pvt
*i
, int state
, int startpbx
, int idx
, int law
, const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
, ast_callid callid
);
2358 static struct ast_channel
*my_new_analog_ast_channel(void *pvt
, int state
, int startpbx
, enum analog_sub sub
, const struct ast_channel
*requestor
)
2360 ast_callid callid
= 0;
2361 int callid_created
= ast_callid_threadstorage_auto(&callid
);
2362 struct dahdi_pvt
*p
= pvt
;
2363 int dsub
= analogsub_to_dahdisub(sub
);
2365 return dahdi_new_callid_clean(p
, state
, startpbx
, dsub
, 0, NULL
, requestor
, callid
, callid_created
);
2368 #if defined(HAVE_PRI) || defined(HAVE_SS7)
2369 static int dahdi_setlaw(int dfd
, int law
)
2372 res
= ioctl(dfd
, DAHDI_SETLAW
, &law
);
2377 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2379 #if defined(HAVE_PRI)
2380 static struct ast_channel
*my_new_pri_ast_channel(void *pvt
, int state
,
2381 enum sig_pri_law law
, char *exten
, const struct ast_assigned_ids
*assignedids
,
2382 const struct ast_channel
*requestor
)
2384 struct dahdi_pvt
*p
= pvt
;
2387 ast_callid callid
= 0;
2388 int callid_created
= ast_callid_threadstorage_auto(&callid
);
2391 case SIG_PRI_LIB_HANDLE_CASES
:
2392 if (((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
) {
2393 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
2398 /* Set to audio mode at this point */
2400 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &audio
) == -1) {
2401 ast_log(LOG_WARNING
, "Unable to set audio mode on channel %d to %d: %s\n",
2402 p
->channel
, audio
, strerror(errno
));
2407 if (law
!= SIG_PRI_DEFLAW
) {
2408 dahdi_setlaw(p
->subs
[SUB_REAL
].dfd
, (law
== SIG_PRI_ULAW
) ? DAHDI_LAW_MULAW
: DAHDI_LAW_ALAW
);
2411 ast_copy_string(p
->exten
, exten
, sizeof(p
->exten
));
2414 case SIG_PRI_DEFLAW
:
2418 newlaw
= DAHDI_LAW_ALAW
;
2421 newlaw
= DAHDI_LAW_MULAW
;
2425 return dahdi_new_callid_clean(p
, state
, 0, SUB_REAL
, newlaw
, assignedids
, requestor
, callid
, callid_created
);
2427 #endif /* defined(HAVE_PRI) */
2429 static int set_actual_gain(int fd
, float rxgain
, float txgain
, float rxdrc
, float txdrc
, int law
);
2431 #if defined(HAVE_PRI) || defined(HAVE_SS7)
2434 * \brief Open the PRI/SS7 channel media path.
2437 * \param p Channel private control structure.
2439 static void my_pri_ss7_open_media(void *p
)
2441 struct dahdi_pvt
*pvt
= p
;
2446 dfd
= pvt
->subs
[SUB_REAL
].dfd
;
2448 /* Open the media path. */
2450 res
= ioctl(dfd
, DAHDI_AUDIOMODE
, &set_val
);
2452 ast_log(LOG_WARNING
, "Unable to enable audio mode on channel %d (%s)\n",
2453 pvt
->channel
, strerror(errno
));
2456 /* Set correct companding law for this call. */
2457 res
= dahdi_setlaw(dfd
, pvt
->law
);
2459 ast_log(LOG_WARNING
, "Unable to set law on channel %d\n", pvt
->channel
);
2462 /* Set correct gain for this call. */
2464 res
= set_actual_gain(dfd
, 0, 0, pvt
->rxdrc
, pvt
->txdrc
, pvt
->law
);
2466 res
= set_actual_gain(dfd
, pvt
->rxgain
, pvt
->txgain
, pvt
->rxdrc
, pvt
->txdrc
,
2470 ast_log(LOG_WARNING
, "Unable to set gains on channel %d\n", pvt
->channel
);
2473 if (pvt
->dsp_features
&& pvt
->dsp
) {
2474 ast_dsp_set_features(pvt
->dsp
, pvt
->dsp_features
);
2477 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2479 #if defined(HAVE_PRI)
2482 * \brief Ask DAHDI to dial the given dial string.
2485 * \param p Channel private control structure.
2486 * \param dial_string String to pass to DAHDI to dial.
2488 * \note The channel private lock needs to be held when calling.
2490 static void my_pri_dial_digits(void *p
, const char *dial_string
)
2492 char dial_str
[DAHDI_MAX_DTMF_BUF
];
2493 struct dahdi_pvt
*pvt
= p
;
2496 snprintf(dial_str
, sizeof(dial_str
), "T%s", dial_string
);
2497 res
= dahdi_dial_str(pvt
, DAHDI_DIAL_OP_APPEND
, dial_str
);
2502 #endif /* defined(HAVE_PRI) */
2504 static int unalloc_sub(struct dahdi_pvt
*p
, int x
);
2506 static int my_unallocate_sub(void *pvt
, enum analog_sub analogsub
)
2508 struct dahdi_pvt
*p
= pvt
;
2510 return unalloc_sub(p
, analogsub_to_dahdisub(analogsub
));
2513 static int alloc_sub(struct dahdi_pvt
*p
, int x
);
2515 static int my_allocate_sub(void *pvt
, enum analog_sub analogsub
)
2517 struct dahdi_pvt
*p
= pvt
;
2519 return alloc_sub(p
, analogsub_to_dahdisub(analogsub
));
2522 static int has_voicemail(struct dahdi_pvt
*p
);
2524 static int my_has_voicemail(void *pvt
)
2526 struct dahdi_pvt
*p
= pvt
;
2528 return has_voicemail(p
);
2531 static int my_play_tone(void *pvt
, enum analog_sub sub
, enum analog_tone tone
)
2533 struct dahdi_pvt
*p
= pvt
;
2536 index
= analogsub_to_dahdisub(sub
);
2538 return tone_zone_play_tone(p
->subs
[index
].dfd
, analog_tone_to_dahditone(tone
));
2541 static enum analog_event
dahdievent_to_analogevent(int event
)
2543 enum analog_event res
;
2546 case DAHDI_EVENT_ONHOOK
:
2547 res
= ANALOG_EVENT_ONHOOK
;
2549 case DAHDI_EVENT_RINGOFFHOOK
:
2550 res
= ANALOG_EVENT_RINGOFFHOOK
;
2552 case DAHDI_EVENT_WINKFLASH
:
2553 res
= ANALOG_EVENT_WINKFLASH
;
2555 case DAHDI_EVENT_ALARM
:
2556 res
= ANALOG_EVENT_ALARM
;
2558 case DAHDI_EVENT_NOALARM
:
2559 res
= ANALOG_EVENT_NOALARM
;
2561 case DAHDI_EVENT_DIALCOMPLETE
:
2562 res
= ANALOG_EVENT_DIALCOMPLETE
;
2564 case DAHDI_EVENT_RINGERON
:
2565 res
= ANALOG_EVENT_RINGERON
;
2567 case DAHDI_EVENT_RINGEROFF
:
2568 res
= ANALOG_EVENT_RINGEROFF
;
2570 case DAHDI_EVENT_HOOKCOMPLETE
:
2571 res
= ANALOG_EVENT_HOOKCOMPLETE
;
2573 case DAHDI_EVENT_PULSE_START
:
2574 res
= ANALOG_EVENT_PULSE_START
;
2576 case DAHDI_EVENT_POLARITY
:
2577 res
= ANALOG_EVENT_POLARITY
;
2579 case DAHDI_EVENT_RINGBEGIN
:
2580 res
= ANALOG_EVENT_RINGBEGIN
;
2582 case DAHDI_EVENT_EC_DISABLED
:
2583 res
= ANALOG_EVENT_EC_DISABLED
;
2585 case DAHDI_EVENT_REMOVED
:
2586 res
= ANALOG_EVENT_REMOVED
;
2588 case DAHDI_EVENT_NEONMWI_ACTIVE
:
2589 res
= ANALOG_EVENT_NEONMWI_ACTIVE
;
2591 case DAHDI_EVENT_NEONMWI_INACTIVE
:
2592 res
= ANALOG_EVENT_NEONMWI_INACTIVE
;
2594 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
2595 case DAHDI_EVENT_TX_CED_DETECTED
:
2596 res
= ANALOG_EVENT_TX_CED_DETECTED
;
2598 case DAHDI_EVENT_RX_CED_DETECTED
:
2599 res
= ANALOG_EVENT_RX_CED_DETECTED
;
2601 case DAHDI_EVENT_EC_NLP_DISABLED
:
2602 res
= ANALOG_EVENT_EC_NLP_DISABLED
;
2604 case DAHDI_EVENT_EC_NLP_ENABLED
:
2605 res
= ANALOG_EVENT_EC_NLP_ENABLED
;
2608 case DAHDI_EVENT_PULSEDIGIT
:
2609 res
= ANALOG_EVENT_PULSEDIGIT
;
2611 case DAHDI_EVENT_DTMFDOWN
:
2612 res
= ANALOG_EVENT_DTMFDOWN
;
2614 case DAHDI_EVENT_DTMFUP
:
2615 res
= ANALOG_EVENT_DTMFUP
;
2618 switch(event
& 0xFFFF0000) {
2619 case DAHDI_EVENT_PULSEDIGIT
:
2620 case DAHDI_EVENT_DTMFDOWN
:
2621 case DAHDI_EVENT_DTMFUP
:
2622 /* The event includes a digit number in the low word.
2623 * Converting it to a 'enum analog_event' would remove
2624 * that information. Thus it is returned as-is.
2629 res
= ANALOG_EVENT_ERROR
;
2636 static inline int dahdi_wait_event(int fd
);
2638 static int my_wait_event(void *pvt
)
2640 struct dahdi_pvt
*p
= pvt
;
2642 return dahdi_wait_event(p
->subs
[SUB_REAL
].dfd
);
2645 static int my_get_event(void *pvt
)
2647 struct dahdi_pvt
*p
= pvt
;
2650 if (p
->fake_event
) {
2651 res
= p
->fake_event
;
2654 res
= dahdi_get_event(p
->subs
[SUB_REAL
].dfd
);
2656 return dahdievent_to_analogevent(res
);
2659 static int my_is_off_hook(void *pvt
)
2661 struct dahdi_pvt
*p
= pvt
;
2663 struct dahdi_params par
;
2665 memset(&par
, 0, sizeof(par
));
2667 if (p
->subs
[SUB_REAL
].dfd
> -1)
2668 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &par
);
2670 /* Assume not off hook on CVRS */
2672 par
.rxisoffhook
= 0;
2675 ast_log(LOG_WARNING
, "Unable to check hook state on channel %d: %s\n", p
->channel
, strerror(errno
));
2678 if ((p
->sig
== SIG_FXSKS
) || (p
->sig
== SIG_FXSGS
)) {
2679 /* When "onhook" that means no battery on the line, and thus
2680 it is out of service..., if it's on a TDM card... If it's a channel
2681 bank, there is no telling... */
2682 return (par
.rxbits
> -1) || par
.rxisoffhook
;
2685 return par
.rxisoffhook
;
2688 static int my_set_echocanceller(void *pvt
, int enable
)
2690 struct dahdi_pvt
*p
= pvt
;
2695 dahdi_ec_disable(p
);
2700 static int dahdi_ring_phone(struct dahdi_pvt
*p
);
2702 static int my_ring(void *pvt
)
2704 struct dahdi_pvt
*p
= pvt
;
2706 return dahdi_ring_phone(p
);
2709 static int my_flash(void *pvt
)
2711 struct dahdi_pvt
*p
= pvt
;
2712 int func
= DAHDI_FLASH
;
2713 return ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &func
);
2716 static inline int dahdi_set_hook(int fd
, int hs
);
2718 static int my_off_hook(void *pvt
)
2720 struct dahdi_pvt
*p
= pvt
;
2721 return dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
2724 static void my_set_needringing(void *pvt
, int value
)
2726 struct dahdi_pvt
*p
= pvt
;
2727 p
->subs
[SUB_REAL
].needringing
= value
;
2730 static void my_set_polarity(void *pvt
, int value
)
2732 struct dahdi_pvt
*p
= pvt
;
2734 if (p
->channel
== CHAN_PSEUDO
) {
2737 p
->polarity
= value
;
2738 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETPOLARITY
, &value
);
2741 static void my_start_polarityswitch(void *pvt
)
2743 struct dahdi_pvt
*p
= pvt
;
2745 if (p
->answeronpolarityswitch
|| p
->hanguponpolarityswitch
) {
2746 my_set_polarity(pvt
, 0);
2750 static void my_answer_polarityswitch(void *pvt
)
2752 struct dahdi_pvt
*p
= pvt
;
2754 if (!p
->answeronpolarityswitch
) {
2758 my_set_polarity(pvt
, 1);
2761 static void my_hangup_polarityswitch(void *pvt
)
2763 struct dahdi_pvt
*p
= pvt
;
2765 if (!p
->hanguponpolarityswitch
) {
2769 if (p
->answeronpolarityswitch
) {
2770 my_set_polarity(pvt
, 0);
2772 my_set_polarity(pvt
, 1);
2776 /*! \brief Return DAHDI pivot if channel is FXO signalled */
2777 static struct dahdi_pvt
*fxo_pvt(struct ast_channel
*chan
)
2780 struct dahdi_params dahdip
;
2781 struct dahdi_pvt
*pvt
= NULL
;
2783 if (strcasecmp(ast_channel_tech(chan
)->type
, "DAHDI")) {
2784 ast_log(LOG_WARNING
, "%s is not a DAHDI channel\n", ast_channel_name(chan
));
2788 memset(&dahdip
, 0, sizeof(dahdip
));
2789 res
= ioctl(ast_channel_fd(chan
, 0), DAHDI_GET_PARAMS
, &dahdip
);
2792 ast_log(LOG_WARNING
, "Unable to get parameters of %s: %s\n", ast_channel_name(chan
), strerror(errno
));
2795 if (!(dahdip
.sigtype
& __DAHDI_SIG_FXO
)) {
2796 ast_log(LOG_WARNING
, "%s is not FXO signalled\n", ast_channel_name(chan
));
2800 pvt
= ast_channel_tech_pvt(chan
);
2801 if (!dahdi_analog_lib_handles(pvt
->sig
, 0, 0)) {
2802 ast_log(LOG_WARNING
, "Channel signalling is not analog");
2809 static int polarity_read(struct ast_channel
*chan
, const char *cmd
, char *data
, char *buffer
, size_t buflen
)
2811 struct dahdi_pvt
*pvt
;
2813 pvt
= fxo_pvt(chan
);
2818 snprintf(buffer
, buflen
, "%d", pvt
->polarity
);
2823 static int polarity_write(struct ast_channel
*chan
, const char *cmd
, char *data
, const char *value
)
2825 struct dahdi_pvt
*pvt
;
2828 pvt
= fxo_pvt(chan
);
2833 if (!strcasecmp(value
, "idle")) {
2834 polarity
= POLARITY_IDLE
;
2835 } else if (!strcasecmp(value
, "reverse")) {
2836 polarity
= POLARITY_REV
;
2838 polarity
= atoi(value
);
2841 if (polarity
!= POLARITY_IDLE
&& polarity
!= POLARITY_REV
) {
2842 ast_log(LOG_WARNING
, "Invalid polarity: '%s'\n", value
);
2846 my_set_polarity(pvt
, polarity
);
2850 static struct ast_custom_function polarity_function
= {
2852 .write
= polarity_write
,
2853 .read
= polarity_read
,
2856 static int my_start(void *pvt
)
2858 struct dahdi_pvt
*p
= pvt
;
2859 int x
= DAHDI_START
;
2861 return ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
2864 static int my_dial_digits(void *pvt
, enum analog_sub sub
, struct analog_dialoperation
*dop
)
2866 struct dahdi_pvt
*p
= pvt
;
2868 if (dop
->op
!= ANALOG_DIAL_OP_REPLACE
) {
2869 ast_log(LOG_ERROR
, "Fix the dial_digits callback!\n");
2873 if (sub
!= ANALOG_SUB_REAL
) {
2874 ast_log(LOG_ERROR
, "Trying to dial_digits '%s' on channel %d subchannel %u\n",
2875 dop
->dialstr
, p
->channel
, sub
);
2879 return dahdi_dial_str(p
, DAHDI_DIAL_OP_REPLACE
, dop
->dialstr
);
2882 static void dahdi_train_ec(struct dahdi_pvt
*p
);
2884 static int my_train_echocanceller(void *pvt
)
2886 struct dahdi_pvt
*p
= pvt
;
2893 static int my_is_dialing(void *pvt
, enum analog_sub sub
)
2895 struct dahdi_pvt
*p
= pvt
;
2899 index
= analogsub_to_dahdisub(sub
);
2901 if (ioctl(p
->subs
[index
].dfd
, DAHDI_DIALING
, &x
)) {
2902 ast_debug(1, "DAHDI_DIALING ioctl failed!\n");
2909 static int my_on_hook(void *pvt
)
2911 struct dahdi_pvt
*p
= pvt
;
2912 return dahdi_set_hook(p
->subs
[ANALOG_SUB_REAL
].dfd
, DAHDI_ONHOOK
);
2915 #if defined(HAVE_PRI)
2916 static void my_pri_fixup_chans(void *chan_old
, void *chan_new
)
2918 struct dahdi_pvt
*old_chan
= chan_old
;
2919 struct dahdi_pvt
*new_chan
= chan_new
;
2921 new_chan
->owner
= old_chan
->owner
;
2922 old_chan
->owner
= NULL
;
2923 if (new_chan
->owner
) {
2924 ast_channel_tech_pvt_set(new_chan
->owner
, new_chan
);
2925 ast_channel_internal_fd_set(new_chan
->owner
, 0, new_chan
->subs
[SUB_REAL
].dfd
);
2926 new_chan
->subs
[SUB_REAL
].owner
= old_chan
->subs
[SUB_REAL
].owner
;
2927 old_chan
->subs
[SUB_REAL
].owner
= NULL
;
2929 /* Copy any DSP that may be present */
2930 new_chan
->dsp
= old_chan
->dsp
;
2931 new_chan
->dsp_features
= old_chan
->dsp_features
;
2932 old_chan
->dsp
= NULL
;
2933 old_chan
->dsp_features
= 0;
2935 /* Transfer flags from the old channel. */
2936 new_chan
->dialing
= old_chan
->dialing
;
2937 new_chan
->digital
= old_chan
->digital
;
2938 new_chan
->outgoing
= old_chan
->outgoing
;
2939 old_chan
->dialing
= 0;
2940 old_chan
->digital
= 0;
2941 old_chan
->outgoing
= 0;
2943 /* More stuff to transfer to the new channel. */
2944 new_chan
->law
= old_chan
->law
;
2945 strcpy(new_chan
->dialstring
, old_chan
->dialstring
);
2947 #endif /* defined(HAVE_PRI) */
2949 #if defined(HAVE_PRI)
2950 static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone
)
2953 case SIG_PRI_TONE_RINGTONE
:
2954 return DAHDI_TONE_RINGTONE
;
2955 case SIG_PRI_TONE_STUTTER
:
2956 return DAHDI_TONE_STUTTER
;
2957 case SIG_PRI_TONE_CONGESTION
:
2958 return DAHDI_TONE_CONGESTION
;
2959 case SIG_PRI_TONE_DIALTONE
:
2960 return DAHDI_TONE_DIALTONE
;
2961 case SIG_PRI_TONE_DIALRECALL
:
2962 return DAHDI_TONE_DIALRECALL
;
2963 case SIG_PRI_TONE_INFO
:
2964 return DAHDI_TONE_INFO
;
2965 case SIG_PRI_TONE_BUSY
:
2966 return DAHDI_TONE_BUSY
;
2971 #endif /* defined(HAVE_PRI) */
2973 #if defined(HAVE_PRI)
2974 static void my_handle_dchan_exception(struct sig_pri_span
*pri
, int index
)
2978 ioctl(pri
->fds
[index
], DAHDI_GETEVENT
, &x
);
2980 case DAHDI_EVENT_NONE
:
2982 case DAHDI_EVENT_ALARM
:
2983 case DAHDI_EVENT_NOALARM
:
2984 if (sig_pri_is_alarm_ignored(pri
)) {
2989 ast_log(LOG_NOTICE
, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
2990 event2str(x
), x
, pri
->span
);
2993 /* Keep track of alarm state */
2995 case DAHDI_EVENT_ALARM
:
2996 pri_event_alarm(pri
, index
, 0);
2998 case DAHDI_EVENT_NOALARM
:
2999 pri_event_noalarm(pri
, index
, 0);
3001 case DAHDI_EVENT_REMOVED
:
3002 pri_queue_for_destruction(pri
);
3008 #endif /* defined(HAVE_PRI) */
3010 #if defined(HAVE_PRI)
3011 static int my_pri_play_tone(void *pvt
, enum sig_pri_tone tone
)
3013 struct dahdi_pvt
*p
= pvt
;
3015 return tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, sig_pri_tone_to_dahditone(tone
));
3017 #endif /* defined(HAVE_PRI) */
3019 #if defined(HAVE_PRI) || defined(HAVE_SS7)
3022 * \brief Set the caller id information.
3025 * \param pvt DAHDI private structure
3026 * \param caller Caller-id information to set.
3028 static void my_set_callerid(void *pvt
, const struct ast_party_caller
*caller
)
3030 struct dahdi_pvt
*p
= pvt
;
3032 ast_copy_string(p
->cid_num
,
3033 S_COR(caller
->id
.number
.valid
, caller
->id
.number
.str
, ""),
3034 sizeof(p
->cid_num
));
3035 ast_copy_string(p
->cid_name
,
3036 S_COR(caller
->id
.name
.valid
, caller
->id
.name
.str
, ""),
3037 sizeof(p
->cid_name
));
3038 ast_copy_string(p
->cid_subaddr
,
3039 S_COR(caller
->id
.subaddress
.valid
, caller
->id
.subaddress
.str
, ""),
3040 sizeof(p
->cid_subaddr
));
3041 p
->cid_ton
= caller
->id
.number
.plan
;
3042 p
->callingpres
= ast_party_id_presentation(&caller
->id
);
3043 if (caller
->id
.tag
) {
3044 ast_copy_string(p
->cid_tag
, caller
->id
.tag
, sizeof(p
->cid_tag
));
3046 ast_copy_string(p
->cid_ani
,
3047 S_COR(caller
->ani
.number
.valid
, caller
->ani
.number
.str
, ""),
3048 sizeof(p
->cid_ani
));
3049 p
->cid_ani2
= caller
->ani2
;
3051 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3053 #if defined(HAVE_PRI) || defined(HAVE_SS7)
3056 * \brief Set the Dialed Number Identifier.
3059 * \param pvt DAHDI private structure
3060 * \param dnid Dialed Number Identifier string.
3062 static void my_set_dnid(void *pvt
, const char *dnid
)
3064 struct dahdi_pvt
*p
= pvt
;
3066 ast_copy_string(p
->dnid
, dnid
, sizeof(p
->dnid
));
3068 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3070 #if defined(HAVE_PRI)
3073 * \brief Set the Redirecting Directory Number Information Service (RDNIS).
3076 * \param pvt DAHDI private structure
3077 * \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
3079 static void my_set_rdnis(void *pvt
, const char *rdnis
)
3081 struct dahdi_pvt
*p
= pvt
;
3083 ast_copy_string(p
->rdnis
, rdnis
, sizeof(p
->rdnis
));
3085 #endif /* defined(HAVE_PRI) */
3087 #if defined(HAVE_PRI)
3090 * \brief Make a dialstring for native ISDN CC to recall properly.
3093 * \param priv Channel private control structure.
3094 * \param buf Where to put the modified dialstring.
3095 * \param buf_size Size of modified dialstring buffer.
3098 * original dialstring:
3100 DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3103 * The modified dialstring will have prefixed the channel-group section
3104 * with the ISDN channel restriction.
3108 DAHDI/i<span>-(g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3111 * The routine will check to see if the ISDN channel restriction is already
3112 * in the original dialstring.
3114 static void my_pri_make_cc_dialstring(void *priv
, char *buf
, size_t buf_size
)
3117 struct dahdi_pvt
*pvt
;
3118 AST_DECLARE_APP_ARGS(args
,
3119 AST_APP_ARG(tech
); /* channel technology token */
3120 AST_APP_ARG(group
); /* channel/group token */
3121 //AST_APP_ARG(ext); /* extension token */
3122 //AST_APP_ARG(opts); /* options token */
3123 //AST_APP_ARG(other); /* Any remining unused arguments */
3127 dial
= ast_strdupa(pvt
->dialstring
);
3128 AST_NONSTANDARD_APP_ARGS(args
, dial
, '/');
3130 ast_copy_string(buf
, pvt
->dialstring
, buf_size
);
3134 /* Append the ISDN span channel restriction to the dialstring. */
3135 snprintf(buf
, buf_size
, "%s/i%d-", args
.tech
, pvt
->pri
->span
);
3138 if (isdigit(args
.group
[0]) || args
.group
[0] == 'i' || strchr(args
.group
, '!')) {
3139 /* The ISDN span channel restriction is not needed or already
3140 * in the dialstring. */
3141 ast_copy_string(buf
, pvt
->dialstring
, buf_size
);
3144 /* Insert the ISDN span channel restriction into the dialstring. */
3145 snprintf(buf
, buf_size
, "%s/i%d-%s", args
.tech
, pvt
->pri
->span
, args
.group
);
3147 #endif /* defined(HAVE_PRI) */
3149 #if defined(HAVE_PRI)
3152 * \brief Reevaluate the PRI span device state.
3155 * \param pri Asterisk D channel control structure.
3157 * \note Assumes the pri->lock is already obtained.
3159 static void dahdi_pri_update_span_devstate(struct sig_pri_span
*pri
)
3162 unsigned num_b_chans
; /* Number of B channels provisioned on the span. */
3163 unsigned in_use
; /* Number of B channels in use on the span. */
3164 unsigned in_alarm
; /* TRUE if the span is in alarm condition. */
3165 enum ast_device_state new_state
;
3167 /* Count the number of B channels and the number of B channels in use. */
3171 for (idx
= pri
->numchans
; idx
--;) {
3172 if (pri
->pvts
[idx
] && !pri
->pvts
[idx
]->no_b_channel
) {
3173 /* This is a B channel interface. */
3175 if (!sig_pri_is_chan_available(pri
->pvts
[idx
])) {
3178 if (!pri
->pvts
[idx
]->inalarm
) {
3179 /* There is a channel that is not in alarm. */
3185 /* Update the span congestion device state and report any change. */
3187 new_state
= AST_DEVICE_UNAVAILABLE
;
3189 new_state
= num_b_chans
== in_use
? AST_DEVICE_BUSY
: AST_DEVICE_NOT_INUSE
;
3191 if (pri
->congestion_devstate
!= new_state
) {
3192 pri
->congestion_devstate
= new_state
;
3193 ast_devstate_changed(AST_DEVICE_UNKNOWN
, AST_DEVSTATE_NOT_CACHABLE
, "DAHDI/I%d/congestion", pri
->span
);
3195 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
3196 /* Update the span threshold device state and report any change. */
3198 new_state
= AST_DEVICE_UNAVAILABLE
;
3199 } else if (!in_use
) {
3200 new_state
= AST_DEVICE_NOT_INUSE
;
3201 } else if (!pri
->user_busy_threshold
) {
3202 new_state
= in_use
< num_b_chans
? AST_DEVICE_INUSE
: AST_DEVICE_BUSY
;
3204 new_state
= in_use
< pri
->user_busy_threshold
? AST_DEVICE_INUSE
3207 if (pri
->threshold_devstate
!= new_state
) {
3208 pri
->threshold_devstate
= new_state
;
3209 ast_devstate_changed(AST_DEVICE_UNKNOWN
, AST_DEVSTATE_NOT_CACHABLE
, "DAHDI/I%d/threshold", pri
->span
);
3211 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
3213 #endif /* defined(HAVE_PRI) */
3215 #if defined(HAVE_PRI)
3218 * \brief Reference this module.
3221 static void my_module_ref(void)
3223 ast_module_ref(ast_module_info
->self
);
3225 #endif /* defined(HAVE_PRI) */
3227 #if defined(HAVE_PRI)
3230 * \brief Unreference this module.
3233 static void my_module_unref(void)
3235 ast_module_unref(ast_module_info
->self
);
3237 #endif /* defined(HAVE_PRI) */
3239 #if defined(HAVE_PRI)
3240 #if defined(HAVE_PRI_CALL_WAITING)
3241 static void my_pri_init_config(void *priv
, struct sig_pri_span
*pri
);
3242 #endif /* defined(HAVE_PRI_CALL_WAITING) */
3243 static int dahdi_new_pri_nobch_channel(struct sig_pri_span
*pri
);
3245 struct sig_pri_callback sig_pri_callbacks
=
3247 .handle_dchan_exception
= my_handle_dchan_exception
,
3248 .play_tone
= my_pri_play_tone
,
3249 .set_echocanceller
= my_set_echocanceller
,
3250 .dsp_reset_and_flush_digits
= my_dsp_reset_and_flush_digits
,
3251 .lock_private
= my_lock_private
,
3252 .unlock_private
= my_unlock_private
,
3253 .deadlock_avoidance_private
= my_deadlock_avoidance_private
,
3254 .new_ast_channel
= my_new_pri_ast_channel
,
3255 .fixup_chans
= my_pri_fixup_chans
,
3256 .set_alarm
= my_set_alarm
,
3257 .set_dialing
= my_set_dialing
,
3258 .set_outgoing
= my_set_outgoing
,
3259 .set_digital
= my_set_digital
,
3260 .set_callerid
= my_set_callerid
,
3261 .set_dnid
= my_set_dnid
,
3262 .set_rdnis
= my_set_rdnis
,
3263 .new_nobch_intf
= dahdi_new_pri_nobch_channel
,
3264 #if defined(HAVE_PRI_CALL_WAITING)
3265 .init_config
= my_pri_init_config
,
3266 #endif /* defined(HAVE_PRI_CALL_WAITING) */
3267 .get_orig_dialstring
= my_get_orig_dialstring
,
3268 .make_cc_dialstring
= my_pri_make_cc_dialstring
,
3269 .update_span_devstate
= dahdi_pri_update_span_devstate
,
3270 .module_ref
= my_module_ref
,
3271 .module_unref
= my_module_unref
,
3272 .dial_digits
= my_pri_dial_digits
,
3273 .open_media
= my_pri_ss7_open_media
,
3274 .ami_channel_event
= my_ami_channel_event
,
3275 .destroy_later
= pri_queue_for_destruction
,
3277 #endif /* defined(HAVE_PRI) */
3279 #if defined(HAVE_SS7)
3282 * \brief Handle the SS7 link exception.
3285 * \param linkset Controlling linkset for the channel.
3286 * \param which Link index of the signaling channel.
3288 static void my_handle_link_exception(struct sig_ss7_linkset
*linkset
, int which
)
3292 if (ioctl(linkset
->fds
[which
], DAHDI_GETEVENT
, &event
)) {
3293 ast_log(LOG_ERROR
, "SS7: Error in exception retrieval on span %d/%d!\n",
3294 linkset
->span
, which
);
3298 case DAHDI_EVENT_NONE
:
3300 case DAHDI_EVENT_ALARM
:
3301 ast_log(LOG_ERROR
, "SS7 got event: %s(%d) on span %d/%d\n",
3302 event2str(event
), event
, linkset
->span
, which
);
3303 sig_ss7_link_alarm(linkset
, which
);
3305 case DAHDI_EVENT_NOALARM
:
3306 ast_log(LOG_ERROR
, "SS7 got event: %s(%d) on span %d/%d\n",
3307 event2str(event
), event
, linkset
->span
, which
);
3308 sig_ss7_link_noalarm(linkset
, which
);
3311 ast_log(LOG_NOTICE
, "SS7 got event: %s(%d) on span %d/%d\n",
3312 event2str(event
), event
, linkset
->span
, which
);
3316 #endif /* defined(HAVE_SS7) */
3318 #if defined(HAVE_SS7)
3319 static void my_ss7_set_loopback(void *pvt
, int enable
)
3321 struct dahdi_pvt
*p
= pvt
;
3323 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_LOOPBACK
, &enable
)) {
3324 ast_log(LOG_WARNING
, "Unable to set loopback on channel %d: %s\n", p
->channel
,
3328 #endif /* defined(HAVE_SS7) */
3330 #if defined(HAVE_SS7)
3333 * \brief Find the linkset to which SS7 belongs.
3336 * \param ss7 structure to match on.
3338 * \retval linkset if found.
3339 * \retval NULL if not found.
3341 static struct sig_ss7_linkset
*my_ss7_find_linkset(struct ss7
*ss7
)
3349 for (idx
= 0; idx
< NUM_SPANS
; ++idx
) {
3350 if (linksets
[idx
].ss7
.ss7
== ss7
) {
3351 return &linksets
[idx
].ss7
;
3356 #endif /* defined(HAVE_SS7) */
3358 #if defined(HAVE_SS7)
3361 * \brief Create a new asterisk channel structure for SS7.
3364 * \param pvt Private channel structure.
3365 * \param state Initial state of new channel.
3366 * \param law Companding law to use.
3367 * \param exten Dialplan extension for incoming call.
3368 * \param requestor Channel requesting this new channel.
3369 * \param assignedids
3371 * \retval ast_channel on success.
3372 * \retval NULL on error.
3374 static struct ast_channel
*my_new_ss7_ast_channel(void *pvt
, int state
, enum sig_ss7_law law
, char *exten
, const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
)
3376 struct dahdi_pvt
*p
= pvt
;
3379 ast_callid callid
= 0;
3380 int callid_created
= ast_callid_threadstorage_auto(&callid
);
3382 /* Set to audio mode at this point */
3384 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &audio
) == -1)
3385 ast_log(LOG_WARNING
, "Unable to set audio mode on channel %d to %d: %s\n",
3386 p
->channel
, audio
, strerror(errno
));
3388 if (law
!= SIG_SS7_DEFLAW
) {
3389 dahdi_setlaw(p
->subs
[SUB_REAL
].dfd
,
3390 (law
== SIG_SS7_ULAW
) ? DAHDI_LAW_MULAW
: DAHDI_LAW_ALAW
);
3393 ast_copy_string(p
->exten
, exten
, sizeof(p
->exten
));
3397 case SIG_SS7_DEFLAW
:
3401 newlaw
= DAHDI_LAW_ALAW
;
3404 newlaw
= DAHDI_LAW_MULAW
;
3407 return dahdi_new_callid_clean(p
, state
, 0, SUB_REAL
, newlaw
, assignedids
, requestor
, callid
, callid_created
);
3409 #endif /* defined(HAVE_SS7) */
3411 #if defined(HAVE_SS7)
3412 static int sig_ss7_tone_to_dahditone(enum sig_ss7_tone tone
)
3415 case SIG_SS7_TONE_RINGTONE
:
3416 return DAHDI_TONE_RINGTONE
;
3417 case SIG_SS7_TONE_STUTTER
:
3418 return DAHDI_TONE_STUTTER
;
3419 case SIG_SS7_TONE_CONGESTION
:
3420 return DAHDI_TONE_CONGESTION
;
3421 case SIG_SS7_TONE_DIALTONE
:
3422 return DAHDI_TONE_DIALTONE
;
3423 case SIG_SS7_TONE_DIALRECALL
:
3424 return DAHDI_TONE_DIALRECALL
;
3425 case SIG_SS7_TONE_INFO
:
3426 return DAHDI_TONE_INFO
;
3427 case SIG_SS7_TONE_BUSY
:
3428 return DAHDI_TONE_BUSY
;
3433 #endif /* defined(HAVE_SS7) */
3435 #if defined(HAVE_SS7)
3436 static int my_ss7_play_tone(void *pvt
, enum sig_ss7_tone tone
)
3438 struct dahdi_pvt
*p
= pvt
;
3440 return tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, sig_ss7_tone_to_dahditone(tone
));
3442 #endif /* defined(HAVE_SS7) */
3444 #if defined(HAVE_SS7)
3445 struct sig_ss7_callback sig_ss7_callbacks
=
3447 .lock_private
= my_lock_private
,
3448 .unlock_private
= my_unlock_private
,
3449 .deadlock_avoidance_private
= my_deadlock_avoidance_private
,
3451 .set_echocanceller
= my_set_echocanceller
,
3452 .set_loopback
= my_ss7_set_loopback
,
3454 .new_ast_channel
= my_new_ss7_ast_channel
,
3455 .play_tone
= my_ss7_play_tone
,
3457 .handle_link_exception
= my_handle_link_exception
,
3458 .set_alarm
= my_set_alarm
,
3459 .set_dialing
= my_set_dialing
,
3460 .set_outgoing
= my_set_outgoing
,
3461 .set_digital
= my_set_digital
,
3462 .set_inservice
= my_set_inservice
,
3463 .set_locallyblocked
= my_set_locallyblocked
,
3464 .set_remotelyblocked
= my_set_remotelyblocked
,
3465 .set_callerid
= my_set_callerid
,
3466 .set_dnid
= my_set_dnid
,
3467 .open_media
= my_pri_ss7_open_media
,
3468 .find_linkset
= my_ss7_find_linkset
,
3470 #endif /* defined(HAVE_SS7) */
3473 * \brief Send MWI state change
3475 * \param mailbox This is the mailbox associated with the FXO line that the
3476 * MWI state has changed on.
3477 * \param thereornot This argument should simply be set to 1 or 0, to indicate
3478 * whether there are messages waiting or not.
3480 * This function does two things:
3482 * 1) It generates an internal Asterisk event notifying any other module that
3483 * cares about MWI that the state of a mailbox has changed.
3485 * 2) It runs the script specified by the mwimonitornotify option to allow
3486 * some custom handling of the state change.
3488 static void notify_message(char *mailbox
, int thereornot
)
3490 char s
[sizeof(mwimonitornotify
) + 164];
3492 if (ast_strlen_zero(mailbox
)) {
3496 ast_publish_mwi_state(mailbox
, NULL
, thereornot
, thereornot
);
3497 if (!ast_strlen_zero(mwimonitornotify
)) {
3498 snprintf(s
, sizeof(s
), "%s %s %d", mwimonitornotify
, mailbox
, thereornot
);
3503 static void my_handle_notify_message(struct ast_channel
*chan
, void *pvt
, int cid_flags
, int neon_mwievent
)
3505 struct dahdi_pvt
*p
= pvt
;
3507 if (neon_mwievent
> -1 && !p
->mwimonitor_neon
)
3510 if (neon_mwievent
== ANALOG_EVENT_NEONMWI_ACTIVE
|| cid_flags
& CID_MSGWAITING
) {
3511 ast_log(LOG_NOTICE
, "MWI: Channel %d message waiting, mailbox %s\n", p
->channel
, p
->mailbox
);
3512 notify_message(p
->mailbox
, 1);
3513 } else if (neon_mwievent
== ANALOG_EVENT_NEONMWI_INACTIVE
|| cid_flags
& CID_NOMSGWAITING
) {
3514 ast_log(LOG_NOTICE
, "MWI: Channel %d no message waiting, mailbox %s\n", p
->channel
, p
->mailbox
);
3515 notify_message(p
->mailbox
, 0);
3517 /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
3518 /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
3519 if (neon_mwievent
== -1 && p
->mwimonitor_rpas
) {
3525 static int my_have_progressdetect(void *pvt
)
3527 struct dahdi_pvt
*p
= pvt
;
3529 if ((p
->callprogress
& CALLPROGRESS_PROGRESS
)
3530 && CANPROGRESSDETECT(p
) && p
->dsp
&& p
->outgoing
) {
3533 /* Don't have progress detection. */
3538 #define gen_pvt_field_callback(type, field) \
3539 static type my_get_##field(void *pvt) \
3541 struct dahdi_pvt *p = pvt; \
3545 gen_pvt_field_callback(int, firstdigit_timeout
);
3546 gen_pvt_field_callback(int, interdigit_timeout
);
3547 gen_pvt_field_callback(int, matchdigit_timeout
);
3549 #undef gen_pvt_field_callback
3551 struct analog_callback analog_callbacks
=
3553 .play_tone
= my_play_tone
,
3554 .get_event
= my_get_event
,
3555 .wait_event
= my_wait_event
,
3556 .is_off_hook
= my_is_off_hook
,
3557 .set_echocanceller
= my_set_echocanceller
,
3560 .off_hook
= my_off_hook
,
3561 .dial_digits
= my_dial_digits
,
3562 .train_echocanceller
= my_train_echocanceller
,
3563 .on_hook
= my_on_hook
,
3564 .is_dialing
= my_is_dialing
,
3565 .allocate_sub
= my_allocate_sub
,
3566 .unallocate_sub
= my_unallocate_sub
,
3567 .swap_subs
= my_swap_subchannels
,
3568 .has_voicemail
= my_has_voicemail
,
3569 .check_for_conference
= my_check_for_conference
,
3570 .conf_add
= my_conf_add
,
3571 .conf_del
= my_conf_del
,
3572 .complete_conference_update
= my_complete_conference_update
,
3574 .all_subchannels_hungup
= my_all_subchannels_hungup
,
3575 .lock_private
= my_lock_private
,
3576 .unlock_private
= my_unlock_private
,
3577 .deadlock_avoidance_private
= my_deadlock_avoidance_private
,
3578 .handle_dtmf
= my_handle_dtmf
,
3580 .new_ast_channel
= my_new_analog_ast_channel
,
3581 .dsp_set_digitmode
= my_dsp_set_digitmode
,
3582 .dsp_reset_and_flush_digits
= my_dsp_reset_and_flush_digits
,
3583 .send_callerid
= my_send_callerid
,
3584 .callwait
= my_callwait
,
3585 .stop_callwait
= my_stop_callwait
,
3586 .get_callerid
= my_get_callerid
,
3587 .start_cid_detect
= my_start_cid_detect
,
3588 .stop_cid_detect
= my_stop_cid_detect
,
3589 .handle_notify_message
= my_handle_notify_message
,
3590 .increase_ss_count
= my_increase_ss_count
,
3591 .decrease_ss_count
= my_decrease_ss_count
,
3592 .distinctive_ring
= my_distinctive_ring
,
3593 .set_linear_mode
= my_set_linear_mode
,
3594 .set_inthreeway
= my_set_inthreeway
,
3595 .get_and_handle_alarms
= my_get_and_handle_alarms
,
3596 .get_sigpvt_bridged_channel
= my_get_sigpvt_bridged_channel
,
3597 .get_sub_fd
= my_get_sub_fd
,
3598 .set_cadence
= my_set_cadence
,
3599 .set_alarm
= my_set_alarm
,
3600 .set_dialing
= my_set_dialing
,
3601 .set_outgoing
= my_set_outgoing
,
3602 .set_ringtimeout
= my_set_ringtimeout
,
3603 .set_waitingfordt
= my_set_waitingfordt
,
3604 .check_waitingfordt
= my_check_waitingfordt
,
3605 .set_confirmanswer
= my_set_confirmanswer
,
3606 .check_confirmanswer
= my_check_confirmanswer
,
3607 .set_callwaiting
= my_set_callwaiting
,
3608 .cancel_cidspill
= my_cancel_cidspill
,
3609 .confmute
= my_confmute
,
3610 .set_pulsedial
= my_set_pulsedial
,
3611 .set_new_owner
= my_set_new_owner
,
3612 .get_orig_dialstring
= my_get_orig_dialstring
,
3613 .set_needringing
= my_set_needringing
,
3614 .set_polarity
= my_set_polarity
,
3615 .start_polarityswitch
= my_start_polarityswitch
,
3616 .answer_polarityswitch
= my_answer_polarityswitch
,
3617 .hangup_polarityswitch
= my_hangup_polarityswitch
,
3618 .have_progressdetect
= my_have_progressdetect
,
3619 .get_firstdigit_timeout
= my_get_firstdigit_timeout
,
3620 .get_matchdigit_timeout
= my_get_matchdigit_timeout
,
3621 .get_interdigit_timeout
= my_get_interdigit_timeout
,
3624 /*! Round robin search locations. */
3625 static struct dahdi_pvt
*round_robin
[64]; /* groups can range from 0-63 */
3627 int _dahdi_get_index(struct ast_channel
*ast
, struct dahdi_pvt
*p
, int nullok
, const char *fname
, unsigned long line
)
3630 if (p
->subs
[SUB_REAL
].owner
== ast
)
3632 else if (p
->subs
[SUB_CALLWAIT
].owner
== ast
)
3634 else if (p
->subs
[SUB_THREEWAY
].owner
== ast
)
3639 ast_log(LOG_WARNING
,
3640 "Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
3641 ast
? ast_channel_name(ast
) : "", p
->channel
, fname
, line
);
3648 * \brief Obtain the specified subchannel owner lock if the owner exists.
3650 * \param pvt Channel private struct.
3651 * \param sub_idx Subchannel owner to lock.
3653 * \note Assumes the pvt->lock is already obtained.
3656 * Because deadlock avoidance may have been necessary, you need to confirm
3657 * the state of things before continuing.
3659 static void dahdi_lock_sub_owner(struct dahdi_pvt
*pvt
, int sub_idx
)
3662 if (!pvt
->subs
[sub_idx
].owner
) {
3663 /* No subchannel owner pointer */
3666 if (!ast_channel_trylock(pvt
->subs
[sub_idx
].owner
)) {
3667 /* Got subchannel owner lock */
3670 /* We must unlock the private to avoid the possibility of a deadlock */
3671 DEADLOCK_AVOIDANCE(&pvt
->lock
);
3675 static void wakeup_sub(struct dahdi_pvt
*p
, int a
)
3677 dahdi_lock_sub_owner(p
, a
);
3678 if (p
->subs
[a
].owner
) {
3679 ast_queue_frame(p
->subs
[a
].owner
, &ast_null_frame
);
3680 ast_channel_unlock(p
->subs
[a
].owner
);
3684 static void dahdi_queue_frame(struct dahdi_pvt
*p
, struct ast_frame
*f
)
3688 if (ast_channel_trylock(p
->owner
)) {
3689 DEADLOCK_AVOIDANCE(&p
->lock
);
3691 ast_queue_frame(p
->owner
, f
);
3692 ast_channel_unlock(p
->owner
);
3700 static void publish_channel_alarm_clear(int channel
)
3702 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
3703 RAII_VAR(struct ast_str
*, dahdi_chan
, ast_str_create(32), ast_free
);
3708 ast_str_set(&dahdi_chan
, 0, "%d", channel
);
3709 ast_log(LOG_NOTICE
, "Alarm cleared on channel DAHDI/%d\n", channel
);
3710 body
= ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan
));
3715 ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM
, body
);
3718 static void publish_span_alarm_clear(int span
)
3720 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
3722 ast_log(LOG_NOTICE
, "Alarm cleared on span %d\n", span
);
3723 body
= ast_json_pack("{s: i}", "Span", span
);
3728 ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM
, body
);
3731 static void handle_clear_alarms(struct dahdi_pvt
*p
)
3733 #if defined(HAVE_PRI)
3734 if (dahdi_sig_pri_lib_handles(p
->sig
) && sig_pri_is_alarm_ignored(p
->pri
)) {
3737 #endif /* defined(HAVE_PRI) */
3739 if (report_alarms
& REPORT_CHANNEL_ALARMS
) {
3740 publish_channel_alarm_clear(p
->channel
);
3742 if (report_alarms
& REPORT_SPAN_ALARMS
&& p
->manages_span_alarms
) {
3743 publish_span_alarm_clear(p
->span
);
3748 static void mfcr2_queue_for_destruction(const struct dahdi_pvt
*p
)
3750 const struct dahdi_mfcr2
*r2link
= p
->mfcr2
;
3751 struct r2link_entry
*cur
;
3752 AST_LIST_LOCK(&r2links
);
3753 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links
, cur
, list
) {
3754 if (r2link
== &cur
->mfcr2
) {
3755 ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p
->channel
);
3756 AST_LIST_MOVE_CURRENT(&nodev_r2links
, list
);
3760 AST_LIST_TRAVERSE_SAFE_END
;
3761 AST_LIST_UNLOCK(&r2links
);
3764 static int dahdi_r2_answer(struct dahdi_pvt
*p
)
3767 /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
3768 * and does not has support for openr2_chan_answer_call_with_mode
3770 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
3771 const char *double_answer
= pbx_builtin_getvar_helper(p
->owner
, "MFCR2_DOUBLE_ANSWER");
3772 int wants_double_answer
= ast_true(double_answer
) ? 1 : 0;
3773 if (!double_answer
) {
3774 /* this still can result in double answer if the channel context
3775 * was configured that way */
3776 res
= openr2_chan_answer_call(p
->r2chan
);
3777 } else if (wants_double_answer
) {
3778 res
= openr2_chan_answer_call_with_mode(p
->r2chan
, OR2_ANSWER_DOUBLE
);
3780 res
= openr2_chan_answer_call_with_mode(p
->r2chan
, OR2_ANSWER_SIMPLE
);
3783 res
= openr2_chan_answer_call(p
->r2chan
);
3790 /* should be called with the ast_channel locked */
3791 static openr2_calling_party_category_t
dahdi_r2_get_channel_category(struct ast_channel
*c
)
3793 openr2_calling_party_category_t cat
;
3794 const char *catstr
= pbx_builtin_getvar_helper(c
, "MFCR2_CATEGORY");
3795 struct dahdi_pvt
*p
= ast_channel_tech_pvt(c
);
3796 if (ast_strlen_zero(catstr
)) {
3797 ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
3798 ast_channel_name(c
), openr2_proto_get_category_string(p
->mfcr2_category
));
3799 return p
->mfcr2_category
;
3801 if ((cat
= openr2_proto_get_category(catstr
)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN
) {
3802 ast_log(LOG_WARNING
, "Invalid category specified '%s' for chan %s, using default %s\n",
3803 catstr
, ast_channel_name(c
), openr2_proto_get_category_string(p
->mfcr2_category
));
3804 return p
->mfcr2_category
;
3806 ast_debug(1, "Using category %s\n", catstr
);
3810 static void dahdi_r2_on_call_init(openr2_chan_t
*r2chan
)
3812 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
3813 ast_mutex_lock(&p
->lock
);
3815 ast_mutex_unlock(&p
->lock
);
3816 /* TODO: This can happen when some other thread just finished dahdi_request requesting this very same
3817 interface but has not yet seized the line (dahdi_call), and the far end wins and seize the line,
3818 can we avoid this somehow?, at this point when dahdi_call send the seize, it is likely that since
3819 the other end will see our seize as a forced release and drop the call, we will see an invalid
3820 pattern that will be seen and treated as protocol error. */
3821 ast_log(LOG_ERROR
, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan
));
3825 /* better safe than sorry ... */
3826 p
->cid_name
[0] = '\0';
3827 p
->cid_num
[0] = '\0';
3828 p
->cid_subaddr
[0] = '\0';
3831 p
->mfcr2_ani_index
= '\0';
3832 p
->mfcr2_dnis_index
= '\0';
3833 p
->mfcr2_dnis_matched
= 0;
3834 p
->mfcr2_answer_pending
= 0;
3835 p
->mfcr2_call_accepted
= 0;
3836 ast_mutex_unlock(&p
->lock
);
3837 ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan
));
3840 static void dahdi_r2_on_hardware_alarm(openr2_chan_t
*r2chan
, int alarm
)
3843 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
3844 ast_mutex_lock(&p
->lock
);
3845 p
->inalarm
= alarm
? 1 : 0;
3847 res
= get_alarms(p
);
3848 if (res
== DAHDI_ALARM_NOTOPEN
) {
3849 mfcr2_queue_for_destruction(p
);
3851 handle_alarms(p
, res
);
3853 handle_clear_alarms(p
);
3855 ast_mutex_unlock(&p
->lock
);
3858 static void dahdi_r2_on_os_error(openr2_chan_t
*r2chan
, int errorcode
)
3860 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
3862 ast_log(LOG_ERROR
, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan
), strerror(errorcode
));
3863 ast_mutex_lock(&p
->lock
);
3865 if (errorcode
== ENODEV
) {
3866 struct dahdi_mfcr2
*r2link
= p
->mfcr2
;
3872 ast_mutex_unlock(&p
->lock
);
3875 static void dahdi_r2_on_protocol_error(openr2_chan_t
*r2chan
, openr2_protocol_error_t reason
)
3877 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
3878 ast_log(LOG_ERROR
, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan
), openr2_proto_get_error(reason
));
3880 ast_channel_hangupcause_set(p
->owner
, AST_CAUSE_PROTOCOL_ERROR
);
3881 ast_channel_softhangup_internal_flag_add(p
->owner
, AST_SOFTHANGUP_DEV
);
3883 ast_mutex_lock(&p
->lock
);
3885 ast_mutex_unlock(&p
->lock
);
3888 static void dahdi_r2_disconnect_call(struct dahdi_pvt
*p
, openr2_call_disconnect_cause_t cause
)
3890 if (openr2_chan_disconnect_call(p
->r2chan
, cause
)) {
3891 ast_log(LOG_NOTICE
, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
3892 p
->channel
, openr2_proto_get_disconnect_string(cause
));
3893 /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
3894 openr2_chan_set_idle(p
->r2chan
);
3895 ast_mutex_lock(&p
->lock
);
3897 ast_mutex_unlock(&p
->lock
);
3901 static void dahdi_r2_on_call_offered(openr2_chan_t
*r2chan
, const char *ani
, const char *dnis
, openr2_calling_party_category_t category
)
3903 struct dahdi_pvt
*p
;
3904 struct ast_channel
*c
;
3905 ast_callid callid
= 0;
3906 int callid_created
= ast_callid_threadstorage_auto(&callid
);
3907 ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
3908 openr2_chan_get_number(r2chan
), ani
? ani
: "(restricted)", dnis
,
3909 openr2_proto_get_category_string(category
));
3910 p
= openr2_chan_get_client_data(r2chan
);
3911 /* if collect calls are not allowed and this is a collect call, reject it! */
3912 if (!p
->mfcr2_allow_collect_calls
&& category
== OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL
) {
3913 ast_log(LOG_NOTICE
, "Rejecting MFC/R2 collect call\n");
3914 dahdi_r2_disconnect_call(p
, OR2_CAUSE_COLLECT_CALL_REJECTED
);
3915 goto dahdi_r2_on_call_offered_cleanup
;
3917 ast_mutex_lock(&p
->lock
);
3918 p
->mfcr2_recvd_category
= category
;
3919 /* if we're not supposed to use CID, clear whatever we have */
3920 if (!p
->use_callerid
) {
3921 ast_debug(1, "No CID allowed in configuration, CID is being cleared!\n");
3925 /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
3926 if (p
->immediate
|| !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan
))) {
3927 ast_debug(1, "Setting exten => s because of immediate or 0 DNIS configured\n");
3931 ast_mutex_unlock(&p
->lock
);
3932 if (!ast_exists_extension(NULL
, p
->context
, p
->exten
, 1, p
->cid_num
)) {
3933 ast_log(LOG_NOTICE
, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
3934 p
->channel
, p
->exten
, p
->context
);
3935 dahdi_r2_disconnect_call(p
, OR2_CAUSE_UNALLOCATED_NUMBER
);
3936 goto dahdi_r2_on_call_offered_cleanup
;
3938 if (!p
->mfcr2_accept_on_offer
) {
3939 /* The user wants us to start the PBX thread right away without accepting the call first */
3940 c
= dahdi_new(p
, AST_STATE_RING
, 1, SUB_REAL
, DAHDI_LAW_ALAW
, NULL
, NULL
, callid
);
3942 /* Done here, don't disable reading now since we still need to generate MF tones to accept
3943 the call or reject it and detect the tone off condition of the other end, all of this
3944 will be done in the PBX thread now */
3945 goto dahdi_r2_on_call_offered_cleanup
;
3947 ast_log(LOG_WARNING
, "Unable to create PBX channel in DAHDI channel %d\n", p
->channel
);
3948 dahdi_r2_disconnect_call(p
, OR2_CAUSE_OUT_OF_ORDER
);
3949 } else if (p
->mfcr2_charge_calls
) {
3950 ast_debug(1, "Accepting MFC/R2 call with charge on chan %d\n", p
->channel
);
3951 openr2_chan_accept_call(r2chan
, OR2_CALL_WITH_CHARGE
);
3953 ast_debug(1, "Accepting MFC/R2 call with no charge on chan %d\n", p
->channel
);
3954 openr2_chan_accept_call(r2chan
, OR2_CALL_NO_CHARGE
);
3957 dahdi_r2_on_call_offered_cleanup
:
3958 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
3961 static void dahdi_r2_on_call_end(openr2_chan_t
*r2chan
)
3963 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
3964 ast_verbose("MFC/R2 call end on channel %d\n", p
->channel
);
3965 ast_mutex_lock(&p
->lock
);
3967 ast_mutex_unlock(&p
->lock
);
3970 static void dahdi_r2_on_call_accepted(openr2_chan_t
*r2chan
, openr2_call_mode_t mode
)
3972 struct dahdi_pvt
*p
= NULL
;
3973 struct ast_channel
*c
= NULL
;
3974 ast_callid callid
= 0;
3975 int callid_created
= ast_callid_threadstorage_auto(&callid
);
3976 p
= openr2_chan_get_client_data(r2chan
);
3978 p
->mfcr2_call_accepted
= 1;
3979 /* if it's an incoming call ... */
3980 if (OR2_DIR_BACKWARD
== openr2_chan_get_direction(r2chan
)) {
3981 ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan
));
3982 /* If accept on offer is not set, it means at this point the PBX thread is already
3983 launched (was launched in the 'on call offered' handler) and therefore this callback
3984 is being executed already in the PBX thread rather than the monitor thread, don't launch
3985 any other thread, just disable the openr2 reading and answer the call if needed */
3986 if (!p
->mfcr2_accept_on_offer
) {
3987 openr2_chan_disable_read(r2chan
);
3988 if (p
->mfcr2_answer_pending
) {
3989 ast_debug(1, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan
));
3992 goto dahdi_r2_on_call_accepted_cleanup
;
3994 c
= dahdi_new(p
, AST_STATE_RING
, 1, SUB_REAL
, DAHDI_LAW_ALAW
, NULL
, NULL
, callid
);
3996 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
3997 library to forget about it */
3998 openr2_chan_disable_read(r2chan
);
3999 goto dahdi_r2_on_call_accepted_cleanup
;
4001 ast_log(LOG_WARNING
, "Unable to create PBX channel in DAHDI channel %d\n", p
->channel
);
4002 /* failed to create the channel, bail out and report it as an out of order line */
4003 dahdi_r2_disconnect_call(p
, OR2_CAUSE_OUT_OF_ORDER
);
4004 goto dahdi_r2_on_call_accepted_cleanup
;
4006 /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
4007 ast_verbose("MFC/R2 call has been accepted on forward channel %d\n", p
->channel
);
4008 p
->subs
[SUB_REAL
].needringing
= 1;
4010 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the library to forget about it */
4011 openr2_chan_disable_read(r2chan
);
4013 dahdi_r2_on_call_accepted_cleanup
:
4014 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
4017 static void dahdi_r2_on_call_answered(openr2_chan_t
*r2chan
)
4019 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
4020 ast_verbose("MFC/R2 call has been answered on channel %d\n", openr2_chan_get_number(r2chan
));
4021 p
->subs
[SUB_REAL
].needanswer
= 1;
4024 static void dahdi_r2_on_call_read(openr2_chan_t
*r2chan
, const unsigned char *buf
, int buflen
)
4026 /*ast_debug(1, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
4029 static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause
)
4032 case OR2_CAUSE_BUSY_NUMBER
:
4033 return AST_CAUSE_BUSY
;
4034 case OR2_CAUSE_NETWORK_CONGESTION
:
4035 return AST_CAUSE_CONGESTION
;
4036 case OR2_CAUSE_OUT_OF_ORDER
:
4037 return AST_CAUSE_DESTINATION_OUT_OF_ORDER
;
4038 case OR2_CAUSE_UNALLOCATED_NUMBER
:
4039 return AST_CAUSE_UNREGISTERED
;
4040 case OR2_CAUSE_NO_ANSWER
:
4041 return AST_CAUSE_NO_ANSWER
;
4042 case OR2_CAUSE_NORMAL_CLEARING
:
4043 return AST_CAUSE_NORMAL_CLEARING
;
4044 case OR2_CAUSE_UNSPECIFIED
:
4046 return AST_CAUSE_NOTDEFINED
;
4050 static void dahdi_r2_on_call_disconnect(openr2_chan_t
*r2chan
, openr2_call_disconnect_cause_t cause
)
4052 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
4054 struct ast_control_pvt_cause_code
*cause_code
;
4055 int datalen
= sizeof(*cause_code
);
4057 ast_verbose("MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan
));
4058 ast_mutex_lock(&p
->lock
);
4060 ast_mutex_unlock(&p
->lock
);
4061 /* no owner, therefore we can't use dahdi_hangup to disconnect, do it right now */
4062 dahdi_r2_disconnect_call(p
, OR2_CAUSE_NORMAL_CLEARING
);
4066 snprintf(cause_str
, sizeof(cause_str
), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause
));
4067 datalen
+= strlen(cause_str
);
4068 cause_code
= ast_alloca(datalen
);
4069 memset(cause_code
, 0, datalen
);
4070 cause_code
->ast_cause
= dahdi_r2_cause_to_ast_cause(cause
);
4071 ast_copy_string(cause_code
->chan_name
, ast_channel_name(p
->owner
), AST_CHANNEL_NAME
);
4072 ast_copy_string(cause_code
->code
, cause_str
, datalen
+ 1 - sizeof(*cause_code
));
4073 ast_queue_control_data(p
->owner
, AST_CONTROL_PVT_CAUSE_CODE
, cause_code
, datalen
);
4074 ast_channel_hangupcause_hash_set(p
->owner
, cause_code
, datalen
);
4075 ast_channel_hangupcause_set(p
->owner
, cause_code
->ast_cause
);
4077 /* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
4078 be done in dahdi_hangup */
4079 if (ast_channel_state(p
->owner
) == AST_STATE_UP
) {
4080 ast_channel_softhangup_internal_flag_add(p
->owner
, AST_SOFTHANGUP_DEV
);
4081 ast_mutex_unlock(&p
->lock
);
4082 } else if (openr2_chan_get_direction(r2chan
) == OR2_DIR_FORWARD
) {
4083 /* being the forward side we must report what happened to the call to whoever requested it */
4085 case OR2_CAUSE_BUSY_NUMBER
:
4086 p
->subs
[SUB_REAL
].needbusy
= 1;
4088 case OR2_CAUSE_NETWORK_CONGESTION
:
4089 case OR2_CAUSE_OUT_OF_ORDER
:
4090 case OR2_CAUSE_UNALLOCATED_NUMBER
:
4091 case OR2_CAUSE_NO_ANSWER
:
4092 case OR2_CAUSE_UNSPECIFIED
:
4093 case OR2_CAUSE_NORMAL_CLEARING
:
4094 p
->subs
[SUB_REAL
].needcongestion
= 1;
4097 ast_channel_softhangup_internal_flag_add(p
->owner
, AST_SOFTHANGUP_DEV
);
4099 ast_mutex_unlock(&p
->lock
);
4101 ast_mutex_unlock(&p
->lock
);
4102 /* being the backward side and not UP yet, we only need to request hangup */
4103 /* TODO: what about doing this same thing when were AST_STATE_UP? */
4104 ast_queue_hangup_with_cause(p
->owner
, dahdi_r2_cause_to_ast_cause(cause
));
4108 static void dahdi_r2_write_log(openr2_log_level_t level
, char *logmessage
)
4111 case OR2_LOG_NOTICE
:
4112 ast_verbose("%s", logmessage
);
4114 case OR2_LOG_WARNING
:
4115 ast_log(LOG_WARNING
, "%s", logmessage
);
4118 ast_log(LOG_ERROR
, "%s", logmessage
);
4120 case OR2_LOG_STACK_TRACE
:
4121 case OR2_LOG_MF_TRACE
:
4122 case OR2_LOG_CAS_TRACE
:
4124 case OR2_LOG_EX_DEBUG
:
4125 ast_debug(1, "%s", logmessage
);
4128 ast_log(LOG_WARNING
, "We should handle logging level %d here.\n", level
);
4129 ast_debug(1, "%s", logmessage
);
4134 static void dahdi_r2_on_line_blocked(openr2_chan_t
*r2chan
)
4136 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
4137 ast_mutex_lock(&p
->lock
);
4138 p
->remotelyblocked
= 1;
4139 ast_mutex_unlock(&p
->lock
);
4140 ast_log(LOG_NOTICE
, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan
));
4143 static void dahdi_r2_on_line_idle(openr2_chan_t
*r2chan
)
4145 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
4146 ast_mutex_lock(&p
->lock
);
4147 p
->remotelyblocked
= 0;
4148 ast_mutex_unlock(&p
->lock
);
4149 ast_log(LOG_NOTICE
, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan
));
4152 static void dahdi_r2_on_context_log(openr2_context_t
*r2context
, openr2_log_level_t level
, const char *fmt
, va_list ap
)
4153 __attribute__((format (printf
, 3, 0)));
4154 static void dahdi_r2_on_context_log(openr2_context_t
*r2context
, openr2_log_level_t level
, const char *fmt
, va_list ap
)
4156 #define CONTEXT_TAG "Context - "
4158 char completemsg
[sizeof(logmsg
) * 2];
4159 vsnprintf(logmsg
, sizeof(logmsg
), fmt
, ap
);
4160 snprintf(completemsg
, sizeof(completemsg
), CONTEXT_TAG
"%s", logmsg
);
4161 dahdi_r2_write_log(level
, completemsg
);
4165 static void dahdi_r2_on_chan_log(openr2_chan_t
*r2chan
, openr2_log_level_t level
, const char *fmt
, va_list ap
)
4166 __attribute__((format (printf
, 3, 0)));
4167 static void dahdi_r2_on_chan_log(openr2_chan_t
*r2chan
, openr2_log_level_t level
, const char *fmt
, va_list ap
)
4169 #define CHAN_TAG "Chan "
4171 char completemsg
[sizeof(logmsg
) * 2];
4172 vsnprintf(logmsg
, sizeof(logmsg
), fmt
, ap
);
4173 snprintf(completemsg
, sizeof(completemsg
), CHAN_TAG
"%d - %s", openr2_chan_get_number(r2chan
), logmsg
);
4174 dahdi_r2_write_log(level
, completemsg
);
4178 static int dahdi_r2_on_dnis_digit_received(openr2_chan_t
*r2chan
, char digit
)
4180 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
4181 /* if 'immediate' is set, let's stop requesting DNIS */
4185 p
->exten
[p
->mfcr2_dnis_index
] = digit
;
4186 p
->rdnis
[p
->mfcr2_dnis_index
] = digit
;
4187 p
->mfcr2_dnis_index
++;
4188 p
->exten
[p
->mfcr2_dnis_index
] = 0;
4189 p
->rdnis
[p
->mfcr2_dnis_index
] = 0;
4190 /* if the DNIS is a match and cannot match more, stop requesting DNIS */
4191 if ((p
->mfcr2_dnis_matched
||
4192 (ast_exists_extension(NULL
, p
->context
, p
->exten
, 1, p
->cid_num
) && (p
->mfcr2_dnis_matched
= 1))) &&
4193 !ast_matchmore_extension(NULL
, p
->context
, p
->exten
, 1, p
->cid_num
)) {
4196 /* otherwise keep going */
4200 static void dahdi_r2_on_ani_digit_received(openr2_chan_t
*r2chan
, char digit
)
4202 struct dahdi_pvt
*p
= openr2_chan_get_client_data(r2chan
);
4203 p
->cid_num
[p
->mfcr2_ani_index
] = digit
;
4204 p
->cid_name
[p
->mfcr2_ani_index
] = digit
;
4205 p
->mfcr2_ani_index
++;
4206 p
->cid_num
[p
->mfcr2_ani_index
] = 0;
4207 p
->cid_name
[p
->mfcr2_ani_index
] = 0;
4210 static void dahdi_r2_on_billing_pulse_received(openr2_chan_t
*r2chan
)
4212 ast_verbose("MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan
));
4215 static openr2_event_interface_t dahdi_r2_event_iface
= {
4216 .on_call_init
= dahdi_r2_on_call_init
,
4217 .on_call_offered
= dahdi_r2_on_call_offered
,
4218 .on_call_accepted
= dahdi_r2_on_call_accepted
,
4219 .on_call_answered
= dahdi_r2_on_call_answered
,
4220 .on_call_disconnect
= dahdi_r2_on_call_disconnect
,
4221 .on_call_end
= dahdi_r2_on_call_end
,
4222 .on_call_read
= dahdi_r2_on_call_read
,
4223 .on_hardware_alarm
= dahdi_r2_on_hardware_alarm
,
4224 .on_os_error
= dahdi_r2_on_os_error
,
4225 .on_protocol_error
= dahdi_r2_on_protocol_error
,
4226 .on_line_blocked
= dahdi_r2_on_line_blocked
,
4227 .on_line_idle
= dahdi_r2_on_line_idle
,
4228 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
4229 .on_context_log
= (openr2_handle_context_logging_func
)dahdi_r2_on_context_log
,
4230 .on_dnis_digit_received
= dahdi_r2_on_dnis_digit_received
,
4231 .on_ani_digit_received
= dahdi_r2_on_ani_digit_received
,
4232 /* so far we do nothing with billing pulses */
4233 .on_billing_pulse_received
= dahdi_r2_on_billing_pulse_received
4236 static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample
)
4238 return AST_ALAW(sample
);
4241 static inline uint8_t dahdi_r2_linear_to_alaw(int sample
)
4243 return AST_LIN2A(sample
);
4246 static openr2_transcoder_interface_t dahdi_r2_transcode_iface
= {
4247 dahdi_r2_alaw_to_linear
,
4248 dahdi_r2_linear_to_alaw
4251 #endif /* HAVE_OPENR2 */
4253 static void swap_subs(struct dahdi_pvt
*p
, int a
, int b
)
4257 struct ast_channel
*towner
;
4259 ast_debug(1, "Swapping %d and %d\n", a
, b
);
4261 tchan
= p
->subs
[a
].chan
;
4262 towner
= p
->subs
[a
].owner
;
4263 tinthreeway
= p
->subs
[a
].inthreeway
;
4265 p
->subs
[a
].chan
= p
->subs
[b
].chan
;
4266 p
->subs
[a
].owner
= p
->subs
[b
].owner
;
4267 p
->subs
[a
].inthreeway
= p
->subs
[b
].inthreeway
;
4269 p
->subs
[b
].chan
= tchan
;
4270 p
->subs
[b
].owner
= towner
;
4271 p
->subs
[b
].inthreeway
= tinthreeway
;
4273 if (p
->subs
[a
].owner
)
4274 ast_channel_set_fd(p
->subs
[a
].owner
, 0, p
->subs
[a
].dfd
);
4275 if (p
->subs
[b
].owner
)
4276 ast_channel_set_fd(p
->subs
[b
].owner
, 0, p
->subs
[b
].dfd
);
4281 static int dahdi_open(char *fn
)
4289 for (x
= 0; x
< strlen(fn
); x
++) {
4290 if (!isdigit(fn
[x
])) {
4298 ast_log(LOG_WARNING
, "Invalid channel number '%s'\n", fn
);
4301 fn
= "/dev/dahdi/channel";
4303 fd
= open(fn
, O_RDWR
| O_NONBLOCK
);
4305 ast_log(LOG_WARNING
, "Unable to open '%s': %s\n", fn
, strerror(errno
));
4309 if (ioctl(fd
, DAHDI_SPECIFY
, &chan
)) {
4313 ast_log(LOG_WARNING
, "Unable to specify channel %d: %s\n", chan
, strerror(errno
));
4318 if (ioctl(fd
, DAHDI_SET_BLOCKSIZE
, &bs
) == -1) {
4319 ast_log(LOG_WARNING
, "Unable to set blocksize '%d': %s\n", bs
, strerror(errno
));
4328 static void dahdi_close(int fd
)
4334 static void dahdi_close_sub(struct dahdi_pvt
*chan_pvt
, int sub_num
)
4336 dahdi_close(chan_pvt
->subs
[sub_num
].dfd
);
4337 chan_pvt
->subs
[sub_num
].dfd
= -1;
4340 #if defined(HAVE_PRI)
4341 static void dahdi_close_pri_fd(struct dahdi_pri
*pri
, int fd_num
)
4343 dahdi_close(pri
->pri
.fds
[fd_num
]);
4344 pri
->pri
.fds
[fd_num
] = -1;
4346 #endif /* defined(HAVE_PRI) */
4348 #if defined(HAVE_SS7)
4349 static void dahdi_close_ss7_fd(struct dahdi_ss7
*ss7
, int fd_num
)
4351 dahdi_close(ss7
->ss7
.fds
[fd_num
]);
4352 ss7
->ss7
.fds
[fd_num
] = -1;
4354 #endif /* defined(HAVE_SS7) */
4356 static int dahdi_setlinear(int dfd
, int linear
)
4358 return ioctl(dfd
, DAHDI_SETLINEAR
, &linear
);
4362 static int alloc_sub(struct dahdi_pvt
*p
, int x
)
4364 struct dahdi_bufferinfo bi
;
4366 if (p
->subs
[x
].dfd
>= 0) {
4367 ast_log(LOG_WARNING
, "%s subchannel of %d already in use\n", subnames
[x
], p
->channel
);
4371 p
->subs
[x
].dfd
= dahdi_open("/dev/dahdi/pseudo");
4372 if (p
->subs
[x
].dfd
<= -1) {
4373 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
4377 res
= ioctl(p
->subs
[x
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
4379 bi
.txbufpolicy
= p
->buf_policy
;
4380 bi
.rxbufpolicy
= p
->buf_policy
;
4381 bi
.numbufs
= p
->buf_no
;
4382 res
= ioctl(p
->subs
[x
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
4384 ast_log(LOG_WARNING
, "Unable to set buffer policy on channel %d: %s\n", x
, strerror(errno
));
4387 ast_log(LOG_WARNING
, "Unable to check buffer policy on channel %d: %s\n", x
, strerror(errno
));
4389 if (ioctl(p
->subs
[x
].dfd
, DAHDI_CHANNO
, &p
->subs
[x
].chan
) == 1) {
4390 ast_log(LOG_WARNING
, "Unable to get channel number for pseudo channel on FD %d: %s\n", p
->subs
[x
].dfd
, strerror(errno
));
4391 dahdi_close_sub(p
, x
);
4392 p
->subs
[x
].dfd
= -1;
4395 ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames
[x
], p
->subs
[x
].dfd
, p
->subs
[x
].chan
);
4399 static int unalloc_sub(struct dahdi_pvt
*p
, int x
)
4402 ast_log(LOG_WARNING
, "Trying to unalloc the real channel %d?!?\n", p
->channel
);
4405 ast_debug(1, "Released sub %d of channel %d\n", x
, p
->channel
);
4406 dahdi_close_sub(p
, x
);
4407 p
->subs
[x
].linear
= 0;
4408 p
->subs
[x
].chan
= 0;
4409 p
->subs
[x
].owner
= NULL
;
4410 p
->subs
[x
].inthreeway
= 0;
4411 p
->polarity
= POLARITY_IDLE
;
4412 memset(&p
->subs
[x
].curconf
, 0, sizeof(p
->subs
[x
].curconf
));
4416 static int digit_to_dtmfindex(char digit
)
4419 return DAHDI_TONE_DTMF_BASE
+ (digit
- '0');
4420 else if (digit
>= 'A' && digit
<= 'D')
4421 return DAHDI_TONE_DTMF_A
+ (digit
- 'A');
4422 else if (digit
>= 'a' && digit
<= 'd')
4423 return DAHDI_TONE_DTMF_A
+ (digit
- 'a');
4424 else if (digit
== '*')
4425 return DAHDI_TONE_DTMF_s
;
4426 else if (digit
== '#')
4427 return DAHDI_TONE_DTMF_p
;
4432 static int dahdi_digit_begin(struct ast_channel
*chan
, char digit
)
4434 struct dahdi_pvt
*pvt
;
4439 pvt
= ast_channel_tech_pvt(chan
);
4441 ast_mutex_lock(&pvt
->lock
);
4443 idx
= dahdi_get_index(chan
, pvt
, 0);
4445 if ((idx
!= SUB_REAL
) || !pvt
->owner
)
4450 case SIG_PRI_LIB_HANDLE_CASES
:
4451 res
= sig_pri_digit_begin(pvt
->sig_pvt
, chan
, digit
);
4459 dtmf
= digit_to_dtmfindex(digit
);
4461 /* Not a valid DTMF digit */
4465 if (pvt
->pulse
|| ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_SENDTONE
, &dtmf
)) {
4466 char dial_str
[] = { 'T', digit
, '\0' };
4468 res
= dahdi_dial_str(pvt
, DAHDI_DIAL_OP_APPEND
, dial_str
);
4474 pvt
->begindigit
= digit
;
4476 /* Flush the write buffer in DAHDI to start sending the digit immediately. */
4477 dtmf
= DAHDI_FLUSH_WRITE
;
4478 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_FLUSH
, &dtmf
);
4480 ast_log(LOG_WARNING
, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
4481 pvt
->channel
, strerror(errno
));
4484 ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
4485 ast_channel_name(chan
), digit
);
4489 ast_mutex_unlock(&pvt
->lock
);
4494 static int dahdi_digit_end(struct ast_channel
*chan
, char digit
, unsigned int duration
)
4496 struct dahdi_pvt
*pvt
;
4501 pvt
= ast_channel_tech_pvt(chan
);
4503 ast_mutex_lock(&pvt
->lock
);
4505 idx
= dahdi_get_index(chan
, pvt
, 0);
4507 if ((idx
!= SUB_REAL
) || !pvt
->owner
|| pvt
->pulse
)
4511 /* This means that the digit was already sent via PRI signalling */
4512 if (dahdi_sig_pri_lib_handles(pvt
->sig
) && !pvt
->begindigit
) {
4517 if (pvt
->begindigit
) {
4519 ast_debug(1, "Channel %s ending VLDTMF digit '%c'\n",
4520 ast_channel_name(chan
), digit
);
4521 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_SENDTONE
, &x
);
4523 pvt
->begindigit
= 0;
4527 ast_mutex_unlock(&pvt
->lock
);
4532 static const char * const events
[] = {
4545 "Hook Transition Complete",
4550 "Polarity Reversal",
4558 { DAHDI_ALARM_RED
, "Red Alarm" },
4559 { DAHDI_ALARM_YELLOW
, "Yellow Alarm" },
4560 { DAHDI_ALARM_BLUE
, "Blue Alarm" },
4561 { DAHDI_ALARM_RECOVER
, "Recovering" },
4562 { DAHDI_ALARM_LOOPBACK
, "Loopback" },
4563 { DAHDI_ALARM_NOTOPEN
, "Not Open" },
4564 { DAHDI_ALARM_NONE
, "None" },
4567 static char *alarm2str(int alm
)
4570 for (x
= 0; x
< ARRAY_LEN(alarms
); x
++) {
4571 if (alarms
[x
].alarm
& alm
)
4572 return alarms
[x
].name
;
4574 return alm
? "Unknown Alarm" : "No Alarm";
4577 static const char *event2str(int event
)
4579 static char buf
[256];
4580 if ((event
> -1) && (event
< (ARRAY_LEN(events
))) )
4581 return events
[event
];
4582 sprintf(buf
, "Event %d", event
); /* safe */
4586 static char *dahdi_sig2str(int sig
)
4588 static char buf
[256];
4591 return "E & M Immediate";
4593 return "E & M Wink";
4597 return "Feature Group D (DTMF)";
4599 return "Feature Group D (MF)";
4600 case SIG_FEATDMF_TA
:
4601 return "Feature Group D (MF) Tandem Access";
4603 return "Feature Group B (MF)";
4607 return "FGC/CAMA (Dialpulse)";
4608 case SIG_FGC_CAMAMF
:
4609 return "FGC/CAMA (MF)";
4611 return "FXS Loopstart";
4613 return "FXS Groundstart";
4615 return "FXS Kewlstart";
4617 return "FXO Loopstart";
4619 return "FXO Groundstart";
4621 return "FXO Kewlstart";
4625 return "ISDN BRI Point to Point";
4627 return "ISDN BRI Point to MultiPoint";
4633 return "SF (Tone) Immediate";
4635 return "SF (Tone) Wink";
4637 return "SF (Tone) with Feature Group D (DTMF)";
4638 case SIG_SF_FEATDMF
:
4639 return "SF (Tone) with Feature Group D (MF)";
4641 return "SF (Tone) with Feature Group B (MF)";
4645 snprintf(buf
, sizeof(buf
), "Unknown signalling %d", sig
);
4650 #define sig2str dahdi_sig2str
4652 static int conf_add(struct dahdi_pvt
*p
, struct dahdi_subchannel
*c
, int idx
, int slavechannel
)
4654 /* If the conference already exists, and we're already in it
4655 don't bother doing anything */
4656 struct dahdi_confinfo zi
;
4658 memset(&zi
, 0, sizeof(zi
));
4661 if (slavechannel
> 0) {
4662 /* If we have only one slave, do a digital mon */
4663 zi
.confmode
= DAHDI_CONF_DIGITALMON
;
4664 zi
.confno
= slavechannel
;
4667 /* Real-side and pseudo-side both participate in conference */
4668 zi
.confmode
= DAHDI_CONF_REALANDPSEUDO
| DAHDI_CONF_TALKER
| DAHDI_CONF_LISTENER
|
4669 DAHDI_CONF_PSEUDO_TALKER
| DAHDI_CONF_PSEUDO_LISTENER
;
4671 zi
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
| DAHDI_CONF_LISTENER
;
4672 zi
.confno
= p
->confno
;
4674 if ((zi
.confno
== c
->curconf
.confno
) && (zi
.confmode
== c
->curconf
.confmode
))
4678 if (ioctl(c
->dfd
, DAHDI_SETCONF
, &zi
)) {
4679 ast_log(LOG_WARNING
, "Failed to add %d to conference %d/%d: %s\n", c
->dfd
, zi
.confmode
, zi
.confno
, strerror(errno
));
4682 if (slavechannel
< 1) {
4683 p
->confno
= zi
.confno
;
4686 ast_debug(1, "Added %d to conference %d/%d\n", c
->dfd
, c
->curconf
.confmode
, c
->curconf
.confno
);
4690 static int isourconf(struct dahdi_pvt
*p
, struct dahdi_subchannel
*c
)
4692 /* If they're listening to our channel, they're ours */
4693 if ((p
->channel
== c
->curconf
.confno
) && (c
->curconf
.confmode
== DAHDI_CONF_DIGITALMON
))
4695 /* If they're a talker on our (allocated) conference, they're ours */
4696 if ((p
->confno
> 0) && (p
->confno
== c
->curconf
.confno
) && (c
->curconf
.confmode
& DAHDI_CONF_TALKER
))
4701 static int conf_del(struct dahdi_pvt
*p
, struct dahdi_subchannel
*c
, int idx
)
4703 struct dahdi_confinfo zi
;
4704 if (/* Can't delete if there's no dfd */
4706 /* Don't delete from the conference if it's not our conference */
4708 /* Don't delete if we don't think it's conferenced at all (implied) */
4710 memset(&zi
, 0, sizeof(zi
));
4711 if (ioctl(c
->dfd
, DAHDI_SETCONF
, &zi
)) {
4712 ast_log(LOG_WARNING
, "Failed to drop %d from conference %d/%d: %s\n", c
->dfd
, c
->curconf
.confmode
, c
->curconf
.confno
, strerror(errno
));
4715 ast_debug(1, "Removed %d from conference %d/%d\n", c
->dfd
, c
->curconf
.confmode
, c
->curconf
.confno
);
4716 memcpy(&c
->curconf
, &zi
, sizeof(c
->curconf
));
4720 static int isslavenative(struct dahdi_pvt
*p
, struct dahdi_pvt
**out
)
4724 struct dahdi_pvt
*slave
= NULL
;
4725 /* Start out optimistic */
4727 /* Update conference state in a stateless fashion */
4728 for (x
= 0; x
< 3; x
++) {
4729 /* Any three-way calling makes slave native mode *definitely* out
4731 if ((p
->subs
[x
].dfd
> -1) && p
->subs
[x
].inthreeway
)
4734 /* If we don't have any 3-way calls, check to see if we have
4735 precisely one slave */
4736 if (useslavenative
) {
4737 for (x
= 0; x
< MAX_SLAVES
; x
++) {
4740 /* Whoops already have a slave! No
4741 slave native and stop right away */
4746 /* We have one slave so far */
4747 slave
= p
->slaves
[x
];
4752 /* If no slave, slave native definitely out */
4755 else if (slave
->law
!= p
->law
) {
4761 return useslavenative
;
4764 static int reset_conf(struct dahdi_pvt
*p
)
4767 memset(&p
->subs
[SUB_REAL
].curconf
, 0, sizeof(p
->subs
[SUB_REAL
].curconf
));
4768 if (p
->subs
[SUB_REAL
].dfd
> -1) {
4769 struct dahdi_confinfo zi
;
4771 memset(&zi
, 0, sizeof(zi
));
4772 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETCONF
, &zi
))
4773 ast_log(LOG_WARNING
, "Failed to reset conferencing on channel %d: %s\n", p
->channel
, strerror(errno
));
4778 void dahdi_conf_update(struct dahdi_pvt
*p
)
4783 struct dahdi_pvt
*slave
= NULL
;
4785 useslavenative
= isslavenative(p
, &slave
);
4786 /* Start with the obvious, general stuff */
4787 for (x
= 0; x
< 3; x
++) {
4788 /* Look for three way calls */
4789 if ((p
->subs
[x
].dfd
> -1) && p
->subs
[x
].inthreeway
) {
4790 conf_add(p
, &p
->subs
[x
], x
, 0);
4793 conf_del(p
, &p
->subs
[x
], x
);
4796 /* If we have a slave, add him to our conference now. or DAX
4797 if this is slave native */
4798 for (x
= 0; x
< MAX_SLAVES
; x
++) {
4801 conf_add(p
, &p
->slaves
[x
]->subs
[SUB_REAL
], SUB_REAL
, GET_CHANNEL(p
));
4803 conf_add(p
, &p
->slaves
[x
]->subs
[SUB_REAL
], SUB_REAL
, 0);
4808 /* If we're supposed to be in there, do so now */
4809 if (p
->inconference
&& !p
->subs
[SUB_REAL
].inthreeway
) {
4811 conf_add(p
, &p
->subs
[SUB_REAL
], SUB_REAL
, GET_CHANNEL(slave
));
4813 conf_add(p
, &p
->subs
[SUB_REAL
], SUB_REAL
, 0);
4817 /* If we have a master, add ourselves to his conference */
4819 if (isslavenative(p
->master
, NULL
)) {
4820 conf_add(p
->master
, &p
->subs
[SUB_REAL
], SUB_REAL
, GET_CHANNEL(p
->master
));
4822 conf_add(p
->master
, &p
->subs
[SUB_REAL
], SUB_REAL
, 0);
4826 /* Nobody is left (or should be left) in our conference.
4830 ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p
->channel
, needconf
);
4833 void dahdi_ec_enable(struct dahdi_pvt
*p
)
4839 ast_debug(1, "Echo cancellation already on\n");
4843 ast_debug(1, "Echo cancellation isn't required on digital connection\n");
4846 if (p
->echocancel
.head
.tap_length
) {
4847 #if defined(HAVE_PRI) || defined(HAVE_SS7)
4849 #if defined(HAVE_PRI)
4850 case SIG_PRI_LIB_HANDLE_CASES
:
4851 if (((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
) {
4853 * PRI nobch pseudo channel. Does not need ec anyway.
4854 * Does not handle ioctl(DAHDI_AUDIOMODE)
4859 #endif /* defined(HAVE_PRI) */
4860 #if defined(HAVE_SS7)
4862 #endif /* defined(HAVE_SS7) */
4866 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &x
);
4868 ast_log(LOG_WARNING
,
4869 "Unable to enable audio mode on channel %d (%s)\n",
4870 p
->channel
, strerror(errno
));
4876 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
4877 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOCANCEL_PARAMS
, &p
->echocancel
);
4879 ast_log(LOG_WARNING
, "Unable to enable echo cancellation on channel %d (%s)\n", p
->channel
, strerror(errno
));
4882 ast_debug(1, "Enabled echo cancellation on channel %d\n", p
->channel
);
4885 ast_debug(1, "No echo cancellation requested\n");
4888 static void dahdi_train_ec(struct dahdi_pvt
*p
)
4893 if (p
&& p
->echocanon
&& p
->echotraining
) {
4894 x
= p
->echotraining
;
4895 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOTRAIN
, &x
);
4897 ast_log(LOG_WARNING
, "Unable to request echo training on channel %d: %s\n", p
->channel
, strerror(errno
));
4899 ast_debug(1, "Engaged echo training on channel %d\n", p
->channel
);
4901 ast_debug(1, "No echo training requested\n");
4905 void dahdi_ec_disable(struct dahdi_pvt
*p
)
4910 struct dahdi_echocanparams ecp
= { .tap_length
= 0 };
4912 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOCANCEL_PARAMS
, &ecp
);
4915 ast_log(LOG_WARNING
, "Unable to disable echo cancellation on channel %d: %s\n", p
->channel
, strerror(errno
));
4917 ast_debug(1, "Disabled echo cancellation on channel %d\n", p
->channel
);
4923 static int set_hwgain(int fd
, float gain
, int tx_direction
)
4925 struct dahdi_hwgain hwgain
;
4927 hwgain
.newgain
= gain
* 10.0;
4928 hwgain
.tx
= tx_direction
;
4929 return ioctl(fd
, DAHDI_SET_HWGAIN
, &hwgain
) < 0;
4932 /* perform a dynamic range compression transform on the given sample */
4933 static int drc_sample(int sample
, float drc
)
4936 float shallow
, steep
;
4937 float max
= SHRT_MAX
;
4939 neg
= (sample
< 0 ? -1 : 1);
4941 shallow
= neg
*(max
-max
/drc
)+(float)sample
/drc
;
4942 if (fabsf(steep
) < fabsf(shallow
)) {
4953 static void fill_txgain(struct dahdi_gains
*g
, float gain
, float drc
, int law
)
4958 float linear_gain
= pow(10.0, gain
/ 20.0);
4961 case DAHDI_LAW_ALAW
:
4962 for (j
= 0; j
< ARRAY_LEN(g
->txgain
); j
++) {
4966 k
= drc_sample(k
, drc
);
4968 k
= (float)k
* linear_gain
;
4971 } else if (k
< -32768) {
4974 g
->txgain
[j
] = AST_LIN2A(k
);
4980 case DAHDI_LAW_MULAW
:
4981 for (j
= 0; j
< ARRAY_LEN(g
->txgain
); j
++) {
4985 k
= drc_sample(k
, drc
);
4987 k
= (float)k
* linear_gain
;
4990 } else if (k
< -32768) {
4993 g
->txgain
[j
] = AST_LIN2MU(k
);
5003 static void fill_rxgain(struct dahdi_gains
*g
, float gain
, float drc
, int law
)
5007 float linear_gain
= pow(10.0, gain
/ 20.0);
5010 case DAHDI_LAW_ALAW
:
5011 for (j
= 0; j
< ARRAY_LEN(g
->rxgain
); j
++) {
5015 k
= drc_sample(k
, drc
);
5017 k
= (float)k
* linear_gain
;
5020 } else if (k
< -32768) {
5023 g
->rxgain
[j
] = AST_LIN2A(k
);
5029 case DAHDI_LAW_MULAW
:
5030 for (j
= 0; j
< ARRAY_LEN(g
->rxgain
); j
++) {
5034 k
= drc_sample(k
, drc
);
5036 k
= (float)k
* linear_gain
;
5039 } else if (k
< -32768) {
5042 g
->rxgain
[j
] = AST_LIN2MU(k
);
5051 static int set_actual_txgain(int fd
, float gain
, float drc
, int law
)
5053 struct dahdi_gains g
;
5056 memset(&g
, 0, sizeof(g
));
5057 res
= ioctl(fd
, DAHDI_GETGAINS
, &g
);
5059 ast_debug(1, "Failed to read gains: %s\n", strerror(errno
));
5063 fill_txgain(&g
, gain
, drc
, law
);
5065 return ioctl(fd
, DAHDI_SETGAINS
, &g
);
5068 static int set_actual_rxgain(int fd
, float gain
, float drc
, int law
)
5070 struct dahdi_gains g
;
5073 memset(&g
, 0, sizeof(g
));
5074 res
= ioctl(fd
, DAHDI_GETGAINS
, &g
);
5076 ast_debug(1, "Failed to read gains: %s\n", strerror(errno
));
5080 fill_rxgain(&g
, gain
, drc
, law
);
5082 return ioctl(fd
, DAHDI_SETGAINS
, &g
);
5085 static int set_actual_gain(int fd
, float rxgain
, float txgain
, float rxdrc
, float txdrc
, int law
)
5087 return set_actual_txgain(fd
, txgain
, txdrc
, law
) | set_actual_rxgain(fd
, rxgain
, rxdrc
, law
);
5090 static int bump_gains(struct dahdi_pvt
*p
)
5094 /* Bump receive gain by value stored in cid_rxgain */
5095 res
= set_actual_gain(p
->subs
[SUB_REAL
].dfd
, p
->rxgain
+ p
->cid_rxgain
, p
->txgain
, p
->rxdrc
, p
->txdrc
, p
->law
);
5097 ast_log(LOG_WARNING
, "Unable to bump gain: %s\n", strerror(errno
));
5104 static int restore_gains(struct dahdi_pvt
*p
)
5108 res
= set_actual_gain(p
->subs
[SUB_REAL
].dfd
, p
->rxgain
, p
->txgain
, p
->rxdrc
, p
->txdrc
, p
->law
);
5110 ast_log(LOG_WARNING
, "Unable to restore gains: %s\n", strerror(errno
));
5117 static inline int dahdi_set_hook(int fd
, int hs
)
5122 res
= ioctl(fd
, DAHDI_HOOK
, &x
);
5125 if (errno
== EINPROGRESS
)
5127 ast_log(LOG_WARNING
, "DAHDI hook failed returned %d (trying %d): %s\n", res
, hs
, strerror(errno
));
5128 /* will expectedly fail if phone is off hook during operation, such as during a restart */
5134 static inline int dahdi_confmute(struct dahdi_pvt
*p
, int muted
)
5139 #if defined(HAVE_PRI) || defined(HAVE_SS7)
5141 #if defined(HAVE_PRI)
5142 case SIG_PRI_LIB_HANDLE_CASES
:
5143 if (((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
) {
5144 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
5148 #endif /* defined(HAVE_PRI) */
5149 #if defined(HAVE_SS7)
5151 #endif /* defined(HAVE_SS7) */
5155 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &y
);
5157 ast_log(LOG_WARNING
, "Unable to set audio mode on %d: %s\n",
5158 p
->channel
, strerror(errno
));
5164 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5165 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_CONFMUTE
, &x
);
5167 ast_log(LOG_WARNING
, "DAHDI confmute(%d) failed on channel %d: %s\n", muted
, p
->channel
, strerror(errno
));
5171 static int save_conference(struct dahdi_pvt
*p
)
5173 struct dahdi_confinfo c
;
5175 if (p
->saveconf
.confmode
) {
5176 ast_log(LOG_WARNING
, "Can't save conference -- already in use\n");
5179 p
->saveconf
.chan
= 0;
5180 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONF
, &p
->saveconf
);
5182 ast_log(LOG_WARNING
, "Unable to get conference info: %s\n", strerror(errno
));
5183 p
->saveconf
.confmode
= 0;
5186 memset(&c
, 0, sizeof(c
));
5187 c
.confmode
= DAHDI_CONF_NORMAL
;
5188 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETCONF
, &c
);
5190 ast_log(LOG_WARNING
, "Unable to set conference info: %s\n", strerror(errno
));
5193 ast_debug(1, "Disabled conferencing\n");
5197 static int restore_conference(struct dahdi_pvt
*p
)
5200 if (p
->saveconf
.confmode
) {
5201 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETCONF
, &p
->saveconf
);
5202 p
->saveconf
.confmode
= 0;
5204 ast_log(LOG_WARNING
, "Unable to restore conference info: %s\n", strerror(errno
));
5207 ast_debug(1, "Restored conferencing\n");
5212 static int send_cwcidspill(struct dahdi_pvt
*p
)
5216 p
->cid_suppress_expire
= 0;
5217 if (!(p
->cidspill
= ast_malloc(MAX_CALLERID_SIZE
)))
5219 p
->cidlen
= ast_callerid_callwaiting_generate(p
->cidspill
, p
->callwait_name
, p
->callwait_num
, AST_LAW(p
));
5220 /* Make sure we account for the end */
5221 p
->cidlen
+= READ_SIZE
* 4;
5224 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p
->callwait_name
, p
->callwait_num
);
5228 static int has_voicemail(struct dahdi_pvt
*p
)
5231 RAII_VAR(struct stasis_message
*, mwi_message
, NULL
, ao2_cleanup
);
5233 /* A manual MWI disposition has been requested, use that instead
5234 * if this is for sending the new MWI indication. */
5235 if (p
->mwioverride_active
) {
5236 /* We don't clear p->mwioverride_active automatically,
5237 * because otherwise do_monitor would just change it back to the way it was.
5238 * We need to keep the override active until explicitly disabled by the user,
5239 * so that we can keep returning the correct answer in subsequent calls to do_monitor. */
5240 ast_debug(6, "MWI manual override active on channel %d: pretending that it should be %s\n",
5241 p
->channel
, p
->mwioverride_disposition
? "active" : "inactive");
5242 return p
->mwioverride_disposition
;
5245 mwi_message
= stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p
->mailbox
);
5247 struct ast_mwi_state
*mwi_state
= stasis_message_data(mwi_message
);
5248 new_msgs
= mwi_state
->new_msgs
;
5250 new_msgs
= ast_app_has_voicemail(p
->mailbox
, NULL
);
5258 static int send_callerid(struct dahdi_pvt
*p
)
5260 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
5262 /* Take out of linear mode if necessary */
5263 if (p
->subs
[SUB_REAL
].linear
) {
5264 p
->subs
[SUB_REAL
].linear
= 0;
5265 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
5267 while (p
->cidpos
< p
->cidlen
) {
5268 res
= write(p
->subs
[SUB_REAL
].dfd
, p
->cidspill
+ p
->cidpos
, p
->cidlen
- p
->cidpos
);
5269 ast_debug(4, "writing callerid at pos %d of %d, res = %d\n", p
->cidpos
, p
->cidlen
, res
);
5271 if (errno
== EAGAIN
)
5274 ast_log(LOG_WARNING
, "write failed: %s\n", strerror(errno
));
5282 p
->cid_suppress_expire
= CALLWAITING_SUPPRESS_SAMPLES
;
5283 ast_free(p
->cidspill
);
5285 if (p
->callwaitcas
) {
5286 /* Wait for CID/CW to expire */
5287 p
->cidcwexpire
= CIDCW_EXPIRE_SAMPLES
;
5288 p
->cid_suppress_expire
= p
->cidcwexpire
;
5290 restore_conference(p
);
5294 static int dahdi_callwait(struct ast_channel
*ast
)
5296 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
5298 p
->callwaitingrepeat
= CALLWAITING_REPEAT_SAMPLES
;
5300 ast_log(LOG_WARNING
, "Spill already exists?!?\n");
5301 ast_free(p
->cidspill
);
5305 * SAS: Subscriber Alert Signal, 440Hz for 300ms
5306 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
5308 if (!(p
->cidspill
= ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE
* 4)))
5312 memset(p
->cidspill
, 0x7f, 2400 + 600 + READ_SIZE
* 4);
5313 if (!p
->callwaitrings
&& p
->callwaitingcallerid
) {
5314 ast_gen_cas(p
->cidspill
, 1, 2400 + 680, AST_LAW(p
));
5316 p
->cidlen
= 2400 + 680 + READ_SIZE
* 4;
5318 ast_gen_cas(p
->cidspill
, 1, 2400, AST_LAW(p
));
5320 p
->cidlen
= 2400 + READ_SIZE
* 4;
5328 static int dahdi_call(struct ast_channel
*ast
, const char *rdest
, int timeout
)
5330 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
5333 AST_DECLARE_APP_ARGS(args
,
5334 AST_APP_ARG(group
); /* channel/group token */
5335 AST_APP_ARG(ext
); /* extension token */
5336 //AST_APP_ARG(opts); /* options token */
5337 AST_APP_ARG(other
); /* Any remining unused arguments */
5340 ast_mutex_lock(&p
->lock
);
5341 ast_copy_string(p
->dialdest
, rdest
, sizeof(p
->dialdest
));
5343 /* Split the dialstring */
5344 dest
= ast_strdupa(rdest
);
5345 AST_NONSTANDARD_APP_ARGS(args
, dest
, '/');
5350 #if defined(HAVE_PRI)
5351 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
5354 sig_pri_extract_called_num_subaddr(p
->sig_pvt
, rdest
, p
->exten
, sizeof(p
->exten
));
5356 /* Remove any subaddress for uniformity with incoming calls. */
5357 subaddr
= strchr(p
->exten
, ':');
5362 #endif /* defined(HAVE_PRI) */
5364 ast_copy_string(p
->exten
, args
.ext
, sizeof(p
->exten
));
5367 if ((ast_channel_state(ast
) == AST_STATE_BUSY
)) {
5368 p
->subs
[SUB_REAL
].needbusy
= 1;
5369 ast_mutex_unlock(&p
->lock
);
5372 if ((ast_channel_state(ast
) != AST_STATE_DOWN
) && (ast_channel_state(ast
) != AST_STATE_RESERVED
)) {
5373 ast_log(LOG_WARNING
, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast
));
5374 ast_mutex_unlock(&p
->lock
);
5377 p
->waitingfordt
.tv_sec
= 0;
5379 if ((p
->radio
|| (p
->oprmode
< 0))) /* if a radio channel, up immediately */
5381 /* Special pseudo -- automatically up */
5382 ast_setstate(ast
, AST_STATE_UP
);
5383 ast_mutex_unlock(&p
->lock
);
5386 x
= DAHDI_FLUSH_READ
| DAHDI_FLUSH_WRITE
;
5387 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_FLUSH
, &x
);
5389 ast_log(LOG_WARNING
, "Unable to flush input on channel %d: %s\n", p
->channel
, strerror(errno
));
5392 if (IS_DIGITAL(ast_channel_transfercapability(ast
))){
5393 set_actual_gain(p
->subs
[SUB_REAL
].dfd
, 0, 0, p
->rxdrc
, p
->txdrc
, p
->law
);
5395 set_actual_gain(p
->subs
[SUB_REAL
].dfd
, p
->rxgain
, p
->txgain
, p
->rxdrc
, p
->txdrc
, p
->law
);
5399 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
5400 res
= sig_pri_call(p
->sig_pvt
, ast
, rdest
, timeout
,
5401 (p
->law
== DAHDI_LAW_ALAW
) ? PRI_LAYER_1_ALAW
: PRI_LAYER_1_ULAW
);
5402 ast_mutex_unlock(&p
->lock
);
5407 #if defined(HAVE_SS7)
5408 if (p
->sig
== SIG_SS7
) {
5409 res
= sig_ss7_call(p
->sig_pvt
, ast
, rdest
);
5410 ast_mutex_unlock(&p
->lock
);
5413 #endif /* defined(HAVE_SS7) */
5415 /* If this is analog signalling we can exit here */
5416 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
5417 p
->callwaitrings
= 0;
5418 res
= analog_call(p
->sig_pvt
, ast
, rdest
, timeout
);
5419 ast_mutex_unlock(&p
->lock
);
5423 mysig
= p
->outsigmod
> -1 ? p
->outsigmod
: p
->sig
;
5426 /* Special pseudo -- automatically up*/
5427 ast_setstate(ast
, AST_STATE_UP
);
5432 ast_debug(1, "not yet implemented\n");
5433 ast_mutex_unlock(&p
->lock
);
5439 openr2_calling_party_category_t chancat
;
5443 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
5444 p
->dialdest
[0] = '\0';
5447 if (!p
->hidecallerid
) {
5448 l
= ast_channel_connected(ast
)->id
.number
.valid
? ast_channel_connected(ast
)->id
.number
.str
: NULL
;
5452 if (strlen(c
) < p
->stripmsd
) {
5453 ast_log(LOG_WARNING
, "Number '%s' is shorter than stripmsd (%d)\n", c
, p
->stripmsd
);
5454 ast_mutex_unlock(&p
->lock
);
5458 chancat
= dahdi_r2_get_channel_category(ast
);
5459 callres
= openr2_chan_make_call(p
->r2chan
, l
, (c
+ p
->stripmsd
), chancat
);
5460 if (-1 == callres
) {
5461 ast_mutex_unlock(&p
->lock
);
5462 ast_log(LOG_ERROR
, "unable to make new MFC/R2 call!\n");
5465 p
->mfcr2_call_accepted
= 0;
5466 p
->mfcr2_progress_sent
= 0;
5467 ast_setstate(ast
, AST_STATE_DIALING
);
5469 #endif /* HAVE_OPENR2 */
5470 ast_mutex_unlock(&p
->lock
);
5476 * \brief Insert the given chan_dahdi interface structure into the interface list.
5479 * \param pvt chan_dahdi private interface structure to insert.
5482 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5483 * Any duplicates are inserted after the existing entries.
5485 * \note The new interface must not already be in the list.
5487 static void dahdi_iflist_insert(struct dahdi_pvt
*pvt
)
5489 struct dahdi_pvt
*cur
;
5491 pvt
->which_iflist
= DAHDI_IFLIST_MAIN
;
5493 /* Find place in middle of list for the new interface. */
5494 for (cur
= iflist
; cur
; cur
= cur
->next
) {
5495 if (pvt
->channel
< cur
->channel
) {
5496 /* New interface goes before the current interface. */
5497 pvt
->prev
= cur
->prev
;
5500 /* Insert into the middle of the list. */
5501 cur
->prev
->next
= pvt
;
5503 /* Insert at head of list. */
5511 /* New interface goes onto the end of the list */
5519 /* List was empty */
5526 * \brief Extract the given chan_dahdi interface structure from the interface list.
5529 * \param pvt chan_dahdi private interface structure to extract.
5532 * The given interface structure can be either in the interface list or a stand alone
5533 * structure that has not been put in the list if the next and prev pointers are NULL.
5535 static void dahdi_iflist_extract(struct dahdi_pvt
*pvt
)
5537 /* Extract from the forward chain. */
5539 pvt
->prev
->next
= pvt
->next
;
5540 } else if (iflist
== pvt
) {
5541 /* Node is at the head of the list. */
5545 /* Extract from the reverse chain. */
5547 pvt
->next
->prev
= pvt
->prev
;
5548 } else if (ifend
== pvt
) {
5549 /* Node is at the end of the list. */
5553 /* Node is no longer in the list. */
5554 pvt
->which_iflist
= DAHDI_IFLIST_NONE
;
5559 #if defined(HAVE_PRI)
5562 * \brief Insert the given chan_dahdi interface structure into the no B channel list.
5565 * \param pri sig_pri span control structure holding no B channel list.
5566 * \param pvt chan_dahdi private interface structure to insert.
5569 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5570 * Any duplicates are inserted after the existing entries.
5572 * \note The new interface must not already be in the list.
5574 static void dahdi_nobch_insert(struct sig_pri_span
*pri
, struct dahdi_pvt
*pvt
)
5576 struct dahdi_pvt
*cur
;
5578 pvt
->which_iflist
= DAHDI_IFLIST_NO_B_CHAN
;
5580 /* Find place in middle of list for the new interface. */
5581 for (cur
= pri
->no_b_chan_iflist
; cur
; cur
= cur
->next
) {
5582 if (pvt
->channel
< cur
->channel
) {
5583 /* New interface goes before the current interface. */
5584 pvt
->prev
= cur
->prev
;
5587 /* Insert into the middle of the list. */
5588 cur
->prev
->next
= pvt
;
5590 /* Insert at head of list. */
5591 pri
->no_b_chan_iflist
= pvt
;
5598 /* New interface goes onto the end of the list */
5599 pvt
->prev
= pri
->no_b_chan_end
;
5601 if (pri
->no_b_chan_end
) {
5602 ((struct dahdi_pvt
*) pri
->no_b_chan_end
)->next
= pvt
;
5604 pri
->no_b_chan_end
= pvt
;
5605 if (!pri
->no_b_chan_iflist
) {
5606 /* List was empty */
5607 pri
->no_b_chan_iflist
= pvt
;
5610 #endif /* defined(HAVE_PRI) */
5612 #if defined(HAVE_PRI)
5615 * \brief Extract the given chan_dahdi interface structure from the no B channel list.
5618 * \param pri sig_pri span control structure holding no B channel list.
5619 * \param pvt chan_dahdi private interface structure to extract.
5622 * The given interface structure can be either in the interface list or a stand alone
5623 * structure that has not been put in the list if the next and prev pointers are NULL.
5625 static void dahdi_nobch_extract(struct sig_pri_span
*pri
, struct dahdi_pvt
*pvt
)
5627 /* Extract from the forward chain. */
5629 pvt
->prev
->next
= pvt
->next
;
5630 } else if (pri
->no_b_chan_iflist
== pvt
) {
5631 /* Node is at the head of the list. */
5632 pri
->no_b_chan_iflist
= pvt
->next
;
5635 /* Extract from the reverse chain. */
5637 pvt
->next
->prev
= pvt
->prev
;
5638 } else if (pri
->no_b_chan_end
== pvt
) {
5639 /* Node is at the end of the list. */
5640 pri
->no_b_chan_end
= pvt
->prev
;
5643 /* Node is no longer in the list. */
5644 pvt
->which_iflist
= DAHDI_IFLIST_NONE
;
5648 #endif /* defined(HAVE_PRI) */
5650 #if defined(HAVE_PRI)
5653 * \brief Unlink the channel interface from the PRI private pointer array.
5656 * \param pvt chan_dahdi private interface structure to unlink.
5658 static void dahdi_unlink_pri_pvt(struct dahdi_pvt
*pvt
)
5661 struct sig_pri_span
*pri
;
5665 /* Not PRI signaling so cannot be in a PRI private pointer array. */
5668 ast_mutex_lock(&pri
->lock
);
5669 for (idx
= 0; idx
< pri
->numchans
; ++idx
) {
5670 if (pri
->pvts
[idx
] == pvt
->sig_pvt
) {
5671 pri
->pvts
[idx
] = NULL
;
5672 ast_mutex_unlock(&pri
->lock
);
5676 ast_mutex_unlock(&pri
->lock
);
5678 #endif /* defined(HAVE_PRI) */
5680 #if defined(HAVE_SS7)
5683 * \brief Unlink the channel interface from the SS7 private pointer array.
5686 * \param pvt chan_dahdi private interface structure to unlink.
5688 static void dahdi_unlink_ss7_pvt(struct dahdi_pvt
*pvt
)
5691 struct sig_ss7_linkset
*ss7
;
5695 /* Not SS7 signaling so cannot be in a SS7 private pointer array. */
5698 ast_mutex_lock(&ss7
->lock
);
5699 for (idx
= 0; idx
< ss7
->numchans
; ++idx
) {
5700 if (ss7
->pvts
[idx
] == pvt
->sig_pvt
) {
5701 ss7
->pvts
[idx
] = NULL
;
5702 ast_mutex_unlock(&ss7
->lock
);
5706 ast_mutex_unlock(&ss7
->lock
);
5708 #endif /* defined(HAVE_SS7) */
5710 #if defined(HAVE_OPENR2)
5713 * \brief Unlink the channel interface from the MFC/R2 private pointer array.
5715 * \param pvt chan_dahdi private interface structure to unlink.
5717 static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt
*pvt
)
5720 struct dahdi_mfcr2
*mfcr2
;
5721 int should_destroy_link
= 0;
5723 ast_mutex_lock(&pvt
->lock
);
5725 ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt
->channel
);
5726 openr2_chan_disable_read(pvt
->r2chan
);
5730 for (idx
= 0; idx
< mfcr2
->numchans
; ++idx
) {
5731 if (mfcr2
->pvts
[idx
] == pvt
) {
5732 ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt
->channel
);
5733 mfcr2
->pvts
[idx
] = NULL
;
5734 mfcr2
->live_chans
--;
5738 if (!mfcr2
->live_chans
) {
5739 ast_debug(1, "MFC/R2 link is now empty\n");
5740 should_destroy_link
= 1;
5743 ast_mutex_unlock(&pvt
->lock
);
5744 if (should_destroy_link
) {
5745 ast_debug(1, "MFC/R2 link is now empty\n");
5746 mfcr2_queue_for_destruction(pvt
);
5749 #endif /* defined(HAVE_OPENR2) */
5751 static struct dahdi_pvt
*find_next_iface_in_span(struct dahdi_pvt
*cur
)
5753 if (cur
->next
&& cur
->next
->span
== cur
->span
) {
5755 } else if (cur
->prev
&& cur
->prev
->span
== cur
->span
) {
5762 static void destroy_dahdi_pvt(struct dahdi_pvt
*pvt
)
5764 struct dahdi_pvt
*p
= pvt
;
5766 if (p
->manages_span_alarms
) {
5767 struct dahdi_pvt
*next
= find_next_iface_in_span(p
);
5769 next
->manages_span_alarms
= 1;
5773 /* Remove channel from the list */
5774 #if defined(HAVE_PRI)
5775 dahdi_unlink_pri_pvt(p
);
5776 #endif /* defined(HAVE_PRI) */
5777 #if defined(HAVE_SS7)
5778 dahdi_unlink_ss7_pvt(p
);
5779 #endif /* defined(HAVE_SS7) */
5780 #if defined(HAVE_OPENR2)
5781 dahdi_unlink_mfcr2_pvt(p
);
5782 #endif /* defined(HAVE_SS7) */
5783 switch (pvt
->which_iflist
) {
5784 case DAHDI_IFLIST_NONE
:
5786 case DAHDI_IFLIST_MAIN
:
5787 dahdi_iflist_extract(p
);
5789 #if defined(HAVE_PRI)
5790 case DAHDI_IFLIST_NO_B_CHAN
:
5792 dahdi_nobch_extract(p
->pri
, p
);
5795 #endif /* defined(HAVE_PRI) */
5799 if (dahdi_analog_lib_handles(p
->sig
, 0, 0)) {
5800 analog_delete(p
->sig_pvt
);
5803 #if defined(HAVE_PRI)
5804 case SIG_PRI_LIB_HANDLE_CASES
:
5805 sig_pri_chan_delete(p
->sig_pvt
);
5807 #endif /* defined(HAVE_PRI) */
5808 #if defined(HAVE_SS7)
5810 sig_ss7_chan_delete(p
->sig_pvt
);
5812 #endif /* defined(HAVE_SS7) */
5817 ast_free(p
->cidspill
);
5819 ao2_cleanup(p
->smdi_iface
);
5821 if (p
->mwi_event_sub
) {
5822 p
->mwi_event_sub
= ast_mwi_unsubscribe(p
->mwi_event_sub
);
5825 ast_variables_destroy(p
->vars
);
5828 ast_cc_config_params_destroy(p
->cc_params
);
5831 p
->named_callgroups
= ast_unref_namedgroups(p
->named_callgroups
);
5832 p
->named_pickupgroups
= ast_unref_namedgroups(p
->named_pickupgroups
);
5834 ast_mutex_destroy(&p
->lock
);
5835 dahdi_close_sub(p
, SUB_REAL
);
5837 ast_channel_tech_pvt_set(p
->owner
, NULL
);
5842 static void destroy_channel(struct dahdi_pvt
*cur
, int now
)
5847 /* Do not destroy the channel now if it is owned by someone. */
5851 for (i
= 0; i
< 3; i
++) {
5852 if (cur
->subs
[i
].owner
) {
5857 destroy_dahdi_pvt(cur
);
5860 static void destroy_all_channels(void)
5863 #if defined(HAVE_PRI)
5865 struct sig_pri_span
*pri
;
5866 #endif /* defined(HAVE_PRI) */
5867 struct dahdi_pvt
*p
;
5869 while (num_restart_pending
) {
5873 ast_mutex_lock(&iflock
);
5874 /* Destroy all the interfaces and free their memory */
5879 #if defined(HAVE_PRI_SERVICE_MESSAGES)
5881 char db_chan_name
[20];
5886 snprintf(db_chan_name
, sizeof(db_chan_name
), "%s/%d:%d", dahdi_db
, p
->span
, chan
);
5887 if (!ast_db_get(db_chan_name
, SRVST_DBKEY
, db_answer
, sizeof(db_answer
))) {
5888 sscanf(db_answer
, "%1c:%30d", &state
, &why
);
5891 /* SRVST persistence is not required */
5892 ast_db_del(db_chan_name
, SRVST_DBKEY
);
5895 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
5896 /* Free associated memory */
5897 destroy_dahdi_pvt(p
);
5898 ast_verb(3, "Unregistered channel %d\n", chan
);
5901 ast_mutex_unlock(&iflock
);
5903 #if defined(HAVE_PRI)
5904 /* Destroy all of the no B channel interface lists */
5905 for (span
= 0; span
< NUM_SPANS
; ++span
) {
5906 if (!pris
[span
].dchannels
[0]) {
5909 pri
= &pris
[span
].pri
;
5910 ast_mutex_lock(&pri
->lock
);
5911 while (pri
->no_b_chan_iflist
) {
5912 p
= pri
->no_b_chan_iflist
;
5914 /* Free associated memory */
5915 destroy_dahdi_pvt(p
);
5917 ast_mutex_unlock(&pri
->lock
);
5919 #endif /* defined(HAVE_PRI) */
5922 #if defined(HAVE_PRI)
5923 static char *dahdi_send_keypad_facility_app
= "DAHDISendKeypadFacility";
5925 static int dahdi_send_keypad_facility_exec(struct ast_channel
*chan
, const char *digits
)
5927 /* Data will be our digit string */
5928 struct dahdi_pvt
*p
;
5930 if (ast_strlen_zero(digits
)) {
5931 ast_debug(1, "No digit string sent to application!\n");
5935 p
= (struct dahdi_pvt
*)ast_channel_tech_pvt(chan
);
5938 ast_debug(1, "Unable to find technology private\n");
5942 pri_send_keypad_facility_exec(p
->sig_pvt
, digits
);
5946 #endif /* defined(HAVE_PRI) */
5948 #if defined(HAVE_PRI)
5949 #if defined(HAVE_PRI_PROG_W_CAUSE)
5950 static char *dahdi_send_callrerouting_facility_app
= "DAHDISendCallreroutingFacility";
5952 static int dahdi_send_callrerouting_facility_exec(struct ast_channel
*chan
, const char *data
)
5954 /* Data will be our digit string */
5955 struct dahdi_pvt
*pvt
;
5958 AST_DECLARE_APP_ARGS(args
,
5959 AST_APP_ARG(destination
);
5960 AST_APP_ARG(original
);
5961 AST_APP_ARG(reason
);
5964 if (ast_strlen_zero(data
)) {
5965 ast_debug(1, "No data sent to application!\n");
5968 if (ast_channel_tech(chan
) != &dahdi_tech
) {
5969 ast_debug(1, "Only DAHDI technology accepted!\n");
5972 pvt
= (struct dahdi_pvt
*) ast_channel_tech_pvt(chan
);
5974 ast_debug(1, "Unable to find technology private\n");
5978 case SIG_PRI_LIB_HANDLE_CASES
:
5981 ast_debug(1, "callrerouting attempted on non-ISDN channel %s\n",
5982 ast_channel_name(chan
));
5986 parse
= ast_strdupa(data
);
5987 AST_STANDARD_APP_ARGS(args
, parse
);
5989 if (ast_strlen_zero(args
.destination
)) {
5990 ast_log(LOG_WARNING
, "callrerouting facility requires at least destination number argument\n");
5994 if (ast_strlen_zero(args
.original
)) {
5995 ast_log(LOG_WARNING
, "Callrerouting Facility without original called number argument\n");
5996 args
.original
= NULL
;
5999 if (ast_strlen_zero(args
.reason
)) {
6000 ast_log(LOG_NOTICE
, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n");
6004 res
= pri_send_callrerouting_facility_exec(pvt
->sig_pvt
, ast_channel_state(chan
),
6005 args
.destination
, args
.original
, args
.reason
);
6008 * Wait up to 5 seconds for a reply before hanging up this call
6009 * leg if the peer does not disconnect first.
6011 ast_safe_sleep(chan
, 5000);
6016 #endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
6017 #endif /* defined(HAVE_PRI) */
6019 #if defined(HAVE_OPENR2)
6020 static const char * const dahdi_accept_r2_call_app
= "DAHDIAcceptR2Call";
6022 static int dahdi_accept_r2_call_exec(struct ast_channel
*chan
, const char *data
)
6024 /* data is whether to accept with charge or no charge */
6025 openr2_call_mode_t accept_mode
;
6026 int res
, timeout
, maxloops
;
6027 struct ast_frame
*f
;
6028 struct dahdi_pvt
*p
;
6030 AST_DECLARE_APP_ARGS(args
,
6031 AST_APP_ARG(charge
);
6034 if (ast_strlen_zero(data
)) {
6035 ast_debug(1, "No data sent to application!\n");
6039 if (ast_channel_tech(chan
) != &dahdi_tech
) {
6040 ast_debug(1, "Only DAHDI technology accepted!\n");
6044 p
= (struct dahdi_pvt
*)ast_channel_tech_pvt(chan
);
6046 ast_debug(1, "Unable to find technology private!\n");
6050 parse
= ast_strdupa(data
);
6051 AST_STANDARD_APP_ARGS(args
, parse
);
6053 if (ast_strlen_zero(args
.charge
)) {
6054 ast_log(LOG_WARNING
, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
6058 ast_mutex_lock(&p
->lock
);
6059 if (!p
->mfcr2
|| !p
->mfcr2call
) {
6060 ast_mutex_unlock(&p
->lock
);
6061 ast_debug(1, "Channel %s does not seems to be an R2 active channel!\n", ast_channel_name(chan
));
6065 if (p
->mfcr2_call_accepted
) {
6066 ast_mutex_unlock(&p
->lock
);
6067 ast_debug(1, "MFC/R2 call already accepted on channel %s!\n", ast_channel_name(chan
));
6070 accept_mode
= ast_true(args
.charge
) ? OR2_CALL_WITH_CHARGE
: OR2_CALL_NO_CHARGE
;
6071 if (openr2_chan_accept_call(p
->r2chan
, accept_mode
)) {
6072 ast_mutex_unlock(&p
->lock
);
6073 ast_log(LOG_WARNING
, "Failed to accept MFC/R2 call!\n");
6076 ast_mutex_unlock(&p
->lock
);
6080 maxloops
= 50; /* wait up to 5 seconds */
6081 /* we need to read() until the call is accepted */
6082 while (maxloops
> 0) {
6084 if (ast_check_hangup(chan
)) {
6087 res
= ast_waitfor(chan
, timeout
);
6089 ast_debug(1, "ast_waitfor failed on channel %s, going out ...\n", ast_channel_name(chan
));
6099 ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan
));
6103 if (f
->frametype
== AST_FRAME_CONTROL
&& f
->subclass
.integer
== AST_CONTROL_HANGUP
) {
6104 ast_debug(1, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan
));
6110 ast_mutex_lock(&p
->lock
);
6111 if (p
->mfcr2_call_accepted
) {
6112 ast_mutex_unlock(&p
->lock
);
6113 ast_debug(1, "Accepted MFC/R2 call!\n");
6116 ast_mutex_unlock(&p
->lock
);
6119 ast_log(LOG_WARNING
, "Failed to accept MFC/R2 call!\n");
6124 static openr2_call_disconnect_cause_t
dahdi_ast_cause_to_r2_cause(int cause
)
6126 openr2_call_disconnect_cause_t r2cause
= OR2_CAUSE_NORMAL_CLEARING
;
6128 case AST_CAUSE_USER_BUSY
:
6129 case AST_CAUSE_CALL_REJECTED
:
6130 case AST_CAUSE_INTERWORKING
: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
6131 r2cause
= OR2_CAUSE_BUSY_NUMBER
;
6134 case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION
:
6135 case AST_CAUSE_SWITCH_CONGESTION
:
6136 r2cause
= OR2_CAUSE_NETWORK_CONGESTION
;
6139 case AST_CAUSE_UNALLOCATED
:
6140 r2cause
= OR2_CAUSE_UNALLOCATED_NUMBER
;
6143 case AST_CAUSE_NETWORK_OUT_OF_ORDER
:
6144 case AST_CAUSE_DESTINATION_OUT_OF_ORDER
:
6145 r2cause
= OR2_CAUSE_OUT_OF_ORDER
;
6148 case AST_CAUSE_NO_ANSWER
:
6149 case AST_CAUSE_NO_USER_RESPONSE
:
6150 r2cause
= OR2_CAUSE_NO_ANSWER
;
6154 r2cause
= OR2_CAUSE_NORMAL_CLEARING
;
6157 ast_debug(1, "ast cause %d resulted in openr2 cause %d/%s\n",
6158 cause
, r2cause
, openr2_proto_get_disconnect_string(r2cause
));
6163 static int revert_fax_buffers(struct dahdi_pvt
*p
, struct ast_channel
*ast
)
6165 if (p
->bufferoverrideinuse
) {
6166 /* faxbuffers are in use, revert them */
6167 struct dahdi_bufferinfo bi
= {
6168 .txbufpolicy
= p
->buf_policy
,
6169 .rxbufpolicy
= p
->buf_policy
,
6170 .bufsize
= p
->bufsize
,
6171 .numbufs
= p
->buf_no
6175 if ((bpres
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
6176 ast_log(LOG_WARNING
, "Channel '%s' unable to revert buffer policy: %s\n", ast_channel_name(ast
), strerror(errno
));
6178 p
->bufferoverrideinuse
= 0;
6185 static int dahdi_hangup(struct ast_channel
*ast
)
6190 /*static int restore_gains(struct dahdi_pvt *p);*/
6191 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
6192 struct dahdi_params par
;
6194 ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast
));
6195 if (!ast_channel_tech_pvt(ast
)) {
6196 ast_log(LOG_WARNING
, "Asked to hangup channel not connected\n");
6200 ast_mutex_lock(&p
->lock
);
6202 /* Always use sig_analog hangup handling for operator mode */
6203 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, 0)) {
6205 dahdi_confmute(p
, 0);
6208 p
->waitingfordt
.tv_sec
= 0;
6210 res
= analog_hangup(p
->sig_pvt
, ast
);
6211 revert_fax_buffers(p
, ast
);
6215 p
->cid_num
[0] = '\0';
6216 p
->cid_name
[0] = '\0';
6217 p
->cid_subaddr
[0] = '\0';
6220 #if defined(HAVE_PRI)
6221 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
6223 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6225 dahdi_confmute(p
, 0);
6229 ast_dsp_free(p
->dsp
);
6234 /* Real channel, do some fixup */
6235 p
->subs
[SUB_REAL
].owner
= NULL
;
6236 p
->subs
[SUB_REAL
].needbusy
= 0;
6237 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
6240 p
->cid_tag
[0] = '\0';
6241 p
->ringt
= 0;/* Probably not used in this mode. Reset anyway. */
6242 p
->distinctivering
= 0;/* Probably not used in this mode. Reset anyway. */
6243 p
->confirmanswer
= 0;/* Probably not used in this mode. Reset anyway. */
6247 p
->pulsedial
= 0;/* Probably not used in this mode. Reset anyway. */
6249 revert_fax_buffers(p
, ast
);
6251 p
->law
= p
->law_default
;
6252 law
= p
->law_default
;
6253 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
6255 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n",
6256 p
->channel
, strerror(errno
));
6259 sig_pri_hangup(p
->sig_pvt
, ast
);
6261 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6262 dahdi_ec_disable(p
);
6265 ast_channel_setoption(ast
, AST_OPTION_TDD
, &x
, sizeof(char), 0);
6266 p
->didtdd
= 0;/* Probably not used in this mode. Reset anyway. */
6269 dahdi_conf_update(p
);
6272 /* Restore data mode */
6274 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6276 if (num_restart_pending
== 0) {
6281 #endif /* defined(HAVE_PRI) */
6283 #if defined(HAVE_SS7)
6284 if (p
->sig
== SIG_SS7
) {
6286 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6288 dahdi_confmute(p
, 0);
6292 ast_dsp_free(p
->dsp
);
6297 /* Real channel, do some fixup */
6298 p
->subs
[SUB_REAL
].owner
= NULL
;
6299 p
->subs
[SUB_REAL
].needbusy
= 0;
6300 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
6303 p
->ringt
= 0;/* Probably not used in this mode. Reset anyway. */
6304 p
->distinctivering
= 0;/* Probably not used in this mode. Reset anyway. */
6305 p
->confirmanswer
= 0;/* Probably not used in this mode. Reset anyway. */
6309 p
->pulsedial
= 0;/* Probably not used in this mode. Reset anyway. */
6311 revert_fax_buffers(p
, ast
);
6313 p
->law
= p
->law_default
;
6314 law
= p
->law_default
;
6315 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
6317 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n",
6318 p
->channel
, strerror(errno
));
6321 sig_ss7_hangup(p
->sig_pvt
, ast
);
6323 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6324 dahdi_ec_disable(p
);
6327 ast_channel_setoption(ast
, AST_OPTION_TDD
, &x
, sizeof(char), 0);
6328 p
->didtdd
= 0;/* Probably not used in this mode. Reset anyway. */
6330 dahdi_conf_update(p
);
6333 /* Restore data mode */
6335 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6337 if (num_restart_pending
== 0) {
6342 #endif /* defined(HAVE_SS7) */
6344 idx
= dahdi_get_index(ast
, p
, 1);
6346 dahdi_confmute(p
, 0);
6349 if (p
->origcid_num
) {
6350 ast_copy_string(p
->cid_num
, p
->origcid_num
, sizeof(p
->cid_num
));
6351 ast_free(p
->origcid_num
);
6352 p
->origcid_num
= NULL
;
6354 if (p
->origcid_name
) {
6355 ast_copy_string(p
->cid_name
, p
->origcid_name
, sizeof(p
->cid_name
));
6356 ast_free(p
->origcid_name
);
6357 p
->origcid_name
= NULL
;
6360 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
6362 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
6363 p
->channel
, idx
, p
->subs
[SUB_REAL
].dfd
, p
->subs
[SUB_CALLWAIT
].dfd
, p
->subs
[SUB_THREEWAY
].dfd
);
6367 /* Real channel, do some fixup */
6368 p
->subs
[idx
].owner
= NULL
;
6369 p
->subs
[idx
].needanswer
= 0;
6370 p
->subs
[idx
].needflash
= 0;
6371 p
->subs
[idx
].needringing
= 0;
6372 p
->subs
[idx
].needbusy
= 0;
6373 p
->subs
[idx
].needcongestion
= 0;
6374 p
->subs
[idx
].linear
= 0;
6375 p
->polarity
= POLARITY_IDLE
;
6376 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
6377 if (idx
== SUB_REAL
) {
6378 if ((p
->subs
[SUB_CALLWAIT
].dfd
> -1) && (p
->subs
[SUB_THREEWAY
].dfd
> -1)) {
6379 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
6380 if (p
->subs
[SUB_CALLWAIT
].inthreeway
) {
6381 /* We had flipped over to answer a callwait and now it's gone */
6382 ast_debug(1, "We were flipped over to the callwait, moving back and not owning.\n");
6383 /* Move to the call-wait, but un-own us until they flip back. */
6384 swap_subs(p
, SUB_CALLWAIT
, SUB_REAL
);
6385 unalloc_sub(p
, SUB_CALLWAIT
);
6388 /* The three way hung up, but we still have a call wait */
6389 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
6390 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
6391 unalloc_sub(p
, SUB_THREEWAY
);
6392 if (p
->subs
[SUB_REAL
].inthreeway
) {
6393 /* This was part of a three way call. Immediately make way for
6395 ast_debug(1, "Call was complete, setting owner to former third call\n");
6396 p
->owner
= p
->subs
[SUB_REAL
].owner
;
6398 /* This call hasn't been completed yet... Set owner to NULL */
6399 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6402 p
->subs
[SUB_REAL
].inthreeway
= 0;
6404 } else if (p
->subs
[SUB_CALLWAIT
].dfd
> -1) {
6405 /* Move to the call-wait and switch back to them. */
6406 swap_subs(p
, SUB_CALLWAIT
, SUB_REAL
);
6407 unalloc_sub(p
, SUB_CALLWAIT
);
6408 p
->owner
= p
->subs
[SUB_REAL
].owner
;
6409 if (ast_channel_state(p
->owner
) != AST_STATE_UP
)
6410 p
->subs
[SUB_REAL
].needanswer
= 1;
6411 ast_queue_unhold(p
->subs
[SUB_REAL
].owner
);
6412 } else if (p
->subs
[SUB_THREEWAY
].dfd
> -1) {
6413 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
6414 unalloc_sub(p
, SUB_THREEWAY
);
6415 if (p
->subs
[SUB_REAL
].inthreeway
) {
6416 /* This was part of a three way call. Immediately make way for
6418 ast_debug(1, "Call was complete, setting owner to former third call\n");
6419 p
->owner
= p
->subs
[SUB_REAL
].owner
;
6421 /* This call hasn't been completed yet... Set owner to NULL */
6422 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6425 p
->subs
[SUB_REAL
].inthreeway
= 0;
6427 } else if (idx
== SUB_CALLWAIT
) {
6428 /* Ditch the holding callwait call, and immediately make it availabe */
6429 if (p
->subs
[SUB_CALLWAIT
].inthreeway
) {
6430 /* This is actually part of a three way, placed on hold. Place the third part
6431 on music on hold now */
6432 if (p
->subs
[SUB_THREEWAY
].owner
) {
6433 ast_queue_hold(p
->subs
[SUB_THREEWAY
].owner
, p
->mohsuggest
);
6435 p
->subs
[SUB_THREEWAY
].inthreeway
= 0;
6436 /* Make it the call wait now */
6437 swap_subs(p
, SUB_CALLWAIT
, SUB_THREEWAY
);
6438 unalloc_sub(p
, SUB_THREEWAY
);
6440 unalloc_sub(p
, SUB_CALLWAIT
);
6441 } else if (idx
== SUB_THREEWAY
) {
6442 if (p
->subs
[SUB_CALLWAIT
].inthreeway
) {
6443 /* The other party of the three way call is currently in a call-wait state.
6444 Start music on hold for them, and take the main guy out of the third call */
6445 if (p
->subs
[SUB_CALLWAIT
].owner
) {
6446 ast_queue_hold(p
->subs
[SUB_CALLWAIT
].owner
, p
->mohsuggest
);
6448 p
->subs
[SUB_CALLWAIT
].inthreeway
= 0;
6450 p
->subs
[SUB_REAL
].inthreeway
= 0;
6451 /* If this was part of a three way call index, let us make
6452 another three way call */
6453 unalloc_sub(p
, SUB_THREEWAY
);
6455 /* This wasn't any sort of call, but how are we an index? */
6456 ast_log(LOG_WARNING
, "Index found but not any type of call?\n");
6460 if (!p
->subs
[SUB_REAL
].owner
&& !p
->subs
[SUB_CALLWAIT
].owner
&& !p
->subs
[SUB_THREEWAY
].owner
) {
6463 p
->distinctivering
= 0;
6464 p
->confirmanswer
= 0;
6470 ast_dsp_free(p
->dsp
);
6474 revert_fax_buffers(p
, ast
);
6476 p
->law
= p
->law_default
;
6477 law
= p
->law_default
;
6478 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
6480 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n", p
->channel
, strerror(errno
));
6481 /* Perform low level hangup if no owner left */
6483 if (p
->mfcr2
&& p
->mfcr2call
&& openr2_chan_get_direction(p
->r2chan
) != OR2_DIR_STOPPED
) {
6484 ast_debug(1, "disconnecting MFC/R2 call on chan %d\n", p
->channel
);
6485 /* If it's an incoming call, check the mfcr2_forced_release setting */
6486 if (openr2_chan_get_direction(p
->r2chan
) == OR2_DIR_BACKWARD
&& p
->mfcr2_forced_release
) {
6487 dahdi_r2_disconnect_call(p
, OR2_CAUSE_FORCED_RELEASE
);
6489 const char *r2causestr
= pbx_builtin_getvar_helper(ast
, "MFCR2_CAUSE");
6490 int r2cause_user
= r2causestr
? atoi(r2causestr
) : 0;
6491 openr2_call_disconnect_cause_t r2cause
= r2cause_user
? dahdi_ast_cause_to_r2_cause(r2cause_user
)
6492 : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast
));
6493 dahdi_r2_disconnect_call(p
, r2cause
);
6495 } else if (p
->mfcr2call
) {
6496 ast_debug(1, "Clearing call request on channel %d\n", p
->channel
);
6497 /* since ast_request() was called but not ast_call() we have not yet dialed
6498 and the openr2 stack will not call on_call_end callback, we need to unset
6499 the mfcr2call flag and bump the monitor count so the monitor thread can take
6500 care of this channel events from now on */
6507 case SIG_PRI_LIB_HANDLE_CASES
:
6511 res
= dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
6515 ast_log(LOG_WARNING
, "Unable to hangup line %s\n", ast_channel_name(ast
));
6521 memset(&par
, 0, sizeof(par
));
6522 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &par
);
6524 struct analog_pvt
*analog_p
= p
->sig_pvt
;
6526 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p
->channel
, par
.rxisoffhook
);
6528 /* If they're off hook, try playing congestion */
6529 if ((par
.rxisoffhook
) && (!(p
->radio
|| (p
->oprmode
< 0))))
6530 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
6532 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6533 analog_p
->fxsoffhookstate
= par
.rxisoffhook
;
6539 /* Make sure we're not made available for at least two seconds assuming
6540 we were actually used for an inbound or outbound call. */
6541 if (ast_channel_state(ast
) != AST_STATE_RESERVED
) {
6542 time(&p
->guardtime
);
6547 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6551 dahdi_ec_disable(p
);
6553 ast_channel_setoption(ast
,AST_OPTION_TONE_VERIFY
,&x
,sizeof(char),0);
6554 ast_channel_setoption(ast
,AST_OPTION_TDD
,&x
,sizeof(char),0);
6557 p
->callwaiting
= p
->permcallwaiting
;
6558 p
->hidecallerid
= p
->permhidecallerid
;
6559 p
->waitingfordt
.tv_sec
= 0;
6562 dahdi_conf_update(p
);
6564 /* Restore data mode */
6566 case SIG_PRI_LIB_HANDLE_CASES
:
6569 ast_channel_setoption(ast
,AST_OPTION_AUDIO_MODE
,&x
,sizeof(char),0);
6574 if (num_restart_pending
== 0)
6578 p
->callwaitingrepeat
= 0;
6580 p
->cid_suppress_expire
= 0;
6583 ast_channel_tech_pvt_set(ast
, NULL
);
6584 ast_free(p
->cidspill
);
6587 if (p
->reoriginate
&& p
->sig
== SIG_FXOKS
&& dahdi_analog_lib_handles(p
->sig
, p
->radio
, 0)) {
6588 /* Automatic reorigination: if all calls towards a user have hung up,
6589 * give dial tone again, so user doesn't need to cycle the hook state manually. */
6590 if (my_is_off_hook(p
) && !p
->owner
) {
6591 /* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
6592 ast_debug(1, "Queuing reorigination for channel %d\n", p
->channel
);
6593 my_play_tone(p
, SUB_REAL
, -1); /* Stop any congestion tone that may be present. */
6594 /* Must wait for the loop disconnect to end.
6595 * Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
6596 * Calling usleep on an active DAHDI channel is a no-no, but this is okay.
6598 usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
6599 /* If the line is still off-hook and ownerless, actually queue the reorigination.
6600 * do_monitor will actually go ahead and do it. */
6601 if (!p
->owner
&& my_is_off_hook(p
)) {
6602 p
->doreoriginate
= 1; /* Tell do_monitor to reoriginate this channel */
6603 /* Note, my_off_hook will fail if called before the loop disconnect has finished
6604 * (important for FXOKS signaled channels). This is because DAHDI will reject
6605 * DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
6606 * so we have to wait for that to finish (see comment above).
6607 * do_monitor itself cannot block, so make the blocking usleep call
6608 * here in the channel thread instead.
6610 my_off_hook(p
); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
6612 ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p
->channel
);
6617 ast_mutex_unlock(&p
->lock
);
6618 ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast
));
6620 ast_mutex_lock(&iflock
);
6621 if (p
->restartpending
) {
6622 num_restart_pending
--;
6626 destroy_channel(p
, 0);
6628 ast_mutex_unlock(&iflock
);
6630 ast_module_unref(ast_module_info
->self
);
6634 static int dahdi_answer(struct ast_channel
*ast
)
6636 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
6639 ast_setstate(ast
, AST_STATE_UP
);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
6640 ast_mutex_lock(&p
->lock
);
6641 idx
= dahdi_get_index(ast
, p
, 0);
6644 /* nothing to do if a radio channel */
6645 if ((p
->radio
|| (p
->oprmode
< 0))) {
6646 ast_mutex_unlock(&p
->lock
);
6650 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
6651 res
= analog_answer(p
->sig_pvt
, ast
);
6652 ast_mutex_unlock(&p
->lock
);
6657 #if defined(HAVE_PRI)
6658 case SIG_PRI_LIB_HANDLE_CASES
:
6659 res
= sig_pri_answer(p
->sig_pvt
, ast
);
6661 #endif /* defined(HAVE_PRI) */
6662 #if defined(HAVE_SS7)
6664 res
= sig_ss7_answer(p
->sig_pvt
, ast
);
6666 #endif /* defined(HAVE_SS7) */
6669 if (!p
->mfcr2_call_accepted
) {
6670 /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
6671 openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
6672 p
->mfcr2_answer_pending
= 1;
6673 if (p
->mfcr2_charge_calls
) {
6674 ast_debug(1, "Accepting MFC/R2 call with charge before answering on chan %d\n", p
->channel
);
6675 openr2_chan_accept_call(p
->r2chan
, OR2_CALL_WITH_CHARGE
);
6677 ast_debug(1, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p
->channel
);
6678 openr2_chan_accept_call(p
->r2chan
, OR2_CALL_NO_CHARGE
);
6681 ast_debug(1, "Answering MFC/R2 call on chan %d\n", p
->channel
);
6687 ast_mutex_unlock(&p
->lock
);
6690 ast_log(LOG_WARNING
, "Don't know how to answer signalling %d (channel %d)\n", p
->sig
, p
->channel
);
6694 ast_mutex_unlock(&p
->lock
);
6698 void dahdi_dtmf_detect_disable(struct dahdi_pvt
*p
)
6704 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONEDETECT
, &val
);
6706 if (!p
->hardwaredtmf
&& p
->dsp
) {
6707 p
->dsp_features
&= ~DSP_FEATURE_DIGIT_DETECT
;
6708 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
6712 void dahdi_dtmf_detect_enable(struct dahdi_pvt
*p
)
6714 int val
= DAHDI_TONEDETECT_ON
| DAHDI_TONEDETECT_MUTE
;
6716 if (p
->channel
== CHAN_PSEUDO
)
6721 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONEDETECT
, &val
);
6723 if (!p
->hardwaredtmf
&& p
->dsp
) {
6724 p
->dsp_features
|= DSP_FEATURE_DIGIT_DETECT
;
6725 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
6729 static int dahdi_queryoption(struct ast_channel
*chan
, int option
, void *data
, int *datalen
)
6732 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
6734 /* all supported options require data */
6735 if (!p
|| !data
|| (*datalen
< 1)) {
6741 case AST_OPTION_TDD
:
6746 *cp
= p
->tdd
? 1 : 0;
6749 case AST_OPTION_DIGIT_DETECT
:
6751 *cp
= p
->ignoredtmf
? 0 : 1;
6752 ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp
? "en" : "dis", ast_channel_name(chan
));
6754 case AST_OPTION_FAX_DETECT
:
6756 *cp
= (p
->dsp_features
& DSP_FEATURE_FAX_DETECT
) ? 0 : 1;
6757 ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp
? "en" : "dis", ast_channel_name(chan
));
6759 case AST_OPTION_CC_AGENT_TYPE
:
6760 #if defined(HAVE_PRI)
6761 #if defined(HAVE_PRI_CCSS)
6762 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
6763 ast_copy_string((char *) data
, dahdi_pri_cc_type
, *datalen
);
6766 #endif /* defined(HAVE_PRI_CCSS) */
6767 #endif /* defined(HAVE_PRI) */
6778 static int dahdi_setoption(struct ast_channel
*chan
, int option
, void *data
, int datalen
)
6784 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
), *pp
;
6785 struct oprmode
*oprmode
;
6788 /* all supported options require data */
6789 if (!p
|| !data
|| (datalen
< 1)) {
6795 case AST_OPTION_TXGAIN
:
6796 scp
= (signed char *) data
;
6797 idx
= dahdi_get_index(chan
, p
, 0);
6799 ast_log(LOG_WARNING
, "No index in TXGAIN?\n");
6802 ast_debug(1, "Setting actual tx gain on %s to %f\n", ast_channel_name(chan
), p
->txgain
+ (float) *scp
);
6803 return set_actual_txgain(p
->subs
[idx
].dfd
, p
->txgain
+ (float) *scp
, p
->txdrc
, p
->law
);
6804 case AST_OPTION_RXGAIN
:
6805 scp
= (signed char *) data
;
6806 idx
= dahdi_get_index(chan
, p
, 0);
6808 ast_log(LOG_WARNING
, "No index in RXGAIN?\n");
6811 ast_debug(1, "Setting actual rx gain on %s to %f\n", ast_channel_name(chan
), p
->rxgain
+ (float) *scp
);
6812 return set_actual_rxgain(p
->subs
[idx
].dfd
, p
->rxgain
+ (float) *scp
, p
->rxdrc
, p
->law
);
6813 case AST_OPTION_TONE_VERIFY
:
6819 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",ast_channel_name(chan
));
6820 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MUTECONF
| p
->dtmfrelax
); /* set mute mode if desired */
6823 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",ast_channel_name(chan
));
6824 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MUTECONF
| DSP_DIGITMODE_MUTEMAX
| p
->dtmfrelax
); /* set mute mode if desired */
6827 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",ast_channel_name(chan
));
6828 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
); /* set mute mode if desired */
6832 case AST_OPTION_TDD
:
6833 /* turn on or off TDD */
6836 if (!*cp
) { /* turn it off */
6837 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",ast_channel_name(chan
));
6843 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
6844 (*cp
== 2) ? "MATE" : "ON", (int) *cp
, ast_channel_name(chan
));
6845 dahdi_ec_disable(p
);
6846 /* otherwise, turn it on */
6847 if (!p
->didtdd
) { /* if havent done it yet */
6848 unsigned char mybuf
[41000];/*! \todo XXX This is an abuse of the stack!! */
6850 int size
, res
, fd
, len
;
6851 struct pollfd fds
[1];
6854 memset(buf
, 0x7f, sizeof(mybuf
)); /* set to silence */
6855 ast_tdd_gen_ecdisa(buf
+ 16000, 16000); /* put in tone */
6857 idx
= dahdi_get_index(chan
, p
, 0);
6859 ast_log(LOG_WARNING
, "No index in TDD?\n");
6862 fd
= p
->subs
[idx
].dfd
;
6864 if (ast_check_hangup(chan
))
6867 if (size
> READ_SIZE
)
6870 fds
[0].events
= POLLPRI
| POLLOUT
;
6872 res
= poll(fds
, 1, -1);
6874 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p
->channel
);
6877 /* if got exception */
6878 if (fds
[0].revents
& POLLPRI
)
6880 if (!(fds
[0].revents
& POLLOUT
)) {
6881 ast_debug(1, "write fd not ready on channel %d\n", p
->channel
);
6884 res
= write(fd
, buf
, size
);
6886 if (res
== -1) return -1;
6887 ast_debug(1, "Write returned %d (%s) on channel %d\n", res
, strerror(errno
), p
->channel
);
6893 p
->didtdd
= 1; /* set to have done it now */
6895 if (*cp
== 2) { /* Mate mode */
6902 if (!p
->tdd
) { /* if we don't have one yet */
6903 p
->tdd
= tdd_new(); /* allocate one */
6906 case AST_OPTION_RELAXDTMF
: /* Relax DTMF decoding (or not) */
6910 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
6911 *cp
? "ON" : "OFF", (int) *cp
, ast_channel_name(chan
));
6912 ast_dsp_set_digitmode(p
->dsp
, ((*cp
) ? DSP_DIGITMODE_RELAXDTMF
: DSP_DIGITMODE_DTMF
) | p
->dtmfrelax
);
6914 case AST_OPTION_AUDIO_MODE
: /* Set AUDIO mode (or not) */
6915 #if defined(HAVE_PRI)
6916 if (dahdi_sig_pri_lib_handles(p
->sig
)
6917 && ((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
) {
6918 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
6921 #endif /* defined(HAVE_PRI) */
6925 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan
));
6927 dahdi_ec_disable(p
);
6929 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan
));
6932 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &x
) == -1)
6933 ast_log(LOG_WARNING
, "Unable to set audio mode on channel %d to %d: %s\n", p
->channel
, x
, strerror(errno
));
6935 case AST_OPTION_OPRMODE
: /* Operator services mode */
6936 oprmode
= (struct oprmode
*) data
;
6937 /* We don't support operator mode across technologies */
6938 if (strcasecmp(ast_channel_tech(chan
)->type
, ast_channel_tech(oprmode
->peer
)->type
)) {
6939 ast_log(LOG_NOTICE
, "Operator mode not supported on %s to %s calls.\n",
6940 ast_channel_tech(chan
)->type
, ast_channel_tech(oprmode
->peer
)->type
);
6944 pp
= ast_channel_tech_pvt(oprmode
->peer
);
6945 p
->oprmode
= pp
->oprmode
= 0;
6949 /* setup modes, if any */
6952 pp
->oprmode
= oprmode
->mode
;
6953 p
->oprmode
= -oprmode
->mode
;
6955 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
6956 oprmode
->mode
, ast_channel_name(chan
),ast_channel_name(oprmode
->peer
));
6958 case AST_OPTION_ECHOCAN
:
6961 ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan
));
6964 ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan
));
6965 dahdi_ec_disable(p
);
6968 case AST_OPTION_DIGIT_DETECT
:
6970 ast_debug(1, "%sabling digit detection on %s\n", *cp
? "En" : "Dis", ast_channel_name(chan
));
6972 dahdi_dtmf_detect_enable(p
);
6974 dahdi_dtmf_detect_disable(p
);
6977 case AST_OPTION_FAX_DETECT
:
6980 ast_debug(1, "%sabling fax tone detection on %s\n", *cp
? "En" : "Dis", ast_channel_name(chan
));
6982 p
->dsp_features
|= DSP_FEATURE_FAX_DETECT
;
6984 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
6986 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
6997 static int dahdi_func_read(struct ast_channel
*chan
, const char *function
, char *data
, char *buf
, size_t len
)
6999 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
7003 /* No private structure! */
7008 if (!strcasecmp(data
, "rxgain")) {
7009 ast_mutex_lock(&p
->lock
);
7010 snprintf(buf
, len
, "%f", p
->rxgain
);
7011 ast_mutex_unlock(&p
->lock
);
7012 } else if (!strcasecmp(data
, "txgain")) {
7013 ast_mutex_lock(&p
->lock
);
7014 snprintf(buf
, len
, "%f", p
->txgain
);
7015 ast_mutex_unlock(&p
->lock
);
7016 } else if (!strcasecmp(data
, "dahdi_channel")) {
7017 ast_mutex_lock(&p
->lock
);
7018 snprintf(buf
, len
, "%d", p
->channel
);
7019 ast_mutex_unlock(&p
->lock
);
7020 } else if (!strcasecmp(data
, "dahdi_span")) {
7021 ast_mutex_lock(&p
->lock
);
7022 snprintf(buf
, len
, "%d", p
->span
);
7023 ast_mutex_unlock(&p
->lock
);
7024 } else if (!strcasecmp(data
, "dahdi_group")) {
7025 ast_mutex_lock(&p
->lock
);
7026 snprintf(buf
, len
, "%llu", p
->group
);
7027 ast_mutex_unlock(&p
->lock
);
7028 } else if (!strcasecmp(data
, "dahdi_type")) {
7029 ast_mutex_lock(&p
->lock
);
7031 #if defined(HAVE_OPENR2)
7033 ast_copy_string(buf
, "mfc/r2", len
);
7035 #endif /* defined(HAVE_OPENR2) */
7036 #if defined(HAVE_PRI)
7037 case SIG_PRI_LIB_HANDLE_CASES
:
7038 ast_copy_string(buf
, "pri", len
);
7040 #endif /* defined(HAVE_PRI) */
7042 ast_copy_string(buf
, "pseudo", len
);
7044 #if defined(HAVE_SS7)
7046 ast_copy_string(buf
, "ss7", len
);
7048 #endif /* defined(HAVE_SS7) */
7050 /* The only thing left is analog ports. */
7051 ast_copy_string(buf
, "analog", len
);
7054 ast_mutex_unlock(&p
->lock
);
7055 #if defined(HAVE_PRI)
7056 #if defined(HAVE_PRI_REVERSE_CHARGE)
7057 } else if (!strcasecmp(data
, "reversecharge")) {
7058 ast_mutex_lock(&p
->lock
);
7060 case SIG_PRI_LIB_HANDLE_CASES
:
7061 snprintf(buf
, len
, "%d", ((struct sig_pri_chan
*) p
->sig_pvt
)->reverse_charging_indication
);
7068 ast_mutex_unlock(&p
->lock
);
7070 #if defined(HAVE_PRI_SETUP_KEYPAD)
7071 } else if (!strcasecmp(data
, "keypad_digits")) {
7072 ast_mutex_lock(&p
->lock
);
7074 case SIG_PRI_LIB_HANDLE_CASES
:
7075 ast_copy_string(buf
, ((struct sig_pri_chan
*) p
->sig_pvt
)->keypad_digits
,
7083 ast_mutex_unlock(&p
->lock
);
7084 #endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
7085 } else if (!strcasecmp(data
, "no_media_path")) {
7086 ast_mutex_lock(&p
->lock
);
7088 case SIG_PRI_LIB_HANDLE_CASES
:
7090 * TRUE if the call is on hold or is call waiting because
7091 * there is no media path available.
7093 snprintf(buf
, len
, "%d", ((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
);
7100 ast_mutex_unlock(&p
->lock
);
7101 #endif /* defined(HAVE_PRI) */
7102 } else if (!strcasecmp(data
, "dialmode")) {
7103 struct analog_pvt
*analog_p
;
7104 ast_mutex_lock(&p
->lock
);
7105 analog_p
= p
->sig_pvt
;
7106 /* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
7107 if (dahdi_analog_lib_handles(p
->sig
, 0, 0) && analog_p
) {
7108 switch (analog_p
->dialmode
) {
7109 case ANALOG_DIALMODE_BOTH
:
7110 ast_copy_string(buf
, "both", len
);
7112 case ANALOG_DIALMODE_PULSE
:
7113 ast_copy_string(buf
, "pulse", len
);
7115 case ANALOG_DIALMODE_DTMF
:
7116 ast_copy_string(buf
, "dtmf", len
);
7118 case ANALOG_DIALMODE_NONE
:
7119 ast_copy_string(buf
, "none", len
);
7123 ast_log(LOG_WARNING
, "%s only supported on analog channels\n", data
);
7127 ast_mutex_unlock(&p
->lock
);
7137 static int parse_buffers_policy(const char *parse
, int *num_buffers
, int *policy
)
7140 char policy_str
[21] = "";
7142 if ((res
= sscanf(parse
, "%30d,%20s", num_buffers
, policy_str
)) != 2) {
7143 ast_log(LOG_WARNING
, "Parsing buffer string '%s' failed.\n", parse
);
7146 if (*num_buffers
< 0) {
7147 ast_log(LOG_WARNING
, "Invalid buffer count given '%d'.\n", *num_buffers
);
7150 if (!strcasecmp(policy_str
, "full")) {
7151 *policy
= DAHDI_POLICY_WHEN_FULL
;
7152 } else if (!strcasecmp(policy_str
, "immediate")) {
7153 *policy
= DAHDI_POLICY_IMMEDIATE
;
7154 #if defined(HAVE_DAHDI_HALF_FULL)
7155 } else if (!strcasecmp(policy_str
, "half")) {
7156 *policy
= DAHDI_POLICY_HALF_FULL
;
7159 ast_log(LOG_WARNING
, "Invalid policy name given '%s'.\n", policy_str
);
7166 static int dahdi_func_write(struct ast_channel
*chan
, const char *function
, char *data
, const char *value
)
7168 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
7172 /* No private structure! */
7176 if (!strcasecmp(data
, "buffers")) {
7177 int num_bufs
, policy
;
7179 if (!(parse_buffers_policy(value
, &num_bufs
, &policy
))) {
7180 struct dahdi_bufferinfo bi
= {
7181 .txbufpolicy
= policy
,
7182 .rxbufpolicy
= policy
,
7183 .bufsize
= p
->bufsize
,
7184 .numbufs
= num_bufs
,
7188 if ((bpres
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
7189 ast_log(LOG_WARNING
, "Channel '%d' unable to override buffer policy: %s\n", p
->channel
, strerror(errno
));
7191 p
->bufferoverrideinuse
= 1;
7196 } else if (!strcasecmp(data
, "echocan_mode")) {
7197 if (!strcasecmp(value
, "on")) {
7198 ast_mutex_lock(&p
->lock
);
7200 ast_mutex_unlock(&p
->lock
);
7201 } else if (!strcasecmp(value
, "off")) {
7202 ast_mutex_lock(&p
->lock
);
7203 dahdi_ec_disable(p
);
7204 ast_mutex_unlock(&p
->lock
);
7205 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7206 } else if (!strcasecmp(value
, "fax")) {
7209 ast_mutex_lock(&p
->lock
);
7210 if (!p
->echocanon
) {
7213 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOCANCEL_FAX_MODE
, &blah
)) {
7214 ast_log(LOG_WARNING
, "Unable to place echocan into fax mode on channel %d: %s\n", p
->channel
, strerror(errno
));
7216 ast_mutex_unlock(&p
->lock
);
7217 } else if (!strcasecmp(value
, "voice")) {
7220 ast_mutex_lock(&p
->lock
);
7221 if (!p
->echocanon
) {
7224 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOCANCEL_FAX_MODE
, &blah
)) {
7225 ast_log(LOG_WARNING
, "Unable to place echocan into voice mode on channel %d: %s\n", p
->channel
, strerror(errno
));
7227 ast_mutex_unlock(&p
->lock
);
7230 ast_log(LOG_WARNING
, "Unsupported value '%s' provided for '%s' item.\n", value
, data
);
7233 } else if (!strcasecmp(data
, "dialmode")) {
7234 struct analog_pvt
*analog_p
;
7236 ast_mutex_lock(&p
->lock
);
7237 analog_p
= p
->sig_pvt
;
7238 if (!dahdi_analog_lib_handles(p
->sig
, 0, 0) || !analog_p
) {
7239 ast_log(LOG_WARNING
, "%s only supported on analog channels\n", data
);
7240 ast_mutex_unlock(&p
->lock
);
7243 /* analog pvt is used for pulse dialing, so update both */
7244 if (!strcasecmp(value
, "pulse")) {
7245 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_PULSE
;
7246 } else if (!strcasecmp(value
, "dtmf") || !strcasecmp(value
, "tone")) {
7247 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_DTMF
;
7248 } else if (!strcasecmp(value
, "none")) {
7249 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_NONE
;
7250 } else if (!strcasecmp(value
, "both")) {
7251 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_BOTH
;
7253 ast_log(LOG_WARNING
, "'%s' is an invalid setting for %s\n", value
, data
);
7256 ast_mutex_unlock(&p
->lock
);
7264 void dahdi_master_slave_unlink(struct dahdi_pvt
*slave
, struct dahdi_pvt
*master
, int needlock
)
7266 /* Unlink a specific slave or all slaves/masters from a given master */
7272 ast_mutex_lock(&master
->lock
);
7274 while (ast_mutex_trylock(&slave
->lock
)) {
7275 DEADLOCK_AVOIDANCE(&master
->lock
);
7280 for (x
= 0; x
< MAX_SLAVES
; x
++) {
7281 if (master
->slaves
[x
]) {
7282 if (!slave
|| (master
->slaves
[x
] == slave
)) {
7283 /* Take slave out of the conference */
7284 ast_debug(1, "Unlinking slave %d from %d\n", master
->slaves
[x
]->channel
, master
->channel
);
7285 conf_del(master
, &master
->slaves
[x
]->subs
[SUB_REAL
], SUB_REAL
);
7286 conf_del(master
->slaves
[x
], &master
->subs
[SUB_REAL
], SUB_REAL
);
7287 master
->slaves
[x
]->master
= NULL
;
7288 master
->slaves
[x
] = NULL
;
7293 master
->inconference
= 0;
7296 if (master
->master
) {
7297 /* Take master out of the conference */
7298 conf_del(master
->master
, &master
->subs
[SUB_REAL
], SUB_REAL
);
7299 conf_del(master
, &master
->master
->subs
[SUB_REAL
], SUB_REAL
);
7301 for (x
= 0; x
< MAX_SLAVES
; x
++) {
7302 if (master
->master
->slaves
[x
] == master
)
7303 master
->master
->slaves
[x
] = NULL
;
7304 else if (master
->master
->slaves
[x
])
7308 master
->master
->inconference
= 0;
7310 master
->master
= NULL
;
7312 dahdi_conf_update(master
);
7315 ast_mutex_unlock(&slave
->lock
);
7316 ast_mutex_unlock(&master
->lock
);
7320 void dahdi_master_slave_link(struct dahdi_pvt
*slave
, struct dahdi_pvt
*master
)
7323 if (!slave
|| !master
) {
7324 ast_log(LOG_WARNING
, "Tried to link to/from NULL??\n");
7327 for (x
= 0; x
< MAX_SLAVES
; x
++) {
7328 if (!master
->slaves
[x
]) {
7329 master
->slaves
[x
] = slave
;
7333 if (x
>= MAX_SLAVES
) {
7334 ast_log(LOG_WARNING
, "Replacing slave %d with new slave, %d\n", master
->slaves
[MAX_SLAVES
- 1]->channel
, slave
->channel
);
7335 master
->slaves
[MAX_SLAVES
- 1] = slave
;
7338 ast_log(LOG_WARNING
, "Replacing master %d with new master, %d\n", slave
->master
->channel
, master
->channel
);
7339 slave
->master
= master
;
7341 ast_debug(1, "Making %d slave to master %d at %d\n", slave
->channel
, master
->channel
, x
);
7344 static int dahdi_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
)
7346 struct dahdi_pvt
*p
= ast_channel_tech_pvt(newchan
);
7349 ast_mutex_lock(&p
->lock
);
7351 ast_debug(1, "New owner for channel %d is %s\n", p
->channel
, ast_channel_name(newchan
));
7352 if (p
->owner
== oldchan
) {
7355 for (x
= 0; x
< 3; x
++) {
7356 if (p
->subs
[x
].owner
== oldchan
) {
7358 dahdi_master_slave_unlink(NULL
, p
, 0);
7360 p
->subs
[x
].owner
= newchan
;
7363 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
7364 analog_fixup(oldchan
, newchan
, p
->sig_pvt
);
7365 #if defined(HAVE_PRI)
7366 } else if (dahdi_sig_pri_lib_handles(p
->sig
)) {
7367 sig_pri_fixup(oldchan
, newchan
, p
->sig_pvt
);
7368 #endif /* defined(HAVE_PRI) */
7369 #if defined(HAVE_SS7)
7370 } else if (p
->sig
== SIG_SS7
) {
7371 sig_ss7_fixup(oldchan
, newchan
, p
->sig_pvt
);
7372 #endif /* defined(HAVE_SS7) */
7374 dahdi_conf_update(p
);
7376 ast_mutex_unlock(&p
->lock
);
7378 if (ast_channel_state(newchan
) == AST_STATE_RINGING
) {
7379 dahdi_indicate(newchan
, AST_CONTROL_RINGING
, NULL
, 0);
7384 static int dahdi_ring_phone(struct dahdi_pvt
*p
)
7388 /* Make sure our transmit state is on hook */
7391 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
7394 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
7399 /* Wait just in case */
7406 ast_log(LOG_WARNING
, "Couldn't ring the phone: %s\n", strerror(errno
));
7414 static void *analog_ss_thread(void *data
);
7418 * \brief Attempt to transfer 3-way call.
7420 * \param p DAHDI private structure.
7422 * \note On entry these locks are held: real-call, private, 3-way call.
7423 * \note On exit these locks are held: real-call, private.
7425 * \retval 0 on success.
7426 * \retval -1 on error.
7428 static int attempt_transfer(struct dahdi_pvt
*p
)
7430 struct ast_channel
*owner_real
;
7431 struct ast_channel
*owner_3way
;
7432 enum ast_transfer_result xfer_res
;
7435 owner_real
= ast_channel_ref(p
->subs
[SUB_REAL
].owner
);
7436 owner_3way
= ast_channel_ref(p
->subs
[SUB_THREEWAY
].owner
);
7438 ast_verb(3, "TRANSFERRING %s to %s\n",
7439 ast_channel_name(owner_3way
), ast_channel_name(owner_real
));
7441 ast_channel_unlock(owner_real
);
7442 ast_channel_unlock(owner_3way
);
7443 ast_mutex_unlock(&p
->lock
);
7445 xfer_res
= ast_bridge_transfer_attended(owner_3way
, owner_real
);
7446 if (xfer_res
!= AST_BRIDGE_TRANSFER_SUCCESS
) {
7447 ast_softhangup(owner_3way
, AST_SOFTHANGUP_DEV
);
7451 /* Must leave with these locked. */
7452 ast_channel_lock(owner_real
);
7453 ast_mutex_lock(&p
->lock
);
7455 ast_channel_unref(owner_real
);
7456 ast_channel_unref(owner_3way
);
7461 static int check_for_conference(struct dahdi_pvt
*p
)
7463 struct dahdi_confinfo ci
;
7464 /* Fine if we already have a master, etc */
7465 if (p
->master
|| (p
->confno
> -1))
7467 memset(&ci
, 0, sizeof(ci
));
7468 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONF
, &ci
)) {
7469 ast_log(LOG_WARNING
, "Failed to get conference info on channel %d: %s\n", p
->channel
, strerror(errno
));
7472 /* If we have no master and don't have a confno, then
7473 if we're in a conference, it's probably a MeetMe room or
7474 some such, so don't let us 3-way out! */
7475 if ((p
->subs
[SUB_REAL
].curconf
.confno
!= ci
.confno
) || (p
->subs
[SUB_REAL
].curconf
.confmode
!= ci
.confmode
)) {
7476 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
7482 /*! Checks channel for alarms
7483 * \param p a channel to check for alarms.
7484 * \returns the alarms on the span to which the channel belongs, or alarms on
7485 * the channel if no span alarms.
7487 static int get_alarms(struct dahdi_pvt
*p
)
7490 struct dahdi_spaninfo zi
;
7491 struct dahdi_params params
;
7493 memset(&zi
, 0, sizeof(zi
));
7494 zi
.spanno
= p
->span
;
7496 if ((res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SPANSTAT
, &zi
)) >= 0) {
7497 if (zi
.alarms
!= DAHDI_ALARM_NONE
)
7500 ast_log(LOG_WARNING
, "Unable to determine alarm on channel %d: %s\n", p
->channel
, strerror(errno
));
7504 /* No alarms on the span. Check for channel alarms. */
7505 memset(¶ms
, 0, sizeof(params
));
7506 if ((res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, ¶ms
)) >= 0)
7507 return params
.chan_alarms
;
7509 ast_log(LOG_WARNING
, "Unable to determine alarm on channel %d\n", p
->channel
);
7511 return DAHDI_ALARM_NONE
;
7514 static void dahdi_handle_dtmf(struct ast_channel
*ast
, int idx
, struct ast_frame
**dest
)
7516 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
7517 struct ast_frame
*f
= *dest
;
7519 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
7520 f
->frametype
== AST_FRAME_DTMF_BEGIN
? "Begin" : "End",
7521 (unsigned)f
->subclass
.integer
, f
->subclass
.integer
, ast_channel_name(ast
));
7523 if (p
->confirmanswer
) {
7524 if (f
->frametype
== AST_FRAME_DTMF_END
) {
7525 ast_debug(1, "Confirm answer on %s!\n", ast_channel_name(ast
));
7526 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
7528 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7529 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
7530 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
7531 p
->confirmanswer
= 0;
7533 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7534 p
->subs
[idx
].f
.subclass
.integer
= 0;
7536 *dest
= &p
->subs
[idx
].f
;
7537 } else if (p
->callwaitcas
) {
7538 if (f
->frametype
== AST_FRAME_DTMF_END
) {
7539 if ((f
->subclass
.integer
== 'A') || (f
->subclass
.integer
== 'D')) {
7540 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
7541 ast_free(p
->cidspill
);
7547 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7548 p
->subs
[idx
].f
.subclass
.integer
= 0;
7549 *dest
= &p
->subs
[idx
].f
;
7550 } else if (f
->subclass
.integer
== 'f') {
7551 if (f
->frametype
== AST_FRAME_DTMF_END
) {
7552 /* Fax tone -- Handle and return NULL */
7553 if ((p
->callprogress
& CALLPROGRESS_FAX
) && !p
->faxhandled
) {
7554 /* If faxbuffers are configured, use them for the fax transmission */
7555 if (p
->usefaxbuffers
&& !p
->bufferoverrideinuse
) {
7556 struct dahdi_bufferinfo bi
= {
7557 .txbufpolicy
= p
->faxbuf_policy
,
7558 .bufsize
= p
->bufsize
,
7559 .numbufs
= p
->faxbuf_no
7563 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
7564 ast_log(LOG_WARNING
, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast
), strerror(errno
));
7566 p
->bufferoverrideinuse
= 1;
7571 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
7572 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
7573 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast
));
7575 if (strcmp(ast_channel_exten(ast
), "fax")) {
7576 const char *target_context
= ast_channel_context(ast
);
7579 * We need to unlock 'ast' here because ast_exists_extension has the
7580 * potential to start autoservice on the channel. Such action is prone
7581 * to deadlock if the channel is locked.
7583 * ast_async_goto() has its own restriction on not holding the
7586 ast_mutex_unlock(&p
->lock
);
7587 ast_channel_unlock(ast
);
7588 if (ast_exists_extension(ast
, target_context
, "fax", 1,
7589 S_COR(ast_channel_caller(ast
)->id
.number
.valid
, ast_channel_caller(ast
)->id
.number
.str
, NULL
))) {
7590 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast
));
7591 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
7592 pbx_builtin_setvar_helper(ast
, "FAXEXTEN", ast_channel_exten(ast
));
7593 if (ast_async_goto(ast
, target_context
, "fax", 1))
7594 ast_log(LOG_WARNING
, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast
), target_context
);
7596 ast_log(LOG_NOTICE
, "Fax detected, but no fax extension\n");
7598 ast_channel_lock(ast
);
7599 ast_mutex_lock(&p
->lock
);
7601 ast_debug(1, "Already in a fax extension, not redirecting\n");
7604 ast_debug(1, "Fax already handled\n");
7606 dahdi_confmute(p
, 0);
7608 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7609 p
->subs
[idx
].f
.subclass
.integer
= 0;
7610 *dest
= &p
->subs
[idx
].f
;
7614 static void publish_span_alarm(int span
, const char *alarm_txt
)
7616 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
7618 body
= ast_json_pack("{s: i, s: s}",
7620 "Alarm", alarm_txt
);
7625 ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM
, body
);
7628 static void publish_channel_alarm(int channel
, const char *alarm_txt
)
7630 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
7631 RAII_VAR(struct ast_str
*, dahdi_chan
, ast_str_create(32), ast_free
);
7636 ast_str_set(&dahdi_chan
, 0, "%d", channel
);
7637 body
= ast_json_pack("{s: s, s: s}",
7638 "DAHDIChannel", ast_str_buffer(dahdi_chan
),
7639 "Alarm", alarm_txt
);
7644 ast_manager_publish_event("Alarm", EVENT_FLAG_SYSTEM
, body
);
7647 static void handle_alarms(struct dahdi_pvt
*p
, int alms
)
7649 const char *alarm_str
;
7651 #if defined(HAVE_PRI)
7652 if (dahdi_sig_pri_lib_handles(p
->sig
) && sig_pri_is_alarm_ignored(p
->pri
)) {
7655 #endif /* defined(HAVE_PRI) */
7657 alarm_str
= alarm2str(alms
);
7658 if (report_alarms
& REPORT_CHANNEL_ALARMS
) {
7659 ast_log(LOG_WARNING
, "Detected alarm on channel %d: %s\n", p
->channel
, alarm_str
);
7660 publish_channel_alarm(p
->channel
, alarm_str
);
7663 if (report_alarms
& REPORT_SPAN_ALARMS
&& p
->manages_span_alarms
) {
7664 ast_log(LOG_WARNING
, "Detected alarm on span %d: %s\n", p
->span
, alarm_str
);
7665 publish_span_alarm(p
->span
, alarm_str
);
7669 static struct ast_frame
*dahdi_handle_event(struct ast_channel
*ast
)
7674 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
7676 struct ast_channel
*chan
;
7677 struct ast_frame
*f
;
7679 idx
= dahdi_get_index(ast
, p
, 0);
7681 return &ast_null_frame
;
7684 if (p
->outsigmod
> -1)
7685 mysig
= p
->outsigmod
;
7686 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7687 p
->subs
[idx
].f
.subclass
.integer
= 0;
7688 p
->subs
[idx
].f
.datalen
= 0;
7689 p
->subs
[idx
].f
.samples
= 0;
7690 p
->subs
[idx
].f
.mallocd
= 0;
7691 p
->subs
[idx
].f
.offset
= 0;
7692 p
->subs
[idx
].f
.src
= "dahdi_handle_event";
7693 p
->subs
[idx
].f
.data
.ptr
= NULL
;
7694 f
= &p
->subs
[idx
].f
;
7696 if (p
->fake_event
) {
7697 res
= p
->fake_event
;
7700 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
7702 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res
), res
, p
->channel
, idx
);
7704 if (res
& (DAHDI_EVENT_PULSEDIGIT
| DAHDI_EVENT_DTMFUP
)) {
7705 p
->pulsedial
= (res
& DAHDI_EVENT_PULSEDIGIT
) ? 1 : 0;
7706 ast_debug(1, "Detected %sdigit '%c'\n", p
->pulsedial
? "pulse ": "", res
& 0xff);
7707 #if defined(HAVE_PRI)
7708 if (dahdi_sig_pri_lib_handles(p
->sig
)
7709 && ((struct sig_pri_chan
*) p
->sig_pvt
)->call_level
< SIG_PRI_CALL_LEVEL_PROCEEDING
7711 && (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_INCOMING
)) {
7714 #endif /* defined(HAVE_PRI) */
7716 /* Unmute conference */
7717 dahdi_confmute(p
, 0);
7718 p
->subs
[idx
].f
.frametype
= AST_FRAME_DTMF_END
;
7719 p
->subs
[idx
].f
.subclass
.integer
= res
& 0xff;
7720 dahdi_handle_dtmf(ast
, idx
, &f
);
7725 if (res
& DAHDI_EVENT_DTMFDOWN
) {
7726 ast_debug(1, "DTMF Down '%c'\n", res
& 0xff);
7727 #if defined(HAVE_PRI)
7728 if (dahdi_sig_pri_lib_handles(p
->sig
)
7729 && ((struct sig_pri_chan
*) p
->sig_pvt
)->call_level
< SIG_PRI_CALL_LEVEL_PROCEEDING
7731 && (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_INCOMING
)) {
7734 #endif /* defined(HAVE_PRI) */
7736 /* Mute conference */
7737 dahdi_confmute(p
, 1);
7738 p
->subs
[idx
].f
.frametype
= AST_FRAME_DTMF_BEGIN
;
7739 p
->subs
[idx
].f
.subclass
.integer
= res
& 0xff;
7740 dahdi_handle_dtmf(ast
, idx
, &f
);
7742 return &p
->subs
[idx
].f
;
7746 case DAHDI_EVENT_EC_DISABLED
:
7747 ast_verb(3, "Channel %d echo canceler disabled.\n", p
->channel
);
7750 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7751 case DAHDI_EVENT_TX_CED_DETECTED
:
7752 ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p
->channel
);
7754 case DAHDI_EVENT_RX_CED_DETECTED
:
7755 ast_verb(3, "Channel %d detected a CED tone from the network.\n", p
->channel
);
7757 case DAHDI_EVENT_EC_NLP_DISABLED
:
7758 ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p
->channel
);
7760 case DAHDI_EVENT_EC_NLP_ENABLED
:
7761 ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p
->channel
);
7764 case DAHDI_EVENT_BITSCHANGED
:
7766 if (p
->sig
!= SIG_MFCR2
) {
7767 ast_log(LOG_WARNING
, "Received bits changed on %s signalling?\n", sig2str(p
->sig
));
7769 ast_debug(1, "bits changed in chan %d\n", p
->channel
);
7770 openr2_chan_handle_cas(p
->r2chan
);
7773 ast_log(LOG_WARNING
, "Received bits changed on %s signalling?\n", sig2str(p
->sig
));
7776 case DAHDI_EVENT_PULSE_START
:
7777 /* Stop tone if there's a pulse start and the PBX isn't started */
7778 if (!ast_channel_pbx(ast
))
7779 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
7781 case DAHDI_EVENT_DIALCOMPLETE
:
7782 /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
7783 #if defined(HAVE_PRI)
7784 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
7788 if (ioctl(p
->subs
[idx
].dfd
, DAHDI_DIALING
, &x
) == -1) {
7789 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
7790 ast_channel_name(ast
), strerror(errno
));
7794 /* Still dialing in DAHDI driver */
7798 * The ast channel is locked and the private may be locked more
7801 sig_pri_dial_complete(p
->sig_pvt
, ast
);
7804 #endif /* defined(HAVE_PRI) */
7806 if ((p
->sig
& SIG_MFCR2
) && p
->r2chan
&& ast_channel_state(ast
) != AST_STATE_UP
) {
7807 /* we don't need to do anything for this event for R2 signaling
7808 if the call is being setup */
7812 if (p
->inalarm
) break;
7813 if ((p
->radio
|| (p
->oprmode
< 0))) break;
7814 if (ioctl(p
->subs
[idx
].dfd
,DAHDI_DIALING
,&x
) == -1) {
7815 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",ast_channel_name(ast
), strerror(errno
));
7818 if (!x
) { /* if not still dialing in driver */
7822 ast_copy_string(p
->dop
.dialstr
, p
->echorest
, sizeof(p
->dop
.dialstr
));
7823 p
->dop
.op
= DAHDI_DIAL_OP_REPLACE
;
7824 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
7828 if ((mysig
== SIG_E911
) || (mysig
== SIG_FGC_CAMA
) || (mysig
== SIG_FGC_CAMAMF
)) {
7829 /* if thru with dialing after offhook */
7830 if (ast_channel_state(ast
) == AST_STATE_DIALING_OFFHOOK
) {
7831 ast_setstate(ast
, AST_STATE_UP
);
7832 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7833 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
7835 } else { /* if to state wait for offhook to dial rest */
7836 /* we now wait for off hook */
7837 ast_setstate(ast
,AST_STATE_DIALING_OFFHOOK
);
7840 if (ast_channel_state(ast
) == AST_STATE_DIALING
) {
7841 if ((p
->callprogress
& CALLPROGRESS_PROGRESS
) && CANPROGRESSDETECT(p
) && p
->dsp
&& p
->outgoing
) {
7842 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
7843 } else if (p
->confirmanswer
|| (!p
->dialednone
7844 && ((mysig
== SIG_EM
) || (mysig
== SIG_EM_E1
)
7845 || (mysig
== SIG_EMWINK
) || (mysig
== SIG_FEATD
)
7846 || (mysig
== SIG_FEATDMF_TA
) || (mysig
== SIG_FEATDMF
)
7847 || (mysig
== SIG_E911
) || (mysig
== SIG_FGC_CAMA
)
7848 || (mysig
== SIG_FGC_CAMAMF
) || (mysig
== SIG_FEATB
)
7849 || (mysig
== SIG_SF
) || (mysig
== SIG_SFWINK
)
7850 || (mysig
== SIG_SF_FEATD
) || (mysig
== SIG_SF_FEATDMF
)
7851 || (mysig
== SIG_SF_FEATB
)))) {
7852 ast_setstate(ast
, AST_STATE_RINGING
);
7853 } else if (!p
->answeronpolarityswitch
) {
7854 ast_setstate(ast
, AST_STATE_UP
);
7855 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7856 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
7857 /* If aops=0 and hops=1, this is necessary */
7858 p
->polarity
= POLARITY_REV
;
7860 /* Start clean, so we can catch the change to REV polarity when party answers */
7861 p
->polarity
= POLARITY_IDLE
;
7867 case DAHDI_EVENT_ALARM
:
7869 #if defined(HAVE_PRI)
7870 case SIG_PRI_LIB_HANDLE_CASES
:
7871 sig_pri_chan_alarm_notify(p
->sig_pvt
, 0);
7873 #endif /* defined(HAVE_PRI) */
7874 #if defined(HAVE_SS7)
7876 sig_ss7_set_alarm(p
->sig_pvt
, 1);
7878 #endif /* defined(HAVE_SS7) */
7883 res
= get_alarms(p
);
7884 handle_alarms(p
, res
);
7886 if (!p
->pri
|| !p
->pri
->pri
|| pri_get_timer(p
->pri
->pri
, PRI_TIMER_T309
) < 0) {
7887 /* fall through intentionally */
7892 #if defined(HAVE_SS7)
7893 if (p
->sig
== SIG_SS7
)
7895 #endif /* defined(HAVE_SS7) */
7897 if (p
->sig
== SIG_MFCR2
)
7900 case DAHDI_EVENT_ONHOOK
:
7902 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7903 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_UNKEY
;
7908 if (p
->oprmode
!= -1) { /* Operator flash recall */
7909 ast_verb(4, "Operator mode enabled on channel %d, holding line for channel %d\n", p
->channel
, p
->oprpeer
->channel
);
7912 /* Otherwise, immediate recall */
7913 if ((p
->sig
== SIG_FXOLS
) || (p
->sig
== SIG_FXOKS
) || (p
->sig
== SIG_FXOGS
))
7915 /* Make sure it starts ringing */
7916 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
);
7917 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_RING
);
7918 save_conference(p
->oprpeer
);
7919 tone_zone_play_tone(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_RINGTONE
);
7920 ast_verb(4, "Operator recall, channel %d ringing back channel %d\n", p
->oprpeer
->channel
, p
->channel
);
7928 /* Check for some special conditions regarding call waiting */
7929 if (idx
== SUB_REAL
) {
7930 /* The normal line was hung up */
7931 if (p
->subs
[SUB_CALLWAIT
].owner
) {
7932 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
7933 swap_subs(p
, SUB_CALLWAIT
, SUB_REAL
);
7934 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p
->channel
);
7935 unalloc_sub(p
, SUB_CALLWAIT
);
7937 p
->subs
[idx
].needanswer
= 0;
7938 p
->subs
[idx
].needringing
= 0;
7940 p
->callwaitingrepeat
= 0;
7942 p
->cid_suppress_expire
= 0;
7944 /* Don't start streaming audio yet if the incoming call isn't up yet */
7945 if (ast_channel_state(p
->subs
[SUB_REAL
].owner
) != AST_STATE_UP
)
7947 dahdi_ring_phone(p
);
7948 } else if (p
->subs
[SUB_THREEWAY
].owner
) {
7949 unsigned int mssinceflash
;
7950 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
7951 the private structure -- not especially easy or clean */
7952 while (p
->subs
[SUB_THREEWAY
].owner
&& ast_channel_trylock(p
->subs
[SUB_THREEWAY
].owner
)) {
7953 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
7954 DLA_UNLOCK(&p
->lock
);
7955 CHANNEL_DEADLOCK_AVOIDANCE(ast
);
7956 /* We can grab ast and p in that order, without worry. We should make sure
7957 nothing seriously bad has happened though like some sort of bizarre double
7960 if (p
->owner
!= ast
) {
7961 ast_log(LOG_WARNING
, "This isn't good...\n");
7965 if (!p
->subs
[SUB_THREEWAY
].owner
) {
7966 ast_log(LOG_NOTICE
, "Whoa, threeway disappeared kinda randomly.\n");
7969 mssinceflash
= ast_tvdiff_ms(ast_tvnow(), p
->flashtime
);
7970 ast_debug(1, "Last flash was %u ms ago\n", mssinceflash
);
7971 if (mssinceflash
< MIN_MS_SINCE_FLASH
) {
7972 /* It hasn't been long enough since the last flashook. This is probably a bounce on
7973 hanging up. Hangup both channels now */
7974 if (p
->subs
[SUB_THREEWAY
].owner
)
7975 ast_queue_hangup_with_cause(p
->subs
[SUB_THREEWAY
].owner
, AST_CAUSE_NO_ANSWER
);
7976 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
7977 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p
->channel
);
7978 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
7979 } else if ((ast_channel_pbx(ast
)) || (ast_channel_state(ast
) == AST_STATE_UP
)) {
7981 /* In any case this isn't a threeway call anymore */
7982 p
->subs
[SUB_REAL
].inthreeway
= 0;
7983 p
->subs
[SUB_THREEWAY
].inthreeway
= 0;
7984 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
7985 if (!p
->transfertobusy
&& ast_channel_state(ast
) == AST_STATE_BUSY
) {
7986 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
7987 /* Swap subs and dis-own channel */
7988 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
7990 /* Ring the phone */
7991 dahdi_ring_phone(p
);
7992 } else if (!attempt_transfer(p
)) {
7994 * Transfer successful. Don't actually hang up at this point.
7995 * Let our channel legs of the calls die off as the transfer
7996 * percolates through the core.
8001 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
8002 if (p
->subs
[SUB_THREEWAY
].owner
)
8003 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
8006 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
8007 /* Swap subs and dis-own channel */
8008 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8010 /* Ring the phone */
8011 dahdi_ring_phone(p
);
8015 ast_log(LOG_WARNING
, "Got a hangup and my index is %d?\n", idx
);
8019 dahdi_ec_disable(p
);
8023 case DAHDI_EVENT_RINGOFFHOOK
:
8024 if (p
->inalarm
) break;
8027 if ((p
->sig
== SIG_FXOLS
) || (p
->sig
== SIG_FXOKS
) || (p
->sig
== SIG_FXOGS
))
8029 /* Make sure it stops ringing */
8030 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
);
8031 tone_zone_play_tone(p
->oprpeer
->subs
[SUB_REAL
].dfd
, -1);
8032 restore_conference(p
->oprpeer
);
8033 ast_debug(1, "Operator recall by channel %d for channel %d complete\n", p
->oprpeer
->channel
, p
->channel
);
8039 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8040 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_KEY
;
8043 /* for E911, its supposed to wait for offhook then dial
8044 the second half of the dial string */
8045 if (((mysig
== SIG_E911
) || (mysig
== SIG_FGC_CAMA
) || (mysig
== SIG_FGC_CAMAMF
)) && (ast_channel_state(ast
) == AST_STATE_DIALING_OFFHOOK
)) {
8046 c
= strchr(p
->dialdest
, '/');
8053 int numchars
= snprintf(p
->dop
.dialstr
, sizeof(p
->dop
.dialstr
), "M*0%s#", c
);
8054 if (numchars
>= sizeof(p
->dop
.dialstr
)) {
8055 ast_log(LOG_WARNING
, "Dial string '%s' truncated\n", c
);
8058 ast_copy_string(p
->dop
.dialstr
,"M*2#", sizeof(p
->dop
.dialstr
));
8061 if (strlen(p
->dop
.dialstr
) > 4) {
8062 memset(p
->echorest
, 'w', sizeof(p
->echorest
) - 1);
8063 strcpy(p
->echorest
+ (p
->echotraining
/ 401) + 1, p
->dop
.dialstr
+ strlen(p
->dop
.dialstr
) - 2);
8064 p
->echorest
[sizeof(p
->echorest
) - 1] = '\0';
8066 p
->dop
.dialstr
[strlen(p
->dop
.dialstr
)-2] = '\0';
8069 if (dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
)) {
8071 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
8075 return &p
->subs
[idx
].f
;
8081 switch (ast_channel_state(ast
)) {
8082 case AST_STATE_RINGING
:
8085 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8086 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
8087 /* Make sure it stops ringing */
8088 p
->subs
[SUB_REAL
].needringing
= 0;
8089 dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_OFFHOOK
);
8090 ast_debug(1, "channel %d answered\n", p
->channel
);
8092 /* Cancel any running CallerID spill */
8093 ast_free(p
->cidspill
);
8095 restore_conference(p
);
8099 if (p
->confirmanswer
) {
8100 /* Ignore answer if "confirm answer" is enabled */
8101 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8102 p
->subs
[idx
].f
.subclass
.integer
= 0;
8103 } else if (!ast_strlen_zero(p
->dop
.dialstr
)) {
8104 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
8105 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
8107 p
->dop
.dialstr
[0] = '\0';
8110 ast_debug(1, "Sent FXO deferred digit string: %s\n", p
->dop
.dialstr
);
8111 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8112 p
->subs
[idx
].f
.subclass
.integer
= 0;
8115 p
->dop
.dialstr
[0] = '\0';
8116 ast_setstate(ast
, AST_STATE_DIALING
);
8118 ast_setstate(ast
, AST_STATE_UP
);
8119 return &p
->subs
[idx
].f
;
8120 case AST_STATE_DOWN
:
8121 ast_setstate(ast
, AST_STATE_RING
);
8122 ast_channel_rings_set(ast
, 1);
8123 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8124 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_OFFHOOK
;
8125 ast_debug(1, "channel %d picked up\n", p
->channel
);
8126 return &p
->subs
[idx
].f
;
8128 /* Make sure it stops ringing */
8129 dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_OFFHOOK
);
8130 /* Okay -- probably call waiting*/
8131 ast_queue_unhold(p
->owner
);
8132 p
->subs
[idx
].needunhold
= 1;
8134 case AST_STATE_RESERVED
:
8135 /* Start up dialtone */
8136 if (has_voicemail(p
))
8137 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_STUTTER
);
8139 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_DIALTONE
);
8142 ast_log(LOG_WARNING
, "FXO phone off hook in weird state %u??\n", ast_channel_state(ast
));
8148 if (ast_channel_state(ast
) == AST_STATE_RING
) {
8149 p
->ringt
= p
->ringt_base
;
8152 /* If we get a ring then we cannot be in
8153 * reversed polarity. So we reset to idle */
8154 ast_debug(1, "Setting IDLE polarity due "
8155 "to ring. Old polarity was %d\n",
8157 p
->polarity
= POLARITY_IDLE
;
8165 case SIG_FEATDMF_TA
:
8168 case SIG_FGC_CAMAMF
:
8173 case SIG_SF_FEATDMF
:
8175 if (ast_channel_state(ast
) == AST_STATE_PRERING
)
8176 ast_setstate(ast
, AST_STATE_RING
);
8177 if ((ast_channel_state(ast
) == AST_STATE_DOWN
) || (ast_channel_state(ast
) == AST_STATE_RING
)) {
8178 ast_debug(1, "Ring detected\n");
8179 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8180 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RING
;
8181 } else if (p
->outgoing
&& ((ast_channel_state(ast
) == AST_STATE_RINGING
) || (ast_channel_state(ast
) == AST_STATE_DIALING
))) {
8182 ast_debug(1, "Line answered\n");
8183 if (p
->confirmanswer
) {
8184 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8185 p
->subs
[idx
].f
.subclass
.integer
= 0;
8187 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8188 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
8189 ast_setstate(ast
, AST_STATE_UP
);
8191 } else if (ast_channel_state(ast
) != AST_STATE_RING
)
8192 ast_log(LOG_WARNING
, "Ring/Off-hook in strange state %u on channel %d\n", ast_channel_state(ast
), p
->channel
);
8195 ast_log(LOG_WARNING
, "Don't know how to handle ring/off hook for signalling %d\n", p
->sig
);
8198 case DAHDI_EVENT_RINGBEGIN
:
8203 if (ast_channel_state(ast
) == AST_STATE_RING
) {
8204 p
->ringt
= p
->ringt_base
;
8209 case DAHDI_EVENT_RINGERON
:
8211 case DAHDI_EVENT_NOALARM
:
8213 #if defined(HAVE_PRI)
8214 case SIG_PRI_LIB_HANDLE_CASES
:
8215 sig_pri_chan_alarm_notify(p
->sig_pvt
, 1);
8217 #endif /* defined(HAVE_PRI) */
8218 #if defined(HAVE_SS7)
8220 sig_ss7_set_alarm(p
->sig_pvt
, 0);
8222 #endif /* defined(HAVE_SS7) */
8227 handle_clear_alarms(p
);
8229 case DAHDI_EVENT_WINKFLASH
:
8230 if (p
->inalarm
) break;
8231 if (p
->radio
) break;
8232 if (p
->oprmode
< 0) break;
8235 struct dahdi_params par
;
8237 memset(&par
, 0, sizeof(par
));
8238 if (ioctl(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &par
) != -1)
8240 if (!par
.rxisoffhook
)
8242 /* Make sure it stops ringing */
8243 dahdi_set_hook(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
);
8244 dahdi_set_hook(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_RING
);
8246 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_RINGTONE
);
8247 ast_verb(4, "Operator flash recall, channel %d ringing back channel %d\n", p
->oprpeer
->channel
, p
->channel
);
8252 /* Remember last time we got a flash-hook */
8253 p
->flashtime
= ast_tvnow();
8258 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
8259 idx
, p
->subs
[SUB_REAL
].dfd
, p
->subs
[SUB_CALLWAIT
].dfd
, p
->subs
[SUB_THREEWAY
].dfd
);
8261 /* Cancel any running CallerID spill */
8262 ast_free(p
->cidspill
);
8264 restore_conference(p
);
8267 if (idx
!= SUB_REAL
) {
8268 ast_log(LOG_WARNING
, "Got flash hook with index %d on channel %d?!?\n", idx
, p
->channel
);
8272 if (p
->subs
[SUB_CALLWAIT
].owner
) {
8273 /* Swap to call-wait */
8274 swap_subs(p
, SUB_REAL
, SUB_CALLWAIT
);
8275 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
8276 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8277 ast_debug(1, "Making %s the new owner\n", ast_channel_name(p
->owner
));
8278 if (ast_channel_state(p
->owner
) == AST_STATE_RINGING
) {
8279 ast_setstate(p
->owner
, AST_STATE_UP
);
8280 p
->subs
[SUB_REAL
].needanswer
= 1;
8282 p
->callwaitingrepeat
= 0;
8284 p
->cid_suppress_expire
= 0;
8285 /* Start music on hold if appropriate */
8286 if (!p
->subs
[SUB_CALLWAIT
].inthreeway
) {
8287 ast_queue_hold(p
->subs
[SUB_CALLWAIT
].owner
, p
->mohsuggest
);
8289 p
->subs
[SUB_CALLWAIT
].needhold
= 1;
8290 ast_queue_hold(p
->subs
[SUB_REAL
].owner
, p
->mohsuggest
);
8291 p
->subs
[SUB_REAL
].needunhold
= 1;
8292 } else if (!p
->subs
[SUB_THREEWAY
].owner
) {
8293 if (!p
->threewaycalling
) {
8294 /* Just send a flash if no 3-way calling */
8295 p
->subs
[SUB_REAL
].needflash
= 1;
8297 } else if (!check_for_conference(p
)) {
8298 ast_callid callid
= 0;
8305 if (p
->dahditrcallerid
&& p
->owner
) {
8306 if (ast_channel_caller(p
->owner
)->id
.number
.valid
8307 && ast_channel_caller(p
->owner
)->id
.number
.str
) {
8308 ast_copy_string(cid_num
, ast_channel_caller(p
->owner
)->id
.number
.str
,
8311 if (ast_channel_caller(p
->owner
)->id
.name
.valid
8312 && ast_channel_caller(p
->owner
)->id
.name
.str
) {
8313 ast_copy_string(cid_name
, ast_channel_caller(p
->owner
)->id
.name
.str
,
8317 /* XXX This section needs much more error checking!!! XXX */
8318 /* Start a 3-way call if feasible */
8319 if (!((ast_channel_pbx(ast
)) ||
8320 (ast_channel_state(ast
) == AST_STATE_UP
) ||
8321 (ast_channel_state(ast
) == AST_STATE_RING
))) {
8322 ast_debug(1, "Flash when call not up or ringing\n");
8325 if (alloc_sub(p
, SUB_THREEWAY
)) {
8326 ast_log(LOG_WARNING
, "Unable to allocate three-way subchannel\n");
8329 callid_created
= ast_callid_threadstorage_auto(&callid
);
8333 * We cannot hold the p or ast locks while creating a new
8336 ast_mutex_unlock(&p
->lock
);
8337 ast_channel_unlock(ast
);
8338 chan
= dahdi_new(p
, AST_STATE_RESERVED
, 0, SUB_THREEWAY
, 0, NULL
, NULL
, callid
);
8339 ast_channel_lock(ast
);
8340 ast_mutex_lock(&p
->lock
);
8341 if (p
->dahditrcallerid
) {
8342 if (!p
->origcid_num
)
8343 p
->origcid_num
= ast_strdup(p
->cid_num
);
8344 if (!p
->origcid_name
)
8345 p
->origcid_name
= ast_strdup(p
->cid_name
);
8346 ast_copy_string(p
->cid_num
, cid_num
, sizeof(p
->cid_num
));
8347 ast_copy_string(p
->cid_name
, cid_name
, sizeof(p
->cid_name
));
8349 /* Swap things around between the three-way and real call */
8350 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8351 /* Disable echo canceller for better dialing */
8352 dahdi_ec_disable(p
);
8353 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_DIALRECALL
);
8355 ast_log(LOG_WARNING
, "Unable to start dial recall tone on channel %d\n", p
->channel
);
8358 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", p
->channel
);
8359 } else if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
8360 ast_log(LOG_WARNING
, "Unable to start simple switch on channel %d\n", p
->channel
);
8361 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
8365 ast_verb(3, "Started three way call on channel %d\n", p
->channel
);
8367 /* Start music on hold */
8368 ast_queue_hold(p
->subs
[SUB_THREEWAY
].owner
, p
->mohsuggest
);
8369 p
->subs
[SUB_THREEWAY
].needhold
= 1;
8371 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
8374 /* Already have a 3 way call */
8375 if (p
->subs
[SUB_THREEWAY
].inthreeway
) {
8376 /* Call is already up, drop the last person */
8377 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p
->channel
);
8378 /* If the primary call isn't answered yet, use it */
8379 if ((ast_channel_state(p
->subs
[SUB_REAL
].owner
) != AST_STATE_UP
) && (ast_channel_state(p
->subs
[SUB_THREEWAY
].owner
) == AST_STATE_UP
)) {
8380 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
8381 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8382 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8384 /* Drop the last call and stop the conference */
8385 ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p
->subs
[SUB_THREEWAY
].owner
));
8386 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
8387 p
->subs
[SUB_REAL
].inthreeway
= 0;
8388 p
->subs
[SUB_THREEWAY
].inthreeway
= 0;
8390 /* Lets see what we're up to */
8391 if (((ast_channel_pbx(ast
)) || (ast_channel_state(ast
) == AST_STATE_UP
)) &&
8392 (p
->transfertobusy
|| (ast_channel_state(ast
) != AST_STATE_BUSY
))) {
8393 int otherindex
= SUB_THREEWAY
;
8395 ast_verb(3, "Building conference call with %s and %s\n",
8396 ast_channel_name(p
->subs
[SUB_THREEWAY
].owner
),
8397 ast_channel_name(p
->subs
[SUB_REAL
].owner
));
8398 /* Put them in the threeway, and flip */
8399 p
->subs
[SUB_THREEWAY
].inthreeway
= 1;
8400 p
->subs
[SUB_REAL
].inthreeway
= 1;
8401 if (ast_channel_state(ast
) == AST_STATE_UP
) {
8402 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8403 otherindex
= SUB_REAL
;
8405 if (p
->subs
[otherindex
].owner
) {
8406 ast_queue_unhold(p
->subs
[otherindex
].owner
);
8408 p
->subs
[otherindex
].needunhold
= 1;
8409 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8411 ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p
->subs
[SUB_THREEWAY
].owner
));
8412 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8413 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
8414 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8415 if (p
->subs
[SUB_REAL
].owner
) {
8416 ast_queue_unhold(p
->subs
[SUB_REAL
].owner
);
8418 p
->subs
[SUB_REAL
].needunhold
= 1;
8424 dahdi_conf_update(p
);
8435 ast_debug(1, "Ignoring wink on channel %d\n", p
->channel
);
8437 ast_debug(1, "Got wink in weird state %u on channel %d\n", ast_channel_state(ast
), p
->channel
);
8439 case SIG_FEATDMF_TA
:
8440 switch (p
->whichwink
) {
8442 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p
->owner
)->ani2
,
8443 S_COR(ast_channel_caller(p
->owner
)->ani
.number
.valid
,
8444 ast_channel_caller(p
->owner
)->ani
.number
.str
, ""));
8445 snprintf(p
->dop
.dialstr
, sizeof(p
->dop
.dialstr
), "M*%d%s#",
8446 ast_channel_caller(p
->owner
)->ani2
,
8447 S_COR(ast_channel_caller(p
->owner
)->ani
.number
.valid
,
8448 ast_channel_caller(p
->owner
)->ani
.number
.str
, ""));
8451 ast_copy_string(p
->dop
.dialstr
, p
->finaldial
, sizeof(p
->dop
.dialstr
));
8454 ast_log(LOG_WARNING
, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
8461 case SIG_FGC_CAMAMF
:
8464 case SIG_SF_FEATDMF
:
8467 /* FGD MF and EMWINK *Must* wait for wink */
8468 if (!ast_strlen_zero(p
->dop
.dialstr
)) {
8469 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
8471 p
->dop
.dialstr
[0] = '\0';
8474 ast_debug(1, "Sent deferred digit string: %s\n", p
->dop
.dialstr
);
8476 p
->dop
.dialstr
[0] = '\0';
8479 ast_log(LOG_WARNING
, "Don't know how to handle ring/off hook for signalling %d\n", p
->sig
);
8482 case DAHDI_EVENT_HOOKCOMPLETE
:
8483 if (p
->inalarm
) break;
8484 if ((p
->radio
|| (p
->oprmode
< 0))) break;
8485 if (p
->waitingfordt
.tv_sec
) break;
8487 case SIG_FXSLS
: /* only interesting for FXS */
8497 if (!ast_strlen_zero(p
->dop
.dialstr
)) {
8498 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
8500 p
->dop
.dialstr
[0] = '\0';
8503 ast_debug(1, "Sent deferred digit string: %s\n", p
->dop
.dialstr
);
8505 p
->dop
.dialstr
[0] = '\0';
8506 p
->dop
.op
= DAHDI_DIAL_OP_REPLACE
;
8509 case SIG_FEATDMF_TA
:
8512 case SIG_FGC_CAMAMF
:
8514 case SIG_SF_FEATDMF
:
8516 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p
->channel
);
8522 case DAHDI_EVENT_POLARITY
:
8524 * If we get a Polarity Switch event, check to see
8525 * if we should change the polarity state and
8526 * mark the channel as UP or if this is an indication
8527 * of remote end disconnect.
8529 if (p
->polarity
== POLARITY_IDLE
) {
8530 p
->polarity
= POLARITY_REV
;
8531 if (p
->answeronpolarityswitch
&&
8532 ((ast_channel_state(ast
) == AST_STATE_DIALING
) ||
8533 (ast_channel_state(ast
) == AST_STATE_RINGING
))) {
8534 ast_debug(1, "Answering on polarity switch!\n");
8535 ast_setstate(p
->owner
, AST_STATE_UP
);
8536 if (p
->hanguponpolarityswitch
) {
8537 p
->polaritydelaytv
= ast_tvnow();
8540 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %u\n", p
->channel
, ast_channel_state(ast
));
8542 /* Removed else statement from here as it was preventing hangups from ever happening*/
8543 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
8544 if (p
->hanguponpolarityswitch
&&
8545 (p
->polarityonanswerdelay
> 0) &&
8546 (p
->polarity
== POLARITY_REV
) &&
8547 ((ast_channel_state(ast
) == AST_STATE_UP
) || (ast_channel_state(ast
) == AST_STATE_RING
)) ) {
8548 /* Added log_debug information below to provide a better indication of what is going on */
8549 ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %u, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64
"\n", p
->channel
, ast_channel_state(ast
), p
->polarity
, p
->answeronpolarityswitch
, p
->hanguponpolarityswitch
, p
->polarityonanswerdelay
, ast_tvdiff_ms(ast_tvnow(), p
->polaritydelaytv
) );
8551 if (ast_tvdiff_ms(ast_tvnow(), p
->polaritydelaytv
) > p
->polarityonanswerdelay
) {
8552 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p
->channel
);
8553 ast_softhangup(p
->owner
, AST_SOFTHANGUP_EXPLICIT
);
8554 p
->polarity
= POLARITY_IDLE
;
8556 ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %u\n", p
->channel
, ast_channel_state(ast
));
8559 p
->polarity
= POLARITY_IDLE
;
8560 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %u\n", p
->channel
, ast_channel_state(ast
));
8562 /* Added more log_debug information below to provide a better indication of what is going on */
8563 ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %u, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64
"\n", p
->channel
, ast_channel_state(ast
), p
->polarity
, p
->answeronpolarityswitch
, p
->hanguponpolarityswitch
, p
->polarityonanswerdelay
, ast_tvdiff_ms(ast_tvnow(), p
->polaritydelaytv
) );
8566 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res
, p
->channel
);
8568 return &p
->subs
[idx
].f
;
8571 static struct ast_frame
*__dahdi_exception(struct ast_channel
*ast
)
8575 struct ast_frame
*f
;
8577 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
8579 if ((idx
= dahdi_get_index(ast
, p
, 0)) < 0) {
8583 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8584 p
->subs
[idx
].f
.datalen
= 0;
8585 p
->subs
[idx
].f
.samples
= 0;
8586 p
->subs
[idx
].f
.mallocd
= 0;
8587 p
->subs
[idx
].f
.offset
= 0;
8588 p
->subs
[idx
].f
.subclass
.integer
= 0;
8589 p
->subs
[idx
].f
.delivery
= ast_tv(0,0);
8590 p
->subs
[idx
].f
.src
= "dahdi_exception";
8591 p
->subs
[idx
].f
.data
.ptr
= NULL
;
8594 if ((!p
->owner
) && (!(p
->radio
|| (p
->oprmode
< 0)))) {
8595 /* If nobody owns us, absorb the event appropriately, otherwise
8596 we loop indefinitely. This occurs when, during call waiting, the
8597 other end hangs up our channel so that it no longer exists, but we
8598 have neither FLASH'd nor ONHOOK'd to signify our desire to
8599 change to the other channel. */
8600 if (p
->fake_event
) {
8601 res
= p
->fake_event
;
8604 res
= dahdi_get_event(p
->subs
[SUB_REAL
].dfd
);
8605 /* Switch to real if there is one and this isn't something really silly... */
8606 if ((res
!= DAHDI_EVENT_RINGEROFF
) && (res
!= DAHDI_EVENT_RINGERON
) &&
8607 (res
!= DAHDI_EVENT_HOOKCOMPLETE
)) {
8608 ast_debug(1, "Restoring owner of channel %d on event %d\n", p
->channel
, res
);
8609 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8611 ast_queue_unhold(p
->owner
);
8613 p
->subs
[SUB_REAL
].needunhold
= 1;
8616 case DAHDI_EVENT_ONHOOK
:
8617 dahdi_ec_disable(p
);
8619 ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p
->owner
));
8620 dahdi_ring_phone(p
);
8621 p
->callwaitingrepeat
= 0;
8623 p
->cid_suppress_expire
= 0;
8625 ast_log(LOG_WARNING
, "Absorbed on hook, but nobody is left!?!?\n");
8626 dahdi_conf_update(p
);
8628 case DAHDI_EVENT_RINGOFFHOOK
:
8630 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
8631 if (p
->owner
&& (ast_channel_state(p
->owner
) == AST_STATE_RINGING
)) {
8632 p
->subs
[SUB_REAL
].needanswer
= 1;
8636 case DAHDI_EVENT_HOOKCOMPLETE
:
8637 case DAHDI_EVENT_RINGERON
:
8638 case DAHDI_EVENT_RINGEROFF
:
8641 case DAHDI_EVENT_WINKFLASH
:
8642 p
->flashtime
= ast_tvnow();
8644 ast_verb(3, "Channel %d flashed to other channel %s\n", p
->channel
, ast_channel_name(p
->owner
));
8645 if (ast_channel_state(p
->owner
) != AST_STATE_UP
) {
8646 /* Answer if necessary */
8647 usedindex
= dahdi_get_index(p
->owner
, p
, 0);
8648 if (usedindex
> -1) {
8649 p
->subs
[usedindex
].needanswer
= 1;
8651 ast_setstate(p
->owner
, AST_STATE_UP
);
8653 p
->callwaitingrepeat
= 0;
8655 p
->cid_suppress_expire
= 0;
8656 ast_queue_unhold(p
->owner
);
8657 p
->subs
[SUB_REAL
].needunhold
= 1;
8659 ast_log(LOG_WARNING
, "Absorbed on hook, but nobody is left!?!?\n");
8660 dahdi_conf_update(p
);
8663 ast_log(LOG_WARNING
, "Don't know how to absorb event %s\n", event2str(res
));
8665 f
= &p
->subs
[idx
].f
;
8668 if (!(p
->radio
|| (p
->oprmode
< 0)))
8669 ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast
, 0), p
->channel
);
8670 /* If it's not us, return NULL immediately */
8671 if (ast
!= p
->owner
) {
8673 ast_log(LOG_WARNING
, "We're %s, not %s\n", ast_channel_name(ast
), ast_channel_name(p
->owner
));
8675 f
= &p
->subs
[idx
].f
;
8679 f
= dahdi_handle_event(ast
);
8681 const char *name
= ast_strdupa(ast_channel_name(ast
));
8683 /* Tell the CDR this DAHDI device hung up */
8684 ast_mutex_unlock(&p
->lock
);
8685 ast_channel_unlock(ast
);
8686 ast_set_hangupsource(ast
, name
, 0);
8687 ast_channel_lock(ast
);
8688 ast_mutex_lock(&p
->lock
);
8693 static struct ast_frame
*dahdi_exception(struct ast_channel
*ast
)
8695 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
8696 struct ast_frame
*f
;
8697 ast_mutex_lock(&p
->lock
);
8698 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8699 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8700 f
= analog_exception(analog_p
, ast
);
8702 f
= __dahdi_exception(ast
);
8704 ast_mutex_unlock(&p
->lock
);
8708 static struct ast_frame
*dahdi_read(struct ast_channel
*ast
)
8710 struct dahdi_pvt
*p
;
8714 struct ast_frame
*f
;
8717 * For analog channels, we must do deadlock avoidance because
8718 * analog ports can have more than one Asterisk channel using
8719 * the same private structure.
8721 p
= ast_channel_tech_pvt(ast
);
8722 while (ast_mutex_trylock(&p
->lock
)) {
8723 CHANNEL_DEADLOCK_AVOIDANCE(ast
);
8726 * Check to see if the channel is still associated with the same
8727 * private structure. While the Asterisk channel was unlocked
8728 * the following events may have occured:
8730 * 1) A masquerade may have associated the channel with another
8731 * technology or private structure.
8733 * 2) For PRI calls, call signaling could change the channel
8734 * association to another B channel (private structure).
8736 if (ast_channel_tech_pvt(ast
) != p
) {
8737 /* The channel is no longer associated. Quit gracefully. */
8738 return &ast_null_frame
;
8742 idx
= dahdi_get_index(ast
, p
, 0);
8744 /* Hang up if we don't really exist */
8746 ast_log(LOG_WARNING
, "We don't exist?\n");
8747 ast_mutex_unlock(&p
->lock
);
8751 if ((p
->radio
|| (p
->oprmode
< 0)) && p
->inalarm
) {
8752 ast_mutex_unlock(&p
->lock
);
8756 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8757 p
->subs
[idx
].f
.datalen
= 0;
8758 p
->subs
[idx
].f
.samples
= 0;
8759 p
->subs
[idx
].f
.mallocd
= 0;
8760 p
->subs
[idx
].f
.offset
= 0;
8761 p
->subs
[idx
].f
.subclass
.integer
= 0;
8762 p
->subs
[idx
].f
.delivery
= ast_tv(0,0);
8763 p
->subs
[idx
].f
.src
= "dahdi_read";
8764 p
->subs
[idx
].f
.data
.ptr
= NULL
;
8766 /* make sure it sends initial key state as first frame */
8767 if ((p
->radio
|| (p
->oprmode
< 0)) && (!p
->firstradio
))
8769 struct dahdi_params ps
;
8771 memset(&ps
, 0, sizeof(ps
));
8772 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &ps
) < 0) {
8773 ast_mutex_unlock(&p
->lock
);
8777 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8780 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_KEY
;
8784 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_UNKEY
;
8786 ast_mutex_unlock(&p
->lock
);
8787 return &p
->subs
[idx
].f
;
8790 if (!(--p
->ringt
)) {
8791 ast_mutex_unlock(&p
->lock
);
8798 openr2_chan_process_event(p
->r2chan
);
8799 if (OR2_DIR_FORWARD
== openr2_chan_get_direction(p
->r2chan
)) {
8800 struct ast_frame fr
= { AST_FRAME_CONTROL
, { AST_CONTROL_PROGRESS
} };
8801 /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
8802 * now enqueue a progress frame to bridge the media up */
8803 if (p
->mfcr2_call_accepted
&&
8804 !p
->mfcr2_progress_sent
&&
8805 ast_channel_state(ast
) == AST_STATE_RINGING
) {
8806 ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p
->channel
);
8807 ast_queue_frame(p
->owner
, &fr
);
8808 p
->mfcr2_progress_sent
= 1;
8814 if (p
->subs
[idx
].needringing
) {
8815 /* Send ringing frame if requested */
8816 p
->subs
[idx
].needringing
= 0;
8817 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8818 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RINGING
;
8819 ast_setstate(ast
, AST_STATE_RINGING
);
8820 ast_mutex_unlock(&p
->lock
);
8821 return &p
->subs
[idx
].f
;
8824 if (p
->subs
[idx
].needbusy
) {
8825 /* Send busy frame if requested */
8826 p
->subs
[idx
].needbusy
= 0;
8827 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8828 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_BUSY
;
8829 ast_mutex_unlock(&p
->lock
);
8830 return &p
->subs
[idx
].f
;
8833 if (p
->subs
[idx
].needcongestion
) {
8834 /* Send congestion frame if requested */
8835 p
->subs
[idx
].needcongestion
= 0;
8836 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8837 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_CONGESTION
;
8838 ast_mutex_unlock(&p
->lock
);
8839 return &p
->subs
[idx
].f
;
8842 if (p
->subs
[idx
].needanswer
) {
8843 /* Send answer frame if requested */
8844 p
->subs
[idx
].needanswer
= 0;
8845 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8846 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
8847 ast_mutex_unlock(&p
->lock
);
8848 return &p
->subs
[idx
].f
;
8851 if (p
->mfcr2
&& openr2_chan_get_read_enabled(p
->r2chan
)) {
8852 /* openr2 took care of reading and handling any event
8853 (needanswer, needbusy etc), if we continue we will read()
8854 twice, lets just return a null frame. This should only
8855 happen when openr2 is dialing out */
8856 ast_mutex_unlock(&p
->lock
);
8857 return &ast_null_frame
;
8861 if (p
->subs
[idx
].needflash
) {
8862 /* Send answer frame if requested */
8863 p
->subs
[idx
].needflash
= 0;
8864 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8865 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_FLASH
;
8866 ast_mutex_unlock(&p
->lock
);
8867 return &p
->subs
[idx
].f
;
8870 if (p
->subs
[idx
].needhold
) {
8871 /* Send answer frame if requested */
8872 p
->subs
[idx
].needhold
= 0;
8873 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8874 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_HOLD
;
8875 ast_mutex_unlock(&p
->lock
);
8876 ast_debug(1, "Sending hold on '%s'\n", ast_channel_name(ast
));
8877 return &p
->subs
[idx
].f
;
8880 if (p
->subs
[idx
].needunhold
) {
8881 /* Send answer frame if requested */
8882 p
->subs
[idx
].needunhold
= 0;
8883 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8884 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_UNHOLD
;
8885 ast_mutex_unlock(&p
->lock
);
8886 ast_debug(1, "Sending unhold on '%s'\n", ast_channel_name(ast
));
8887 return &p
->subs
[idx
].f
;
8891 * If we have a fake_event, fake an exception to handle it only
8892 * if this channel owns the private.
8894 if (p
->fake_event
&& p
->owner
== ast
) {
8895 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8896 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8898 f
= analog_exception(analog_p
, ast
);
8900 f
= __dahdi_exception(ast
);
8902 ast_mutex_unlock(&p
->lock
);
8906 if (ast_format_cmp(ast_channel_rawreadformat(ast
), ast_format_slin
) == AST_FORMAT_CMP_EQUAL
) {
8907 if (!p
->subs
[idx
].linear
) {
8908 p
->subs
[idx
].linear
= 1;
8909 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
8911 ast_log(LOG_WARNING
, "Unable to set channel %d (index %d) to linear mode.\n", p
->channel
, idx
);
8914 if (p
->subs
[idx
].linear
) {
8915 p
->subs
[idx
].linear
= 0;
8916 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
8918 ast_log(LOG_WARNING
, "Unable to set channel %d (index %d) to companded mode.\n", p
->channel
, idx
);
8921 readbuf
= ((unsigned char *)p
->subs
[idx
].buffer
) + AST_FRIENDLY_OFFSET
;
8922 CHECK_BLOCKING(ast
);
8923 res
= read(p
->subs
[idx
].dfd
, readbuf
, p
->subs
[idx
].linear
? READ_SIZE
* 2 : READ_SIZE
);
8924 ast_clear_flag(ast_channel_flags(ast
), AST_FLAG_BLOCKING
);
8925 /* Check for hangup */
8929 if (errno
== EAGAIN
) {
8930 /* Return "NULL" frame if there is nobody there */
8931 ast_mutex_unlock(&p
->lock
);
8932 return &p
->subs
[idx
].f
;
8933 } else if (errno
== ELAST
) {
8934 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8935 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8936 f
= analog_exception(analog_p
, ast
);
8938 f
= __dahdi_exception(ast
);
8941 ast_log(LOG_WARNING
, "dahdi_rec: %s\n", strerror(errno
));
8943 ast_mutex_unlock(&p
->lock
);
8946 if (res
!= (p
->subs
[idx
].linear
? READ_SIZE
* 2 : READ_SIZE
)) {
8947 ast_debug(1, "Short read (%d/%d), must be an event...\n", res
, p
->subs
[idx
].linear
? READ_SIZE
* 2 : READ_SIZE
);
8948 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8949 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8950 f
= analog_exception(analog_p
, ast
);
8952 f
= __dahdi_exception(ast
);
8954 ast_mutex_unlock(&p
->lock
);
8957 if (p
->tdd
) { /* if in TDD mode, see if we receive that */
8960 c
= tdd_feed(p
->tdd
,readbuf
,READ_SIZE
);
8962 ast_debug(1,"tdd_feed failed\n");
8963 ast_mutex_unlock(&p
->lock
);
8966 if (c
) { /* if a char to return */
8967 p
->subs
[idx
].f
.subclass
.integer
= 0;
8968 p
->subs
[idx
].f
.frametype
= AST_FRAME_TEXT
;
8969 p
->subs
[idx
].f
.mallocd
= 0;
8970 p
->subs
[idx
].f
.offset
= AST_FRIENDLY_OFFSET
;
8971 p
->subs
[idx
].f
.data
.ptr
= p
->subs
[idx
].buffer
+ AST_FRIENDLY_OFFSET
;
8972 p
->subs
[idx
].f
.datalen
= 1;
8973 *((char *) p
->subs
[idx
].f
.data
.ptr
) = c
;
8974 ast_mutex_unlock(&p
->lock
);
8975 return &p
->subs
[idx
].f
;
8978 if (idx
== SUB_REAL
) {
8979 /* Ensure the CW timers decrement only on a single subchannel */
8980 if (p
->cidcwexpire
) {
8981 if (!--p
->cidcwexpire
) {
8982 /* Expired CID/CW */
8983 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
8984 restore_conference(p
);
8987 if (p
->cid_suppress_expire
) {
8988 --p
->cid_suppress_expire
;
8990 if (p
->callwaitingrepeat
) {
8991 if (!--p
->callwaitingrepeat
) {
8992 /* Expired, Repeat callwaiting tone */
8994 dahdi_callwait(ast
);
8998 if (p
->subs
[idx
].linear
) {
8999 p
->subs
[idx
].f
.datalen
= READ_SIZE
* 2;
9001 p
->subs
[idx
].f
.datalen
= READ_SIZE
;
9003 /* Handle CallerID Transmission */
9004 if ((p
->owner
== ast
) && p
->cidspill
) {
9008 p
->subs
[idx
].f
.frametype
= AST_FRAME_VOICE
;
9009 p
->subs
[idx
].f
.subclass
.format
= ast_channel_rawreadformat(ast
);
9010 p
->subs
[idx
].f
.samples
= READ_SIZE
;
9011 p
->subs
[idx
].f
.mallocd
= 0;
9012 p
->subs
[idx
].f
.offset
= AST_FRIENDLY_OFFSET
;
9013 p
->subs
[idx
].f
.data
.ptr
= p
->subs
[idx
].buffer
+ AST_FRIENDLY_OFFSET
/ sizeof(p
->subs
[idx
].buffer
[0]);
9015 ast_debug(1, "Read %d of voice on %s\n", p
->subs
[idx
].f
.datalen
, ast
->name
);
9017 if ((p
->dialing
&& !p
->waitingfordt
.tv_sec
) || p
->radio
|| /* Transmitting something */
9018 (idx
&& (ast_channel_state(ast
) != AST_STATE_UP
)) || /* Three-way or callwait that isn't up */
9019 ((idx
== SUB_CALLWAIT
) && !p
->subs
[SUB_CALLWAIT
].inthreeway
) /* Inactive and non-confed call-wait */
9021 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
9022 don't send anything */
9023 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
9024 p
->subs
[idx
].f
.subclass
.integer
= 0;
9025 p
->subs
[idx
].f
.samples
= 0;
9026 p
->subs
[idx
].f
.mallocd
= 0;
9027 p
->subs
[idx
].f
.offset
= 0;
9028 p
->subs
[idx
].f
.data
.ptr
= NULL
;
9029 p
->subs
[idx
].f
.datalen
= 0;
9031 if (p
->dsp
&& (!p
->ignoredtmf
|| p
->callwaitcas
|| p
->busydetect
|| p
->callprogress
|| p
->waitingfordt
.tv_sec
|| p
->dialtone_detect
) && !idx
) {
9032 /* Perform busy detection etc on the dahdi line */
9035 if ((p
->dsp_features
& DSP_FEATURE_FAX_DETECT
)
9036 && p
->faxdetect_timeout
9037 && p
->faxdetect_timeout
<= ast_channel_get_up_time(ast
)) {
9038 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
9039 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
9040 ast_debug(1, "Channel driver fax CNG detection timeout on %s\n",
9041 ast_channel_name(ast
));
9044 f
= ast_dsp_process(ast
, p
->dsp
, &p
->subs
[idx
].f
);
9046 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
9047 mute
= ast_dsp_was_muted(p
->dsp
);
9048 if (p
->muting
!= mute
) {
9050 dahdi_confmute(p
, mute
);
9054 if ((p
->dsp_features
& DSP_FEATURE_WAITDIALTONE
) && (p
->dialtone_detect
> 0)
9055 && !p
->outgoing
&& ast_channel_state(ast
) == AST_STATE_UP
) {
9056 if (++p
->dialtone_scanning_time_elapsed
>= p
->dialtone_detect
) {
9057 p
->dsp_features
&= ~DSP_FEATURE_WAITDIALTONE
;
9058 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
9061 if ((f
->frametype
== AST_FRAME_CONTROL
) && (f
->subclass
.integer
== AST_CONTROL_BUSY
)) {
9062 if ((ast_channel_state(ast
) == AST_STATE_UP
) && !p
->outgoing
) {
9064 * Treat this as a "hangup" instead of a "busy" on the
9065 * assumption that a busy means the incoming call went away.
9070 } else if (p
->dialtone_detect
&& !p
->outgoing
&& f
->frametype
== AST_FRAME_VOICE
) {
9071 if ((ast_dsp_get_tstate(p
->dsp
) == DSP_TONE_STATE_DIALTONE
) && (ast_dsp_get_tcount(p
->dsp
) > 9)) {
9072 /* Dialtone detected on inbound call; hangup the channel */
9076 } else if (f
->frametype
== AST_FRAME_DTMF_BEGIN
9077 || f
->frametype
== AST_FRAME_DTMF_END
) {
9079 if (dahdi_sig_pri_lib_handles(p
->sig
)
9080 && ((struct sig_pri_chan
*) p
->sig_pvt
)->call_level
< SIG_PRI_CALL_LEVEL_PROCEEDING
9082 && ((!p
->outgoing
&& (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_INCOMING
))
9083 || (p
->outgoing
&& (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_OUTGOING
)))) {
9084 /* Don't accept in-band DTMF when in overlap dial mode */
9085 ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n",
9086 f
->frametype
== AST_FRAME_DTMF_BEGIN
? "begin" : "end",
9087 (unsigned)f
->subclass
.integer
, f
->subclass
.integer
, ast_channel_name(ast
));
9089 f
->frametype
= AST_FRAME_NULL
;
9090 f
->subclass
.integer
= 0;
9093 /* DSP clears us of being pulse */
9095 } else if (p
->waitingfordt
.tv_sec
) {
9096 if (ast_tvdiff_ms(ast_tvnow(), p
->waitingfordt
) >= p
->waitfordialtone
) {
9097 p
->waitingfordt
.tv_sec
= 0;
9098 ast_log(LOG_WARNING
, "Never saw dialtone on channel %d\n", p
->channel
);
9101 } else if (f
->frametype
== AST_FRAME_VOICE
) {
9102 f
->frametype
= AST_FRAME_NULL
;
9103 f
->subclass
.integer
= 0;
9104 if ((ast_dsp_get_tstate(p
->dsp
) == DSP_TONE_STATE_DIALTONE
|| ast_dsp_get_tstate(p
->dsp
) == DSP_TONE_STATE_RINGING
) && ast_dsp_get_tcount(p
->dsp
) > 9) {
9105 p
->waitingfordt
.tv_sec
= 0;
9106 p
->dsp_features
&= ~DSP_FEATURE_WAITDIALTONE
;
9107 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
9108 ast_debug(1, "Got 10 samples of dialtone!\n");
9109 if (!ast_strlen_zero(p
->dop
.dialstr
)) { /* Dial deferred digits */
9110 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
9112 p
->dop
.dialstr
[0] = '\0';
9113 ast_mutex_unlock(&p
->lock
);
9117 ast_debug(1, "Sent deferred digit string: %s\n", p
->dop
.dialstr
);
9119 p
->dop
.dialstr
[0] = '\0';
9120 p
->dop
.op
= DAHDI_DIAL_OP_REPLACE
;
9121 ast_setstate(ast
, AST_STATE_DIALING
);
9129 f
= &p
->subs
[idx
].f
;
9132 switch (f
->frametype
) {
9133 case AST_FRAME_DTMF_BEGIN
:
9134 case AST_FRAME_DTMF_END
:
9135 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
9136 analog_handle_dtmf(p
->sig_pvt
, ast
, idx
, &f
);
9138 dahdi_handle_dtmf(ast
, idx
, &f
);
9140 if (!(p
->dialmode
== ANALOG_DIALMODE_BOTH
|| p
->dialmode
== ANALOG_DIALMODE_DTMF
)) {
9141 if (f
->frametype
== AST_FRAME_DTMF_END
) { /* only show this message when the key is let go of */
9142 ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f
->subclass
.integer
);
9144 f
->frametype
= AST_FRAME_NULL
;
9145 f
->subclass
.integer
= 0;
9148 case AST_FRAME_VOICE
:
9149 if (p
->cidspill
|| p
->cid_suppress_expire
) {
9150 /* We are/were sending a caller id spill. Suppress any echo. */
9151 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
9152 p
->subs
[idx
].f
.subclass
.integer
= 0;
9153 p
->subs
[idx
].f
.samples
= 0;
9154 p
->subs
[idx
].f
.mallocd
= 0;
9155 p
->subs
[idx
].f
.offset
= 0;
9156 p
->subs
[idx
].f
.data
.ptr
= NULL
;
9157 p
->subs
[idx
].f
.datalen
= 0;
9165 ast_mutex_unlock(&p
->lock
);
9169 static int my_dahdi_write(struct dahdi_pvt
*p
, unsigned char *buf
, int len
, int idx
, int linear
)
9175 fd
= p
->subs
[idx
].dfd
;
9178 if (size
> (linear
? READ_SIZE
* 2 : READ_SIZE
))
9179 size
= (linear
? READ_SIZE
* 2 : READ_SIZE
);
9180 res
= write(fd
, buf
, size
);
9182 ast_debug(1, "Write returned %d (%s) on channel %d\n", res
, strerror(errno
), p
->channel
);
9191 static int dahdi_write(struct ast_channel
*ast
, struct ast_frame
*frame
)
9193 struct dahdi_pvt
*p
;
9197 /* Write a frame of (presumably voice) data */
9198 if (frame
->frametype
!= AST_FRAME_VOICE
) {
9199 if (frame
->frametype
!= AST_FRAME_IMAGE
) {
9200 ast_log(LOG_WARNING
, "Don't know what to do with frame type '%u'\n",
9206 /* Return if it's not valid data */
9207 if (!frame
->data
.ptr
|| !frame
->datalen
) {
9211 p
= ast_channel_tech_pvt(ast
);
9212 ast_mutex_lock(&p
->lock
);
9214 idx
= dahdi_get_index(ast
, p
, 0);
9216 ast_mutex_unlock(&p
->lock
);
9217 ast_log(LOG_WARNING
, "%s doesn't really exist?\n", ast_channel_name(ast
));
9222 ast_mutex_unlock(&p
->lock
);
9223 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9224 ast_channel_name(ast
));
9228 ast_mutex_unlock(&p
->lock
);
9229 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9230 ast_channel_name(ast
));
9234 ast_mutex_unlock(&p
->lock
);
9235 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9236 ast_channel_name(ast
));
9240 if (ast_format_cmp(frame
->subclass
.format
, ast_format_slin
) == AST_FORMAT_CMP_EQUAL
) {
9241 if (!p
->subs
[idx
].linear
) {
9242 p
->subs
[idx
].linear
= 1;
9243 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
9245 ast_log(LOG_WARNING
, "Unable to set linear mode on channel %d\n", p
->channel
);
9247 res
= my_dahdi_write(p
, (unsigned char *)frame
->data
.ptr
, frame
->datalen
, idx
, 1);
9248 } else if (ast_format_cmp(frame
->subclass
.format
, ast_format_ulaw
) == AST_FORMAT_CMP_EQUAL
9249 || ast_format_cmp(frame
->subclass
.format
, ast_format_alaw
) == AST_FORMAT_CMP_EQUAL
) {
9251 if (p
->subs
[idx
].linear
) {
9252 p
->subs
[idx
].linear
= 0;
9253 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
9255 ast_log(LOG_WARNING
, "Unable to set companded mode on channel %d\n", p
->channel
);
9257 res
= my_dahdi_write(p
, (unsigned char *)frame
->data
.ptr
, frame
->datalen
, idx
, 0);
9259 ast_mutex_unlock(&p
->lock
);
9260 ast_log(LOG_WARNING
, "Cannot handle frames in %s format\n",
9261 ast_format_get_name(frame
->subclass
.format
));
9264 ast_mutex_unlock(&p
->lock
);
9266 ast_log(LOG_WARNING
, "write failed: %s\n", strerror(errno
));
9272 static int dahdi_indicate(struct ast_channel
*chan
, int condition
, const void *data
, size_t datalen
)
9274 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
9277 int func
= DAHDI_FLASH
;
9279 ast_mutex_lock(&p
->lock
);
9280 ast_debug(1, "Requested indication %d on channel %s\n", condition
, ast_channel_name(chan
));
9282 #if defined(HAVE_PRI)
9283 case SIG_PRI_LIB_HANDLE_CASES
:
9284 res
= sig_pri_indicate(p
->sig_pvt
, chan
, condition
, data
, datalen
);
9285 ast_mutex_unlock(&p
->lock
);
9287 #endif /* defined(HAVE_PRI) */
9288 #if defined(HAVE_SS7)
9290 res
= sig_ss7_indicate(p
->sig_pvt
, chan
, condition
, data
, datalen
);
9291 ast_mutex_unlock(&p
->lock
);
9293 #endif /* defined(HAVE_SS7) */
9298 if (p
->mfcr2
&& !p
->mfcr2_call_accepted
) {
9299 ast_mutex_unlock(&p
->lock
);
9300 /* if this is an R2 call and the call is not yet accepted, we don't want the
9301 tone indications to mess up with the MF tones */
9305 idx
= dahdi_get_index(chan
, p
, 0);
9306 if (idx
== SUB_REAL
) {
9307 switch (condition
) {
9308 case AST_CONTROL_BUSY
:
9309 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_BUSY
);
9311 case AST_CONTROL_RINGING
:
9312 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_RINGTONE
);
9314 if (ast_channel_state(chan
) != AST_STATE_UP
) {
9315 if ((ast_channel_state(chan
) != AST_STATE_RING
) ||
9316 ((p
->sig
!= SIG_FXSKS
) &&
9317 (p
->sig
!= SIG_FXSLS
) &&
9318 (p
->sig
!= SIG_FXSGS
)))
9319 ast_setstate(chan
, AST_STATE_RINGING
);
9322 case AST_CONTROL_INCOMPLETE
:
9323 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan
));
9324 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9327 case AST_CONTROL_PROCEEDING
:
9328 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan
));
9329 /* don't continue in ast_indicate */
9332 case AST_CONTROL_PROGRESS
:
9333 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan
));
9334 /* don't continue in ast_indicate */
9337 case AST_CONTROL_CONGESTION
:
9338 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9339 switch (ast_channel_hangupcause(chan
)) {
9340 case AST_CAUSE_USER_BUSY
:
9341 case AST_CAUSE_NORMAL_CLEARING
:
9342 case 0:/* Cause has not been set. */
9343 /* Supply a more appropriate cause. */
9344 ast_channel_hangupcause_set(chan
, AST_CAUSE_CONGESTION
);
9350 case AST_CONTROL_HOLD
:
9351 ast_moh_start(chan
, data
, p
->mohinterpret
);
9353 case AST_CONTROL_UNHOLD
:
9356 case AST_CONTROL_RADIO_KEY
:
9358 res
= dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_OFFHOOK
);
9361 case AST_CONTROL_RADIO_UNKEY
:
9363 res
= dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_RINGOFF
);
9366 case AST_CONTROL_FLASH
:
9367 /* flash hookswitch */
9368 if (ISTRUNK(p
) && (p
->sig
!= SIG_PRI
)) {
9369 /* Clear out the dial buffer */
9370 p
->dop
.dialstr
[0] = '\0';
9371 if ((ioctl(p
->subs
[SUB_REAL
].dfd
,DAHDI_HOOK
,&func
) == -1) && (errno
!= EINPROGRESS
)) {
9372 ast_log(LOG_WARNING
, "Unable to flash external trunk on channel %s: %s\n",
9373 ast_channel_name(chan
), strerror(errno
));
9379 case AST_CONTROL_SRCUPDATE
:
9383 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
9389 ast_mutex_unlock(&p
->lock
);
9393 #if defined(HAVE_PRI)
9394 static struct ast_str
*create_channel_name(struct dahdi_pvt
*i
, int is_outgoing
, char *address
)
9396 static struct ast_str
*create_channel_name(struct dahdi_pvt
*i
)
9397 #endif /* defined(HAVE_PRI) */
9399 struct ast_str
*chan_name
;
9402 /* Create the new channel name tail. */
9403 if (!(chan_name
= ast_str_create(32))) {
9406 if (i
->channel
== CHAN_PSEUDO
) {
9407 ast_str_set(&chan_name
, 0, "pseudo-%ld", ast_random());
9408 #if defined(HAVE_PRI)
9409 } else if (i
->pri
) {
9410 ast_mutex_lock(&i
->pri
->lock
);
9411 y
= ++i
->pri
->new_chan_seq
;
9413 ast_str_set(&chan_name
, 0, "i%d/%s-%x", i
->pri
->span
, address
, (unsigned)y
);
9415 } else if (ast_strlen_zero(i
->cid_subaddr
)) {
9416 /* Put in caller-id number only since there is no subaddress. */
9417 ast_str_set(&chan_name
, 0, "i%d/%s-%x", i
->pri
->span
, i
->cid_num
, (unsigned)y
);
9419 /* Put in caller-id number and subaddress. */
9420 ast_str_set(&chan_name
, 0, "i%d/%s:%s-%x", i
->pri
->span
, i
->cid_num
,
9421 i
->cid_subaddr
, (unsigned)y
);
9423 ast_mutex_unlock(&i
->pri
->lock
);
9424 #endif /* defined(HAVE_PRI) */
9428 ast_str_set(&chan_name
, 0, "%d-%d", i
->channel
, y
);
9429 for (x
= 0; x
< 3; ++x
) {
9430 if (i
->subs
[x
].owner
&& !strcasecmp(ast_str_buffer(chan_name
),
9431 ast_channel_name(i
->subs
[x
].owner
) + 6)) {
9441 static struct ast_channel
*dahdi_new_callid_clean(struct dahdi_pvt
*i
, int state
, int startpbx
, int idx
, int law
, const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
, ast_callid callid
, int callid_created
)
9443 struct ast_channel
*new_channel
= dahdi_new(i
, state
, startpbx
, idx
, law
, assignedids
, requestor
, callid
);
9445 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
9450 static struct ast_channel
*dahdi_new(struct dahdi_pvt
*i
, int state
, int startpbx
, int idx
, int law
, const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
, ast_callid callid
)
9452 struct ast_channel
*tmp
;
9453 struct ast_format_cap
*caps
;
9454 struct ast_format
*deflaw
;
9457 struct ast_str
*chan_name
;
9458 struct ast_variable
*v
;
9460 char device_name
[AST_CHANNEL_NAME
];
9462 if (i
->subs
[idx
].owner
) {
9463 ast_log(LOG_WARNING
, "Channel %d already has a %s call\n", i
->channel
,subnames
[idx
]);
9467 #if defined(HAVE_PRI)
9469 * The dnid has been stuffed with the called-number[:subaddress]
9470 * by dahdi_request() for outgoing calls.
9472 chan_name
= create_channel_name(i
, i
->outgoing
, i
->dnid
);
9474 chan_name
= create_channel_name(i
);
9475 #endif /* defined(HAVE_PRI) */
9480 caps
= ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT
);
9482 ast_free(chan_name
);
9486 tmp
= ast_channel_alloc(0, state
, i
->cid_num
, i
->cid_name
, i
->accountcode
, i
->exten
, i
->context
, assignedids
, requestor
, i
->amaflags
, "DAHDI/%s", ast_str_buffer(chan_name
));
9487 ast_free(chan_name
);
9493 ast_channel_stage_snapshot(tmp
);
9496 ast_channel_callid_set(tmp
, callid
);
9499 ast_channel_tech_set(tmp
, &dahdi_tech
);
9500 #if defined(HAVE_PRI)
9502 ast_cc_copy_config_params(i
->cc_params
, i
->pri
->cc_params
);
9504 #endif /* defined(HAVE_PRI) */
9505 ast_channel_cc_params_init(tmp
, i
->cc_params
);
9508 if (law
== DAHDI_LAW_ALAW
) {
9509 deflaw
= ast_format_alaw
;
9511 deflaw
= ast_format_ulaw
;
9515 case SIG_PRI_LIB_HANDLE_CASES
:
9516 /* Make sure companding law is known. */
9517 i
->law
= (i
->law_default
== DAHDI_LAW_ALAW
)
9518 ? DAHDI_LAW_ALAW
: DAHDI_LAW_MULAW
;
9521 i
->law
= i
->law_default
;
9524 if (i
->law_default
== DAHDI_LAW_ALAW
) {
9525 deflaw
= ast_format_alaw
;
9527 deflaw
= ast_format_ulaw
;
9530 ast_channel_set_fd(tmp
, 0, i
->subs
[idx
].dfd
);
9531 ast_format_cap_append(caps
, deflaw
, 0);
9532 ast_channel_nativeformats_set(tmp
, caps
);
9534 /* Start out assuming ulaw since it's smaller :) */
9535 ast_channel_set_rawreadformat(tmp
, deflaw
);
9536 ast_channel_set_readformat(tmp
, deflaw
);
9537 ast_channel_set_rawwriteformat(tmp
, deflaw
);
9538 ast_channel_set_writeformat(tmp
, deflaw
);
9539 i
->subs
[idx
].linear
= 0;
9540 dahdi_setlinear(i
->subs
[idx
].dfd
, i
->subs
[idx
].linear
);
9542 if (idx
== SUB_REAL
) {
9543 if (i
->busydetect
&& CANBUSYDETECT(i
))
9544 features
|= DSP_FEATURE_BUSY_DETECT
;
9545 if ((i
->callprogress
& CALLPROGRESS_PROGRESS
) && CANPROGRESSDETECT(i
))
9546 features
|= DSP_FEATURE_CALL_PROGRESS
;
9547 if ((i
->waitfordialtone
|| i
->dialtone_detect
) && CANPROGRESSDETECT(i
))
9548 features
|= DSP_FEATURE_WAITDIALTONE
;
9549 if ((!i
->outgoing
&& (i
->callprogress
& CALLPROGRESS_FAX_INCOMING
)) ||
9550 (i
->outgoing
&& (i
->callprogress
& CALLPROGRESS_FAX_OUTGOING
))) {
9551 features
|= DSP_FEATURE_FAX_DETECT
;
9553 x
= DAHDI_TONEDETECT_ON
| DAHDI_TONEDETECT_MUTE
;
9554 if (ioctl(i
->subs
[idx
].dfd
, DAHDI_TONEDETECT
, &x
)) {
9555 i
->hardwaredtmf
= 0;
9556 features
|= DSP_FEATURE_DIGIT_DETECT
;
9557 } else if (NEED_MFDETECT(i
)) {
9558 i
->hardwaredtmf
= 1;
9559 features
|= DSP_FEATURE_DIGIT_DETECT
;
9564 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp
));
9566 if (i
->channel
!= CHAN_PSEUDO
)
9567 i
->dsp
= ast_dsp_new();
9571 i
->dsp_features
= features
;
9572 #if defined(HAVE_PRI) || defined(HAVE_SS7)
9573 /* We cannot do progress detection until receive PROGRESS message */
9574 if (i
->outgoing
&& (dahdi_sig_pri_lib_handles(i
->sig
) || (i
->sig
== SIG_SS7
))) {
9575 /* Remember requested DSP features, don't treat
9576 talking as ANSWER */
9577 i
->dsp_features
= features
& ~DSP_PROGRESS_TALK
;
9580 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9581 ast_dsp_set_features(i
->dsp
, features
);
9582 ast_dsp_set_digitmode(i
->dsp
, DSP_DIGITMODE_DTMF
| i
->dtmfrelax
);
9583 if (!ast_strlen_zero(progzone
))
9584 ast_dsp_set_call_progress_zone(i
->dsp
, progzone
);
9585 if (i
->busydetect
&& CANBUSYDETECT(i
)) {
9586 ast_dsp_set_busy_count(i
->dsp
, i
->busycount
);
9587 ast_dsp_set_busy_pattern(i
->dsp
, &i
->busy_cadence
);
9593 i
->dialtone_scanning_time_elapsed
= 0;
9595 if (state
== AST_STATE_RING
)
9596 ast_channel_rings_set(tmp
, 1);
9597 ast_channel_tech_pvt_set(tmp
, i
);
9598 if ((i
->sig
== SIG_FXOKS
) || (i
->sig
== SIG_FXOGS
) || (i
->sig
== SIG_FXOLS
)) {
9599 /* Only FXO signalled stuff can be picked up */
9600 ast_channel_callgroup_set(tmp
, i
->callgroup
);
9601 ast_channel_pickupgroup_set(tmp
, i
->pickupgroup
);
9602 ast_channel_named_callgroups_set(tmp
, i
->named_callgroups
);
9603 ast_channel_named_pickupgroups_set(tmp
, i
->named_pickupgroups
);
9605 if (!ast_strlen_zero(i
->parkinglot
))
9606 ast_channel_parkinglot_set(tmp
, i
->parkinglot
);
9607 if (!ast_strlen_zero(i
->language
))
9608 ast_channel_language_set(tmp
, i
->language
);
9611 if (!ast_strlen_zero(i
->accountcode
))
9612 ast_channel_accountcode_set(tmp
, i
->accountcode
);
9614 ast_channel_amaflags_set(tmp
, i
->amaflags
);
9615 i
->subs
[idx
].owner
= tmp
;
9616 ast_channel_context_set(tmp
, i
->context
);
9617 if (!dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
9618 ast_channel_call_forward_set(tmp
, i
->call_forward
);
9620 /* If we've been told "no ADSI" then enforce it */
9622 ast_channel_adsicpe_set(tmp
, AST_ADSI_UNAVAILABLE
);
9623 if (!ast_strlen_zero(i
->exten
))
9624 ast_channel_exten_set(tmp
, i
->exten
);
9625 if (!ast_strlen_zero(i
->rdnis
)) {
9626 ast_channel_redirecting(tmp
)->from
.number
.valid
= 1;
9627 ast_channel_redirecting(tmp
)->from
.number
.str
= ast_strdup(i
->rdnis
);
9629 if (!ast_strlen_zero(i
->dnid
)) {
9630 ast_channel_dialed(tmp
)->number
.str
= ast_strdup(i
->dnid
);
9633 /* Don't use ast_set_callerid() here because it will
9634 * generate a needless NewCallerID event */
9635 #if defined(HAVE_PRI) || defined(HAVE_SS7)
9636 if (!ast_strlen_zero(i
->cid_ani
)) {
9637 ast_channel_caller(tmp
)->ani
.number
.valid
= 1;
9638 ast_channel_caller(tmp
)->ani
.number
.str
= ast_strdup(i
->cid_ani
);
9639 } else if (!ast_strlen_zero(i
->cid_num
)) {
9640 ast_channel_caller(tmp
)->ani
.number
.valid
= 1;
9641 ast_channel_caller(tmp
)->ani
.number
.str
= ast_strdup(i
->cid_num
);
9644 if (!ast_strlen_zero(i
->cid_num
)) {
9645 ast_channel_caller(tmp
)->ani
.number
.valid
= 1;
9646 ast_channel_caller(tmp
)->ani
.number
.str
= ast_strdup(i
->cid_num
);
9648 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9649 ast_channel_caller(tmp
)->id
.name
.presentation
= i
->callingpres
;
9650 ast_channel_caller(tmp
)->id
.number
.presentation
= i
->callingpres
;
9651 ast_channel_caller(tmp
)->id
.number
.plan
= i
->cid_ton
;
9652 ast_channel_caller(tmp
)->ani2
= i
->cid_ani2
;
9653 ast_channel_caller(tmp
)->id
.tag
= ast_strdup(i
->cid_tag
);
9654 /* clear the fake event in case we posted one before we had ast_channel */
9656 /* Assure there is no confmute on this channel */
9657 dahdi_confmute(i
, 0);
9659 /* Configure the new channel jb */
9660 ast_jb_configure(tmp
, &global_jbconf
);
9662 /* Set initial device state */
9663 ast_copy_string(device_name
, ast_channel_name(tmp
), sizeof(device_name
));
9664 dashptr
= strrchr(device_name
, '-');
9668 ast_set_flag(ast_channel_flags(tmp
), AST_FLAG_DISABLE_DEVSTATE_CACHE
);
9669 ast_devstate_changed_literal(AST_DEVICE_UNKNOWN
, AST_DEVSTATE_NOT_CACHABLE
, device_name
);
9671 for (v
= i
->vars
; v
; v
= v
->next
)
9672 pbx_builtin_setvar_helper(tmp
, v
->name
, v
->value
);
9674 ast_channel_stage_snapshot_done(tmp
);
9676 ast_channel_unlock(tmp
);
9678 ast_module_ref(ast_module_info
->self
);
9680 dahdi_ami_channel_event(i
, tmp
);
9684 pbx_builtin_setvar_helper(tmp
, "MFCR2_CATEGORY", openr2_proto_get_category_string(i
->mfcr2_recvd_category
));
9687 if (ast_pbx_start(tmp
)) {
9688 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", ast_channel_name(tmp
));
9697 static int my_getsigstr(struct ast_channel
*chan
, char *str
, const char *term
, int ms
)
9701 *str
= 0; /* start with empty output buffer */
9704 /* Wait for the first digit (up to specified ms). */
9705 c
= ast_waitfordigit(chan
, ms
);
9706 /* if timeout, hangup or error, return as such */
9711 if (strchr(term
, c
))
9716 static int dahdi_wink(struct dahdi_pvt
*p
, int idx
)
9719 dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_WINK
);
9722 /* set bits of interest */
9723 j
= DAHDI_IOMUX_SIGEVENT
;
9724 /* wait for some happening */
9725 if (ioctl(p
->subs
[idx
].dfd
,DAHDI_IOMUX
,&j
) == -1) return(-1);
9726 /* exit loop if we have it */
9727 if (j
& DAHDI_IOMUX_SIGEVENT
) break;
9729 /* get the event info */
9730 if (ioctl(p
->subs
[idx
].dfd
,DAHDI_GETEVENT
,&j
) == -1) return(-1);
9734 static void publish_dnd_state(int channel
, const char *status
)
9736 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
9737 RAII_VAR(struct ast_str
*, dahdichan
, ast_str_create(32), ast_free
);
9742 ast_str_set(&dahdichan
, 0, "%d", channel
);
9744 body
= ast_json_pack("{s: s, s: s}",
9745 "DAHDIChannel", ast_str_buffer(dahdichan
),
9751 ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM
, body
);
9754 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9755 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9756 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9758 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9759 * DAHDI channel). Use this to enable or disable it.
9761 * \bug the use of the word "channel" for those dahdichans is really confusing.
9763 static int dahdi_dnd(struct dahdi_pvt
*dahdichan
, int flag
)
9765 if (dahdi_analog_lib_handles(dahdichan
->sig
, dahdichan
->radio
, dahdichan
->oprmode
)) {
9766 return analog_dnd(dahdichan
->sig_pvt
, flag
);
9770 return dahdichan
->dnd
;
9773 /* Do not disturb */
9774 dahdichan
->dnd
= flag
;
9775 ast_verb(3, "%s DND on channel %d\n",
9776 flag
? "Enabled" : "Disabled",
9777 dahdichan
->channel
);
9778 publish_dnd_state(dahdichan
->channel
, flag
? "enabled" : "disabled");
9782 static int canmatch_featurecode(const char *pickupexten
, const char *exten
)
9784 int extlen
= strlen(exten
);
9790 if (extlen
< strlen(pickupexten
) && !strncmp(pickupexten
, exten
, extlen
)) {
9793 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9794 if (exten
[0] == '*' && extlen
< 3) {
9798 /* "*0" should be processed before it gets here */
9809 static void *analog_ss_thread(void *data
)
9811 struct ast_channel
*chan
= data
;
9812 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
9813 char exten
[AST_MAX_EXTENSION
] = "";
9814 char exten2
[AST_MAX_EXTENSION
] = "";
9815 unsigned char buf
[256];
9818 struct callerid_state
*cs
= NULL
;
9819 char *name
= NULL
, *number
= NULL
;
9826 struct ast_smdi_md_message
*smdi_msg
= NULL
;
9835 RAII_VAR(struct ast_features_pickup_config
*, pickup_cfg
, NULL
, ao2_cleanup
);
9836 const char *pickupexten
;
9838 ast_mutex_lock(&ss_thread_lock
);
9840 ast_mutex_unlock(&ss_thread_lock
);
9841 /* in the bizarre case where the channel has become a zombie before we
9842 even get started here, abort safely
9845 ast_log(LOG_WARNING
, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan
));
9849 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan
));
9850 idx
= dahdi_get_index(chan
, p
, 1);
9852 ast_log(LOG_WARNING
, "Huh?\n");
9857 ast_channel_lock(chan
);
9858 pickup_cfg
= ast_get_chan_features_pickup_config(chan
);
9860 ast_log(LOG_ERROR
, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
9863 pickupexten
= ast_strdupa(pickup_cfg
->pickupexten
);
9865 ast_channel_unlock(chan
);
9868 ast_dsp_digitreset(p
->dsp
);
9872 case SIG_FEATDMF_TA
:
9874 case SIG_FGC_CAMAMF
:
9878 case SIG_SF_FEATDMF
:
9881 if (dahdi_wink(p
, idx
))
9888 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
9890 ast_dsp_digitreset(p
->dsp
);
9891 /* set digit mode appropriately */
9893 if (NEED_MFDETECT(p
))
9894 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MF
| p
->dtmfrelax
);
9896 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
9898 memset(dtmfbuf
, 0, sizeof(dtmfbuf
));
9899 /* Wait for the first digit only if immediate=no */
9901 /* Wait for the first digit (up to 5 seconds). */
9902 res
= ast_waitfordigit(chan
, 5000);
9906 /* save first char */
9911 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "*", 3000);
9913 res
= my_getsigstr(chan
, dtmfbuf
+ strlen(dtmfbuf
), "*", 3000);
9914 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9916 case SIG_FEATDMF_TA
:
9917 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9918 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9919 if (dahdi_wink(p
, idx
)) goto quit
;
9921 /* Wait for the first digit (up to 5 seconds). */
9922 res
= ast_waitfordigit(chan
, 5000);
9923 if (res
<= 0) break;
9925 /* fall through intentionally */
9928 case SIG_FGC_CAMAMF
:
9929 case SIG_SF_FEATDMF
:
9930 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9931 /* if international caca, do it again to get real ANO */
9932 if ((p
->sig
== SIG_FEATDMF
) && (dtmfbuf
[1] != '0') && (strlen(dtmfbuf
) != 14))
9934 if (dahdi_wink(p
, idx
)) goto quit
;
9936 /* Wait for the first digit (up to 5 seconds). */
9937 res
= ast_waitfordigit(chan
, 5000);
9938 if (res
<= 0) break;
9940 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9943 /* if E911, take off hook */
9944 if (p
->sig
== SIG_E911
)
9945 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
9946 res
= my_getsigstr(chan
, dtmfbuf
+ strlen(dtmfbuf
), "#", 3000);
9948 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9952 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9953 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9956 /* if we received a '*', we are actually receiving Feature Group D
9957 dial syntax, so use that mode; otherwise, fall through to normal
9961 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "*", 3000);
9963 res
= my_getsigstr(chan
, dtmfbuf
+ strlen(dtmfbuf
), "*", 3000);
9964 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9968 /* If we got the first digit, get the rest */
9970 dtmfbuf
[len
] = '\0';
9971 while ((len
< AST_MAX_EXTENSION
-1) && ast_matchmore_extension(chan
, ast_channel_context(chan
), dtmfbuf
, 1, p
->cid_num
)) {
9972 if (ast_exists_extension(chan
, ast_channel_context(chan
), dtmfbuf
, 1, p
->cid_num
)) {
9973 timeout
= p
->matchdigit_timeout
;
9975 timeout
= p
->interdigit_timeout
;
9977 res
= ast_waitfordigit(chan
, timeout
);
9979 ast_debug(1, "waitfordigit returned < 0...\n");
9983 dtmfbuf
[len
++] = res
;
9984 dtmfbuf
[len
] = '\0';
9993 ast_log(LOG_WARNING
, "getdtmf on channel %d: %s\n", p
->channel
, strerror(errno
));
9996 } else if (res
< 0) {
9997 ast_debug(1, "Got hung up before digits finished\n");
10002 if (p
->sig
== SIG_FGC_CAMA
) {
10005 if (ast_safe_sleep(chan
,1000) == -1) {
10009 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
10010 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MF
| p
->dtmfrelax
);
10011 res
= my_getsigstr(chan
, anibuf
, "#", 10000);
10012 if ((res
> 0) && (strlen(anibuf
) > 2)) {
10013 if (anibuf
[strlen(anibuf
) - 1] == '#')
10014 anibuf
[strlen(anibuf
) - 1] = 0;
10015 ast_set_callerid(chan
, anibuf
+ 2, NULL
, anibuf
+ 2);
10017 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
10020 ast_copy_string(exten
, dtmfbuf
, sizeof(exten
));
10021 if (ast_strlen_zero(exten
))
10022 ast_copy_string(exten
, "s", sizeof(exten
));
10023 if (p
->sig
== SIG_FEATD
|| p
->sig
== SIG_EMWINK
) {
10024 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10025 if (exten
[0] == '*') {
10026 char *stringp
=NULL
;
10027 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10028 /* Parse out extension and callerid */
10030 s1
= strsep(&stringp
, "*");
10031 s2
= strsep(&stringp
, "*");
10033 if (!ast_strlen_zero(p
->cid_num
))
10034 ast_set_callerid(chan
, p
->cid_num
, NULL
, p
->cid_num
);
10036 ast_set_callerid(chan
, s1
, NULL
, s1
);
10037 ast_copy_string(exten
, s2
, sizeof(exten
));
10039 ast_copy_string(exten
, s1
, sizeof(exten
));
10040 } else if (p
->sig
== SIG_FEATD
)
10041 ast_log(LOG_WARNING
, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10043 if ((p
->sig
== SIG_FEATDMF
) || (p
->sig
== SIG_FEATDMF_TA
)) {
10044 if (exten
[0] == '*') {
10045 char *stringp
=NULL
;
10046 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10047 /* Parse out extension and callerid */
10049 s1
= strsep(&stringp
, "#");
10050 s2
= strsep(&stringp
, "#");
10052 if (!ast_strlen_zero(p
->cid_num
))
10053 ast_set_callerid(chan
, p
->cid_num
, NULL
, p
->cid_num
);
10056 ast_set_callerid(chan
, s1
+ 2, NULL
, s1
+ 2);
10057 ast_copy_string(exten
, s2
+ 1, sizeof(exten
));
10059 ast_copy_string(exten
, s1
+ 2, sizeof(exten
));
10061 ast_log(LOG_WARNING
, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10063 if ((p
->sig
== SIG_E911
) || (p
->sig
== SIG_FGC_CAMAMF
)) {
10064 if (exten
[0] == '*') {
10065 char *stringp
=NULL
;
10066 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10067 /* Parse out extension and callerid */
10069 s1
= strsep(&stringp
, "#");
10070 s2
= strsep(&stringp
, "#");
10071 if (s2
&& (*(s2
+ 1) == '0')) {
10073 ast_set_callerid(chan
, s2
+ 2, NULL
, s2
+ 2);
10075 if (s1
) ast_copy_string(exten
, s1
, sizeof(exten
));
10076 else ast_copy_string(exten
, "911", sizeof(exten
));
10078 ast_log(LOG_WARNING
, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10080 if (p
->sig
== SIG_FEATB
) {
10081 if (exten
[0] == '*') {
10082 char *stringp
=NULL
;
10083 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10084 /* Parse out extension and callerid */
10086 s1
= strsep(&stringp
, "#");
10087 ast_copy_string(exten
, exten2
+ 1, sizeof(exten
));
10089 ast_log(LOG_WARNING
, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10091 if ((p
->sig
== SIG_FEATDMF
) || (p
->sig
== SIG_FEATDMF_TA
)) {
10092 dahdi_wink(p
, idx
);
10093 /* some switches require a minimum guard time between
10094 the last FGD wink and something that answers
10095 immediately. This ensures it */
10096 if (ast_safe_sleep(chan
, 100)) {
10101 dahdi_ec_enable(p
);
10102 if (NEED_MFDETECT(p
)) {
10104 if (!p
->hardwaredtmf
)
10105 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
10107 ast_dsp_free(p
->dsp
);
10113 if (ast_exists_extension(chan
, ast_channel_context(chan
), exten
, 1,
10114 S_COR(ast_channel_caller(chan
)->id
.number
.valid
, ast_channel_caller(chan
)->id
.number
.str
, NULL
))) {
10115 ast_channel_exten_set(chan
, exten
);
10116 if (p
->dsp
) ast_dsp_digitreset(p
->dsp
);
10117 res
= ast_pbx_run(chan
);
10119 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
10120 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10124 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten
, ast_channel_context(chan
));
10126 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_INFO
);
10128 ast_log(LOG_WARNING
, "Unable to start special tone on %d\n", p
->channel
);
10131 res
= ast_streamfile(chan
, "ss-noservice", ast_channel_language(chan
));
10133 ast_waitstream(chan
, "");
10134 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10142 /* Read the first digit */
10143 timeout
= p
->firstdigit_timeout
;
10144 /* If starting a threeway call, never timeout on the first digit so someone
10145 can use flash-hook as a "hold" feature */
10146 if (p
->subs
[SUB_THREEWAY
].owner
)
10148 while (len
< AST_MAX_EXTENSION
-1) {
10149 int is_exten_parking
= 0;
10151 /* Read digit unless it's supposed to be immediate, in which case the
10152 only answer is 's' */
10156 res
= ast_waitfordigit(chan
, timeout
);
10159 ast_debug(1, "waitfordigit returned < 0...\n");
10160 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10164 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res
, res
, timeout
);
10168 if (!ast_ignore_pattern(ast_channel_context(chan
), exten
)) {
10169 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10171 tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALTONE
);
10173 if (ast_parking_provider_registered()) {
10174 is_exten_parking
= ast_parking_is_exten_park(ast_channel_context(chan
), exten
);
10176 if (ast_exists_extension(chan
, ast_channel_context(chan
), exten
, 1, p
->cid_num
) && !is_exten_parking
) {
10177 if (!res
|| !ast_matchmore_extension(chan
, ast_channel_context(chan
), exten
, 1, p
->cid_num
)) {
10179 /* Record this as the forwarding extension */
10180 ast_copy_string(p
->call_forward
, exten
, sizeof(p
->call_forward
));
10181 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p
->call_forward
, p
->channel
);
10182 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10186 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10188 memset(exten
, 0, sizeof(exten
));
10189 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALTONE
);
10193 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10194 ast_channel_lock(chan
);
10195 ast_channel_exten_set(chan
, exten
);
10196 if (!ast_strlen_zero(p
->cid_num
)) {
10197 if (!p
->hidecallerid
)
10198 ast_set_callerid(chan
, p
->cid_num
, NULL
, p
->cid_num
);
10200 ast_set_callerid(chan
, NULL
, NULL
, p
->cid_num
);
10202 if (!ast_strlen_zero(p
->cid_name
)) {
10203 if (!p
->hidecallerid
)
10204 ast_set_callerid(chan
, NULL
, p
->cid_name
, NULL
);
10206 ast_setstate(chan
, AST_STATE_RING
);
10207 ast_channel_unlock(chan
);
10208 dahdi_ec_enable(p
);
10209 res
= ast_pbx_run(chan
);
10211 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
10212 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10217 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10218 so just set the timeout to matchdigit_timeout and wait some more */
10219 timeout
= p
->matchdigit_timeout
;
10221 } else if (res
== 0) {
10222 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10223 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10224 dahdi_wait_event(p
->subs
[idx
].dfd
);
10227 } else if (p
->callwaiting
&& !strcmp(exten
, "*70")) {
10228 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan
));
10229 /* Disable call waiting if enabled */
10230 p
->callwaiting
= 0;
10231 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10233 ast_log(LOG_WARNING
, "Unable to do dial recall on channel %s: %s\n",
10234 ast_channel_name(chan
), strerror(errno
));
10237 ioctl(p
->subs
[idx
].dfd
,DAHDI_CONFDIAG
,&len
);
10238 memset(exten
, 0, sizeof(exten
));
10239 timeout
= p
->firstdigit_timeout
;
10241 } else if (!strcmp(exten
, pickupexten
)) {
10242 /* Scan all channels and see if there are any
10243 * ringing channels that have call groups
10244 * that equal this channels pickup group
10246 if (idx
== SUB_REAL
) {
10247 /* Switch us from Third call to Call Wait */
10248 if (p
->subs
[SUB_THREEWAY
].owner
) {
10249 /* If you make a threeway call and the *8# a call, it should actually
10250 look like a callwait */
10251 alloc_sub(p
, SUB_CALLWAIT
);
10252 swap_subs(p
, SUB_CALLWAIT
, SUB_THREEWAY
);
10253 unalloc_sub(p
, SUB_THREEWAY
);
10255 dahdi_ec_enable(p
);
10256 if (ast_pickup_call(chan
)) {
10257 ast_debug(1, "No call pickup possible...\n");
10258 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10259 dahdi_wait_event(p
->subs
[idx
].dfd
);
10264 ast_log(LOG_WARNING
, "Huh? Got *8# on call not on real\n");
10269 } else if (!p
->hidecallerid
&& !strcmp(exten
, "*67")) {
10270 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan
));
10271 /* Disable Caller*ID if enabled */
10272 p
->hidecallerid
= 1;
10273 ast_party_number_free(&ast_channel_caller(chan
)->id
.number
);
10274 ast_party_number_init(&ast_channel_caller(chan
)->id
.number
);
10275 ast_party_name_free(&ast_channel_caller(chan
)->id
.name
);
10276 ast_party_name_init(&ast_channel_caller(chan
)->id
.name
);
10277 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10279 ast_log(LOG_WARNING
, "Unable to do dial recall on channel %s: %s\n",
10280 ast_channel_name(chan
), strerror(errno
));
10283 memset(exten
, 0, sizeof(exten
));
10284 timeout
= p
->firstdigit_timeout
;
10285 } else if (p
->callreturn
&& !strcmp(exten
, "*69")) {
10286 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10288 } else if (!strcmp(exten
, "*78")) {
10290 /* Do not disturb */
10291 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10293 memset(exten
, 0, sizeof(exten
));
10295 } else if (!strcmp(exten
, "*79")) {
10297 /* Do not disturb */
10298 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10300 memset(exten
, 0, sizeof(exten
));
10302 } else if (p
->cancallforward
&& !strcmp(exten
, "*72")) {
10303 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10305 memset(exten
, 0, sizeof(exten
));
10307 } else if (p
->cancallforward
&& !strcmp(exten
, "*73")) {
10308 ast_verb(3, "Cancelling call forwarding on channel %d\n", p
->channel
);
10309 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10310 memset(p
->call_forward
, 0, sizeof(p
->call_forward
));
10312 memset(exten
, 0, sizeof(exten
));
10314 } else if ((p
->transfer
|| p
->canpark
) && is_exten_parking
10315 && p
->subs
[SUB_THREEWAY
].owner
) {
10316 struct ast_bridge_channel
*bridge_channel
;
10319 * This is a three way call, the main call being a real channel,
10320 * and we're parking the first call.
10322 ast_channel_lock(p
->subs
[SUB_THREEWAY
].owner
);
10323 bridge_channel
= ast_channel_get_bridge_channel(p
->subs
[SUB_THREEWAY
].owner
);
10324 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
10325 if (bridge_channel
) {
10326 if (!ast_parking_blind_transfer_park(bridge_channel
, ast_channel_context(chan
), exten
, NULL
, NULL
)) {
10328 * Swap things around between the three-way and real call so we
10329 * can hear where the channel got parked.
10331 ast_mutex_lock(&p
->lock
);
10332 p
->owner
= p
->subs
[SUB_THREEWAY
].owner
;
10333 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
10334 ast_mutex_unlock(&p
->lock
);
10336 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan
));
10338 ao2_ref(bridge_channel
, -1);
10341 ao2_ref(bridge_channel
, -1);
10344 } else if (p
->hidecallerid
&& !strcmp(exten
, "*82")) {
10345 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan
));
10346 /* Enable Caller*ID if enabled */
10347 p
->hidecallerid
= 0;
10348 ast_set_callerid(chan
, p
->cid_num
, p
->cid_name
, NULL
);
10349 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10351 ast_log(LOG_WARNING
, "Unable to do dial recall on channel %s: %s\n",
10352 ast_channel_name(chan
), strerror(errno
));
10355 memset(exten
, 0, sizeof(exten
));
10356 timeout
= p
->firstdigit_timeout
;
10357 } else if (!strcmp(exten
, "*0")) {
10358 struct ast_channel
*nbridge
=
10359 p
->subs
[SUB_THREEWAY
].owner
;
10360 struct dahdi_pvt
*pbridge
= NULL
;
10361 RAII_VAR(struct ast_channel
*, bridged
, nbridge
? ast_channel_bridge_peer(nbridge
) : NULL
, ast_channel_cleanup
);
10363 /* set up the private struct of the bridged one, if any */
10364 if (nbridge
&& bridged
) {
10365 pbridge
= ast_channel_tech_pvt(bridged
);
10367 if (nbridge
&& pbridge
&&
10368 (ast_channel_tech(nbridge
) == &dahdi_tech
) &&
10369 (ast_channel_tech(bridged
) == &dahdi_tech
) &&
10370 ISTRUNK(pbridge
)) {
10371 int func
= DAHDI_FLASH
;
10372 /* Clear out the dial buffer */
10373 p
->dop
.dialstr
[0] = '\0';
10374 /* flash hookswitch */
10375 if ((ioctl(pbridge
->subs
[SUB_REAL
].dfd
,DAHDI_HOOK
,&func
) == -1) && (errno
!= EINPROGRESS
)) {
10376 ast_log(LOG_WARNING
, "Unable to flash external trunk on channel %s: %s\n",
10377 ast_channel_name(nbridge
), strerror(errno
));
10379 swap_subs(p
, SUB_REAL
, SUB_THREEWAY
);
10380 unalloc_sub(p
, SUB_THREEWAY
);
10381 p
->owner
= p
->subs
[SUB_REAL
].owner
;
10382 ast_queue_unhold(p
->subs
[SUB_REAL
].owner
);
10386 tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10387 dahdi_wait_event(p
->subs
[idx
].dfd
);
10388 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10389 swap_subs(p
, SUB_REAL
, SUB_THREEWAY
);
10390 unalloc_sub(p
, SUB_THREEWAY
);
10391 p
->owner
= p
->subs
[SUB_REAL
].owner
;
10395 } else if (!ast_canmatch_extension(chan
, ast_channel_context(chan
), exten
, 1,
10396 S_COR(ast_channel_caller(chan
)->id
.number
.valid
, ast_channel_caller(chan
)->id
.number
.str
, NULL
))
10397 && !canmatch_featurecode(pickupexten
, exten
)) {
10398 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten
,
10399 S_COR(ast_channel_caller(chan
)->id
.number
.valid
, ast_channel_caller(chan
)->id
.number
.str
, "<Unknown Caller>"),
10400 ast_channel_context(chan
));
10404 timeout
= p
->interdigit_timeout
;
10405 if (len
&& !ast_ignore_pattern(ast_channel_context(chan
), exten
))
10406 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10412 /* check for SMDI messages */
10413 if (p
->use_smdi
&& p
->smdi_iface
) {
10414 smdi_msg
= ast_smdi_md_message_wait(p
->smdi_iface
, SMDI_MD_WAIT_TIMEOUT
);
10416 if (smdi_msg
!= NULL
) {
10417 ast_channel_exten_set(chan
, smdi_msg
->fwd_st
);
10419 if (smdi_msg
->type
== 'B')
10420 pbx_builtin_setvar_helper(chan
, "_SMDI_VM_TYPE", "b");
10421 else if (smdi_msg
->type
== 'N')
10422 pbx_builtin_setvar_helper(chan
, "_SMDI_VM_TYPE", "u");
10424 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan
));
10426 ast_log(LOG_WARNING
, "SMDI enabled but no SMDI message present\n");
10430 if (p
->use_callerid
&& (p
->cid_signalling
== CID_SIG_SMDI
&& smdi_msg
)) {
10431 number
= smdi_msg
->calling_st
;
10433 /* If we want caller id, we're in a prering state due to a polarity reversal
10434 * and we're set to use a polarity reversal to trigger the start of caller id,
10435 * grab the caller id and wait for ringing to start... */
10436 } else if (p
->use_callerid
&& (ast_channel_state(chan
) == AST_STATE_PRERING
&&
10437 (p
->cid_start
== CID_START_POLARITY
|| p
->cid_start
== CID_START_POLARITY_IN
|| p
->cid_start
== CID_START_DTMF_NOALERT
))) {
10438 /* If set to use DTMF CID signalling, listen for DTMF */
10439 if (p
->cid_signalling
== CID_SIG_DTMF
) {
10442 struct timeval start
= ast_tvnow();
10445 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan
));
10446 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10448 * We are the only party interested in the Rx stream since
10449 * we have not answered yet. We don't need or even want DTMF
10450 * emulation. The DTMF digits can come so fast that emulation
10451 * can drop some of them.
10453 ast_channel_lock(chan
);
10454 ast_set_flag(ast_channel_flags(chan
), AST_FLAG_END_DTMF_ONLY
);
10455 ast_channel_unlock(chan
);
10456 off_ms
= 4000;/* This is a typical OFF time between rings. */
10458 struct ast_frame
*f
;
10460 ms
= ast_remaining_ms(start
, off_ms
);
10461 res
= ast_waitfor(chan
, ms
);
10464 * We do not need to restore the dahdi_setlinear()
10465 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10466 * are hanging up the channel.
10468 ast_log(LOG_WARNING
, "DTMFCID timed out waiting for ring. "
10469 "Exiting simple switch\n");
10473 f
= ast_read(chan
);
10476 if (f
->frametype
== AST_FRAME_DTMF
) {
10477 if (k
< ARRAY_LEN(dtmfbuf
) - 1) {
10478 dtmfbuf
[k
++] = f
->subclass
.integer
;
10480 ast_debug(1, "CID got digit '%c'\n", f
->subclass
.integer
);
10481 start
= ast_tvnow();
10484 if (ast_channel_state(chan
) == AST_STATE_RING
||
10485 ast_channel_state(chan
) == AST_STATE_RINGING
)
10486 break; /* Got ring */
10488 ast_channel_lock(chan
);
10489 ast_clear_flag(ast_channel_flags(chan
), AST_FLAG_END_DTMF_ONLY
);
10490 ast_channel_unlock(chan
);
10492 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10493 /* Got cid and ring. */
10494 ast_debug(1, "CID got string '%s'\n", dtmfbuf
);
10495 callerid_get_dtmf(dtmfbuf
, dtmfcid
, &flags
);
10496 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid
, flags
);
10497 /* If first byte is NULL, we have no cid */
10498 if (!ast_strlen_zero(dtmfcid
))
10502 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10503 } else if ((p
->cid_signalling
== CID_SIG_V23
) || (p
->cid_signalling
== CID_SIG_V23_JP
)) {
10504 cs
= callerid_new(p
->cid_signalling
);
10507 struct timeval start
;
10513 /* Take out of linear mode for Caller*ID processing */
10514 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10516 /* First we wait and listen for the Caller*ID */
10518 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10519 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10520 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10525 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10526 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10527 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10528 if (res
== DAHDI_EVENT_NOALARM
) {
10532 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
10533 if (res
== DAHDI_EVENT_RINGBEGIN
) {
10534 res
= dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
10541 } else if (i
& DAHDI_IOMUX_READ
) {
10542 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10544 if (errno
!= ELAST
) {
10545 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10554 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
10555 res
= callerid_feed_jp(cs
, buf
, res
, AST_LAW(p
));
10557 res
= callerid_feed(cs
, buf
, res
, AST_LAW(p
));
10561 * The previous diagnostic message output likely
10562 * explains why it failed.
10564 ast_log(LOG_WARNING
,
10565 "Failed to decode CallerID on channel '%s'\n",
10566 ast_channel_name(chan
));
10570 else if (samples
> (8000 * 10))
10575 callerid_get(cs
, &name
, &number
, &flags
);
10576 ast_log(LOG_NOTICE
, "CallerID number: %s, name: %s, flags=%d\n", number
, name
, flags
);
10579 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
10580 res
= dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
10584 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10585 start
= ast_tvnow();
10586 off_ms
= 4000;/* This is a typical OFF time between rings. */
10588 struct ast_frame
*f
;
10590 ms
= ast_remaining_ms(start
, off_ms
);
10591 res
= ast_waitfor(chan
, ms
);
10593 ast_log(LOG_WARNING
, "CID timed out waiting for ring. "
10594 "Exiting simple switch\n");
10598 if (!(f
= ast_read(chan
))) {
10599 ast_log(LOG_WARNING
, "Hangup received waiting for ring. Exiting simple switch\n");
10604 if (ast_channel_state(chan
) == AST_STATE_RING
||
10605 ast_channel_state(chan
) == AST_STATE_RINGING
)
10606 break; /* Got ring */
10609 /* We must have a ring by now, so, if configured, lets try to listen for
10610 * distinctive ringing */
10611 if (p
->usedistinctiveringdetection
) {
10614 /* Clear the current ring data array so we don't have old data in it. */
10615 for (receivedRingT
= 0; receivedRingT
< ARRAY_LEN(curRingData
); receivedRingT
++)
10616 curRingData
[receivedRingT
] = 0;
10620 /* Check to see if context is what it should be, if not set to be. */
10621 if (strcmp(p
->context
,p
->defcontext
) != 0) {
10622 ast_copy_string(p
->context
, p
->defcontext
, sizeof(p
->context
));
10623 ast_channel_context_set(chan
, p
->defcontext
);
10627 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10628 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10629 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10634 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10635 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10636 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10637 if (res
== DAHDI_EVENT_NOALARM
) {
10641 /* Let us detect distinctive ring */
10643 curRingData
[receivedRingT
] = p
->ringt
;
10645 if (p
->ringt
< p
->ringt_base
/2)
10647 /* Increment the ringT counter so we can match it against
10648 values in chan_dahdi.conf for distinctive ring */
10649 if (++receivedRingT
== ARRAY_LEN(curRingData
))
10651 } else if (i
& DAHDI_IOMUX_READ
) {
10652 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10654 if (errno
!= ELAST
) {
10655 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10662 if (p
->ringt
> 0) {
10663 if (!(--p
->ringt
)) {
10670 /* this only shows up if you have n of the dring patterns filled in */
10671 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData
[0],curRingData
[1],curRingData
[2]);
10672 for (counter
= 0; counter
< 3; counter
++) {
10673 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10676 for (counter1
= 0; counter1
< 3; counter1
++) {
10677 ast_verb(3, "Ring pattern check range: %d\n", p
->drings
.ringnum
[counter
].range
);
10678 if (p
->drings
.ringnum
[counter
].ring
[counter1
] == -1) {
10679 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10680 curRingData
[counter1
]);
10682 } else if (curRingData
[counter1
] <= (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
) &&
10683 curRingData
[counter1
] >= (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
)) {
10684 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10685 (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
),
10686 (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
));
10691 if (distMatches
== 3) {
10692 /* The ring matches, set the context to whatever is for distinctive ring.. */
10693 ast_copy_string(p
->context
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
), sizeof(p
->context
));
10694 ast_channel_context_set(chan
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
));
10695 ast_verb(3, "Distinctive Ring matched context %s\n",p
->context
);
10700 /* Restore linear mode (if appropriate) for Caller*ID processing */
10701 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10706 ast_log(LOG_WARNING
, "Unable to get caller ID space\n");
10708 ast_log(LOG_WARNING
, "Channel %s in prering "
10709 "state, but I have nothing to do. "
10710 "Terminating simple switch, should be "
10711 "restarted by the actual ring.\n",
10712 ast_channel_name(chan
));
10716 } else if (p
->use_callerid
&& p
->cid_start
== CID_START_RING
) {
10717 if (p
->cid_signalling
== CID_SIG_DTMF
) {
10720 struct timeval start
;
10723 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10725 start
= ast_tvnow();
10727 struct ast_frame
*f
;
10729 ms
= ast_remaining_ms(start
, off_ms
);
10730 res
= ast_waitfor(chan
, ms
);
10732 ast_log(LOG_WARNING
, "DTMFCID timed out waiting for ring. "
10733 "Exiting simple switch\n");
10737 f
= ast_read(chan
);
10739 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10743 if (f
->frametype
== AST_FRAME_DTMF
) {
10744 dtmfbuf
[k
++] = f
->subclass
.integer
;
10745 ast_debug(1, "CID got digit '%c'\n", f
->subclass
.integer
);
10746 start
= ast_tvnow();
10750 if (p
->ringt_base
== p
->ringt
)
10754 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10755 /* Got cid and ring. */
10756 callerid_get_dtmf(dtmfbuf
, dtmfcid
, &flags
);
10757 ast_debug(1, "CID is '%s', flags %d\n",
10759 /* If first byte is NULL, we have no cid */
10760 if (!ast_strlen_zero(dtmfcid
))
10764 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10766 /* FSK Bell202 callerID */
10767 cs
= callerid_new(p
->cid_signalling
);
10775 /* Clear the current ring data array so we don't have old data in it. */
10776 for (receivedRingT
= 0; receivedRingT
< ARRAY_LEN(curRingData
); receivedRingT
++)
10777 curRingData
[receivedRingT
] = 0;
10781 /* Check to see if context is what it should be, if not set to be. */
10782 if (strcmp(p
->context
,p
->defcontext
) != 0) {
10783 ast_copy_string(p
->context
, p
->defcontext
, sizeof(p
->context
));
10784 ast_channel_context_set(chan
, p
->defcontext
);
10787 /* Take out of linear mode for Caller*ID processing */
10788 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10790 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10791 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10792 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10797 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10798 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10799 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10800 if (res
== DAHDI_EVENT_NOALARM
) {
10803 /* If we get a PR event, they hung up while processing calerid */
10804 if ( res
== DAHDI_EVENT_POLARITY
&& p
->hanguponpolarityswitch
&& p
->polarity
== POLARITY_REV
) {
10805 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p
->channel
);
10806 p
->polarity
= POLARITY_IDLE
;
10812 /* Let us detect callerid when the telco uses distinctive ring */
10814 curRingData
[receivedRingT
] = p
->ringt
;
10816 if (p
->ringt
< p
->ringt_base
/2)
10818 /* Increment the ringT counter so we can match it against
10819 values in chan_dahdi.conf for distinctive ring */
10820 if (++receivedRingT
== ARRAY_LEN(curRingData
))
10822 } else if (i
& DAHDI_IOMUX_READ
) {
10823 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10825 if (errno
!= ELAST
) {
10826 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10833 if (p
->ringt
> 0) {
10834 if (!(--p
->ringt
)) {
10840 res
= callerid_feed(cs
, buf
, res
, AST_LAW(p
));
10843 * The previous diagnostic message output likely
10844 * explains why it failed.
10846 ast_log(LOG_WARNING
,
10847 "Failed to decode CallerID on channel '%s'\n",
10848 ast_channel_name(chan
));
10852 else if (samples
> (8000 * 10))
10857 callerid_get(cs
, &name
, &number
, &flags
);
10858 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number
, name
, flags
);
10860 if (distinctiveringaftercid
== 1) {
10861 /* Clear the current ring data array so we don't have old data in it. */
10862 for (receivedRingT
= 0; receivedRingT
< 3; receivedRingT
++) {
10863 curRingData
[receivedRingT
] = 0;
10866 ast_verb(3, "Detecting post-CID distinctive ring\n");
10868 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10869 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10870 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10875 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10876 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10877 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10878 if (res
== DAHDI_EVENT_NOALARM
) {
10882 /* Let us detect callerid when the telco uses distinctive ring */
10884 curRingData
[receivedRingT
] = p
->ringt
;
10886 if (p
->ringt
< p
->ringt_base
/2)
10888 /* Increment the ringT counter so we can match it against
10889 values in chan_dahdi.conf for distinctive ring */
10890 if (++receivedRingT
== ARRAY_LEN(curRingData
))
10892 } else if (i
& DAHDI_IOMUX_READ
) {
10893 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10895 if (errno
!= ELAST
) {
10896 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10903 if (p
->ringt
> 0) {
10904 if (!(--p
->ringt
)) {
10912 if (p
->usedistinctiveringdetection
) {
10913 /* this only shows up if you have n of the dring patterns filled in */
10914 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData
[0],curRingData
[1],curRingData
[2]);
10916 for (counter
= 0; counter
< 3; counter
++) {
10917 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10919 /* this only shows up if you have n of the dring patterns filled in */
10920 ast_verb(3, "Checking %d,%d,%d\n",
10921 p
->drings
.ringnum
[counter
].ring
[0],
10922 p
->drings
.ringnum
[counter
].ring
[1],
10923 p
->drings
.ringnum
[counter
].ring
[2]);
10925 for (counter1
= 0; counter1
< 3; counter1
++) {
10926 ast_verb(3, "Ring pattern check range: %d\n", p
->drings
.ringnum
[counter
].range
);
10927 if (p
->drings
.ringnum
[counter
].ring
[counter1
] == -1) {
10928 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10929 curRingData
[counter1
]);
10932 else if (curRingData
[counter1
] <= (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
) &&
10933 curRingData
[counter1
] >= (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
)) {
10934 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10935 (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
),
10936 (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
));
10940 if (distMatches
== 3) {
10941 /* The ring matches, set the context to whatever is for distinctive ring.. */
10942 ast_copy_string(p
->context
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
), sizeof(p
->context
));
10943 ast_channel_context_set(chan
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
));
10944 ast_verb(3, "Distinctive Ring matched context %s\n",p
->context
);
10949 /* Restore linear mode (if appropriate) for Caller*ID processing */
10950 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10955 ast_log(LOG_WARNING
, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan
));
10958 ast_log(LOG_WARNING
, "Unable to get caller ID space\n");
10964 ast_shrink_phone_number(number
);
10965 ast_set_callerid(chan
, number
, name
, number
);
10967 ao2_cleanup(smdi_msg
);
10972 my_handle_notify_message(chan
, p
, flags
, -1);
10974 ast_channel_lock(chan
);
10975 ast_setstate(chan
, AST_STATE_RING
);
10976 ast_channel_rings_set(chan
, 1);
10977 ast_channel_unlock(chan
);
10978 p
->ringt
= p
->ringt_base
;
10979 res
= ast_pbx_run(chan
);
10982 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
10986 ast_log(LOG_WARNING
, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p
->sig
), p
->channel
);
10987 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10989 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", p
->channel
);
10991 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10993 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", p
->channel
);
10996 ast_mutex_lock(&ss_thread_lock
);
10998 ast_cond_signal(&ss_thread_complete
);
10999 ast_mutex_unlock(&ss_thread_lock
);
11003 struct mwi_thread_data
{
11004 struct dahdi_pvt
*pvt
;
11005 unsigned char buf
[READ_SIZE
];
11009 static int calc_energy(const unsigned char *buf
, int len
, struct ast_format
*law
)
11017 for (x
= 0; x
< len
; x
++)
11018 sum
+= abs(law
== ast_format_ulaw
? AST_MULAW(buf
[x
]) : AST_ALAW(buf
[x
]));
11023 static void *mwi_thread(void *data
)
11025 struct mwi_thread_data
*mtd
= data
;
11026 struct callerid_state
*cs
;
11027 pthread_t threadid
;
11029 char *name
, *number
;
11032 unsigned int spill_done
= 0;
11033 int spill_result
= -1;
11035 if (!(cs
= callerid_new(mtd
->pvt
->cid_signalling
))) {
11036 goto quit_no_clean
;
11039 callerid_feed(cs
, mtd
->buf
, mtd
->len
, AST_LAW(mtd
->pvt
));
11041 bump_gains(mtd
->pvt
);
11044 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
11045 if ((res
= ioctl(mtd
->pvt
->subs
[SUB_REAL
].dfd
, DAHDI_IOMUX
, &i
))) {
11046 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
11050 if (i
& DAHDI_IOMUX_SIGEVENT
) {
11051 struct ast_channel
*chan
;
11052 ast_callid callid
= 0;
11053 int callid_created
;
11055 /* If we get an event, screen out events that we do not act on.
11056 * Otherwise, cancel and go to the simple switch to let it deal with it.
11058 res
= dahdi_get_event(mtd
->pvt
->subs
[SUB_REAL
].dfd
);
11061 case DAHDI_EVENT_NEONMWI_ACTIVE
:
11062 case DAHDI_EVENT_NEONMWI_INACTIVE
:
11063 case DAHDI_EVENT_NONE
:
11064 case DAHDI_EVENT_BITSCHANGED
:
11066 case DAHDI_EVENT_NOALARM
:
11067 if (dahdi_analog_lib_handles(mtd
->pvt
->sig
, mtd
->pvt
->radio
, mtd
->pvt
->oprmode
)) {
11068 struct analog_pvt
*analog_p
= mtd
->pvt
->sig_pvt
;
11070 analog_p
->inalarm
= 0;
11072 mtd
->pvt
->inalarm
= 0;
11073 handle_clear_alarms(mtd
->pvt
);
11075 case DAHDI_EVENT_ALARM
:
11076 if (dahdi_analog_lib_handles(mtd
->pvt
->sig
, mtd
->pvt
->radio
, mtd
->pvt
->oprmode
)) {
11077 struct analog_pvt
*analog_p
= mtd
->pvt
->sig_pvt
;
11079 analog_p
->inalarm
= 1;
11081 mtd
->pvt
->inalarm
= 1;
11082 res
= get_alarms(mtd
->pvt
);
11083 handle_alarms(mtd
->pvt
, res
);
11084 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11086 callid_created
= ast_callid_threadstorage_auto(&callid
);
11087 ast_log(LOG_NOTICE
, "Got event %d (%s)... Passing along to analog_ss_thread\n", res
, event2str(res
));
11090 restore_gains(mtd
->pvt
);
11091 mtd
->pvt
->ringt
= mtd
->pvt
->ringt_base
;
11093 if ((chan
= dahdi_new(mtd
->pvt
, AST_STATE_RING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
))) {
11096 if (dahdi_analog_lib_handles(mtd
->pvt
->sig
, mtd
->pvt
->radio
, mtd
->pvt
->oprmode
)) {
11097 result
= analog_ss_thread_start(mtd
->pvt
->sig_pvt
, chan
);
11099 result
= ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
);
11102 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", mtd
->pvt
->channel
);
11103 res
= tone_zone_play_tone(mtd
->pvt
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11105 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", mtd
->pvt
->channel
);
11109 ast_log(LOG_WARNING
, "Could not create channel to handle call\n");
11112 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11113 goto quit_no_clean
;
11115 } else if (i
& DAHDI_IOMUX_READ
) {
11116 if ((res
= read(mtd
->pvt
->subs
[SUB_REAL
].dfd
, mtd
->buf
, sizeof(mtd
->buf
))) < 0) {
11117 if (errno
!= ELAST
) {
11118 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
11125 if ((spill_result
= callerid_feed(cs
, mtd
->buf
, res
, AST_LAW(mtd
->pvt
))) < 0) {
11127 * The previous diagnostic message output likely
11128 * explains why it failed.
11130 ast_log(LOG_WARNING
, "Failed to decode CallerID\n");
11132 } else if (spill_result
) {
11136 /* keep reading data until the energy level drops below the threshold
11137 so we don't get another 'trigger' on the remaining carrier signal
11139 if (calc_energy(mtd
->buf
, res
, AST_LAW(mtd
->pvt
)) <= mwilevel
)
11142 if (samples
> (8000 * 4)) /*Termination case - time to give up*/
11147 if (spill_result
== 1) {
11148 callerid_get(cs
, &name
, &number
, &flags
);
11149 if (flags
& CID_MSGWAITING
) {
11150 ast_log(LOG_NOTICE
, "mwi: Have Messages on channel %d\n", mtd
->pvt
->channel
);
11151 notify_message(mtd
->pvt
->mailbox
, 1);
11152 } else if (flags
& CID_NOMSGWAITING
) {
11153 ast_log(LOG_NOTICE
, "mwi: No Messages on channel %d\n", mtd
->pvt
->channel
);
11154 notify_message(mtd
->pvt
->mailbox
, 0);
11156 ast_log(LOG_NOTICE
, "mwi: Status unknown on channel %d\n", mtd
->pvt
->channel
);
11164 restore_gains(mtd
->pvt
);
11167 mtd
->pvt
->mwimonitoractive
= 0;
11174 * The following three functions (mwi_send_init, mwi_send_process_buffer,
11175 * mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11176 * that are sent out via FXS port on voicemail state change. The execution of
11177 * the mwi send is state driven and can either generate a ring pulse prior to
11178 * sending the fsk spill or simply send an fsk spill.
11180 static int mwi_send_init(struct dahdi_pvt
* pvt
)
11184 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11185 /* Determine how this spill is to be sent */
11186 if (pvt
->mwisend_rpas
) {
11187 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SA
;
11188 pvt
->mwisendactive
= 1;
11189 } else if (pvt
->mwisend_fsk
) {
11190 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SPILL
;
11191 pvt
->mwisendactive
= 1;
11193 pvt
->mwisendactive
= 0;
11197 if (mwisend_rpas
) {
11198 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SA
;
11200 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SPILL
;
11202 pvt
->mwisendactive
= 1;
11205 if (pvt
->cidspill
) {
11206 ast_log(LOG_WARNING
, "cidspill already exists when trying to send FSK MWI\n");
11207 ast_free(pvt
->cidspill
);
11208 pvt
->cidspill
= NULL
;
11212 pvt
->cidspill
= ast_calloc(1, MAX_CALLERID_SIZE
);
11213 if (!pvt
->cidspill
) {
11214 pvt
->mwisendactive
= 0;
11217 x
= DAHDI_FLUSH_BOTH
;
11218 ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_FLUSH
, &x
);
11220 ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOKTRANSFER
, &x
);
11221 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11222 if (pvt
->mwisend_fsk
) {
11224 pvt
->cidlen
= ast_callerid_vmwi_generate(pvt
->cidspill
, has_voicemail(pvt
),
11225 CID_MWI_TYPE_MDMF_FULL
, AST_LAW(pvt
), pvt
->cid_name
, pvt
->cid_num
, 0);
11227 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11233 static int mwi_send_process_buffer(struct dahdi_pvt
* pvt
, int num_read
)
11235 struct timeval now
;
11238 /* sanity check to catch if this had been interrupted previously
11239 * i.e. state says there is more to do but there is no spill allocated
11241 if (MWI_SEND_DONE
!= pvt
->mwisend_data
.mwisend_current
&& !pvt
->cidspill
) {
11242 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11243 } else if (MWI_SEND_DONE
!= pvt
->mwisend_data
.mwisend_current
) {
11244 /* Normal processing -- Perform mwi send action */
11245 switch ( pvt
->mwisend_data
.mwisend_current
) {
11247 /* Send the Ring Pulse Signal Alert */
11248 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_SETCADENCE
, &AS_RP_cadence
);
11250 ast_log(LOG_WARNING
, "Unable to set RP-AS ring cadence: %s\n", strerror(errno
));
11253 res
= dahdi_set_hook(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_RING
);
11254 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SA_WAIT
;
11256 case MWI_SEND_SA_WAIT
: /* do nothing until I get RINGEROFF event */
11258 case MWI_SEND_PAUSE
: /* Wait between alert and spill - min of 500 mS*/
11259 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11260 if (pvt
->mwisend_fsk
) {
11262 gettimeofday(&now
, NULL
);
11263 if ((int)(now
.tv_sec
- pvt
->mwisend_data
.pause
.tv_sec
) * 1000000 + (int)now
.tv_usec
- (int)pvt
->mwisend_data
.pause
.tv_usec
> 500000) {
11264 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SPILL
;
11266 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11267 } else { /* support for mwisendtype=nofsk */
11268 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_CLEANUP
;
11272 case MWI_SEND_SPILL
:
11273 /* We read some number of bytes. Write an equal amount of data */
11274 if (0 < num_read
) {
11275 if (num_read
> pvt
->cidlen
- pvt
->cidpos
) {
11276 num_read
= pvt
->cidlen
- pvt
->cidpos
;
11278 res
= write(pvt
->subs
[SUB_REAL
].dfd
, pvt
->cidspill
+ pvt
->cidpos
, num_read
);
11280 pvt
->cidpos
+= res
;
11281 if (pvt
->cidpos
>= pvt
->cidlen
) {
11282 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_CLEANUP
;
11285 ast_log(LOG_WARNING
, "MWI FSK Send Write failed: %s\n", strerror(errno
));
11290 case MWI_SEND_CLEANUP
:
11291 /* For now, do nothing */
11292 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11295 /* Should not get here, punt*/
11300 if (MWI_SEND_DONE
== pvt
->mwisend_data
.mwisend_current
) {
11301 if (pvt
->cidspill
) {
11302 ast_free(pvt
->cidspill
);
11303 pvt
->cidspill
= NULL
;
11307 pvt
->mwisendactive
= 0;
11311 if (pvt
->cidspill
) {
11312 ast_free(pvt
->cidspill
);
11313 pvt
->cidspill
= NULL
;
11317 pvt
->mwisendactive
= 0;
11321 static int mwi_send_process_event(struct dahdi_pvt
* pvt
, int event
)
11325 if (MWI_SEND_DONE
!= pvt
->mwisend_data
.mwisend_current
) {
11327 case DAHDI_EVENT_RINGEROFF
:
11328 if (pvt
->mwisend_data
.mwisend_current
== MWI_SEND_SA_WAIT
) {
11331 if (dahdi_set_hook(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
) ) {
11332 ast_log(LOG_WARNING
, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno
));
11333 ast_free(pvt
->cidspill
);
11334 pvt
->cidspill
= NULL
;
11335 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11336 pvt
->mwisendactive
= 0;
11338 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_PAUSE
;
11339 gettimeofday(&pvt
->mwisend_data
.pause
, NULL
);
11343 /* Going off hook, I need to punt this spill */
11344 case DAHDI_EVENT_RINGOFFHOOK
:
11345 if (pvt
->cidspill
) {
11346 ast_free(pvt
->cidspill
);
11347 pvt
->cidspill
= NULL
;
11351 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11352 pvt
->mwisendactive
= 0;
11354 case DAHDI_EVENT_RINGERON
:
11355 case DAHDI_EVENT_HOOKCOMPLETE
:
11364 /* destroy a range DAHDI channels, identified by their number */
11365 static void dahdi_destroy_channel_range(int start
, int end
)
11367 struct dahdi_pvt
*cur
;
11368 struct dahdi_pvt
*next
;
11369 int destroyed_first
= 0;
11370 int destroyed_last
= 0;
11372 ast_mutex_lock(&iflock
);
11373 ast_debug(1, "range: %d-%d\n", start
, end
);
11374 for (cur
= iflist
; cur
; cur
= next
) {
11376 if (cur
->channel
>= start
&& cur
->channel
<= end
) {
11377 int x
= DAHDI_FLASH
;
11379 if (cur
->channel
> destroyed_last
) {
11380 destroyed_last
= cur
->channel
;
11382 if (destroyed_first
< 1 || cur
->channel
< destroyed_first
) {
11383 destroyed_first
= cur
->channel
;
11385 ast_debug(3, "Destroying %d\n", cur
->channel
);
11386 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11387 ioctl(cur
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
11389 destroy_channel(cur
, 1);
11390 ast_module_unref(ast_module_info
->self
);
11393 ast_mutex_unlock(&iflock
);
11394 if (destroyed_first
> start
|| destroyed_last
< end
) {
11395 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11396 start
, end
, destroyed_first
, destroyed_last
);
11401 static void dahdi_r2_destroy_nodev(void)
11403 struct r2link_entry
*cur
;
11404 AST_LIST_LOCK(&nodev_r2links
);
11405 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links
, cur
, list
) {
11407 struct dahdi_mfcr2
*r2
= &cur
->mfcr2
;
11408 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2
->numchans
);
11409 for (i
= 0; i
< r2
->numchans
; i
++) {
11411 struct dahdi_pvt
*pvt
= r2
->pvts
[i
];
11415 channel
= pvt
->channel
;
11416 ast_debug(3, "About to destroy B-channel %d.\n", channel
);
11417 dahdi_destroy_channel_range(channel
, channel
);
11419 ast_debug(3, "Destroying R2 link\n");
11420 AST_LIST_REMOVE(&nodev_r2links
, cur
, list
);
11421 if (r2
->r2master
!= AST_PTHREADT_NULL
) {
11422 pthread_cancel(r2
->r2master
);
11423 pthread_join(r2
->r2master
, NULL
);
11424 r2
->r2master
= AST_PTHREADT_NULL
;
11425 openr2_context_delete(r2
->protocol_context
);
11429 AST_LIST_TRAVERSE_SAFE_END
;
11430 AST_LIST_UNLOCK(&nodev_r2links
);
11434 static int setup_dahdi(int reload
);
11435 static int setup_dahdi_int(int reload
, struct dahdi_chan_conf
*default_conf
, struct dahdi_chan_conf
*base_conf
, struct dahdi_chan_conf
*conf
);
11439 * \brief create a range of new DAHDI channels
11441 * \param start first channel in the range
11442 * \param end last channel in the range
11444 * \retval RESULT_SUCCESS on success.
11445 * \retval RESULT_FAILURE on error.
11447 static int dahdi_create_channel_range(int start
, int end
)
11449 struct dahdi_pvt
*cur
;
11450 struct dahdi_chan_conf default_conf
= dahdi_chan_conf_default();
11451 struct dahdi_chan_conf base_conf
= dahdi_chan_conf_default();
11452 struct dahdi_chan_conf conf
= dahdi_chan_conf_default();
11453 int ret
= RESULT_FAILURE
; /* be pessimistic */
11455 ast_debug(1, "channel range caps: %d - %d\n", start
, end
);
11456 ast_mutex_lock(&iflock
);
11457 for (cur
= iflist
; cur
; cur
= cur
->next
) {
11458 if (cur
->channel
>= start
&& cur
->channel
<= end
) {
11460 "channel range %d-%d is occupied\n",
11468 for (x
= 0; x
< NUM_SPANS
; x
++) {
11469 struct dahdi_pri
*pri
= pris
+ x
;
11471 if (!pris
[x
].pri
.pvts
[0]) {
11474 for (i
= 0; i
< SIG_PRI_NUM_DCHANS
; i
++) {
11475 int channo
= pri
->dchannels
[i
];
11480 if (!pri
->pri
.fds
[i
]) {
11483 if (channo
>= start
&& channo
<= end
) {
11485 "channel range %d-%d is occupied by span %d\n",
11486 start
, end
, x
+ 1);
11493 if (!default_conf
.chan
.cc_params
|| !base_conf
.chan
.cc_params
||
11494 !conf
.chan
.cc_params
) {
11497 default_conf
.wanted_channels_start
= start
;
11498 base_conf
.wanted_channels_start
= start
;
11499 conf
.wanted_channels_start
= start
;
11500 default_conf
.wanted_channels_end
= end
;
11501 base_conf
.wanted_channels_end
= end
;
11502 conf
.wanted_channels_end
= end
;
11503 if (setup_dahdi_int(0, &default_conf
, &base_conf
, &conf
) == 0) {
11504 ret
= RESULT_SUCCESS
;
11507 ast_cc_config_params_destroy(default_conf
.chan
.cc_params
);
11508 ast_cc_config_params_destroy(base_conf
.chan
.cc_params
);
11509 ast_cc_config_params_destroy(conf
.chan
.cc_params
);
11510 ast_mutex_unlock(&iflock
);
11515 static struct dahdi_pvt
*handle_init_event(struct dahdi_pvt
*i
, int event
)
11518 pthread_t threadid
;
11519 struct ast_channel
*chan
;
11520 ast_callid callid
= 0;
11521 int callid_created
;
11523 /* Handle an event on a given channel for the monitor thread. */
11526 case DAHDI_EVENT_NONE
:
11527 case DAHDI_EVENT_BITSCHANGED
:
11529 case DAHDI_EVENT_WINKFLASH
:
11530 case DAHDI_EVENT_RINGOFFHOOK
:
11531 if (i
->inalarm
) break;
11532 if (i
->radio
) break;
11533 /* Got a ring/answer. What kind of channel are we? */
11538 res
= dahdi_set_hook(i
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
11539 if (res
&& (errno
== EBUSY
)) {
11543 callid_created
= ast_callid_threadstorage_auto(&callid
);
11545 /* Cancel VMWI spill */
11546 ast_free(i
->cidspill
);
11547 i
->cidspill
= NULL
;
11548 restore_conference(i
);
11550 if (i
->immediate
) {
11551 dahdi_ec_enable(i
);
11552 /* The channel is immediately up. Start right away */
11553 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_RINGTONE
);
11554 chan
= dahdi_new(i
, AST_STATE_RING
, 1, SUB_REAL
, 0, NULL
, NULL
, callid
);
11556 ast_log(LOG_WARNING
, "Unable to start PBX on channel %d\n", i
->channel
);
11557 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11559 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11562 /* Check for callerid, digits, etc */
11563 chan
= dahdi_new(i
, AST_STATE_RESERVED
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11565 if (has_voicemail(i
))
11566 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_STUTTER
);
11568 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_DIALTONE
);
11570 ast_log(LOG_WARNING
, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i
->channel
);
11571 if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
11572 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
11573 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11575 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11579 ast_log(LOG_WARNING
, "Unable to create channel\n");
11582 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11587 i
->ringt
= i
->ringt_base
;
11592 case SIG_FEATDMF_TA
:
11595 case SIG_FGC_CAMAMF
:
11601 case SIG_SF_FEATDMF
:
11604 /* Check for callerid, digits, etc */
11605 callid_created
= ast_callid_threadstorage_auto(&callid
);
11606 if (i
->cid_start
== CID_START_POLARITY_IN
) {
11607 chan
= dahdi_new(i
, AST_STATE_PRERING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11609 chan
= dahdi_new(i
, AST_STATE_RING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11613 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", i
->channel
);
11614 } else if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
11615 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
11616 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11618 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11623 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11626 ast_log(LOG_WARNING
, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i
->sig
), i
->channel
);
11627 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11629 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11633 case DAHDI_EVENT_NOALARM
:
11635 #if defined(HAVE_PRI)
11636 case SIG_PRI_LIB_HANDLE_CASES
:
11637 ast_mutex_lock(&i
->lock
);
11638 sig_pri_chan_alarm_notify(i
->sig_pvt
, 1);
11639 ast_mutex_unlock(&i
->lock
);
11641 #endif /* defined(HAVE_PRI) */
11642 #if defined(HAVE_SS7)
11644 sig_ss7_set_alarm(i
->sig_pvt
, 0);
11646 #endif /* defined(HAVE_SS7) */
11651 handle_clear_alarms(i
);
11653 case DAHDI_EVENT_ALARM
:
11655 #if defined(HAVE_PRI)
11656 case SIG_PRI_LIB_HANDLE_CASES
:
11657 ast_mutex_lock(&i
->lock
);
11658 sig_pri_chan_alarm_notify(i
->sig_pvt
, 0);
11659 ast_mutex_unlock(&i
->lock
);
11661 #endif /* defined(HAVE_PRI) */
11662 #if defined(HAVE_SS7)
11664 sig_ss7_set_alarm(i
->sig_pvt
, 1);
11666 #endif /* defined(HAVE_SS7) */
11671 res
= get_alarms(i
);
11672 handle_alarms(i
, res
);
11673 /* fall thru intentionally */
11674 case DAHDI_EVENT_ONHOOK
:
11677 /* Back on hook. Hang up. */
11683 case SIG_FEATDMF_TA
:
11686 case SIG_FGC_CAMAMF
:
11692 case SIG_SF_FEATDMF
:
11700 dahdi_ec_disable(i
);
11701 /* Diddle the battery for the zhone */
11703 dahdi_set_hook(i
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
11706 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, -1);
11707 dahdi_set_hook(i
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
11710 case SIG_PRI_LIB_HANDLE_CASES
:
11711 dahdi_ec_disable(i
);
11712 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, -1);
11715 ast_log(LOG_WARNING
, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i
->sig
), i
->channel
);
11716 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, -1);
11720 case DAHDI_EVENT_POLARITY
:
11725 /* We have already got a PR before the channel was
11726 created, but it wasn't handled. We need polarity
11727 to be REV for remote hangup detection to work.
11728 At least in Spain */
11729 callid_created
= ast_callid_threadstorage_auto(&callid
);
11730 if (i
->hanguponpolarityswitch
)
11731 i
->polarity
= POLARITY_REV
;
11732 if (i
->cid_start
== CID_START_POLARITY
|| i
->cid_start
== CID_START_POLARITY_IN
) {
11733 i
->polarity
= POLARITY_REV
;
11734 ast_verb(2, "Starting post polarity "
11735 "CID detection on channel %d\n",
11737 chan
= dahdi_new(i
, AST_STATE_PRERING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11739 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", i
->channel
);
11740 } else if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
11741 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
11745 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11748 ast_log(LOG_WARNING
, "handle_init_event detected "
11749 "polarity reversal on non-FXO (SIG_FXS) "
11750 "interface %d\n", i
->channel
);
11753 case DAHDI_EVENT_REMOVED
: /* destroy channel, will actually do so in do_monitor */
11754 ast_log(LOG_NOTICE
,
11755 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11758 case DAHDI_EVENT_NEONMWI_ACTIVE
:
11759 if (i
->mwimonitor_neon
) {
11760 notify_message(i
->mailbox
, 1);
11761 ast_log(LOG_NOTICE
, "NEON MWI set for channel %d, mailbox %s \n", i
->channel
, i
->mailbox
);
11764 case DAHDI_EVENT_NEONMWI_INACTIVE
:
11765 if (i
->mwimonitor_neon
) {
11766 notify_message(i
->mailbox
, 0);
11767 ast_log(LOG_NOTICE
, "NEON MWI cleared for channel %d, mailbox %s\n", i
->channel
, i
->mailbox
);
11774 static void monitor_pfds_clean(void *arg
) {
11775 struct pollfd
**pfds
= arg
;
11779 static void *do_monitor(void *data
)
11781 int count
, res
, res2
, spoint
, pollres
=0;
11782 struct dahdi_pvt
*i
;
11783 struct dahdi_pvt
*last
= NULL
;
11784 struct dahdi_pvt
*doomed
;
11785 time_t thispass
= 0, lastpass
= 0;
11788 struct pollfd
*pfds
=NULL
;
11789 int lastalloc
= -1;
11790 /* This thread monitors all the frame relay interfaces which are not yet in use
11791 (and thus do not have a separate thread) indefinitely */
11792 /* From here on out, we die whenever asked */
11794 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
)) {
11795 ast_log(LOG_WARNING
, "Unable to set cancel type to asynchronous\n");
11798 ast_debug(1, "Monitor starting...\n");
11800 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
11802 pthread_cleanup_push(monitor_pfds_clean
, &pfds
);
11804 /* Lock the interface list */
11805 ast_mutex_lock(&iflock
);
11806 if (!pfds
|| (lastalloc
!= ifcount
)) {
11812 if (!(pfds
= ast_calloc(1, ifcount
* sizeof(*pfds
)))) {
11813 ast_mutex_unlock(&iflock
);
11817 lastalloc
= ifcount
;
11819 /* Build the stuff we're going to poll on, that is the socket of every
11820 dahdi_pvt that does not have an associated owner channel */
11822 for (i
= iflist
; i
; i
= i
->next
) {
11823 ast_mutex_lock(&i
->lock
);
11824 if (pfds
&& (i
->subs
[SUB_REAL
].dfd
> -1) && i
->sig
&& (!i
->radio
) && !(i
->sig
& SIG_MFCR2
)) {
11825 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
11826 struct analog_pvt
*p
= i
->sig_pvt
;
11829 ast_log(LOG_ERROR
, "No sig_pvt?\n");
11830 } else if (!p
->owner
&& !p
->subs
[SUB_REAL
].owner
) {
11831 /* This needs to be watched, as it lacks an owner */
11832 pfds
[count
].fd
= i
->subs
[SUB_REAL
].dfd
;
11833 pfds
[count
].events
= POLLPRI
;
11834 pfds
[count
].revents
= 0;
11835 /* Message waiting or r2 channels also get watched for reading */
11836 if (i
->cidspill
|| i
->mwisendactive
|| i
->mwimonitor_fsk
||
11837 (i
->cid_start
== CID_START_DTMF_NOALERT
&& (i
->sig
== SIG_FXSLS
|| i
->sig
== SIG_FXSGS
|| i
->sig
== SIG_FXSKS
))) {
11838 pfds
[count
].events
|= POLLIN
;
11843 if (!i
->owner
&& !i
->subs
[SUB_REAL
].owner
&& !i
->mwimonitoractive
) {
11844 /* This needs to be watched, as it lacks an owner */
11845 pfds
[count
].fd
= i
->subs
[SUB_REAL
].dfd
;
11846 pfds
[count
].events
= POLLPRI
;
11847 pfds
[count
].revents
= 0;
11848 /* If we are monitoring for VMWI or sending CID, we need to
11849 read from the channel as well */
11850 if (i
->cidspill
|| i
->mwisendactive
|| i
->mwimonitor_fsk
||
11851 (i
->cid_start
== CID_START_DTMF_NOALERT
&& (i
->sig
== SIG_FXSLS
|| i
->sig
== SIG_FXSGS
|| i
->sig
== SIG_FXSKS
))) {
11852 pfds
[count
].events
|= POLLIN
;
11858 ast_mutex_unlock(&i
->lock
);
11860 /* Okay, now that we know what to do, release the interface lock */
11861 ast_mutex_unlock(&iflock
);
11863 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
11864 pthread_testcancel();
11865 /* Wait at least a second for something to happen */
11866 res
= poll(pfds
, count
, 1000);
11867 pthread_testcancel();
11868 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
11870 /* Okay, poll has finished. Let's see what happened. */
11872 if ((errno
!= EAGAIN
) && (errno
!= EINTR
))
11873 ast_log(LOG_WARNING
, "poll return %d: %s\n", res
, strerror(errno
));
11876 /* Alright, lock the interface list again, and let's look and see what has
11878 ast_mutex_lock(&iflock
);
11881 lastpass
= thispass
;
11882 thispass
= time(NULL
);
11884 for (i
= iflist
;; i
= i
->next
) {
11886 dahdi_destroy_channel_range(doomed
->channel
, doomed
->channel
);
11893 if (thispass
!= lastpass
) {
11894 if (!found
&& ((i
== last
) || ((i
== iflist
) && !last
))) {
11897 struct analog_pvt
*analog_p
= last
->sig_pvt
;
11898 /* Only allow MWI to be initiated on a quiescent fxs port */
11900 && !last
->mwisendactive
11901 && (last
->sig
& __DAHDI_SIG_FXO
)
11902 && !analog_p
->fxsoffhookstate
11904 && (!ast_strlen_zero(last
->mailbox
) || last
->mwioverride_active
)
11905 && !analog_p
->subs
[SUB_REAL
].owner
/* could be a recall ring from a flash hook hold */
11906 && (thispass
- analog_p
->onhooktime
> 3)) {
11907 res
= has_voicemail(last
);
11908 if (analog_p
->msgstate
!= res
) {
11909 /* Set driver resources for signalling VMWI */
11910 res2
= ioctl(last
->subs
[SUB_REAL
].dfd
, DAHDI_VMWI
, &res
);
11912 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
11913 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last
->channel
, strerror(errno
));
11915 /* If enabled for FSK spill then initiate it */
11916 if (mwi_send_init(last
)) {
11917 ast_log(LOG_WARNING
, "Unable to initiate mwi send sequence on channel %d\n", last
->channel
);
11919 analog_p
->msgstate
= res
;
11927 if ((i
->subs
[SUB_REAL
].dfd
> -1) && i
->sig
) {
11928 if (i
->radio
&& !i
->owner
)
11930 res
= dahdi_get_event(i
->subs
[SUB_REAL
].dfd
);
11933 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res
), i
->channel
);
11934 /* Don't hold iflock while handling init events */
11935 ast_mutex_unlock(&iflock
);
11936 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
))
11937 doomed
= (struct dahdi_pvt
*) analog_handle_init_event(i
->sig_pvt
, dahdievent_to_analogevent(res
));
11939 doomed
= handle_init_event(i
, res
);
11940 ast_mutex_lock(&iflock
);
11944 pollres
= ast_fdisset(pfds
, i
->subs
[SUB_REAL
].dfd
, count
, &spoint
);
11945 if (pollres
& POLLIN
) {
11946 if (i
->owner
|| i
->subs
[SUB_REAL
].owner
) {
11950 ast_log(LOG_WARNING
, "Whoa.... I'm owned but found (%d) in read...\n", i
->subs
[SUB_REAL
].dfd
);
11953 if (!i
->mwimonitor_fsk
&& !i
->mwisendactive
&& i
->cid_start
!= CID_START_DTMF_NOALERT
) {
11954 ast_log(LOG_WARNING
, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i
->subs
[SUB_REAL
].dfd
);
11957 res
= read(i
->subs
[SUB_REAL
].dfd
, buf
, sizeof(buf
));
11959 if (i
->mwimonitor_fsk
) {
11960 if (calc_energy((unsigned char *) buf
, res
, AST_LAW(i
)) > mwilevel
) {
11961 pthread_attr_t attr
;
11962 pthread_t threadid
;
11963 struct mwi_thread_data
*mtd
;
11965 pthread_attr_init(&attr
);
11966 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
11968 ast_debug(1, "Maybe some MWI on port %d!\n", i
->channel
);
11969 if ((mtd
= ast_calloc(1, sizeof(*mtd
)))) {
11971 memcpy(mtd
->buf
, buf
, res
);
11973 i
->mwimonitoractive
= 1;
11974 if (ast_pthread_create_background(&threadid
, &attr
, mwi_thread
, mtd
)) {
11975 ast_log(LOG_WARNING
, "Unable to start mwi thread on channel %d\n", i
->channel
);
11976 i
->mwimonitoractive
= 0;
11981 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
11982 } else if (i
->cid_start
== CID_START_DTMF_NOALERT
) {
11984 struct timeval now
;
11985 /* State machine dtmfcid_holdoff_state allows for the line to settle
11986 * before checking agin for dtmf energy. Presently waits for 500 mS before checking again
11988 if (1 == i
->dtmfcid_holdoff_state
) {
11989 gettimeofday(&i
->dtmfcid_delay
, NULL
);
11990 i
->dtmfcid_holdoff_state
= 2;
11991 } else if (2 == i
->dtmfcid_holdoff_state
) {
11992 gettimeofday(&now
, NULL
);
11993 if ((int)(now
.tv_sec
- i
->dtmfcid_delay
.tv_sec
) * 1000000 + (int)now
.tv_usec
- (int)i
->dtmfcid_delay
.tv_usec
> 500000) {
11994 i
->dtmfcid_holdoff_state
= 0;
11997 energy
= calc_energy((unsigned char *) buf
, res
, AST_LAW(i
));
11998 if (!i
->mwisendactive
&& energy
> dtmfcid_level
) {
11999 pthread_t threadid
;
12000 struct ast_channel
*chan
;
12001 ast_mutex_unlock(&iflock
);
12002 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
12003 /* just in case this event changes or somehow destroys a channel, set doomed here too */
12004 doomed
= analog_handle_init_event(i
->sig_pvt
, ANALOG_EVENT_DTMFCID
);
12005 i
->dtmfcid_holdoff_state
= 1;
12007 ast_callid callid
= 0;
12008 int callid_created
= ast_callid_threadstorage_auto(&callid
);
12009 chan
= dahdi_new(i
, AST_STATE_PRERING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
12011 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", i
->channel
);
12013 res
= ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
);
12015 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
12018 i
->dtmfcid_holdoff_state
= 1;
12021 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
12023 ast_mutex_lock(&iflock
);
12027 if (i
->mwisendactive
) {
12028 mwi_send_process_buffer(i
, res
);
12031 ast_log(LOG_WARNING
, "Read failed with %d: %s\n", res
, strerror(errno
));
12034 if (pollres
& POLLPRI
) {
12035 if (i
->owner
|| i
->subs
[SUB_REAL
].owner
) {
12039 ast_log(LOG_WARNING
, "Whoa.... I'm owned but found (%d)...\n", i
->subs
[SUB_REAL
].dfd
);
12042 res
= dahdi_get_event(i
->subs
[SUB_REAL
].dfd
);
12043 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res
), i
->channel
);
12044 /* Don't hold iflock while handling init events */
12045 ast_mutex_unlock(&iflock
);
12046 if (0 == i
->mwisendactive
|| 0 == mwi_send_process_event(i
, res
)) {
12047 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
))
12048 doomed
= (struct dahdi_pvt
*) analog_handle_init_event(i
->sig_pvt
, dahdievent_to_analogevent(res
));
12050 doomed
= handle_init_event(i
, res
);
12052 if (i
->doreoriginate
&& res
== DAHDI_EVENT_HOOKCOMPLETE
) {
12053 /* Actually automatically reoriginate this FXS line, if directed to.
12054 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12055 * doing its thing (one reason why this is for FXOKS only: FXOLS
12056 * hangups don't give us any DAHDI events to piggyback off of)*/
12057 i
->doreoriginate
= 0;
12058 /* Double check the channel is still off-hook. There's only about a millisecond
12059 * between when doreoriginate is set high and we see that here, but just to be safe. */
12060 if (!my_is_off_hook(i
)) {
12061 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i
->channel
);
12063 ast_verb(3, "Automatic reorigination on channel %d\n", i
->channel
);
12064 res
= DAHDI_EVENT_RINGOFFHOOK
; /* Pretend that the physical channel just went off hook */
12065 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
12066 doomed
= (struct dahdi_pvt
*) analog_handle_init_event(i
->sig_pvt
, dahdievent_to_analogevent(res
));
12068 doomed
= handle_init_event(i
, res
);
12072 ast_mutex_lock(&iflock
);
12076 ast_mutex_unlock(&iflock
);
12077 release_doomed_pris();
12079 dahdi_r2_destroy_nodev();
12082 /* Never reached */
12083 pthread_cleanup_pop(1);
12088 static int restart_monitor(void)
12090 /* If we're supposed to be stopped -- stay stopped */
12091 if (monitor_thread
== AST_PTHREADT_STOP
)
12093 ast_mutex_lock(&monlock
);
12094 if (monitor_thread
== pthread_self()) {
12095 ast_mutex_unlock(&monlock
);
12096 ast_log(LOG_WARNING
, "Cannot kill myself\n");
12099 if (monitor_thread
!= AST_PTHREADT_NULL
) {
12100 /* Wake up the thread */
12101 pthread_kill(monitor_thread
, SIGURG
);
12103 /* Start a new monitor */
12104 if (ast_pthread_create_background(&monitor_thread
, NULL
, do_monitor
, NULL
) < 0) {
12105 ast_mutex_unlock(&monlock
);
12106 ast_log(LOG_ERROR
, "Unable to start monitor thread.\n");
12110 ast_mutex_unlock(&monlock
);
12114 #if defined(HAVE_PRI)
12115 static int pri_resolve_span(int *span
, int channel
, int offset
, struct dahdi_spaninfo
*si
)
12119 /* Get appropriate trunk group if there is one */
12120 trunkgroup
= pris
[*span
].mastertrunkgroup
;
12122 /* Select a specific trunk group */
12123 for (x
= 0; x
< NUM_SPANS
; x
++) {
12124 if (pris
[x
].pri
.trunkgroup
== trunkgroup
) {
12129 ast_log(LOG_WARNING
, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel
, *span
, trunkgroup
);
12132 if (pris
[*span
].pri
.trunkgroup
) {
12133 ast_log(LOG_WARNING
, "Unable to use span %d implicitly since it is trunk group %d (please use spanmap)\n", *span
, pris
[*span
].pri
.trunkgroup
);
12135 } else if (pris
[*span
].mastertrunkgroup
) {
12136 ast_log(LOG_WARNING
, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span
, pris
[*span
].mastertrunkgroup
);
12139 if (si
->totalchans
== 31) {
12141 pris
[*span
].dchannels
[0] = 16 + offset
;
12142 } else if (si
->totalchans
== 24) {
12144 pris
[*span
].dchannels
[0] = 24 + offset
;
12145 } else if (si
->totalchans
== 3) {
12147 pris
[*span
].dchannels
[0] = 3 + offset
;
12149 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
);
12153 pris
[*span
].pri
.span
= *span
+ 1;
12158 #endif /* defined(HAVE_PRI) */
12160 #if defined(HAVE_PRI)
12161 static int pri_create_trunkgroup(int trunkgroup
, int *channels
)
12163 struct dahdi_spaninfo si
;
12164 struct dahdi_params p
;
12169 for (x
= 0; x
< NUM_SPANS
; x
++) {
12170 if (pris
[x
].pri
.trunkgroup
== trunkgroup
) {
12171 ast_log(LOG_WARNING
, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup
, x
+ 1, pris
[x
].dchannels
[0]);
12175 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
12178 memset(&si
, 0, sizeof(si
));
12179 memset(&p
, 0, sizeof(p
));
12180 fd
= open("/dev/dahdi/channel", O_RDWR
);
12182 ast_log(LOG_WARNING
, "Failed to open channel: %s\n", strerror(errno
));
12186 if (ioctl(fd
, DAHDI_SPECIFY
, &x
)) {
12187 ast_log(LOG_WARNING
, "Failed to specify channel %d: %s\n", channels
[y
], strerror(errno
));
12191 if (ioctl(fd
, DAHDI_GET_PARAMS
, &p
)) {
12192 ast_log(LOG_WARNING
, "Failed to get channel parameters for channel %d: %s\n", channels
[y
], strerror(errno
));
12196 if (ioctl(fd
, DAHDI_SPANSTAT
, &si
)) {
12197 ast_log(LOG_WARNING
, "Failed go get span information on channel %d (span %d): %s\n", channels
[y
], p
.spanno
, strerror(errno
));
12201 span
= p
.spanno
- 1;
12202 if (pris
[span
].pri
.trunkgroup
) {
12203 ast_log(LOG_WARNING
, "Span %d is already provisioned for trunk group %d\n", span
+ 1, pris
[span
].pri
.trunkgroup
);
12207 if (pris
[span
].pri
.pvts
[0]) {
12208 ast_log(LOG_WARNING
, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span
+ 1);
12213 pris
[span
].pri
.trunkgroup
= trunkgroup
;
12216 pris
[ospan
].dchannels
[y
] = channels
[y
];
12217 pris
[span
].pri
.span
= span
+ 1;
12222 #endif /* defined(HAVE_PRI) */
12224 #if defined(HAVE_PRI)
12225 static int pri_create_spanmap(int span
, int trunkgroup
, int logicalspan
)
12227 if (pris
[span
].mastertrunkgroup
) {
12228 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
);
12231 pris
[span
].mastertrunkgroup
= trunkgroup
;
12232 pris
[span
].prilogicalspan
= logicalspan
;
12235 #endif /* defined(HAVE_PRI) */
12237 #if defined(HAVE_SS7)
12238 static unsigned int parse_pointcode(const char *pcstring
)
12240 unsigned int code1
, code2
, code3
;
12243 numvals
= sscanf(pcstring
, "%30d-%30d-%30d", &code1
, &code2
, &code3
);
12247 return (code1
<< 16) | (code2
<< 8) | code3
;
12251 #endif /* defined(HAVE_SS7) */
12253 #if defined(HAVE_SS7)
12254 static struct dahdi_ss7
* ss7_resolve_linkset(int linkset
)
12256 if ((linkset
< 0) || (linkset
>= NUM_SPANS
))
12259 return &linksets
[linkset
- 1];
12261 #endif /* defined(HAVE_SS7) */
12264 static void dahdi_r2_destroy_links(void)
12266 struct r2link_entry
*cur
;
12268 /* Queue everything for removal */
12269 AST_LIST_LOCK(&r2links
);
12270 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links
, cur
, list
) {
12271 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur
->mfcr2
.index
);
12272 AST_LIST_MOVE_CURRENT(&nodev_r2links
, list
);
12274 AST_LIST_TRAVERSE_SAFE_END
;
12275 AST_LIST_UNLOCK(&r2links
);
12276 /* Now destroy properly */
12277 dahdi_r2_destroy_nodev();
12280 /* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12281 #define R2_LINK_CAPACITY 30
12282 static struct r2link_entry
*dahdi_r2_get_link(const struct dahdi_chan_conf
*conf
)
12284 struct r2link_entry
*cur
= NULL
;
12285 /* Only create a new R2 link if
12286 1. This is the first link requested
12287 2. Configuration changed
12288 3. We got more channels than supported per link */
12289 AST_LIST_LOCK(&r2links
);
12290 if (! AST_LIST_EMPTY(&r2links
)) {
12291 cur
= AST_LIST_LAST(&r2links
);
12292 if (memcmp(&conf
->mfcr2
, &cur
->mfcr2
.conf
, sizeof(conf
->mfcr2
))) {
12293 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12295 } else if (cur
->mfcr2
.numchans
== R2_LINK_CAPACITY
) {
12296 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY
);
12301 struct r2link_entry
*tmp
= NULL
;
12302 int new_idx
= r2links_count
+ 1;
12304 for (i
= 1; i
<= r2links_count
; i
++) {
12306 AST_LIST_TRAVERSE(&r2links
, tmp
, list
) {
12307 if (i
== tmp
->mfcr2
.index
) {
12317 cur
= ast_calloc(1, sizeof(*cur
));
12319 ast_log(LOG_ERROR
, "Cannot allocate R2 link!\n");
12322 cur
->mfcr2
.index
= new_idx
;
12323 cur
->mfcr2
.r2master
= AST_PTHREADT_NULL
;
12325 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx
, r2links_count
);
12326 AST_LIST_INSERT_TAIL(&r2links
, cur
, list
);
12328 AST_LIST_UNLOCK(&r2links
);
12332 static int dahdi_r2_set_context(struct dahdi_mfcr2
*r2_link
, const struct dahdi_chan_conf
*conf
)
12334 char tmplogdir
[] = "/tmp";
12335 char logdir
[OR2_MAX_PATH
];
12338 r2_link
->protocol_context
= openr2_context_new(NULL
, &dahdi_r2_event_iface
,
12339 &dahdi_r2_transcode_iface
, conf
->mfcr2
.variant
, conf
->mfcr2
.max_ani
,
12340 conf
->mfcr2
.max_dnis
);
12341 if (!r2_link
->protocol_context
) {
12344 openr2_context_set_log_level(r2_link
->protocol_context
, conf
->mfcr2
.loglevel
);
12345 openr2_context_set_ani_first(r2_link
->protocol_context
, conf
->mfcr2
.get_ani_first
);
12346 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12347 openr2_context_set_skip_category_request(r2_link
->protocol_context
, conf
->mfcr2
.skip_category_request
);
12349 openr2_context_set_mf_threshold(r2_link
->protocol_context
, threshold
);
12350 openr2_context_set_mf_back_timeout(r2_link
->protocol_context
, conf
->mfcr2
.mfback_timeout
);
12351 openr2_context_set_metering_pulse_timeout(r2_link
->protocol_context
, conf
->mfcr2
.metering_pulse_timeout
);
12352 openr2_context_set_double_answer(r2_link
->protocol_context
, conf
->mfcr2
.double_answer
);
12353 openr2_context_set_immediate_accept(r2_link
->protocol_context
, conf
->mfcr2
.immediate_accept
);
12354 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12355 openr2_context_set_dtmf_dialing(r2_link
->protocol_context
, conf
->mfcr2
.dtmf_dialing
, conf
->mfcr2
.dtmf_time_on
, conf
->mfcr2
.dtmf_time_off
);
12356 openr2_context_set_dtmf_detection(r2_link
->protocol_context
, conf
->mfcr2
.dtmf_detection
);
12358 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12359 openr2_context_set_dtmf_detection_end_timeout(r2_link
->protocol_context
, conf
->mfcr2
.dtmf_end_timeout
);
12361 if (ast_strlen_zero(conf
->mfcr2
.logdir
)) {
12362 if (openr2_context_set_log_directory(r2_link
->protocol_context
, tmplogdir
)) {
12363 ast_log(LOG_ERROR
, "Failed setting default MFC/R2 log directory %s\n", tmplogdir
);
12366 snres
= snprintf(logdir
, sizeof(logdir
), "%s/%s/%s", ast_config_AST_LOG_DIR
, "mfcr2", conf
->mfcr2
.logdir
);
12367 if (snres
>= sizeof(logdir
)) {
12368 ast_log(LOG_ERROR
, "MFC/R2 logging directory truncated, using %s\n", tmplogdir
);
12369 if (openr2_context_set_log_directory(r2_link
->protocol_context
, tmplogdir
)) {
12370 ast_log(LOG_ERROR
, "Failed setting default MFC/R2 log directory %s\n", tmplogdir
);
12373 if (openr2_context_set_log_directory(r2_link
->protocol_context
, logdir
)) {
12374 ast_log(LOG_ERROR
, "Failed setting MFC/R2 log directory %s\n", logdir
);
12378 if (!ast_strlen_zero(conf
->mfcr2
.r2proto_file
)) {
12379 if (openr2_context_configure_from_advanced_file(r2_link
->protocol_context
, conf
->mfcr2
.r2proto_file
)) {
12380 ast_log(LOG_ERROR
, "Failed to configure r2context from advanced configuration file %s\n", conf
->mfcr2
.r2proto_file
);
12383 /* Save the configuration used to setup this link */
12384 memcpy(&r2_link
->conf
, &conf
->mfcr2
, sizeof(r2_link
->conf
));
12389 /* converts a DAHDI sigtype to signalling as can be configured from
12391 * While both have basically the same values, this will later be the
12392 * place to add filters and sanity checks
12394 static int sigtype_to_signalling(int sigtype
)
12401 * \brief Initialize/create a channel interface.
12403 * \param channel Channel interface number to initialize/create.
12404 * \param conf Configuration parameters to initialize interface with.
12405 * \param reloading What we are doing now:
12406 * 0 - initial module load,
12407 * 1 - module reload,
12408 * 2 - module restart
12410 * \retval Interface-pointer initialized/created
12411 * \retval NULL if error
12413 static struct dahdi_pvt
*mkintf(int channel
, const struct dahdi_chan_conf
*conf
, int reloading
)
12415 /* Make a dahdi_pvt structure for this interface */
12416 struct dahdi_pvt
*tmp
;/*!< Current channel structure initializing */
12418 struct dahdi_bufferinfo bi
;
12421 #if defined(HAVE_PRI)
12423 #endif /* defined(HAVE_PRI) */
12424 int here
= 0;/*!< TRUE if the channel interface already exists. */
12426 struct analog_pvt
*analog_p
= NULL
;
12427 struct dahdi_params p
;
12428 #if defined(HAVE_PRI)
12429 struct dahdi_spaninfo si
;
12430 struct sig_pri_chan
*pri_chan
= NULL
;
12431 #endif /* defined(HAVE_PRI) */
12432 #if defined(HAVE_SS7)
12433 struct sig_ss7_chan
*ss7_chan
= NULL
;
12434 #endif /* defined(HAVE_SS7) */
12436 /* Search channel interface list to see if it already exists. */
12437 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
12438 if (!tmp
->destroy
) {
12439 if (tmp
->channel
== channel
) {
12440 /* The channel interface already exists. */
12444 if (tmp
->channel
> channel
) {
12445 /* No way it can be in the sorted list. */
12452 if (!here
&& reloading
!= 1) {
12453 tmp
= ast_calloc(1, sizeof(*tmp
));
12457 tmp
->cc_params
= ast_cc_config_params_init();
12458 if (!tmp
->cc_params
) {
12462 ast_mutex_init(&tmp
->lock
);
12464 for (x
= 0; x
< 3; x
++)
12465 tmp
->subs
[x
].dfd
= -1;
12466 tmp
->channel
= channel
;
12467 tmp
->priindication_oob
= conf
->chan
.priindication_oob
;
12471 int chan_sig
= conf
->chan
.sig
;
12473 /* If there are variables in tmp before it is updated to match the new config, clear them */
12474 if (reloading
&& tmp
->vars
) {
12475 ast_variables_destroy(tmp
->vars
);
12480 /* Can only get here if this is a new channel interface being created. */
12481 if ((channel
!= CHAN_PSEUDO
)) {
12484 snprintf(fn
, sizeof(fn
), "%d", channel
);
12485 /* Open non-blocking */
12486 tmp
->subs
[SUB_REAL
].dfd
= dahdi_open(fn
);
12487 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 */
12489 tmp
->subs
[SUB_REAL
].dfd
= dahdi_open(fn
);
12492 /* Allocate a DAHDI structure */
12493 if (tmp
->subs
[SUB_REAL
].dfd
< 0) {
12494 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
);
12495 destroy_dahdi_pvt(tmp
);
12498 memset(&p
, 0, sizeof(p
));
12499 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &p
);
12501 ast_log(LOG_ERROR
, "Unable to get parameters: %s\n", strerror(errno
));
12502 destroy_dahdi_pvt(tmp
);
12505 if (conf
->is_sig_auto
)
12506 chan_sig
= sigtype_to_signalling(p
.sigtype
);
12507 if (p
.sigtype
!= (chan_sig
& 0x3ffff)) {
12508 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
));
12509 destroy_dahdi_pvt(tmp
);
12512 tmp
->law_default
= p
.curlaw
;
12513 tmp
->law
= p
.curlaw
;
12514 tmp
->span
= p
.spanno
;
12515 #if defined(HAVE_PRI)
12516 span
= p
.spanno
- 1;
12517 #endif /* defined(HAVE_PRI) */
12521 tmp
->sig
= chan_sig
;
12522 tmp
->outsigmod
= conf
->chan
.outsigmod
;
12524 if (dahdi_analog_lib_handles(chan_sig
, tmp
->radio
, tmp
->oprmode
)) {
12525 analog_p
= analog_new(dahdisig_to_analogsig(chan_sig
), tmp
);
12527 destroy_dahdi_pvt(tmp
);
12530 tmp
->sig_pvt
= analog_p
;
12532 #if defined(HAVE_SS7)
12533 if (chan_sig
== SIG_SS7
) {
12534 struct dahdi_ss7
*ss7
;
12537 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &clear
)) {
12538 ast_log(LOG_ERROR
, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel
, p
.spanno
, strerror(errno
));
12539 destroy_dahdi_pvt(tmp
);
12543 ss7
= ss7_resolve_linkset(cur_linkset
);
12545 ast_log(LOG_ERROR
, "Unable to find linkset %d\n", cur_linkset
);
12546 destroy_dahdi_pvt(tmp
);
12549 ss7
->ss7
.span
= cur_linkset
;
12550 if (cur_cicbeginswith
< 0) {
12551 ast_log(LOG_ERROR
, "Need to set cicbeginswith for the channels!\n");
12552 destroy_dahdi_pvt(tmp
);
12555 ss7_chan
= sig_ss7_chan_new(tmp
, &ss7
->ss7
);
12557 destroy_dahdi_pvt(tmp
);
12560 tmp
->sig_pvt
= ss7_chan
;
12561 tmp
->ss7
= &ss7
->ss7
;
12563 ss7_chan
->channel
= tmp
->channel
;
12564 ss7_chan
->cic
= cur_cicbeginswith
++;
12566 /* DB: Add CIC's DPC information */
12567 ss7_chan
->dpc
= cur_defaultdpc
;
12569 ss7
->ss7
.pvts
[ss7
->ss7
.numchans
++] = ss7_chan
;
12571 ast_copy_string(ss7
->ss7
.internationalprefix
, conf
->ss7
.ss7
.internationalprefix
, sizeof(ss7
->ss7
.internationalprefix
));
12572 ast_copy_string(ss7
->ss7
.nationalprefix
, conf
->ss7
.ss7
.nationalprefix
, sizeof(ss7
->ss7
.nationalprefix
));
12573 ast_copy_string(ss7
->ss7
.subscriberprefix
, conf
->ss7
.ss7
.subscriberprefix
, sizeof(ss7
->ss7
.subscriberprefix
));
12574 ast_copy_string(ss7
->ss7
.unknownprefix
, conf
->ss7
.ss7
.unknownprefix
, sizeof(ss7
->ss7
.unknownprefix
));
12575 ast_copy_string(ss7
->ss7
.networkroutedprefix
, conf
->ss7
.ss7
.networkroutedprefix
, sizeof(ss7
->ss7
.networkroutedprefix
));
12577 ss7
->ss7
.called_nai
= conf
->ss7
.ss7
.called_nai
;
12578 ss7
->ss7
.calling_nai
= conf
->ss7
.ss7
.calling_nai
;
12580 #endif /* defined(HAVE_SS7) */
12582 if (chan_sig
== SIG_MFCR2
) {
12583 struct dahdi_mfcr2
*r2_link
;
12584 struct r2link_entry
*r2_le
= dahdi_r2_get_link(conf
);
12585 r2_link
= &r2_le
->mfcr2
;
12587 ast_log(LOG_WARNING
, "Cannot get another R2 DAHDI context!\n");
12588 destroy_dahdi_pvt(tmp
);
12591 if (!r2_link
->protocol_context
&& dahdi_r2_set_context(r2_link
, conf
)) {
12592 ast_log(LOG_ERROR
, "Cannot create OpenR2 protocol context.\n");
12593 destroy_dahdi_pvt(tmp
);
12596 if (r2_link
->numchans
== ARRAY_LEN(r2_link
->pvts
)) {
12597 ast_log(LOG_ERROR
, "Cannot add more channels to this link!\n");
12598 destroy_dahdi_pvt(tmp
);
12601 r2_link
->pvts
[r2_link
->numchans
++] = tmp
;
12602 tmp
->r2chan
= openr2_chan_new_from_fd(r2_link
->protocol_context
,
12603 tmp
->subs
[SUB_REAL
].dfd
,
12605 if (!tmp
->r2chan
) {
12606 openr2_liberr_t err
= openr2_context_get_last_error(r2_link
->protocol_context
);
12607 ast_log(LOG_ERROR
, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err
));
12608 destroy_dahdi_pvt(tmp
);
12611 r2_link
->live_chans
++;
12612 tmp
->mfcr2
= r2_link
;
12613 if (conf
->mfcr2
.call_files
) {
12614 openr2_chan_enable_call_files(tmp
->r2chan
);
12616 openr2_chan_set_client_data(tmp
->r2chan
, tmp
);
12617 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12618 openr2_chan_set_logging_func(tmp
->r2chan
, (openr2_logging_func_t
)dahdi_r2_on_chan_log
);
12619 openr2_chan_set_log_level(tmp
->r2chan
, conf
->mfcr2
.loglevel
);
12620 tmp
->mfcr2_category
= conf
->mfcr2
.category
;
12621 tmp
->mfcr2_charge_calls
= conf
->mfcr2
.charge_calls
;
12622 tmp
->mfcr2_allow_collect_calls
= conf
->mfcr2
.allow_collect_calls
;
12623 tmp
->mfcr2_forced_release
= conf
->mfcr2
.forced_release
;
12624 tmp
->mfcr2_accept_on_offer
= conf
->mfcr2
.accept_on_offer
;
12625 tmp
->mfcr2call
= 0;
12626 tmp
->mfcr2_dnis_index
= 0;
12627 tmp
->mfcr2_ani_index
= 0;
12631 if (dahdi_sig_pri_lib_handles(chan_sig
)) {
12635 int myswitchtype
= 0;
12638 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &offset
)) {
12639 ast_log(LOG_ERROR
, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel
, p
.spanno
, strerror(errno
));
12640 destroy_dahdi_pvt(tmp
);
12643 if (span
>= NUM_SPANS
) {
12644 ast_log(LOG_ERROR
, "Channel %d does not lie on a span I know of (%d)\n", channel
, span
);
12645 destroy_dahdi_pvt(tmp
);
12649 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
,DAHDI_SPANSTAT
,&si
) == -1) {
12650 ast_log(LOG_ERROR
, "Unable to get span status: %s\n", strerror(errno
));
12651 destroy_dahdi_pvt(tmp
);
12654 /* Store the logical span first based upon the real span */
12655 tmp
->logicalspan
= pris
[span
].prilogicalspan
;
12656 pri_resolve_span(&span
, channel
, (channel
- p
.chanpos
), &si
);
12658 ast_log(LOG_WARNING
, "Channel %d: Unable to find locate channel/trunk group!\n", channel
);
12659 destroy_dahdi_pvt(tmp
);
12662 myswitchtype
= conf
->pri
.pri
.switchtype
;
12663 /* Make sure this isn't a d-channel */
12665 for (x
= 0; x
< NUM_SPANS
; x
++) {
12666 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
12667 if (pris
[x
].dchannels
[y
] == tmp
->channel
) {
12673 if (!matchesdchan
) {
12674 if (pris
[span
].pri
.nodetype
&& (pris
[span
].pri
.nodetype
!= conf
->pri
.pri
.nodetype
)) {
12675 ast_log(LOG_ERROR
, "Span %d is already a %s node\n", span
+ 1, pri_node2str(pris
[span
].pri
.nodetype
));
12676 destroy_dahdi_pvt(tmp
);
12679 if (pris
[span
].pri
.switchtype
&& (pris
[span
].pri
.switchtype
!= myswitchtype
)) {
12680 ast_log(LOG_ERROR
, "Span %d is already a %s switch\n", span
+ 1, pri_switch2str(pris
[span
].pri
.switchtype
));
12681 destroy_dahdi_pvt(tmp
);
12684 if ((pris
[span
].pri
.dialplan
) && (pris
[span
].pri
.dialplan
!= conf
->pri
.pri
.dialplan
)) {
12685 ast_log(LOG_ERROR
, "Span %d is already a %s dialing plan\n", span
+ 1, pris
[span
].pri
.dialplan
== -1 ? "Dynamically set dialplan in ISDN" : pri_plan2str(pris
[span
].pri
.dialplan
));
12686 destroy_dahdi_pvt(tmp
);
12689 if (!ast_strlen_zero(pris
[span
].pri
.idledial
) && strcmp(pris
[span
].pri
.idledial
, conf
->pri
.pri
.idledial
)) {
12690 ast_log(LOG_ERROR
, "Span %d already has idledial '%s'.\n", span
+ 1, conf
->pri
.pri
.idledial
);
12691 destroy_dahdi_pvt(tmp
);
12694 if (!ast_strlen_zero(pris
[span
].pri
.idleext
) && strcmp(pris
[span
].pri
.idleext
, conf
->pri
.pri
.idleext
)) {
12695 ast_log(LOG_ERROR
, "Span %d already has idleext '%s'.\n", span
+ 1, conf
->pri
.pri
.idleext
);
12696 destroy_dahdi_pvt(tmp
);
12699 if (pris
[span
].pri
.minunused
&& (pris
[span
].pri
.minunused
!= conf
->pri
.pri
.minunused
)) {
12700 ast_log(LOG_ERROR
, "Span %d already has minunused of %d.\n", span
+ 1, conf
->pri
.pri
.minunused
);
12701 destroy_dahdi_pvt(tmp
);
12704 if (pris
[span
].pri
.minidle
&& (pris
[span
].pri
.minidle
!= conf
->pri
.pri
.minidle
)) {
12705 ast_log(LOG_ERROR
, "Span %d already has minidle of %d.\n", span
+ 1, conf
->pri
.pri
.minidle
);
12706 destroy_dahdi_pvt(tmp
);
12709 if (pris
[span
].pri
.numchans
>= ARRAY_LEN(pris
[span
].pri
.pvts
)) {
12710 ast_log(LOG_ERROR
, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel
,
12711 pris
[span
].pri
.trunkgroup
);
12712 destroy_dahdi_pvt(tmp
);
12716 pri_chan
= sig_pri_chan_new(tmp
, &pris
[span
].pri
, tmp
->logicalspan
, p
.chanpos
, pris
[span
].mastertrunkgroup
);
12718 destroy_dahdi_pvt(tmp
);
12721 tmp
->sig_pvt
= pri_chan
;
12722 tmp
->pri
= &pris
[span
].pri
;
12724 tmp
->priexclusive
= conf
->chan
.priexclusive
;
12726 if (!tmp
->pri
->cc_params
) {
12727 tmp
->pri
->cc_params
= ast_cc_config_params_init();
12728 if (!tmp
->pri
->cc_params
) {
12729 destroy_dahdi_pvt(tmp
);
12733 ast_cc_copy_config_params(tmp
->pri
->cc_params
,
12734 conf
->chan
.cc_params
);
12736 pris
[span
].pri
.sig
= chan_sig
;
12737 pris
[span
].pri
.nodetype
= conf
->pri
.pri
.nodetype
;
12738 pris
[span
].pri
.switchtype
= myswitchtype
;
12739 pris
[span
].pri
.nsf
= conf
->pri
.pri
.nsf
;
12740 pris
[span
].pri
.dialplan
= conf
->pri
.pri
.dialplan
;
12741 pris
[span
].pri
.localdialplan
= conf
->pri
.pri
.localdialplan
;
12742 pris
[span
].pri
.cpndialplan
= conf
->pri
.pri
.cpndialplan
;
12743 pris
[span
].pri
.pvts
[pris
[span
].pri
.numchans
++] = tmp
->sig_pvt
;
12744 pris
[span
].pri
.minunused
= conf
->pri
.pri
.minunused
;
12745 pris
[span
].pri
.minidle
= conf
->pri
.pri
.minidle
;
12746 pris
[span
].pri
.overlapdial
= conf
->pri
.pri
.overlapdial
;
12747 pris
[span
].pri
.qsigchannelmapping
= conf
->pri
.pri
.qsigchannelmapping
;
12748 pris
[span
].pri
.discardremoteholdretrieval
= conf
->pri
.pri
.discardremoteholdretrieval
;
12749 #if defined(HAVE_PRI_SERVICE_MESSAGES)
12750 pris
[span
].pri
.enable_service_message_support
= conf
->pri
.pri
.enable_service_message_support
;
12751 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12752 #ifdef HAVE_PRI_INBANDDISCONNECT
12753 pris
[span
].pri
.inbanddisconnect
= conf
->pri
.pri
.inbanddisconnect
;
12755 #if defined(HAVE_PRI_CALL_HOLD)
12756 pris
[span
].pri
.hold_disconnect_transfer
=
12757 conf
->pri
.pri
.hold_disconnect_transfer
;
12758 #endif /* defined(HAVE_PRI_CALL_HOLD) */
12759 #if defined(HAVE_PRI_CCSS)
12760 pris
[span
].pri
.cc_ptmp_recall_mode
=
12761 conf
->pri
.pri
.cc_ptmp_recall_mode
;
12762 pris
[span
].pri
.cc_qsig_signaling_link_req
=
12763 conf
->pri
.pri
.cc_qsig_signaling_link_req
;
12764 pris
[span
].pri
.cc_qsig_signaling_link_rsp
=
12765 conf
->pri
.pri
.cc_qsig_signaling_link_rsp
;
12766 #endif /* defined(HAVE_PRI_CCSS) */
12767 #if defined(HAVE_PRI_CALL_WAITING)
12768 pris
[span
].pri
.max_call_waiting_calls
=
12769 conf
->pri
.pri
.max_call_waiting_calls
;
12770 pris
[span
].pri
.allow_call_waiting_calls
=
12771 conf
->pri
.pri
.allow_call_waiting_calls
;
12772 #endif /* defined(HAVE_PRI_CALL_WAITING) */
12773 pris
[span
].pri
.transfer
= conf
->chan
.transfer
;
12774 pris
[span
].pri
.facilityenable
= conf
->pri
.pri
.facilityenable
;
12775 #if defined(HAVE_PRI_L2_PERSISTENCE)
12776 pris
[span
].pri
.l2_persistence
= conf
->pri
.pri
.l2_persistence
;
12777 #endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12778 pris
[span
].pri
.colp_send
= conf
->pri
.pri
.colp_send
;
12779 #if defined(HAVE_PRI_AOC_EVENTS)
12780 pris
[span
].pri
.aoc_passthrough_flag
= conf
->pri
.pri
.aoc_passthrough_flag
;
12781 pris
[span
].pri
.aoce_delayhangup
= conf
->pri
.pri
.aoce_delayhangup
;
12782 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
12783 if (chan_sig
== SIG_BRI_PTMP
) {
12784 pris
[span
].pri
.layer1_ignored
= conf
->pri
.pri
.layer1_ignored
;
12786 /* Option does not apply to this line type. */
12787 pris
[span
].pri
.layer1_ignored
= 0;
12789 pris
[span
].pri
.append_msn_to_user_tag
= conf
->pri
.pri
.append_msn_to_user_tag
;
12790 pris
[span
].pri
.inband_on_setup_ack
= conf
->pri
.pri
.inband_on_setup_ack
;
12791 pris
[span
].pri
.inband_on_proceeding
= conf
->pri
.pri
.inband_on_proceeding
;
12792 ast_copy_string(pris
[span
].pri
.initial_user_tag
, conf
->chan
.cid_tag
, sizeof(pris
[span
].pri
.initial_user_tag
));
12793 ast_copy_string(pris
[span
].pri
.msn_list
, conf
->pri
.pri
.msn_list
, sizeof(pris
[span
].pri
.msn_list
));
12794 #if defined(HAVE_PRI_MWI)
12795 ast_copy_string(pris
[span
].pri
.mwi_mailboxes
,
12796 conf
->pri
.pri
.mwi_mailboxes
,
12797 sizeof(pris
[span
].pri
.mwi_mailboxes
));
12798 ast_copy_string(pris
[span
].pri
.mwi_vm_boxes
,
12799 conf
->pri
.pri
.mwi_vm_boxes
,
12800 sizeof(pris
[span
].pri
.mwi_vm_boxes
));
12801 ast_copy_string(pris
[span
].pri
.mwi_vm_numbers
,
12802 conf
->pri
.pri
.mwi_vm_numbers
,
12803 sizeof(pris
[span
].pri
.mwi_vm_numbers
));
12804 #endif /* defined(HAVE_PRI_MWI) */
12805 ast_copy_string(pris
[span
].pri
.idledial
, conf
->pri
.pri
.idledial
, sizeof(pris
[span
].pri
.idledial
));
12806 ast_copy_string(pris
[span
].pri
.idleext
, conf
->pri
.pri
.idleext
, sizeof(pris
[span
].pri
.idleext
));
12807 ast_copy_string(pris
[span
].pri
.internationalprefix
, conf
->pri
.pri
.internationalprefix
, sizeof(pris
[span
].pri
.internationalprefix
));
12808 ast_copy_string(pris
[span
].pri
.nationalprefix
, conf
->pri
.pri
.nationalprefix
, sizeof(pris
[span
].pri
.nationalprefix
));
12809 ast_copy_string(pris
[span
].pri
.localprefix
, conf
->pri
.pri
.localprefix
, sizeof(pris
[span
].pri
.localprefix
));
12810 ast_copy_string(pris
[span
].pri
.privateprefix
, conf
->pri
.pri
.privateprefix
, sizeof(pris
[span
].pri
.privateprefix
));
12811 ast_copy_string(pris
[span
].pri
.unknownprefix
, conf
->pri
.pri
.unknownprefix
, sizeof(pris
[span
].pri
.unknownprefix
));
12812 pris
[span
].pri
.moh_signaling
= conf
->pri
.pri
.moh_signaling
;
12813 pris
[span
].pri
.resetinterval
= conf
->pri
.pri
.resetinterval
;
12814 #if defined(HAVE_PRI_DISPLAY_TEXT)
12815 pris
[span
].pri
.display_flags_send
= conf
->pri
.pri
.display_flags_send
;
12816 pris
[span
].pri
.display_flags_receive
= conf
->pri
.pri
.display_flags_receive
;
12817 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
12818 #if defined(HAVE_PRI_MCID)
12819 pris
[span
].pri
.mcid_send
= conf
->pri
.pri
.mcid_send
;
12820 #endif /* defined(HAVE_PRI_MCID) */
12821 pris
[span
].pri
.force_restart_unavailable_chans
= conf
->pri
.pri
.force_restart_unavailable_chans
;
12822 #if defined(HAVE_PRI_DATETIME_SEND)
12823 pris
[span
].pri
.datetime_send
= conf
->pri
.pri
.datetime_send
;
12824 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
12826 for (x
= 0; x
< PRI_MAX_TIMERS
; x
++) {
12827 pris
[span
].pri
.pritimers
[x
] = conf
->pri
.pri
.pritimers
[x
];
12830 #if defined(HAVE_PRI_CALL_WAITING)
12831 /* Channel initial config parameters. */
12832 pris
[span
].pri
.ch_cfg
.stripmsd
= conf
->chan
.stripmsd
;
12833 pris
[span
].pri
.ch_cfg
.hidecallerid
= conf
->chan
.hidecallerid
;
12834 pris
[span
].pri
.ch_cfg
.hidecalleridname
= conf
->chan
.hidecalleridname
;
12835 pris
[span
].pri
.ch_cfg
.immediate
= conf
->chan
.immediate
;
12836 pris
[span
].pri
.ch_cfg
.priexclusive
= conf
->chan
.priexclusive
;
12837 pris
[span
].pri
.ch_cfg
.priindication_oob
= conf
->chan
.priindication_oob
;
12838 pris
[span
].pri
.ch_cfg
.use_callerid
= conf
->chan
.use_callerid
;
12839 pris
[span
].pri
.ch_cfg
.use_callingpres
= conf
->chan
.use_callingpres
;
12840 ast_copy_string(pris
[span
].pri
.ch_cfg
.context
, conf
->chan
.context
, sizeof(pris
[span
].pri
.ch_cfg
.context
));
12841 ast_copy_string(pris
[span
].pri
.ch_cfg
.mohinterpret
, conf
->chan
.mohinterpret
, sizeof(pris
[span
].pri
.ch_cfg
.mohinterpret
));
12842 #endif /* defined(HAVE_PRI_CALL_WAITING) */
12844 ast_log(LOG_ERROR
, "Channel %d is reserved for D-channel.\n", p
.chanpos
);
12845 destroy_dahdi_pvt(tmp
);
12852 /* already exists in interface list */
12853 ast_log(LOG_WARNING
, "Attempt to configure channel %d with signaling %s ignored because it is already configured to be %s.\n", tmp
->channel
, dahdi_sig2str(chan_sig
), dahdi_sig2str(tmp
->sig
));
12854 chan_sig
= tmp
->sig
;
12855 if (tmp
->subs
[SUB_REAL
].dfd
> -1) {
12856 memset(&p
, 0, sizeof(p
));
12857 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &p
);
12860 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
12861 switch (chan_sig
) {
12869 case SIG_FEATDMF_TA
:
12875 case SIG_FGC_CAMAMF
:
12877 case SIG_SF_FEATDMF
:
12884 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
12885 p
.channo
= channel
;
12889 p
.debouncetime
= 5;
12891 p
.channo
= channel
;
12892 /* Override timing settings based on config file */
12893 if (conf
->timing
.prewinktime
>= 0)
12894 p
.prewinktime
= conf
->timing
.prewinktime
;
12895 if (conf
->timing
.preflashtime
>= 0)
12896 p
.preflashtime
= conf
->timing
.preflashtime
;
12897 if (conf
->timing
.winktime
>= 0)
12898 p
.winktime
= conf
->timing
.winktime
;
12899 if (conf
->timing
.flashtime
>= 0)
12900 p
.flashtime
= conf
->timing
.flashtime
;
12901 if (conf
->timing
.starttime
>= 0)
12902 p
.starttime
= conf
->timing
.starttime
;
12903 if (conf
->timing
.rxwinktime
>= 0)
12904 p
.rxwinktime
= conf
->timing
.rxwinktime
;
12905 if (conf
->timing
.rxflashtime
>= 0)
12906 p
.rxflashtime
= conf
->timing
.rxflashtime
;
12907 if (conf
->timing
.debouncetime
>= 0)
12908 p
.debouncetime
= conf
->timing
.debouncetime
;
12911 /* don't set parms on a pseudo-channel */
12912 if (tmp
->subs
[SUB_REAL
].dfd
>= 0)
12914 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_SET_PARAMS
, &p
);
12916 ast_log(LOG_ERROR
, "Unable to set parameters: %s\n", strerror(errno
));
12917 destroy_dahdi_pvt(tmp
);
12922 if (!here
&& (tmp
->subs
[SUB_REAL
].dfd
> -1)) {
12923 memset(&bi
, 0, sizeof(bi
));
12924 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
12926 bi
.txbufpolicy
= conf
->chan
.buf_policy
;
12927 bi
.rxbufpolicy
= conf
->chan
.buf_policy
;
12928 bi
.numbufs
= conf
->chan
.buf_no
;
12929 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
12931 ast_log(LOG_WARNING
, "Unable to set buffer policy on channel %d: %s\n", channel
, strerror(errno
));
12934 ast_log(LOG_WARNING
, "Unable to check buffer policy on channel %d: %s\n", channel
, strerror(errno
));
12936 tmp
->buf_policy
= conf
->chan
.buf_policy
;
12937 tmp
->buf_no
= conf
->chan
.buf_no
;
12938 tmp
->usefaxbuffers
= conf
->chan
.usefaxbuffers
;
12939 tmp
->faxbuf_policy
= conf
->chan
.faxbuf_policy
;
12940 tmp
->faxbuf_no
= conf
->chan
.faxbuf_no
;
12941 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
12942 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
12943 * The reason the ioctl call above failed should to be determined before worrying about the
12944 * faxbuffer-related ioctl calls */
12945 tmp
->bufsize
= bi
.bufsize
;
12948 tmp
->immediate
= conf
->chan
.immediate
;
12949 tmp
->immediatering
= conf
->chan
.immediatering
;
12950 tmp
->transfertobusy
= conf
->chan
.transfertobusy
;
12951 tmp
->dialmode
= conf
->chan
.dialmode
;
12952 if (chan_sig
& __DAHDI_SIG_FXS
) {
12953 tmp
->mwimonitor_fsk
= conf
->chan
.mwimonitor_fsk
;
12954 tmp
->mwimonitor_neon
= conf
->chan
.mwimonitor_neon
;
12955 tmp
->mwimonitor_rpas
= conf
->chan
.mwimonitor_rpas
;
12957 tmp
->ringt_base
= ringt_base
;
12958 tmp
->firstradio
= 0;
12959 if ((chan_sig
== SIG_FXOKS
) || (chan_sig
== SIG_FXOLS
) || (chan_sig
== SIG_FXOGS
))
12960 tmp
->permcallwaiting
= conf
->chan
.callwaiting
;
12962 tmp
->permcallwaiting
= 0;
12963 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
12965 tmp
->drings
= conf
->chan
.drings
;
12967 /* 10 is a nice default. */
12968 if (tmp
->drings
.ringnum
[0].range
== 0)
12969 tmp
->drings
.ringnum
[0].range
= 10;
12970 if (tmp
->drings
.ringnum
[1].range
== 0)
12971 tmp
->drings
.ringnum
[1].range
= 10;
12972 if (tmp
->drings
.ringnum
[2].range
== 0)
12973 tmp
->drings
.ringnum
[2].range
= 10;
12975 tmp
->usedistinctiveringdetection
= usedistinctiveringdetection
;
12976 tmp
->callwaitingcallerid
= conf
->chan
.callwaitingcallerid
;
12977 tmp
->threewaycalling
= conf
->chan
.threewaycalling
;
12978 tmp
->threewaysilenthold
= conf
->chan
.threewaysilenthold
;
12979 tmp
->calledsubscriberheld
= conf
->chan
.calledsubscriberheld
; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
12980 tmp
->adsi
= conf
->chan
.adsi
;
12981 tmp
->use_smdi
= conf
->chan
.use_smdi
;
12982 tmp
->permhidecallerid
= conf
->chan
.hidecallerid
;
12983 tmp
->hidecalleridname
= conf
->chan
.hidecalleridname
;
12984 tmp
->callreturn
= conf
->chan
.callreturn
;
12985 tmp
->echocancel
= conf
->chan
.echocancel
;
12986 tmp
->echotraining
= conf
->chan
.echotraining
;
12987 tmp
->pulse
= conf
->chan
.pulse
;
12988 if (tmp
->echocancel
.head
.tap_length
) {
12989 tmp
->echocanbridged
= conf
->chan
.echocanbridged
;
12991 if (conf
->chan
.echocanbridged
)
12992 ast_log(LOG_NOTICE
, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
12993 tmp
->echocanbridged
= 0;
12995 tmp
->busydetect
= conf
->chan
.busydetect
;
12996 tmp
->busycount
= conf
->chan
.busycount
;
12997 tmp
->busy_cadence
= conf
->chan
.busy_cadence
;
12998 tmp
->callprogress
= conf
->chan
.callprogress
;
12999 tmp
->waitfordialtone
= conf
->chan
.waitfordialtone
;
13000 tmp
->dialtone_detect
= conf
->chan
.dialtone_detect
;
13001 tmp
->faxdetect_timeout
= conf
->chan
.faxdetect_timeout
;
13002 tmp
->firstdigit_timeout
= conf
->chan
.firstdigit_timeout
;
13003 tmp
->interdigit_timeout
= conf
->chan
.interdigit_timeout
;
13004 tmp
->matchdigit_timeout
= conf
->chan
.matchdigit_timeout
;
13005 tmp
->cancallforward
= conf
->chan
.cancallforward
;
13006 tmp
->dtmfrelax
= conf
->chan
.dtmfrelax
;
13007 tmp
->callwaiting
= tmp
->permcallwaiting
;
13008 tmp
->hidecallerid
= tmp
->permhidecallerid
;
13009 tmp
->channel
= channel
;
13010 tmp
->stripmsd
= conf
->chan
.stripmsd
;
13011 tmp
->use_callerid
= conf
->chan
.use_callerid
;
13012 tmp
->cid_signalling
= conf
->chan
.cid_signalling
;
13013 tmp
->cid_start
= conf
->chan
.cid_start
;
13014 tmp
->dahditrcallerid
= conf
->chan
.dahditrcallerid
;
13015 tmp
->restrictcid
= conf
->chan
.restrictcid
;
13016 tmp
->use_callingpres
= conf
->chan
.use_callingpres
;
13017 if (tmp
->usedistinctiveringdetection
) {
13018 if (!tmp
->use_callerid
) {
13019 ast_log(LOG_NOTICE
, "Distinctive Ring detect requires 'usecallerid' be on\n");
13020 tmp
->use_callerid
= 1;
13024 if (tmp
->cid_signalling
== CID_SIG_SMDI
) {
13025 if (!tmp
->use_smdi
) {
13026 ast_log(LOG_WARNING
, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13030 if (tmp
->use_smdi
) {
13031 tmp
->smdi_iface
= ast_smdi_interface_find(conf
->smdi_port
);
13032 if (!(tmp
->smdi_iface
)) {
13033 ast_log(LOG_ERROR
, "Invalid SMDI port specfied, disabling SMDI support\n");
13038 ast_copy_string(tmp
->accountcode
, conf
->chan
.accountcode
, sizeof(tmp
->accountcode
));
13039 tmp
->amaflags
= conf
->chan
.amaflags
;
13042 tmp
->propconfno
= -1;
13044 tmp
->canpark
= conf
->chan
.canpark
;
13045 tmp
->transfer
= conf
->chan
.transfer
;
13046 ast_copy_string(tmp
->defcontext
,conf
->chan
.context
,sizeof(tmp
->defcontext
));
13047 ast_copy_string(tmp
->language
, conf
->chan
.language
, sizeof(tmp
->language
));
13048 ast_copy_string(tmp
->mohinterpret
, conf
->chan
.mohinterpret
, sizeof(tmp
->mohinterpret
));
13049 ast_copy_string(tmp
->mohsuggest
, conf
->chan
.mohsuggest
, sizeof(tmp
->mohsuggest
));
13050 ast_copy_string(tmp
->context
, conf
->chan
.context
, sizeof(tmp
->context
));
13051 ast_copy_string(tmp
->description
, conf
->chan
.description
, sizeof(tmp
->description
));
13052 ast_copy_string(tmp
->parkinglot
, conf
->chan
.parkinglot
, sizeof(tmp
->parkinglot
));
13054 if (dahdi_analog_lib_handles(tmp
->sig
, tmp
->radio
, tmp
->oprmode
)) {
13055 ast_copy_string(tmp
->cid_num
, conf
->chan
.cid_num
, sizeof(tmp
->cid_num
));
13056 ast_copy_string(tmp
->cid_name
, conf
->chan
.cid_name
, sizeof(tmp
->cid_name
));
13058 tmp
->cid_num
[0] = '\0';
13059 tmp
->cid_name
[0] = '\0';
13061 #if defined(HAVE_PRI)
13062 if (dahdi_sig_pri_lib_handles(tmp
->sig
)) {
13063 tmp
->cid_tag
[0] = '\0';
13065 #endif /* defined(HAVE_PRI) */
13067 ast_copy_string(tmp
->cid_tag
, conf
->chan
.cid_tag
, sizeof(tmp
->cid_tag
));
13069 tmp
->cid_subaddr
[0] = '\0';
13070 ast_copy_string(tmp
->mailbox
, conf
->chan
.mailbox
, sizeof(tmp
->mailbox
));
13071 if (channel
!= CHAN_PSEUDO
&& !ast_strlen_zero(tmp
->mailbox
)) {
13072 /* This module does not handle MWI in an event-based manner. However, it
13073 * subscribes to MWI for each mailbox that is configured so that the core
13074 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13075 * event cache instead of checking the mailbox directly. */
13076 tmp
->mwi_event_sub
= ast_mwi_subscribe_pool(tmp
->mailbox
, stasis_subscription_cb_noop
, NULL
);
13078 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13079 tmp
->mwisend_setting
= conf
->chan
.mwisend_setting
;
13080 tmp
->mwisend_fsk
= conf
->chan
.mwisend_fsk
;
13081 tmp
->mwisend_rpas
= conf
->chan
.mwisend_rpas
;
13084 tmp
->group
= conf
->chan
.group
;
13085 tmp
->callgroup
= conf
->chan
.callgroup
;
13086 tmp
->pickupgroup
= conf
->chan
.pickupgroup
;
13087 ast_unref_namedgroups(tmp
->named_callgroups
);
13088 tmp
->named_callgroups
= ast_ref_namedgroups(conf
->chan
.named_callgroups
);
13089 ast_unref_namedgroups(tmp
->named_pickupgroups
);
13090 tmp
->named_pickupgroups
= ast_ref_namedgroups(conf
->chan
.named_pickupgroups
);
13091 if (conf
->chan
.vars
) {
13092 struct ast_variable
*v
, *tmpvar
;
13093 for (v
= conf
->chan
.vars
; v
; v
= v
->next
) {
13094 if ((tmpvar
= ast_variable_new(v
->name
, v
->value
, v
->file
))) {
13095 if (ast_variable_list_replace(&tmp
->vars
, tmpvar
)) {
13096 tmpvar
->next
= tmp
->vars
;
13097 tmp
->vars
= tmpvar
;
13102 tmp
->hwrxgain_enabled
= conf
->chan
.hwrxgain_enabled
;
13103 tmp
->hwtxgain_enabled
= conf
->chan
.hwtxgain_enabled
;
13104 tmp
->hwrxgain
= conf
->chan
.hwrxgain
;
13105 tmp
->hwtxgain
= conf
->chan
.hwtxgain
;
13106 tmp
->cid_rxgain
= conf
->chan
.cid_rxgain
;
13107 tmp
->rxgain
= conf
->chan
.rxgain
;
13108 tmp
->txgain
= conf
->chan
.txgain
;
13109 tmp
->txdrc
= conf
->chan
.txdrc
;
13110 tmp
->rxdrc
= conf
->chan
.rxdrc
;
13111 tmp
->tonezone
= conf
->chan
.tonezone
;
13112 if (tmp
->subs
[SUB_REAL
].dfd
> -1) {
13113 if (tmp
->hwrxgain_enabled
) {
13114 tmp
->hwrxgain_enabled
= !set_hwgain(tmp
->subs
[SUB_REAL
].dfd
, tmp
->hwrxgain
, 0);
13116 if (tmp
->hwtxgain_enabled
) {
13117 tmp
->hwtxgain_enabled
= !set_hwgain(tmp
->subs
[SUB_REAL
].dfd
, tmp
->hwtxgain
, 1);
13119 set_actual_gain(tmp
->subs
[SUB_REAL
].dfd
, tmp
->rxgain
, tmp
->txgain
, tmp
->rxdrc
, tmp
->txdrc
, tmp
->law
);
13121 ast_dsp_set_digitmode(tmp
->dsp
, DSP_DIGITMODE_DTMF
| tmp
->dtmfrelax
);
13122 dahdi_conf_update(tmp
);
13124 switch (chan_sig
) {
13125 case SIG_PRI_LIB_HANDLE_CASES
:
13130 /* Hang it up to be sure it's good */
13131 dahdi_set_hook(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
13135 ioctl(tmp
->subs
[SUB_REAL
].dfd
,DAHDI_SETTONEZONE
,&tmp
->tonezone
);
13136 if ((res
= get_alarms(tmp
)) != DAHDI_ALARM_NONE
) {
13137 /* the dchannel is down so put the channel in alarm */
13138 switch (tmp
->sig
) {
13140 case SIG_PRI_LIB_HANDLE_CASES
:
13141 sig_pri_set_alarm(tmp
->sig_pvt
, 1);
13144 #if defined(HAVE_SS7)
13146 sig_ss7_set_alarm(tmp
->sig_pvt
, 1);
13148 #endif /* defined(HAVE_SS7) */
13150 /* The only sig submodule left should be sig_analog. */
13151 analog_p
= tmp
->sig_pvt
;
13153 analog_p
->inalarm
= 1;
13158 handle_alarms(tmp
, res
);
13162 tmp
->polarityonanswerdelay
= conf
->chan
.polarityonanswerdelay
;
13163 tmp
->answeronpolarityswitch
= conf
->chan
.answeronpolarityswitch
;
13164 tmp
->ani_info_digits
= conf
->chan
.ani_info_digits
;
13165 tmp
->ani_wink_time
= conf
->chan
.ani_wink_time
;
13166 tmp
->ani_timeout
= conf
->chan
.ani_timeout
;
13167 tmp
->hanguponpolarityswitch
= conf
->chan
.hanguponpolarityswitch
;
13168 tmp
->reoriginate
= conf
->chan
.reoriginate
;
13169 tmp
->sendcalleridafter
= conf
->chan
.sendcalleridafter
;
13170 ast_cc_copy_config_params(tmp
->cc_params
, conf
->chan
.cc_params
);
13173 tmp
->locallyblocked
= 0;
13174 tmp
->remotelyblocked
= 0;
13175 switch (tmp
->sig
) {
13176 #if defined(HAVE_PRI)
13177 case SIG_PRI_LIB_HANDLE_CASES
:
13178 tmp
->inservice
= 1;/* Inservice until actually implemented. */
13179 #if defined(HAVE_PRI_SERVICE_MESSAGES)
13180 ((struct sig_pri_chan
*) tmp
->sig_pvt
)->service_status
= 0;
13181 if (chan_sig
== SIG_PRI
) {
13182 char db_chan_name
[20];
13186 * Initialize the active out-of-service status
13187 * and delete any record if the feature is not enabled.
13189 snprintf(db_chan_name
, sizeof(db_chan_name
), "%s/%d:%d", dahdi_db
, tmp
->span
, tmp
->channel
);
13190 if (!ast_db_get(db_chan_name
, SRVST_DBKEY
, db_answer
, sizeof(db_answer
))) {
13193 why
= &((struct sig_pri_chan
*) tmp
->sig_pvt
)->service_status
;
13194 if (tmp
->pri
->enable_service_message_support
) {
13197 sscanf(db_answer
, "%1c:%30u", &state
, why
);
13199 /* Ensure that only the implemented bits could be set.*/
13200 *why
&= (SRVST_NEAREND
| SRVST_FAREND
);
13203 ast_db_del(db_chan_name
, SRVST_DBKEY
);
13207 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13209 #endif /* defined(HAVE_PRI) */
13210 #if defined(HAVE_SS7)
13212 tmp
->inservice
= 0;
13213 if (tmp
->ss7
->flags
& LINKSET_FLAG_INITIALHWBLO
) {
13214 tmp
->remotelyblocked
|= SS7_BLOCKED_HARDWARE
;
13217 #endif /* defined(HAVE_SS7) */
13219 /* We default to in service on protocols that don't have a reset */
13220 tmp
->inservice
= 1;
13225 switch (tmp
->sig
) {
13226 #if defined(HAVE_PRI)
13227 case SIG_PRI_LIB_HANDLE_CASES
:
13229 pri_chan
->channel
= tmp
->channel
;
13230 pri_chan
->hidecallerid
= tmp
->hidecallerid
;
13231 pri_chan
->hidecalleridname
= tmp
->hidecalleridname
;
13232 pri_chan
->immediate
= tmp
->immediate
;
13233 pri_chan
->inalarm
= tmp
->inalarm
;
13234 pri_chan
->priexclusive
= tmp
->priexclusive
;
13235 pri_chan
->priindication_oob
= tmp
->priindication_oob
;
13236 pri_chan
->use_callerid
= tmp
->use_callerid
;
13237 pri_chan
->use_callingpres
= tmp
->use_callingpres
;
13238 ast_copy_string(pri_chan
->context
, tmp
->context
,
13239 sizeof(pri_chan
->context
));
13240 ast_copy_string(pri_chan
->mohinterpret
, tmp
->mohinterpret
,
13241 sizeof(pri_chan
->mohinterpret
));
13242 pri_chan
->stripmsd
= tmp
->stripmsd
;
13245 #endif /* defined(HAVE_PRI) */
13246 #if defined(HAVE_SS7)
13249 ss7_chan
->inalarm
= tmp
->inalarm
;
13250 ss7_chan
->inservice
= tmp
->inservice
;
13252 ss7_chan
->stripmsd
= tmp
->stripmsd
;
13253 ss7_chan
->hidecallerid
= tmp
->hidecallerid
;
13254 ss7_chan
->use_callerid
= tmp
->use_callerid
;
13255 ss7_chan
->use_callingpres
= tmp
->use_callingpres
;
13256 ss7_chan
->immediate
= tmp
->immediate
;
13257 ss7_chan
->locallyblocked
= tmp
->locallyblocked
;
13258 ss7_chan
->remotelyblocked
= tmp
->remotelyblocked
;
13259 ast_copy_string(ss7_chan
->context
, tmp
->context
,
13260 sizeof(ss7_chan
->context
));
13261 ast_copy_string(ss7_chan
->mohinterpret
, tmp
->mohinterpret
,
13262 sizeof(ss7_chan
->mohinterpret
));
13265 #endif /* defined(HAVE_SS7) */
13267 /* The only sig submodule left should be sig_analog. */
13268 analog_p
= tmp
->sig_pvt
;
13270 analog_p
->channel
= tmp
->channel
;
13271 analog_p
->polarityonanswerdelay
= conf
->chan
.polarityonanswerdelay
;
13272 analog_p
->answeronpolarityswitch
= conf
->chan
.answeronpolarityswitch
;
13273 analog_p
->ani_info_digits
= conf
->chan
.ani_info_digits
;
13274 analog_p
->ani_timeout
= conf
->chan
.ani_timeout
;
13275 analog_p
->ani_wink_time
= conf
->chan
.ani_wink_time
;
13276 analog_p
->hanguponpolarityswitch
= conf
->chan
.hanguponpolarityswitch
;
13277 analog_p
->permcallwaiting
= conf
->chan
.callwaiting
; /* permcallwaiting possibly modified in analog_config_complete */
13278 analog_p
->calledsubscriberheld
= conf
->chan
.calledsubscriberheld
; /* Only actually used in analog pvt, not DAHDI pvt */
13279 analog_p
->callreturn
= conf
->chan
.callreturn
;
13280 analog_p
->cancallforward
= conf
->chan
.cancallforward
;
13281 analog_p
->canpark
= conf
->chan
.canpark
;
13282 analog_p
->dahditrcallerid
= conf
->chan
.dahditrcallerid
;
13283 analog_p
->immediate
= conf
->chan
.immediate
;
13284 analog_p
->immediatering
= conf
->chan
.immediatering
;
13285 analog_p
->permhidecallerid
= conf
->chan
.hidecallerid
; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13286 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13287 analog_p
->pulse
= conf
->chan
.pulse
;
13288 analog_p
->threewaycalling
= conf
->chan
.threewaycalling
;
13289 analog_p
->transfer
= conf
->chan
.transfer
;
13290 analog_p
->transfertobusy
= conf
->chan
.transfertobusy
;
13291 analog_p
->dialmode
= conf
->chan
.dialmode
;
13292 analog_p
->use_callerid
= tmp
->use_callerid
;
13293 analog_p
->usedistinctiveringdetection
= tmp
->usedistinctiveringdetection
;
13294 analog_p
->use_smdi
= tmp
->use_smdi
;
13295 analog_p
->smdi_iface
= tmp
->smdi_iface
;
13296 analog_p
->outsigmod
= ANALOG_SIG_NONE
;
13297 analog_p
->echotraining
= conf
->chan
.echotraining
;
13298 analog_p
->cid_signalling
= conf
->chan
.cid_signalling
;
13299 analog_p
->stripmsd
= conf
->chan
.stripmsd
;
13300 switch (conf
->chan
.cid_start
) {
13301 case CID_START_POLARITY
:
13302 analog_p
->cid_start
= ANALOG_CID_START_POLARITY
;
13304 case CID_START_POLARITY_IN
:
13305 analog_p
->cid_start
= ANALOG_CID_START_POLARITY_IN
;
13307 case CID_START_DTMF_NOALERT
:
13308 analog_p
->cid_start
= ANALOG_CID_START_DTMF_NOALERT
;
13311 analog_p
->cid_start
= ANALOG_CID_START_RING
;
13314 analog_p
->callwaitingcallerid
= conf
->chan
.callwaitingcallerid
;
13315 analog_p
->ringt
= conf
->chan
.ringt
;
13316 analog_p
->ringt_base
= ringt_base
;
13317 analog_p
->onhooktime
= time(NULL
);
13318 if (chan_sig
& __DAHDI_SIG_FXO
) {
13319 memset(&p
, 0, sizeof(p
));
13320 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &p
);
13322 analog_p
->fxsoffhookstate
= p
.rxisoffhook
;
13324 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13325 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_VMWI_CONFIG
, &tmp
->mwisend_setting
);
13328 analog_p
->msgstate
= -1;
13330 ast_copy_string(analog_p
->mohsuggest
, conf
->chan
.mohsuggest
, sizeof(analog_p
->mohsuggest
));
13331 ast_copy_string(analog_p
->cid_num
, conf
->chan
.cid_num
, sizeof(analog_p
->cid_num
));
13332 ast_copy_string(analog_p
->cid_name
, conf
->chan
.cid_name
, sizeof(analog_p
->cid_name
));
13334 analog_config_complete(analog_p
);
13338 #if defined(HAVE_PRI)
13339 if (tmp
->channel
== CHAN_PSEUDO
) {
13341 * Save off pseudo channel buffer policy values for dynamic creation of
13342 * no B channel interfaces.
13344 dahdi_pseudo_parms
.buf_no
= tmp
->buf_no
;
13345 dahdi_pseudo_parms
.buf_policy
= tmp
->buf_policy
;
13346 dahdi_pseudo_parms
.faxbuf_no
= tmp
->faxbuf_no
;
13347 dahdi_pseudo_parms
.faxbuf_policy
= tmp
->faxbuf_policy
;
13349 #endif /* defined(HAVE_PRI) */
13351 if (tmp
&& !here
) {
13352 /* Add the new channel interface to the sorted channel interface list. */
13353 dahdi_iflist_insert(tmp
);
13358 static int is_group_or_channel_match(struct dahdi_pvt
*p
, int span
, ast_group_t groupmatch
, int *groupmatched
, int channelmatch
, int *channelmatched
)
13360 #if defined(HAVE_PRI)
13362 /* The channel must be on the specified PRI span. */
13363 if (!p
->pri
|| p
->pri
->span
!= span
) {
13366 if (!groupmatch
&& channelmatch
== -1) {
13367 /* Match any group since it only needs to be on the PRI span. */
13372 #endif /* defined(HAVE_PRI) */
13373 /* check group matching */
13375 if ((p
->group
& groupmatch
) != groupmatch
)
13376 /* Doesn't match the specified group, try the next one */
13380 /* Check to see if we have a channel match */
13381 if (channelmatch
!= -1) {
13382 if (p
->channel
!= channelmatch
)
13383 /* Doesn't match the specified channel, try the next one */
13385 *channelmatched
= 1;
13391 static int available(struct dahdi_pvt
**pvt
, int is_specific_channel
)
13393 struct dahdi_pvt
*p
= *pvt
;
13398 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
))
13399 return analog_available(p
->sig_pvt
);
13402 #if defined(HAVE_PRI)
13403 case SIG_PRI_LIB_HANDLE_CASES
:
13405 struct sig_pri_chan
*pvt_chan
;
13408 pvt_chan
= p
->sig_pvt
;
13409 res
= sig_pri_available(&pvt_chan
, is_specific_channel
);
13410 *pvt
= pvt_chan
->chan_pvt
;
13413 #endif /* defined(HAVE_PRI) */
13414 #if defined(HAVE_SS7)
13416 return sig_ss7_available(p
->sig_pvt
);
13417 #endif /* defined(HAVE_SS7) */
13422 if (p
->locallyblocked
|| p
->remotelyblocked
) {
13426 /* If no owner definitely available */
13431 if (p
->mfcr2call
) {
13444 #if defined(HAVE_PRI)
13445 #if defined(HAVE_PRI_CALL_WAITING)
13448 * \brief Init the private channel configuration using the span controller.
13451 * \param priv Channel to init the configuration.
13452 * \param pri sig_pri PRI control structure.
13454 * \note Assumes the pri->lock is already obtained.
13456 static void my_pri_init_config(void *priv
, struct sig_pri_span
*pri
)
13458 struct dahdi_pvt
*pvt
= priv
;
13460 pvt
->stripmsd
= pri
->ch_cfg
.stripmsd
;
13461 pvt
->hidecallerid
= pri
->ch_cfg
.hidecallerid
;
13462 pvt
->hidecalleridname
= pri
->ch_cfg
.hidecalleridname
;
13463 pvt
->immediate
= pri
->ch_cfg
.immediate
;
13464 pvt
->priexclusive
= pri
->ch_cfg
.priexclusive
;
13465 pvt
->priindication_oob
= pri
->ch_cfg
.priindication_oob
;
13466 pvt
->use_callerid
= pri
->ch_cfg
.use_callerid
;
13467 pvt
->use_callingpres
= pri
->ch_cfg
.use_callingpres
;
13468 ast_copy_string(pvt
->context
, pri
->ch_cfg
.context
, sizeof(pvt
->context
));
13469 ast_copy_string(pvt
->mohinterpret
, pri
->ch_cfg
.mohinterpret
, sizeof(pvt
->mohinterpret
));
13471 #endif /* defined(HAVE_PRI_CALL_WAITING) */
13472 #endif /* defined(HAVE_PRI) */
13474 #if defined(HAVE_PRI)
13477 * \brief Create a no B channel interface.
13480 * \param pri sig_pri span controller to add interface.
13482 * \note Assumes the pri->lock is already obtained.
13484 * \retval array-index into private pointer array on success.
13485 * \retval -1 on error.
13487 static int dahdi_new_pri_nobch_channel(struct sig_pri_span
*pri
)
13492 struct dahdi_pvt
*pvt
;
13493 struct sig_pri_chan
*chan
;
13494 struct dahdi_bufferinfo bi
;
13496 static int nobch_channel
= CHAN_PSEUDO
;
13498 /* Find spot in the private pointer array for new interface. */
13499 for (pvt_idx
= 0; pvt_idx
< pri
->numchans
; ++pvt_idx
) {
13500 if (!pri
->pvts
[pvt_idx
]) {
13504 if (pri
->numchans
== pvt_idx
) {
13505 if (ARRAY_LEN(pri
->pvts
) <= pvt_idx
) {
13506 ast_log(LOG_ERROR
, "Unable to add a no-B-channel interface!\n");
13510 /* Add new spot to the private pointer array. */
13511 pri
->pvts
[pvt_idx
] = NULL
;
13515 pvt
= ast_calloc(1, sizeof(*pvt
));
13519 pvt
->cc_params
= ast_cc_config_params_init();
13520 if (!pvt
->cc_params
) {
13524 ast_mutex_init(&pvt
->lock
);
13525 for (idx
= 0; idx
< ARRAY_LEN(pvt
->subs
); ++idx
) {
13526 pvt
->subs
[idx
].dfd
= -1;
13528 pvt
->buf_no
= dahdi_pseudo_parms
.buf_no
;
13529 pvt
->buf_policy
= dahdi_pseudo_parms
.buf_policy
;
13530 pvt
->faxbuf_no
= dahdi_pseudo_parms
.faxbuf_no
;
13531 pvt
->faxbuf_policy
= dahdi_pseudo_parms
.faxbuf_policy
;
13533 chan
= sig_pri_chan_new(pvt
, pri
, 0, 0, 0);
13535 destroy_dahdi_pvt(pvt
);
13538 chan
->no_b_channel
= 1;
13541 * Pseudo channel companding law.
13542 * Needed for outgoing call waiting calls.
13543 * XXX May need to make this determined by switchtype or user option.
13545 pvt
->law_default
= DAHDI_LAW_ALAW
;
13547 pvt
->sig
= pri
->sig
;
13548 pvt
->outsigmod
= -1;
13550 pvt
->sig_pvt
= chan
;
13551 pri
->pvts
[pvt_idx
] = chan
;
13553 pvt
->subs
[SUB_REAL
].dfd
= dahdi_open("/dev/dahdi/pseudo");
13554 if (pvt
->subs
[SUB_REAL
].dfd
< 0) {
13555 ast_log(LOG_ERROR
, "Unable to open no B channel interface pseudo channel: %s\n",
13557 destroy_dahdi_pvt(pvt
);
13560 memset(&bi
, 0, sizeof(bi
));
13561 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
13563 pvt
->bufsize
= bi
.bufsize
;
13564 bi
.txbufpolicy
= pvt
->buf_policy
;
13565 bi
.rxbufpolicy
= pvt
->buf_policy
;
13566 bi
.numbufs
= pvt
->buf_no
;
13567 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
13569 ast_log(LOG_WARNING
,
13570 "Unable to set buffer policy on no B channel interface: %s\n",
13574 ast_log(LOG_WARNING
,
13575 "Unable to check buffer policy on no B channel interface: %s\n",
13579 if (CHAN_PSEUDO
< nobch_channel
) {
13580 nobch_channel
= CHAN_PSEUDO
- 1;
13582 pvt
->channel
= nobch_channel
;
13583 pvt
->span
= pri
->span
;
13584 chan
->channel
= pvt
->channel
;
13586 dahdi_nobch_insert(pri
, pvt
);
13590 #endif /* defined(HAVE_PRI) */
13592 /* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13593 structures; it makes no attempt to safely copy regular channel private
13594 structures that might contain reference-counted object pointers and other
13597 static struct dahdi_pvt
*duplicate_pseudo(struct dahdi_pvt
*src
)
13599 struct dahdi_pvt
*p
;
13600 struct dahdi_bufferinfo bi
;
13603 p
= ast_malloc(sizeof(*p
));
13609 /* Must deep copy the cc_params. */
13610 p
->cc_params
= ast_cc_config_params_init();
13611 if (!p
->cc_params
) {
13615 ast_cc_copy_config_params(p
->cc_params
, src
->cc_params
);
13617 p
->which_iflist
= DAHDI_IFLIST_NONE
;
13620 ast_mutex_init(&p
->lock
);
13621 p
->subs
[SUB_REAL
].dfd
= dahdi_open("/dev/dahdi/pseudo");
13622 if (p
->subs
[SUB_REAL
].dfd
< 0) {
13623 ast_log(LOG_ERROR
, "Unable to dup channel: %s\n", strerror(errno
));
13624 destroy_dahdi_pvt(p
);
13627 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
13629 bi
.txbufpolicy
= src
->buf_policy
;
13630 bi
.rxbufpolicy
= src
->buf_policy
;
13631 bi
.numbufs
= src
->buf_no
;
13632 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
13634 ast_log(LOG_WARNING
, "Unable to set buffer policy on dup channel: %s\n", strerror(errno
));
13637 ast_log(LOG_WARNING
, "Unable to check buffer policy on dup channel: %s\n", strerror(errno
));
13639 dahdi_iflist_insert(p
);
13643 struct dahdi_starting_point
{
13644 /*! Group matching mask. Zero if not specified. */
13645 ast_group_t groupmatch
;
13646 /*! DAHDI channel to match with. -1 if not specified. */
13648 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13649 int rr_starting_point
;
13650 /*! ISDN span where channels can be picked (Zero if not specified) */
13652 /*! Analog channel distinctive ring cadence index. */
13654 /*! Dialing option. c/r/d if present and valid. */
13656 /*! TRUE if to search the channel list backwards. */
13658 /*! TRUE if search is done with round robin sequence. */
13661 static struct dahdi_pvt
*determine_starting_point(const char *data
, struct dahdi_starting_point
*param
)
13667 struct dahdi_pvt
*p
;
13668 char *subdir
= NULL
;
13669 AST_DECLARE_APP_ARGS(args
,
13670 AST_APP_ARG(group
); /* channel/group token */
13671 //AST_APP_ARG(ext); /* extension token */
13672 //AST_APP_ARG(opts); /* options token */
13673 AST_APP_ARG(other
); /* Any remining unused arguments */
13678 * Dial(DAHDI/pseudo[/extension[/options]])
13679 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13680 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13681 * Dial(DAHDI/i<span>[/extension[/options]])
13682 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13684 * i - ISDN span channel restriction.
13685 * Used by CC to ensure that the CC recall goes out the same span.
13686 * Also to make ISDN channel names dialable when the sequence number
13687 * is stripped off. (Used by DTMF attended transfer feature.)
13689 * g - channel group allocation search forward
13690 * G - channel group allocation search backward
13691 * r - channel group allocation round robin search forward
13692 * R - channel group allocation round robin search backward
13694 * c - Wait for DTMF digit to confirm answer
13695 * r<cadence#> - Set distinctive ring cadence number
13696 * d - Force bearer capability for ISDN/SS7 call to digital.
13700 dest
= ast_strdupa(data
);
13702 ast_log(LOG_WARNING
, "Channel requested with no data\n");
13705 AST_NONSTANDARD_APP_ARGS(args
, dest
, '/');
13706 if (!args
.argc
|| ast_strlen_zero(args
.group
)) {
13707 ast_log(LOG_WARNING
, "No channel/group specified\n");
13711 /* Initialize the output parameters */
13712 memset(param
, 0, sizeof(*param
));
13713 param
->channelmatch
= -1;
13715 if (strchr(args
.group
, '!') != NULL
) {
13716 char *prev
= args
.group
;
13717 while ((s
= strchr(prev
, '!')) != NULL
) {
13721 *(prev
- 1) = '\0';
13722 subdir
= args
.group
;
13724 } else if (args
.group
[0] == 'i') {
13725 /* Extract the ISDN span channel restriction specifier. */
13726 res
= sscanf(args
.group
+ 1, "%30d", &x
);
13728 ast_log(LOG_WARNING
, "Unable to determine ISDN span for data %s\n", data
);
13733 /* Remove the ISDN span channel restriction specifier. */
13734 s
= strchr(args
.group
, '-');
13736 /* Search all groups since we are ISDN span restricted. */
13739 args
.group
= s
+ 1;
13742 if (toupper(args
.group
[0]) == 'G' || toupper(args
.group
[0])=='R') {
13743 /* Retrieve the group number */
13744 s
= args
.group
+ 1;
13745 res
= sscanf(s
, "%30d%1c%30d", &x
, ¶m
->opt
, ¶m
->cadence
);
13747 ast_log(LOG_WARNING
, "Unable to determine group for data %s\n", data
);
13750 param
->groupmatch
= ((ast_group_t
) 1 << x
);
13752 if (toupper(args
.group
[0]) == 'G') {
13753 if (args
.group
[0] == 'G') {
13754 param
->backwards
= 1;
13759 if (ARRAY_LEN(round_robin
) <= x
) {
13760 ast_log(LOG_WARNING
, "Round robin index %d out of range for data %s\n",
13764 if (args
.group
[0] == 'R') {
13765 param
->backwards
= 1;
13766 p
= round_robin
[x
] ? round_robin
[x
]->prev
: ifend
;
13770 p
= round_robin
[x
] ? round_robin
[x
]->next
: iflist
;
13774 param
->roundrobin
= 1;
13775 param
->rr_starting_point
= x
;
13779 if (!strcasecmp(s
, "pseudo")) {
13780 /* Special case for pseudo */
13782 param
->channelmatch
= x
;
13784 res
= sscanf(s
, "%30d%1c%30d", &x
, ¶m
->opt
, ¶m
->cadence
);
13786 ast_log(LOG_WARNING
, "Unable to determine channel for data %s\n", data
);
13789 param
->channelmatch
= x
;
13793 char path
[PATH_MAX
];
13796 snprintf(path
, sizeof(path
), "/dev/dahdi/%s/%d",
13797 subdir
, param
->channelmatch
);
13798 if (stat(path
, &stbuf
) < 0) {
13799 ast_log(LOG_WARNING
, "stat(%s) failed: %s\n",
13800 path
, strerror(errno
));
13803 if (!S_ISCHR(stbuf
.st_mode
)) {
13804 ast_log(LOG_ERROR
, "%s: Not a character device file\n",
13808 param
->channelmatch
= minor(stbuf
.st_rdev
);
13814 if (param
->opt
== 'r' && res
< 3) {
13815 ast_log(LOG_WARNING
, "Distinctive ring missing identifier in '%s'\n", data
);
13822 static struct ast_channel
*dahdi_request(const char *type
, struct ast_format_cap
*cap
,
13823 const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
,
13824 const char *data
, int *cause
)
13827 struct dahdi_pvt
*p
;
13828 struct ast_channel
*tmp
= NULL
;
13829 struct dahdi_pvt
*exitpvt
;
13830 int channelmatched
= 0;
13831 int foundowner
= 0;
13832 int groupmatched
= 0;
13833 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13834 int transcapdigital
= 0;
13835 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
13836 struct dahdi_starting_point start
;
13837 ast_callid callid
= 0;
13838 int callid_created
= ast_callid_threadstorage_auto(&callid
);
13840 ast_mutex_lock(&iflock
);
13841 p
= determine_starting_point(data
, &start
);
13843 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
13844 ast_mutex_unlock(&iflock
);
13845 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
13849 /* Search for an unowned channel */
13851 while (p
&& !tmp
) {
13852 if (start
.roundrobin
)
13853 round_robin
[start
.rr_starting_point
] = p
;
13859 if (is_group_or_channel_match(p
, start
.span
, start
.groupmatch
, &groupmatched
, start
.channelmatch
, &channelmatched
)
13860 && available(&p
, channelmatched
)) {
13861 ast_debug(1, "Using channel %d\n", p
->channel
);
13863 callwait
= (p
->owner
!= NULL
);
13866 ast_mutex_lock(&p
->lock
);
13867 if (p
->mfcr2call
) {
13868 ast_mutex_unlock(&p
->lock
);
13869 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p
->channel
);
13873 ast_mutex_unlock(&p
->lock
);
13876 if (p
->channel
== CHAN_PSEUDO
) {
13877 p
= duplicate_pseudo(p
);
13883 p
->distinctivering
= 0;
13884 /* Make special notes */
13885 switch (start
.opt
) {
13887 /* No option present. */
13890 /* Confirm answer */
13891 p
->confirmanswer
= 1;
13894 /* Distinctive ring */
13895 p
->distinctivering
= start
.cadence
;
13898 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13899 /* If this is an ISDN call, make it digital */
13900 transcapdigital
= AST_TRANS_CAP_DIGITAL
;
13901 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
13904 ast_log(LOG_WARNING
, "Unknown option '%c' in '%s'\n", start
.opt
, data
);
13909 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
13910 tmp
= analog_request(p
->sig_pvt
, &callwait
, requestor
);
13912 } else if (dahdi_sig_pri_lib_handles(p
->sig
)) {
13914 * We already have the B channel reserved for this call. We
13915 * just need to make sure that dahdi_hangup() has completed
13916 * cleaning up before continuing.
13918 ast_mutex_lock(&p
->lock
);
13919 ast_mutex_unlock(&p
->lock
);
13921 sig_pri_extract_called_num_subaddr(p
->sig_pvt
, data
, p
->dnid
,
13923 tmp
= sig_pri_request(p
->sig_pvt
, SIG_PRI_DEFLAW
, assignedids
, requestor
, transcapdigital
);
13925 #if defined(HAVE_SS7)
13926 } else if (p
->sig
== SIG_SS7
) {
13927 tmp
= sig_ss7_request(p
->sig_pvt
, SIG_SS7_DEFLAW
, assignedids
, requestor
, transcapdigital
);
13928 #endif /* defined(HAVE_SS7) */
13930 tmp
= dahdi_new(p
, AST_STATE_RESERVED
, 0, p
->owner
? SUB_CALLWAIT
: SUB_REAL
, 0, assignedids
, requestor
, callid
);
13934 #if defined(HAVE_PRI)
13936 case SIG_PRI_LIB_HANDLE_CASES
:
13937 #if defined(HAVE_PRI_CALL_WAITING)
13938 if (((struct sig_pri_chan
*) p
->sig_pvt
)->is_call_waiting
) {
13939 ((struct sig_pri_chan
*) p
->sig_pvt
)->is_call_waiting
= 0;
13940 ast_atomic_fetchadd_int(&p
->pri
->num_call_waiting_calls
, -1);
13942 #endif /* defined(HAVE_PRI_CALL_WAITING) */
13944 * This should be the last thing to clear when we are done with
13947 ((struct sig_pri_chan
*) p
->sig_pvt
)->allocated
= 0;
13952 #endif /* defined(HAVE_PRI) */
13954 snprintf(p
->dialstring
, sizeof(p
->dialstring
), "DAHDI/%s", data
);
13961 if (start
.backwards
) {
13970 /* stop when you roll to the one that we started from */
13974 ast_mutex_unlock(&iflock
);
13976 if (cause
&& !tmp
) {
13977 if (callwait
|| (channelmatched
&& foundowner
)) {
13978 *cause
= AST_CAUSE_BUSY
;
13979 } else if (groupmatched
) {
13980 *cause
= AST_CAUSE_CONGESTION
;
13983 * We did not match any channel requested.
13984 * Dialplan error requesting non-existant channel?
13989 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
13995 * \brief Determine the device state for a given DAHDI device if we can.
13998 * \param data DAHDI device name after "DAHDI/".
14000 * \retval device_state enum ast_device_state value.
14001 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
14003 static int dahdi_devicestate(const char *data
)
14005 #if defined(HAVE_PRI)
14006 const char *device
;
14012 if (*device
!= 'I') {
14013 /* The request is not for an ISDN span device. */
14014 return AST_DEVICE_UNKNOWN
;
14016 res
= sscanf(device
, "I%30u", &span
);
14017 if (res
!= 1 || !span
|| NUM_SPANS
< span
) {
14018 /* Bad format for ISDN span device name. */
14019 return AST_DEVICE_UNKNOWN
;
14021 device
= strchr(device
, '/');
14023 /* Bad format for ISDN span device name. */
14024 return AST_DEVICE_UNKNOWN
;
14028 * Since there are currently no other span devstate's defined,
14029 * it must be congestion.
14031 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14033 if (!strcmp(device
, "congestion"))
14034 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14036 return pris
[span
- 1].pri
.congestion_devstate
;
14038 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14039 else if (!strcmp(device
, "threshold")) {
14040 return pris
[span
- 1].pri
.threshold_devstate
;
14042 return AST_DEVICE_UNKNOWN
;
14043 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14045 return AST_DEVICE_UNKNOWN
;
14046 #endif /* defined(HAVE_PRI) */
14050 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14053 * \param inbound Incoming asterisk channel.
14054 * \param dest Same dial string passed to dahdi_request().
14055 * \param callback Callback into CC core to announce a busy channel available for CC.
14058 * This callback acts like a forked dial with all prongs of the fork busy.
14059 * Essentially, for each channel that could have taken the call, indicate that
14062 * \retval 0 on success.
14063 * \retval -1 on error.
14065 static int dahdi_cc_callback(struct ast_channel
*inbound
, const char *dest
, ast_cc_callback_fn callback
)
14067 struct dahdi_pvt
*p
;
14068 struct dahdi_pvt
*exitpvt
;
14069 struct dahdi_starting_point start
;
14070 int groupmatched
= 0;
14071 int channelmatched
= 0;
14073 ast_mutex_lock(&iflock
);
14074 p
= determine_starting_point(dest
, &start
);
14076 ast_mutex_unlock(&iflock
);
14081 if (is_group_or_channel_match(p
, start
.span
, start
.groupmatch
, &groupmatched
, start
.channelmatch
, &channelmatched
)) {
14082 /* We found a potential match. call the callback */
14083 struct ast_str
*device_name
;
14085 const char *monitor_type
;
14086 char dialstring
[AST_CHANNEL_NAME
];
14087 char full_device_name
[AST_CHANNEL_NAME
];
14089 switch (ast_get_cc_monitor_policy(p
->cc_params
)) {
14090 case AST_CC_MONITOR_NEVER
:
14092 case AST_CC_MONITOR_NATIVE
:
14093 case AST_CC_MONITOR_ALWAYS
:
14094 case AST_CC_MONITOR_GENERIC
:
14095 #if defined(HAVE_PRI)
14096 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
14098 * ISDN is in a trunk busy condition so we need to monitor
14099 * the span congestion device state.
14101 snprintf(full_device_name
, sizeof(full_device_name
),
14102 "DAHDI/I%d/congestion", p
->pri
->span
);
14104 #endif /* defined(HAVE_PRI) */
14106 #if defined(HAVE_PRI)
14107 device_name
= create_channel_name(p
, 1, "");
14109 device_name
= create_channel_name(p
);
14110 #endif /* defined(HAVE_PRI) */
14111 snprintf(full_device_name
, sizeof(full_device_name
), "DAHDI/%s",
14112 device_name
? ast_str_buffer(device_name
) : "");
14113 ast_free(device_name
);
14115 * The portion after the '-' in the channel name is either a random
14116 * number, a sequence number, or a subchannel number. None are
14117 * necessary so strip them off.
14119 dash
= strrchr(full_device_name
, '-');
14124 snprintf(dialstring
, sizeof(dialstring
), "DAHDI/%s", dest
);
14127 * Analog can only do generic monitoring.
14128 * ISDN is in a trunk busy condition and any "device" is going
14129 * to be busy until a B channel becomes available. The generic
14130 * monitor can do this task.
14132 monitor_type
= AST_CC_GENERIC_MONITOR_TYPE
;
14134 #if defined(HAVE_PRI)
14135 p
->pri
? p
->pri
->cc_params
: p
->cc_params
,
14138 #endif /* defined(HAVE_PRI) */
14139 monitor_type
, full_device_name
, dialstring
, NULL
);
14143 p
= start
.backwards
? p
->prev
: p
->next
;
14145 p
= start
.backwards
? ifend
: iflist
;
14147 if (p
== exitpvt
) {
14151 ast_mutex_unlock(&iflock
);
14155 #if defined(HAVE_SS7)
14156 static void dahdi_ss7_message(struct ss7
*ss7
, char *s
)
14161 for (i
= 0; i
< NUM_SPANS
; i
++) {
14162 if (linksets
[i
].ss7
.ss7
== ss7
) {
14163 ast_verbose_callid(0, "[%d] %s", i
+ 1, s
);
14168 ast_verbose_callid(0, "%s", s
);
14170 #endif /* defined(HAVE_SS7) */
14172 #if defined(HAVE_SS7)
14173 static void dahdi_ss7_error(struct ss7
*ss7
, char *s
)
14178 for (i
= 0; i
< NUM_SPANS
; i
++) {
14179 if (linksets
[i
].ss7
.ss7
== ss7
) {
14180 ast_log_callid(LOG_ERROR
, 0, "[%d] %s", i
+ 1, s
);
14185 ast_log_callid(LOG_ERROR
, 0, "%s", s
);
14187 #endif /* defined(HAVE_SS7) */
14189 #if defined(HAVE_OPENR2)
14190 static void *mfcr2_monitor(void *data
)
14192 struct dahdi_mfcr2
*mfcr2
= data
;
14193 struct dahdi_pvt
*pvt
;
14195 /* we should be using pthread_key_create
14196 and allocate pollers dynamically.
14197 I think do_monitor() could be leaking, since it
14198 could be cancelled at any time and is not
14199 using thread keys, why?, */
14200 struct pollfd pollers
[ARRAY_LEN(mfcr2
->pvts
)];
14208 /* now that we're ready to get calls, unblock our side and
14209 get current line state */
14210 for (i
= 0; i
< mfcr2
->numchans
; i
++) {
14211 pvt
= mfcr2
->pvts
[i
];
14215 openr2_chan_set_idle(pvt
->r2chan
);
14216 openr2_chan_handle_cas(pvt
->r2chan
);
14219 /* we trust here that the mfcr2 channel list will not ever change once
14220 the module is loaded */
14222 for (i
= 0; i
< mfcr2
->numchans
; i
++) {
14223 pollers
[i
].revents
= 0;
14224 pollers
[i
].events
= 0;
14225 pvt
= mfcr2
->pvts
[i
];
14232 if (mfcr2
->nodev
) {
14235 if (!pvt
->r2chan
) {
14236 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt
->channel
);
14240 openr2_chan_enable_read(pvt
->r2chan
);
14241 pollers
[i
].events
= POLLIN
| POLLPRI
;
14242 pollers
[i
].fd
= pvt
->subs
[SUB_REAL
].dfd
;
14248 if (pollsize
== 0) {
14250 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14253 poll(NULL
, 0, maxsleep
);
14257 /* probably poll() is a valid cancel point, lets just be on the safe side
14258 by calling pthread_testcancel */
14259 pthread_testcancel();
14260 res
= poll(pollers
, mfcr2
->numchans
, maxsleep
);
14261 pthread_testcancel();
14262 if ((res
< 0) && (errno
!= EINTR
)) {
14263 ast_log(LOG_ERROR
, "going out, poll failed: %s\n", strerror(errno
));
14266 /* do we want to allow to cancel while processing events? */
14267 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &oldstate
);
14268 for (i
= 0; i
< mfcr2
->numchans
; i
++) {
14269 pvt
= mfcr2
->pvts
[i
];
14273 if (pollers
[i
].revents
& POLLPRI
|| pollers
[i
].revents
& POLLIN
) {
14274 openr2_chan_process_event(pvt
->r2chan
);
14277 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
14279 ast_log(LOG_NOTICE
, "Quitting MFC/R2 monitor thread\n");
14282 #endif /* HAVE_OPENR2 */
14284 #if defined(HAVE_PRI)
14285 static void dahdi_pri_message(struct pri
*pri
, char *s
)
14291 int dchancount
= 0;
14294 for (x
= 0; x
< NUM_SPANS
; x
++) {
14295 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
14296 if (pris
[x
].pri
.dchans
[y
]) {
14300 if (pris
[x
].pri
.dchans
[y
] == pri
) {
14311 if (1 < dchancount
) {
14312 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span
+ 1, dchan
, s
);
14314 ast_verbose_callid(0, "PRI Span: %d %s", span
+ 1, s
);
14317 ast_verbose_callid(0, "PRI Span: ? %s", s
);
14320 ast_verbose_callid(0, "PRI Span: ? %s", s
);
14323 ast_mutex_lock(&pridebugfdlock
);
14325 if (pridebugfd
>= 0) {
14326 if (write(pridebugfd
, s
, strlen(s
)) < 0) {
14327 ast_log_callid(LOG_WARNING
, 0, "write() failed: %s\n", strerror(errno
));
14331 ast_mutex_unlock(&pridebugfdlock
);
14333 #endif /* defined(HAVE_PRI) */
14335 #if defined(HAVE_PRI)
14336 static void dahdi_pri_error(struct pri
*pri
, char *s
)
14342 int dchancount
= 0;
14345 for (x
= 0; x
< NUM_SPANS
; x
++) {
14346 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
14347 if (pris
[x
].pri
.dchans
[y
]) {
14351 if (pris
[x
].pri
.dchans
[y
] == pri
) {
14362 if (1 < dchancount
) {
14363 ast_log_callid(LOG_ERROR
, 0, "[PRI Span: %d D-Channel: %d] %s", span
+ 1, dchan
, s
);
14365 ast_log_callid(LOG_ERROR
, 0, "PRI Span: %d %s", span
+ 1, s
);
14368 ast_log_callid(LOG_ERROR
, 0, "PRI Span: ? %s", s
);
14371 ast_log_callid(LOG_ERROR
, 0, "PRI Span: ? %s", s
);
14374 ast_mutex_lock(&pridebugfdlock
);
14376 if (pridebugfd
>= 0) {
14377 if (write(pridebugfd
, s
, strlen(s
)) < 0) {
14378 ast_log_callid(LOG_WARNING
, 0, "write() failed: %s\n", strerror(errno
));
14382 ast_mutex_unlock(&pridebugfdlock
);
14384 #endif /* defined(HAVE_PRI) */
14386 #if defined(HAVE_PRI)
14387 static int prepare_pri(struct dahdi_pri
*pri
)
14390 struct dahdi_params p
;
14391 struct dahdi_bufferinfo bi
;
14392 struct dahdi_spaninfo si
;
14394 for (i
= 0; i
< SIG_PRI_NUM_DCHANS
; i
++) {
14395 if (!pri
->dchannels
[i
])
14397 if (pri
->pri
.fds
[i
] >= 0) {
14398 /* A partial range addition. Not a complete setup. */
14401 pri
->pri
.fds
[i
] = open("/dev/dahdi/channel", O_RDWR
);
14402 if ((pri
->pri
.fds
[i
] < 0)) {
14403 ast_log(LOG_ERROR
, "Unable to open D-channel (fd=%d) (%s)\n",
14404 pri
->pri
.fds
[i
], strerror(errno
));
14407 x
= pri
->dchannels
[i
];
14408 res
= ioctl(pri
->pri
.fds
[i
], DAHDI_SPECIFY
, &x
);
14410 dahdi_close_pri_fd(pri
, i
);
14411 ast_log(LOG_ERROR
, "Unable to SPECIFY channel %d (%s)\n", x
, strerror(errno
));
14414 memset(&p
, 0, sizeof(p
));
14415 res
= ioctl(pri
->pri
.fds
[i
], DAHDI_GET_PARAMS
, &p
);
14417 dahdi_close_pri_fd(pri
, i
);
14418 ast_log(LOG_ERROR
, "Unable to get parameters for D-channel %d (%s)\n", x
, strerror(errno
));
14421 if ((p
.sigtype
!= DAHDI_SIG_HDLCFCS
) && (p
.sigtype
!= DAHDI_SIG_HARDHDLC
)) {
14422 dahdi_close_pri_fd(pri
, i
);
14423 ast_log(LOG_ERROR
, "D-channel %d is not in HDLC/FCS mode.\n", x
);
14426 memset(&si
, 0, sizeof(si
));
14427 res
= ioctl(pri
->pri
.fds
[i
], DAHDI_SPANSTAT
, &si
);
14429 dahdi_close_pri_fd(pri
, i
);
14430 ast_log(LOG_ERROR
, "Unable to get span state for D-channel %d (%s)\n", x
, strerror(errno
));
14433 pri_event_noalarm(&pri
->pri
, i
, 1);
14435 pri_event_alarm(&pri
->pri
, i
, 1);
14437 memset(&bi
, 0, sizeof(bi
));
14438 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
14439 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
14442 if (ioctl(pri
->pri
.fds
[i
], DAHDI_SET_BUFINFO
, &bi
)) {
14443 ast_log(LOG_ERROR
, "Unable to set appropriate buffering on channel %d: %s\n", x
, strerror(errno
));
14444 dahdi_close_pri_fd(pri
, i
);
14447 pri
->pri
.dchan_logical_span
[i
] = pris
[p
.spanno
- 1].prilogicalspan
;
14451 #endif /* defined(HAVE_PRI) */
14453 #if defined(HAVE_PRI)
14454 static char *complete_span_helper(const char *line
, const char *word
, int pos
, int state
, int rpos
)
14462 for (which
= span
= 0; span
< NUM_SPANS
; span
++) {
14463 if (pris
[span
].pri
.pri
&& ++which
> state
) {
14464 if (ast_asprintf(&ret
, "%d", span
+ 1) < 0) { /* user indexes start from 1 */
14472 #endif /* defined(HAVE_PRI) */
14474 #if defined(HAVE_PRI)
14475 static char *complete_span_4(const char *line
, const char *word
, int pos
, int state
)
14477 return complete_span_helper(line
,word
,pos
,state
,3);
14479 #endif /* defined(HAVE_PRI) */
14481 #if defined(HAVE_PRI)
14482 static char *handle_pri_set_debug_file(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14487 e
->command
= "pri set debug file";
14488 e
->usage
= "Usage: pri set debug file [output-file]\n"
14489 " Sends PRI debug output to the specified output file\n";
14495 return CLI_SHOWUSAGE
;
14497 if (ast_strlen_zero(a
->argv
[4]))
14498 return CLI_SHOWUSAGE
;
14500 myfd
= open(a
->argv
[4], O_CREAT
|O_WRONLY
, AST_FILE_MODE
);
14502 ast_cli(a
->fd
, "Unable to open '%s' for writing\n", a
->argv
[4]);
14503 return CLI_SUCCESS
;
14506 ast_mutex_lock(&pridebugfdlock
);
14508 if (pridebugfd
>= 0)
14512 ast_copy_string(pridebugfilename
,a
->argv
[4],sizeof(pridebugfilename
));
14513 ast_mutex_unlock(&pridebugfdlock
);
14514 ast_cli(a
->fd
, "PRI debug output will be sent to '%s'\n", a
->argv
[4]);
14515 return CLI_SUCCESS
;
14517 #endif /* defined(HAVE_PRI) */
14519 #if defined(HAVE_PRI)
14520 static int action_pri_debug_file_set(struct mansession
*s
, const struct message
*m
)
14522 const char *output_file
= astman_get_header(m
, "File");
14525 if (ast_strlen_zero(output_file
)) {
14526 astman_send_error(s
, m
, "Action must define a 'File'");
14529 myfd
= open(output_file
, O_CREAT
|O_WRONLY
, AST_FILE_MODE
);
14531 astman_send_error(s
, m
, "Unable to open requested file for writing");
14535 ast_mutex_lock(&pridebugfdlock
);
14537 if (pridebugfd
>= 0) {
14542 ast_copy_string(pridebugfilename
, output_file
, sizeof(pridebugfilename
));
14543 ast_mutex_unlock(&pridebugfdlock
);
14544 astman_send_ack(s
, m
, "PRI debug output will now be sent to requested file.");
14548 #endif /* defined(HAVE_PRI) */
14550 #if defined(HAVE_PRI)
14551 static int action_pri_debug_file_unset(struct mansession
*s
, const struct message
*m
)
14553 ast_mutex_lock(&pridebugfdlock
);
14555 if (pridebugfd
>= 0) {
14561 ast_mutex_unlock(&pridebugfdlock
);
14563 astman_send_ack(s
, m
, "PRI Debug output to file disabled");
14566 #endif /* defined(HAVE_PRI) */
14568 #if defined(HAVE_PRI)
14569 static char *handle_pri_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14577 e
->command
= "pri set debug {on|off|hex|intense|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15} span";
14579 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14580 " Enables debugging on a given PRI span\n"
14581 " Level is a bitmap of the following values:\n"
14582 " 1 General debugging incl. state changes\n"
14583 " 2 Decoded Q.931 messages\n"
14584 " 4 Decoded Q.921 messages\n"
14585 " 8 Raw hex dumps of Q.921 frames\n"
14586 " on - equivalent to 3\n"
14587 " hex - equivalent to 8\n"
14588 " intense - equivalent to 15\n";
14591 return complete_span_4(a
->line
, a
->word
, a
->pos
, a
->n
);
14594 return CLI_SHOWUSAGE
;
14597 if (!strcasecmp(a
->argv
[3], "on")) {
14599 } else if (!strcasecmp(a
->argv
[3], "off")) {
14601 } else if (!strcasecmp(a
->argv
[3], "intense")) {
14603 } else if (!strcasecmp(a
->argv
[3], "hex")) {
14606 level
= atoi(a
->argv
[3]);
14608 span
= atoi(a
->argv
[5]);
14609 if ((span
< 1) || (span
> NUM_SPANS
)) {
14610 ast_cli(a
->fd
, "Invalid span %s. Should be a number %d to %d\n", a
->argv
[5], 1, NUM_SPANS
);
14611 return CLI_SUCCESS
;
14613 if (!pris
[span
-1].pri
.pri
) {
14614 ast_cli(a
->fd
, "No PRI running on span %d\n", span
);
14615 return CLI_SUCCESS
;
14618 if (level
& 1) debugmask
|= SIG_PRI_DEBUG_NORMAL
;
14619 if (level
& 2) debugmask
|= PRI_DEBUG_Q931_DUMP
;
14620 if (level
& 4) debugmask
|= PRI_DEBUG_Q921_DUMP
;
14621 if (level
& 8) debugmask
|= PRI_DEBUG_Q921_RAW
;
14623 /* Set debug level in libpri */
14624 for (x
= 0; x
< SIG_PRI_NUM_DCHANS
; x
++) {
14625 if (pris
[span
- 1].pri
.dchans
[x
]) {
14626 pri_set_debug(pris
[span
- 1].pri
.dchans
[x
], debugmask
);
14630 /* Close the debugging file if it's set */
14631 ast_mutex_lock(&pridebugfdlock
);
14632 if (0 <= pridebugfd
) {
14635 ast_cli(a
->fd
, "Disabled PRI debug output to file '%s'\n",
14638 ast_mutex_unlock(&pridebugfdlock
);
14640 pris
[span
- 1].pri
.debug
= (level
) ? 1 : 0;
14641 ast_cli(a
->fd
, "%s debugging on span %d\n", (level
) ? "Enabled" : "Disabled", span
);
14642 return CLI_SUCCESS
;
14644 #endif /* defined(HAVE_PRI) */
14646 #if defined(HAVE_PRI)
14647 static int action_pri_debug_set(struct mansession
*s
, const struct message
*m
)
14649 const char *level
= astman_get_header(m
, "Level");
14650 const char *span
= astman_get_header(m
, "Span");
14656 if (ast_strlen_zero(level
)) {
14657 astman_send_error(s
, m
, "'Level' was not specified");
14661 if (ast_strlen_zero(span
)) {
14662 astman_send_error(s
, m
, "'Span' was not specified");
14666 if (!strcasecmp(level
, "on")) {
14668 } else if (!strcasecmp(level
, "off")) {
14670 } else if (!strcasecmp(level
, "intense")) {
14672 } else if (!strcasecmp(level
, "hex")) {
14675 if (sscanf(level
, "%30d", &level_val
) != 1) {
14676 astman_send_error(s
, m
, "Invalid value for 'Level'");
14681 if (sscanf(span
, "%30d", &span_val
) != 1) {
14682 astman_send_error(s
, m
, "Invalid value for 'Span'");
14685 if ((span_val
< 1) || (span_val
> NUM_SPANS
)) {
14686 const char *id
= astman_get_header(m
, "ActionID");
14687 char id_text
[256] = "";
14689 if (!ast_strlen_zero(id
)) {
14690 snprintf(id_text
, sizeof(id_text
), "ActionID: %s\r\n", id
);
14693 astman_append(s
, "Response: Error\r\n"
14695 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14703 if (!pris
[span_val
-1].pri
.pri
) {
14704 astman_send_error(s
, m
, "No PRI running on requested span");
14708 if (level_val
& 1) {
14709 debugmask
|= SIG_PRI_DEBUG_NORMAL
;
14711 if (level_val
& 2) {
14712 debugmask
|= PRI_DEBUG_Q931_DUMP
;
14714 if (level_val
& 4) {
14715 debugmask
|= PRI_DEBUG_Q921_DUMP
;
14717 if (level_val
& 8) {
14718 debugmask
|= PRI_DEBUG_Q921_RAW
;
14721 /* Set debug level in libpri */
14722 for (x
= 0; x
< SIG_PRI_NUM_DCHANS
; x
++) {
14723 if (pris
[span_val
- 1].pri
.dchans
[x
]) {
14724 pri_set_debug(pris
[span_val
- 1].pri
.dchans
[x
], debugmask
);
14728 pris
[span_val
- 1].pri
.debug
= (level_val
) ? 1 : 0;
14729 astman_send_ack(s
, m
, "Debug level set for requested span");
14733 #endif /* defined(HAVE_PRI) */
14735 #if defined(HAVE_PRI)
14736 #if defined(HAVE_PRI_SERVICE_MESSAGES)
14737 static char *handle_pri_service_generic(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
, int changestatus
)
14742 int x
, y
, fd
= a
->fd
;
14743 int interfaceid
= 0;
14744 char db_chan_name
[20], db_answer
[15];
14745 struct dahdi_pvt
*tmp
;
14746 struct dahdi_pri
*pri
;
14748 if (a
->argc
< 5 || a
->argc
> 6)
14749 return CLI_SHOWUSAGE
;
14750 if (strchr(a
->argv
[4], ':')) {
14751 if (sscanf(a
->argv
[4], "%30d:%30d", &trunkgroup
, &channel
) != 2)
14752 return CLI_SHOWUSAGE
;
14753 if ((trunkgroup
< 1) || (channel
< 1))
14754 return CLI_SHOWUSAGE
;
14756 for (x
=0;x
<NUM_SPANS
;x
++) {
14757 if (pris
[x
].pri
.trunkgroup
== trunkgroup
) {
14763 ast_cli(fd
, "No such trunk group %d\n", trunkgroup
);
14764 return CLI_FAILURE
;
14767 channel
= atoi(a
->argv
[4]);
14770 interfaceid
= atoi(a
->argv
[5]);
14772 /* either servicing a D-Channel */
14773 for (x
= 0; x
< NUM_SPANS
; x
++) {
14774 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
14775 if (pris
[x
].dchannels
[y
] == channel
) {
14777 if (pri
->pri
.enable_service_message_support
) {
14778 ast_mutex_lock(&pri
->pri
.lock
);
14779 pri_maintenance_service(pri
->pri
.pri
, interfaceid
, -1, changestatus
);
14780 ast_mutex_unlock(&pri
->pri
.lock
);
14783 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14784 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14786 return CLI_SUCCESS
;
14791 /* or servicing a B-Channel */
14792 ast_mutex_lock(&iflock
);
14793 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
14794 if (tmp
->pri
&& tmp
->channel
== channel
) {
14795 ast_mutex_unlock(&iflock
);
14796 ast_mutex_lock(&tmp
->pri
->lock
);
14797 if (!tmp
->pri
->enable_service_message_support
) {
14798 ast_mutex_unlock(&tmp
->pri
->lock
);
14800 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14801 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14802 return CLI_SUCCESS
;
14804 snprintf(db_chan_name
, sizeof(db_chan_name
), "%s/%d:%d", dahdi_db
, tmp
->span
, channel
);
14805 why
= &((struct sig_pri_chan
*) tmp
->sig_pvt
)->service_status
;
14806 switch(changestatus
) {
14807 case 0: /* enable */
14808 /* Near end wants to be in service now. */
14809 ast_db_del(db_chan_name
, SRVST_DBKEY
);
14810 *why
&= ~SRVST_NEAREND
;
14812 snprintf(db_answer
, sizeof(db_answer
), "%s:%u", SRVST_TYPE_OOS
, *why
);
14813 ast_db_put(db_chan_name
, SRVST_DBKEY
, db_answer
);
14815 dahdi_pri_update_span_devstate(tmp
->pri
);
14818 /* case 1: -- loop */
14819 case 2: /* disable */
14820 /* Near end wants to be out-of-service now. */
14821 ast_db_del(db_chan_name
, SRVST_DBKEY
);
14822 *why
|= SRVST_NEAREND
;
14823 snprintf(db_answer
, sizeof(db_answer
), "%s:%u", SRVST_TYPE_OOS
, *why
);
14824 ast_db_put(db_chan_name
, SRVST_DBKEY
, db_answer
);
14825 dahdi_pri_update_span_devstate(tmp
->pri
);
14827 /* case 3: -- continuity */
14828 /* case 4: -- shutdown */
14830 ast_log(LOG_WARNING
, "Unsupported changestatus: '%d'\n", changestatus
);
14833 pri_maintenance_bservice(tmp
->pri
->pri
, tmp
->sig_pvt
, changestatus
);
14834 ast_mutex_unlock(&tmp
->pri
->lock
);
14835 return CLI_SUCCESS
;
14838 ast_mutex_unlock(&iflock
);
14840 ast_cli(fd
, "Unable to find given channel %d, possibly not a PRI\n", channel
);
14841 return CLI_FAILURE
;
14844 static char *handle_pri_service_enable_channel(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14848 e
->command
= "pri service enable channel";
14850 "Usage: pri service enable channel <channel> [<interface id>]\n"
14851 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
14852 " to restore a channel to service, with optional interface id\n"
14853 " as agreed upon with remote switch operator\n";
14858 return handle_pri_service_generic(e
, cmd
, a
, 0);
14861 static char *handle_pri_service_disable_channel(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14865 e
->command
= "pri service disable channel";
14867 "Usage: pri service disable channel <chan num> [<interface id>]\n"
14868 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
14869 " to remove a channel from service, with optional interface id\n"
14870 " as agreed upon with remote switch operator\n";
14875 return handle_pri_service_generic(e
, cmd
, a
, 2);
14877 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
14878 #endif /* defined(HAVE_PRI) */
14880 #if defined(HAVE_PRI)
14881 static char *handle_pri_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14887 e
->command
= "pri show channels";
14889 "Usage: pri show channels\n"
14890 " Displays PRI channel information such as the current mapping\n"
14891 " of DAHDI B channels to Asterisk channel names and which calls\n"
14892 " are on hold or call-waiting. Calls on hold or call-waiting\n"
14893 " are not associated with any B channel.\n";
14900 return CLI_SHOWUSAGE
;
14902 sig_pri_cli_show_channels_header(a
->fd
);
14903 for (span
= 0; span
< NUM_SPANS
; ++span
) {
14904 if (pris
[span
].pri
.pri
) {
14905 sig_pri_cli_show_channels(a
->fd
, &pris
[span
].pri
);
14908 return CLI_SUCCESS
;
14910 #endif /* defined(HAVE_PRI) */
14912 #if defined(HAVE_PRI)
14913 static char *handle_pri_show_spans(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14919 e
->command
= "pri show spans";
14921 "Usage: pri show spans\n"
14922 " Displays PRI span information\n";
14929 return CLI_SHOWUSAGE
;
14931 for (span
= 0; span
< NUM_SPANS
; span
++) {
14932 if (pris
[span
].pri
.pri
) {
14933 sig_pri_cli_show_spans(a
->fd
, span
+ 1, &pris
[span
].pri
);
14936 return CLI_SUCCESS
;
14938 #endif /* defined(HAVE_PRI) */
14940 #if defined(HAVE_PRI)
14941 #define container_of(ptr, type, member) \
14942 ((type *)((char *)(ptr) - offsetof(type, member)))
14945 * \brief Destroy a D-Channel of a PRI span
14948 * \param pri the pri span
14950 * Shuts down a span and destroys its D-Channel. Further destruction
14951 * of the B-channels using dahdi_destroy_channel() would probably be required
14952 * for the B-Channels.
14954 static void pri_destroy_span(struct sig_pri_span
*pri
)
14959 struct dahdi_pri
* dahdi_pri
;
14960 pthread_t master
= pri
->master
;
14962 if (!master
|| (master
== AST_PTHREADT_NULL
)) {
14965 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri
->span
);
14966 for (i
= 0; i
< pri
->numchans
; i
++) {
14968 struct sig_pri_chan
*pvt
= pri
->pvts
[i
];
14973 channel
= pvt
->channel
;
14974 ast_debug(2, "About to destroy B-channel %d.\n", channel
);
14975 dahdi_destroy_channel_range(channel
, channel
);
14978 cancel_code
= pthread_cancel(master
);
14979 pthread_kill(master
, SIGURG
);
14981 "Waiting to join thread of span %d "
14982 "with pid=%p cancel_code=%d\n",
14983 pri
->span
, (void *)master
, cancel_code
);
14984 res
= pthread_join(master
, NULL
);
14986 ast_log(LOG_NOTICE
, "pthread_join failed: %d\n", res
);
14988 pri
->master
= AST_PTHREADT_NULL
;
14990 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
14991 dahdi_pri
= container_of(pri
, struct dahdi_pri
, pri
);
14992 for (i
= 0; i
< SIG_PRI_NUM_DCHANS
; i
++) {
14993 ast_debug(4, "closing pri_fd %d\n", i
);
14994 dahdi_close_pri_fd(dahdi_pri
, i
);
14995 dahdi_pri
->dchannels
[i
] = 0;
14997 sig_pri_init_pri(pri
);
14998 ast_debug(1, "PRI span %d destroyed\n", pri
->span
);
15001 static char *handle_pri_destroy_span(struct ast_cli_entry
*e
, int cmd
,
15002 struct ast_cli_args
*a
)
15006 struct sig_pri_span
*pri
;
15010 e
->command
= "pri destroy span";
15012 "Usage: pri destroy span <span>\n"
15013 " Destorys D-channel of span and its B-channels.\n"
15014 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15017 return complete_span_4(a
->line
, a
->word
, a
->pos
, a
->n
);
15021 return CLI_SHOWUSAGE
;
15023 res
= sscanf(a
->argv
[3], "%30d", &span
);
15024 if ((res
!= 1) || span
< 1 || span
> NUM_SPANS
) {
15026 "Invalid span '%s'. Should be a number from %d to %d\n",
15027 a
->argv
[3], 1, NUM_SPANS
);
15028 return CLI_SUCCESS
;
15030 pri
= &pris
[span
- 1].pri
;
15032 ast_cli(a
->fd
, "No PRI running on span %d\n", span
);
15033 return CLI_SUCCESS
;
15036 pri_destroy_span(pri
);
15037 return CLI_SUCCESS
;
15040 #endif /* defined(HAVE_PRI) */
15042 #if defined(HAVE_PRI)
15043 static char *handle_pri_show_span(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15049 e
->command
= "pri show span";
15051 "Usage: pri show span <span>\n"
15052 " Displays PRI Information on a given PRI span\n";
15055 return complete_span_4(a
->line
, a
->word
, a
->pos
, a
->n
);
15059 return CLI_SHOWUSAGE
;
15060 span
= atoi(a
->argv
[3]);
15061 if ((span
< 1) || (span
> NUM_SPANS
)) {
15062 ast_cli(a
->fd
, "Invalid span '%s'. Should be a number from %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
15063 return CLI_SUCCESS
;
15065 if (!pris
[span
-1].pri
.pri
) {
15066 ast_cli(a
->fd
, "No PRI running on span %d\n", span
);
15067 return CLI_SUCCESS
;
15070 sig_pri_cli_show_span(a
->fd
, pris
[span
-1].dchannels
, &pris
[span
-1].pri
);
15072 return CLI_SUCCESS
;
15074 #endif /* defined(HAVE_PRI) */
15076 #if defined(HAVE_PRI)
15077 static char *handle_pri_show_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15086 e
->command
= "pri show debug";
15088 "Usage: pri show debug\n"
15089 " Show the debug state of pri spans\n";
15095 for (span
= 0; span
< NUM_SPANS
; span
++) {
15096 if (pris
[span
].pri
.pri
) {
15097 for (x
= 0; x
< SIG_PRI_NUM_DCHANS
; x
++) {
15098 if (pris
[span
].pri
.dchans
[x
]) {
15099 debug
= pri_get_debug(pris
[span
].pri
.dchans
[x
]);
15100 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" );
15107 ast_mutex_lock(&pridebugfdlock
);
15108 if (pridebugfd
>= 0)
15109 ast_cli(a
->fd
, "Logging PRI debug to file %s\n", pridebugfilename
);
15110 ast_mutex_unlock(&pridebugfdlock
);
15113 ast_cli(a
->fd
, "No PRI running\n");
15114 return CLI_SUCCESS
;
15116 #endif /* defined(HAVE_PRI) */
15118 #if defined(HAVE_PRI)
15119 static char *handle_pri_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15123 e
->command
= "pri show version";
15125 "Usage: pri show version\n"
15126 "Show libpri version information\n";
15132 ast_cli(a
->fd
, "libpri version: %s\n", pri_get_version());
15134 return CLI_SUCCESS
;
15136 #endif /* defined(HAVE_PRI) */
15138 #if defined(HAVE_PRI)
15139 static struct ast_cli_entry dahdi_pri_cli
[] = {
15140 AST_CLI_DEFINE(handle_pri_debug
, "Enables PRI debugging on a span"),
15141 #if defined(HAVE_PRI_SERVICE_MESSAGES)
15142 AST_CLI_DEFINE(handle_pri_service_enable_channel
, "Return a channel to service"),
15143 AST_CLI_DEFINE(handle_pri_service_disable_channel
, "Remove a channel from service"),
15144 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15145 AST_CLI_DEFINE(handle_pri_show_channels
, "Displays PRI channel information"),
15146 AST_CLI_DEFINE(handle_pri_show_spans
, "Displays PRI span information"),
15147 AST_CLI_DEFINE(handle_pri_show_span
, "Displays PRI span information"),
15148 AST_CLI_DEFINE(handle_pri_destroy_span
, "Destroy a PRI span"),
15149 AST_CLI_DEFINE(handle_pri_show_debug
, "Displays current PRI debug settings"),
15150 AST_CLI_DEFINE(handle_pri_set_debug_file
, "Sends PRI debug output to the specified file"),
15151 AST_CLI_DEFINE(handle_pri_version
, "Displays libpri version"),
15153 #endif /* defined(HAVE_PRI) */
15157 static char *handle_mfcr2_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15161 e
->command
= "mfcr2 show version";
15163 "Usage: mfcr2 show version\n"
15164 " Shows the version of the OpenR2 library being used.\n";
15169 ast_cli(a
->fd
, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15170 return CLI_SUCCESS
;
15173 static char *handle_mfcr2_show_variants(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15175 #define FORMAT "%4s %40s\n"
15177 int numvariants
= 0;
15178 const openr2_variant_entry_t
*variants
;
15181 e
->command
= "mfcr2 show variants";
15183 "Usage: mfcr2 show variants\n"
15184 " Shows the list of MFC/R2 variants supported.\n";
15189 if (!(variants
= openr2_proto_get_variant_list(&numvariants
))) {
15190 ast_cli(a
->fd
, "Failed to get list of variants.\n");
15191 return CLI_FAILURE
;
15193 ast_cli(a
->fd
, FORMAT
, "Variant Code", "Country");
15194 for (i
= 0; i
< numvariants
; i
++) {
15195 ast_cli(a
->fd
, FORMAT
, variants
[i
].name
, variants
[i
].country
);
15197 return CLI_SUCCESS
;
15201 static char *handle_mfcr2_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15203 #define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15204 int filtertype
= 0;
15210 struct dahdi_pvt
*p
;
15211 openr2_context_t
*r2context
;
15212 openr2_variant_t r2variant
;
15215 e
->command
= "mfcr2 show channels [group|context]";
15217 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15218 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15223 if (!((a
->argc
== 3) || (a
->argc
== 5))) {
15224 return CLI_SHOWUSAGE
;
15226 if (a
->argc
== 5) {
15227 if (!strcasecmp(a
->argv
[3], "group")) {
15228 targetnum
= atoi(a
->argv
[4]);
15229 if ((targetnum
< 0) || (targetnum
> 63))
15230 return CLI_SHOWUSAGE
;
15231 targetnum
= 1 << targetnum
;
15233 } else if (!strcasecmp(a
->argv
[3], "context")) {
15236 return CLI_SHOWUSAGE
;
15239 ast_cli(a
->fd
, FORMAT
, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15240 ast_mutex_lock(&iflock
);
15241 for (p
= iflist
; p
; p
= p
->next
) {
15242 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15246 switch(filtertype
) {
15247 case 1: /* mfcr2 show channels group <group> */
15248 if (p
->group
!= targetnum
) {
15252 case 2: /* mfcr2 show channels context <context> */
15253 if (strcasecmp(p
->context
, a
->argv
[4])) {
15261 r2context
= openr2_chan_get_context(p
->r2chan
);
15262 r2variant
= openr2_context_get_variant(r2context
);
15263 snprintf(channo
, sizeof(channo
), "%d", p
->channel
);
15264 snprintf(linkno
, sizeof(linkno
), "%d", p
->mfcr2
->index
);
15265 snprintf(anino
, sizeof(anino
), "%d", openr2_context_get_max_ani(r2context
));
15266 snprintf(dnisno
, sizeof(dnisno
), "%d", openr2_context_get_max_dnis(r2context
));
15267 ast_cli(a
->fd
, FORMAT
, channo
, linkno
, openr2_proto_get_variant_string(r2variant
),
15268 anino
, dnisno
, openr2_context_get_ani_first(r2context
) ? "Yes" : "No",
15269 openr2_context_get_immediate_accept(r2context
) ? "Yes" : "No",
15270 openr2_chan_get_tx_cas_string(p
->r2chan
), openr2_chan_get_rx_cas_string(p
->r2chan
));
15272 ast_mutex_unlock(&iflock
);
15273 return CLI_SUCCESS
;
15277 static char *handle_mfcr2_set_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15279 struct dahdi_pvt
*p
= NULL
;
15281 char *toklevel
= NULL
;
15282 char *saveptr
= NULL
;
15283 char *logval
= NULL
;
15284 openr2_log_level_t loglevel
= OR2_LOG_NOTHING
;
15285 openr2_log_level_t tmplevel
= OR2_LOG_NOTHING
;
15288 e
->command
= "mfcr2 set debug";
15290 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15291 " Set a new logging level for the specified channel.\n"
15292 " If no channel is specified the logging level will be applied to all channels.\n";
15298 return CLI_SHOWUSAGE
;
15300 channo
= (a
->argc
== 5) ? atoi(a
->argv
[4]) : -1;
15301 logval
= ast_strdupa(a
->argv
[3]);
15302 toklevel
= strtok_r(logval
, ",", &saveptr
);
15303 if (-1 == (tmplevel
= openr2_log_get_level(toklevel
))) {
15304 ast_cli(a
->fd
, "Invalid MFC/R2 logging level '%s'.\n", a
->argv
[3]);
15305 return CLI_FAILURE
;
15306 } else if (OR2_LOG_NOTHING
== tmplevel
) {
15307 loglevel
= tmplevel
;
15309 loglevel
|= tmplevel
;
15310 while ((toklevel
= strtok_r(NULL
, ",", &saveptr
))) {
15311 if (-1 == (tmplevel
= openr2_log_get_level(toklevel
))) {
15312 ast_cli(a
->fd
, "Ignoring invalid logging level: '%s'.\n", toklevel
);
15315 loglevel
|= tmplevel
;
15318 ast_mutex_lock(&iflock
);
15319 for (p
= iflist
; p
; p
= p
->next
) {
15320 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15323 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15326 openr2_chan_set_log_level(p
->r2chan
, loglevel
);
15327 if (channo
!= -1) {
15328 ast_cli(a
->fd
, "MFC/R2 debugging set to '%s' for channel %d.\n", a
->argv
[3], p
->channel
);
15332 if ((channo
!= -1) && !p
) {
15333 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15335 if (channo
== -1) {
15336 ast_cli(a
->fd
, "MFC/R2 debugging set to '%s' for all channels.\n", a
->argv
[3]);
15338 ast_mutex_unlock(&iflock
);
15339 return CLI_SUCCESS
;
15342 static char *handle_mfcr2_call_files(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15344 struct dahdi_pvt
*p
= NULL
;
15348 e
->command
= "mfcr2 call files [on|off]";
15350 "Usage: mfcr2 call files [on|off] <channel>\n"
15351 " Enable call files creation on the specified channel.\n"
15352 " If no channel is specified call files creation policy will be applied to all channels.\n";
15358 return CLI_SHOWUSAGE
;
15360 channo
= (a
->argc
== 5) ? atoi(a
->argv
[4]) : -1;
15361 ast_mutex_lock(&iflock
);
15362 for (p
= iflist
; p
; p
= p
->next
) {
15363 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15366 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15369 if (ast_true(a
->argv
[3])) {
15370 openr2_chan_enable_call_files(p
->r2chan
);
15372 openr2_chan_disable_call_files(p
->r2chan
);
15374 if (channo
!= -1) {
15375 if (ast_true(a
->argv
[3])) {
15376 ast_cli(a
->fd
, "MFC/R2 call files enabled for channel %d.\n", p
->channel
);
15378 ast_cli(a
->fd
, "MFC/R2 call files disabled for channel %d.\n", p
->channel
);
15383 if ((channo
!= -1) && !p
) {
15384 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15386 if (channo
== -1) {
15387 if (ast_true(a
->argv
[3])) {
15388 ast_cli(a
->fd
, "MFC/R2 Call files enabled for all channels.\n");
15390 ast_cli(a
->fd
, "MFC/R2 Call files disabled for all channels.\n");
15393 ast_mutex_unlock(&iflock
);
15394 return CLI_SUCCESS
;
15397 static char *handle_mfcr2_set_idle(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15399 struct dahdi_pvt
*p
= NULL
;
15403 e
->command
= "mfcr2 set idle";
15405 "Usage: mfcr2 set idle <channel>\n"
15406 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15407 " Force the given channel into IDLE state.\n"
15408 " If no channel is specified, all channels will be set to IDLE.\n";
15413 channo
= (a
->argc
== 4) ? atoi(a
->argv
[3]) : -1;
15414 ast_mutex_lock(&iflock
);
15415 for (p
= iflist
; p
; p
= p
->next
) {
15416 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15419 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15422 openr2_chan_set_idle(p
->r2chan
);
15423 ast_mutex_lock(&p
->lock
);
15424 p
->locallyblocked
= 0;
15426 ast_mutex_unlock(&p
->lock
);
15427 if (channo
!= -1) {
15431 if ((channo
!= -1) && !p
) {
15432 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15434 ast_mutex_unlock(&iflock
);
15435 return CLI_SUCCESS
;
15438 static char *handle_mfcr2_set_blocked(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15440 struct dahdi_pvt
*p
= NULL
;
15444 e
->command
= "mfcr2 set blocked";
15446 "Usage: mfcr2 set blocked <channel>\n"
15447 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15448 " Force the given channel into BLOCKED state.\n"
15449 " If no channel is specified, all channels will be set to BLOCKED.\n";
15454 channo
= (a
->argc
== 4) ? atoi(a
->argv
[3]) : -1;
15455 ast_mutex_lock(&iflock
);
15456 for (p
= iflist
; p
; p
= p
->next
) {
15457 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15460 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15463 openr2_chan_set_blocked(p
->r2chan
);
15464 ast_mutex_lock(&p
->lock
);
15465 p
->locallyblocked
= 1;
15466 ast_mutex_unlock(&p
->lock
);
15467 if (channo
!= -1) {
15471 if ((channo
!= -1) && !p
) {
15472 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15474 ast_mutex_unlock(&iflock
);
15475 return CLI_SUCCESS
;
15478 static void mfcr2_show_links_of(struct ast_cli_args
*a
, struct r2links
*list_head
, const char *title
)
15480 #define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15481 AST_LIST_LOCK(list_head
);
15482 if (! AST_LIST_EMPTY(list_head
)) {
15485 char live_chans_str
[5];
15486 char channel_list
[R2_LINK_CAPACITY
* 4];
15487 struct r2link_entry
*cur
;
15488 ast_cli(a
->fd
, "%s\n", title
);
15489 ast_cli(a
->fd
, FORMAT
, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15490 AST_LIST_TRAVERSE(list_head
, cur
, list
) {
15491 struct dahdi_mfcr2
*mfcr2
= &cur
->mfcr2
;
15492 const char *thread_status
= NULL
;
15499 if (mfcr2
->r2master
== 0L) {
15500 thread_status
= "zero";
15501 } else if (mfcr2
->r2master
== AST_PTHREADT_NULL
) {
15502 thread_status
= "none";
15504 thread_status
= "created";
15506 snprintf(index
, sizeof(index
), "%d", mfcr2
->index
);
15507 snprintf(live_chans_str
, sizeof(live_chans_str
), "%d", mfcr2
->live_chans
);
15512 /* Prepare nice string in channel_list[] */
15513 for (i
= 0; i
< mfcr2
->numchans
&& len
< sizeof(channel_list
) - 1; i
++) {
15514 struct dahdi_pvt
*p
= mfcr2
->pvts
[i
];
15518 channo
= p
->channel
;
15519 /* Don't show a range until we know the last channel number */
15520 if (prev_channo
&& prev_channo
== channo
- 1) {
15521 prev_channo
= channo
;
15525 if (inside_range
) {
15527 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, "-%d,%d", prev_channo
, channo
);
15529 } else if (prev_channo
) {
15530 /* Non-sequential channel numbers */
15531 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, ",%d", channo
);
15533 /* First channel number */
15534 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, "%d", channo
);
15536 prev_channo
= channo
;
15538 /* Handle leftover channels */
15539 if (inside_range
) {
15541 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, "-%d", channo
);
15543 } else if (prev_channo
) {
15544 /* Non-sequential channel numbers */
15545 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, ",%d", channo
);
15547 // channel_list[len] = '\0';
15548 ast_cli(a
->fd
, FORMAT
,
15551 (mfcr2
->nodev
) ? "MISSING" : "OK",
15556 AST_LIST_UNLOCK(list_head
);
15560 static char *handle_mfcr2_show_links(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15564 e
->command
= "mfcr2 show links";
15566 "Usage: mfcr2 show links\n"
15567 " Shows the DAHDI MFC/R2 links.\n";
15572 if (a
->argc
!= 3) {
15573 return CLI_SHOWUSAGE
;
15575 mfcr2_show_links_of(a
, &r2links
, "Live links\n");
15576 mfcr2_show_links_of(a
, &nodev_r2links
, "Links to be removed (device missing)\n");
15577 return CLI_SUCCESS
;
15580 static char *handle_mfcr2_destroy_link(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15583 int wanted_link_index
;
15584 int found_link
= 0;
15585 struct r2link_entry
*cur
= NULL
;
15589 e
->command
= "mfcr2 destroy link";
15591 "Usage: mfcr2 destroy link <index-number>\n"
15592 " Destorys D-channel of link and its B-channels.\n"
15593 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15599 return CLI_SHOWUSAGE
;
15601 res
= sscanf(a
->argv
[3], "%30d", &wanted_link_index
);
15602 if ((res
!= 1) || wanted_link_index
< 1) {
15604 "Invalid link index '%s'. Should be a positive number\n", a
->argv
[3]);
15605 return CLI_SUCCESS
;
15607 AST_LIST_LOCK(&r2links
);
15608 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links
, cur
, list
) {
15609 struct dahdi_mfcr2
*mfcr2
= &cur
->mfcr2
;
15610 if (wanted_link_index
== mfcr2
->index
) {
15611 AST_LIST_MOVE_CURRENT(&nodev_r2links
, list
);
15616 AST_LIST_TRAVERSE_SAFE_END
;
15617 AST_LIST_UNLOCK(&r2links
);
15618 if (! found_link
) {
15619 ast_cli(a
->fd
, "No link found with index %d.\n", wanted_link_index
);
15620 return CLI_FAILURE
;
15622 return CLI_SUCCESS
;
15625 static struct ast_cli_entry dahdi_mfcr2_cli
[] = {
15626 AST_CLI_DEFINE(handle_mfcr2_version
, "Show OpenR2 library version"),
15627 AST_CLI_DEFINE(handle_mfcr2_show_variants
, "Show supported MFC/R2 variants"),
15628 AST_CLI_DEFINE(handle_mfcr2_show_channels
, "Show MFC/R2 channels"),
15629 AST_CLI_DEFINE(handle_mfcr2_show_links
, "Show MFC/R2 links"),
15630 AST_CLI_DEFINE(handle_mfcr2_set_debug
, "Set MFC/R2 channel logging level"),
15631 AST_CLI_DEFINE(handle_mfcr2_call_files
, "Enable/Disable MFC/R2 call files"),
15632 AST_CLI_DEFINE(handle_mfcr2_set_idle
, "Reset MFC/R2 channel forcing it to IDLE"),
15633 AST_CLI_DEFINE(handle_mfcr2_set_blocked
, "Reset MFC/R2 channel forcing it to BLOCKED"),
15634 AST_CLI_DEFINE(handle_mfcr2_destroy_link
, "Destroy given MFC/R2 link"),
15637 #endif /* HAVE_OPENR2 */
15639 static char *dahdi_destroy_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15645 e
->command
= "dahdi destroy channels";
15647 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15648 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15653 if ((a
->argc
< 4) || a
->argc
> 5) {
15654 return CLI_SHOWUSAGE
;
15656 start
= atoi(a
->argv
[3]);
15658 ast_cli(a
->fd
, "Invalid starting channel number %s.\n",
15660 return CLI_FAILURE
;
15662 if (a
->argc
== 5) {
15663 end
= atoi(a
->argv
[4]);
15665 ast_cli(a
->fd
, "Invalid ending channel number %s.\n",
15667 return CLI_FAILURE
;
15675 "range end (%d) is smaller than range start (%d)\n",
15677 return CLI_FAILURE
;
15679 dahdi_destroy_channel_range(start
, end
);
15680 return CLI_SUCCESS
;
15683 static char *dahdi_create_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15691 e
->command
= "dahdi create channels";
15692 e
->usage
= "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15693 " dahdi create channels new - add channels not yet created\n"
15694 "For ISDN and SS7 the range should include complete spans.\n";
15699 if ((a
->argc
< 4) || a
->argc
> 5) {
15700 return CLI_SHOWUSAGE
;
15702 if (a
->argc
== 4 && !strcmp(a
->argv
[3], "new")) {
15703 ret
= dahdi_create_channel_range(0, 0);
15704 return (RESULT_SUCCESS
== ret
) ? CLI_SUCCESS
: CLI_FAILURE
;
15706 start
= atoi(a
->argv
[3]);
15708 ast_cli(a
->fd
, "Invalid starting channel number '%s'.\n",
15710 return CLI_FAILURE
;
15712 if (a
->argc
== 5) {
15713 end
= atoi(a
->argv
[4]);
15715 ast_cli(a
->fd
, "Invalid ending channel number '%s'.\n",
15717 return CLI_FAILURE
;
15724 "range end (%d) is smaller than range start (%d)\n",
15726 return CLI_FAILURE
;
15728 ret
= dahdi_create_channel_range(start
, end
);
15729 return (RESULT_SUCCESS
== ret
) ? CLI_SUCCESS
: CLI_FAILURE
;
15732 static void dahdi_softhangup_all(void)
15734 struct dahdi_pvt
*p
;
15736 ast_mutex_lock(&iflock
);
15737 for (p
= iflist
; p
; p
= p
->next
) {
15738 ast_mutex_lock(&p
->lock
);
15739 if (p
->owner
&& !p
->restartpending
) {
15740 if (ast_channel_trylock(p
->owner
)) {
15741 if (DEBUG_ATLEAST(3))
15742 ast_verbose("Avoiding deadlock\n");
15743 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15744 ast_mutex_unlock(&p
->lock
);
15745 ast_mutex_unlock(&iflock
);
15748 if (DEBUG_ATLEAST(3))
15749 ast_verbose("Softhanging up on %s\n", ast_channel_name(p
->owner
));
15750 ast_softhangup_nolock(p
->owner
, AST_SOFTHANGUP_EXPLICIT
);
15751 p
->restartpending
= 1;
15752 num_restart_pending
++;
15753 ast_channel_unlock(p
->owner
);
15755 ast_mutex_unlock(&p
->lock
);
15757 ast_mutex_unlock(&iflock
);
15760 static int dahdi_restart(void)
15762 #if defined(HAVE_PRI) || defined(HAVE_SS7)
15764 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15766 struct dahdi_pvt
*p
;
15768 ast_mutex_lock(&restart_lock
);
15769 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15770 dahdi_softhangup_all();
15771 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15773 dahdi_r2_destroy_links();
15776 #if defined(HAVE_PRI)
15777 for (i
= 0; i
< NUM_SPANS
; i
++) {
15778 if (pris
[i
].pri
.master
&& (pris
[i
].pri
.master
!= AST_PTHREADT_NULL
)) {
15779 cancel_code
= pthread_cancel(pris
[i
].pri
.master
);
15780 pthread_kill(pris
[i
].pri
.master
, SIGURG
);
15781 ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i
, (void *) pris
[i
].pri
.master
, cancel_code
);
15782 pthread_join(pris
[i
].pri
.master
, NULL
);
15783 ast_debug(4, "Joined thread of span %d\n", i
);
15788 #if defined(HAVE_SS7)
15789 for (i
= 0; i
< NUM_SPANS
; i
++) {
15790 if (linksets
[i
].ss7
.master
&& (linksets
[i
].ss7
.master
!= AST_PTHREADT_NULL
)) {
15791 cancel_code
= pthread_cancel(linksets
[i
].ss7
.master
);
15792 pthread_kill(linksets
[i
].ss7
.master
, SIGURG
);
15793 ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i
, (void *) linksets
[i
].ss7
.master
, cancel_code
);
15794 pthread_join(linksets
[i
].ss7
.master
, NULL
);
15795 ast_debug(4, "Joined thread of span %d\n", i
);
15798 #endif /* defined(HAVE_SS7) */
15800 ast_mutex_lock(&monlock
);
15801 if (monitor_thread
&& (monitor_thread
!= AST_PTHREADT_STOP
) && (monitor_thread
!= AST_PTHREADT_NULL
)) {
15802 cancel_code
= pthread_cancel(monitor_thread
);
15803 pthread_kill(monitor_thread
, SIGURG
);
15804 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread
, cancel_code
);
15805 pthread_join(monitor_thread
, NULL
);
15806 ast_debug(4, "Joined monitor thread\n");
15808 monitor_thread
= AST_PTHREADT_NULL
; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
15810 ast_mutex_lock(&ss_thread_lock
);
15811 while (ss_thread_count
> 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
15812 int x
= DAHDI_FLASH
;
15813 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count
);
15815 ast_mutex_lock(&iflock
);
15816 for (p
= iflist
; p
; p
= p
->next
) {
15818 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
15819 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
15822 ast_mutex_unlock(&iflock
);
15823 ast_cond_wait(&ss_thread_complete
, &ss_thread_lock
);
15826 /* ensure any created channels before monitor threads were stopped are hungup */
15827 dahdi_softhangup_all();
15828 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
15829 destroy_all_channels();
15830 memset(round_robin
, 0, sizeof(round_robin
));
15831 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
15833 ast_mutex_unlock(&monlock
);
15836 for (i
= 0; i
< NUM_SPANS
; i
++) {
15837 for (j
= 0; j
< SIG_PRI_NUM_DCHANS
; j
++)
15838 dahdi_close_pri_fd(&(pris
[i
]), j
);
15841 memset(pris
, 0, sizeof(pris
));
15842 for (i
= 0; i
< NUM_SPANS
; i
++) {
15843 sig_pri_init_pri(&pris
[i
].pri
);
15845 pri_set_error(dahdi_pri_error
);
15846 pri_set_message(dahdi_pri_message
);
15848 #if defined(HAVE_SS7)
15849 for (i
= 0; i
< NUM_SPANS
; i
++) {
15850 for (j
= 0; j
< SIG_SS7_NUM_DCHANS
; j
++)
15851 dahdi_close_ss7_fd(&(linksets
[i
]), j
);
15854 memset(linksets
, 0, sizeof(linksets
));
15855 for (i
= 0; i
< NUM_SPANS
; i
++) {
15856 sig_ss7_init_linkset(&linksets
[i
].ss7
);
15858 ss7_set_error(dahdi_ss7_error
);
15859 ss7_set_message(dahdi_ss7_message
);
15860 ss7_set_hangup(sig_ss7_cb_hangup
);
15861 ss7_set_notinservice(sig_ss7_cb_notinservice
);
15862 ss7_set_call_null(sig_ss7_cb_call_null
);
15863 #endif /* defined(HAVE_SS7) */
15865 if (setup_dahdi(2) != 0) {
15866 ast_log(LOG_WARNING
, "Reload channels from dahdi config failed!\n");
15867 ast_mutex_unlock(&ss_thread_lock
);
15870 ast_mutex_unlock(&ss_thread_lock
);
15871 ast_mutex_unlock(&restart_lock
);
15875 static char *dahdi_restart_cmd(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15879 e
->command
= "dahdi restart";
15881 "Usage: dahdi restart\n"
15882 " Restarts the DAHDI channels: destroys them all and then\n"
15883 " re-reads them from chan_dahdi.conf.\n"
15884 " Note that this will STOP any running CALL on DAHDI channels.\n"
15891 return CLI_SHOWUSAGE
;
15893 if (dahdi_restart() != 0)
15894 return CLI_FAILURE
;
15895 return CLI_SUCCESS
;
15898 static int action_dahdirestart(struct mansession
*s
, const struct message
*m
)
15900 if (dahdi_restart() != 0) {
15901 astman_send_error(s
, m
, "Failed rereading DAHDI configuration");
15904 astman_send_ack(s
, m
, "DAHDIRestart: Success");
15908 static char *dahdi_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15910 #define FORMAT "%7s %-15.15s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
15911 #define FORMAT2 "%7s %-15.15s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
15912 ast_group_t targetnum
= 0;
15913 int filtertype
= 0;
15914 struct dahdi_pvt
*tmp
= NULL
;
15920 e
->command
= "dahdi show channels [group|context]";
15922 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
15923 " Shows a list of available channels with optional filtering\n"
15924 " <group> must be a number between 0 and 63\n";
15930 /* syntax: dahdi show channels [ group <group> | context <context> ] */
15932 if (!((a
->argc
== 3) || (a
->argc
== 5))) {
15933 return CLI_SHOWUSAGE
;
15936 if (a
->argc
== 5) {
15937 if (!strcasecmp(a
->argv
[3], "group")) {
15938 targetnum
= atoi(a
->argv
[4]);
15939 if (63 < targetnum
) {
15940 return CLI_SHOWUSAGE
;
15942 targetnum
= ((ast_group_t
) 1) << targetnum
;
15944 } else if (!strcasecmp(a
->argv
[3], "context")) {
15949 ast_cli(a
->fd
, FORMAT2
, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Description");
15950 ast_mutex_lock(&iflock
);
15951 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
15953 switch(filtertype
) {
15954 case 1: /* dahdi show channels group <group> */
15955 if (!(tmp
->group
& targetnum
)) {
15959 case 2: /* dahdi show channels context <context> */
15960 if (strcasecmp(tmp
->context
, a
->argv
[4])) {
15968 if (tmp
->channel
> 0) {
15969 snprintf(tmps
, sizeof(tmps
), "%d", tmp
->channel
);
15971 ast_copy_string(tmps
, "pseudo", sizeof(tmps
));
15974 blockstr
[0] = tmp
->locallyblocked
? 'L' : ' ';
15975 blockstr
[1] = tmp
->remotelyblocked
? 'R' : ' ';
15976 blockstr
[2] = '\0';
15978 ast_cli(a
->fd
, FORMAT
, tmps
, tmp
->exten
, tmp
->context
, tmp
->language
, tmp
->mohinterpret
, blockstr
, tmp
->inservice
? "Yes" : "No", tmp
->description
);
15980 ast_mutex_unlock(&iflock
);
15981 return CLI_SUCCESS
;
15986 static char *dahdi_show_channel(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15989 struct dahdi_pvt
*tmp
= NULL
;
15990 struct dahdi_confinfo ci
;
15991 struct dahdi_params ps
;
15998 e
->command
= "dahdi show channel";
16000 "Usage: dahdi show channel <chan num>\n"
16001 " Detailed information about a given channel\n";
16008 return CLI_SHOWUSAGE
;
16010 channel
= atoi(a
->argv
[3]);
16012 ast_mutex_lock(&iflock
);
16013 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16014 if (tmp
->channel
== channel
) {
16015 ast_cli(a
->fd
, "Channel: %d\n", tmp
->channel
);
16016 ast_cli(a
->fd
, "Description: %s\n", tmp
->description
);
16017 ast_cli(a
->fd
, "File Descriptor: %d\n", tmp
->subs
[SUB_REAL
].dfd
);
16018 ast_cli(a
->fd
, "Span: %d\n", tmp
->span
);
16019 ast_cli(a
->fd
, "Extension: %s\n", tmp
->exten
);
16020 ast_cli(a
->fd
, "Dialing: %s\n", tmp
->dialing
? "yes" : "no");
16021 ast_cli(a
->fd
, "Context: %s\n", tmp
->context
);
16022 ast_cli(a
->fd
, "Caller ID: %s\n", tmp
->cid_num
);
16023 ast_cli(a
->fd
, "Calling TON: %d\n", tmp
->cid_ton
);
16024 #if defined(HAVE_PRI)
16025 #if defined(HAVE_PRI_SUBADDR)
16026 ast_cli(a
->fd
, "Caller ID subaddress: %s\n", tmp
->cid_subaddr
);
16027 #endif /* defined(HAVE_PRI_SUBADDR) */
16028 #endif /* defined(HAVE_PRI) */
16029 ast_cli(a
->fd
, "Caller ID name: %s\n", tmp
->cid_name
);
16030 ast_cli(a
->fd
, "Mailbox: %s\n", S_OR(tmp
->mailbox
, "none"));
16032 struct ast_variable
*v
;
16033 ast_cli(a
->fd
, "Variables:\n");
16034 for (v
= tmp
->vars
; v
; v
= v
->next
)
16035 ast_cli(a
->fd
, " %s = %s\n", v
->name
, v
->value
);
16037 ast_cli(a
->fd
, "Destroy: %d\n", tmp
->destroy
);
16038 ast_cli(a
->fd
, "InAlarm: %d\n", tmp
->inalarm
);
16039 ast_cli(a
->fd
, "Signalling Type: %s\n", sig2str(tmp
->sig
));
16040 ast_cli(a
->fd
, "Radio: %d\n", tmp
->radio
);
16041 ast_cli(a
->fd
, "Owner: %s\n", tmp
->owner
? ast_channel_name(tmp
->owner
) : "<None>");
16042 ast_cli(a
->fd
, "Real: %s%s%s\n", tmp
->subs
[SUB_REAL
].owner
? ast_channel_name(tmp
->subs
[SUB_REAL
].owner
) : "<None>", tmp
->subs
[SUB_REAL
].inthreeway
? " (Confed)" : "", tmp
->subs
[SUB_REAL
].linear
? " (Linear)" : "");
16043 ast_cli(a
->fd
, "Callwait: %s%s%s\n", tmp
->subs
[SUB_CALLWAIT
].owner
? ast_channel_name(tmp
->subs
[SUB_CALLWAIT
].owner
) : "<None>", tmp
->subs
[SUB_CALLWAIT
].inthreeway
? " (Confed)" : "", tmp
->subs
[SUB_CALLWAIT
].linear
? " (Linear)" : "");
16044 ast_cli(a
->fd
, "Threeway: %s%s%s\n", tmp
->subs
[SUB_THREEWAY
].owner
? ast_channel_name(tmp
->subs
[SUB_THREEWAY
].owner
) : "<None>", tmp
->subs
[SUB_THREEWAY
].inthreeway
? " (Confed)" : "", tmp
->subs
[SUB_THREEWAY
].linear
? " (Linear)" : "");
16045 ast_cli(a
->fd
, "Confno: %d\n", tmp
->confno
);
16046 ast_cli(a
->fd
, "Propagated Conference: %d\n", tmp
->propconfno
);
16047 ast_cli(a
->fd
, "Real in conference: %d\n", tmp
->inconference
);
16048 ast_cli(a
->fd
, "DSP: %s\n", tmp
->dsp
? "yes" : "no");
16049 ast_cli(a
->fd
, "Busy Detection: %s\n", tmp
->busydetect
? "yes" : "no");
16050 if (tmp
->busydetect
) {
16051 #if defined(BUSYDETECT_TONEONLY)
16052 ast_cli(a
->fd
, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16053 #elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16054 ast_cli(a
->fd
, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16056 #ifdef BUSYDETECT_DEBUG
16057 ast_cli(a
->fd
, " Busy Detector Debug: Enabled\n");
16059 ast_cli(a
->fd
, " Busy Count: %d\n", tmp
->busycount
);
16060 ast_cli(a
->fd
, " Busy Pattern: %d,%d,%d,%d\n", tmp
->busy_cadence
.pattern
[0], tmp
->busy_cadence
.pattern
[1], (tmp
->busy_cadence
.length
== 4) ? tmp
->busy_cadence
.pattern
[2] : 0, (tmp
->busy_cadence
.length
== 4) ? tmp
->busy_cadence
.pattern
[3] : 0);
16062 ast_cli(a
->fd
, "TDD: %s\n", tmp
->tdd
? "yes" : "no");
16063 ast_cli(a
->fd
, "Relax DTMF: %s\n", tmp
->dtmfrelax
? "yes" : "no");
16064 ast_cli(a
->fd
, "Dialing/CallwaitCAS: %d/%d\n", tmp
->dialing
, tmp
->callwaitcas
);
16065 ast_cli(a
->fd
, "Default law: %s\n", tmp
->law_default
== DAHDI_LAW_MULAW
? "ulaw" : tmp
->law_default
== DAHDI_LAW_ALAW
? "alaw" : "unknown");
16066 ast_cli(a
->fd
, "Fax Handled: %s\n", tmp
->faxhandled
? "yes" : "no");
16067 ast_cli(a
->fd
, "Pulse phone: %s\n", tmp
->pulsedial
? "yes" : "no");
16068 if (tmp
->hwrxgain_enabled
) {
16069 snprintf(hwrxgain
, sizeof(hwrxgain
), "%.1f", tmp
->hwrxgain
);
16071 ast_copy_string(hwrxgain
, "Disabled", sizeof(hwrxgain
));
16073 if (tmp
->hwtxgain_enabled
) {
16074 snprintf(hwtxgain
, sizeof(hwtxgain
), "%.1f", tmp
->hwtxgain
);
16076 ast_copy_string(hwtxgain
, "Disabled", sizeof(hwtxgain
));
16078 ast_cli(a
->fd
, "HW Gains (RX/TX): %s/%s\n", hwrxgain
, hwtxgain
);
16079 ast_cli(a
->fd
, "SW Gains (RX/TX): %.2f/%.2f\n", tmp
->rxgain
, tmp
->txgain
);
16080 ast_cli(a
->fd
, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp
->rxdrc
, tmp
->txdrc
);
16081 ast_cli(a
->fd
, "DND: %s\n", dahdi_dnd(tmp
, -1) ? "yes" : "no");
16082 ast_cli(a
->fd
, "Echo Cancellation:\n");
16084 if (tmp
->echocancel
.head
.tap_length
) {
16085 ast_cli(a
->fd
, "\t%u taps\n", tmp
->echocancel
.head
.tap_length
);
16086 for (x
= 0; x
< tmp
->echocancel
.head
.param_count
; x
++) {
16087 ast_cli(a
->fd
, "\t\t%s: %dd\n", tmp
->echocancel
.params
[x
].name
, tmp
->echocancel
.params
[x
].value
);
16089 ast_cli(a
->fd
, "\t%scurrently %s\n", tmp
->echocanbridged
? "" : "(unless TDM bridged) ", tmp
->echocanon
? "ON" : "OFF");
16091 ast_cli(a
->fd
, "\tnone\n");
16093 ast_cli(a
->fd
, "Wait for dialtone: %dms\n", tmp
->waitfordialtone
);
16095 ast_cli(a
->fd
, "Master Channel: %d\n", tmp
->master
->channel
);
16096 for (x
= 0; x
< MAX_SLAVES
; x
++) {
16097 if (tmp
->slaves
[x
])
16098 ast_cli(a
->fd
, "Slave Channel: %d\n", tmp
->slaves
[x
]->channel
);
16102 char calldir
[OR2_MAX_PATH
];
16103 openr2_context_t
*r2context
= openr2_chan_get_context(tmp
->r2chan
);
16104 openr2_variant_t r2variant
= openr2_context_get_variant(r2context
);
16105 ast_cli(a
->fd
, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp
->r2chan
));
16106 ast_cli(a
->fd
, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp
->r2chan
));
16107 ast_cli(a
->fd
, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp
->r2chan
));
16108 ast_cli(a
->fd
, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp
->r2chan
));
16109 ast_cli(a
->fd
, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp
->r2chan
) ? "Yes" : "No");
16110 ast_cli(a
->fd
, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant
));
16111 ast_cli(a
->fd
, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context
));
16112 ast_cli(a
->fd
, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context
));
16113 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16114 ast_cli(a
->fd
, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context
, NULL
, NULL
) ? "Yes" : "No");
16115 ast_cli(a
->fd
, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context
) ? "Yes" : "No");
16117 ast_cli(a
->fd
, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context
) ? "Yes" : "No");
16118 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16119 ast_cli(a
->fd
, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context
) ? "Yes" : "No");
16121 ast_cli(a
->fd
, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context
) ? "Yes" : "No");
16122 ast_cli(a
->fd
, "MFC/R2 Accept on Offer: %s\n", tmp
->mfcr2_accept_on_offer
? "Yes" : "No");
16123 ast_cli(a
->fd
, "MFC/R2 Charge Calls: %s\n", tmp
->mfcr2_charge_calls
? "Yes" : "No");
16124 ast_cli(a
->fd
, "MFC/R2 Allow Collect Calls: %s\n", tmp
->mfcr2_allow_collect_calls
? "Yes" : "No");
16125 ast_cli(a
->fd
, "MFC/R2 Forced Release: %s\n", tmp
->mfcr2_forced_release
? "Yes" : "No");
16126 ast_cli(a
->fd
, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context
));
16127 ast_cli(a
->fd
, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context
));
16128 ast_cli(a
->fd
, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp
->r2chan
));
16129 ast_cli(a
->fd
, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp
->r2chan
));
16130 ast_cli(a
->fd
, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp
->r2chan
));
16131 ast_cli(a
->fd
, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp
->r2chan
));
16132 ast_cli(a
->fd
, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context
, calldir
, sizeof(calldir
)));
16135 #if defined(HAVE_SS7)
16137 struct sig_ss7_chan
*chan
= tmp
->sig_pvt
;
16139 ast_cli(a
->fd
, "CIC: %d\n", chan
->cic
);
16141 #endif /* defined(HAVE_SS7) */
16144 struct sig_pri_chan
*chan
= tmp
->sig_pvt
;
16146 ast_cli(a
->fd
, "PRI Flags: ");
16147 if (chan
->resetting
!= SIG_PRI_RESET_IDLE
) {
16148 ast_cli(a
->fd
, "Resetting=%u ", chan
->resetting
);
16151 ast_cli(a
->fd
, "Call ");
16152 if (chan
->allocated
) {
16153 ast_cli(a
->fd
, "Allocated ");
16155 ast_cli(a
->fd
, "\n");
16156 if (tmp
->logicalspan
)
16157 ast_cli(a
->fd
, "PRI Logical Span: %d\n", tmp
->logicalspan
);
16159 ast_cli(a
->fd
, "PRI Logical Span: Implicit\n");
16162 memset(&ci
, 0, sizeof(ci
));
16163 ps
.channo
= tmp
->channel
;
16164 if (tmp
->subs
[SUB_REAL
].dfd
> -1) {
16165 memset(&ci
, 0, sizeof(ci
));
16166 if (!ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONF
, &ci
)) {
16167 ast_cli(a
->fd
, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci
.confno
, (unsigned)ci
.confmode
);
16169 if (!ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONFMUTE
, &x
)) {
16170 ast_cli(a
->fd
, "Actual Confmute: %s\n", x
? "Yes" : "No");
16172 memset(&ps
, 0, sizeof(ps
));
16173 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &ps
) < 0) {
16174 ast_log(LOG_WARNING
, "Failed to get parameters on channel %d: %s\n", tmp
->channel
, strerror(errno
));
16176 ast_cli(a
->fd
, "Hookstate (FXS only): %s\n", ps
.rxisoffhook
? "Offhook" : "Onhook");
16179 ast_mutex_unlock(&iflock
);
16180 return CLI_SUCCESS
;
16183 ast_mutex_unlock(&iflock
);
16185 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16186 return CLI_FAILURE
;
16189 static char *handle_dahdi_show_cadences(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16194 e
->command
= "dahdi show cadences";
16196 "Usage: dahdi show cadences\n"
16197 " Shows all cadences currently defined\n";
16202 for (i
= 0; i
< num_cadence
; i
++) {
16204 char tmp
[16], tmp2
[64];
16205 snprintf(tmp
, sizeof(tmp
), "r%d: ", i
+ 1);
16206 term_color(output
, tmp
, COLOR_GREEN
, COLOR_BLACK
, sizeof(output
));
16208 for (j
= 0; j
< 16; j
++) {
16209 if (cadences
[i
].ringcadence
[j
] == 0)
16211 snprintf(tmp
, sizeof(tmp
), "%d", cadences
[i
].ringcadence
[j
]);
16212 if (cidrings
[i
] * 2 - 1 == j
)
16213 term_color(tmp2
, tmp
, COLOR_MAGENTA
, COLOR_BLACK
, sizeof(tmp2
) - 1);
16215 term_color(tmp2
, tmp
, COLOR_GREEN
, COLOR_BLACK
, sizeof(tmp2
) - 1);
16217 strncat(output
, ",", sizeof(output
) - strlen(output
) - 1);
16218 strncat(output
, tmp2
, sizeof(output
) - strlen(output
) - 1);
16220 ast_cli(a
->fd
,"%s\n",output
);
16222 return CLI_SUCCESS
;
16225 /* Based on irqmiss.c */
16226 static char *dahdi_show_status(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16228 #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16229 #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16235 struct dahdi_spaninfo s
;
16239 e
->command
= "dahdi show status";
16241 "Usage: dahdi show status\n"
16242 " Shows a list of DAHDI cards with status\n";
16247 ctl
= open("/dev/dahdi/ctl", O_RDWR
);
16249 ast_cli(a
->fd
, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno
));
16250 return CLI_FAILURE
;
16252 ast_cli(a
->fd
, FORMAT2
, "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16254 for (span
= 1; span
< DAHDI_MAX_SPANS
; ++span
) {
16256 res
= ioctl(ctl
, DAHDI_SPANSTAT
, &s
);
16260 alarmstr
[0] = '\0';
16261 if (s
.alarms
> 0) {
16262 if (s
.alarms
& DAHDI_ALARM_BLUE
)
16263 strcat(alarmstr
, "BLU/");
16264 if (s
.alarms
& DAHDI_ALARM_YELLOW
)
16265 strcat(alarmstr
, "YEL/");
16266 if (s
.alarms
& DAHDI_ALARM_RED
)
16267 strcat(alarmstr
, "RED/");
16268 if (s
.alarms
& DAHDI_ALARM_LOOPBACK
)
16269 strcat(alarmstr
, "LB/");
16270 if (s
.alarms
& DAHDI_ALARM_RECOVER
)
16271 strcat(alarmstr
, "REC/");
16272 if (s
.alarms
& DAHDI_ALARM_NOTOPEN
)
16273 strcat(alarmstr
, "NOP/");
16274 if (!strlen(alarmstr
))
16275 strcat(alarmstr
, "UUU/");
16276 if (strlen(alarmstr
)) {
16277 /* Strip trailing / */
16278 alarmstr
[strlen(alarmstr
) - 1] = '\0';
16282 strcpy(alarmstr
, "OK");
16284 strcpy(alarmstr
, "UNCONFIGURED");
16287 ast_cli(a
->fd
, FORMAT
, s
.desc
, alarmstr
, s
.irqmisses
, s
.bpvcount
, s
.crc4count
,
16288 s
.lineconfig
& DAHDI_CONFIG_D4
? "D4" :
16289 s
.lineconfig
& DAHDI_CONFIG_ESF
? "ESF" :
16290 s
.lineconfig
& DAHDI_CONFIG_CCS
? "CCS" :
16292 s
.lineconfig
& DAHDI_CONFIG_B8ZS
? "B8ZS" :
16293 s
.lineconfig
& DAHDI_CONFIG_HDB3
? "HDB3" :
16294 s
.lineconfig
& DAHDI_CONFIG_AMI
? "AMI" :
16296 s
.lineconfig
& DAHDI_CONFIG_CRC4
?
16297 s
.lineconfig
& DAHDI_CONFIG_NOTOPEN
? "CRC4/YEL" : "CRC4" :
16298 s
.lineconfig
& DAHDI_CONFIG_NOTOPEN
? "YEL" : "",
16304 return CLI_SUCCESS
;
16309 static char *dahdi_show_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16311 int pseudo_fd
= -1;
16312 struct dahdi_versioninfo vi
;
16316 e
->command
= "dahdi show version";
16318 "Usage: dahdi show version\n"
16319 " Shows the DAHDI version in use\n";
16324 if ((pseudo_fd
= open("/dev/dahdi/ctl", O_RDONLY
)) < 0) {
16325 ast_cli(a
->fd
, "Failed to open control file to get version.\n");
16326 return CLI_SUCCESS
;
16329 strcpy(vi
.version
, "Unknown");
16330 strcpy(vi
.echo_canceller
, "Unknown");
16332 if (ioctl(pseudo_fd
, DAHDI_GETVERSION
, &vi
))
16333 ast_cli(a
->fd
, "Failed to get DAHDI version: %s\n", strerror(errno
));
16335 ast_cli(a
->fd
, "DAHDI Version: %s Echo Canceller: %s\n", vi
.version
, vi
.echo_canceller
);
16339 return CLI_SUCCESS
;
16342 static char *dahdi_set_hwgain(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16347 struct dahdi_pvt
*tmp
= NULL
;
16351 e
->command
= "dahdi set hwgain {rx|tx}";
16353 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16354 " Sets the hardware gain on a given channel and overrides the\n"
16355 " value provided at module loadtime. Changes take effect\n"
16356 " immediately whether the channel is in use or not.\n"
16358 " <rx|tx> which direction do you want to change (relative to our module)\n"
16359 " <chan num> is the channel number relative to the device\n"
16360 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16363 " * hwgain is only supportable by hardware with analog ports because\n"
16364 " hwgain works on the analog side of an analog-digital conversion.\n";
16371 return CLI_SHOWUSAGE
;
16373 if (!strcasecmp("rx", a
->argv
[3]))
16375 else if (!strcasecmp("tx", a
->argv
[3]))
16378 return CLI_SHOWUSAGE
;
16380 channel
= atoi(a
->argv
[4]);
16381 gain
= atof(a
->argv
[5]);
16383 ast_mutex_lock(&iflock
);
16385 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16387 if (tmp
->channel
!= channel
)
16390 if (tmp
->subs
[SUB_REAL
].dfd
== -1)
16393 if (set_hwgain(tmp
->subs
[SUB_REAL
].dfd
, gain
, tx
)) {
16394 ast_cli(a
->fd
, "Unable to set the hardware gain for channel %d: %s\n", channel
, strerror(errno
));
16395 ast_mutex_unlock(&iflock
);
16396 return CLI_FAILURE
;
16398 ast_cli(a
->fd
, "Hardware %s gain set to %.1f dB on channel %d.\n",
16399 tx
? "tx" : "rx", gain
, channel
);
16402 tmp
->hwtxgain_enabled
= 1;
16403 tmp
->hwtxgain
= gain
;
16405 tmp
->hwrxgain_enabled
= 1;
16406 tmp
->hwrxgain
= gain
;
16411 ast_mutex_unlock(&iflock
);
16414 return CLI_SUCCESS
;
16416 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16417 return CLI_FAILURE
;
16421 static char *dahdi_set_swgain(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16427 struct dahdi_pvt
*tmp
= NULL
;
16431 e
->command
= "dahdi set swgain {rx|tx}";
16433 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16434 " Sets the software gain on a given channel and overrides the\n"
16435 " value provided at module loadtime. Changes take effect\n"
16436 " immediately whether the channel is in use or not.\n"
16438 " <rx|tx> which direction do you want to change (relative to our module)\n"
16439 " <chan num> is the channel number relative to the device\n"
16440 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16447 return CLI_SHOWUSAGE
;
16449 if (!strcasecmp("rx", a
->argv
[3]))
16451 else if (!strcasecmp("tx", a
->argv
[3]))
16454 return CLI_SHOWUSAGE
;
16456 channel
= atoi(a
->argv
[4]);
16457 gain
= atof(a
->argv
[5]);
16459 ast_mutex_lock(&iflock
);
16460 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16462 if (tmp
->channel
!= channel
)
16465 if (tmp
->subs
[SUB_REAL
].dfd
== -1)
16469 res
= set_actual_txgain(tmp
->subs
[SUB_REAL
].dfd
, gain
, tmp
->txdrc
, tmp
->law
);
16471 res
= set_actual_rxgain(tmp
->subs
[SUB_REAL
].dfd
, gain
, tmp
->rxdrc
, tmp
->law
);
16474 ast_cli(a
->fd
, "Unable to set the software gain for channel %d\n", channel
);
16475 ast_mutex_unlock(&iflock
);
16476 return CLI_FAILURE
;
16479 ast_cli(a
->fd
, "Software %s gain set to %.2f dB on channel %d.\n",
16480 tx
? "tx" : "rx", gain
, channel
);
16483 tmp
->txgain
= gain
;
16485 tmp
->rxgain
= gain
;
16489 ast_mutex_unlock(&iflock
);
16492 return CLI_SUCCESS
;
16494 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16495 return CLI_FAILURE
;
16499 static char *dahdi_set_dnd(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16503 struct dahdi_pvt
*dahdi_chan
= NULL
;
16507 e
->command
= "dahdi set dnd";
16509 "Usage: dahdi set dnd <chan#> <on|off>\n"
16510 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16511 " Changes take effect immediately.\n"
16512 " <chan num> is the channel number\n"
16513 " <on|off> Enable or disable DND mode?\n"
16521 return CLI_SHOWUSAGE
;
16523 if ((channel
= atoi(a
->argv
[3])) <= 0) {
16524 ast_cli(a
->fd
, "Expected channel number, got '%s'\n", a
->argv
[3]);
16525 return CLI_SHOWUSAGE
;
16528 if (ast_true(a
->argv
[4]))
16530 else if (ast_false(a
->argv
[4]))
16533 ast_cli(a
->fd
, "Expected 'on' or 'off', got '%s'\n", a
->argv
[4]);
16534 return CLI_SHOWUSAGE
;
16537 ast_mutex_lock(&iflock
);
16538 for (dahdi_chan
= iflist
; dahdi_chan
; dahdi_chan
= dahdi_chan
->next
) {
16539 if (dahdi_chan
->channel
!= channel
)
16542 /* Found the channel. Actually set it */
16543 dahdi_dnd(dahdi_chan
, on
);
16546 ast_mutex_unlock(&iflock
);
16549 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16550 return CLI_FAILURE
;
16553 return CLI_SUCCESS
;
16556 static char *dahdi_set_mwi(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16561 struct dahdi_pvt
*dahdi_chan
= NULL
;
16565 e
->command
= "dahdi set mwi";
16567 "Usage: dahdi set mwi <chan#> <on|off|reset>\n"
16568 " Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
16569 " This may be used regardless of whether the channel is assigned any mailboxes.\n"
16570 " When active, this setting will override the voicemail status to set MWI.\n"
16571 " Once cleared, the voicemail status will resume control of MWI.\n"
16572 " Changes are queued for when the channel is idle and persist until cleared.\n"
16573 " <chan num> is the channel number\n"
16574 " <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
16582 return CLI_SHOWUSAGE
;
16584 if ((channel
= atoi(a
->argv
[3])) <= 0) {
16585 ast_cli(a
->fd
, "Expected channel number, got '%s'\n", a
->argv
[3]);
16586 return CLI_SHOWUSAGE
;
16589 if (ast_true(a
->argv
[4])) {
16591 } else if (ast_false(a
->argv
[4])) {
16593 } else if (!strcmp(a
->argv
[4], "reset")) {
16596 ast_cli(a
->fd
, "Expected 'on' or 'off' or 'reset', got '%s'\n", a
->argv
[4]);
16597 return CLI_SHOWUSAGE
;
16600 ast_mutex_lock(&iflock
);
16601 for (dahdi_chan
= iflist
; dahdi_chan
; dahdi_chan
= dahdi_chan
->next
) {
16602 if (dahdi_chan
->channel
!= channel
)
16605 /* Found the channel. Actually set it */
16607 dahdi_chan
->mwioverride_disposition
= on
;
16608 ast_cli(a
->fd
, "MWI '%s' queued for channel %d\n", on
? "enable" : "disable", channel
);
16610 dahdi_chan
->mwioverride_active
= override
;
16611 /* The do_monitor thread will take care of actually sending the MWI
16612 * at an appropriate time for the channel. */
16615 ast_mutex_unlock(&iflock
);
16618 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16619 return CLI_FAILURE
;
16622 return CLI_SUCCESS
;
16625 static struct ast_cli_entry dahdi_cli
[] = {
16626 AST_CLI_DEFINE(handle_dahdi_show_cadences
, "List cadences"),
16627 AST_CLI_DEFINE(dahdi_show_channels
, "Show active DAHDI channels"),
16628 AST_CLI_DEFINE(dahdi_show_channel
, "Show information on a channel"),
16629 AST_CLI_DEFINE(dahdi_destroy_channels
, "Destroy channels"),
16630 AST_CLI_DEFINE(dahdi_create_channels
, "Create channels"),
16631 AST_CLI_DEFINE(dahdi_restart_cmd
, "Fully restart DAHDI channels"),
16632 AST_CLI_DEFINE(dahdi_show_status
, "Show all DAHDI cards status"),
16633 AST_CLI_DEFINE(dahdi_show_version
, "Show the DAHDI version in use"),
16634 AST_CLI_DEFINE(dahdi_set_hwgain
, "Set hardware gain on a channel"),
16635 AST_CLI_DEFINE(dahdi_set_swgain
, "Set software gain on a channel"),
16636 AST_CLI_DEFINE(dahdi_set_dnd
, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16637 AST_CLI_DEFINE(dahdi_set_mwi
, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
16643 static int dahdi_fake_event(struct dahdi_pvt
*p
, int mode
)
16648 p
->fake_event
= DAHDI_EVENT_WINKFLASH
;
16651 p
->fake_event
= DAHDI_EVENT_ONHOOK
;
16654 ast_log(LOG_WARNING
, "I don't know how to handle transfer event with this: %d on channel %s\n",mode
, ast_channel_name(p
->owner
));
16659 static struct dahdi_pvt
*find_channel(int channel
)
16661 struct dahdi_pvt
*p
;
16663 ast_mutex_lock(&iflock
);
16664 for (p
= iflist
; p
; p
= p
->next
) {
16665 if (p
->channel
== channel
) {
16669 ast_mutex_unlock(&iflock
);
16675 * \brief Get private struct using given numeric channel string.
16677 * \param channel Numeric channel number string get private struct.
16679 * \retval pvt on success.
16680 * \retval NULL on error.
16682 static struct dahdi_pvt
*find_channel_from_str(const char *channel
)
16686 if (sscanf(channel
, "%30d", &chan_num
) != 1) {
16687 /* Not numeric string. */
16691 return find_channel(chan_num
);
16694 static int action_dahdidndon(struct mansession
*s
, const struct message
*m
)
16696 struct dahdi_pvt
*p
;
16697 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16699 if (ast_strlen_zero(channel
)) {
16700 astman_send_error(s
, m
, "No channel specified");
16703 p
= find_channel_from_str(channel
);
16705 astman_send_error(s
, m
, "No such channel");
16709 astman_send_ack(s
, m
, "DND Enabled");
16713 static int action_dahdidndoff(struct mansession
*s
, const struct message
*m
)
16715 struct dahdi_pvt
*p
;
16716 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16718 if (ast_strlen_zero(channel
)) {
16719 astman_send_error(s
, m
, "No channel specified");
16722 p
= find_channel_from_str(channel
);
16724 astman_send_error(s
, m
, "No such channel");
16728 astman_send_ack(s
, m
, "DND Disabled");
16732 static int action_transfer(struct mansession
*s
, const struct message
*m
)
16734 struct dahdi_pvt
*p
;
16735 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16737 if (ast_strlen_zero(channel
)) {
16738 astman_send_error(s
, m
, "No channel specified");
16741 p
= find_channel_from_str(channel
);
16743 astman_send_error(s
, m
, "No such channel");
16746 if (!dahdi_analog_lib_handles(p
->sig
, 0, 0)) {
16747 astman_send_error(s
, m
, "Channel signaling is not analog");
16750 dahdi_fake_event(p
,TRANSFER
);
16751 astman_send_ack(s
, m
, "DAHDITransfer");
16755 static int action_transferhangup(struct mansession
*s
, const struct message
*m
)
16757 struct dahdi_pvt
*p
;
16758 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16760 if (ast_strlen_zero(channel
)) {
16761 astman_send_error(s
, m
, "No channel specified");
16764 p
= find_channel_from_str(channel
);
16766 astman_send_error(s
, m
, "No such channel");
16769 if (!dahdi_analog_lib_handles(p
->sig
, 0, 0)) {
16770 astman_send_error(s
, m
, "Channel signaling is not analog");
16773 dahdi_fake_event(p
,HANGUP
);
16774 astman_send_ack(s
, m
, "DAHDIHangup");
16778 static int action_dahdidialoffhook(struct mansession
*s
, const struct message
*m
)
16780 struct dahdi_pvt
*p
;
16781 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16782 const char *number
= astman_get_header(m
, "Number");
16785 if (ast_strlen_zero(channel
)) {
16786 astman_send_error(s
, m
, "No channel specified");
16789 if (ast_strlen_zero(number
)) {
16790 astman_send_error(s
, m
, "No number specified");
16793 p
= find_channel_from_str(channel
);
16795 astman_send_error(s
, m
, "No such channel");
16799 astman_send_error(s
, m
, "Channel does not have it's owner");
16802 for (i
= 0; i
< strlen(number
); i
++) {
16803 struct ast_frame f
= { AST_FRAME_DTMF
, .subclass
.integer
= number
[i
] };
16804 dahdi_queue_frame(p
, &f
);
16806 astman_send_ack(s
, m
, "DAHDIDialOffhook");
16810 static int action_dahdishowchannels(struct mansession
*s
, const struct message
*m
)
16812 struct dahdi_pvt
*tmp
= NULL
;
16813 const char *id
= astman_get_header(m
, "ActionID");
16814 const char *dahdichannel
= astman_get_header(m
, "DAHDIChannel");
16817 int dahdichanquery
;
16819 if (!dahdichannel
|| sscanf(dahdichannel
, "%30d", &dahdichanquery
) != 1) {
16820 /* Not numeric string. */
16821 dahdichanquery
= -1;
16825 if (!ast_strlen_zero(id
)) {
16826 snprintf(idText
, sizeof(idText
), "ActionID: %s\r\n", id
);
16829 astman_send_listack(s
, m
, "DAHDI channel status will follow", "start");
16831 ast_mutex_lock(&iflock
);
16833 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16834 if (tmp
->channel
> 0) {
16837 /* If a specific channel is queried for, only deliver status for that channel */
16838 if (dahdichanquery
> 0 && tmp
->channel
!= dahdichanquery
)
16841 alm
= get_alarms(tmp
);
16844 /* Add data if we have a current call */
16846 "Event: DAHDIShowChannels\r\n"
16847 "DAHDIChannel: %d\r\n"
16850 "AccountCode: %s\r\n"
16851 "Signalling: %s\r\n"
16852 "SignallingCode: %d\r\n"
16856 "Description: %s\r\n"
16860 ast_channel_name(tmp
->owner
),
16861 ast_channel_uniqueid(tmp
->owner
),
16862 ast_channel_accountcode(tmp
->owner
),
16866 dahdi_dnd(tmp
, -1) ? "Enabled" : "Disabled",
16868 tmp
->description
, idText
);
16871 "Event: DAHDIShowChannels\r\n"
16872 "DAHDIChannel: %d\r\n"
16873 "Signalling: %s\r\n"
16874 "SignallingCode: %d\r\n"
16878 "Description: %s\r\n"
16881 tmp
->channel
, sig2str(tmp
->sig
), tmp
->sig
,
16883 dahdi_dnd(tmp
, -1) ? "Enabled" : "Disabled",
16885 tmp
->description
, idText
);
16890 ast_mutex_unlock(&iflock
);
16892 astman_send_list_complete_start(s
, m
, "DAHDIShowChannelsComplete", channels
);
16893 astman_append(s
, "Items: %d\r\n", channels
);
16894 astman_send_list_complete_end(s
);
16898 #if defined(HAVE_PRI)
16899 static int action_prishowspans(struct mansession
*s
, const struct message
*m
)
16904 struct dahdi_pri
*dspan
;
16905 const char *id
= astman_get_header(m
, "ActionID");
16906 const char *span_str
= astman_get_header(m
, "Span");
16907 char action_id
[256];
16908 const char *show_cmd
= "PRIShowSpans";
16910 /* NOTE: Asking for span 0 gets all spans. */
16911 if (!ast_strlen_zero(span_str
)) {
16912 span_query
= atoi(span_str
);
16917 if (!ast_strlen_zero(id
)) {
16918 snprintf(action_id
, sizeof(action_id
), "ActionID: %s\r\n", id
);
16920 action_id
[0] = '\0';
16923 astman_send_listack(s
, m
, "Span status will follow", "start");
16926 for (idx
= 0; idx
< ARRAY_LEN(pris
); ++idx
) {
16927 dspan
= &pris
[idx
];
16929 /* If a specific span is asked for, only deliver status for that span. */
16930 if (0 < span_query
&& dspan
->pri
.span
!= span_query
) {
16934 if (dspan
->pri
.pri
) {
16935 count
+= sig_pri_ami_show_spans(s
, show_cmd
, &dspan
->pri
, dspan
->dchannels
,
16940 astman_send_list_complete_start(s
, m
, "PRIShowSpansComplete", count
);
16941 astman_append(s
, "Items: %d\r\n", count
);
16942 astman_send_list_complete_end(s
);
16945 #endif /* defined(HAVE_PRI) */
16947 #if defined(HAVE_SS7)
16948 static int linkset_addsigchan(int sigchan
)
16950 struct dahdi_ss7
*link
;
16953 struct dahdi_params params
;
16954 struct dahdi_bufferinfo bi
;
16955 struct dahdi_spaninfo si
;
16958 ast_log(LOG_ERROR
, "Invalid sigchan!\n");
16961 if (cur_ss7type
< 0) {
16962 ast_log(LOG_ERROR
, "Unspecified or invalid ss7type\n");
16965 if (cur_pointcode
< 0) {
16966 ast_log(LOG_ERROR
, "Unspecified pointcode!\n");
16969 if (cur_adjpointcode
< 0) {
16970 ast_log(LOG_ERROR
, "Unspecified adjpointcode!\n");
16973 if (cur_defaultdpc
< 0) {
16974 ast_log(LOG_ERROR
, "Unspecified defaultdpc!\n");
16977 if (cur_networkindicator
< 0) {
16978 ast_log(LOG_ERROR
, "Invalid networkindicator!\n");
16981 link
= ss7_resolve_linkset(cur_linkset
);
16983 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
16986 if (link
->ss7
.numsigchans
>= SIG_SS7_NUM_DCHANS
) {
16987 ast_log(LOG_ERROR
, "Too many sigchans on linkset %d\n", cur_linkset
);
16991 curfd
= link
->ss7
.numsigchans
;
16993 /* Open signaling channel */
16994 link
->ss7
.fds
[curfd
] = open("/dev/dahdi/channel", O_RDWR
, 0600);
16995 if (link
->ss7
.fds
[curfd
] < 0) {
16996 ast_log(LOG_ERROR
, "Unable to open SS7 sigchan %d (%s)\n", sigchan
,
17000 if (ioctl(link
->ss7
.fds
[curfd
], DAHDI_SPECIFY
, &sigchan
) == -1) {
17001 dahdi_close_ss7_fd(link
, curfd
);
17002 ast_log(LOG_ERROR
, "Unable to specify SS7 sigchan %d (%s)\n", sigchan
,
17007 /* Get signaling channel parameters */
17008 memset(¶ms
, 0, sizeof(params
));
17009 res
= ioctl(link
->ss7
.fds
[curfd
], DAHDI_GET_PARAMS
, ¶ms
);
17011 dahdi_close_ss7_fd(link
, curfd
);
17012 ast_log(LOG_ERROR
, "Unable to get parameters for sigchan %d (%s)\n", sigchan
,
17016 if (params
.sigtype
!= DAHDI_SIG_HDLCFCS
17017 && params
.sigtype
!= DAHDI_SIG_HARDHDLC
17018 && params
.sigtype
!= DAHDI_SIG_MTP2
) {
17019 dahdi_close_ss7_fd(link
, curfd
);
17020 ast_log(LOG_ERROR
, "sigchan %d is not in HDLC/FCS mode.\n", sigchan
);
17024 /* Set signaling channel buffer policy. */
17025 memset(&bi
, 0, sizeof(bi
));
17026 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
17027 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
17030 if (ioctl(link
->ss7
.fds
[curfd
], DAHDI_SET_BUFINFO
, &bi
)) {
17031 ast_log(LOG_ERROR
, "Unable to set appropriate buffering on channel %d: %s\n",
17032 sigchan
, strerror(errno
));
17033 dahdi_close_ss7_fd(link
, curfd
);
17037 /* Get current signaling channel alarm status. */
17038 memset(&si
, 0, sizeof(si
));
17039 res
= ioctl(link
->ss7
.fds
[curfd
], DAHDI_SPANSTAT
, &si
);
17041 dahdi_close_ss7_fd(link
, curfd
);
17042 ast_log(LOG_ERROR
, "Unable to get span state for sigchan %d (%s)\n", sigchan
,
17046 res
= sig_ss7_add_sigchan(&link
->ss7
, curfd
, cur_ss7type
,
17047 (params
.sigtype
== DAHDI_SIG_MTP2
)
17048 ? SS7_TRANSPORT_DAHDIMTP2
17049 : SS7_TRANSPORT_DAHDIDCHAN
,
17050 si
.alarms
, cur_networkindicator
, cur_pointcode
, cur_adjpointcode
, cur_slc
);
17052 dahdi_close_ss7_fd(link
, curfd
);
17056 ++link
->ss7
.numsigchans
;
17060 #endif /* defined(HAVE_SS7) */
17062 #if defined(HAVE_SS7)
17063 static char *handle_ss7_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17068 e
->command
= "ss7 set debug {on|off} linkset";
17070 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
17071 " Enables debugging on a given SS7 linkset\n";
17078 return CLI_SHOWUSAGE
;
17081 span
= atoi(a
->argv
[5]);
17082 if ((span
< 1) || (span
> NUM_SPANS
)) {
17083 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number from %d to %d\n", a
->argv
[5], 1, NUM_SPANS
);
17084 return CLI_SUCCESS
;
17086 if (!linksets
[span
-1].ss7
.ss7
) {
17087 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", span
);
17089 if (!strcasecmp(a
->argv
[3], "on")) {
17090 linksets
[span
- 1].ss7
.debug
= 1;
17091 ss7_set_debug(linksets
[span
-1].ss7
.ss7
, SIG_SS7_DEBUG
);
17092 ast_cli(a
->fd
, "Enabled debugging on linkset %d\n", span
);
17094 linksets
[span
- 1].ss7
.debug
= 0;
17095 ss7_set_debug(linksets
[span
-1].ss7
.ss7
, 0);
17096 ast_cli(a
->fd
, "Disabled debugging on linkset %d\n", span
);
17100 return CLI_SUCCESS
;
17102 #endif /* defined(HAVE_SS7) */
17104 #if defined(HAVE_SS7)
17105 static char *handle_ss7_cic_blocking(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17114 e
->command
= "ss7 {block|unblock} cic";
17116 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17117 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17123 if (a
->argc
== 6) {
17124 linkset
= atoi(a
->argv
[3]);
17126 return CLI_SHOWUSAGE
;
17129 if (!strcasecmp(a
->argv
[1], "block")) {
17131 } else if (strcasecmp(a
->argv
[1], "unblock")) {
17132 return CLI_SHOWUSAGE
;
17135 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17136 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17137 return CLI_SUCCESS
;
17140 if (!linksets
[linkset
-1].ss7
.ss7
) {
17141 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17142 return CLI_SUCCESS
;
17145 cic
= atoi(a
->argv
[5]);
17147 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17148 return CLI_SUCCESS
;
17151 dpc
= atoi(a
->argv
[4]);
17153 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17154 return CLI_SUCCESS
;
17157 for (i
= 0; i
< linksets
[linkset
-1].ss7
.numchans
; i
++) {
17158 if (linksets
[linkset
-1].ss7
.pvts
[i
] && linksets
[linkset
-1].ss7
.pvts
[i
]->cic
== cic
&& linksets
[linkset
-1].ss7
.pvts
[i
]->dpc
== dpc
) {
17159 blocked
= linksets
[linkset
-1].ss7
.pvts
[i
]->locallyblocked
;
17160 if (!do_block
^ !(blocked
& SS7_BLOCKED_MAINTENANCE
)) {
17161 if (sig_ss7_cic_blocking(&linksets
[linkset
-1].ss7
, do_block
, i
) < 0) {
17162 ast_cli(a
->fd
, "Unable to allocate new ss7call\n");
17164 ast_cli(a
->fd
, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block
) ? "" : "un", linkset
, cic
, dpc
);
17166 } else if (!do_block
&& blocked
) {
17167 ast_cli(a
->fd
, "CIC %d is hardware locally blocked!\n", cic
);
17169 ast_cli(a
->fd
, "CIC %d %s locally blocked\n", cic
, do_block
? "already" : "is not");
17171 return CLI_SUCCESS
;
17175 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17176 return CLI_SUCCESS
;
17178 #endif /* defined(HAVE_SS7) */
17180 #if defined(HAVE_SS7)
17181 static char *handle_ss7_linkset_mng(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17192 e
->command
= "ss7 {reset|block|unblock} linkset";
17194 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17195 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17201 if (a
->argc
== 4) {
17202 linkset
= atoi(a
->argv
[3]);
17204 return CLI_SHOWUSAGE
;
17207 if (!strcasecmp(a
->argv
[1], "block")) {
17208 do_what
= DO_BLOCK
;
17209 } else if (!strcasecmp(a
->argv
[1], "unblock")) {
17210 do_what
= DO_UNBLOCK
;
17211 } else if (!strcasecmp(a
->argv
[1], "reset")) {
17212 do_what
= DO_RESET
;
17214 return CLI_SHOWUSAGE
;
17217 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17218 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17219 return CLI_SUCCESS
;
17222 if (!linksets
[linkset
- 1].ss7
.ss7
) {
17223 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17224 return CLI_SUCCESS
;
17227 for (i
= 0; i
< linksets
[linkset
- 1].ss7
.numchans
; i
++) {
17228 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17229 if (linksets
[linkset
- 1].ss7
.pvts
[i
]) {
17233 if (sig_ss7_cic_blocking(&linksets
[linkset
- 1].ss7
, do_what
== DO_BLOCK
, i
)) {
17234 ast_cli(a
->fd
, "Sent remote %s request on CIC %d\n",
17235 (do_what
== DO_BLOCK
) ? "blocking" : "unblocking",
17236 linksets
[linkset
- 1].ss7
.pvts
[i
]->cic
);
17240 if (sig_ss7_reset_cic(&linksets
[linkset
- 1].ss7
,
17241 linksets
[linkset
- 1].ss7
.pvts
[i
]->cic
,
17242 linksets
[linkset
- 1].ss7
.pvts
[i
]->dpc
)) {
17243 ast_cli(a
->fd
, "Sent reset request on CIC %d\n",
17244 linksets
[linkset
- 1].ss7
.pvts
[i
]->cic
);
17251 return CLI_SUCCESS
;
17253 #endif /* defined(HAVE_SS7) */
17255 #if defined(HAVE_SS7)
17256 static char *handle_ss7_group_blocking(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17258 int linkset
, cic
, range
, chanpos
;
17259 int i
, dpc
, orient
= 0;
17261 unsigned char state
[255];
17265 e
->command
= "ss7 {block|unblock} group";
17267 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17268 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17274 if (a
->argc
== 7 || a
->argc
== 8) {
17275 linkset
= atoi(a
->argv
[3]);
17277 return CLI_SHOWUSAGE
;
17280 if (!strcasecmp(a
->argv
[1], "block")) {
17282 } else if (strcasecmp(a
->argv
[1], "unblock")) {
17283 return CLI_SHOWUSAGE
;
17286 if (a
->argc
== 8) {
17287 if (!strcasecmp(a
->argv
[7], "H")) {
17290 return CLI_SHOWUSAGE
;
17294 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17295 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[4], 1, NUM_SPANS
);
17296 return CLI_SUCCESS
;
17299 if (!linksets
[linkset
-1].ss7
.ss7
) {
17300 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17301 return CLI_SUCCESS
;
17304 cic
= atoi(a
->argv
[5]);
17306 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17307 return CLI_SUCCESS
;
17310 range
= atoi(a
->argv
[6]);
17311 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17312 if (range
< 1 || range
> (linksets
[linkset
- 1].ss7
.type
== SS7_ANSI
? 24 : 31)) {
17313 ast_cli(a
->fd
, "Invalid range specified!\n");
17314 return CLI_SUCCESS
;
17317 dpc
= atoi(a
->argv
[4]);
17319 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17320 return CLI_SUCCESS
;
17323 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17324 if (!sig_ss7_find_cic_range(&linksets
[linkset
-1].ss7
, cic
, cic
+ range
, dpc
)) {
17325 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17326 ast_cli(a
->fd
, "Invalid CIC/RANGE\n");
17327 return CLI_SHOWUSAGE
;
17330 memset(state
, 0, sizeof(state
));
17331 for (i
= 0; i
<= range
; ++i
) {
17335 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17336 chanpos
= sig_ss7_find_cic(&linksets
[linkset
-1].ss7
, cic
, dpc
);
17337 if (sig_ss7_group_blocking(&linksets
[linkset
-1].ss7
, do_block
, chanpos
, cic
+ range
, state
, orient
)) {
17338 ast_cli(a
->fd
, "Unable allocate new ss7call\n");
17340 ast_cli(a
->fd
, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17341 orient
? " hardware" : "", do_block
? "" : "un", linkset
, cic
, range
);
17344 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17346 /* Break poll on the linkset so it sends our messages */
17347 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17348 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17350 return CLI_SUCCESS
;
17352 #endif /* defined(HAVE_SS7) */
17354 #if defined(HAVE_SS7)
17355 static char *handle_ss7_group_reset(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17357 int linkset
, cic
, range
;
17362 e
->command
= "ss7 reset group";
17364 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17365 " Send a GRS for the given CIC range on the specified linkset\n";
17371 if (a
->argc
== 7) {
17372 linkset
= atoi(a
->argv
[3]);
17374 return CLI_SHOWUSAGE
;
17377 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17378 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[4], 1, NUM_SPANS
);
17379 return CLI_SUCCESS
;
17382 if (!linksets
[linkset
-1].ss7
.ss7
) {
17383 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17384 return CLI_SUCCESS
;
17387 cic
= atoi(a
->argv
[5]);
17390 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17391 return CLI_SUCCESS
;
17394 range
= atoi(a
->argv
[6]);
17395 if (range
< 1 || range
> (linksets
[linkset
- 1].ss7
.type
== SS7_ANSI
? 24 : 31)) {
17396 ast_cli(a
->fd
, "Invalid range specified!\n");
17397 return CLI_SUCCESS
;
17400 dpc
= atoi(a
->argv
[4]);
17402 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17403 return CLI_SUCCESS
;
17406 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17407 if (!sig_ss7_find_cic_range(&linksets
[linkset
-1].ss7
, cic
, cic
+ range
, dpc
)) {
17408 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17409 ast_cli(a
->fd
, "Invalid CIC/RANGE\n");
17410 return CLI_SHOWUSAGE
;
17413 if (sig_ss7_reset_group(&linksets
[linkset
-1].ss7
, cic
, dpc
, range
)) {
17414 ast_cli(a
->fd
, "Unable to allocate new ss7call\n");
17416 ast_cli(a
->fd
, "GRS sent ... \n");
17419 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17421 /* Break poll on the linkset so it sends our messages */
17422 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17423 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17425 return CLI_SUCCESS
;
17427 #endif /* defined(HAVE_SS7) */
17429 #if defined(HAVE_SS7)
17430 static char *handle_ss7_show_calls(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17436 e
->command
= "ss7 show calls";
17438 "Usage: ss7 show calls <linkset>\n"
17439 " Show SS7 calls on the specified linkset\n";
17445 if (a
->argc
== 4) {
17446 linkset
= atoi(a
->argv
[3]);
17448 return CLI_SHOWUSAGE
;
17451 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17452 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17453 return CLI_SUCCESS
;
17456 if (!linksets
[linkset
-1].ss7
.ss7
) {
17457 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17458 return CLI_SUCCESS
;
17461 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17462 isup_show_calls(linksets
[linkset
-1].ss7
.ss7
, &ast_cli
, a
->fd
);
17463 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17465 return CLI_SUCCESS
;
17467 #endif /* defined(HAVE_SS7) */
17469 #if defined(HAVE_SS7)
17470 static char *handle_ss7_reset_cic(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17472 int linkset
, cic
, res
;
17477 e
->command
= "ss7 reset cic";
17479 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17480 " Send a RSC for the given CIC on the specified linkset\n";
17486 if (a
->argc
== 6) {
17487 linkset
= atoi(a
->argv
[3]);
17489 return CLI_SHOWUSAGE
;
17492 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17493 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17494 return CLI_SUCCESS
;
17497 if (!linksets
[linkset
-1].ss7
.ss7
) {
17498 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17499 return CLI_SUCCESS
;
17502 cic
= atoi(a
->argv
[5]);
17505 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17506 return CLI_SUCCESS
;
17509 dpc
= atoi(a
->argv
[4]);
17511 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17512 return CLI_SUCCESS
;
17515 res
= sig_ss7_reset_cic(&linksets
[linkset
-1].ss7
, cic
, dpc
);
17517 ast_cli(a
->fd
, "%s RSC for linkset %d on CIC %d DPC %d\n", res
? "Sent" : "Failed", linkset
, cic
, dpc
);
17519 return CLI_SUCCESS
;
17521 #endif /* defined(HAVE_SS7) */
17523 #if defined(HAVE_SS7)
17524 static char *handle_ss7_net_mng(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17528 unsigned int arg
= 0;
17533 e
->command
= "ss7 mtp3";
17535 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
17536 " Send a NET MNG message\n"
17537 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
17544 return CLI_SHOWUSAGE
;
17547 linkset
= atoi(a
->argv
[2]);
17548 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17549 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[2], 1, NUM_SPANS
);
17550 return CLI_SUCCESS
;
17552 if (!linksets
[linkset
-1].ss7
.ss7
) {
17553 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17554 return CLI_SUCCESS
;
17557 slc
= atoi(a
->argv
[3]);
17559 if (a
->argc
== 6) {
17560 arg
= atoi(a
->argv
[5]);
17563 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17564 res
= mtp3_net_mng(linksets
[linkset
-1].ss7
.ss7
, slc
, a
->argv
[4], arg
);
17565 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17567 /* Break poll on the linkset so it sends our messages */
17568 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17569 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17572 ast_cli(a
->fd
, "%s", res
);
17574 return CLI_SUCCESS
;
17576 #endif /* defined(HAVE_SS7) */
17578 #if defined(HAVE_SS7)
17579 static char *handle_ss7_mtp3_restart(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17582 unsigned int slc
= 0;
17586 e
->command
= "ss7 restart mtp3";
17588 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
17596 return CLI_SHOWUSAGE
;
17599 linkset
= atoi(a
->argv
[3]);
17600 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17601 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[2], 1, NUM_SPANS
);
17602 return CLI_SUCCESS
;
17604 if (!linksets
[linkset
-1].ss7
.ss7
) {
17605 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17606 return CLI_SUCCESS
;
17609 slc
= atoi(a
->argv
[4]);
17611 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17612 mtp3_init_restart(linksets
[linkset
-1].ss7
.ss7
, slc
);
17613 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17615 /* Break poll on the linkset so it sends our messages */
17616 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17617 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17620 return CLI_SUCCESS
;
17622 #endif /* defined(HAVE_SS7) */
17624 #if defined(HAVE_SS7)
17625 static char *handle_ss7_show_linkset(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17628 struct sig_ss7_linkset
*ss7
;
17631 e
->command
= "ss7 show linkset";
17633 "Usage: ss7 show linkset <span>\n"
17634 " Shows the status of an SS7 linkset.\n";
17641 return CLI_SHOWUSAGE
;
17644 linkset
= atoi(a
->argv
[3]);
17645 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17646 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17647 return CLI_SUCCESS
;
17649 ss7
= &linksets
[linkset
- 1].ss7
;
17651 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17652 return CLI_SUCCESS
;
17655 ast_cli(a
->fd
, "SS7 flags: 0x%x\n", ss7
->flags
);
17656 ast_cli(a
->fd
, "SS7 linkset %d status: %s\n", linkset
, (ss7
->state
== LINKSET_STATE_UP
) ? "Up" : "Down");
17657 ast_cli(a
->fd
, "SS7 calling nai: %i\n", ss7
->calling_nai
);
17658 ast_cli(a
->fd
, "SS7 called nai: %i\n", ss7
->called_nai
);
17659 ast_cli(a
->fd
, "SS7 nationalprefix: %s\n", ss7
->nationalprefix
);
17660 ast_cli(a
->fd
, "SS7 internationalprefix: %s\n", ss7
->internationalprefix
);
17661 ast_cli(a
->fd
, "SS7 unknownprefix: %s\n", ss7
->unknownprefix
);
17662 ast_cli(a
->fd
, "SS7 networkroutedprefix: %s\n", ss7
->networkroutedprefix
);
17663 ast_cli(a
->fd
, "SS7 subscriberprefix: %s\n", ss7
->subscriberprefix
);
17664 ss7_show_linkset(ss7
->ss7
, &ast_cli
, a
->fd
);
17666 return CLI_SUCCESS
;
17668 #endif /* defined(HAVE_SS7) */
17670 #if defined(HAVE_SS7)
17671 static char *handle_ss7_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17677 e
->command
= "ss7 show channels";
17679 "Usage: ss7 show channels\n"
17680 " Displays SS7 channel information at a glance.\n";
17686 if (a
->argc
!= 3) {
17687 return CLI_SHOWUSAGE
;
17690 sig_ss7_cli_show_channels_header(a
->fd
);
17691 for (linkset
= 0; linkset
< NUM_SPANS
; ++linkset
) {
17692 if (linksets
[linkset
].ss7
.ss7
) {
17693 sig_ss7_cli_show_channels(a
->fd
, &linksets
[linkset
].ss7
);
17696 return CLI_SUCCESS
;
17698 #endif /* defined(HAVE_SS7) */
17700 #if defined(HAVE_SS7)
17701 static char *handle_ss7_show_cics(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17703 #define FORMAT "%5s %5s %6s %12s %-12s\n"
17704 #define FORMAT2 "%5i %5i %6i %12s %-12s\n"
17705 int i
, linkset
, dpc
= 0;
17706 struct sig_ss7_linkset
*ss7
;
17712 e
->command
= "ss7 show cics";
17714 "Usage: ss7 show cics <linkset> [dpc]\n"
17715 " Shows the cics of an SS7 linkset.\n";
17721 if (a
->argc
< 4 || a
->argc
> 5) {
17722 return CLI_SHOWUSAGE
;
17725 linkset
= atoi(a
->argv
[3]);
17727 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17728 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17729 return CLI_SUCCESS
;
17732 if (!linksets
[linkset
-1].ss7
.ss7
) {
17733 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17734 return CLI_SUCCESS
;
17736 ss7
= &linksets
[linkset
-1].ss7
;
17738 if (a
->argc
== 5) {
17739 dpc
= atoi(a
->argv
[4]);
17741 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17742 return CLI_SUCCESS
;
17746 ast_cli(a
->fd
, FORMAT
, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
17748 for (i
= 0; i
< ss7
->numchans
; i
++) {
17749 if (!dpc
|| (ss7
->pvts
[i
] && ss7
->pvts
[i
]->dpc
== dpc
)) {
17750 struct dahdi_pvt
*p
= ss7
->pvts
[i
]->chan_pvt
;
17752 if (ss7
->pvts
[i
]->owner
) {
17754 } else if (ss7
->pvts
[i
]->ss7call
) {
17756 } else if (!p
->inservice
) {
17757 state
= "NotInServ";
17762 if (p
->locallyblocked
) {
17763 strcpy(blocking
, "L:");
17764 if (p
->locallyblocked
& SS7_BLOCKED_MAINTENANCE
) {
17765 strcat(blocking
, "M");
17767 strcat(blocking
, " ");
17770 if (p
->locallyblocked
& SS7_BLOCKED_HARDWARE
) {
17771 strcat(blocking
, "H");
17773 strcat(blocking
, " ");
17776 strcpy(blocking
, " ");
17779 if (p
->remotelyblocked
) {
17780 strcat(blocking
, " R:");
17781 if (p
->remotelyblocked
& SS7_BLOCKED_MAINTENANCE
) {
17782 strcat(blocking
, "M");
17784 strcat(blocking
, " ");
17787 if (p
->remotelyblocked
& SS7_BLOCKED_HARDWARE
) {
17788 strcat(blocking
, "H");
17790 strcat(blocking
, " ");
17794 ast_cli(a
->fd
, FORMAT2
, ss7
->pvts
[i
]->cic
, ss7
->pvts
[i
]->dpc
, ss7
->pvts
[i
]->channel
, state
, blocking
);
17798 return CLI_SUCCESS
;
17802 #endif /* defined(HAVE_SS7) */
17804 #if defined(HAVE_SS7)
17805 static char *handle_ss7_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17809 e
->command
= "ss7 show version";
17811 "Usage: ss7 show version\n"
17812 " Show the libss7 version\n";
17818 ast_cli(a
->fd
, "libss7 version: %s\n", ss7_get_version());
17820 return CLI_SUCCESS
;
17822 #endif /* defined(HAVE_SS7) */
17824 #if defined(HAVE_SS7)
17825 static struct ast_cli_entry dahdi_ss7_cli
[] = {
17826 AST_CLI_DEFINE(handle_ss7_debug
, "Enables SS7 debugging on a linkset"),
17827 AST_CLI_DEFINE(handle_ss7_cic_blocking
, "Blocks/Unblocks the given CIC"),
17828 AST_CLI_DEFINE(handle_ss7_linkset_mng
, "Resets/Blocks/Unblocks all CICs on a linkset"),
17829 AST_CLI_DEFINE(handle_ss7_group_blocking
, "Blocks/Unblocks the given CIC range"),
17830 AST_CLI_DEFINE(handle_ss7_reset_cic
, "Resets the given CIC"),
17831 AST_CLI_DEFINE(handle_ss7_group_reset
, "Resets the given CIC range"),
17832 AST_CLI_DEFINE(handle_ss7_mtp3_restart
, "Restart a link"),
17833 AST_CLI_DEFINE(handle_ss7_net_mng
, "Send an NET MNG message"),
17834 AST_CLI_DEFINE(handle_ss7_show_linkset
, "Shows the status of a linkset"),
17835 AST_CLI_DEFINE(handle_ss7_show_channels
, "Displays SS7 channel information"),
17836 AST_CLI_DEFINE(handle_ss7_show_calls
, "Show ss7 calls"),
17837 AST_CLI_DEFINE(handle_ss7_show_cics
, "Show cics on a linkset"),
17838 AST_CLI_DEFINE(handle_ss7_version
, "Displays libss7 version"),
17840 #endif /* defined(HAVE_SS7) */
17842 #if defined(HAVE_PRI)
17843 #if defined(HAVE_PRI_CCSS)
17846 * \brief CC agent initialization.
17849 * \param agent CC core agent control.
17850 * \param chan Original channel the agent will attempt to recall.
17853 * This callback is called when the CC core is initialized. Agents should allocate
17854 * any private data necessary for the call and assign it to the private_data
17855 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
17856 * specific agent type, they should be set in this function as well.
17858 * \retval 0 on success.
17859 * \retval -1 on error.
17861 static int dahdi_pri_cc_agent_init(struct ast_cc_agent
*agent
, struct ast_channel
*chan
)
17863 struct dahdi_pvt
*pvt
;
17864 struct sig_pri_chan
*pvt_chan
;
17867 ast_assert(!strcmp(ast_channel_tech(chan
)->type
, "DAHDI"));
17869 pvt
= ast_channel_tech_pvt(chan
);
17870 if (dahdi_sig_pri_lib_handles(pvt
->sig
)) {
17871 pvt_chan
= pvt
->sig_pvt
;
17879 ast_module_ref(ast_module_info
->self
);
17881 res
= sig_pri_cc_agent_init(agent
, pvt_chan
);
17883 ast_module_unref(ast_module_info
->self
);
17887 #endif /* defined(HAVE_PRI_CCSS) */
17888 #endif /* defined(HAVE_PRI) */
17890 #if defined(HAVE_PRI)
17891 #if defined(HAVE_PRI_CCSS)
17894 * \brief Destroy private data on the agent.
17897 * \param agent CC core agent control.
17900 * The core will call this function upon completion
17901 * or failure of CC.
17903 static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent
*agent
)
17905 sig_pri_cc_agent_destructor(agent
);
17907 ast_module_unref(ast_module_info
->self
);
17909 #endif /* defined(HAVE_PRI_CCSS) */
17910 #endif /* defined(HAVE_PRI) */
17912 #if defined(HAVE_PRI)
17913 #if defined(HAVE_PRI_CCSS)
17914 static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks
= {
17915 .type
= dahdi_pri_cc_type
,
17916 .init
= dahdi_pri_cc_agent_init
,
17917 .start_offer_timer
= sig_pri_cc_agent_start_offer_timer
,
17918 .stop_offer_timer
= sig_pri_cc_agent_stop_offer_timer
,
17919 .respond
= sig_pri_cc_agent_req_rsp
,
17920 .status_request
= sig_pri_cc_agent_status_req
,
17921 .stop_ringing
= sig_pri_cc_agent_stop_ringing
,
17922 .party_b_free
= sig_pri_cc_agent_party_b_free
,
17923 .start_monitoring
= sig_pri_cc_agent_start_monitoring
,
17924 .callee_available
= sig_pri_cc_agent_callee_available
,
17925 .destructor
= dahdi_pri_cc_agent_destructor
,
17927 #endif /* defined(HAVE_PRI_CCSS) */
17928 #endif /* defined(HAVE_PRI) */
17930 #if defined(HAVE_PRI)
17931 #if defined(HAVE_PRI_CCSS)
17932 static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks
= {
17933 .type
= dahdi_pri_cc_type
,
17934 .request_cc
= sig_pri_cc_monitor_req_cc
,
17935 .suspend
= sig_pri_cc_monitor_suspend
,
17936 .unsuspend
= sig_pri_cc_monitor_unsuspend
,
17937 .status_response
= sig_pri_cc_monitor_status_rsp
,
17938 .cancel_available_timer
= sig_pri_cc_monitor_cancel_available_timer
,
17939 .destructor
= sig_pri_cc_monitor_destructor
,
17941 #endif /* defined(HAVE_PRI_CCSS) */
17942 #endif /* defined(HAVE_PRI) */
17944 static int __unload_module(void)
17946 struct dahdi_pvt
*p
;
17947 #if defined(HAVE_PRI) || defined(HAVE_SS7)
17949 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
17952 for (i
= 0; i
< NUM_SPANS
; i
++) {
17953 if (pris
[i
].pri
.master
!= AST_PTHREADT_NULL
) {
17954 pthread_cancel(pris
[i
].pri
.master
);
17955 pthread_kill(pris
[i
].pri
.master
, SIGURG
);
17958 ast_cli_unregister_multiple(dahdi_pri_cli
, ARRAY_LEN(dahdi_pri_cli
));
17959 ast_unregister_application(dahdi_send_keypad_facility_app
);
17960 #ifdef HAVE_PRI_PROG_W_CAUSE
17961 ast_unregister_application(dahdi_send_callrerouting_facility_app
);
17964 #if defined(HAVE_SS7)
17965 for (i
= 0; i
< NUM_SPANS
; i
++) {
17966 if (linksets
[i
].ss7
.master
!= AST_PTHREADT_NULL
) {
17967 pthread_cancel(linksets
[i
].ss7
.master
);
17968 pthread_kill(linksets
[i
].ss7
.master
, SIGURG
);
17971 ast_cli_unregister_multiple(dahdi_ss7_cli
, ARRAY_LEN(dahdi_ss7_cli
));
17972 #endif /* defined(HAVE_SS7) */
17973 #if defined(HAVE_OPENR2)
17974 dahdi_r2_destroy_links();
17975 ast_cli_unregister_multiple(dahdi_mfcr2_cli
, ARRAY_LEN(dahdi_mfcr2_cli
));
17976 ast_unregister_application(dahdi_accept_r2_call_app
);
17979 ast_custom_function_unregister(&polarity_function
);
17981 ast_cli_unregister_multiple(dahdi_cli
, ARRAY_LEN(dahdi_cli
));
17982 ast_manager_unregister("DAHDIDialOffhook");
17983 ast_manager_unregister("DAHDIHangup");
17984 ast_manager_unregister("DAHDITransfer");
17985 ast_manager_unregister("DAHDIDNDoff");
17986 ast_manager_unregister("DAHDIDNDon");
17987 ast_manager_unregister("DAHDIShowChannels");
17988 ast_manager_unregister("DAHDIRestart");
17989 #if defined(HAVE_PRI)
17990 ast_manager_unregister("PRIShowSpans");
17991 ast_manager_unregister("PRIDebugSet");
17992 ast_manager_unregister("PRIDebugFileSet");
17993 ast_manager_unregister("PRIDebugFileUnset");
17994 #endif /* defined(HAVE_PRI) */
17995 ast_channel_unregister(&dahdi_tech
);
17997 /* Hangup all interfaces if they have an owner */
17998 ast_mutex_lock(&iflock
);
17999 for (p
= iflist
; p
; p
= p
->next
) {
18001 ast_softhangup(p
->owner
, AST_SOFTHANGUP_APPUNLOAD
);
18003 ast_mutex_unlock(&iflock
);
18005 ast_mutex_lock(&monlock
);
18006 if (monitor_thread
&& (monitor_thread
!= AST_PTHREADT_STOP
) && (monitor_thread
!= AST_PTHREADT_NULL
)) {
18007 pthread_cancel(monitor_thread
);
18008 pthread_kill(monitor_thread
, SIGURG
);
18009 pthread_join(monitor_thread
, NULL
);
18011 monitor_thread
= AST_PTHREADT_STOP
;
18012 ast_mutex_unlock(&monlock
);
18014 destroy_all_channels();
18016 #if defined(HAVE_PRI)
18017 for (i
= 0; i
< NUM_SPANS
; i
++) {
18018 if (pris
[i
].pri
.master
&& (pris
[i
].pri
.master
!= AST_PTHREADT_NULL
)) {
18019 pthread_join(pris
[i
].pri
.master
, NULL
);
18021 for (j
= 0; j
< SIG_PRI_NUM_DCHANS
; j
++) {
18022 dahdi_close_pri_fd(&(pris
[i
]), j
);
18024 sig_pri_stop_pri(&pris
[i
].pri
);
18026 #if defined(HAVE_PRI_CCSS)
18027 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks
);
18028 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks
);
18029 #endif /* defined(HAVE_PRI_CCSS) */
18033 #if defined(HAVE_SS7)
18034 for (i
= 0; i
< NUM_SPANS
; i
++) {
18035 if (linksets
[i
].ss7
.master
&& (linksets
[i
].ss7
.master
!= AST_PTHREADT_NULL
)) {
18036 pthread_join(linksets
[i
].ss7
.master
, NULL
);
18038 for (j
= 0; j
< SIG_SS7_NUM_DCHANS
; j
++) {
18039 dahdi_close_ss7_fd(&(linksets
[i
]), j
);
18041 if (linksets
[i
].ss7
.ss7
) {
18042 ss7_destroy(linksets
[i
].ss7
.ss7
);
18043 linksets
[i
].ss7
.ss7
= NULL
;
18046 #endif /* defined(HAVE_SS7) */
18047 ast_cond_destroy(&ss_thread_complete
);
18049 dahdi_native_unload();
18051 ao2_cleanup(dahdi_tech
.capabilities
);
18052 dahdi_tech
.capabilities
= NULL
;
18053 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type
);
18057 static int unload_module(void)
18059 #if defined(HAVE_PRI) || defined(HAVE_SS7)
18061 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18063 for (y
= 0; y
< NUM_SPANS
; y
++)
18064 ast_mutex_destroy(&pris
[y
].pri
.lock
);
18066 #if defined(HAVE_SS7)
18067 for (y
= 0; y
< NUM_SPANS
; y
++)
18068 ast_mutex_destroy(&linksets
[y
].ss7
.lock
);
18069 #endif /* defined(HAVE_SS7) */
18070 return __unload_module();
18073 static int build_channels(struct dahdi_chan_conf
*conf
, const char *value
, int reload
, int lineno
)
18076 int x
, start
, finish
;
18077 struct dahdi_pvt
*tmp
;
18079 if ((reload
== 0) && (conf
->chan
.sig
< 0) && !conf
->is_sig_auto
) {
18080 ast_log(LOG_ERROR
, "Signalling must be specified before any channels are.\n");
18084 c
= ast_strdupa(value
);
18086 while ((chan
= strsep(&c
, ","))) {
18087 if (sscanf(chan
, "%30d-%30d", &start
, &finish
) == 2) {
18089 } else if (sscanf(chan
, "%30d", &start
)) {
18092 } else if (!strcasecmp(chan
, "pseudo")) {
18093 finish
= start
= CHAN_PSEUDO
;
18095 ast_log(LOG_ERROR
, "Syntax error parsing '%s' at '%s'\n", value
, chan
);
18098 if (finish
< start
) {
18099 ast_log(LOG_WARNING
, "Silliness: %d < %d\n", start
, finish
);
18105 for (x
= start
; x
<= finish
; x
++) {
18106 if (conf
->wanted_channels_start
&&
18107 (x
< conf
->wanted_channels_start
||
18108 x
> conf
->wanted_channels_end
)
18112 tmp
= mkintf(x
, conf
, reload
);
18115 ast_verb(3, "%s channel %d, %s signalling\n", reload
? "Reconfigured" : "Registered", x
, sig2str(tmp
->sig
));
18117 ast_log(LOG_ERROR
, "Unable to %s channel '%s'\n",
18118 (reload
== 1) ? "reconfigure" : "register", value
);
18121 if (x
== CHAN_PSEUDO
) {
18130 /** The length of the parameters list of 'dahdichan'.
18131 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18132 #define MAX_CHANLIST_LEN 80
18134 static void process_echocancel(struct dahdi_chan_conf
*confp
, const char *data
, unsigned int line
)
18136 char *parse
= ast_strdupa(data
);
18137 char *params
[DAHDI_MAX_ECHOCANPARAMS
+ 1];
18138 unsigned int param_count
;
18141 if (!(param_count
= ast_app_separate_args(parse
, ',', params
, ARRAY_LEN(params
))))
18144 memset(&confp
->chan
.echocancel
, 0, sizeof(confp
->chan
.echocancel
));
18146 /* first parameter is tap length, process it here */
18148 x
= ast_strlen_zero(params
[0]) ? 0 : atoi(params
[0]);
18150 if ((x
== 32) || (x
== 64) || (x
== 128) || (x
== 256) || (x
== 512) || (x
== 1024))
18151 confp
->chan
.echocancel
.head
.tap_length
= x
;
18152 else if ((confp
->chan
.echocancel
.head
.tap_length
= ast_true(params
[0])))
18153 confp
->chan
.echocancel
.head
.tap_length
= 128;
18155 /* now process any remaining parameters */
18157 for (x
= 1; x
< param_count
; x
++) {
18163 if (ast_app_separate_args(params
[x
], '=', (char **) ¶m
, 2) < 1) {
18164 ast_log(LOG_WARNING
, "Invalid echocancel parameter supplied at line %u: '%s'\n", line
, params
[x
]);
18168 if (ast_strlen_zero(param
.name
) || (strlen(param
.name
) > sizeof(confp
->chan
.echocancel
.params
[0].name
)-1)) {
18169 ast_log(LOG_WARNING
, "Invalid echocancel parameter supplied at line %u: '%s'\n", line
, param
.name
);
18173 strcpy(confp
->chan
.echocancel
.params
[confp
->chan
.echocancel
.head
.param_count
].name
, param
.name
);
18176 if (sscanf(param
.value
, "%30d", &confp
->chan
.echocancel
.params
[confp
->chan
.echocancel
.head
.param_count
].value
) != 1) {
18177 ast_log(LOG_WARNING
, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line
, param
.value
);
18181 confp
->chan
.echocancel
.head
.param_count
++;
18185 #if defined(HAVE_PRI)
18186 #if defined(HAVE_PRI_DISPLAY_TEXT)
18189 * \brief Determine the configured display text options.
18192 * \param value Configuration value string.
18194 * \return Configured display text option flags.
18196 static unsigned long dahdi_display_text_option(const char *value
)
18200 unsigned long options
;
18203 val_str
= ast_strdupa(value
);
18206 opt_str
= strsep(&val_str
, ",");
18210 opt_str
= ast_strip(opt_str
);
18215 if (!strcasecmp(opt_str
, "block")) {
18216 options
|= PRI_DISPLAY_OPTION_BLOCK
;
18217 } else if (!strcasecmp(opt_str
, "name_initial")) {
18218 options
|= PRI_DISPLAY_OPTION_NAME_INITIAL
;
18219 } else if (!strcasecmp(opt_str
, "name_update")) {
18220 options
|= PRI_DISPLAY_OPTION_NAME_UPDATE
;
18221 } else if (!strcasecmp(opt_str
, "name")) {
18222 options
|= (PRI_DISPLAY_OPTION_NAME_INITIAL
| PRI_DISPLAY_OPTION_NAME_UPDATE
);
18223 } else if (!strcasecmp(opt_str
, "text")) {
18224 options
|= PRI_DISPLAY_OPTION_TEXT
;
18229 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18230 #endif /* defined(HAVE_PRI) */
18232 #if defined(HAVE_PRI)
18233 #if defined(HAVE_PRI_DATETIME_SEND)
18236 * \brief Determine the configured date/time send policy option.
18239 * \param value Configuration value string.
18241 * \return Configured date/time send policy option.
18243 static int dahdi_datetime_send_option(const char *value
)
18247 option
= PRI_DATE_TIME_SEND_DEFAULT
;
18249 if (ast_false(value
)) {
18250 option
= PRI_DATE_TIME_SEND_NO
;
18251 } else if (!strcasecmp(value
, "date")) {
18252 option
= PRI_DATE_TIME_SEND_DATE
;
18253 } else if (!strcasecmp(value
, "date_hh")) {
18254 option
= PRI_DATE_TIME_SEND_DATE_HH
;
18255 } else if (!strcasecmp(value
, "date_hhmm")) {
18256 option
= PRI_DATE_TIME_SEND_DATE_HHMM
;
18257 } else if (!strcasecmp(value
, "date_hhmmss")) {
18258 option
= PRI_DATE_TIME_SEND_DATE_HHMMSS
;
18263 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
18264 #endif /* defined(HAVE_PRI) */
18266 /*! process_dahdi() - ignore keyword 'channel' and similar */
18267 #define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18268 /*! process_dahdi() - No warnings on non-existing cofiguration keywords */
18269 #define PROC_DAHDI_OPT_NOWARN (1 << 1)
18271 static void parse_busy_pattern(struct ast_variable
*v
, struct ast_dsp_busy_pattern
*busy_cadence
)
18273 int count_pattern
= 0;
18278 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18279 if (!sscanf(v
->value
, "%30d", &norval
) && count_pattern
== 0) {
18280 ast_log(LOG_ERROR
, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v
->lineno
);
18284 busy_cadence
->pattern
[count_pattern
] = norval
;
18287 if (count_pattern
== 4) {
18291 temp
= strchr(v
->value
, ',');
18292 if (temp
== NULL
) {
18295 v
->value
= temp
+ 1;
18297 busy_cadence
->length
= count_pattern
;
18299 if (count_pattern
% 2 != 0) {
18300 /* The pattern length must be divisible by two */
18301 ast_log(LOG_ERROR
, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v
->lineno
);
18306 static int process_dahdi(struct dahdi_chan_conf
*confp
, const char *cat
, struct ast_variable
*v
, int reload
, int options
)
18308 struct dahdi_pvt
*tmp
;
18310 struct ast_variable
*dahdichan
= NULL
;
18312 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18313 user_has_defined_cadences
= 0;
18315 for (; v
; v
= v
->next
) {
18316 if (!ast_jb_read_conf(&global_jbconf
, v
->name
, v
->value
))
18319 /* Create the interface list */
18320 if (!strcasecmp(v
->name
, "channel") || !strcasecmp(v
->name
, "channels")) {
18321 if (options
& PROC_DAHDI_OPT_NOCHAN
) {
18322 ast_log(LOG_WARNING
, "Channel '%s' ignored.\n", v
->value
);
18325 if (build_channels(confp
, v
->value
, reload
, v
->lineno
)) {
18326 if (confp
->ignore_failed_channels
) {
18327 ast_log(LOG_WARNING
, "Channel '%s' failure ignored: ignore_failed_channels.\n", v
->value
);
18333 ast_debug(1, "Channel '%s' configured.\n", v
->value
);
18334 } else if (!strcasecmp(v
->name
, "ignore_failed_channels")) {
18335 confp
->ignore_failed_channels
= ast_true(v
->value
);
18336 } else if (!strcasecmp(v
->name
, "buffers")) {
18337 if (parse_buffers_policy(v
->value
, &confp
->chan
.buf_no
, &confp
->chan
.buf_policy
)) {
18338 ast_log(LOG_WARNING
, "Using default buffer policy.\n");
18339 confp
->chan
.buf_no
= numbufs
;
18340 confp
->chan
.buf_policy
= DAHDI_POLICY_IMMEDIATE
;
18342 } else if (!strcasecmp(v
->name
, "faxbuffers")) {
18343 if (!parse_buffers_policy(v
->value
, &confp
->chan
.faxbuf_no
, &confp
->chan
.faxbuf_policy
)) {
18344 confp
->chan
.usefaxbuffers
= 1;
18346 } else if (!strcasecmp(v
->name
, "dahdichan")) {
18347 /* Only process the last dahdichan value. */
18349 } else if (!strcasecmp(v
->name
, "usedistinctiveringdetection")) {
18350 usedistinctiveringdetection
= ast_true(v
->value
);
18351 } else if (!strcasecmp(v
->name
, "distinctiveringaftercid")) {
18352 distinctiveringaftercid
= ast_true(v
->value
);
18353 } else if (!strcasecmp(v
->name
, "dring1context")) {
18354 ast_copy_string(confp
->chan
.drings
.ringContext
[0].contextData
,v
->value
,sizeof(confp
->chan
.drings
.ringContext
[0].contextData
));
18355 } else if (!strcasecmp(v
->name
, "dring2context")) {
18356 ast_copy_string(confp
->chan
.drings
.ringContext
[1].contextData
,v
->value
,sizeof(confp
->chan
.drings
.ringContext
[1].contextData
));
18357 } else if (!strcasecmp(v
->name
, "dring3context")) {
18358 ast_copy_string(confp
->chan
.drings
.ringContext
[2].contextData
,v
->value
,sizeof(confp
->chan
.drings
.ringContext
[2].contextData
));
18359 } else if (!strcasecmp(v
->name
, "dring1range")) {
18360 confp
->chan
.drings
.ringnum
[0].range
= atoi(v
->value
);
18361 } else if (!strcasecmp(v
->name
, "dring2range")) {
18362 confp
->chan
.drings
.ringnum
[1].range
= atoi(v
->value
);
18363 } else if (!strcasecmp(v
->name
, "dring3range")) {
18364 confp
->chan
.drings
.ringnum
[2].range
= atoi(v
->value
);
18365 } else if (!strcasecmp(v
->name
, "dring1")) {
18366 sscanf(v
->value
, "%30d,%30d,%30d", &confp
->chan
.drings
.ringnum
[0].ring
[0], &confp
->chan
.drings
.ringnum
[0].ring
[1], &confp
->chan
.drings
.ringnum
[0].ring
[2]);
18367 } else if (!strcasecmp(v
->name
, "dring2")) {
18368 sscanf(v
->value
, "%30d,%30d,%30d", &confp
->chan
.drings
.ringnum
[1].ring
[0], &confp
->chan
.drings
.ringnum
[1].ring
[1], &confp
->chan
.drings
.ringnum
[1].ring
[2]);
18369 } else if (!strcasecmp(v
->name
, "dring3")) {
18370 sscanf(v
->value
, "%30d,%30d,%30d", &confp
->chan
.drings
.ringnum
[2].ring
[0], &confp
->chan
.drings
.ringnum
[2].ring
[1], &confp
->chan
.drings
.ringnum
[2].ring
[2]);
18371 } else if (!strcasecmp(v
->name
, "usecallerid")) {
18372 confp
->chan
.use_callerid
= ast_true(v
->value
);
18373 } else if (!strcasecmp(v
->name
, "cidsignalling")) {
18374 if (!strcasecmp(v
->value
, "bell"))
18375 confp
->chan
.cid_signalling
= CID_SIG_BELL
;
18376 else if (!strcasecmp(v
->value
, "v23"))
18377 confp
->chan
.cid_signalling
= CID_SIG_V23
;
18378 else if (!strcasecmp(v
->value
, "dtmf"))
18379 confp
->chan
.cid_signalling
= CID_SIG_DTMF
;
18380 else if (!strcasecmp(v
->value
, "smdi"))
18381 confp
->chan
.cid_signalling
= CID_SIG_SMDI
;
18382 else if (!strcasecmp(v
->value
, "v23_jp"))
18383 confp
->chan
.cid_signalling
= CID_SIG_V23_JP
;
18384 else if (ast_true(v
->value
))
18385 confp
->chan
.cid_signalling
= CID_SIG_BELL
;
18386 } else if (!strcasecmp(v
->name
, "cidstart")) {
18387 if (!strcasecmp(v
->value
, "ring"))
18388 confp
->chan
.cid_start
= CID_START_RING
;
18389 else if (!strcasecmp(v
->value
, "polarity_in"))
18390 confp
->chan
.cid_start
= CID_START_POLARITY_IN
;
18391 else if (!strcasecmp(v
->value
, "polarity"))
18392 confp
->chan
.cid_start
= CID_START_POLARITY
;
18393 else if (!strcasecmp(v
->value
, "dtmf"))
18394 confp
->chan
.cid_start
= CID_START_DTMF_NOALERT
;
18395 else if (ast_true(v
->value
))
18396 confp
->chan
.cid_start
= CID_START_RING
;
18397 } else if (!strcasecmp(v
->name
, "threewaycalling")) {
18398 confp
->chan
.threewaycalling
= ast_true(v
->value
);
18399 } else if (!strcasecmp(v
->name
, "threewaysilenthold")) {
18400 confp
->chan
.threewaysilenthold
= ast_true(v
->value
);
18401 } else if (!strcasecmp(v
->name
, "cancallforward")) {
18402 confp
->chan
.cancallforward
= ast_true(v
->value
);
18403 } else if (!strcasecmp(v
->name
, "relaxdtmf")) {
18404 if (ast_true(v
->value
))
18405 confp
->chan
.dtmfrelax
= DSP_DIGITMODE_RELAXDTMF
;
18407 confp
->chan
.dtmfrelax
= 0;
18408 } else if (!strcasecmp(v
->name
, "mailbox")) {
18409 ast_copy_string(confp
->chan
.mailbox
, v
->value
, sizeof(confp
->chan
.mailbox
));
18410 } else if (!strcasecmp(v
->name
, "description")) {
18411 ast_copy_string(confp
->chan
.description
, v
->value
, sizeof(confp
->chan
.description
));
18412 } else if (!strcasecmp(v
->name
, "hasvoicemail")) {
18413 if (ast_true(v
->value
) && ast_strlen_zero(confp
->chan
.mailbox
)) {
18415 * hasvoicemail is a users.conf legacy voicemail enable method.
18416 * hasvoicemail is only going to work for app_voicemail mailboxes.
18418 if (strchr(cat
, '@')) {
18419 ast_copy_string(confp
->chan
.mailbox
, cat
, sizeof(confp
->chan
.mailbox
));
18421 snprintf(confp
->chan
.mailbox
, sizeof(confp
->chan
.mailbox
),
18422 "%s@default", cat
);
18425 } else if (!strcasecmp(v
->name
, "adsi")) {
18426 confp
->chan
.adsi
= ast_true(v
->value
);
18427 } else if (!strcasecmp(v
->name
, "usesmdi")) {
18428 confp
->chan
.use_smdi
= ast_true(v
->value
);
18429 } else if (!strcasecmp(v
->name
, "smdiport")) {
18430 ast_copy_string(confp
->smdi_port
, v
->value
, sizeof(confp
->smdi_port
));
18431 } else if (!strcasecmp(v
->name
, "transfer")) {
18432 confp
->chan
.transfer
= ast_true(v
->value
);
18433 } else if (!strcasecmp(v
->name
, "canpark")) {
18434 confp
->chan
.canpark
= ast_true(v
->value
);
18435 } else if (!strcasecmp(v
->name
, "echocancelwhenbridged")) {
18436 confp
->chan
.echocanbridged
= ast_true(v
->value
);
18437 } else if (!strcasecmp(v
->name
, "busydetect")) {
18438 confp
->chan
.busydetect
= ast_true(v
->value
);
18439 } else if (!strcasecmp(v
->name
, "busycount")) {
18440 confp
->chan
.busycount
= atoi(v
->value
);
18441 } else if (!strcasecmp(v
->name
, "busypattern")) {
18442 parse_busy_pattern(v
, &confp
->chan
.busy_cadence
);
18443 } else if (!strcasecmp(v
->name
, "calledsubscriberheld")) {
18444 confp
->chan
.calledsubscriberheld
= ast_true(v
->value
);
18445 } else if (!strcasecmp(v
->name
, "callprogress")) {
18446 confp
->chan
.callprogress
&= ~CALLPROGRESS_PROGRESS
;
18447 if (ast_true(v
->value
))
18448 confp
->chan
.callprogress
|= CALLPROGRESS_PROGRESS
;
18449 } else if (!strcasecmp(v
->name
, "waitfordialtone")) {
18450 confp
->chan
.waitfordialtone
= atoi(v
->value
);
18451 } else if (!strcasecmp(v
->name
, "dialtone_detect")) {
18452 if (!strcasecmp(v
->value
, "always")) {
18453 confp
->chan
.dialtone_detect
= -1;
18454 } else if (ast_true(v
->value
)) {
18455 confp
->chan
.dialtone_detect
= DEFAULT_DIALTONE_DETECT_TIMEOUT
;
18456 } else if (ast_false(v
->value
)) {
18457 confp
->chan
.dialtone_detect
= 0;
18459 confp
->chan
.dialtone_detect
= ast_strlen_zero(v
->value
) ? 0 : (8 * atoi(v
->value
)) / READ_SIZE
;
18461 } else if (!strcasecmp(v
->name
, "faxdetect")) {
18462 confp
->chan
.callprogress
&= ~CALLPROGRESS_FAX
;
18463 if (!strcasecmp(v
->value
, "incoming")) {
18464 confp
->chan
.callprogress
|= CALLPROGRESS_FAX_INCOMING
;
18465 } else if (!strcasecmp(v
->value
, "outgoing")) {
18466 confp
->chan
.callprogress
|= CALLPROGRESS_FAX_OUTGOING
;
18467 } else if (!strcasecmp(v
->value
, "both") || ast_true(v
->value
))
18468 confp
->chan
.callprogress
|= CALLPROGRESS_FAX_INCOMING
| CALLPROGRESS_FAX_OUTGOING
;
18469 } else if (!strcasecmp(v
->name
, "faxdetect_timeout")) {
18470 if (sscanf(v
->value
, "%30u", &confp
->chan
.faxdetect_timeout
) != 1) {
18471 confp
->chan
.faxdetect_timeout
= 0;
18473 } else if (!strcasecmp(v
->name
, "firstdigit_timeout")) {
18474 if (sscanf(v
->value
, "%30d", &confp
->chan
.firstdigit_timeout
) != 1
18475 || confp
->chan
.firstdigit_timeout
<= 0) {
18476 confp
->chan
.firstdigit_timeout
= ANALOG_FIRST_DIGIT_TIMEOUT
;
18478 } else if (!strcasecmp(v
->name
, "interdigit_timeout")) {
18479 if (sscanf(v
->value
, "%30d", &confp
->chan
.interdigit_timeout
) != 1
18480 || confp
->chan
.interdigit_timeout
<= 0) {
18481 confp
->chan
.interdigit_timeout
= ANALOG_INTER_DIGIT_TIMEOUT
;
18483 } else if (!strcasecmp(v
->name
, "matchdigit_timeout")) {
18484 if (sscanf(v
->value
, "%30d", &confp
->chan
.matchdigit_timeout
) != 1
18485 || confp
->chan
.matchdigit_timeout
<= 0) {
18486 confp
->chan
.matchdigit_timeout
= ANALOG_MATCH_DIGIT_TIMEOUT
;
18488 } else if (!strcasecmp(v
->name
, "echocancel")) {
18489 process_echocancel(confp
, v
->value
, v
->lineno
);
18490 } else if (!strcasecmp(v
->name
, "echotraining")) {
18491 if (sscanf(v
->value
, "%30d", &y
) == 1) {
18492 if ((y
< 10) || (y
> 4000)) {
18493 ast_log(LOG_WARNING
, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v
->lineno
);
18495 confp
->chan
.echotraining
= y
;
18497 } else if (ast_true(v
->value
)) {
18498 confp
->chan
.echotraining
= 400;
18500 confp
->chan
.echotraining
= 0;
18501 } else if (!strcasecmp(v
->name
, "hidecallerid")) {
18502 confp
->chan
.hidecallerid
= ast_true(v
->value
);
18503 } else if (!strcasecmp(v
->name
, "hidecalleridname")) {
18504 confp
->chan
.hidecalleridname
= ast_true(v
->value
);
18505 } else if (!strcasecmp(v
->name
, "pulsedial")) {
18506 confp
->chan
.pulse
= ast_true(v
->value
);
18507 } else if (!strcasecmp(v
->name
, "callreturn")) {
18508 confp
->chan
.callreturn
= ast_true(v
->value
);
18509 } else if (!strcasecmp(v
->name
, "callwaiting")) {
18510 confp
->chan
.callwaiting
= ast_true(v
->value
);
18511 } else if (!strcasecmp(v
->name
, "callwaitingcallerid")) {
18512 confp
->chan
.callwaitingcallerid
= ast_true(v
->value
);
18513 } else if (!strcasecmp(v
->name
, "context")) {
18514 ast_copy_string(confp
->chan
.context
, v
->value
, sizeof(confp
->chan
.context
));
18515 } else if (!strcasecmp(v
->name
, "language")) {
18516 ast_copy_string(confp
->chan
.language
, v
->value
, sizeof(confp
->chan
.language
));
18517 } else if (!strcasecmp(v
->name
, "progzone")) {
18518 ast_copy_string(progzone
, v
->value
, sizeof(progzone
));
18519 } else if (!strcasecmp(v
->name
, "mohinterpret")
18520 ||!strcasecmp(v
->name
, "musiconhold") || !strcasecmp(v
->name
, "musicclass")) {
18521 ast_copy_string(confp
->chan
.mohinterpret
, v
->value
, sizeof(confp
->chan
.mohinterpret
));
18522 } else if (!strcasecmp(v
->name
, "mohsuggest")) {
18523 ast_copy_string(confp
->chan
.mohsuggest
, v
->value
, sizeof(confp
->chan
.mohsuggest
));
18524 } else if (!strcasecmp(v
->name
, "parkinglot")) {
18525 ast_copy_string(confp
->chan
.parkinglot
, v
->value
, sizeof(confp
->chan
.parkinglot
));
18526 } else if (!strcasecmp(v
->name
, "stripmsd")) {
18527 ast_log(LOG_NOTICE
, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v
->name
);
18528 confp
->chan
.stripmsd
= atoi(v
->value
);
18529 } else if (!strcasecmp(v
->name
, "jitterbuffers")) {
18530 numbufs
= atoi(v
->value
);
18531 } else if (!strcasecmp(v
->name
, "group")) {
18532 confp
->chan
.group
= ast_get_group(v
->value
);
18533 } else if (!strcasecmp(v
->name
, "callgroup")) {
18534 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18535 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a call group\n");
18537 if (!strcasecmp(v
->value
, "none"))
18538 confp
->chan
.callgroup
= 0;
18540 confp
->chan
.callgroup
= ast_get_group(v
->value
);
18541 } else if (!strcasecmp(v
->name
, "pickupgroup")) {
18542 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18543 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a pickup group\n");
18545 if (!strcasecmp(v
->value
, "none"))
18546 confp
->chan
.pickupgroup
= 0;
18548 confp
->chan
.pickupgroup
= ast_get_group(v
->value
);
18549 } else if (!strcasecmp(v
->name
, "namedcallgroup")) {
18550 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18551 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a named call group\n");
18553 confp
->chan
.named_callgroups
= ast_get_namedgroups(v
->value
);
18554 } else if (!strcasecmp(v
->name
, "namedpickupgroup")) {
18555 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18556 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a named pickup group\n");
18558 confp
->chan
.named_pickupgroups
= ast_get_namedgroups(v
->value
);
18559 } else if (!strcasecmp(v
->name
, "setvar")) {
18561 char *varval
= NULL
;
18562 struct ast_variable
*tmpvar
;
18563 char varname
[strlen(v
->value
) + 1];
18564 strcpy(varname
, v
->value
); /* safe */
18565 if ((varval
= strchr(varname
, '='))) {
18567 if ((tmpvar
= ast_variable_new(varname
, varval
, ""))) {
18568 if (ast_variable_list_replace(&confp
->chan
.vars
, tmpvar
)) {
18569 tmpvar
->next
= confp
->chan
.vars
;
18570 confp
->chan
.vars
= tmpvar
;
18575 } else if (!strcasecmp(v
->name
, "immediate")) {
18576 confp
->chan
.immediate
= ast_true(v
->value
);
18577 } else if (!strcasecmp(v
->name
, "immediatering")) {
18578 confp
->chan
.immediatering
= ast_true(v
->value
);
18579 } else if (!strcasecmp(v
->name
, "transfertobusy")) {
18580 confp
->chan
.transfertobusy
= ast_true(v
->value
);
18581 } else if (!strcasecmp(v
->name
, "dialmode")) {
18582 if (!strcasecmp(v
->value
, "pulse")) {
18583 confp
->chan
.dialmode
= ANALOG_DIALMODE_PULSE
;
18584 } else if (!strcasecmp(v
->value
, "dtmf") || !strcasecmp(v
->value
, "tone")) {
18585 confp
->chan
.dialmode
= ANALOG_DIALMODE_DTMF
;
18586 } else if (!strcasecmp(v
->value
, "none")) {
18587 confp
->chan
.dialmode
= ANALOG_DIALMODE_NONE
;
18589 confp
->chan
.dialmode
= ANALOG_DIALMODE_BOTH
;
18591 } else if (!strcasecmp(v
->name
, "mwimonitor")) {
18592 confp
->chan
.mwimonitor_neon
= 0;
18593 confp
->chan
.mwimonitor_fsk
= 0;
18594 confp
->chan
.mwimonitor_rpas
= 0;
18595 if (strcasestr(v
->value
, "fsk")) {
18596 confp
->chan
.mwimonitor_fsk
= 1;
18598 if (strcasestr(v
->value
, "rpas")) {
18599 confp
->chan
.mwimonitor_rpas
= 1;
18601 if (strcasestr(v
->value
, "neon")) {
18602 confp
->chan
.mwimonitor_neon
= 1;
18604 /* If set to true or yes, assume that simple fsk is desired */
18605 if (ast_true(v
->value
)) {
18606 confp
->chan
.mwimonitor_fsk
= 1;
18608 } else if (!strcasecmp(v
->name
, "hwrxgain")) {
18609 confp
->chan
.hwrxgain_enabled
= 0;
18610 if (strcasecmp(v
->value
, "disabled")) {
18611 if (sscanf(v
->value
, "%30f", &confp
->chan
.hwrxgain
) == 1) {
18612 confp
->chan
.hwrxgain_enabled
= 1;
18614 ast_log(LOG_WARNING
, "Invalid hwrxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18617 } else if (!strcasecmp(v
->name
, "hwtxgain")) {
18618 confp
->chan
.hwtxgain_enabled
= 0;
18619 if (strcasecmp(v
->value
, "disabled")) {
18620 if (sscanf(v
->value
, "%30f", &confp
->chan
.hwtxgain
) == 1) {
18621 confp
->chan
.hwtxgain_enabled
= 1;
18623 ast_log(LOG_WARNING
, "Invalid hwtxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18626 } else if (!strcasecmp(v
->name
, "cid_rxgain")) {
18627 if (sscanf(v
->value
, "%30f", &confp
->chan
.cid_rxgain
) != 1) {
18628 ast_log(LOG_WARNING
, "Invalid cid_rxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18630 } else if (!strcasecmp(v
->name
, "rxgain")) {
18631 if (sscanf(v
->value
, "%30f", &confp
->chan
.rxgain
) != 1) {
18632 ast_log(LOG_WARNING
, "Invalid rxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18634 } else if (!strcasecmp(v
->name
, "txgain")) {
18635 if (sscanf(v
->value
, "%30f", &confp
->chan
.txgain
) != 1) {
18636 ast_log(LOG_WARNING
, "Invalid txgain: %s at line %d.\n", v
->value
, v
->lineno
);
18638 } else if (!strcasecmp(v
->name
, "txdrc")) {
18639 if (sscanf(v
->value
, "%f", &confp
->chan
.txdrc
) != 1) {
18640 ast_log(LOG_WARNING
, "Invalid txdrc: %s\n", v
->value
);
18642 } else if (!strcasecmp(v
->name
, "rxdrc")) {
18643 if (sscanf(v
->value
, "%f", &confp
->chan
.rxdrc
) != 1) {
18644 ast_log(LOG_WARNING
, "Invalid rxdrc: %s\n", v
->value
);
18646 } else if (!strcasecmp(v
->name
, "tonezone")) {
18647 if (sscanf(v
->value
, "%30d", &confp
->chan
.tonezone
) != 1) {
18648 ast_log(LOG_WARNING
, "Invalid tonezone: %s at line %d.\n", v
->value
, v
->lineno
);
18650 } else if (!strcasecmp(v
->name
, "callerid")) {
18651 if (!strcasecmp(v
->value
, "asreceived")) {
18652 confp
->chan
.cid_num
[0] = '\0';
18653 confp
->chan
.cid_name
[0] = '\0';
18655 ast_callerid_split(v
->value
, confp
->chan
.cid_name
, sizeof(confp
->chan
.cid_name
), confp
->chan
.cid_num
, sizeof(confp
->chan
.cid_num
));
18657 } else if (!strcasecmp(v
->name
, "fullname")) {
18658 ast_copy_string(confp
->chan
.cid_name
, v
->value
, sizeof(confp
->chan
.cid_name
));
18659 } else if (!strcasecmp(v
->name
, "cid_number")) {
18660 ast_copy_string(confp
->chan
.cid_num
, v
->value
, sizeof(confp
->chan
.cid_num
));
18661 } else if (!strcasecmp(v
->name
, "cid_tag")) {
18662 ast_copy_string(confp
->chan
.cid_tag
, v
->value
, sizeof(confp
->chan
.cid_tag
));
18663 } else if (!strcasecmp(v
->name
, "useincomingcalleridondahditransfer")) {
18664 confp
->chan
.dahditrcallerid
= ast_true(v
->value
);
18665 } else if (!strcasecmp(v
->name
, "restrictcid")) {
18666 confp
->chan
.restrictcid
= ast_true(v
->value
);
18667 } else if (!strcasecmp(v
->name
, "usecallingpres")) {
18668 confp
->chan
.use_callingpres
= ast_true(v
->value
);
18669 } else if (!strcasecmp(v
->name
, "accountcode")) {
18670 ast_copy_string(confp
->chan
.accountcode
, v
->value
, sizeof(confp
->chan
.accountcode
));
18671 } else if (!strcasecmp(v
->name
, "amaflags")) {
18672 y
= ast_channel_string2amaflag(v
->value
);
18674 ast_log(LOG_WARNING
, "Invalid AMA flags: %s at line %d.\n", v
->value
, v
->lineno
);
18676 confp
->chan
.amaflags
= y
;
18677 } else if (!strcasecmp(v
->name
, "polarityonanswerdelay")) {
18678 confp
->chan
.polarityonanswerdelay
= atoi(v
->value
);
18679 } else if (!strcasecmp(v
->name
, "answeronpolarityswitch")) {
18680 confp
->chan
.answeronpolarityswitch
= ast_true(v
->value
);
18681 } else if (!strcasecmp(v
->name
, "ani_info_digits")) {
18682 confp
->chan
.ani_info_digits
= atoi(v
->value
);
18683 } else if (!strcasecmp(v
->name
, "ani_wink_time")) {
18684 confp
->chan
.ani_wink_time
= atoi(v
->value
);
18685 } else if (!strcasecmp(v
->name
, "ani_timeout")) {
18686 confp
->chan
.ani_timeout
= atoi(v
->value
);
18687 } else if (!strcasecmp(v
->name
, "hanguponpolarityswitch")) {
18688 confp
->chan
.hanguponpolarityswitch
= ast_true(v
->value
);
18689 } else if (!strcasecmp(v
->name
, "autoreoriginate")) {
18690 confp
->chan
.reoriginate
= ast_true(v
->value
);
18691 } else if (!strcasecmp(v
->name
, "sendcalleridafter")) {
18692 confp
->chan
.sendcalleridafter
= atoi(v
->value
);
18693 } else if (!strcasecmp(v
->name
, "mwimonitornotify")) {
18694 ast_copy_string(mwimonitornotify
, v
->value
, sizeof(mwimonitornotify
));
18695 } else if (ast_cc_is_config_param(v
->name
)) {
18696 ast_cc_set_param(confp
->chan
.cc_params
, v
->name
, v
->value
);
18697 } else if (!strcasecmp(v
->name
, "mwisendtype")) {
18698 #ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
18699 if (!strcasecmp(v
->value
, "rpas")) { /* Ring Pulse Alert Signal */
18705 /* Default is fsk, to turn it off you must specify nofsk */
18706 memset(&confp
->chan
.mwisend_setting
, 0, sizeof(confp
->chan
.mwisend_setting
));
18707 if (strcasestr(v
->value
, "nofsk")) { /* NoFSK */
18708 confp
->chan
.mwisend_fsk
= 0;
18709 } else { /* Default FSK */
18710 confp
->chan
.mwisend_fsk
= 1;
18712 if (strcasestr(v
->value
, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
18713 confp
->chan
.mwisend_rpas
= 1;
18715 confp
->chan
.mwisend_rpas
= 0;
18717 if (strcasestr(v
->value
, "lrev")) { /* Line Reversal */
18718 confp
->chan
.mwisend_setting
.vmwi_type
|= DAHDI_VMWI_LREV
;
18720 if (strcasestr(v
->value
, "hvdc")) { /* HV 90VDC */
18721 confp
->chan
.mwisend_setting
.vmwi_type
|= DAHDI_VMWI_HVDC
;
18723 if ( (strcasestr(v
->value
, "neon")) || (strcasestr(v
->value
, "hvac")) ) { /* 90V DC pulses */
18724 confp
->chan
.mwisend_setting
.vmwi_type
|= DAHDI_VMWI_HVAC
;
18727 } else if (reload
!= 1) {
18728 if (!strcasecmp(v
->name
, "signalling") || !strcasecmp(v
->name
, "signaling")) {
18729 int orig_radio
= confp
->chan
.radio
;
18730 int orig_outsigmod
= confp
->chan
.outsigmod
;
18731 int orig_auto
= confp
->is_sig_auto
;
18733 confp
->chan
.radio
= 0;
18734 confp
->chan
.outsigmod
= -1;
18735 confp
->is_sig_auto
= 0;
18736 if (!strcasecmp(v
->value
, "em")) {
18737 confp
->chan
.sig
= SIG_EM
;
18738 } else if (!strcasecmp(v
->value
, "em_e1")) {
18739 confp
->chan
.sig
= SIG_EM_E1
;
18740 } else if (!strcasecmp(v
->value
, "em_w")) {
18741 confp
->chan
.sig
= SIG_EMWINK
;
18742 } else if (!strcasecmp(v
->value
, "fxs_ls")) {
18743 confp
->chan
.sig
= SIG_FXSLS
;
18744 } else if (!strcasecmp(v
->value
, "fxs_gs")) {
18745 confp
->chan
.sig
= SIG_FXSGS
;
18746 } else if (!strcasecmp(v
->value
, "fxs_ks")) {
18747 confp
->chan
.sig
= SIG_FXSKS
;
18748 } else if (!strcasecmp(v
->value
, "fxo_ls")) {
18749 confp
->chan
.sig
= SIG_FXOLS
;
18750 } else if (!strcasecmp(v
->value
, "fxo_gs")) {
18751 confp
->chan
.sig
= SIG_FXOGS
;
18752 } else if (!strcasecmp(v
->value
, "fxo_ks")) {
18753 confp
->chan
.sig
= SIG_FXOKS
;
18754 } else if (!strcasecmp(v
->value
, "fxs_rx")) {
18755 confp
->chan
.sig
= SIG_FXSKS
;
18756 confp
->chan
.radio
= 1;
18757 } else if (!strcasecmp(v
->value
, "fxo_rx")) {
18758 confp
->chan
.sig
= SIG_FXOLS
;
18759 confp
->chan
.radio
= 1;
18760 } else if (!strcasecmp(v
->value
, "fxs_tx")) {
18761 confp
->chan
.sig
= SIG_FXSLS
;
18762 confp
->chan
.radio
= 1;
18763 } else if (!strcasecmp(v
->value
, "fxo_tx")) {
18764 confp
->chan
.sig
= SIG_FXOGS
;
18765 confp
->chan
.radio
= 1;
18766 } else if (!strcasecmp(v
->value
, "em_rx")) {
18767 confp
->chan
.sig
= SIG_EM
;
18768 confp
->chan
.radio
= 1;
18769 } else if (!strcasecmp(v
->value
, "em_tx")) {
18770 confp
->chan
.sig
= SIG_EM
;
18771 confp
->chan
.radio
= 1;
18772 } else if (!strcasecmp(v
->value
, "em_rxtx")) {
18773 confp
->chan
.sig
= SIG_EM
;
18774 confp
->chan
.radio
= 2;
18775 } else if (!strcasecmp(v
->value
, "em_txrx")) {
18776 confp
->chan
.sig
= SIG_EM
;
18777 confp
->chan
.radio
= 2;
18778 } else if (!strcasecmp(v
->value
, "sf")) {
18779 confp
->chan
.sig
= SIG_SF
;
18780 } else if (!strcasecmp(v
->value
, "sf_w")) {
18781 confp
->chan
.sig
= SIG_SFWINK
;
18782 } else if (!strcasecmp(v
->value
, "sf_featd")) {
18783 confp
->chan
.sig
= SIG_FEATD
;
18784 } else if (!strcasecmp(v
->value
, "sf_featdmf")) {
18785 confp
->chan
.sig
= SIG_FEATDMF
;
18786 } else if (!strcasecmp(v
->value
, "sf_featb")) {
18787 confp
->chan
.sig
= SIG_SF_FEATB
;
18788 } else if (!strcasecmp(v
->value
, "sf")) {
18789 confp
->chan
.sig
= SIG_SF
;
18790 } else if (!strcasecmp(v
->value
, "sf_rx")) {
18791 confp
->chan
.sig
= SIG_SF
;
18792 confp
->chan
.radio
= 1;
18793 } else if (!strcasecmp(v
->value
, "sf_tx")) {
18794 confp
->chan
.sig
= SIG_SF
;
18795 confp
->chan
.radio
= 1;
18796 } else if (!strcasecmp(v
->value
, "sf_rxtx")) {
18797 confp
->chan
.sig
= SIG_SF
;
18798 confp
->chan
.radio
= 2;
18799 } else if (!strcasecmp(v
->value
, "sf_txrx")) {
18800 confp
->chan
.sig
= SIG_SF
;
18801 confp
->chan
.radio
= 2;
18802 } else if (!strcasecmp(v
->value
, "featd")) {
18803 confp
->chan
.sig
= SIG_FEATD
;
18804 } else if (!strcasecmp(v
->value
, "featdmf")) {
18805 confp
->chan
.sig
= SIG_FEATDMF
;
18806 } else if (!strcasecmp(v
->value
, "featdmf_ta")) {
18807 confp
->chan
.sig
= SIG_FEATDMF_TA
;
18808 } else if (!strcasecmp(v
->value
, "e911")) {
18809 confp
->chan
.sig
= SIG_E911
;
18810 } else if (!strcasecmp(v
->value
, "fgccama")) {
18811 confp
->chan
.sig
= SIG_FGC_CAMA
;
18812 } else if (!strcasecmp(v
->value
, "fgccamamf")) {
18813 confp
->chan
.sig
= SIG_FGC_CAMAMF
;
18814 } else if (!strcasecmp(v
->value
, "featb")) {
18815 confp
->chan
.sig
= SIG_FEATB
;
18817 } else if (!strcasecmp(v
->value
, "pri_net")) {
18818 confp
->chan
.sig
= SIG_PRI
;
18819 confp
->pri
.pri
.nodetype
= PRI_NETWORK
;
18820 } else if (!strcasecmp(v
->value
, "pri_cpe")) {
18821 confp
->chan
.sig
= SIG_PRI
;
18822 confp
->pri
.pri
.nodetype
= PRI_CPE
;
18823 } else if (!strcasecmp(v
->value
, "bri_cpe")) {
18824 confp
->chan
.sig
= SIG_BRI
;
18825 confp
->pri
.pri
.nodetype
= PRI_CPE
;
18826 } else if (!strcasecmp(v
->value
, "bri_net")) {
18827 confp
->chan
.sig
= SIG_BRI
;
18828 confp
->pri
.pri
.nodetype
= PRI_NETWORK
;
18829 } else if (!strcasecmp(v
->value
, "bri_cpe_ptmp")) {
18830 confp
->chan
.sig
= SIG_BRI_PTMP
;
18831 confp
->pri
.pri
.nodetype
= PRI_CPE
;
18832 } else if (!strcasecmp(v
->value
, "bri_net_ptmp")) {
18833 #if defined(HAVE_PRI_CALL_HOLD)
18834 confp
->chan
.sig
= SIG_BRI_PTMP
;
18835 confp
->pri
.pri
.nodetype
= PRI_NETWORK
;
18837 ast_log(LOG_WARNING
, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v
->lineno
);
18838 #endif /* !defined(HAVE_PRI_CALL_HOLD) */
18840 #if defined(HAVE_SS7)
18841 } else if (!strcasecmp(v
->value
, "ss7")) {
18842 confp
->chan
.sig
= SIG_SS7
;
18843 #endif /* defined(HAVE_SS7) */
18845 } else if (!strcasecmp(v
->value
, "mfcr2")) {
18846 confp
->chan
.sig
= SIG_MFCR2
;
18848 } else if (!strcasecmp(v
->value
, "auto")) {
18849 confp
->is_sig_auto
= 1;
18851 confp
->chan
.outsigmod
= orig_outsigmod
;
18852 confp
->chan
.radio
= orig_radio
;
18853 confp
->is_sig_auto
= orig_auto
;
18854 ast_log(LOG_ERROR
, "Unknown signalling method '%s' at line %d.\n", v
->value
, v
->lineno
);
18856 } else if (!strcasecmp(v
->name
, "outsignalling") || !strcasecmp(v
->name
, "outsignaling")) {
18857 if (!strcasecmp(v
->value
, "em")) {
18858 confp
->chan
.outsigmod
= SIG_EM
;
18859 } else if (!strcasecmp(v
->value
, "em_e1")) {
18860 confp
->chan
.outsigmod
= SIG_EM_E1
;
18861 } else if (!strcasecmp(v
->value
, "em_w")) {
18862 confp
->chan
.outsigmod
= SIG_EMWINK
;
18863 } else if (!strcasecmp(v
->value
, "sf")) {
18864 confp
->chan
.outsigmod
= SIG_SF
;
18865 } else if (!strcasecmp(v
->value
, "sf_w")) {
18866 confp
->chan
.outsigmod
= SIG_SFWINK
;
18867 } else if (!strcasecmp(v
->value
, "sf_featd")) {
18868 confp
->chan
.outsigmod
= SIG_FEATD
;
18869 } else if (!strcasecmp(v
->value
, "sf_featdmf")) {
18870 confp
->chan
.outsigmod
= SIG_FEATDMF
;
18871 } else if (!strcasecmp(v
->value
, "sf_featb")) {
18872 confp
->chan
.outsigmod
= SIG_SF_FEATB
;
18873 } else if (!strcasecmp(v
->value
, "sf")) {
18874 confp
->chan
.outsigmod
= SIG_SF
;
18875 } else if (!strcasecmp(v
->value
, "featd")) {
18876 confp
->chan
.outsigmod
= SIG_FEATD
;
18877 } else if (!strcasecmp(v
->value
, "featdmf")) {
18878 confp
->chan
.outsigmod
= SIG_FEATDMF
;
18879 } else if (!strcasecmp(v
->value
, "featdmf_ta")) {
18880 confp
->chan
.outsigmod
= SIG_FEATDMF_TA
;
18881 } else if (!strcasecmp(v
->value
, "e911")) {
18882 confp
->chan
.outsigmod
= SIG_E911
;
18883 } else if (!strcasecmp(v
->value
, "fgccama")) {
18884 confp
->chan
.outsigmod
= SIG_FGC_CAMA
;
18885 } else if (!strcasecmp(v
->value
, "fgccamamf")) {
18886 confp
->chan
.outsigmod
= SIG_FGC_CAMAMF
;
18887 } else if (!strcasecmp(v
->value
, "featb")) {
18888 confp
->chan
.outsigmod
= SIG_FEATB
;
18890 ast_log(LOG_ERROR
, "Unknown signalling method '%s' at line %d.\n", v
->value
, v
->lineno
);
18893 } else if (!strcasecmp(v
->name
, "pridialplan")) {
18894 if (!strcasecmp(v
->value
, "national")) {
18895 confp
->pri
.pri
.dialplan
= PRI_NATIONAL_ISDN
+ 1;
18896 } else if (!strcasecmp(v
->value
, "unknown")) {
18897 confp
->pri
.pri
.dialplan
= PRI_UNKNOWN
+ 1;
18898 } else if (!strcasecmp(v
->value
, "private")) {
18899 confp
->pri
.pri
.dialplan
= PRI_PRIVATE
+ 1;
18900 } else if (!strcasecmp(v
->value
, "international")) {
18901 confp
->pri
.pri
.dialplan
= PRI_INTERNATIONAL_ISDN
+ 1;
18902 } else if (!strcasecmp(v
->value
, "local")) {
18903 confp
->pri
.pri
.dialplan
= PRI_LOCAL_ISDN
+ 1;
18904 } else if (!strcasecmp(v
->value
, "dynamic")) {
18905 confp
->pri
.pri
.dialplan
= -1;
18906 } else if (!strcasecmp(v
->value
, "redundant")) {
18907 confp
->pri
.pri
.dialplan
= -2;
18909 ast_log(LOG_WARNING
, "Unknown PRI dialplan '%s' at line %d.\n", v
->value
, v
->lineno
);
18911 } else if (!strcasecmp(v
->name
, "prilocaldialplan")) {
18912 if (!strcasecmp(v
->value
, "national")) {
18913 confp
->pri
.pri
.localdialplan
= PRI_NATIONAL_ISDN
+ 1;
18914 } else if (!strcasecmp(v
->value
, "unknown")) {
18915 confp
->pri
.pri
.localdialplan
= PRI_UNKNOWN
+ 1;
18916 } else if (!strcasecmp(v
->value
, "private")) {
18917 confp
->pri
.pri
.localdialplan
= PRI_PRIVATE
+ 1;
18918 } else if (!strcasecmp(v
->value
, "international")) {
18919 confp
->pri
.pri
.localdialplan
= PRI_INTERNATIONAL_ISDN
+ 1;
18920 } else if (!strcasecmp(v
->value
, "local")) {
18921 confp
->pri
.pri
.localdialplan
= PRI_LOCAL_ISDN
+ 1;
18922 } else if (!strcasecmp(v
->value
, "from_channel")) {
18923 confp
->pri
.pri
.localdialplan
= 0;
18924 } else if (!strcasecmp(v
->value
, "dynamic")) {
18925 confp
->pri
.pri
.localdialplan
= -1;
18926 } else if (!strcasecmp(v
->value
, "redundant")) {
18927 confp
->pri
.pri
.localdialplan
= -2;
18929 ast_log(LOG_WARNING
, "Unknown PRI localdialplan '%s' at line %d.\n", v
->value
, v
->lineno
);
18931 } else if (!strcasecmp(v
->name
, "pricpndialplan")) {
18932 if (!strcasecmp(v
->value
, "national")) {
18933 confp
->pri
.pri
.cpndialplan
= PRI_NATIONAL_ISDN
+ 1;
18934 } else if (!strcasecmp(v
->value
, "unknown")) {
18935 confp
->pri
.pri
.cpndialplan
= PRI_UNKNOWN
+ 1;
18936 } else if (!strcasecmp(v
->value
, "private")) {
18937 confp
->pri
.pri
.cpndialplan
= PRI_PRIVATE
+ 1;
18938 } else if (!strcasecmp(v
->value
, "international")) {
18939 confp
->pri
.pri
.cpndialplan
= PRI_INTERNATIONAL_ISDN
+ 1;
18940 } else if (!strcasecmp(v
->value
, "local")) {
18941 confp
->pri
.pri
.cpndialplan
= PRI_LOCAL_ISDN
+ 1;
18942 } else if (!strcasecmp(v
->value
, "from_channel")) {
18943 confp
->pri
.pri
.cpndialplan
= 0;
18944 } else if (!strcasecmp(v
->value
, "dynamic")) {
18945 confp
->pri
.pri
.cpndialplan
= -1;
18946 } else if (!strcasecmp(v
->value
, "redundant")) {
18947 confp
->pri
.pri
.cpndialplan
= -2;
18949 ast_log(LOG_WARNING
, "Unknown PRI cpndialplan '%s' at line %d.\n", v
->value
, v
->lineno
);
18951 } else if (!strcasecmp(v
->name
, "switchtype")) {
18952 if (!strcasecmp(v
->value
, "national"))
18953 confp
->pri
.pri
.switchtype
= PRI_SWITCH_NI2
;
18954 else if (!strcasecmp(v
->value
, "ni1"))
18955 confp
->pri
.pri
.switchtype
= PRI_SWITCH_NI1
;
18956 else if (!strcasecmp(v
->value
, "dms100"))
18957 confp
->pri
.pri
.switchtype
= PRI_SWITCH_DMS100
;
18958 else if (!strcasecmp(v
->value
, "4ess"))
18959 confp
->pri
.pri
.switchtype
= PRI_SWITCH_ATT4ESS
;
18960 else if (!strcasecmp(v
->value
, "5ess"))
18961 confp
->pri
.pri
.switchtype
= PRI_SWITCH_LUCENT5E
;
18962 else if (!strcasecmp(v
->value
, "euroisdn"))
18963 confp
->pri
.pri
.switchtype
= PRI_SWITCH_EUROISDN_E1
;
18964 else if (!strcasecmp(v
->value
, "qsig"))
18965 confp
->pri
.pri
.switchtype
= PRI_SWITCH_QSIG
;
18967 ast_log(LOG_ERROR
, "Unknown switchtype '%s' at line %d.\n", v
->value
, v
->lineno
);
18970 } else if (!strcasecmp(v
->name
, "msn")) {
18971 ast_copy_string(confp
->pri
.pri
.msn_list
, v
->value
,
18972 sizeof(confp
->pri
.pri
.msn_list
));
18973 } else if (!strcasecmp(v
->name
, "nsf")) {
18974 if (!strcasecmp(v
->value
, "sdn"))
18975 confp
->pri
.pri
.nsf
= PRI_NSF_SDN
;
18976 else if (!strcasecmp(v
->value
, "megacom"))
18977 confp
->pri
.pri
.nsf
= PRI_NSF_MEGACOM
;
18978 else if (!strcasecmp(v
->value
, "tollfreemegacom"))
18979 confp
->pri
.pri
.nsf
= PRI_NSF_TOLL_FREE_MEGACOM
;
18980 else if (!strcasecmp(v
->value
, "accunet"))
18981 confp
->pri
.pri
.nsf
= PRI_NSF_ACCUNET
;
18982 else if (!strcasecmp(v
->value
, "none"))
18983 confp
->pri
.pri
.nsf
= PRI_NSF_NONE
;
18985 ast_log(LOG_WARNING
, "Unknown network-specific facility '%s' at line %d.\n", v
->value
, v
->lineno
);
18986 confp
->pri
.pri
.nsf
= PRI_NSF_NONE
;
18988 } else if (!strcasecmp(v
->name
, "priindication")) {
18989 if (!strcasecmp(v
->value
, "outofband"))
18990 confp
->chan
.priindication_oob
= 1;
18991 else if (!strcasecmp(v
->value
, "inband"))
18992 confp
->chan
.priindication_oob
= 0;
18994 ast_log(LOG_WARNING
, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
18995 v
->value
, v
->lineno
);
18996 } else if (!strcasecmp(v
->name
, "priexclusive")) {
18997 confp
->chan
.priexclusive
= ast_true(v
->value
);
18998 } else if (!strcasecmp(v
->name
, "internationalprefix")) {
18999 ast_copy_string(confp
->pri
.pri
.internationalprefix
, v
->value
, sizeof(confp
->pri
.pri
.internationalprefix
));
19000 } else if (!strcasecmp(v
->name
, "nationalprefix")) {
19001 ast_copy_string(confp
->pri
.pri
.nationalprefix
, v
->value
, sizeof(confp
->pri
.pri
.nationalprefix
));
19002 } else if (!strcasecmp(v
->name
, "localprefix")) {
19003 ast_copy_string(confp
->pri
.pri
.localprefix
, v
->value
, sizeof(confp
->pri
.pri
.localprefix
));
19004 } else if (!strcasecmp(v
->name
, "privateprefix")) {
19005 ast_copy_string(confp
->pri
.pri
.privateprefix
, v
->value
, sizeof(confp
->pri
.pri
.privateprefix
));
19006 } else if (!strcasecmp(v
->name
, "unknownprefix")) {
19007 ast_copy_string(confp
->pri
.pri
.unknownprefix
, v
->value
, sizeof(confp
->pri
.pri
.unknownprefix
));
19008 } else if (!strcasecmp(v
->name
, "resetinterval")) {
19009 if (!strcasecmp(v
->value
, "never"))
19010 confp
->pri
.pri
.resetinterval
= -1;
19011 else if (atoi(v
->value
) >= 60)
19012 confp
->pri
.pri
.resetinterval
= atoi(v
->value
);
19014 ast_log(LOG_WARNING
, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
19015 v
->value
, v
->lineno
);
19016 } else if (!strcasecmp(v
->name
, "force_restart_unavailable_chans")) {
19017 confp
->pri
.pri
.force_restart_unavailable_chans
= ast_true(v
->value
);
19018 } else if (!strcasecmp(v
->name
, "minunused")) {
19019 confp
->pri
.pri
.minunused
= atoi(v
->value
);
19020 } else if (!strcasecmp(v
->name
, "minidle")) {
19021 confp
->pri
.pri
.minidle
= atoi(v
->value
);
19022 } else if (!strcasecmp(v
->name
, "idleext")) {
19023 ast_copy_string(confp
->pri
.pri
.idleext
, v
->value
, sizeof(confp
->pri
.pri
.idleext
));
19024 } else if (!strcasecmp(v
->name
, "idledial")) {
19025 ast_copy_string(confp
->pri
.pri
.idledial
, v
->value
, sizeof(confp
->pri
.pri
.idledial
));
19026 } else if (!strcasecmp(v
->name
, "overlapdial")) {
19027 if (ast_true(v
->value
)) {
19028 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_BOTH
;
19029 } else if (!strcasecmp(v
->value
, "incoming")) {
19030 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_INCOMING
;
19031 } else if (!strcasecmp(v
->value
, "outgoing")) {
19032 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_OUTGOING
;
19033 } else if (!strcasecmp(v
->value
, "both") || ast_true(v
->value
)) {
19034 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_BOTH
;
19036 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_NONE
;
19038 #ifdef HAVE_PRI_PROG_W_CAUSE
19039 } else if (!strcasecmp(v
->name
, "qsigchannelmapping")) {
19040 if (!strcasecmp(v
->value
, "logical")) {
19041 confp
->pri
.pri
.qsigchannelmapping
= DAHDI_CHAN_MAPPING_LOGICAL
;
19042 } else if (!strcasecmp(v
->value
, "physical")) {
19043 confp
->pri
.pri
.qsigchannelmapping
= DAHDI_CHAN_MAPPING_PHYSICAL
;
19045 confp
->pri
.pri
.qsigchannelmapping
= DAHDI_CHAN_MAPPING_PHYSICAL
;
19048 } else if (!strcasecmp(v
->name
, "discardremoteholdretrieval")) {
19049 confp
->pri
.pri
.discardremoteholdretrieval
= ast_true(v
->value
);
19050 #if defined(HAVE_PRI_SERVICE_MESSAGES)
19051 } else if (!strcasecmp(v
->name
, "service_message_support")) {
19052 /* assuming switchtype for this channel group has been configured already */
19053 if ((confp
->pri
.pri
.switchtype
== PRI_SWITCH_ATT4ESS
19054 || confp
->pri
.pri
.switchtype
== PRI_SWITCH_LUCENT5E
19055 || confp
->pri
.pri
.switchtype
== PRI_SWITCH_NI2
) && ast_true(v
->value
)) {
19056 confp
->pri
.pri
.enable_service_message_support
= 1;
19058 confp
->pri
.pri
.enable_service_message_support
= 0;
19060 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
19061 #ifdef HAVE_PRI_INBANDDISCONNECT
19062 } else if (!strcasecmp(v
->name
, "inbanddisconnect")) {
19063 confp
->pri
.pri
.inbanddisconnect
= ast_true(v
->value
);
19065 } else if (!strcasecmp(v
->name
, "pritimer")) {
19066 #ifdef PRI_GETSET_TIMERS
19073 ast_copy_string(tmp
, v
->value
, sizeof(tmp
));
19075 timerc
= strsep(&c
, ",");
19076 if (!ast_strlen_zero(timerc
) && !ast_strlen_zero(c
)) {
19077 timeridx
= pri_timer2idx(timerc
);
19079 if (timeridx
< 0 || PRI_MAX_TIMERS
<= timeridx
) {
19080 ast_log(LOG_WARNING
,
19081 "'%s' is not a valid ISDN timer at line %d.\n", timerc
,
19083 } else if (!timer
) {
19084 ast_log(LOG_WARNING
,
19085 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19086 c
, timerc
, v
->lineno
);
19088 confp
->pri
.pri
.pritimers
[timeridx
] = timer
;
19091 ast_log(LOG_WARNING
,
19092 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19093 v
->value
, v
->lineno
);
19095 #endif /* PRI_GETSET_TIMERS */
19096 } else if (!strcasecmp(v
->name
, "facilityenable")) {
19097 confp
->pri
.pri
.facilityenable
= ast_true(v
->value
);
19098 #if defined(HAVE_PRI_AOC_EVENTS)
19099 } else if (!strcasecmp(v
->name
, "aoc_enable")) {
19100 confp
->pri
.pri
.aoc_passthrough_flag
= 0;
19101 if (strchr(v
->value
, 's') || strchr(v
->value
, 'S')) {
19102 confp
->pri
.pri
.aoc_passthrough_flag
|= SIG_PRI_AOC_GRANT_S
;
19104 if (strchr(v
->value
, 'd') || strchr(v
->value
, 'D')) {
19105 confp
->pri
.pri
.aoc_passthrough_flag
|= SIG_PRI_AOC_GRANT_D
;
19107 if (strchr(v
->value
, 'e') || strchr(v
->value
, 'E')) {
19108 confp
->pri
.pri
.aoc_passthrough_flag
|= SIG_PRI_AOC_GRANT_E
;
19110 } else if (!strcasecmp(v
->name
, "aoce_delayhangup")) {
19111 confp
->pri
.pri
.aoce_delayhangup
= ast_true(v
->value
);
19112 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
19113 #if defined(HAVE_PRI_CALL_HOLD)
19114 } else if (!strcasecmp(v
->name
, "hold_disconnect_transfer")) {
19115 confp
->pri
.pri
.hold_disconnect_transfer
= ast_true(v
->value
);
19116 #endif /* defined(HAVE_PRI_CALL_HOLD) */
19117 } else if (!strcasecmp(v
->name
, "moh_signaling")
19118 || !strcasecmp(v
->name
, "moh_signalling")) {
19119 if (!strcasecmp(v
->value
, "moh")) {
19120 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_MOH
;
19121 } else if (!strcasecmp(v
->value
, "notify")) {
19122 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_NOTIFY
;
19123 #if defined(HAVE_PRI_CALL_HOLD)
19124 } else if (!strcasecmp(v
->value
, "hold")) {
19125 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_HOLD
;
19126 #endif /* defined(HAVE_PRI_CALL_HOLD) */
19128 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_MOH
;
19130 #if defined(HAVE_PRI_CCSS)
19131 } else if (!strcasecmp(v
->name
, "cc_ptmp_recall_mode")) {
19132 if (!strcasecmp(v
->value
, "global")) {
19133 confp
->pri
.pri
.cc_ptmp_recall_mode
= 0;/* globalRecall */
19134 } else if (!strcasecmp(v
->value
, "specific")) {
19135 confp
->pri
.pri
.cc_ptmp_recall_mode
= 1;/* specificRecall */
19137 confp
->pri
.pri
.cc_ptmp_recall_mode
= 1;/* specificRecall */
19139 } else if (!strcasecmp(v
->name
, "cc_qsig_signaling_link_req")) {
19140 if (!strcasecmp(v
->value
, "release")) {
19141 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 0;/* release */
19142 } else if (!strcasecmp(v
->value
, "retain")) {
19143 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 1;/* retain */
19144 } else if (!strcasecmp(v
->value
, "do_not_care")) {
19145 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 2;/* do-not-care */
19147 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 1;/* retain */
19149 } else if (!strcasecmp(v
->name
, "cc_qsig_signaling_link_rsp")) {
19150 if (!strcasecmp(v
->value
, "release")) {
19151 confp
->pri
.pri
.cc_qsig_signaling_link_rsp
= 0;/* release */
19152 } else if (!strcasecmp(v
->value
, "retain")) {
19153 confp
->pri
.pri
.cc_qsig_signaling_link_rsp
= 1;/* retain */
19155 confp
->pri
.pri
.cc_qsig_signaling_link_rsp
= 1;/* retain */
19157 #endif /* defined(HAVE_PRI_CCSS) */
19158 #if defined(HAVE_PRI_CALL_WAITING)
19159 } else if (!strcasecmp(v
->name
, "max_call_waiting_calls")) {
19160 confp
->pri
.pri
.max_call_waiting_calls
= atoi(v
->value
);
19161 if (confp
->pri
.pri
.max_call_waiting_calls
< 0) {
19162 /* Negative values are not allowed. */
19163 confp
->pri
.pri
.max_call_waiting_calls
= 0;
19165 } else if (!strcasecmp(v
->name
, "allow_call_waiting_calls")) {
19166 confp
->pri
.pri
.allow_call_waiting_calls
= ast_true(v
->value
);
19167 #endif /* defined(HAVE_PRI_CALL_WAITING) */
19168 #if defined(HAVE_PRI_MWI)
19169 } else if (!strcasecmp(v
->name
, "mwi_mailboxes")) {
19170 ast_copy_string(confp
->pri
.pri
.mwi_mailboxes
, v
->value
,
19171 sizeof(confp
->pri
.pri
.mwi_mailboxes
));
19172 } else if (!strcasecmp(v
->name
, "mwi_vm_boxes")) {
19173 ast_copy_string(confp
->pri
.pri
.mwi_vm_boxes
, v
->value
,
19174 sizeof(confp
->pri
.pri
.mwi_vm_boxes
));
19175 } else if (!strcasecmp(v
->name
, "mwi_vm_numbers")) {
19176 ast_copy_string(confp
->pri
.pri
.mwi_vm_numbers
, v
->value
,
19177 sizeof(confp
->pri
.pri
.mwi_vm_numbers
));
19178 #endif /* defined(HAVE_PRI_MWI) */
19179 } else if (!strcasecmp(v
->name
, "append_msn_to_cid_tag")) {
19180 confp
->pri
.pri
.append_msn_to_user_tag
= ast_true(v
->value
);
19181 } else if (!strcasecmp(v
->name
, "inband_on_setup_ack")) {
19182 confp
->pri
.pri
.inband_on_setup_ack
= ast_true(v
->value
);
19183 } else if (!strcasecmp(v
->name
, "inband_on_proceeding")) {
19184 confp
->pri
.pri
.inband_on_proceeding
= ast_true(v
->value
);
19185 #if defined(HAVE_PRI_DISPLAY_TEXT)
19186 } else if (!strcasecmp(v
->name
, "display_send")) {
19187 confp
->pri
.pri
.display_flags_send
= dahdi_display_text_option(v
->value
);
19188 } else if (!strcasecmp(v
->name
, "display_receive")) {
19189 confp
->pri
.pri
.display_flags_receive
= dahdi_display_text_option(v
->value
);
19190 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19191 #if defined(HAVE_PRI_MCID)
19192 } else if (!strcasecmp(v
->name
, "mcid_send")) {
19193 confp
->pri
.pri
.mcid_send
= ast_true(v
->value
);
19194 #endif /* defined(HAVE_PRI_MCID) */
19195 #if defined(HAVE_PRI_DATETIME_SEND)
19196 } else if (!strcasecmp(v
->name
, "datetime_send")) {
19197 confp
->pri
.pri
.datetime_send
= dahdi_datetime_send_option(v
->value
);
19198 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
19199 } else if (!strcasecmp(v
->name
, "layer1_presence")) {
19200 if (!strcasecmp(v
->value
, "required")) {
19201 confp
->pri
.pri
.layer1_ignored
= 0;
19202 } else if (!strcasecmp(v
->value
, "ignore")) {
19203 confp
->pri
.pri
.layer1_ignored
= 1;
19206 confp
->pri
.pri
.layer1_ignored
= 0;
19208 #if defined(HAVE_PRI_L2_PERSISTENCE)
19209 } else if (!strcasecmp(v
->name
, "layer2_persistence")) {
19210 if (!strcasecmp(v
->value
, "keep_up")) {
19211 confp
->pri
.pri
.l2_persistence
= PRI_L2_PERSISTENCE_KEEP_UP
;
19212 } else if (!strcasecmp(v
->value
, "leave_down")) {
19213 confp
->pri
.pri
.l2_persistence
= PRI_L2_PERSISTENCE_LEAVE_DOWN
;
19215 confp
->pri
.pri
.l2_persistence
= PRI_L2_PERSISTENCE_DEFAULT
;
19217 #endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19218 } else if (!strcasecmp(v
->name
, "colp_send")) {
19219 if (!strcasecmp(v
->value
, "block")) {
19220 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_BLOCK
;
19221 } else if (!strcasecmp(v
->value
, "connect")) {
19222 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_CONNECT
;
19223 } else if (!strcasecmp(v
->value
, "update")) {
19224 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_UPDATE
;
19226 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_UPDATE
;
19228 #endif /* HAVE_PRI */
19229 #if defined(HAVE_SS7)
19230 } else if (!strcasecmp(v
->name
, "ss7type")) {
19231 if (!strcasecmp(v
->value
, "itu")) {
19232 cur_ss7type
= SS7_ITU
;
19233 } else if (!strcasecmp(v
->value
, "ansi")) {
19234 cur_ss7type
= SS7_ANSI
;
19236 ast_log(LOG_WARNING
, "'%s' is an unknown ss7 switch type at line %d.!\n", v
->value
, v
->lineno
);
19238 } else if (!strcasecmp(v
->name
, "slc")) {
19239 cur_slc
= atoi(v
->value
);
19240 } else if (!strcasecmp(v
->name
, "linkset")) {
19241 cur_linkset
= atoi(v
->value
);
19242 } else if (!strcasecmp(v
->name
, "pointcode")) {
19243 cur_pointcode
= parse_pointcode(v
->value
);
19244 } else if (!strcasecmp(v
->name
, "adjpointcode")) {
19245 cur_adjpointcode
= parse_pointcode(v
->value
);
19246 } else if (!strcasecmp(v
->name
, "defaultdpc")) {
19247 cur_defaultdpc
= parse_pointcode(v
->value
);
19248 } else if (!strcasecmp(v
->name
, "cicbeginswith")) {
19249 cur_cicbeginswith
= atoi(v
->value
);
19250 } else if (!strcasecmp(v
->name
, "networkindicator")) {
19251 if (!strcasecmp(v
->value
, "national")) {
19252 cur_networkindicator
= SS7_NI_NAT
;
19253 } else if (!strcasecmp(v
->value
, "national_spare")) {
19254 cur_networkindicator
= SS7_NI_NAT_SPARE
;
19255 } else if (!strcasecmp(v
->value
, "international")) {
19256 cur_networkindicator
= SS7_NI_INT
;
19257 } else if (!strcasecmp(v
->value
, "international_spare")) {
19258 cur_networkindicator
= SS7_NI_INT_SPARE
;
19260 cur_networkindicator
= -1;
19262 } else if (!strcasecmp(v
->name
, "ss7_internationalprefix")) {
19263 ast_copy_string(confp
->ss7
.ss7
.internationalprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.internationalprefix
));
19264 } else if (!strcasecmp(v
->name
, "ss7_nationalprefix")) {
19265 ast_copy_string(confp
->ss7
.ss7
.nationalprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.nationalprefix
));
19266 } else if (!strcasecmp(v
->name
, "ss7_subscriberprefix")) {
19267 ast_copy_string(confp
->ss7
.ss7
.subscriberprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.subscriberprefix
));
19268 } else if (!strcasecmp(v
->name
, "ss7_unknownprefix")) {
19269 ast_copy_string(confp
->ss7
.ss7
.unknownprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.unknownprefix
));
19270 } else if (!strcasecmp(v
->name
, "ss7_networkroutedprefix")) {
19271 ast_copy_string(confp
->ss7
.ss7
.networkroutedprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.networkroutedprefix
));
19272 } else if (!strcasecmp(v
->name
, "ss7_called_nai")) {
19273 if (!strcasecmp(v
->value
, "national")) {
19274 confp
->ss7
.ss7
.called_nai
= SS7_NAI_NATIONAL
;
19275 } else if (!strcasecmp(v
->value
, "international")) {
19276 confp
->ss7
.ss7
.called_nai
= SS7_NAI_INTERNATIONAL
;
19277 } else if (!strcasecmp(v
->value
, "subscriber")) {
19278 confp
->ss7
.ss7
.called_nai
= SS7_NAI_SUBSCRIBER
;
19279 } else if (!strcasecmp(v
->value
, "unknown")) {
19280 confp
->ss7
.ss7
.called_nai
= SS7_NAI_UNKNOWN
;
19281 } else if (!strcasecmp(v
->value
, "dynamic")) {
19282 confp
->ss7
.ss7
.called_nai
= SS7_NAI_DYNAMIC
;
19284 ast_log(LOG_WARNING
, "Unknown SS7 called_nai '%s' at line %d.\n", v
->value
, v
->lineno
);
19286 } else if (!strcasecmp(v
->name
, "ss7_calling_nai")) {
19287 if (!strcasecmp(v
->value
, "national")) {
19288 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_NATIONAL
;
19289 } else if (!strcasecmp(v
->value
, "international")) {
19290 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_INTERNATIONAL
;
19291 } else if (!strcasecmp(v
->value
, "subscriber")) {
19292 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_SUBSCRIBER
;
19293 } else if (!strcasecmp(v
->value
, "unknown")) {
19294 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_UNKNOWN
;
19295 } else if (!strcasecmp(v
->value
, "dynamic")) {
19296 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_DYNAMIC
;
19298 ast_log(LOG_WARNING
, "Unknown SS7 calling_nai '%s' at line %d.\n", v
->value
, v
->lineno
);
19300 } else if (!strcasecmp(v
->name
, "sigchan")) {
19302 sigchan
= atoi(v
->value
);
19303 res
= linkset_addsigchan(sigchan
);
19307 } else if (!strcasecmp(v
->name
, "ss7_explicitacm")) {
19308 struct dahdi_ss7
*link
;
19309 link
= ss7_resolve_linkset(cur_linkset
);
19311 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19314 if (ast_true(v
->value
)) {
19315 link
->ss7
.flags
|= LINKSET_FLAG_EXPLICITACM
;
19317 link
->ss7
.flags
&= ~LINKSET_FLAG_EXPLICITACM
;
19319 } else if (!strcasecmp(v
->name
, "ss7_autoacm")) {
19320 struct dahdi_ss7
*link
;
19321 link
= ss7_resolve_linkset(cur_linkset
);
19323 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19326 if (ast_true(v
->value
)) {
19327 link
->ss7
.flags
|= LINKSET_FLAG_AUTOACM
;
19329 link
->ss7
.flags
&= ~LINKSET_FLAG_AUTOACM
;
19331 } else if (!strcasecmp(v
->name
, "ss7_initialhwblo")) {
19332 struct dahdi_ss7
*link
;
19333 link
= ss7_resolve_linkset(cur_linkset
);
19335 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19338 if (ast_true(v
->value
)) {
19339 link
->ss7
.flags
|= LINKSET_FLAG_INITIALHWBLO
;
19341 link
->ss7
.flags
&= ~LINKSET_FLAG_INITIALHWBLO
;
19343 } else if (!strcasecmp(v
->name
, "ss7_use_echocontrol")) {
19344 struct dahdi_ss7
*link
;
19345 link
= ss7_resolve_linkset(cur_linkset
);
19347 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19350 if (ast_true(v
->value
)) {
19351 link
->ss7
.flags
|= LINKSET_FLAG_USEECHOCONTROL
;
19353 link
->ss7
.flags
&= ~LINKSET_FLAG_USEECHOCONTROL
;
19355 } else if (!strcasecmp(v
->name
, "ss7_default_echocontrol")) {
19356 struct dahdi_ss7
*link
;
19357 link
= ss7_resolve_linkset(cur_linkset
);
19359 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19362 if (ast_true(v
->value
)) {
19363 link
->ss7
.flags
|= LINKSET_FLAG_DEFAULTECHOCONTROL
;
19365 link
->ss7
.flags
&= ~LINKSET_FLAG_DEFAULTECHOCONTROL
;
19367 } else if (!strncasecmp(v
->name
, "isup_timer.", 11)) {
19368 struct dahdi_ss7
*link
;
19369 link
= ss7_resolve_linkset(cur_linkset
);
19371 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19374 if (!link
->ss7
.ss7
) {
19375 ast_log(LOG_ERROR
, "Please specify isup timers after sigchan!\n");
19376 } else if (!ss7_set_isup_timer(link
->ss7
.ss7
, strstr(v
->name
, ".") + 1, atoi(v
->value
))) {
19377 ast_log(LOG_ERROR
, "Invalid isup timer %s\n", v
->name
);
19379 } else if (!strncasecmp(v
->name
, "mtp3_timer.", 11)) {
19380 struct dahdi_ss7
*link
;
19381 link
= ss7_resolve_linkset(cur_linkset
);
19383 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19386 if (!link
->ss7
.ss7
) {
19387 ast_log(LOG_ERROR
, "Please specify mtp3 timers after sigchan!\n");
19388 } else if (!ss7_set_mtp3_timer(link
->ss7
.ss7
, strstr(v
->name
, ".") + 1, atoi(v
->value
))) {
19389 ast_log(LOG_ERROR
, "Invalid mtp3 timer %s\n", v
->name
);
19391 } else if (!strcasecmp(v
->name
, "inr_if_no_calling")) {
19392 struct dahdi_ss7
*link
;
19393 link
= ss7_resolve_linkset(cur_linkset
);
19395 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19398 if (!link
->ss7
.ss7
) {
19399 ast_log(LOG_ERROR
, "Please specify inr_if_no_calling after sigchan!\n");
19400 } else if (ast_true(v
->value
)) {
19401 ss7_set_flags(link
->ss7
.ss7
, SS7_INR_IF_NO_CALLING
);
19403 ss7_clear_flags(link
->ss7
.ss7
, SS7_INR_IF_NO_CALLING
);
19405 } else if (!strcasecmp(v
->name
, "non_isdn_access")) {
19406 struct dahdi_ss7
*link
;
19407 link
= ss7_resolve_linkset(cur_linkset
);
19409 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19412 if (!link
->ss7
.ss7
) {
19413 ast_log(LOG_ERROR
, "Please specify non_isdn_access after sigchan!\n");
19414 } else if (ast_true(v
->value
)) {
19415 ss7_clear_flags(link
->ss7
.ss7
, SS7_ISDN_ACCESS_INDICATOR
);
19417 ss7_set_flags(link
->ss7
.ss7
, SS7_ISDN_ACCESS_INDICATOR
);
19419 } else if (!strcasecmp(v
->name
, "sls_shift")) {
19420 struct dahdi_ss7
*link
;
19421 int sls_shift
= atoi(v
->value
);
19423 if (sls_shift
< 0 || sls_shift
> 7) {
19424 ast_log(LOG_ERROR
, "Invalid sls_shift value. Must be between 0 and 7\n");
19428 link
= ss7_resolve_linkset(cur_linkset
);
19430 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19433 if (!link
->ss7
.ss7
) {
19434 ast_log(LOG_ERROR
, "Please specify sls_shift after sigchan!\n");
19436 ss7_set_sls_shift(link
->ss7
.ss7
, sls_shift
);
19438 } else if (!strcasecmp(v
->name
, "cause_location")) {
19439 struct dahdi_ss7
*link
;
19440 int cause_location
= atoi(v
->value
);
19442 if (cause_location
< 0 || cause_location
> 15) {
19443 ast_log(LOG_ERROR
, "Invalid cause_location value. Must be between 0 and 15\n");
19446 link
= ss7_resolve_linkset(cur_linkset
);
19448 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19451 if (!link
->ss7
.ss7
) {
19452 ast_log(LOG_ERROR
, "Please specify cause_location after sigchan!\n");
19454 ss7_set_cause_location(link
->ss7
.ss7
, cause_location
);
19456 #endif /* defined(HAVE_SS7) */
19458 } else if (!strcasecmp(v
->name
, "mfcr2_advanced_protocol_file")) {
19459 ast_copy_string(confp
->mfcr2
.r2proto_file
, v
->value
, sizeof(confp
->mfcr2
.r2proto_file
));
19460 ast_log(LOG_WARNING
, "MFC/R2 Protocol file '%s' will be used, you only should use this if you *REALLY KNOW WHAT YOU ARE DOING*.\n", confp
->mfcr2
.r2proto_file
);
19461 } else if (!strcasecmp(v
->name
, "mfcr2_logdir")) {
19462 ast_copy_string(confp
->mfcr2
.logdir
, v
->value
, sizeof(confp
->mfcr2
.logdir
));
19463 } else if (!strcasecmp(v
->name
, "mfcr2_variant")) {
19464 confp
->mfcr2
.variant
= openr2_proto_get_variant(v
->value
);
19465 if (OR2_VAR_UNKNOWN
== confp
->mfcr2
.variant
) {
19466 ast_log(LOG_WARNING
, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v
->value
, v
->lineno
);
19467 confp
->mfcr2
.variant
= OR2_VAR_ITU
;
19469 } else if (!strcasecmp(v
->name
, "mfcr2_mfback_timeout")) {
19470 confp
->mfcr2
.mfback_timeout
= atoi(v
->value
);
19471 if (!confp
->mfcr2
.mfback_timeout
) {
19472 ast_log(LOG_WARNING
, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19473 confp
->mfcr2
.mfback_timeout
= -1;
19474 } else if (confp
->mfcr2
.mfback_timeout
> 0 && confp
->mfcr2
.mfback_timeout
< 500) {
19475 ast_log(LOG_WARNING
, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19477 } else if (!strcasecmp(v
->name
, "mfcr2_metering_pulse_timeout")) {
19478 confp
->mfcr2
.metering_pulse_timeout
= atoi(v
->value
);
19479 if (confp
->mfcr2
.metering_pulse_timeout
> 500) {
19480 ast_log(LOG_WARNING
, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19482 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19483 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_detection")) {
19484 confp
->mfcr2
.dtmf_detection
= ast_true(v
->value
) ? 1 : 0;
19485 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_dialing")) {
19486 confp
->mfcr2
.dtmf_dialing
= ast_true(v
->value
) ? 1 : 0;
19487 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_time_on")) {
19488 confp
->mfcr2
.dtmf_time_on
= atoi(v
->value
);
19489 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_time_off")) {
19490 confp
->mfcr2
.dtmf_time_off
= atoi(v
->value
);
19492 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19493 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_end_timeout")) {
19494 confp
->mfcr2
.dtmf_end_timeout
= atoi(v
->value
);
19496 } else if (!strcasecmp(v
->name
, "mfcr2_get_ani_first")) {
19497 confp
->mfcr2
.get_ani_first
= ast_true(v
->value
) ? 1 : 0;
19498 } else if (!strcasecmp(v
->name
, "mfcr2_double_answer")) {
19499 confp
->mfcr2
.double_answer
= ast_true(v
->value
) ? 1 : 0;
19500 } else if (!strcasecmp(v
->name
, "mfcr2_charge_calls")) {
19501 confp
->mfcr2
.charge_calls
= ast_true(v
->value
) ? 1 : 0;
19502 } else if (!strcasecmp(v
->name
, "mfcr2_accept_on_offer")) {
19503 confp
->mfcr2
.accept_on_offer
= ast_true(v
->value
) ? 1 : 0;
19504 } else if (!strcasecmp(v
->name
, "mfcr2_allow_collect_calls")) {
19505 confp
->mfcr2
.allow_collect_calls
= ast_true(v
->value
) ? 1 : 0;
19506 } else if (!strcasecmp(v
->name
, "mfcr2_forced_release")) {
19507 confp
->mfcr2
.forced_release
= ast_true(v
->value
) ? 1 : 0;
19508 } else if (!strcasecmp(v
->name
, "mfcr2_immediate_accept")) {
19509 confp
->mfcr2
.immediate_accept
= ast_true(v
->value
) ? 1 : 0;
19510 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19511 } else if (!strcasecmp(v
->name
, "mfcr2_skip_category")) {
19512 confp
->mfcr2
.skip_category_request
= ast_true(v
->value
) ? 1 : 0;
19514 } else if (!strcasecmp(v
->name
, "mfcr2_call_files")) {
19515 confp
->mfcr2
.call_files
= ast_true(v
->value
) ? 1 : 0;
19516 } else if (!strcasecmp(v
->name
, "mfcr2_max_ani")) {
19517 confp
->mfcr2
.max_ani
= atoi(v
->value
);
19518 if (confp
->mfcr2
.max_ani
>= AST_MAX_EXTENSION
) {
19519 confp
->mfcr2
.max_ani
= AST_MAX_EXTENSION
- 1;
19521 } else if (!strcasecmp(v
->name
, "mfcr2_max_dnis")) {
19522 confp
->mfcr2
.max_dnis
= atoi(v
->value
);
19523 if (confp
->mfcr2
.max_dnis
>= AST_MAX_EXTENSION
) {
19524 confp
->mfcr2
.max_dnis
= AST_MAX_EXTENSION
- 1;
19526 } else if (!strcasecmp(v
->name
, "mfcr2_category")) {
19527 confp
->mfcr2
.category
= openr2_proto_get_category(v
->value
);
19528 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN
== confp
->mfcr2
.category
) {
19529 confp
->mfcr2
.category
= OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
;
19530 ast_log(LOG_WARNING
, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19531 v
->value
, v
->lineno
);
19533 } else if (!strcasecmp(v
->name
, "mfcr2_logging")) {
19534 openr2_log_level_t tmplevel
;
19537 char copy
[strlen(v
->value
) + 1];
19538 strcpy(copy
, v
->value
); /* safe */
19541 clevel
= strsep(&logval
,",");
19542 if (-1 == (tmplevel
= openr2_log_get_level(clevel
))) {
19543 ast_log(LOG_WARNING
, "Ignoring invalid logging level: '%s' at line %d.\n", clevel
, v
->lineno
);
19546 confp
->mfcr2
.loglevel
|= tmplevel
;
19548 #endif /* HAVE_OPENR2 */
19549 } else if (!strcasecmp(v
->name
, "cadence")) {
19550 /* setup to scan our argument */
19551 int element_count
, c
[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
19553 struct dahdi_ring_cadence new_cadence
;
19554 int cid_location
= -1;
19555 int firstcadencepos
= 0;
19556 char original_args
[80];
19557 int cadence_is_ok
= 1;
19559 ast_copy_string(original_args
, v
->value
, sizeof(original_args
));
19560 /* 16 cadences allowed (8 pairs) */
19561 element_count
= sscanf(v
->value
, "%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d", &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]);
19563 /* Cadence must be even (on/off) */
19564 if (element_count
% 2 == 1) {
19565 ast_log(LOG_ERROR
, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args
, v
->lineno
);
19569 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
19570 if (element_count
> ARRAY_LEN(c
)) {
19571 element_count
= ARRAY_LEN(c
);
19574 /* Ring cadences cannot be negative */
19575 for (i
= 0; i
< element_count
; i
++) {
19577 ast_log(LOG_ERROR
, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args
, v
->lineno
);
19580 } else if (c
[i
] < 0) {
19582 /* Silence duration, negative possibly okay */
19583 if (cid_location
== -1) {
19587 ast_log(LOG_ERROR
, "CID location specified twice: %s at line %d.\n", original_args
, v
->lineno
);
19592 if (firstcadencepos
== 0) {
19593 firstcadencepos
= i
; /* only recorded to avoid duplicate specification */
19594 /* duration will be passed negative to the DAHDI driver */
19596 ast_log(LOG_ERROR
, "First cadence position specified twice: %s at line %d.\n", original_args
, v
->lineno
);
19604 /* Substitute our scanned cadence */
19605 for (i
= 0; i
< 16; i
++) {
19606 new_cadence
.ringcadence
[i
] = c
[i
];
19609 if (cadence_is_ok
) {
19610 /* ---we scanned it without getting annoyed; now some sanity checks--- */
19611 if (element_count
< 2) {
19612 ast_log(LOG_ERROR
, "Minimum cadence is ring,pause: %s at line %d.\n", original_args
, v
->lineno
);
19614 if (cid_location
== -1) {
19615 /* user didn't say; default to first pause */
19618 /* convert element_index to cidrings value */
19619 cid_location
= (cid_location
+ 1) / 2;
19621 /* ---we like their cadence; try to install it--- */
19622 if (!user_has_defined_cadences
++)
19623 /* this is the first user-defined cadence; clear the default user cadences */
19625 if ((num_cadence
+1) >= NUM_CADENCE_MAX
)
19626 ast_log(LOG_ERROR
, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX
, original_args
, v
->lineno
);
19628 cadences
[num_cadence
] = new_cadence
;
19629 cidrings
[num_cadence
++] = cid_location
;
19630 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence
,original_args
);
19634 } else if (!strcasecmp(v
->name
, "ringtimeout")) {
19635 ringt_base
= (atoi(v
->value
) * 8) / READ_SIZE
;
19636 } else if (!strcasecmp(v
->name
, "prewink")) {
19637 confp
->timing
.prewinktime
= atoi(v
->value
);
19638 } else if (!strcasecmp(v
->name
, "preflash")) {
19639 confp
->timing
.preflashtime
= atoi(v
->value
);
19640 } else if (!strcasecmp(v
->name
, "wink")) {
19641 confp
->timing
.winktime
= atoi(v
->value
);
19642 } else if (!strcasecmp(v
->name
, "flash")) {
19643 confp
->timing
.flashtime
= atoi(v
->value
);
19644 } else if (!strcasecmp(v
->name
, "start")) {
19645 confp
->timing
.starttime
= atoi(v
->value
);
19646 } else if (!strcasecmp(v
->name
, "rxwink")) {
19647 confp
->timing
.rxwinktime
= atoi(v
->value
);
19648 } else if (!strcasecmp(v
->name
, "rxflash")) {
19649 confp
->timing
.rxflashtime
= atoi(v
->value
);
19650 } else if (!strcasecmp(v
->name
, "debounce")) {
19651 confp
->timing
.debouncetime
= atoi(v
->value
);
19652 } else if (!strcasecmp(v
->name
, "toneduration")) {
19656 struct dahdi_dialparams dps
;
19658 ctlfd
= open("/dev/dahdi/ctl", O_RDWR
);
19660 ast_log(LOG_ERROR
, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v
->lineno
);
19664 toneduration
= atoi(v
->value
);
19665 if (toneduration
> -1) {
19666 memset(&dps
, 0, sizeof(dps
));
19668 dps
.dtmf_tonelen
= dps
.mfv1_tonelen
= toneduration
;
19669 res
= ioctl(ctlfd
, DAHDI_SET_DIALPARAMS
, &dps
);
19671 ast_log(LOG_ERROR
, "Invalid tone duration: %d ms at line %d: %s\n", toneduration
, v
->lineno
, strerror(errno
));
19677 } else if (!strcasecmp(v
->name
, "defaultcic")) {
19678 ast_copy_string(defaultcic
, v
->value
, sizeof(defaultcic
));
19679 } else if (!strcasecmp(v
->name
, "defaultozz")) {
19680 ast_copy_string(defaultozz
, v
->value
, sizeof(defaultozz
));
19681 } else if (!strcasecmp(v
->name
, "mwilevel")) {
19682 mwilevel
= atoi(v
->value
);
19683 } else if (!strcasecmp(v
->name
, "dtmfcidlevel")) {
19684 dtmfcid_level
= atoi(v
->value
);
19685 } else if (!strcasecmp(v
->name
, "reportalarms")) {
19686 if (!strcasecmp(v
->value
, "all"))
19687 report_alarms
= REPORT_CHANNEL_ALARMS
| REPORT_SPAN_ALARMS
;
19688 if (!strcasecmp(v
->value
, "none"))
19690 else if (!strcasecmp(v
->value
, "channels"))
19691 report_alarms
= REPORT_CHANNEL_ALARMS
;
19692 else if (!strcasecmp(v
->value
, "spans"))
19693 report_alarms
= REPORT_SPAN_ALARMS
;
19695 } else if (!(options
& PROC_DAHDI_OPT_NOWARN
) )
19696 ast_log(LOG_NOTICE
, "Ignoring any changes to '%s' (on reload) at line %d.\n", v
->name
, v
->lineno
);
19700 /* Process the deferred dahdichan value. */
19701 if (build_channels(confp
, dahdichan
->value
, reload
, dahdichan
->lineno
)) {
19702 if (confp
->ignore_failed_channels
) {
19703 ast_log(LOG_WARNING
,
19704 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
19713 * Since confp has already filled individual dahdi_pvt objects with channels
19714 * at this point, clear the variables in confp's pvt.
19716 if (confp
->chan
.vars
) {
19717 ast_variables_destroy(confp
->chan
.vars
);
19718 confp
->chan
.vars
= NULL
;
19721 /* mark the first channels of each DAHDI span to watch for their span alarms */
19722 for (tmp
= iflist
, y
=-1; tmp
; tmp
= tmp
->next
) {
19723 if (!tmp
->destroy
&& tmp
->span
!= y
) {
19724 tmp
->manages_span_alarms
= 1;
19727 tmp
->manages_span_alarms
= 0;
19731 /*< \todo why check for the pseudo in the per-channel section.
19732 * Any actual use for manual setup of the pseudo channel? */
19733 if (!has_pseudo
&& reload
!= 1 && !(options
& PROC_DAHDI_OPT_NOCHAN
)) {
19734 /* use the default configuration for a channel, so
19735 that any settings from real configured channels
19736 don't "leak" into the pseudo channel config
19738 struct dahdi_chan_conf conf
= dahdi_chan_conf_default();
19740 if (conf
.chan
.cc_params
) {
19741 tmp
= mkintf(CHAN_PSEUDO
, &conf
, reload
);
19746 ast_verb(3, "Automatically generated pseudo channel\n");
19749 ast_log(LOG_WARNING
, "Unable to register pseudo channel!\n");
19751 ast_cc_config_params_destroy(conf
.chan
.cc_params
);
19754 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
19755 confp
->chan
.named_callgroups
= ast_unref_namedgroups(confp
->chan
.named_callgroups
);
19756 confp
->chan
.named_pickupgroups
= ast_unref_namedgroups(confp
->chan
.named_pickupgroups
);
19763 * \brief Deep copy struct dahdi_chan_conf.
19766 * \param dest Destination.
19767 * \param src Source.
19769 static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf
*dest
, const struct dahdi_chan_conf
*src
)
19771 struct ast_cc_config_params
*cc_params
;
19773 cc_params
= dest
->chan
.cc_params
;
19775 dest
->chan
.cc_params
= cc_params
;
19776 ast_cc_copy_config_params(dest
->chan
.cc_params
, src
->chan
.cc_params
);
19781 * \brief Setup DAHDI channel driver.
19783 * \param reload enum: load_module(0), reload(1), restart(2).
19784 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
19785 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
19786 * \param conf Local config parameters. So cc_params can be properly destroyed.
19788 * \retval 0 on success.
19789 * \retval -1 on error.
19791 static int setup_dahdi_int(int reload
, struct dahdi_chan_conf
*default_conf
, struct dahdi_chan_conf
*base_conf
, struct dahdi_chan_conf
*conf
)
19793 struct ast_config
*cfg
;
19794 struct ast_config
*ucfg
;
19795 struct ast_variable
*v
;
19796 struct ast_flags config_flags
= { reload
== 1 ? CONFIG_FLAG_FILEUNCHANGED
: 0 };
19807 int dchannels
[SIG_PRI_NUM_DCHANS
];
19810 static int had_cfg_before
= 1;/* So initial load will complain if we don't have cfg. */
19812 cfg
= ast_config_load(config
, config_flags
);
19813 have_cfg_now
= !!cfg
;
19815 /* Error if we have no config file */
19816 if (had_cfg_before
) {
19817 ast_log(LOG_ERROR
, "Unable to load config %s\n", config
);
19818 ast_clear_flag(&config_flags
, CONFIG_FLAG_FILEUNCHANGED
);
19820 cfg
= ast_config_new();/* Dummy config */
19824 ucfg
= ast_config_load("users.conf", config_flags
);
19825 if (ucfg
== CONFIG_STATUS_FILEUNCHANGED
) {
19826 ast_config_destroy(cfg
);
19829 if (ucfg
== CONFIG_STATUS_FILEINVALID
) {
19830 ast_log(LOG_ERROR
, "File users.conf cannot be parsed. Aborting.\n");
19831 ast_config_destroy(cfg
);
19834 } else if (cfg
== CONFIG_STATUS_FILEUNCHANGED
) {
19835 ucfg
= ast_config_load("users.conf", config_flags
);
19836 if (ucfg
== CONFIG_STATUS_FILEUNCHANGED
) {
19839 if (ucfg
== CONFIG_STATUS_FILEINVALID
) {
19840 ast_log(LOG_ERROR
, "File users.conf cannot be parsed. Aborting.\n");
19843 ast_clear_flag(&config_flags
, CONFIG_FLAG_FILEUNCHANGED
);
19844 cfg
= ast_config_load(config
, config_flags
);
19845 have_cfg_now
= !!cfg
;
19847 if (had_cfg_before
) {
19848 /* We should have been able to load the config. */
19849 ast_log(LOG_ERROR
, "Bad. Unable to load config %s\n", config
);
19850 ast_config_destroy(ucfg
);
19853 cfg
= ast_config_new();/* Dummy config */
19855 ast_config_destroy(ucfg
);
19858 } else if (cfg
== CONFIG_STATUS_FILEINVALID
) {
19859 ast_log(LOG_ERROR
, "File %s cannot be parsed. Aborting.\n", config
);
19860 ast_config_destroy(ucfg
);
19863 } else if (cfg
== CONFIG_STATUS_FILEINVALID
) {
19864 ast_log(LOG_ERROR
, "File %s cannot be parsed. Aborting.\n", config
);
19867 ast_clear_flag(&config_flags
, CONFIG_FLAG_FILEUNCHANGED
);
19868 ucfg
= ast_config_load("users.conf", config_flags
);
19869 if (ucfg
== CONFIG_STATUS_FILEINVALID
) {
19870 ast_log(LOG_ERROR
, "File users.conf cannot be parsed. Aborting.\n");
19871 ast_config_destroy(cfg
);
19875 had_cfg_before
= have_cfg_now
;
19877 /* It's a little silly to lock it, but we might as well just to be sure */
19878 ast_mutex_lock(&iflock
);
19881 /* Process trunkgroups first */
19882 v
= ast_variable_browse(cfg
, "trunkgroups");
19884 if (!strcasecmp(v
->name
, "trunkgroup")) {
19885 trunkgroup
= atoi(v
->value
);
19886 if (trunkgroup
> 0) {
19887 if ((c
= strchr(v
->value
, ','))) {
19889 memset(dchannels
, 0, sizeof(dchannels
));
19890 while (c
&& (i
< SIG_PRI_NUM_DCHANS
)) {
19891 dchannels
[i
] = atoi(c
+ 1);
19892 if (dchannels
[i
] < 0) {
19893 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
);
19896 c
= strchr(c
+ 1, ',');
19899 if (pri_create_trunkgroup(trunkgroup
, dchannels
)) {
19900 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
);
19902 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");
19904 ast_log(LOG_WARNING
, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup
, v
->lineno
);
19906 ast_log(LOG_WARNING
, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup
, v
->lineno
);
19908 ast_log(LOG_WARNING
, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v
->lineno
);
19909 } else if (!strcasecmp(v
->name
, "spanmap")) {
19910 spanno
= atoi(v
->value
);
19912 if ((c
= strchr(v
->value
, ','))) {
19913 trunkgroup
= atoi(c
+ 1);
19914 if (trunkgroup
> 0) {
19915 if ((c
= strchr(c
+ 1, ',')))
19916 logicalspan
= atoi(c
+ 1);
19919 if (logicalspan
>= 0) {
19920 if (pri_create_spanmap(spanno
- 1, trunkgroup
, logicalspan
)) {
19921 ast_log(LOG_WARNING
, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno
, trunkgroup
, logicalspan
);
19923 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno
, trunkgroup
, logicalspan
);
19925 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
);
19927 ast_log(LOG_WARNING
, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v
->lineno
);
19929 ast_log(LOG_WARNING
, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v
->lineno
);
19931 ast_log(LOG_WARNING
, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v
->lineno
);
19933 ast_log(LOG_NOTICE
, "Ignoring unknown keyword '%s' in trunkgroups\n", v
->name
);
19940 /* Copy the default jb config over global_jbconf */
19941 memcpy(&global_jbconf
, &default_jbconf
, sizeof(global_jbconf
));
19943 mwimonitornotify
[0] = '\0';
19945 v
= ast_variable_browse(cfg
, "channels");
19946 if ((res
= process_dahdi(base_conf
,
19947 "" /* Must be empty for the channels category. Silly voicemail mailbox. */,
19949 ast_mutex_unlock(&iflock
);
19950 ast_config_destroy(cfg
);
19952 ast_config_destroy(ucfg
);
19957 /* Now get configuration from all normal sections in chan_dahdi.conf: */
19958 for (cat
= ast_category_browse(cfg
, NULL
); cat
; cat
= ast_category_browse(cfg
, cat
)) {
19959 /* [channels] and [trunkgroups] are used. Let's also reserve
19960 * [globals] and [general] for future use
19962 if (!strcasecmp(cat
, "general") ||
19963 !strcasecmp(cat
, "trunkgroups") ||
19964 !strcasecmp(cat
, "globals") ||
19965 !strcasecmp(cat
, "channels")) {
19969 chans
= ast_variable_retrieve(cfg
, cat
, "dahdichan");
19970 if (ast_strlen_zero(chans
)) {
19971 /* Section is useless without a dahdichan value present. */
19975 /* Copy base_conf to conf. */
19976 deep_copy_dahdi_chan_conf(conf
, base_conf
);
19978 if ((res
= process_dahdi(conf
, cat
, ast_variable_browse(cfg
, cat
), reload
, PROC_DAHDI_OPT_NOCHAN
))) {
19979 ast_mutex_unlock(&iflock
);
19980 ast_config_destroy(cfg
);
19982 ast_config_destroy(ucfg
);
19988 ast_config_destroy(cfg
);
19991 /* Reset base_conf, so things don't leak from chan_dahdi.conf */
19992 deep_copy_dahdi_chan_conf(base_conf
, default_conf
);
19993 process_dahdi(base_conf
,
19994 "" /* Must be empty for the general category. Silly voicemail mailbox. */,
19995 ast_variable_browse(ucfg
, "general"), 1, 0);
19997 for (cat
= ast_category_browse(ucfg
, NULL
); cat
; cat
= ast_category_browse(ucfg
, cat
)) {
19998 if (!strcasecmp(cat
, "general")) {
20002 chans
= ast_variable_retrieve(ucfg
, cat
, "dahdichan");
20003 if (ast_strlen_zero(chans
)) {
20004 /* Section is useless without a dahdichan value present. */
20008 /* Copy base_conf to conf. */
20009 deep_copy_dahdi_chan_conf(conf
, base_conf
);
20011 if ((res
= process_dahdi(conf
, cat
, ast_variable_browse(ucfg
, cat
), reload
, PROC_DAHDI_OPT_NOCHAN
| PROC_DAHDI_OPT_NOWARN
))) {
20012 ast_config_destroy(ucfg
);
20013 ast_mutex_unlock(&iflock
);
20017 ast_config_destroy(ucfg
);
20019 ast_mutex_unlock(&iflock
);
20024 for (x
= 0; x
< NUM_SPANS
; x
++) {
20025 if (pris
[x
].pri
.pvts
[0] &&
20026 pris
[x
].pri
.master
== AST_PTHREADT_NULL
) {
20027 prepare_pri(pris
+ x
);
20028 if (sig_pri_start_pri(&pris
[x
].pri
)) {
20029 ast_log(LOG_ERROR
, "Unable to start D-channel on span %d\n", x
+ 1);
20032 ast_verb(2, "Starting D-Channel on span %d\n", x
+ 1);
20037 #if defined(HAVE_SS7)
20040 for (x
= 0; x
< NUM_SPANS
; x
++) {
20041 if (linksets
[x
].ss7
.ss7
) {
20042 if (ast_pthread_create(&linksets
[x
].ss7
.master
, NULL
, ss7_linkset
, &linksets
[x
].ss7
)) {
20043 ast_log(LOG_ERROR
, "Unable to start SS7 linkset on span %d\n", x
+ 1);
20046 ast_verb(2, "Starting SS7 linkset on span %d\n", x
+ 1);
20050 #endif /* defined(HAVE_SS7) */
20053 struct r2link_entry
*cur
;
20055 AST_LIST_LOCK(&r2links
);
20056 AST_LIST_TRAVERSE(&r2links
, cur
, list
) {
20057 struct dahdi_mfcr2
*r2
= &cur
->mfcr2
;
20058 if (r2
->r2master
== AST_PTHREADT_NULL
) {
20059 if (ast_pthread_create(&r2
->r2master
, NULL
, mfcr2_monitor
, r2
)) {
20060 ast_log(LOG_ERROR
, "Unable to start R2 monitor on channel group %d\n", x
+ 1);
20063 ast_verb(2, "Starting R2 monitor on channel group %d\n", x
+ 1);
20068 AST_LIST_UNLOCK(&r2links
);
20071 /* And start the monitor for the first time */
20078 * \brief Setup DAHDI channel driver.
20080 * \param reload enum: load_module(0), reload(1), restart(2).
20082 * \retval 0 on success.
20083 * \retval -1 on error.
20085 static int setup_dahdi(int reload
)
20088 struct dahdi_chan_conf default_conf
= dahdi_chan_conf_default();
20089 struct dahdi_chan_conf base_conf
= dahdi_chan_conf_default();
20090 struct dahdi_chan_conf conf
= dahdi_chan_conf_default();
20092 if (default_conf
.chan
.cc_params
&& base_conf
.chan
.cc_params
&& conf
.chan
.cc_params
) {
20093 res
= setup_dahdi_int(reload
, &default_conf
, &base_conf
, &conf
);
20097 ast_cc_config_params_destroy(default_conf
.chan
.cc_params
);
20098 ast_cc_config_params_destroy(base_conf
.chan
.cc_params
);
20099 ast_cc_config_params_destroy(conf
.chan
.cc_params
);
20105 * \brief Load the module
20107 * Module loading including tests for configuration or dependencies.
20108 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20109 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20110 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20111 * configuration file or other non-critical problem return
20112 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20114 static int load_module(void)
20117 #if defined(HAVE_PRI) || defined(HAVE_SS7)
20119 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20121 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type
)) {
20122 return AST_MODULE_LOAD_DECLINE
;
20125 if (!(dahdi_tech
.capabilities
= ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT
))) {
20126 return AST_MODULE_LOAD_DECLINE
;
20128 ast_format_cap_append(dahdi_tech
.capabilities
, ast_format_slin
, 0);
20129 ast_format_cap_append(dahdi_tech
.capabilities
, ast_format_ulaw
, 0);
20130 ast_format_cap_append(dahdi_tech
.capabilities
, ast_format_alaw
, 0);
20132 if (dahdi_native_load(&dahdi_tech
)) {
20133 ao2_ref(dahdi_tech
.capabilities
, -1);
20134 return AST_MODULE_LOAD_DECLINE
;
20138 memset(pris
, 0, sizeof(pris
));
20139 for (y
= 0; y
< NUM_SPANS
; y
++) {
20140 sig_pri_init_pri(&pris
[y
].pri
);
20142 pri_set_error(dahdi_pri_error
);
20143 pri_set_message(dahdi_pri_message
);
20144 ast_register_application_xml(dahdi_send_keypad_facility_app
, dahdi_send_keypad_facility_exec
);
20145 #ifdef HAVE_PRI_PROG_W_CAUSE
20146 ast_register_application_xml(dahdi_send_callrerouting_facility_app
, dahdi_send_callrerouting_facility_exec
);
20148 #if defined(HAVE_PRI_CCSS)
20149 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks
)
20150 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks
)) {
20152 return AST_MODULE_LOAD_DECLINE
;
20154 #endif /* defined(HAVE_PRI_CCSS) */
20156 #if defined(HAVE_PRI_CCSS)
20160 #endif /* defined(HAVE_PRI_CCSS) */
20163 return AST_MODULE_LOAD_DECLINE
;
20166 #if defined(HAVE_SS7)
20167 memset(linksets
, 0, sizeof(linksets
));
20168 for (y
= 0; y
< NUM_SPANS
; y
++) {
20169 sig_ss7_init_linkset(&linksets
[y
].ss7
);
20171 ss7_set_error(dahdi_ss7_error
);
20172 ss7_set_message(dahdi_ss7_message
);
20173 ss7_set_hangup(sig_ss7_cb_hangup
);
20174 ss7_set_notinservice(sig_ss7_cb_notinservice
);
20175 ss7_set_call_null(sig_ss7_cb_call_null
);
20176 #endif /* defined(HAVE_SS7) */
20177 res
= setup_dahdi(0);
20178 /* Make sure we can register our DAHDI channel type */
20181 return AST_MODULE_LOAD_DECLINE
;
20183 if (ast_channel_register(&dahdi_tech
)) {
20184 ast_log(LOG_ERROR
, "Unable to register channel class 'DAHDI'\n");
20186 return AST_MODULE_LOAD_DECLINE
;
20189 ast_cli_register_multiple(dahdi_pri_cli
, ARRAY_LEN(dahdi_pri_cli
));
20191 #if defined(HAVE_SS7)
20192 ast_cli_register_multiple(dahdi_ss7_cli
, ARRAY_LEN(dahdi_ss7_cli
));
20193 #endif /* defined(HAVE_SS7) */
20195 ast_cli_register_multiple(dahdi_mfcr2_cli
, ARRAY_LEN(dahdi_mfcr2_cli
));
20196 ast_register_application_xml(dahdi_accept_r2_call_app
, dahdi_accept_r2_call_exec
);
20199 ast_custom_function_register(&polarity_function
);
20201 ast_cli_register_multiple(dahdi_cli
, ARRAY_LEN(dahdi_cli
));
20202 memset(round_robin
, 0, sizeof(round_robin
));
20203 ast_manager_register_xml("DAHDITransfer", 0, action_transfer
);
20204 ast_manager_register_xml("DAHDIHangup", 0, action_transferhangup
);
20205 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook
);
20206 ast_manager_register_xml("DAHDIDNDon", 0, action_dahdidndon
);
20207 ast_manager_register_xml("DAHDIDNDoff", 0, action_dahdidndoff
);
20208 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels
);
20209 ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart
);
20210 #if defined(HAVE_PRI)
20211 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans
);
20212 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set
);
20213 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM
, action_pri_debug_file_set
);
20214 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset
);
20215 #endif /* defined(HAVE_PRI) */
20217 ast_cond_init(&ss_thread_complete
, NULL
);
20222 static int dahdi_sendtext(struct ast_channel
*c
, const char *text
)
20224 #define END_SILENCE_LEN 400
20225 #define HEADER_MS 50
20226 #define TRAILER_MS 5
20227 #define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20228 #define ASCII_BYTES_PER_CHAR 80
20230 unsigned char *buf
,*mybuf
;
20231 struct dahdi_pvt
*p
= ast_channel_tech_pvt(c
);
20232 struct pollfd fds
[1];
20233 int size
,res
,fd
,len
,x
;
20238 * Initial carrier (imaginary)
20240 * Note: The following float variables are used by the
20241 * PUT_CLID_MARKMS and PUT_CLID() macros.
20248 return(0); /* if nothing to send, don't */
20250 idx
= dahdi_get_index(c
, p
, 0);
20252 ast_log(LOG_WARNING
, "Huh? I don't exist?\n");
20255 if ((!p
->tdd
) && (!p
->mate
)) {
20256 #if defined(HAVE_PRI)
20257 #if defined(HAVE_PRI_DISPLAY_TEXT)
20258 ast_mutex_lock(&p
->lock
);
20259 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
20260 sig_pri_sendtext(p
->sig_pvt
, text
);
20262 ast_mutex_unlock(&p
->lock
);
20263 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20264 #endif /* defined(HAVE_PRI) */
20265 return(0); /* if not in TDD mode, just return */
20268 buf
= ast_malloc(((strlen(text
) + 1) * ASCII_BYTES_PER_CHAR
) + END_SILENCE_LEN
+ HEADER_LEN
);
20270 buf
= ast_malloc(((strlen(text
) + 1) * TDD_BYTES_PER_CHAR
) + END_SILENCE_LEN
);
20275 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20276 struct ast_format
*codec
= AST_LAW(p
);
20278 for (x
= 0; x
< HEADER_MS
; x
++) { /* 50 ms of Mark */
20281 /* Put actual message */
20282 for (x
= 0; text
[x
]; x
++) {
20285 for (x
= 0; x
< TRAILER_MS
; x
++) { /* 5 ms of Mark */
20291 len
= tdd_generate(p
->tdd
, buf
, text
);
20293 ast_log(LOG_ERROR
, "TDD generate (len %d) failed!!\n", (int)strlen(text
));
20298 memset(buf
+ len
, 0x7f, END_SILENCE_LEN
);
20299 len
+= END_SILENCE_LEN
;
20300 fd
= p
->subs
[idx
].dfd
;
20302 if (ast_check_hangup(c
)) {
20307 if (size
> READ_SIZE
)
20310 fds
[0].events
= POLLOUT
| POLLPRI
;
20311 fds
[0].revents
= 0;
20312 res
= poll(fds
, 1, -1);
20314 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p
->channel
);
20317 /* if got exception */
20318 if (fds
[0].revents
& POLLPRI
) {
20322 if (!(fds
[0].revents
& POLLOUT
)) {
20323 ast_debug(1, "write fd not ready on channel %d\n", p
->channel
);
20326 res
= write(fd
, buf
, size
);
20332 ast_debug(1, "Write returned %d (%s) on channel %d\n", res
, strerror(errno
), p
->channel
);
20343 static int reload(void)
20347 res
= setup_dahdi(1);
20349 ast_log(LOG_WARNING
, "Reload of chan_dahdi.so is unsuccessful!\n");
20355 /* This is a workaround so that menuselect displays a proper description
20356 * AST_MODULE_INFO(, , "DAHDI Telephony"
20359 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_LOAD_ORDER
, tdesc
,
20360 .support_level
= AST_MODULE_SUPPORT_CORE
,
20361 .load
= load_module
,
20362 .unload
= unload_module
,
20364 .load_pri
= AST_MODPRI_CHANNEL_DRIVER
,
20365 .requires
= "ccss",
20366 .optional_modules
= "res_smdi",