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 mwi_message
= stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p
->mailbox
);
5235 struct ast_mwi_state
*mwi_state
= stasis_message_data(mwi_message
);
5236 new_msgs
= mwi_state
->new_msgs
;
5238 new_msgs
= ast_app_has_voicemail(p
->mailbox
, NULL
);
5246 static int send_callerid(struct dahdi_pvt
*p
)
5248 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
5250 /* Take out of linear mode if necessary */
5251 if (p
->subs
[SUB_REAL
].linear
) {
5252 p
->subs
[SUB_REAL
].linear
= 0;
5253 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
5255 while (p
->cidpos
< p
->cidlen
) {
5256 res
= write(p
->subs
[SUB_REAL
].dfd
, p
->cidspill
+ p
->cidpos
, p
->cidlen
- p
->cidpos
);
5257 ast_debug(4, "writing callerid at pos %d of %d, res = %d\n", p
->cidpos
, p
->cidlen
, res
);
5259 if (errno
== EAGAIN
)
5262 ast_log(LOG_WARNING
, "write failed: %s\n", strerror(errno
));
5270 p
->cid_suppress_expire
= CALLWAITING_SUPPRESS_SAMPLES
;
5271 ast_free(p
->cidspill
);
5273 if (p
->callwaitcas
) {
5274 /* Wait for CID/CW to expire */
5275 p
->cidcwexpire
= CIDCW_EXPIRE_SAMPLES
;
5276 p
->cid_suppress_expire
= p
->cidcwexpire
;
5278 restore_conference(p
);
5282 static int dahdi_callwait(struct ast_channel
*ast
)
5284 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
5286 p
->callwaitingrepeat
= CALLWAITING_REPEAT_SAMPLES
;
5288 ast_log(LOG_WARNING
, "Spill already exists?!?\n");
5289 ast_free(p
->cidspill
);
5293 * SAS: Subscriber Alert Signal, 440Hz for 300ms
5294 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
5296 if (!(p
->cidspill
= ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE
* 4)))
5300 memset(p
->cidspill
, 0x7f, 2400 + 600 + READ_SIZE
* 4);
5301 if (!p
->callwaitrings
&& p
->callwaitingcallerid
) {
5302 ast_gen_cas(p
->cidspill
, 1, 2400 + 680, AST_LAW(p
));
5304 p
->cidlen
= 2400 + 680 + READ_SIZE
* 4;
5306 ast_gen_cas(p
->cidspill
, 1, 2400, AST_LAW(p
));
5308 p
->cidlen
= 2400 + READ_SIZE
* 4;
5316 static int dahdi_call(struct ast_channel
*ast
, const char *rdest
, int timeout
)
5318 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
5321 AST_DECLARE_APP_ARGS(args
,
5322 AST_APP_ARG(group
); /* channel/group token */
5323 AST_APP_ARG(ext
); /* extension token */
5324 //AST_APP_ARG(opts); /* options token */
5325 AST_APP_ARG(other
); /* Any remining unused arguments */
5328 ast_mutex_lock(&p
->lock
);
5329 ast_copy_string(p
->dialdest
, rdest
, sizeof(p
->dialdest
));
5331 /* Split the dialstring */
5332 dest
= ast_strdupa(rdest
);
5333 AST_NONSTANDARD_APP_ARGS(args
, dest
, '/');
5338 #if defined(HAVE_PRI)
5339 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
5342 sig_pri_extract_called_num_subaddr(p
->sig_pvt
, rdest
, p
->exten
, sizeof(p
->exten
));
5344 /* Remove any subaddress for uniformity with incoming calls. */
5345 subaddr
= strchr(p
->exten
, ':');
5350 #endif /* defined(HAVE_PRI) */
5352 ast_copy_string(p
->exten
, args
.ext
, sizeof(p
->exten
));
5355 if ((ast_channel_state(ast
) == AST_STATE_BUSY
)) {
5356 p
->subs
[SUB_REAL
].needbusy
= 1;
5357 ast_mutex_unlock(&p
->lock
);
5360 if ((ast_channel_state(ast
) != AST_STATE_DOWN
) && (ast_channel_state(ast
) != AST_STATE_RESERVED
)) {
5361 ast_log(LOG_WARNING
, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast
));
5362 ast_mutex_unlock(&p
->lock
);
5365 p
->waitingfordt
.tv_sec
= 0;
5367 if ((p
->radio
|| (p
->oprmode
< 0))) /* if a radio channel, up immediately */
5369 /* Special pseudo -- automatically up */
5370 ast_setstate(ast
, AST_STATE_UP
);
5371 ast_mutex_unlock(&p
->lock
);
5374 x
= DAHDI_FLUSH_READ
| DAHDI_FLUSH_WRITE
;
5375 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_FLUSH
, &x
);
5377 ast_log(LOG_WARNING
, "Unable to flush input on channel %d: %s\n", p
->channel
, strerror(errno
));
5380 if (IS_DIGITAL(ast_channel_transfercapability(ast
))){
5381 set_actual_gain(p
->subs
[SUB_REAL
].dfd
, 0, 0, p
->rxdrc
, p
->txdrc
, p
->law
);
5383 set_actual_gain(p
->subs
[SUB_REAL
].dfd
, p
->rxgain
, p
->txgain
, p
->rxdrc
, p
->txdrc
, p
->law
);
5387 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
5388 res
= sig_pri_call(p
->sig_pvt
, ast
, rdest
, timeout
,
5389 (p
->law
== DAHDI_LAW_ALAW
) ? PRI_LAYER_1_ALAW
: PRI_LAYER_1_ULAW
);
5390 ast_mutex_unlock(&p
->lock
);
5395 #if defined(HAVE_SS7)
5396 if (p
->sig
== SIG_SS7
) {
5397 res
= sig_ss7_call(p
->sig_pvt
, ast
, rdest
);
5398 ast_mutex_unlock(&p
->lock
);
5401 #endif /* defined(HAVE_SS7) */
5403 /* If this is analog signalling we can exit here */
5404 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
5405 p
->callwaitrings
= 0;
5406 res
= analog_call(p
->sig_pvt
, ast
, rdest
, timeout
);
5407 ast_mutex_unlock(&p
->lock
);
5411 mysig
= p
->outsigmod
> -1 ? p
->outsigmod
: p
->sig
;
5414 /* Special pseudo -- automatically up*/
5415 ast_setstate(ast
, AST_STATE_UP
);
5420 ast_debug(1, "not yet implemented\n");
5421 ast_mutex_unlock(&p
->lock
);
5427 openr2_calling_party_category_t chancat
;
5431 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
5432 p
->dialdest
[0] = '\0';
5435 if (!p
->hidecallerid
) {
5436 l
= ast_channel_connected(ast
)->id
.number
.valid
? ast_channel_connected(ast
)->id
.number
.str
: NULL
;
5440 if (strlen(c
) < p
->stripmsd
) {
5441 ast_log(LOG_WARNING
, "Number '%s' is shorter than stripmsd (%d)\n", c
, p
->stripmsd
);
5442 ast_mutex_unlock(&p
->lock
);
5446 chancat
= dahdi_r2_get_channel_category(ast
);
5447 callres
= openr2_chan_make_call(p
->r2chan
, l
, (c
+ p
->stripmsd
), chancat
);
5448 if (-1 == callres
) {
5449 ast_mutex_unlock(&p
->lock
);
5450 ast_log(LOG_ERROR
, "unable to make new MFC/R2 call!\n");
5453 p
->mfcr2_call_accepted
= 0;
5454 p
->mfcr2_progress_sent
= 0;
5455 ast_setstate(ast
, AST_STATE_DIALING
);
5457 #endif /* HAVE_OPENR2 */
5458 ast_mutex_unlock(&p
->lock
);
5464 * \brief Insert the given chan_dahdi interface structure into the interface list.
5467 * \param pvt chan_dahdi private interface structure to insert.
5470 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5471 * Any duplicates are inserted after the existing entries.
5473 * \note The new interface must not already be in the list.
5475 static void dahdi_iflist_insert(struct dahdi_pvt
*pvt
)
5477 struct dahdi_pvt
*cur
;
5479 pvt
->which_iflist
= DAHDI_IFLIST_MAIN
;
5481 /* Find place in middle of list for the new interface. */
5482 for (cur
= iflist
; cur
; cur
= cur
->next
) {
5483 if (pvt
->channel
< cur
->channel
) {
5484 /* New interface goes before the current interface. */
5485 pvt
->prev
= cur
->prev
;
5488 /* Insert into the middle of the list. */
5489 cur
->prev
->next
= pvt
;
5491 /* Insert at head of list. */
5499 /* New interface goes onto the end of the list */
5507 /* List was empty */
5514 * \brief Extract the given chan_dahdi interface structure from the interface list.
5517 * \param pvt chan_dahdi private interface structure to extract.
5520 * The given interface structure can be either in the interface list or a stand alone
5521 * structure that has not been put in the list if the next and prev pointers are NULL.
5523 static void dahdi_iflist_extract(struct dahdi_pvt
*pvt
)
5525 /* Extract from the forward chain. */
5527 pvt
->prev
->next
= pvt
->next
;
5528 } else if (iflist
== pvt
) {
5529 /* Node is at the head of the list. */
5533 /* Extract from the reverse chain. */
5535 pvt
->next
->prev
= pvt
->prev
;
5536 } else if (ifend
== pvt
) {
5537 /* Node is at the end of the list. */
5541 /* Node is no longer in the list. */
5542 pvt
->which_iflist
= DAHDI_IFLIST_NONE
;
5547 #if defined(HAVE_PRI)
5550 * \brief Insert the given chan_dahdi interface structure into the no B channel list.
5553 * \param pri sig_pri span control structure holding no B channel list.
5554 * \param pvt chan_dahdi private interface structure to insert.
5557 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5558 * Any duplicates are inserted after the existing entries.
5560 * \note The new interface must not already be in the list.
5562 static void dahdi_nobch_insert(struct sig_pri_span
*pri
, struct dahdi_pvt
*pvt
)
5564 struct dahdi_pvt
*cur
;
5566 pvt
->which_iflist
= DAHDI_IFLIST_NO_B_CHAN
;
5568 /* Find place in middle of list for the new interface. */
5569 for (cur
= pri
->no_b_chan_iflist
; cur
; cur
= cur
->next
) {
5570 if (pvt
->channel
< cur
->channel
) {
5571 /* New interface goes before the current interface. */
5572 pvt
->prev
= cur
->prev
;
5575 /* Insert into the middle of the list. */
5576 cur
->prev
->next
= pvt
;
5578 /* Insert at head of list. */
5579 pri
->no_b_chan_iflist
= pvt
;
5586 /* New interface goes onto the end of the list */
5587 pvt
->prev
= pri
->no_b_chan_end
;
5589 if (pri
->no_b_chan_end
) {
5590 ((struct dahdi_pvt
*) pri
->no_b_chan_end
)->next
= pvt
;
5592 pri
->no_b_chan_end
= pvt
;
5593 if (!pri
->no_b_chan_iflist
) {
5594 /* List was empty */
5595 pri
->no_b_chan_iflist
= pvt
;
5598 #endif /* defined(HAVE_PRI) */
5600 #if defined(HAVE_PRI)
5603 * \brief Extract the given chan_dahdi interface structure from the no B channel list.
5606 * \param pri sig_pri span control structure holding no B channel list.
5607 * \param pvt chan_dahdi private interface structure to extract.
5610 * The given interface structure can be either in the interface list or a stand alone
5611 * structure that has not been put in the list if the next and prev pointers are NULL.
5613 static void dahdi_nobch_extract(struct sig_pri_span
*pri
, struct dahdi_pvt
*pvt
)
5615 /* Extract from the forward chain. */
5617 pvt
->prev
->next
= pvt
->next
;
5618 } else if (pri
->no_b_chan_iflist
== pvt
) {
5619 /* Node is at the head of the list. */
5620 pri
->no_b_chan_iflist
= pvt
->next
;
5623 /* Extract from the reverse chain. */
5625 pvt
->next
->prev
= pvt
->prev
;
5626 } else if (pri
->no_b_chan_end
== pvt
) {
5627 /* Node is at the end of the list. */
5628 pri
->no_b_chan_end
= pvt
->prev
;
5631 /* Node is no longer in the list. */
5632 pvt
->which_iflist
= DAHDI_IFLIST_NONE
;
5636 #endif /* defined(HAVE_PRI) */
5638 #if defined(HAVE_PRI)
5641 * \brief Unlink the channel interface from the PRI private pointer array.
5644 * \param pvt chan_dahdi private interface structure to unlink.
5646 static void dahdi_unlink_pri_pvt(struct dahdi_pvt
*pvt
)
5649 struct sig_pri_span
*pri
;
5653 /* Not PRI signaling so cannot be in a PRI private pointer array. */
5656 ast_mutex_lock(&pri
->lock
);
5657 for (idx
= 0; idx
< pri
->numchans
; ++idx
) {
5658 if (pri
->pvts
[idx
] == pvt
->sig_pvt
) {
5659 pri
->pvts
[idx
] = NULL
;
5660 ast_mutex_unlock(&pri
->lock
);
5664 ast_mutex_unlock(&pri
->lock
);
5666 #endif /* defined(HAVE_PRI) */
5668 #if defined(HAVE_SS7)
5671 * \brief Unlink the channel interface from the SS7 private pointer array.
5674 * \param pvt chan_dahdi private interface structure to unlink.
5676 static void dahdi_unlink_ss7_pvt(struct dahdi_pvt
*pvt
)
5679 struct sig_ss7_linkset
*ss7
;
5683 /* Not SS7 signaling so cannot be in a SS7 private pointer array. */
5686 ast_mutex_lock(&ss7
->lock
);
5687 for (idx
= 0; idx
< ss7
->numchans
; ++idx
) {
5688 if (ss7
->pvts
[idx
] == pvt
->sig_pvt
) {
5689 ss7
->pvts
[idx
] = NULL
;
5690 ast_mutex_unlock(&ss7
->lock
);
5694 ast_mutex_unlock(&ss7
->lock
);
5696 #endif /* defined(HAVE_SS7) */
5698 #if defined(HAVE_OPENR2)
5701 * \brief Unlink the channel interface from the MFC/R2 private pointer array.
5703 * \param pvt chan_dahdi private interface structure to unlink.
5705 static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt
*pvt
)
5708 struct dahdi_mfcr2
*mfcr2
;
5709 int should_destroy_link
= 0;
5711 ast_mutex_lock(&pvt
->lock
);
5713 ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt
->channel
);
5714 openr2_chan_disable_read(pvt
->r2chan
);
5718 for (idx
= 0; idx
< mfcr2
->numchans
; ++idx
) {
5719 if (mfcr2
->pvts
[idx
] == pvt
) {
5720 ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt
->channel
);
5721 mfcr2
->pvts
[idx
] = NULL
;
5722 mfcr2
->live_chans
--;
5726 if (!mfcr2
->live_chans
) {
5727 ast_debug(1, "MFC/R2 link is now empty\n");
5728 should_destroy_link
= 1;
5731 ast_mutex_unlock(&pvt
->lock
);
5732 if (should_destroy_link
) {
5733 ast_debug(1, "MFC/R2 link is now empty\n");
5734 mfcr2_queue_for_destruction(pvt
);
5737 #endif /* defined(HAVE_OPENR2) */
5739 static struct dahdi_pvt
*find_next_iface_in_span(struct dahdi_pvt
*cur
)
5741 if (cur
->next
&& cur
->next
->span
== cur
->span
) {
5743 } else if (cur
->prev
&& cur
->prev
->span
== cur
->span
) {
5750 static void destroy_dahdi_pvt(struct dahdi_pvt
*pvt
)
5752 struct dahdi_pvt
*p
= pvt
;
5754 if (p
->manages_span_alarms
) {
5755 struct dahdi_pvt
*next
= find_next_iface_in_span(p
);
5757 next
->manages_span_alarms
= 1;
5761 /* Remove channel from the list */
5762 #if defined(HAVE_PRI)
5763 dahdi_unlink_pri_pvt(p
);
5764 #endif /* defined(HAVE_PRI) */
5765 #if defined(HAVE_SS7)
5766 dahdi_unlink_ss7_pvt(p
);
5767 #endif /* defined(HAVE_SS7) */
5768 #if defined(HAVE_OPENR2)
5769 dahdi_unlink_mfcr2_pvt(p
);
5770 #endif /* defined(HAVE_SS7) */
5771 switch (pvt
->which_iflist
) {
5772 case DAHDI_IFLIST_NONE
:
5774 case DAHDI_IFLIST_MAIN
:
5775 dahdi_iflist_extract(p
);
5777 #if defined(HAVE_PRI)
5778 case DAHDI_IFLIST_NO_B_CHAN
:
5780 dahdi_nobch_extract(p
->pri
, p
);
5783 #endif /* defined(HAVE_PRI) */
5787 if (dahdi_analog_lib_handles(p
->sig
, 0, 0)) {
5788 analog_delete(p
->sig_pvt
);
5791 #if defined(HAVE_PRI)
5792 case SIG_PRI_LIB_HANDLE_CASES
:
5793 sig_pri_chan_delete(p
->sig_pvt
);
5795 #endif /* defined(HAVE_PRI) */
5796 #if defined(HAVE_SS7)
5798 sig_ss7_chan_delete(p
->sig_pvt
);
5800 #endif /* defined(HAVE_SS7) */
5805 ast_free(p
->cidspill
);
5807 ao2_cleanup(p
->smdi_iface
);
5809 if (p
->mwi_event_sub
) {
5810 p
->mwi_event_sub
= ast_mwi_unsubscribe(p
->mwi_event_sub
);
5813 ast_variables_destroy(p
->vars
);
5816 ast_cc_config_params_destroy(p
->cc_params
);
5819 p
->named_callgroups
= ast_unref_namedgroups(p
->named_callgroups
);
5820 p
->named_pickupgroups
= ast_unref_namedgroups(p
->named_pickupgroups
);
5822 ast_mutex_destroy(&p
->lock
);
5823 dahdi_close_sub(p
, SUB_REAL
);
5825 ast_channel_tech_pvt_set(p
->owner
, NULL
);
5830 static void destroy_channel(struct dahdi_pvt
*cur
, int now
)
5835 /* Do not destroy the channel now if it is owned by someone. */
5839 for (i
= 0; i
< 3; i
++) {
5840 if (cur
->subs
[i
].owner
) {
5845 destroy_dahdi_pvt(cur
);
5848 static void destroy_all_channels(void)
5851 #if defined(HAVE_PRI)
5853 struct sig_pri_span
*pri
;
5854 #endif /* defined(HAVE_PRI) */
5855 struct dahdi_pvt
*p
;
5857 while (num_restart_pending
) {
5861 ast_mutex_lock(&iflock
);
5862 /* Destroy all the interfaces and free their memory */
5867 #if defined(HAVE_PRI_SERVICE_MESSAGES)
5869 char db_chan_name
[20];
5874 snprintf(db_chan_name
, sizeof(db_chan_name
), "%s/%d:%d", dahdi_db
, p
->span
, chan
);
5875 if (!ast_db_get(db_chan_name
, SRVST_DBKEY
, db_answer
, sizeof(db_answer
))) {
5876 sscanf(db_answer
, "%1c:%30d", &state
, &why
);
5879 /* SRVST persistence is not required */
5880 ast_db_del(db_chan_name
, SRVST_DBKEY
);
5883 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
5884 /* Free associated memory */
5885 destroy_dahdi_pvt(p
);
5886 ast_verb(3, "Unregistered channel %d\n", chan
);
5889 ast_mutex_unlock(&iflock
);
5891 #if defined(HAVE_PRI)
5892 /* Destroy all of the no B channel interface lists */
5893 for (span
= 0; span
< NUM_SPANS
; ++span
) {
5894 if (!pris
[span
].dchannels
[0]) {
5897 pri
= &pris
[span
].pri
;
5898 ast_mutex_lock(&pri
->lock
);
5899 while (pri
->no_b_chan_iflist
) {
5900 p
= pri
->no_b_chan_iflist
;
5902 /* Free associated memory */
5903 destroy_dahdi_pvt(p
);
5905 ast_mutex_unlock(&pri
->lock
);
5907 #endif /* defined(HAVE_PRI) */
5910 #if defined(HAVE_PRI)
5911 static char *dahdi_send_keypad_facility_app
= "DAHDISendKeypadFacility";
5913 static int dahdi_send_keypad_facility_exec(struct ast_channel
*chan
, const char *digits
)
5915 /* Data will be our digit string */
5916 struct dahdi_pvt
*p
;
5918 if (ast_strlen_zero(digits
)) {
5919 ast_debug(1, "No digit string sent to application!\n");
5923 p
= (struct dahdi_pvt
*)ast_channel_tech_pvt(chan
);
5926 ast_debug(1, "Unable to find technology private\n");
5930 pri_send_keypad_facility_exec(p
->sig_pvt
, digits
);
5934 #endif /* defined(HAVE_PRI) */
5936 #if defined(HAVE_PRI)
5937 #if defined(HAVE_PRI_PROG_W_CAUSE)
5938 static char *dahdi_send_callrerouting_facility_app
= "DAHDISendCallreroutingFacility";
5940 static int dahdi_send_callrerouting_facility_exec(struct ast_channel
*chan
, const char *data
)
5942 /* Data will be our digit string */
5943 struct dahdi_pvt
*pvt
;
5946 AST_DECLARE_APP_ARGS(args
,
5947 AST_APP_ARG(destination
);
5948 AST_APP_ARG(original
);
5949 AST_APP_ARG(reason
);
5952 if (ast_strlen_zero(data
)) {
5953 ast_debug(1, "No data sent to application!\n");
5956 if (ast_channel_tech(chan
) != &dahdi_tech
) {
5957 ast_debug(1, "Only DAHDI technology accepted!\n");
5960 pvt
= (struct dahdi_pvt
*) ast_channel_tech_pvt(chan
);
5962 ast_debug(1, "Unable to find technology private\n");
5966 case SIG_PRI_LIB_HANDLE_CASES
:
5969 ast_debug(1, "callrerouting attempted on non-ISDN channel %s\n",
5970 ast_channel_name(chan
));
5974 parse
= ast_strdupa(data
);
5975 AST_STANDARD_APP_ARGS(args
, parse
);
5977 if (ast_strlen_zero(args
.destination
)) {
5978 ast_log(LOG_WARNING
, "callrerouting facility requires at least destination number argument\n");
5982 if (ast_strlen_zero(args
.original
)) {
5983 ast_log(LOG_WARNING
, "Callrerouting Facility without original called number argument\n");
5984 args
.original
= NULL
;
5987 if (ast_strlen_zero(args
.reason
)) {
5988 ast_log(LOG_NOTICE
, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n");
5992 res
= pri_send_callrerouting_facility_exec(pvt
->sig_pvt
, ast_channel_state(chan
),
5993 args
.destination
, args
.original
, args
.reason
);
5996 * Wait up to 5 seconds for a reply before hanging up this call
5997 * leg if the peer does not disconnect first.
5999 ast_safe_sleep(chan
, 5000);
6004 #endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
6005 #endif /* defined(HAVE_PRI) */
6007 #if defined(HAVE_OPENR2)
6008 static const char * const dahdi_accept_r2_call_app
= "DAHDIAcceptR2Call";
6010 static int dahdi_accept_r2_call_exec(struct ast_channel
*chan
, const char *data
)
6012 /* data is whether to accept with charge or no charge */
6013 openr2_call_mode_t accept_mode
;
6014 int res
, timeout
, maxloops
;
6015 struct ast_frame
*f
;
6016 struct dahdi_pvt
*p
;
6018 AST_DECLARE_APP_ARGS(args
,
6019 AST_APP_ARG(charge
);
6022 if (ast_strlen_zero(data
)) {
6023 ast_debug(1, "No data sent to application!\n");
6027 if (ast_channel_tech(chan
) != &dahdi_tech
) {
6028 ast_debug(1, "Only DAHDI technology accepted!\n");
6032 p
= (struct dahdi_pvt
*)ast_channel_tech_pvt(chan
);
6034 ast_debug(1, "Unable to find technology private!\n");
6038 parse
= ast_strdupa(data
);
6039 AST_STANDARD_APP_ARGS(args
, parse
);
6041 if (ast_strlen_zero(args
.charge
)) {
6042 ast_log(LOG_WARNING
, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
6046 ast_mutex_lock(&p
->lock
);
6047 if (!p
->mfcr2
|| !p
->mfcr2call
) {
6048 ast_mutex_unlock(&p
->lock
);
6049 ast_debug(1, "Channel %s does not seems to be an R2 active channel!\n", ast_channel_name(chan
));
6053 if (p
->mfcr2_call_accepted
) {
6054 ast_mutex_unlock(&p
->lock
);
6055 ast_debug(1, "MFC/R2 call already accepted on channel %s!\n", ast_channel_name(chan
));
6058 accept_mode
= ast_true(args
.charge
) ? OR2_CALL_WITH_CHARGE
: OR2_CALL_NO_CHARGE
;
6059 if (openr2_chan_accept_call(p
->r2chan
, accept_mode
)) {
6060 ast_mutex_unlock(&p
->lock
);
6061 ast_log(LOG_WARNING
, "Failed to accept MFC/R2 call!\n");
6064 ast_mutex_unlock(&p
->lock
);
6068 maxloops
= 50; /* wait up to 5 seconds */
6069 /* we need to read() until the call is accepted */
6070 while (maxloops
> 0) {
6072 if (ast_check_hangup(chan
)) {
6075 res
= ast_waitfor(chan
, timeout
);
6077 ast_debug(1, "ast_waitfor failed on channel %s, going out ...\n", ast_channel_name(chan
));
6087 ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan
));
6091 if (f
->frametype
== AST_FRAME_CONTROL
&& f
->subclass
.integer
== AST_CONTROL_HANGUP
) {
6092 ast_debug(1, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan
));
6098 ast_mutex_lock(&p
->lock
);
6099 if (p
->mfcr2_call_accepted
) {
6100 ast_mutex_unlock(&p
->lock
);
6101 ast_debug(1, "Accepted MFC/R2 call!\n");
6104 ast_mutex_unlock(&p
->lock
);
6107 ast_log(LOG_WARNING
, "Failed to accept MFC/R2 call!\n");
6112 static openr2_call_disconnect_cause_t
dahdi_ast_cause_to_r2_cause(int cause
)
6114 openr2_call_disconnect_cause_t r2cause
= OR2_CAUSE_NORMAL_CLEARING
;
6116 case AST_CAUSE_USER_BUSY
:
6117 case AST_CAUSE_CALL_REJECTED
:
6118 case AST_CAUSE_INTERWORKING
: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
6119 r2cause
= OR2_CAUSE_BUSY_NUMBER
;
6122 case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION
:
6123 case AST_CAUSE_SWITCH_CONGESTION
:
6124 r2cause
= OR2_CAUSE_NETWORK_CONGESTION
;
6127 case AST_CAUSE_UNALLOCATED
:
6128 r2cause
= OR2_CAUSE_UNALLOCATED_NUMBER
;
6131 case AST_CAUSE_NETWORK_OUT_OF_ORDER
:
6132 case AST_CAUSE_DESTINATION_OUT_OF_ORDER
:
6133 r2cause
= OR2_CAUSE_OUT_OF_ORDER
;
6136 case AST_CAUSE_NO_ANSWER
:
6137 case AST_CAUSE_NO_USER_RESPONSE
:
6138 r2cause
= OR2_CAUSE_NO_ANSWER
;
6142 r2cause
= OR2_CAUSE_NORMAL_CLEARING
;
6145 ast_debug(1, "ast cause %d resulted in openr2 cause %d/%s\n",
6146 cause
, r2cause
, openr2_proto_get_disconnect_string(r2cause
));
6151 static int revert_fax_buffers(struct dahdi_pvt
*p
, struct ast_channel
*ast
)
6153 if (p
->bufferoverrideinuse
) {
6154 /* faxbuffers are in use, revert them */
6155 struct dahdi_bufferinfo bi
= {
6156 .txbufpolicy
= p
->buf_policy
,
6157 .rxbufpolicy
= p
->buf_policy
,
6158 .bufsize
= p
->bufsize
,
6159 .numbufs
= p
->buf_no
6163 if ((bpres
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
6164 ast_log(LOG_WARNING
, "Channel '%s' unable to revert buffer policy: %s\n", ast_channel_name(ast
), strerror(errno
));
6166 p
->bufferoverrideinuse
= 0;
6173 static int dahdi_hangup(struct ast_channel
*ast
)
6178 /*static int restore_gains(struct dahdi_pvt *p);*/
6179 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
6180 struct dahdi_params par
;
6182 ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast
));
6183 if (!ast_channel_tech_pvt(ast
)) {
6184 ast_log(LOG_WARNING
, "Asked to hangup channel not connected\n");
6188 ast_mutex_lock(&p
->lock
);
6190 /* Always use sig_analog hangup handling for operator mode */
6191 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, 0)) {
6193 dahdi_confmute(p
, 0);
6196 p
->waitingfordt
.tv_sec
= 0;
6198 res
= analog_hangup(p
->sig_pvt
, ast
);
6199 revert_fax_buffers(p
, ast
);
6203 p
->cid_num
[0] = '\0';
6204 p
->cid_name
[0] = '\0';
6205 p
->cid_subaddr
[0] = '\0';
6208 #if defined(HAVE_PRI)
6209 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
6211 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6213 dahdi_confmute(p
, 0);
6217 ast_dsp_free(p
->dsp
);
6222 /* Real channel, do some fixup */
6223 p
->subs
[SUB_REAL
].owner
= NULL
;
6224 p
->subs
[SUB_REAL
].needbusy
= 0;
6225 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
6228 p
->cid_tag
[0] = '\0';
6229 p
->ringt
= 0;/* Probably not used in this mode. Reset anyway. */
6230 p
->distinctivering
= 0;/* Probably not used in this mode. Reset anyway. */
6231 p
->confirmanswer
= 0;/* Probably not used in this mode. Reset anyway. */
6235 p
->pulsedial
= 0;/* Probably not used in this mode. Reset anyway. */
6237 revert_fax_buffers(p
, ast
);
6239 p
->law
= p
->law_default
;
6240 law
= p
->law_default
;
6241 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
6243 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n",
6244 p
->channel
, strerror(errno
));
6247 sig_pri_hangup(p
->sig_pvt
, ast
);
6249 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6250 dahdi_ec_disable(p
);
6253 ast_channel_setoption(ast
, AST_OPTION_TDD
, &x
, sizeof(char), 0);
6254 p
->didtdd
= 0;/* Probably not used in this mode. Reset anyway. */
6257 dahdi_conf_update(p
);
6260 /* Restore data mode */
6262 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6264 if (num_restart_pending
== 0) {
6269 #endif /* defined(HAVE_PRI) */
6271 #if defined(HAVE_SS7)
6272 if (p
->sig
== SIG_SS7
) {
6274 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6276 dahdi_confmute(p
, 0);
6280 ast_dsp_free(p
->dsp
);
6285 /* Real channel, do some fixup */
6286 p
->subs
[SUB_REAL
].owner
= NULL
;
6287 p
->subs
[SUB_REAL
].needbusy
= 0;
6288 dahdi_setlinear(p
->subs
[SUB_REAL
].dfd
, 0);
6291 p
->ringt
= 0;/* Probably not used in this mode. Reset anyway. */
6292 p
->distinctivering
= 0;/* Probably not used in this mode. Reset anyway. */
6293 p
->confirmanswer
= 0;/* Probably not used in this mode. Reset anyway. */
6297 p
->pulsedial
= 0;/* Probably not used in this mode. Reset anyway. */
6299 revert_fax_buffers(p
, ast
);
6301 p
->law
= p
->law_default
;
6302 law
= p
->law_default
;
6303 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
6305 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n",
6306 p
->channel
, strerror(errno
));
6309 sig_ss7_hangup(p
->sig_pvt
, ast
);
6311 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6312 dahdi_ec_disable(p
);
6315 ast_channel_setoption(ast
, AST_OPTION_TDD
, &x
, sizeof(char), 0);
6316 p
->didtdd
= 0;/* Probably not used in this mode. Reset anyway. */
6318 dahdi_conf_update(p
);
6321 /* Restore data mode */
6323 ast_channel_setoption(ast
, AST_OPTION_AUDIO_MODE
, &x
, sizeof(char), 0);
6325 if (num_restart_pending
== 0) {
6330 #endif /* defined(HAVE_SS7) */
6332 idx
= dahdi_get_index(ast
, p
, 1);
6334 dahdi_confmute(p
, 0);
6337 if (p
->origcid_num
) {
6338 ast_copy_string(p
->cid_num
, p
->origcid_num
, sizeof(p
->cid_num
));
6339 ast_free(p
->origcid_num
);
6340 p
->origcid_num
= NULL
;
6342 if (p
->origcid_name
) {
6343 ast_copy_string(p
->cid_name
, p
->origcid_name
, sizeof(p
->cid_name
));
6344 ast_free(p
->origcid_name
);
6345 p
->origcid_name
= NULL
;
6348 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
6350 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
6351 p
->channel
, idx
, p
->subs
[SUB_REAL
].dfd
, p
->subs
[SUB_CALLWAIT
].dfd
, p
->subs
[SUB_THREEWAY
].dfd
);
6355 /* Real channel, do some fixup */
6356 p
->subs
[idx
].owner
= NULL
;
6357 p
->subs
[idx
].needanswer
= 0;
6358 p
->subs
[idx
].needflash
= 0;
6359 p
->subs
[idx
].needringing
= 0;
6360 p
->subs
[idx
].needbusy
= 0;
6361 p
->subs
[idx
].needcongestion
= 0;
6362 p
->subs
[idx
].linear
= 0;
6363 p
->polarity
= POLARITY_IDLE
;
6364 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
6365 if (idx
== SUB_REAL
) {
6366 if ((p
->subs
[SUB_CALLWAIT
].dfd
> -1) && (p
->subs
[SUB_THREEWAY
].dfd
> -1)) {
6367 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
6368 if (p
->subs
[SUB_CALLWAIT
].inthreeway
) {
6369 /* We had flipped over to answer a callwait and now it's gone */
6370 ast_debug(1, "We were flipped over to the callwait, moving back and not owning.\n");
6371 /* Move to the call-wait, but un-own us until they flip back. */
6372 swap_subs(p
, SUB_CALLWAIT
, SUB_REAL
);
6373 unalloc_sub(p
, SUB_CALLWAIT
);
6376 /* The three way hung up, but we still have a call wait */
6377 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
6378 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
6379 unalloc_sub(p
, SUB_THREEWAY
);
6380 if (p
->subs
[SUB_REAL
].inthreeway
) {
6381 /* This was part of a three way call. Immediately make way for
6383 ast_debug(1, "Call was complete, setting owner to former third call\n");
6384 p
->owner
= p
->subs
[SUB_REAL
].owner
;
6386 /* This call hasn't been completed yet... Set owner to NULL */
6387 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6390 p
->subs
[SUB_REAL
].inthreeway
= 0;
6392 } else if (p
->subs
[SUB_CALLWAIT
].dfd
> -1) {
6393 /* Move to the call-wait and switch back to them. */
6394 swap_subs(p
, SUB_CALLWAIT
, SUB_REAL
);
6395 unalloc_sub(p
, SUB_CALLWAIT
);
6396 p
->owner
= p
->subs
[SUB_REAL
].owner
;
6397 if (ast_channel_state(p
->owner
) != AST_STATE_UP
)
6398 p
->subs
[SUB_REAL
].needanswer
= 1;
6399 ast_queue_unhold(p
->subs
[SUB_REAL
].owner
);
6400 } else if (p
->subs
[SUB_THREEWAY
].dfd
> -1) {
6401 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
6402 unalloc_sub(p
, SUB_THREEWAY
);
6403 if (p
->subs
[SUB_REAL
].inthreeway
) {
6404 /* This was part of a three way call. Immediately make way for
6406 ast_debug(1, "Call was complete, setting owner to former third call\n");
6407 p
->owner
= p
->subs
[SUB_REAL
].owner
;
6409 /* This call hasn't been completed yet... Set owner to NULL */
6410 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6413 p
->subs
[SUB_REAL
].inthreeway
= 0;
6415 } else if (idx
== SUB_CALLWAIT
) {
6416 /* Ditch the holding callwait call, and immediately make it availabe */
6417 if (p
->subs
[SUB_CALLWAIT
].inthreeway
) {
6418 /* This is actually part of a three way, placed on hold. Place the third part
6419 on music on hold now */
6420 if (p
->subs
[SUB_THREEWAY
].owner
) {
6421 ast_queue_hold(p
->subs
[SUB_THREEWAY
].owner
, p
->mohsuggest
);
6423 p
->subs
[SUB_THREEWAY
].inthreeway
= 0;
6424 /* Make it the call wait now */
6425 swap_subs(p
, SUB_CALLWAIT
, SUB_THREEWAY
);
6426 unalloc_sub(p
, SUB_THREEWAY
);
6428 unalloc_sub(p
, SUB_CALLWAIT
);
6429 } else if (idx
== SUB_THREEWAY
) {
6430 if (p
->subs
[SUB_CALLWAIT
].inthreeway
) {
6431 /* The other party of the three way call is currently in a call-wait state.
6432 Start music on hold for them, and take the main guy out of the third call */
6433 if (p
->subs
[SUB_CALLWAIT
].owner
) {
6434 ast_queue_hold(p
->subs
[SUB_CALLWAIT
].owner
, p
->mohsuggest
);
6436 p
->subs
[SUB_CALLWAIT
].inthreeway
= 0;
6438 p
->subs
[SUB_REAL
].inthreeway
= 0;
6439 /* If this was part of a three way call index, let us make
6440 another three way call */
6441 unalloc_sub(p
, SUB_THREEWAY
);
6443 /* This wasn't any sort of call, but how are we an index? */
6444 ast_log(LOG_WARNING
, "Index found but not any type of call?\n");
6448 if (!p
->subs
[SUB_REAL
].owner
&& !p
->subs
[SUB_CALLWAIT
].owner
&& !p
->subs
[SUB_THREEWAY
].owner
) {
6451 p
->distinctivering
= 0;
6452 p
->confirmanswer
= 0;
6458 ast_dsp_free(p
->dsp
);
6462 revert_fax_buffers(p
, ast
);
6464 p
->law
= p
->law_default
;
6465 law
= p
->law_default
;
6466 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SETLAW
, &law
);
6468 ast_log(LOG_WARNING
, "Unable to set law on channel %d to default: %s\n", p
->channel
, strerror(errno
));
6469 /* Perform low level hangup if no owner left */
6471 if (p
->mfcr2
&& p
->mfcr2call
&& openr2_chan_get_direction(p
->r2chan
) != OR2_DIR_STOPPED
) {
6472 ast_debug(1, "disconnecting MFC/R2 call on chan %d\n", p
->channel
);
6473 /* If it's an incoming call, check the mfcr2_forced_release setting */
6474 if (openr2_chan_get_direction(p
->r2chan
) == OR2_DIR_BACKWARD
&& p
->mfcr2_forced_release
) {
6475 dahdi_r2_disconnect_call(p
, OR2_CAUSE_FORCED_RELEASE
);
6477 const char *r2causestr
= pbx_builtin_getvar_helper(ast
, "MFCR2_CAUSE");
6478 int r2cause_user
= r2causestr
? atoi(r2causestr
) : 0;
6479 openr2_call_disconnect_cause_t r2cause
= r2cause_user
? dahdi_ast_cause_to_r2_cause(r2cause_user
)
6480 : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast
));
6481 dahdi_r2_disconnect_call(p
, r2cause
);
6483 } else if (p
->mfcr2call
) {
6484 ast_debug(1, "Clearing call request on channel %d\n", p
->channel
);
6485 /* since ast_request() was called but not ast_call() we have not yet dialed
6486 and the openr2 stack will not call on_call_end callback, we need to unset
6487 the mfcr2call flag and bump the monitor count so the monitor thread can take
6488 care of this channel events from now on */
6495 case SIG_PRI_LIB_HANDLE_CASES
:
6499 res
= dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
6503 ast_log(LOG_WARNING
, "Unable to hangup line %s\n", ast_channel_name(ast
));
6509 memset(&par
, 0, sizeof(par
));
6510 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &par
);
6512 struct analog_pvt
*analog_p
= p
->sig_pvt
;
6514 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p
->channel
, par
.rxisoffhook
);
6516 /* If they're off hook, try playing congestion */
6517 if ((par
.rxisoffhook
) && (!(p
->radio
|| (p
->oprmode
< 0))))
6518 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
6520 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6521 analog_p
->fxsoffhookstate
= par
.rxisoffhook
;
6527 /* Make sure we're not made available for at least two seconds assuming
6528 we were actually used for an inbound or outbound call. */
6529 if (ast_channel_state(ast
) != AST_STATE_RESERVED
) {
6530 time(&p
->guardtime
);
6535 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
6539 dahdi_ec_disable(p
);
6541 ast_channel_setoption(ast
,AST_OPTION_TONE_VERIFY
,&x
,sizeof(char),0);
6542 ast_channel_setoption(ast
,AST_OPTION_TDD
,&x
,sizeof(char),0);
6545 p
->callwaiting
= p
->permcallwaiting
;
6546 p
->hidecallerid
= p
->permhidecallerid
;
6547 p
->waitingfordt
.tv_sec
= 0;
6550 dahdi_conf_update(p
);
6552 /* Restore data mode */
6554 case SIG_PRI_LIB_HANDLE_CASES
:
6557 ast_channel_setoption(ast
,AST_OPTION_AUDIO_MODE
,&x
,sizeof(char),0);
6562 if (num_restart_pending
== 0)
6566 p
->callwaitingrepeat
= 0;
6568 p
->cid_suppress_expire
= 0;
6571 ast_channel_tech_pvt_set(ast
, NULL
);
6572 ast_free(p
->cidspill
);
6575 if (p
->reoriginate
&& p
->sig
== SIG_FXOKS
&& dahdi_analog_lib_handles(p
->sig
, p
->radio
, 0)) {
6576 /* Automatic reorigination: if all calls towards a user have hung up,
6577 * give dial tone again, so user doesn't need to cycle the hook state manually. */
6578 if (my_is_off_hook(p
) && !p
->owner
) {
6579 /* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
6580 ast_debug(1, "Queuing reorigination for channel %d\n", p
->channel
);
6581 my_play_tone(p
, SUB_REAL
, -1); /* Stop any congestion tone that may be present. */
6582 /* Must wait for the loop disconnect to end.
6583 * Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
6584 * Calling usleep on an active DAHDI channel is a no-no, but this is okay.
6586 usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
6587 /* If the line is still off-hook and ownerless, actually queue the reorigination.
6588 * do_monitor will actually go ahead and do it. */
6589 if (!p
->owner
&& my_is_off_hook(p
)) {
6590 p
->doreoriginate
= 1; /* Tell do_monitor to reoriginate this channel */
6591 /* Note, my_off_hook will fail if called before the loop disconnect has finished
6592 * (important for FXOKS signaled channels). This is because DAHDI will reject
6593 * DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
6594 * so we have to wait for that to finish (see comment above).
6595 * do_monitor itself cannot block, so make the blocking usleep call
6596 * here in the channel thread instead.
6598 my_off_hook(p
); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
6600 ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p
->channel
);
6605 ast_mutex_unlock(&p
->lock
);
6606 ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast
));
6608 ast_mutex_lock(&iflock
);
6609 if (p
->restartpending
) {
6610 num_restart_pending
--;
6614 destroy_channel(p
, 0);
6616 ast_mutex_unlock(&iflock
);
6618 ast_module_unref(ast_module_info
->self
);
6622 static int dahdi_answer(struct ast_channel
*ast
)
6624 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
6627 ast_setstate(ast
, AST_STATE_UP
);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
6628 ast_mutex_lock(&p
->lock
);
6629 idx
= dahdi_get_index(ast
, p
, 0);
6632 /* nothing to do if a radio channel */
6633 if ((p
->radio
|| (p
->oprmode
< 0))) {
6634 ast_mutex_unlock(&p
->lock
);
6638 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
6639 res
= analog_answer(p
->sig_pvt
, ast
);
6640 ast_mutex_unlock(&p
->lock
);
6645 #if defined(HAVE_PRI)
6646 case SIG_PRI_LIB_HANDLE_CASES
:
6647 res
= sig_pri_answer(p
->sig_pvt
, ast
);
6649 #endif /* defined(HAVE_PRI) */
6650 #if defined(HAVE_SS7)
6652 res
= sig_ss7_answer(p
->sig_pvt
, ast
);
6654 #endif /* defined(HAVE_SS7) */
6657 if (!p
->mfcr2_call_accepted
) {
6658 /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
6659 openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
6660 p
->mfcr2_answer_pending
= 1;
6661 if (p
->mfcr2_charge_calls
) {
6662 ast_debug(1, "Accepting MFC/R2 call with charge before answering on chan %d\n", p
->channel
);
6663 openr2_chan_accept_call(p
->r2chan
, OR2_CALL_WITH_CHARGE
);
6665 ast_debug(1, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p
->channel
);
6666 openr2_chan_accept_call(p
->r2chan
, OR2_CALL_NO_CHARGE
);
6669 ast_debug(1, "Answering MFC/R2 call on chan %d\n", p
->channel
);
6675 ast_mutex_unlock(&p
->lock
);
6678 ast_log(LOG_WARNING
, "Don't know how to answer signalling %d (channel %d)\n", p
->sig
, p
->channel
);
6682 ast_mutex_unlock(&p
->lock
);
6686 void dahdi_dtmf_detect_disable(struct dahdi_pvt
*p
)
6692 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONEDETECT
, &val
);
6694 if (!p
->hardwaredtmf
&& p
->dsp
) {
6695 p
->dsp_features
&= ~DSP_FEATURE_DIGIT_DETECT
;
6696 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
6700 void dahdi_dtmf_detect_enable(struct dahdi_pvt
*p
)
6702 int val
= DAHDI_TONEDETECT_ON
| DAHDI_TONEDETECT_MUTE
;
6704 if (p
->channel
== CHAN_PSEUDO
)
6709 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONEDETECT
, &val
);
6711 if (!p
->hardwaredtmf
&& p
->dsp
) {
6712 p
->dsp_features
|= DSP_FEATURE_DIGIT_DETECT
;
6713 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
6717 static int dahdi_queryoption(struct ast_channel
*chan
, int option
, void *data
, int *datalen
)
6720 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
6722 /* all supported options require data */
6723 if (!p
|| !data
|| (*datalen
< 1)) {
6729 case AST_OPTION_TDD
:
6734 *cp
= p
->tdd
? 1 : 0;
6737 case AST_OPTION_DIGIT_DETECT
:
6739 *cp
= p
->ignoredtmf
? 0 : 1;
6740 ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp
? "en" : "dis", ast_channel_name(chan
));
6742 case AST_OPTION_FAX_DETECT
:
6744 *cp
= (p
->dsp_features
& DSP_FEATURE_FAX_DETECT
) ? 0 : 1;
6745 ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp
? "en" : "dis", ast_channel_name(chan
));
6747 case AST_OPTION_CC_AGENT_TYPE
:
6748 #if defined(HAVE_PRI)
6749 #if defined(HAVE_PRI_CCSS)
6750 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
6751 ast_copy_string((char *) data
, dahdi_pri_cc_type
, *datalen
);
6754 #endif /* defined(HAVE_PRI_CCSS) */
6755 #endif /* defined(HAVE_PRI) */
6766 static int dahdi_setoption(struct ast_channel
*chan
, int option
, void *data
, int datalen
)
6772 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
), *pp
;
6773 struct oprmode
*oprmode
;
6776 /* all supported options require data */
6777 if (!p
|| !data
|| (datalen
< 1)) {
6783 case AST_OPTION_TXGAIN
:
6784 scp
= (signed char *) data
;
6785 idx
= dahdi_get_index(chan
, p
, 0);
6787 ast_log(LOG_WARNING
, "No index in TXGAIN?\n");
6790 ast_debug(1, "Setting actual tx gain on %s to %f\n", ast_channel_name(chan
), p
->txgain
+ (float) *scp
);
6791 return set_actual_txgain(p
->subs
[idx
].dfd
, p
->txgain
+ (float) *scp
, p
->txdrc
, p
->law
);
6792 case AST_OPTION_RXGAIN
:
6793 scp
= (signed char *) data
;
6794 idx
= dahdi_get_index(chan
, p
, 0);
6796 ast_log(LOG_WARNING
, "No index in RXGAIN?\n");
6799 ast_debug(1, "Setting actual rx gain on %s to %f\n", ast_channel_name(chan
), p
->rxgain
+ (float) *scp
);
6800 return set_actual_rxgain(p
->subs
[idx
].dfd
, p
->rxgain
+ (float) *scp
, p
->rxdrc
, p
->law
);
6801 case AST_OPTION_TONE_VERIFY
:
6807 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",ast_channel_name(chan
));
6808 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MUTECONF
| p
->dtmfrelax
); /* set mute mode if desired */
6811 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",ast_channel_name(chan
));
6812 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MUTECONF
| DSP_DIGITMODE_MUTEMAX
| p
->dtmfrelax
); /* set mute mode if desired */
6815 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",ast_channel_name(chan
));
6816 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
); /* set mute mode if desired */
6820 case AST_OPTION_TDD
:
6821 /* turn on or off TDD */
6824 if (!*cp
) { /* turn it off */
6825 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",ast_channel_name(chan
));
6831 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
6832 (*cp
== 2) ? "MATE" : "ON", (int) *cp
, ast_channel_name(chan
));
6833 dahdi_ec_disable(p
);
6834 /* otherwise, turn it on */
6835 if (!p
->didtdd
) { /* if havent done it yet */
6836 unsigned char mybuf
[41000];/*! \todo XXX This is an abuse of the stack!! */
6838 int size
, res
, fd
, len
;
6839 struct pollfd fds
[1];
6842 memset(buf
, 0x7f, sizeof(mybuf
)); /* set to silence */
6843 ast_tdd_gen_ecdisa(buf
+ 16000, 16000); /* put in tone */
6845 idx
= dahdi_get_index(chan
, p
, 0);
6847 ast_log(LOG_WARNING
, "No index in TDD?\n");
6850 fd
= p
->subs
[idx
].dfd
;
6852 if (ast_check_hangup(chan
))
6855 if (size
> READ_SIZE
)
6858 fds
[0].events
= POLLPRI
| POLLOUT
;
6860 res
= poll(fds
, 1, -1);
6862 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p
->channel
);
6865 /* if got exception */
6866 if (fds
[0].revents
& POLLPRI
)
6868 if (!(fds
[0].revents
& POLLOUT
)) {
6869 ast_debug(1, "write fd not ready on channel %d\n", p
->channel
);
6872 res
= write(fd
, buf
, size
);
6874 if (res
== -1) return -1;
6875 ast_debug(1, "Write returned %d (%s) on channel %d\n", res
, strerror(errno
), p
->channel
);
6881 p
->didtdd
= 1; /* set to have done it now */
6883 if (*cp
== 2) { /* Mate mode */
6890 if (!p
->tdd
) { /* if we don't have one yet */
6891 p
->tdd
= tdd_new(); /* allocate one */
6894 case AST_OPTION_RELAXDTMF
: /* Relax DTMF decoding (or not) */
6898 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
6899 *cp
? "ON" : "OFF", (int) *cp
, ast_channel_name(chan
));
6900 ast_dsp_set_digitmode(p
->dsp
, ((*cp
) ? DSP_DIGITMODE_RELAXDTMF
: DSP_DIGITMODE_DTMF
) | p
->dtmfrelax
);
6902 case AST_OPTION_AUDIO_MODE
: /* Set AUDIO mode (or not) */
6903 #if defined(HAVE_PRI)
6904 if (dahdi_sig_pri_lib_handles(p
->sig
)
6905 && ((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
) {
6906 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
6909 #endif /* defined(HAVE_PRI) */
6913 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan
));
6915 dahdi_ec_disable(p
);
6917 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan
));
6920 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &x
) == -1)
6921 ast_log(LOG_WARNING
, "Unable to set audio mode on channel %d to %d: %s\n", p
->channel
, x
, strerror(errno
));
6923 case AST_OPTION_OPRMODE
: /* Operator services mode */
6924 oprmode
= (struct oprmode
*) data
;
6925 /* We don't support operator mode across technologies */
6926 if (strcasecmp(ast_channel_tech(chan
)->type
, ast_channel_tech(oprmode
->peer
)->type
)) {
6927 ast_log(LOG_NOTICE
, "Operator mode not supported on %s to %s calls.\n",
6928 ast_channel_tech(chan
)->type
, ast_channel_tech(oprmode
->peer
)->type
);
6932 pp
= ast_channel_tech_pvt(oprmode
->peer
);
6933 p
->oprmode
= pp
->oprmode
= 0;
6937 /* setup modes, if any */
6940 pp
->oprmode
= oprmode
->mode
;
6941 p
->oprmode
= -oprmode
->mode
;
6943 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
6944 oprmode
->mode
, ast_channel_name(chan
),ast_channel_name(oprmode
->peer
));
6946 case AST_OPTION_ECHOCAN
:
6949 ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan
));
6952 ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan
));
6953 dahdi_ec_disable(p
);
6956 case AST_OPTION_DIGIT_DETECT
:
6958 ast_debug(1, "%sabling digit detection on %s\n", *cp
? "En" : "Dis", ast_channel_name(chan
));
6960 dahdi_dtmf_detect_enable(p
);
6962 dahdi_dtmf_detect_disable(p
);
6965 case AST_OPTION_FAX_DETECT
:
6968 ast_debug(1, "%sabling fax tone detection on %s\n", *cp
? "En" : "Dis", ast_channel_name(chan
));
6970 p
->dsp_features
|= DSP_FEATURE_FAX_DETECT
;
6972 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
6974 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
6985 static int dahdi_func_read(struct ast_channel
*chan
, const char *function
, char *data
, char *buf
, size_t len
)
6987 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
6991 /* No private structure! */
6996 if (!strcasecmp(data
, "rxgain")) {
6997 ast_mutex_lock(&p
->lock
);
6998 snprintf(buf
, len
, "%f", p
->rxgain
);
6999 ast_mutex_unlock(&p
->lock
);
7000 } else if (!strcasecmp(data
, "txgain")) {
7001 ast_mutex_lock(&p
->lock
);
7002 snprintf(buf
, len
, "%f", p
->txgain
);
7003 ast_mutex_unlock(&p
->lock
);
7004 } else if (!strcasecmp(data
, "dahdi_channel")) {
7005 ast_mutex_lock(&p
->lock
);
7006 snprintf(buf
, len
, "%d", p
->channel
);
7007 ast_mutex_unlock(&p
->lock
);
7008 } else if (!strcasecmp(data
, "dahdi_span")) {
7009 ast_mutex_lock(&p
->lock
);
7010 snprintf(buf
, len
, "%d", p
->span
);
7011 ast_mutex_unlock(&p
->lock
);
7012 } else if (!strcasecmp(data
, "dahdi_group")) {
7013 ast_mutex_lock(&p
->lock
);
7014 snprintf(buf
, len
, "%llu", p
->group
);
7015 ast_mutex_unlock(&p
->lock
);
7016 } else if (!strcasecmp(data
, "dahdi_type")) {
7017 ast_mutex_lock(&p
->lock
);
7019 #if defined(HAVE_OPENR2)
7021 ast_copy_string(buf
, "mfc/r2", len
);
7023 #endif /* defined(HAVE_OPENR2) */
7024 #if defined(HAVE_PRI)
7025 case SIG_PRI_LIB_HANDLE_CASES
:
7026 ast_copy_string(buf
, "pri", len
);
7028 #endif /* defined(HAVE_PRI) */
7030 ast_copy_string(buf
, "pseudo", len
);
7032 #if defined(HAVE_SS7)
7034 ast_copy_string(buf
, "ss7", len
);
7036 #endif /* defined(HAVE_SS7) */
7038 /* The only thing left is analog ports. */
7039 ast_copy_string(buf
, "analog", len
);
7042 ast_mutex_unlock(&p
->lock
);
7043 #if defined(HAVE_PRI)
7044 #if defined(HAVE_PRI_REVERSE_CHARGE)
7045 } else if (!strcasecmp(data
, "reversecharge")) {
7046 ast_mutex_lock(&p
->lock
);
7048 case SIG_PRI_LIB_HANDLE_CASES
:
7049 snprintf(buf
, len
, "%d", ((struct sig_pri_chan
*) p
->sig_pvt
)->reverse_charging_indication
);
7056 ast_mutex_unlock(&p
->lock
);
7058 #if defined(HAVE_PRI_SETUP_KEYPAD)
7059 } else if (!strcasecmp(data
, "keypad_digits")) {
7060 ast_mutex_lock(&p
->lock
);
7062 case SIG_PRI_LIB_HANDLE_CASES
:
7063 ast_copy_string(buf
, ((struct sig_pri_chan
*) p
->sig_pvt
)->keypad_digits
,
7071 ast_mutex_unlock(&p
->lock
);
7072 #endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
7073 } else if (!strcasecmp(data
, "no_media_path")) {
7074 ast_mutex_lock(&p
->lock
);
7076 case SIG_PRI_LIB_HANDLE_CASES
:
7078 * TRUE if the call is on hold or is call waiting because
7079 * there is no media path available.
7081 snprintf(buf
, len
, "%d", ((struct sig_pri_chan
*) p
->sig_pvt
)->no_b_channel
);
7088 ast_mutex_unlock(&p
->lock
);
7089 #endif /* defined(HAVE_PRI) */
7090 } else if (!strcasecmp(data
, "dialmode")) {
7091 struct analog_pvt
*analog_p
;
7092 ast_mutex_lock(&p
->lock
);
7093 analog_p
= p
->sig_pvt
;
7094 /* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
7095 if (dahdi_analog_lib_handles(p
->sig
, 0, 0) && analog_p
) {
7096 switch (analog_p
->dialmode
) {
7097 case ANALOG_DIALMODE_BOTH
:
7098 ast_copy_string(buf
, "both", len
);
7100 case ANALOG_DIALMODE_PULSE
:
7101 ast_copy_string(buf
, "pulse", len
);
7103 case ANALOG_DIALMODE_DTMF
:
7104 ast_copy_string(buf
, "dtmf", len
);
7106 case ANALOG_DIALMODE_NONE
:
7107 ast_copy_string(buf
, "none", len
);
7111 ast_log(LOG_WARNING
, "%s only supported on analog channels\n", data
);
7115 ast_mutex_unlock(&p
->lock
);
7125 static int parse_buffers_policy(const char *parse
, int *num_buffers
, int *policy
)
7128 char policy_str
[21] = "";
7130 if ((res
= sscanf(parse
, "%30d,%20s", num_buffers
, policy_str
)) != 2) {
7131 ast_log(LOG_WARNING
, "Parsing buffer string '%s' failed.\n", parse
);
7134 if (*num_buffers
< 0) {
7135 ast_log(LOG_WARNING
, "Invalid buffer count given '%d'.\n", *num_buffers
);
7138 if (!strcasecmp(policy_str
, "full")) {
7139 *policy
= DAHDI_POLICY_WHEN_FULL
;
7140 } else if (!strcasecmp(policy_str
, "immediate")) {
7141 *policy
= DAHDI_POLICY_IMMEDIATE
;
7142 #if defined(HAVE_DAHDI_HALF_FULL)
7143 } else if (!strcasecmp(policy_str
, "half")) {
7144 *policy
= DAHDI_POLICY_HALF_FULL
;
7147 ast_log(LOG_WARNING
, "Invalid policy name given '%s'.\n", policy_str
);
7154 static int dahdi_func_write(struct ast_channel
*chan
, const char *function
, char *data
, const char *value
)
7156 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
7160 /* No private structure! */
7164 if (!strcasecmp(data
, "buffers")) {
7165 int num_bufs
, policy
;
7167 if (!(parse_buffers_policy(value
, &num_bufs
, &policy
))) {
7168 struct dahdi_bufferinfo bi
= {
7169 .txbufpolicy
= policy
,
7170 .rxbufpolicy
= policy
,
7171 .bufsize
= p
->bufsize
,
7172 .numbufs
= num_bufs
,
7176 if ((bpres
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
7177 ast_log(LOG_WARNING
, "Channel '%d' unable to override buffer policy: %s\n", p
->channel
, strerror(errno
));
7179 p
->bufferoverrideinuse
= 1;
7184 } else if (!strcasecmp(data
, "echocan_mode")) {
7185 if (!strcasecmp(value
, "on")) {
7186 ast_mutex_lock(&p
->lock
);
7188 ast_mutex_unlock(&p
->lock
);
7189 } else if (!strcasecmp(value
, "off")) {
7190 ast_mutex_lock(&p
->lock
);
7191 dahdi_ec_disable(p
);
7192 ast_mutex_unlock(&p
->lock
);
7193 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7194 } else if (!strcasecmp(value
, "fax")) {
7197 ast_mutex_lock(&p
->lock
);
7198 if (!p
->echocanon
) {
7201 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOCANCEL_FAX_MODE
, &blah
)) {
7202 ast_log(LOG_WARNING
, "Unable to place echocan into fax mode on channel %d: %s\n", p
->channel
, strerror(errno
));
7204 ast_mutex_unlock(&p
->lock
);
7205 } else if (!strcasecmp(value
, "voice")) {
7208 ast_mutex_lock(&p
->lock
);
7209 if (!p
->echocanon
) {
7212 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_ECHOCANCEL_FAX_MODE
, &blah
)) {
7213 ast_log(LOG_WARNING
, "Unable to place echocan into voice mode on channel %d: %s\n", p
->channel
, strerror(errno
));
7215 ast_mutex_unlock(&p
->lock
);
7218 ast_log(LOG_WARNING
, "Unsupported value '%s' provided for '%s' item.\n", value
, data
);
7221 } else if (!strcasecmp(data
, "dialmode")) {
7222 struct analog_pvt
*analog_p
;
7224 ast_mutex_lock(&p
->lock
);
7225 analog_p
= p
->sig_pvt
;
7226 if (!dahdi_analog_lib_handles(p
->sig
, 0, 0) || !analog_p
) {
7227 ast_log(LOG_WARNING
, "%s only supported on analog channels\n", data
);
7228 ast_mutex_unlock(&p
->lock
);
7231 /* analog pvt is used for pulse dialing, so update both */
7232 if (!strcasecmp(value
, "pulse")) {
7233 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_PULSE
;
7234 } else if (!strcasecmp(value
, "dtmf") || !strcasecmp(value
, "tone")) {
7235 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_DTMF
;
7236 } else if (!strcasecmp(value
, "none")) {
7237 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_NONE
;
7238 } else if (!strcasecmp(value
, "both")) {
7239 p
->dialmode
= analog_p
->dialmode
= ANALOG_DIALMODE_BOTH
;
7241 ast_log(LOG_WARNING
, "'%s' is an invalid setting for %s\n", value
, data
);
7244 ast_mutex_unlock(&p
->lock
);
7252 void dahdi_master_slave_unlink(struct dahdi_pvt
*slave
, struct dahdi_pvt
*master
, int needlock
)
7254 /* Unlink a specific slave or all slaves/masters from a given master */
7260 ast_mutex_lock(&master
->lock
);
7262 while (ast_mutex_trylock(&slave
->lock
)) {
7263 DEADLOCK_AVOIDANCE(&master
->lock
);
7268 for (x
= 0; x
< MAX_SLAVES
; x
++) {
7269 if (master
->slaves
[x
]) {
7270 if (!slave
|| (master
->slaves
[x
] == slave
)) {
7271 /* Take slave out of the conference */
7272 ast_debug(1, "Unlinking slave %d from %d\n", master
->slaves
[x
]->channel
, master
->channel
);
7273 conf_del(master
, &master
->slaves
[x
]->subs
[SUB_REAL
], SUB_REAL
);
7274 conf_del(master
->slaves
[x
], &master
->subs
[SUB_REAL
], SUB_REAL
);
7275 master
->slaves
[x
]->master
= NULL
;
7276 master
->slaves
[x
] = NULL
;
7281 master
->inconference
= 0;
7284 if (master
->master
) {
7285 /* Take master out of the conference */
7286 conf_del(master
->master
, &master
->subs
[SUB_REAL
], SUB_REAL
);
7287 conf_del(master
, &master
->master
->subs
[SUB_REAL
], SUB_REAL
);
7289 for (x
= 0; x
< MAX_SLAVES
; x
++) {
7290 if (master
->master
->slaves
[x
] == master
)
7291 master
->master
->slaves
[x
] = NULL
;
7292 else if (master
->master
->slaves
[x
])
7296 master
->master
->inconference
= 0;
7298 master
->master
= NULL
;
7300 dahdi_conf_update(master
);
7303 ast_mutex_unlock(&slave
->lock
);
7304 ast_mutex_unlock(&master
->lock
);
7308 void dahdi_master_slave_link(struct dahdi_pvt
*slave
, struct dahdi_pvt
*master
)
7311 if (!slave
|| !master
) {
7312 ast_log(LOG_WARNING
, "Tried to link to/from NULL??\n");
7315 for (x
= 0; x
< MAX_SLAVES
; x
++) {
7316 if (!master
->slaves
[x
]) {
7317 master
->slaves
[x
] = slave
;
7321 if (x
>= MAX_SLAVES
) {
7322 ast_log(LOG_WARNING
, "Replacing slave %d with new slave, %d\n", master
->slaves
[MAX_SLAVES
- 1]->channel
, slave
->channel
);
7323 master
->slaves
[MAX_SLAVES
- 1] = slave
;
7326 ast_log(LOG_WARNING
, "Replacing master %d with new master, %d\n", slave
->master
->channel
, master
->channel
);
7327 slave
->master
= master
;
7329 ast_debug(1, "Making %d slave to master %d at %d\n", slave
->channel
, master
->channel
, x
);
7332 static int dahdi_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
)
7334 struct dahdi_pvt
*p
= ast_channel_tech_pvt(newchan
);
7337 ast_mutex_lock(&p
->lock
);
7339 ast_debug(1, "New owner for channel %d is %s\n", p
->channel
, ast_channel_name(newchan
));
7340 if (p
->owner
== oldchan
) {
7343 for (x
= 0; x
< 3; x
++) {
7344 if (p
->subs
[x
].owner
== oldchan
) {
7346 dahdi_master_slave_unlink(NULL
, p
, 0);
7348 p
->subs
[x
].owner
= newchan
;
7351 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
7352 analog_fixup(oldchan
, newchan
, p
->sig_pvt
);
7353 #if defined(HAVE_PRI)
7354 } else if (dahdi_sig_pri_lib_handles(p
->sig
)) {
7355 sig_pri_fixup(oldchan
, newchan
, p
->sig_pvt
);
7356 #endif /* defined(HAVE_PRI) */
7357 #if defined(HAVE_SS7)
7358 } else if (p
->sig
== SIG_SS7
) {
7359 sig_ss7_fixup(oldchan
, newchan
, p
->sig_pvt
);
7360 #endif /* defined(HAVE_SS7) */
7362 dahdi_conf_update(p
);
7364 ast_mutex_unlock(&p
->lock
);
7366 if (ast_channel_state(newchan
) == AST_STATE_RINGING
) {
7367 dahdi_indicate(newchan
, AST_CONTROL_RINGING
, NULL
, 0);
7372 static int dahdi_ring_phone(struct dahdi_pvt
*p
)
7376 /* Make sure our transmit state is on hook */
7379 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
7382 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
7387 /* Wait just in case */
7394 ast_log(LOG_WARNING
, "Couldn't ring the phone: %s\n", strerror(errno
));
7402 static void *analog_ss_thread(void *data
);
7406 * \brief Attempt to transfer 3-way call.
7408 * \param p DAHDI private structure.
7410 * \note On entry these locks are held: real-call, private, 3-way call.
7411 * \note On exit these locks are held: real-call, private.
7413 * \retval 0 on success.
7414 * \retval -1 on error.
7416 static int attempt_transfer(struct dahdi_pvt
*p
)
7418 struct ast_channel
*owner_real
;
7419 struct ast_channel
*owner_3way
;
7420 enum ast_transfer_result xfer_res
;
7423 owner_real
= ast_channel_ref(p
->subs
[SUB_REAL
].owner
);
7424 owner_3way
= ast_channel_ref(p
->subs
[SUB_THREEWAY
].owner
);
7426 ast_verb(3, "TRANSFERRING %s to %s\n",
7427 ast_channel_name(owner_3way
), ast_channel_name(owner_real
));
7429 ast_channel_unlock(owner_real
);
7430 ast_channel_unlock(owner_3way
);
7431 ast_mutex_unlock(&p
->lock
);
7433 xfer_res
= ast_bridge_transfer_attended(owner_3way
, owner_real
);
7434 if (xfer_res
!= AST_BRIDGE_TRANSFER_SUCCESS
) {
7435 ast_softhangup(owner_3way
, AST_SOFTHANGUP_DEV
);
7439 /* Must leave with these locked. */
7440 ast_channel_lock(owner_real
);
7441 ast_mutex_lock(&p
->lock
);
7443 ast_channel_unref(owner_real
);
7444 ast_channel_unref(owner_3way
);
7449 static int check_for_conference(struct dahdi_pvt
*p
)
7451 struct dahdi_confinfo ci
;
7452 /* Fine if we already have a master, etc */
7453 if (p
->master
|| (p
->confno
> -1))
7455 memset(&ci
, 0, sizeof(ci
));
7456 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONF
, &ci
)) {
7457 ast_log(LOG_WARNING
, "Failed to get conference info on channel %d: %s\n", p
->channel
, strerror(errno
));
7460 /* If we have no master and don't have a confno, then
7461 if we're in a conference, it's probably a MeetMe room or
7462 some such, so don't let us 3-way out! */
7463 if ((p
->subs
[SUB_REAL
].curconf
.confno
!= ci
.confno
) || (p
->subs
[SUB_REAL
].curconf
.confmode
!= ci
.confmode
)) {
7464 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
7470 /*! Checks channel for alarms
7471 * \param p a channel to check for alarms.
7472 * \returns the alarms on the span to which the channel belongs, or alarms on
7473 * the channel if no span alarms.
7475 static int get_alarms(struct dahdi_pvt
*p
)
7478 struct dahdi_spaninfo zi
;
7479 struct dahdi_params params
;
7481 memset(&zi
, 0, sizeof(zi
));
7482 zi
.spanno
= p
->span
;
7484 if ((res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SPANSTAT
, &zi
)) >= 0) {
7485 if (zi
.alarms
!= DAHDI_ALARM_NONE
)
7488 ast_log(LOG_WARNING
, "Unable to determine alarm on channel %d: %s\n", p
->channel
, strerror(errno
));
7492 /* No alarms on the span. Check for channel alarms. */
7493 memset(¶ms
, 0, sizeof(params
));
7494 if ((res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, ¶ms
)) >= 0)
7495 return params
.chan_alarms
;
7497 ast_log(LOG_WARNING
, "Unable to determine alarm on channel %d\n", p
->channel
);
7499 return DAHDI_ALARM_NONE
;
7502 static void dahdi_handle_dtmf(struct ast_channel
*ast
, int idx
, struct ast_frame
**dest
)
7504 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
7505 struct ast_frame
*f
= *dest
;
7507 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
7508 f
->frametype
== AST_FRAME_DTMF_BEGIN
? "Begin" : "End",
7509 (unsigned)f
->subclass
.integer
, f
->subclass
.integer
, ast_channel_name(ast
));
7511 if (p
->confirmanswer
) {
7512 if (f
->frametype
== AST_FRAME_DTMF_END
) {
7513 ast_debug(1, "Confirm answer on %s!\n", ast_channel_name(ast
));
7514 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
7516 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7517 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
7518 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
7519 p
->confirmanswer
= 0;
7521 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7522 p
->subs
[idx
].f
.subclass
.integer
= 0;
7524 *dest
= &p
->subs
[idx
].f
;
7525 } else if (p
->callwaitcas
) {
7526 if (f
->frametype
== AST_FRAME_DTMF_END
) {
7527 if ((f
->subclass
.integer
== 'A') || (f
->subclass
.integer
== 'D')) {
7528 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
7529 ast_free(p
->cidspill
);
7535 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7536 p
->subs
[idx
].f
.subclass
.integer
= 0;
7537 *dest
= &p
->subs
[idx
].f
;
7538 } else if (f
->subclass
.integer
== 'f') {
7539 if (f
->frametype
== AST_FRAME_DTMF_END
) {
7540 /* Fax tone -- Handle and return NULL */
7541 if ((p
->callprogress
& CALLPROGRESS_FAX
) && !p
->faxhandled
) {
7542 /* If faxbuffers are configured, use them for the fax transmission */
7543 if (p
->usefaxbuffers
&& !p
->bufferoverrideinuse
) {
7544 struct dahdi_bufferinfo bi
= {
7545 .txbufpolicy
= p
->faxbuf_policy
,
7546 .bufsize
= p
->bufsize
,
7547 .numbufs
= p
->faxbuf_no
7551 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_SET_BUFINFO
, &bi
)) < 0) {
7552 ast_log(LOG_WARNING
, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast
), strerror(errno
));
7554 p
->bufferoverrideinuse
= 1;
7559 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
7560 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
7561 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast
));
7563 if (strcmp(ast_channel_exten(ast
), "fax")) {
7564 const char *target_context
= ast_channel_context(ast
);
7567 * We need to unlock 'ast' here because ast_exists_extension has the
7568 * potential to start autoservice on the channel. Such action is prone
7569 * to deadlock if the channel is locked.
7571 * ast_async_goto() has its own restriction on not holding the
7574 ast_mutex_unlock(&p
->lock
);
7575 ast_channel_unlock(ast
);
7576 if (ast_exists_extension(ast
, target_context
, "fax", 1,
7577 S_COR(ast_channel_caller(ast
)->id
.number
.valid
, ast_channel_caller(ast
)->id
.number
.str
, NULL
))) {
7578 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast
));
7579 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
7580 pbx_builtin_setvar_helper(ast
, "FAXEXTEN", ast_channel_exten(ast
));
7581 if (ast_async_goto(ast
, target_context
, "fax", 1))
7582 ast_log(LOG_WARNING
, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast
), target_context
);
7584 ast_log(LOG_NOTICE
, "Fax detected, but no fax extension\n");
7586 ast_channel_lock(ast
);
7587 ast_mutex_lock(&p
->lock
);
7589 ast_debug(1, "Already in a fax extension, not redirecting\n");
7592 ast_debug(1, "Fax already handled\n");
7594 dahdi_confmute(p
, 0);
7596 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7597 p
->subs
[idx
].f
.subclass
.integer
= 0;
7598 *dest
= &p
->subs
[idx
].f
;
7602 static void publish_span_alarm(int span
, const char *alarm_txt
)
7604 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
7606 body
= ast_json_pack("{s: i, s: s}",
7608 "Alarm", alarm_txt
);
7613 ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM
, body
);
7616 static void publish_channel_alarm(int channel
, const char *alarm_txt
)
7618 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
7619 RAII_VAR(struct ast_str
*, dahdi_chan
, ast_str_create(32), ast_free
);
7624 ast_str_set(&dahdi_chan
, 0, "%d", channel
);
7625 body
= ast_json_pack("{s: s, s: s}",
7626 "DAHDIChannel", ast_str_buffer(dahdi_chan
),
7627 "Alarm", alarm_txt
);
7632 ast_manager_publish_event("Alarm", EVENT_FLAG_SYSTEM
, body
);
7635 static void handle_alarms(struct dahdi_pvt
*p
, int alms
)
7637 const char *alarm_str
;
7639 #if defined(HAVE_PRI)
7640 if (dahdi_sig_pri_lib_handles(p
->sig
) && sig_pri_is_alarm_ignored(p
->pri
)) {
7643 #endif /* defined(HAVE_PRI) */
7645 alarm_str
= alarm2str(alms
);
7646 if (report_alarms
& REPORT_CHANNEL_ALARMS
) {
7647 ast_log(LOG_WARNING
, "Detected alarm on channel %d: %s\n", p
->channel
, alarm_str
);
7648 publish_channel_alarm(p
->channel
, alarm_str
);
7651 if (report_alarms
& REPORT_SPAN_ALARMS
&& p
->manages_span_alarms
) {
7652 ast_log(LOG_WARNING
, "Detected alarm on span %d: %s\n", p
->span
, alarm_str
);
7653 publish_span_alarm(p
->span
, alarm_str
);
7657 static struct ast_frame
*dahdi_handle_event(struct ast_channel
*ast
)
7662 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
7664 struct ast_channel
*chan
;
7665 struct ast_frame
*f
;
7667 idx
= dahdi_get_index(ast
, p
, 0);
7669 return &ast_null_frame
;
7672 if (p
->outsigmod
> -1)
7673 mysig
= p
->outsigmod
;
7674 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
7675 p
->subs
[idx
].f
.subclass
.integer
= 0;
7676 p
->subs
[idx
].f
.datalen
= 0;
7677 p
->subs
[idx
].f
.samples
= 0;
7678 p
->subs
[idx
].f
.mallocd
= 0;
7679 p
->subs
[idx
].f
.offset
= 0;
7680 p
->subs
[idx
].f
.src
= "dahdi_handle_event";
7681 p
->subs
[idx
].f
.data
.ptr
= NULL
;
7682 f
= &p
->subs
[idx
].f
;
7684 if (p
->fake_event
) {
7685 res
= p
->fake_event
;
7688 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
7690 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res
), res
, p
->channel
, idx
);
7692 if (res
& (DAHDI_EVENT_PULSEDIGIT
| DAHDI_EVENT_DTMFUP
)) {
7693 p
->pulsedial
= (res
& DAHDI_EVENT_PULSEDIGIT
) ? 1 : 0;
7694 ast_debug(1, "Detected %sdigit '%c'\n", p
->pulsedial
? "pulse ": "", res
& 0xff);
7695 #if defined(HAVE_PRI)
7696 if (dahdi_sig_pri_lib_handles(p
->sig
)
7697 && ((struct sig_pri_chan
*) p
->sig_pvt
)->call_level
< SIG_PRI_CALL_LEVEL_PROCEEDING
7699 && (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_INCOMING
)) {
7702 #endif /* defined(HAVE_PRI) */
7704 /* Unmute conference */
7705 dahdi_confmute(p
, 0);
7706 p
->subs
[idx
].f
.frametype
= AST_FRAME_DTMF_END
;
7707 p
->subs
[idx
].f
.subclass
.integer
= res
& 0xff;
7708 dahdi_handle_dtmf(ast
, idx
, &f
);
7713 if (res
& DAHDI_EVENT_DTMFDOWN
) {
7714 ast_debug(1, "DTMF Down '%c'\n", res
& 0xff);
7715 #if defined(HAVE_PRI)
7716 if (dahdi_sig_pri_lib_handles(p
->sig
)
7717 && ((struct sig_pri_chan
*) p
->sig_pvt
)->call_level
< SIG_PRI_CALL_LEVEL_PROCEEDING
7719 && (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_INCOMING
)) {
7722 #endif /* defined(HAVE_PRI) */
7724 /* Mute conference */
7725 dahdi_confmute(p
, 1);
7726 p
->subs
[idx
].f
.frametype
= AST_FRAME_DTMF_BEGIN
;
7727 p
->subs
[idx
].f
.subclass
.integer
= res
& 0xff;
7728 dahdi_handle_dtmf(ast
, idx
, &f
);
7730 return &p
->subs
[idx
].f
;
7734 case DAHDI_EVENT_EC_DISABLED
:
7735 ast_verb(3, "Channel %d echo canceler disabled.\n", p
->channel
);
7738 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7739 case DAHDI_EVENT_TX_CED_DETECTED
:
7740 ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p
->channel
);
7742 case DAHDI_EVENT_RX_CED_DETECTED
:
7743 ast_verb(3, "Channel %d detected a CED tone from the network.\n", p
->channel
);
7745 case DAHDI_EVENT_EC_NLP_DISABLED
:
7746 ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p
->channel
);
7748 case DAHDI_EVENT_EC_NLP_ENABLED
:
7749 ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p
->channel
);
7752 case DAHDI_EVENT_BITSCHANGED
:
7754 if (p
->sig
!= SIG_MFCR2
) {
7755 ast_log(LOG_WARNING
, "Received bits changed on %s signalling?\n", sig2str(p
->sig
));
7757 ast_debug(1, "bits changed in chan %d\n", p
->channel
);
7758 openr2_chan_handle_cas(p
->r2chan
);
7761 ast_log(LOG_WARNING
, "Received bits changed on %s signalling?\n", sig2str(p
->sig
));
7764 case DAHDI_EVENT_PULSE_START
:
7765 /* Stop tone if there's a pulse start and the PBX isn't started */
7766 if (!ast_channel_pbx(ast
))
7767 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
7769 case DAHDI_EVENT_DIALCOMPLETE
:
7770 /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
7771 #if defined(HAVE_PRI)
7772 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
7776 if (ioctl(p
->subs
[idx
].dfd
, DAHDI_DIALING
, &x
) == -1) {
7777 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
7778 ast_channel_name(ast
), strerror(errno
));
7782 /* Still dialing in DAHDI driver */
7786 * The ast channel is locked and the private may be locked more
7789 sig_pri_dial_complete(p
->sig_pvt
, ast
);
7792 #endif /* defined(HAVE_PRI) */
7794 if ((p
->sig
& SIG_MFCR2
) && p
->r2chan
&& ast_channel_state(ast
) != AST_STATE_UP
) {
7795 /* we don't need to do anything for this event for R2 signaling
7796 if the call is being setup */
7800 if (p
->inalarm
) break;
7801 if ((p
->radio
|| (p
->oprmode
< 0))) break;
7802 if (ioctl(p
->subs
[idx
].dfd
,DAHDI_DIALING
,&x
) == -1) {
7803 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",ast_channel_name(ast
), strerror(errno
));
7806 if (!x
) { /* if not still dialing in driver */
7810 ast_copy_string(p
->dop
.dialstr
, p
->echorest
, sizeof(p
->dop
.dialstr
));
7811 p
->dop
.op
= DAHDI_DIAL_OP_REPLACE
;
7812 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
7816 if ((mysig
== SIG_E911
) || (mysig
== SIG_FGC_CAMA
) || (mysig
== SIG_FGC_CAMAMF
)) {
7817 /* if thru with dialing after offhook */
7818 if (ast_channel_state(ast
) == AST_STATE_DIALING_OFFHOOK
) {
7819 ast_setstate(ast
, AST_STATE_UP
);
7820 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7821 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
7823 } else { /* if to state wait for offhook to dial rest */
7824 /* we now wait for off hook */
7825 ast_setstate(ast
,AST_STATE_DIALING_OFFHOOK
);
7828 if (ast_channel_state(ast
) == AST_STATE_DIALING
) {
7829 if ((p
->callprogress
& CALLPROGRESS_PROGRESS
) && CANPROGRESSDETECT(p
) && p
->dsp
&& p
->outgoing
) {
7830 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
7831 } else if (p
->confirmanswer
|| (!p
->dialednone
7832 && ((mysig
== SIG_EM
) || (mysig
== SIG_EM_E1
)
7833 || (mysig
== SIG_EMWINK
) || (mysig
== SIG_FEATD
)
7834 || (mysig
== SIG_FEATDMF_TA
) || (mysig
== SIG_FEATDMF
)
7835 || (mysig
== SIG_E911
) || (mysig
== SIG_FGC_CAMA
)
7836 || (mysig
== SIG_FGC_CAMAMF
) || (mysig
== SIG_FEATB
)
7837 || (mysig
== SIG_SF
) || (mysig
== SIG_SFWINK
)
7838 || (mysig
== SIG_SF_FEATD
) || (mysig
== SIG_SF_FEATDMF
)
7839 || (mysig
== SIG_SF_FEATB
)))) {
7840 ast_setstate(ast
, AST_STATE_RINGING
);
7841 } else if (!p
->answeronpolarityswitch
) {
7842 ast_setstate(ast
, AST_STATE_UP
);
7843 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7844 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
7845 /* If aops=0 and hops=1, this is necessary */
7846 p
->polarity
= POLARITY_REV
;
7848 /* Start clean, so we can catch the change to REV polarity when party answers */
7849 p
->polarity
= POLARITY_IDLE
;
7855 case DAHDI_EVENT_ALARM
:
7857 #if defined(HAVE_PRI)
7858 case SIG_PRI_LIB_HANDLE_CASES
:
7859 sig_pri_chan_alarm_notify(p
->sig_pvt
, 0);
7861 #endif /* defined(HAVE_PRI) */
7862 #if defined(HAVE_SS7)
7864 sig_ss7_set_alarm(p
->sig_pvt
, 1);
7866 #endif /* defined(HAVE_SS7) */
7871 res
= get_alarms(p
);
7872 handle_alarms(p
, res
);
7874 if (!p
->pri
|| !p
->pri
->pri
|| pri_get_timer(p
->pri
->pri
, PRI_TIMER_T309
) < 0) {
7875 /* fall through intentionally */
7880 #if defined(HAVE_SS7)
7881 if (p
->sig
== SIG_SS7
)
7883 #endif /* defined(HAVE_SS7) */
7885 if (p
->sig
== SIG_MFCR2
)
7888 case DAHDI_EVENT_ONHOOK
:
7890 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
7891 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_UNKEY
;
7896 if (p
->oprmode
!= -1) { /* Operator flash recall */
7897 ast_verb(4, "Operator mode enabled on channel %d, holding line for channel %d\n", p
->channel
, p
->oprpeer
->channel
);
7900 /* Otherwise, immediate recall */
7901 if ((p
->sig
== SIG_FXOLS
) || (p
->sig
== SIG_FXOKS
) || (p
->sig
== SIG_FXOGS
))
7903 /* Make sure it starts ringing */
7904 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
);
7905 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_RING
);
7906 save_conference(p
->oprpeer
);
7907 tone_zone_play_tone(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_RINGTONE
);
7908 ast_verb(4, "Operator recall, channel %d ringing back channel %d\n", p
->oprpeer
->channel
, p
->channel
);
7916 /* Check for some special conditions regarding call waiting */
7917 if (idx
== SUB_REAL
) {
7918 /* The normal line was hung up */
7919 if (p
->subs
[SUB_CALLWAIT
].owner
) {
7920 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
7921 swap_subs(p
, SUB_CALLWAIT
, SUB_REAL
);
7922 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p
->channel
);
7923 unalloc_sub(p
, SUB_CALLWAIT
);
7925 p
->subs
[idx
].needanswer
= 0;
7926 p
->subs
[idx
].needringing
= 0;
7928 p
->callwaitingrepeat
= 0;
7930 p
->cid_suppress_expire
= 0;
7932 /* Don't start streaming audio yet if the incoming call isn't up yet */
7933 if (ast_channel_state(p
->subs
[SUB_REAL
].owner
) != AST_STATE_UP
)
7935 dahdi_ring_phone(p
);
7936 } else if (p
->subs
[SUB_THREEWAY
].owner
) {
7937 unsigned int mssinceflash
;
7938 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
7939 the private structure -- not especially easy or clean */
7940 while (p
->subs
[SUB_THREEWAY
].owner
&& ast_channel_trylock(p
->subs
[SUB_THREEWAY
].owner
)) {
7941 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
7942 DLA_UNLOCK(&p
->lock
);
7943 CHANNEL_DEADLOCK_AVOIDANCE(ast
);
7944 /* We can grab ast and p in that order, without worry. We should make sure
7945 nothing seriously bad has happened though like some sort of bizarre double
7948 if (p
->owner
!= ast
) {
7949 ast_log(LOG_WARNING
, "This isn't good...\n");
7953 if (!p
->subs
[SUB_THREEWAY
].owner
) {
7954 ast_log(LOG_NOTICE
, "Whoa, threeway disappeared kinda randomly.\n");
7957 mssinceflash
= ast_tvdiff_ms(ast_tvnow(), p
->flashtime
);
7958 ast_debug(1, "Last flash was %u ms ago\n", mssinceflash
);
7959 if (mssinceflash
< MIN_MS_SINCE_FLASH
) {
7960 /* It hasn't been long enough since the last flashook. This is probably a bounce on
7961 hanging up. Hangup both channels now */
7962 if (p
->subs
[SUB_THREEWAY
].owner
)
7963 ast_queue_hangup_with_cause(p
->subs
[SUB_THREEWAY
].owner
, AST_CAUSE_NO_ANSWER
);
7964 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
7965 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p
->channel
);
7966 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
7967 } else if ((ast_channel_pbx(ast
)) || (ast_channel_state(ast
) == AST_STATE_UP
)) {
7969 /* In any case this isn't a threeway call anymore */
7970 p
->subs
[SUB_REAL
].inthreeway
= 0;
7971 p
->subs
[SUB_THREEWAY
].inthreeway
= 0;
7972 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
7973 if (!p
->transfertobusy
&& ast_channel_state(ast
) == AST_STATE_BUSY
) {
7974 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
7975 /* Swap subs and dis-own channel */
7976 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
7978 /* Ring the phone */
7979 dahdi_ring_phone(p
);
7980 } else if (!attempt_transfer(p
)) {
7982 * Transfer successful. Don't actually hang up at this point.
7983 * Let our channel legs of the calls die off as the transfer
7984 * percolates through the core.
7989 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
7990 if (p
->subs
[SUB_THREEWAY
].owner
)
7991 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
7994 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
7995 /* Swap subs and dis-own channel */
7996 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
7998 /* Ring the phone */
7999 dahdi_ring_phone(p
);
8003 ast_log(LOG_WARNING
, "Got a hangup and my index is %d?\n", idx
);
8007 dahdi_ec_disable(p
);
8011 case DAHDI_EVENT_RINGOFFHOOK
:
8012 if (p
->inalarm
) break;
8015 if ((p
->sig
== SIG_FXOLS
) || (p
->sig
== SIG_FXOKS
) || (p
->sig
== SIG_FXOGS
))
8017 /* Make sure it stops ringing */
8018 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
);
8019 tone_zone_play_tone(p
->oprpeer
->subs
[SUB_REAL
].dfd
, -1);
8020 restore_conference(p
->oprpeer
);
8021 ast_debug(1, "Operator recall by channel %d for channel %d complete\n", p
->oprpeer
->channel
, p
->channel
);
8027 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8028 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_KEY
;
8031 /* for E911, its supposed to wait for offhook then dial
8032 the second half of the dial string */
8033 if (((mysig
== SIG_E911
) || (mysig
== SIG_FGC_CAMA
) || (mysig
== SIG_FGC_CAMAMF
)) && (ast_channel_state(ast
) == AST_STATE_DIALING_OFFHOOK
)) {
8034 c
= strchr(p
->dialdest
, '/');
8041 int numchars
= snprintf(p
->dop
.dialstr
, sizeof(p
->dop
.dialstr
), "M*0%s#", c
);
8042 if (numchars
>= sizeof(p
->dop
.dialstr
)) {
8043 ast_log(LOG_WARNING
, "Dial string '%s' truncated\n", c
);
8046 ast_copy_string(p
->dop
.dialstr
,"M*2#", sizeof(p
->dop
.dialstr
));
8049 if (strlen(p
->dop
.dialstr
) > 4) {
8050 memset(p
->echorest
, 'w', sizeof(p
->echorest
) - 1);
8051 strcpy(p
->echorest
+ (p
->echotraining
/ 401) + 1, p
->dop
.dialstr
+ strlen(p
->dop
.dialstr
) - 2);
8052 p
->echorest
[sizeof(p
->echorest
) - 1] = '\0';
8054 p
->dop
.dialstr
[strlen(p
->dop
.dialstr
)-2] = '\0';
8057 if (dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
)) {
8059 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
8063 return &p
->subs
[idx
].f
;
8069 switch (ast_channel_state(ast
)) {
8070 case AST_STATE_RINGING
:
8073 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8074 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
8075 /* Make sure it stops ringing */
8076 p
->subs
[SUB_REAL
].needringing
= 0;
8077 dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_OFFHOOK
);
8078 ast_debug(1, "channel %d answered\n", p
->channel
);
8080 /* Cancel any running CallerID spill */
8081 ast_free(p
->cidspill
);
8083 restore_conference(p
);
8087 if (p
->confirmanswer
) {
8088 /* Ignore answer if "confirm answer" is enabled */
8089 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8090 p
->subs
[idx
].f
.subclass
.integer
= 0;
8091 } else if (!ast_strlen_zero(p
->dop
.dialstr
)) {
8092 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
8093 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
8095 p
->dop
.dialstr
[0] = '\0';
8098 ast_debug(1, "Sent FXO deferred digit string: %s\n", p
->dop
.dialstr
);
8099 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8100 p
->subs
[idx
].f
.subclass
.integer
= 0;
8103 p
->dop
.dialstr
[0] = '\0';
8104 ast_setstate(ast
, AST_STATE_DIALING
);
8106 ast_setstate(ast
, AST_STATE_UP
);
8107 return &p
->subs
[idx
].f
;
8108 case AST_STATE_DOWN
:
8109 ast_setstate(ast
, AST_STATE_RING
);
8110 ast_channel_rings_set(ast
, 1);
8111 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8112 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_OFFHOOK
;
8113 ast_debug(1, "channel %d picked up\n", p
->channel
);
8114 return &p
->subs
[idx
].f
;
8116 /* Make sure it stops ringing */
8117 dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_OFFHOOK
);
8118 /* Okay -- probably call waiting*/
8119 ast_queue_unhold(p
->owner
);
8120 p
->subs
[idx
].needunhold
= 1;
8122 case AST_STATE_RESERVED
:
8123 /* Start up dialtone */
8124 if (has_voicemail(p
))
8125 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_STUTTER
);
8127 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_DIALTONE
);
8130 ast_log(LOG_WARNING
, "FXO phone off hook in weird state %u??\n", ast_channel_state(ast
));
8136 if (ast_channel_state(ast
) == AST_STATE_RING
) {
8137 p
->ringt
= p
->ringt_base
;
8140 /* If we get a ring then we cannot be in
8141 * reversed polarity. So we reset to idle */
8142 ast_debug(1, "Setting IDLE polarity due "
8143 "to ring. Old polarity was %d\n",
8145 p
->polarity
= POLARITY_IDLE
;
8153 case SIG_FEATDMF_TA
:
8156 case SIG_FGC_CAMAMF
:
8161 case SIG_SF_FEATDMF
:
8163 if (ast_channel_state(ast
) == AST_STATE_PRERING
)
8164 ast_setstate(ast
, AST_STATE_RING
);
8165 if ((ast_channel_state(ast
) == AST_STATE_DOWN
) || (ast_channel_state(ast
) == AST_STATE_RING
)) {
8166 ast_debug(1, "Ring detected\n");
8167 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8168 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RING
;
8169 } else if (p
->outgoing
&& ((ast_channel_state(ast
) == AST_STATE_RINGING
) || (ast_channel_state(ast
) == AST_STATE_DIALING
))) {
8170 ast_debug(1, "Line answered\n");
8171 if (p
->confirmanswer
) {
8172 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8173 p
->subs
[idx
].f
.subclass
.integer
= 0;
8175 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8176 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
8177 ast_setstate(ast
, AST_STATE_UP
);
8179 } else if (ast_channel_state(ast
) != AST_STATE_RING
)
8180 ast_log(LOG_WARNING
, "Ring/Off-hook in strange state %u on channel %d\n", ast_channel_state(ast
), p
->channel
);
8183 ast_log(LOG_WARNING
, "Don't know how to handle ring/off hook for signalling %d\n", p
->sig
);
8186 case DAHDI_EVENT_RINGBEGIN
:
8191 if (ast_channel_state(ast
) == AST_STATE_RING
) {
8192 p
->ringt
= p
->ringt_base
;
8197 case DAHDI_EVENT_RINGERON
:
8199 case DAHDI_EVENT_NOALARM
:
8201 #if defined(HAVE_PRI)
8202 case SIG_PRI_LIB_HANDLE_CASES
:
8203 sig_pri_chan_alarm_notify(p
->sig_pvt
, 1);
8205 #endif /* defined(HAVE_PRI) */
8206 #if defined(HAVE_SS7)
8208 sig_ss7_set_alarm(p
->sig_pvt
, 0);
8210 #endif /* defined(HAVE_SS7) */
8215 handle_clear_alarms(p
);
8217 case DAHDI_EVENT_WINKFLASH
:
8218 if (p
->inalarm
) break;
8219 if (p
->radio
) break;
8220 if (p
->oprmode
< 0) break;
8223 struct dahdi_params par
;
8225 memset(&par
, 0, sizeof(par
));
8226 if (ioctl(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &par
) != -1)
8228 if (!par
.rxisoffhook
)
8230 /* Make sure it stops ringing */
8231 dahdi_set_hook(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
);
8232 dahdi_set_hook(p
->oprpeer
->subs
[SUB_REAL
].dfd
, DAHDI_RING
);
8234 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_RINGTONE
);
8235 ast_verb(4, "Operator flash recall, channel %d ringing back channel %d\n", p
->oprpeer
->channel
, p
->channel
);
8240 /* Remember last time we got a flash-hook */
8241 p
->flashtime
= ast_tvnow();
8246 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
8247 idx
, p
->subs
[SUB_REAL
].dfd
, p
->subs
[SUB_CALLWAIT
].dfd
, p
->subs
[SUB_THREEWAY
].dfd
);
8249 /* Cancel any running CallerID spill */
8250 ast_free(p
->cidspill
);
8252 restore_conference(p
);
8255 if (idx
!= SUB_REAL
) {
8256 ast_log(LOG_WARNING
, "Got flash hook with index %d on channel %d?!?\n", idx
, p
->channel
);
8260 if (p
->subs
[SUB_CALLWAIT
].owner
) {
8261 /* Swap to call-wait */
8262 swap_subs(p
, SUB_REAL
, SUB_CALLWAIT
);
8263 tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, -1);
8264 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8265 ast_debug(1, "Making %s the new owner\n", ast_channel_name(p
->owner
));
8266 if (ast_channel_state(p
->owner
) == AST_STATE_RINGING
) {
8267 ast_setstate(p
->owner
, AST_STATE_UP
);
8268 p
->subs
[SUB_REAL
].needanswer
= 1;
8270 p
->callwaitingrepeat
= 0;
8272 p
->cid_suppress_expire
= 0;
8273 /* Start music on hold if appropriate */
8274 if (!p
->subs
[SUB_CALLWAIT
].inthreeway
) {
8275 ast_queue_hold(p
->subs
[SUB_CALLWAIT
].owner
, p
->mohsuggest
);
8277 p
->subs
[SUB_CALLWAIT
].needhold
= 1;
8278 ast_queue_hold(p
->subs
[SUB_REAL
].owner
, p
->mohsuggest
);
8279 p
->subs
[SUB_REAL
].needunhold
= 1;
8280 } else if (!p
->subs
[SUB_THREEWAY
].owner
) {
8281 if (!p
->threewaycalling
) {
8282 /* Just send a flash if no 3-way calling */
8283 p
->subs
[SUB_REAL
].needflash
= 1;
8285 } else if (!check_for_conference(p
)) {
8286 ast_callid callid
= 0;
8293 if (p
->dahditrcallerid
&& p
->owner
) {
8294 if (ast_channel_caller(p
->owner
)->id
.number
.valid
8295 && ast_channel_caller(p
->owner
)->id
.number
.str
) {
8296 ast_copy_string(cid_num
, ast_channel_caller(p
->owner
)->id
.number
.str
,
8299 if (ast_channel_caller(p
->owner
)->id
.name
.valid
8300 && ast_channel_caller(p
->owner
)->id
.name
.str
) {
8301 ast_copy_string(cid_name
, ast_channel_caller(p
->owner
)->id
.name
.str
,
8305 /* XXX This section needs much more error checking!!! XXX */
8306 /* Start a 3-way call if feasible */
8307 if (!((ast_channel_pbx(ast
)) ||
8308 (ast_channel_state(ast
) == AST_STATE_UP
) ||
8309 (ast_channel_state(ast
) == AST_STATE_RING
))) {
8310 ast_debug(1, "Flash when call not up or ringing\n");
8313 if (alloc_sub(p
, SUB_THREEWAY
)) {
8314 ast_log(LOG_WARNING
, "Unable to allocate three-way subchannel\n");
8317 callid_created
= ast_callid_threadstorage_auto(&callid
);
8321 * We cannot hold the p or ast locks while creating a new
8324 ast_mutex_unlock(&p
->lock
);
8325 ast_channel_unlock(ast
);
8326 chan
= dahdi_new(p
, AST_STATE_RESERVED
, 0, SUB_THREEWAY
, 0, NULL
, NULL
, callid
);
8327 ast_channel_lock(ast
);
8328 ast_mutex_lock(&p
->lock
);
8329 if (p
->dahditrcallerid
) {
8330 if (!p
->origcid_num
)
8331 p
->origcid_num
= ast_strdup(p
->cid_num
);
8332 if (!p
->origcid_name
)
8333 p
->origcid_name
= ast_strdup(p
->cid_name
);
8334 ast_copy_string(p
->cid_num
, cid_num
, sizeof(p
->cid_num
));
8335 ast_copy_string(p
->cid_name
, cid_name
, sizeof(p
->cid_name
));
8337 /* Swap things around between the three-way and real call */
8338 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8339 /* Disable echo canceller for better dialing */
8340 dahdi_ec_disable(p
);
8341 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_DIALRECALL
);
8343 ast_log(LOG_WARNING
, "Unable to start dial recall tone on channel %d\n", p
->channel
);
8346 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", p
->channel
);
8347 } else if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
8348 ast_log(LOG_WARNING
, "Unable to start simple switch on channel %d\n", p
->channel
);
8349 res
= tone_zone_play_tone(p
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
8353 ast_verb(3, "Started three way call on channel %d\n", p
->channel
);
8355 /* Start music on hold */
8356 ast_queue_hold(p
->subs
[SUB_THREEWAY
].owner
, p
->mohsuggest
);
8357 p
->subs
[SUB_THREEWAY
].needhold
= 1;
8359 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
8362 /* Already have a 3 way call */
8363 if (p
->subs
[SUB_THREEWAY
].inthreeway
) {
8364 /* Call is already up, drop the last person */
8365 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p
->channel
);
8366 /* If the primary call isn't answered yet, use it */
8367 if ((ast_channel_state(p
->subs
[SUB_REAL
].owner
) != AST_STATE_UP
) && (ast_channel_state(p
->subs
[SUB_THREEWAY
].owner
) == AST_STATE_UP
)) {
8368 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
8369 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8370 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8372 /* Drop the last call and stop the conference */
8373 ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p
->subs
[SUB_THREEWAY
].owner
));
8374 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
8375 p
->subs
[SUB_REAL
].inthreeway
= 0;
8376 p
->subs
[SUB_THREEWAY
].inthreeway
= 0;
8378 /* Lets see what we're up to */
8379 if (((ast_channel_pbx(ast
)) || (ast_channel_state(ast
) == AST_STATE_UP
)) &&
8380 (p
->transfertobusy
|| (ast_channel_state(ast
) != AST_STATE_BUSY
))) {
8381 int otherindex
= SUB_THREEWAY
;
8383 ast_verb(3, "Building conference call with %s and %s\n",
8384 ast_channel_name(p
->subs
[SUB_THREEWAY
].owner
),
8385 ast_channel_name(p
->subs
[SUB_REAL
].owner
));
8386 /* Put them in the threeway, and flip */
8387 p
->subs
[SUB_THREEWAY
].inthreeway
= 1;
8388 p
->subs
[SUB_REAL
].inthreeway
= 1;
8389 if (ast_channel_state(ast
) == AST_STATE_UP
) {
8390 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8391 otherindex
= SUB_REAL
;
8393 if (p
->subs
[otherindex
].owner
) {
8394 ast_queue_unhold(p
->subs
[otherindex
].owner
);
8396 p
->subs
[otherindex
].needunhold
= 1;
8397 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8399 ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p
->subs
[SUB_THREEWAY
].owner
));
8400 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
8401 ast_channel_softhangup_internal_flag_add(p
->subs
[SUB_THREEWAY
].owner
, AST_SOFTHANGUP_DEV
);
8402 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8403 if (p
->subs
[SUB_REAL
].owner
) {
8404 ast_queue_unhold(p
->subs
[SUB_REAL
].owner
);
8406 p
->subs
[SUB_REAL
].needunhold
= 1;
8412 dahdi_conf_update(p
);
8423 ast_debug(1, "Ignoring wink on channel %d\n", p
->channel
);
8425 ast_debug(1, "Got wink in weird state %u on channel %d\n", ast_channel_state(ast
), p
->channel
);
8427 case SIG_FEATDMF_TA
:
8428 switch (p
->whichwink
) {
8430 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p
->owner
)->ani2
,
8431 S_COR(ast_channel_caller(p
->owner
)->ani
.number
.valid
,
8432 ast_channel_caller(p
->owner
)->ani
.number
.str
, ""));
8433 snprintf(p
->dop
.dialstr
, sizeof(p
->dop
.dialstr
), "M*%d%s#",
8434 ast_channel_caller(p
->owner
)->ani2
,
8435 S_COR(ast_channel_caller(p
->owner
)->ani
.number
.valid
,
8436 ast_channel_caller(p
->owner
)->ani
.number
.str
, ""));
8439 ast_copy_string(p
->dop
.dialstr
, p
->finaldial
, sizeof(p
->dop
.dialstr
));
8442 ast_log(LOG_WARNING
, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
8449 case SIG_FGC_CAMAMF
:
8452 case SIG_SF_FEATDMF
:
8455 /* FGD MF and EMWINK *Must* wait for wink */
8456 if (!ast_strlen_zero(p
->dop
.dialstr
)) {
8457 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
8459 p
->dop
.dialstr
[0] = '\0';
8462 ast_debug(1, "Sent deferred digit string: %s\n", p
->dop
.dialstr
);
8464 p
->dop
.dialstr
[0] = '\0';
8467 ast_log(LOG_WARNING
, "Don't know how to handle ring/off hook for signalling %d\n", p
->sig
);
8470 case DAHDI_EVENT_HOOKCOMPLETE
:
8471 if (p
->inalarm
) break;
8472 if ((p
->radio
|| (p
->oprmode
< 0))) break;
8473 if (p
->waitingfordt
.tv_sec
) break;
8475 case SIG_FXSLS
: /* only interesting for FXS */
8485 if (!ast_strlen_zero(p
->dop
.dialstr
)) {
8486 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
8488 p
->dop
.dialstr
[0] = '\0';
8491 ast_debug(1, "Sent deferred digit string: %s\n", p
->dop
.dialstr
);
8493 p
->dop
.dialstr
[0] = '\0';
8494 p
->dop
.op
= DAHDI_DIAL_OP_REPLACE
;
8497 case SIG_FEATDMF_TA
:
8500 case SIG_FGC_CAMAMF
:
8502 case SIG_SF_FEATDMF
:
8504 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p
->channel
);
8510 case DAHDI_EVENT_POLARITY
:
8512 * If we get a Polarity Switch event, check to see
8513 * if we should change the polarity state and
8514 * mark the channel as UP or if this is an indication
8515 * of remote end disconnect.
8517 if (p
->polarity
== POLARITY_IDLE
) {
8518 p
->polarity
= POLARITY_REV
;
8519 if (p
->answeronpolarityswitch
&&
8520 ((ast_channel_state(ast
) == AST_STATE_DIALING
) ||
8521 (ast_channel_state(ast
) == AST_STATE_RINGING
))) {
8522 ast_debug(1, "Answering on polarity switch!\n");
8523 ast_setstate(p
->owner
, AST_STATE_UP
);
8524 if (p
->hanguponpolarityswitch
) {
8525 p
->polaritydelaytv
= ast_tvnow();
8528 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %u\n", p
->channel
, ast_channel_state(ast
));
8530 /* Removed else statement from here as it was preventing hangups from ever happening*/
8531 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
8532 if (p
->hanguponpolarityswitch
&&
8533 (p
->polarityonanswerdelay
> 0) &&
8534 (p
->polarity
== POLARITY_REV
) &&
8535 ((ast_channel_state(ast
) == AST_STATE_UP
) || (ast_channel_state(ast
) == AST_STATE_RING
)) ) {
8536 /* Added log_debug information below to provide a better indication of what is going on */
8537 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
) );
8539 if (ast_tvdiff_ms(ast_tvnow(), p
->polaritydelaytv
) > p
->polarityonanswerdelay
) {
8540 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p
->channel
);
8541 ast_softhangup(p
->owner
, AST_SOFTHANGUP_EXPLICIT
);
8542 p
->polarity
= POLARITY_IDLE
;
8544 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
));
8547 p
->polarity
= POLARITY_IDLE
;
8548 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %u\n", p
->channel
, ast_channel_state(ast
));
8550 /* Added more log_debug information below to provide a better indication of what is going on */
8551 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
) );
8554 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res
, p
->channel
);
8556 return &p
->subs
[idx
].f
;
8559 static struct ast_frame
*__dahdi_exception(struct ast_channel
*ast
)
8563 struct ast_frame
*f
;
8565 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
8567 if ((idx
= dahdi_get_index(ast
, p
, 0)) < 0) {
8571 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8572 p
->subs
[idx
].f
.datalen
= 0;
8573 p
->subs
[idx
].f
.samples
= 0;
8574 p
->subs
[idx
].f
.mallocd
= 0;
8575 p
->subs
[idx
].f
.offset
= 0;
8576 p
->subs
[idx
].f
.subclass
.integer
= 0;
8577 p
->subs
[idx
].f
.delivery
= ast_tv(0,0);
8578 p
->subs
[idx
].f
.src
= "dahdi_exception";
8579 p
->subs
[idx
].f
.data
.ptr
= NULL
;
8582 if ((!p
->owner
) && (!(p
->radio
|| (p
->oprmode
< 0)))) {
8583 /* If nobody owns us, absorb the event appropriately, otherwise
8584 we loop indefinitely. This occurs when, during call waiting, the
8585 other end hangs up our channel so that it no longer exists, but we
8586 have neither FLASH'd nor ONHOOK'd to signify our desire to
8587 change to the other channel. */
8588 if (p
->fake_event
) {
8589 res
= p
->fake_event
;
8592 res
= dahdi_get_event(p
->subs
[SUB_REAL
].dfd
);
8593 /* Switch to real if there is one and this isn't something really silly... */
8594 if ((res
!= DAHDI_EVENT_RINGEROFF
) && (res
!= DAHDI_EVENT_RINGERON
) &&
8595 (res
!= DAHDI_EVENT_HOOKCOMPLETE
)) {
8596 ast_debug(1, "Restoring owner of channel %d on event %d\n", p
->channel
, res
);
8597 p
->owner
= p
->subs
[SUB_REAL
].owner
;
8599 ast_queue_unhold(p
->owner
);
8601 p
->subs
[SUB_REAL
].needunhold
= 1;
8604 case DAHDI_EVENT_ONHOOK
:
8605 dahdi_ec_disable(p
);
8607 ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p
->owner
));
8608 dahdi_ring_phone(p
);
8609 p
->callwaitingrepeat
= 0;
8611 p
->cid_suppress_expire
= 0;
8613 ast_log(LOG_WARNING
, "Absorbed on hook, but nobody is left!?!?\n");
8614 dahdi_conf_update(p
);
8616 case DAHDI_EVENT_RINGOFFHOOK
:
8618 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
8619 if (p
->owner
&& (ast_channel_state(p
->owner
) == AST_STATE_RINGING
)) {
8620 p
->subs
[SUB_REAL
].needanswer
= 1;
8624 case DAHDI_EVENT_HOOKCOMPLETE
:
8625 case DAHDI_EVENT_RINGERON
:
8626 case DAHDI_EVENT_RINGEROFF
:
8629 case DAHDI_EVENT_WINKFLASH
:
8630 p
->flashtime
= ast_tvnow();
8632 ast_verb(3, "Channel %d flashed to other channel %s\n", p
->channel
, ast_channel_name(p
->owner
));
8633 if (ast_channel_state(p
->owner
) != AST_STATE_UP
) {
8634 /* Answer if necessary */
8635 usedindex
= dahdi_get_index(p
->owner
, p
, 0);
8636 if (usedindex
> -1) {
8637 p
->subs
[usedindex
].needanswer
= 1;
8639 ast_setstate(p
->owner
, AST_STATE_UP
);
8641 p
->callwaitingrepeat
= 0;
8643 p
->cid_suppress_expire
= 0;
8644 ast_queue_unhold(p
->owner
);
8645 p
->subs
[SUB_REAL
].needunhold
= 1;
8647 ast_log(LOG_WARNING
, "Absorbed on hook, but nobody is left!?!?\n");
8648 dahdi_conf_update(p
);
8651 ast_log(LOG_WARNING
, "Don't know how to absorb event %s\n", event2str(res
));
8653 f
= &p
->subs
[idx
].f
;
8656 if (!(p
->radio
|| (p
->oprmode
< 0)))
8657 ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast
, 0), p
->channel
);
8658 /* If it's not us, return NULL immediately */
8659 if (ast
!= p
->owner
) {
8661 ast_log(LOG_WARNING
, "We're %s, not %s\n", ast_channel_name(ast
), ast_channel_name(p
->owner
));
8663 f
= &p
->subs
[idx
].f
;
8667 f
= dahdi_handle_event(ast
);
8669 const char *name
= ast_strdupa(ast_channel_name(ast
));
8671 /* Tell the CDR this DAHDI device hung up */
8672 ast_mutex_unlock(&p
->lock
);
8673 ast_channel_unlock(ast
);
8674 ast_set_hangupsource(ast
, name
, 0);
8675 ast_channel_lock(ast
);
8676 ast_mutex_lock(&p
->lock
);
8681 static struct ast_frame
*dahdi_exception(struct ast_channel
*ast
)
8683 struct dahdi_pvt
*p
= ast_channel_tech_pvt(ast
);
8684 struct ast_frame
*f
;
8685 ast_mutex_lock(&p
->lock
);
8686 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8687 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8688 f
= analog_exception(analog_p
, ast
);
8690 f
= __dahdi_exception(ast
);
8692 ast_mutex_unlock(&p
->lock
);
8696 static struct ast_frame
*dahdi_read(struct ast_channel
*ast
)
8698 struct dahdi_pvt
*p
;
8702 struct ast_frame
*f
;
8705 * For analog channels, we must do deadlock avoidance because
8706 * analog ports can have more than one Asterisk channel using
8707 * the same private structure.
8709 p
= ast_channel_tech_pvt(ast
);
8710 while (ast_mutex_trylock(&p
->lock
)) {
8711 CHANNEL_DEADLOCK_AVOIDANCE(ast
);
8714 * Check to see if the channel is still associated with the same
8715 * private structure. While the Asterisk channel was unlocked
8716 * the following events may have occured:
8718 * 1) A masquerade may have associated the channel with another
8719 * technology or private structure.
8721 * 2) For PRI calls, call signaling could change the channel
8722 * association to another B channel (private structure).
8724 if (ast_channel_tech_pvt(ast
) != p
) {
8725 /* The channel is no longer associated. Quit gracefully. */
8726 return &ast_null_frame
;
8730 idx
= dahdi_get_index(ast
, p
, 0);
8732 /* Hang up if we don't really exist */
8734 ast_log(LOG_WARNING
, "We don't exist?\n");
8735 ast_mutex_unlock(&p
->lock
);
8739 if ((p
->radio
|| (p
->oprmode
< 0)) && p
->inalarm
) {
8740 ast_mutex_unlock(&p
->lock
);
8744 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
8745 p
->subs
[idx
].f
.datalen
= 0;
8746 p
->subs
[idx
].f
.samples
= 0;
8747 p
->subs
[idx
].f
.mallocd
= 0;
8748 p
->subs
[idx
].f
.offset
= 0;
8749 p
->subs
[idx
].f
.subclass
.integer
= 0;
8750 p
->subs
[idx
].f
.delivery
= ast_tv(0,0);
8751 p
->subs
[idx
].f
.src
= "dahdi_read";
8752 p
->subs
[idx
].f
.data
.ptr
= NULL
;
8754 /* make sure it sends initial key state as first frame */
8755 if ((p
->radio
|| (p
->oprmode
< 0)) && (!p
->firstradio
))
8757 struct dahdi_params ps
;
8759 memset(&ps
, 0, sizeof(ps
));
8760 if (ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &ps
) < 0) {
8761 ast_mutex_unlock(&p
->lock
);
8765 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8768 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_KEY
;
8772 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RADIO_UNKEY
;
8774 ast_mutex_unlock(&p
->lock
);
8775 return &p
->subs
[idx
].f
;
8778 if (!(--p
->ringt
)) {
8779 ast_mutex_unlock(&p
->lock
);
8786 openr2_chan_process_event(p
->r2chan
);
8787 if (OR2_DIR_FORWARD
== openr2_chan_get_direction(p
->r2chan
)) {
8788 struct ast_frame fr
= { AST_FRAME_CONTROL
, { AST_CONTROL_PROGRESS
} };
8789 /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
8790 * now enqueue a progress frame to bridge the media up */
8791 if (p
->mfcr2_call_accepted
&&
8792 !p
->mfcr2_progress_sent
&&
8793 ast_channel_state(ast
) == AST_STATE_RINGING
) {
8794 ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p
->channel
);
8795 ast_queue_frame(p
->owner
, &fr
);
8796 p
->mfcr2_progress_sent
= 1;
8802 if (p
->subs
[idx
].needringing
) {
8803 /* Send ringing frame if requested */
8804 p
->subs
[idx
].needringing
= 0;
8805 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8806 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_RINGING
;
8807 ast_setstate(ast
, AST_STATE_RINGING
);
8808 ast_mutex_unlock(&p
->lock
);
8809 return &p
->subs
[idx
].f
;
8812 if (p
->subs
[idx
].needbusy
) {
8813 /* Send busy frame if requested */
8814 p
->subs
[idx
].needbusy
= 0;
8815 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8816 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_BUSY
;
8817 ast_mutex_unlock(&p
->lock
);
8818 return &p
->subs
[idx
].f
;
8821 if (p
->subs
[idx
].needcongestion
) {
8822 /* Send congestion frame if requested */
8823 p
->subs
[idx
].needcongestion
= 0;
8824 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8825 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_CONGESTION
;
8826 ast_mutex_unlock(&p
->lock
);
8827 return &p
->subs
[idx
].f
;
8830 if (p
->subs
[idx
].needanswer
) {
8831 /* Send answer frame if requested */
8832 p
->subs
[idx
].needanswer
= 0;
8833 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8834 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_ANSWER
;
8835 ast_mutex_unlock(&p
->lock
);
8836 return &p
->subs
[idx
].f
;
8839 if (p
->mfcr2
&& openr2_chan_get_read_enabled(p
->r2chan
)) {
8840 /* openr2 took care of reading and handling any event
8841 (needanswer, needbusy etc), if we continue we will read()
8842 twice, lets just return a null frame. This should only
8843 happen when openr2 is dialing out */
8844 ast_mutex_unlock(&p
->lock
);
8845 return &ast_null_frame
;
8849 if (p
->subs
[idx
].needflash
) {
8850 /* Send answer frame if requested */
8851 p
->subs
[idx
].needflash
= 0;
8852 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8853 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_FLASH
;
8854 ast_mutex_unlock(&p
->lock
);
8855 return &p
->subs
[idx
].f
;
8858 if (p
->subs
[idx
].needhold
) {
8859 /* Send answer frame if requested */
8860 p
->subs
[idx
].needhold
= 0;
8861 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8862 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_HOLD
;
8863 ast_mutex_unlock(&p
->lock
);
8864 ast_debug(1, "Sending hold on '%s'\n", ast_channel_name(ast
));
8865 return &p
->subs
[idx
].f
;
8868 if (p
->subs
[idx
].needunhold
) {
8869 /* Send answer frame if requested */
8870 p
->subs
[idx
].needunhold
= 0;
8871 p
->subs
[idx
].f
.frametype
= AST_FRAME_CONTROL
;
8872 p
->subs
[idx
].f
.subclass
.integer
= AST_CONTROL_UNHOLD
;
8873 ast_mutex_unlock(&p
->lock
);
8874 ast_debug(1, "Sending unhold on '%s'\n", ast_channel_name(ast
));
8875 return &p
->subs
[idx
].f
;
8879 * If we have a fake_event, fake an exception to handle it only
8880 * if this channel owns the private.
8882 if (p
->fake_event
&& p
->owner
== ast
) {
8883 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8884 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8886 f
= analog_exception(analog_p
, ast
);
8888 f
= __dahdi_exception(ast
);
8890 ast_mutex_unlock(&p
->lock
);
8894 if (ast_format_cmp(ast_channel_rawreadformat(ast
), ast_format_slin
) == AST_FORMAT_CMP_EQUAL
) {
8895 if (!p
->subs
[idx
].linear
) {
8896 p
->subs
[idx
].linear
= 1;
8897 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
8899 ast_log(LOG_WARNING
, "Unable to set channel %d (index %d) to linear mode.\n", p
->channel
, idx
);
8902 if (p
->subs
[idx
].linear
) {
8903 p
->subs
[idx
].linear
= 0;
8904 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
8906 ast_log(LOG_WARNING
, "Unable to set channel %d (index %d) to companded mode.\n", p
->channel
, idx
);
8909 readbuf
= ((unsigned char *)p
->subs
[idx
].buffer
) + AST_FRIENDLY_OFFSET
;
8910 CHECK_BLOCKING(ast
);
8911 res
= read(p
->subs
[idx
].dfd
, readbuf
, p
->subs
[idx
].linear
? READ_SIZE
* 2 : READ_SIZE
);
8912 ast_clear_flag(ast_channel_flags(ast
), AST_FLAG_BLOCKING
);
8913 /* Check for hangup */
8917 if (errno
== EAGAIN
) {
8918 /* Return "NULL" frame if there is nobody there */
8919 ast_mutex_unlock(&p
->lock
);
8920 return &p
->subs
[idx
].f
;
8921 } else if (errno
== ELAST
) {
8922 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8923 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8924 f
= analog_exception(analog_p
, ast
);
8926 f
= __dahdi_exception(ast
);
8929 ast_log(LOG_WARNING
, "dahdi_rec: %s\n", strerror(errno
));
8931 ast_mutex_unlock(&p
->lock
);
8934 if (res
!= (p
->subs
[idx
].linear
? READ_SIZE
* 2 : READ_SIZE
)) {
8935 ast_debug(1, "Short read (%d/%d), must be an event...\n", res
, p
->subs
[idx
].linear
? READ_SIZE
* 2 : READ_SIZE
);
8936 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
8937 struct analog_pvt
*analog_p
= p
->sig_pvt
;
8938 f
= analog_exception(analog_p
, ast
);
8940 f
= __dahdi_exception(ast
);
8942 ast_mutex_unlock(&p
->lock
);
8945 if (p
->tdd
) { /* if in TDD mode, see if we receive that */
8948 c
= tdd_feed(p
->tdd
,readbuf
,READ_SIZE
);
8950 ast_debug(1,"tdd_feed failed\n");
8951 ast_mutex_unlock(&p
->lock
);
8954 if (c
) { /* if a char to return */
8955 p
->subs
[idx
].f
.subclass
.integer
= 0;
8956 p
->subs
[idx
].f
.frametype
= AST_FRAME_TEXT
;
8957 p
->subs
[idx
].f
.mallocd
= 0;
8958 p
->subs
[idx
].f
.offset
= AST_FRIENDLY_OFFSET
;
8959 p
->subs
[idx
].f
.data
.ptr
= p
->subs
[idx
].buffer
+ AST_FRIENDLY_OFFSET
;
8960 p
->subs
[idx
].f
.datalen
= 1;
8961 *((char *) p
->subs
[idx
].f
.data
.ptr
) = c
;
8962 ast_mutex_unlock(&p
->lock
);
8963 return &p
->subs
[idx
].f
;
8966 if (idx
== SUB_REAL
) {
8967 /* Ensure the CW timers decrement only on a single subchannel */
8968 if (p
->cidcwexpire
) {
8969 if (!--p
->cidcwexpire
) {
8970 /* Expired CID/CW */
8971 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
8972 restore_conference(p
);
8975 if (p
->cid_suppress_expire
) {
8976 --p
->cid_suppress_expire
;
8978 if (p
->callwaitingrepeat
) {
8979 if (!--p
->callwaitingrepeat
) {
8980 /* Expired, Repeat callwaiting tone */
8982 dahdi_callwait(ast
);
8986 if (p
->subs
[idx
].linear
) {
8987 p
->subs
[idx
].f
.datalen
= READ_SIZE
* 2;
8989 p
->subs
[idx
].f
.datalen
= READ_SIZE
;
8991 /* Handle CallerID Transmission */
8992 if ((p
->owner
== ast
) && p
->cidspill
) {
8996 p
->subs
[idx
].f
.frametype
= AST_FRAME_VOICE
;
8997 p
->subs
[idx
].f
.subclass
.format
= ast_channel_rawreadformat(ast
);
8998 p
->subs
[idx
].f
.samples
= READ_SIZE
;
8999 p
->subs
[idx
].f
.mallocd
= 0;
9000 p
->subs
[idx
].f
.offset
= AST_FRIENDLY_OFFSET
;
9001 p
->subs
[idx
].f
.data
.ptr
= p
->subs
[idx
].buffer
+ AST_FRIENDLY_OFFSET
/ sizeof(p
->subs
[idx
].buffer
[0]);
9003 ast_debug(1, "Read %d of voice on %s\n", p
->subs
[idx
].f
.datalen
, ast
->name
);
9005 if ((p
->dialing
&& !p
->waitingfordt
.tv_sec
) || p
->radio
|| /* Transmitting something */
9006 (idx
&& (ast_channel_state(ast
) != AST_STATE_UP
)) || /* Three-way or callwait that isn't up */
9007 ((idx
== SUB_CALLWAIT
) && !p
->subs
[SUB_CALLWAIT
].inthreeway
) /* Inactive and non-confed call-wait */
9009 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
9010 don't send anything */
9011 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
9012 p
->subs
[idx
].f
.subclass
.integer
= 0;
9013 p
->subs
[idx
].f
.samples
= 0;
9014 p
->subs
[idx
].f
.mallocd
= 0;
9015 p
->subs
[idx
].f
.offset
= 0;
9016 p
->subs
[idx
].f
.data
.ptr
= NULL
;
9017 p
->subs
[idx
].f
.datalen
= 0;
9019 if (p
->dsp
&& (!p
->ignoredtmf
|| p
->callwaitcas
|| p
->busydetect
|| p
->callprogress
|| p
->waitingfordt
.tv_sec
|| p
->dialtone_detect
) && !idx
) {
9020 /* Perform busy detection etc on the dahdi line */
9023 if ((p
->dsp_features
& DSP_FEATURE_FAX_DETECT
)
9024 && p
->faxdetect_timeout
9025 && p
->faxdetect_timeout
<= ast_channel_get_up_time(ast
)) {
9026 p
->dsp_features
&= ~DSP_FEATURE_FAX_DETECT
;
9027 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
9028 ast_debug(1, "Channel driver fax CNG detection timeout on %s\n",
9029 ast_channel_name(ast
));
9032 f
= ast_dsp_process(ast
, p
->dsp
, &p
->subs
[idx
].f
);
9034 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
9035 mute
= ast_dsp_was_muted(p
->dsp
);
9036 if (p
->muting
!= mute
) {
9038 dahdi_confmute(p
, mute
);
9042 if ((p
->dsp_features
& DSP_FEATURE_WAITDIALTONE
) && (p
->dialtone_detect
> 0)
9043 && !p
->outgoing
&& ast_channel_state(ast
) == AST_STATE_UP
) {
9044 if (++p
->dialtone_scanning_time_elapsed
>= p
->dialtone_detect
) {
9045 p
->dsp_features
&= ~DSP_FEATURE_WAITDIALTONE
;
9046 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
9049 if ((f
->frametype
== AST_FRAME_CONTROL
) && (f
->subclass
.integer
== AST_CONTROL_BUSY
)) {
9050 if ((ast_channel_state(ast
) == AST_STATE_UP
) && !p
->outgoing
) {
9052 * Treat this as a "hangup" instead of a "busy" on the
9053 * assumption that a busy means the incoming call went away.
9058 } else if (p
->dialtone_detect
&& !p
->outgoing
&& f
->frametype
== AST_FRAME_VOICE
) {
9059 if ((ast_dsp_get_tstate(p
->dsp
) == DSP_TONE_STATE_DIALTONE
) && (ast_dsp_get_tcount(p
->dsp
) > 9)) {
9060 /* Dialtone detected on inbound call; hangup the channel */
9064 } else if (f
->frametype
== AST_FRAME_DTMF_BEGIN
9065 || f
->frametype
== AST_FRAME_DTMF_END
) {
9067 if (dahdi_sig_pri_lib_handles(p
->sig
)
9068 && ((struct sig_pri_chan
*) p
->sig_pvt
)->call_level
< SIG_PRI_CALL_LEVEL_PROCEEDING
9070 && ((!p
->outgoing
&& (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_INCOMING
))
9071 || (p
->outgoing
&& (p
->pri
->overlapdial
& DAHDI_OVERLAPDIAL_OUTGOING
)))) {
9072 /* Don't accept in-band DTMF when in overlap dial mode */
9073 ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n",
9074 f
->frametype
== AST_FRAME_DTMF_BEGIN
? "begin" : "end",
9075 (unsigned)f
->subclass
.integer
, f
->subclass
.integer
, ast_channel_name(ast
));
9077 f
->frametype
= AST_FRAME_NULL
;
9078 f
->subclass
.integer
= 0;
9081 /* DSP clears us of being pulse */
9083 } else if (p
->waitingfordt
.tv_sec
) {
9084 if (ast_tvdiff_ms(ast_tvnow(), p
->waitingfordt
) >= p
->waitfordialtone
) {
9085 p
->waitingfordt
.tv_sec
= 0;
9086 ast_log(LOG_WARNING
, "Never saw dialtone on channel %d\n", p
->channel
);
9089 } else if (f
->frametype
== AST_FRAME_VOICE
) {
9090 f
->frametype
= AST_FRAME_NULL
;
9091 f
->subclass
.integer
= 0;
9092 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) {
9093 p
->waitingfordt
.tv_sec
= 0;
9094 p
->dsp_features
&= ~DSP_FEATURE_WAITDIALTONE
;
9095 ast_dsp_set_features(p
->dsp
, p
->dsp_features
);
9096 ast_debug(1, "Got 10 samples of dialtone!\n");
9097 if (!ast_strlen_zero(p
->dop
.dialstr
)) { /* Dial deferred digits */
9098 res
= dahdi_dial_str(p
, p
->dop
.op
, p
->dop
.dialstr
);
9100 p
->dop
.dialstr
[0] = '\0';
9101 ast_mutex_unlock(&p
->lock
);
9105 ast_debug(1, "Sent deferred digit string: %s\n", p
->dop
.dialstr
);
9107 p
->dop
.dialstr
[0] = '\0';
9108 p
->dop
.op
= DAHDI_DIAL_OP_REPLACE
;
9109 ast_setstate(ast
, AST_STATE_DIALING
);
9117 f
= &p
->subs
[idx
].f
;
9120 switch (f
->frametype
) {
9121 case AST_FRAME_DTMF_BEGIN
:
9122 case AST_FRAME_DTMF_END
:
9123 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
9124 analog_handle_dtmf(p
->sig_pvt
, ast
, idx
, &f
);
9126 dahdi_handle_dtmf(ast
, idx
, &f
);
9128 if (!(p
->dialmode
== ANALOG_DIALMODE_BOTH
|| p
->dialmode
== ANALOG_DIALMODE_DTMF
)) {
9129 if (f
->frametype
== AST_FRAME_DTMF_END
) { /* only show this message when the key is let go of */
9130 ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f
->subclass
.integer
);
9132 f
->frametype
= AST_FRAME_NULL
;
9133 f
->subclass
.integer
= 0;
9136 case AST_FRAME_VOICE
:
9137 if (p
->cidspill
|| p
->cid_suppress_expire
) {
9138 /* We are/were sending a caller id spill. Suppress any echo. */
9139 p
->subs
[idx
].f
.frametype
= AST_FRAME_NULL
;
9140 p
->subs
[idx
].f
.subclass
.integer
= 0;
9141 p
->subs
[idx
].f
.samples
= 0;
9142 p
->subs
[idx
].f
.mallocd
= 0;
9143 p
->subs
[idx
].f
.offset
= 0;
9144 p
->subs
[idx
].f
.data
.ptr
= NULL
;
9145 p
->subs
[idx
].f
.datalen
= 0;
9153 ast_mutex_unlock(&p
->lock
);
9157 static int my_dahdi_write(struct dahdi_pvt
*p
, unsigned char *buf
, int len
, int idx
, int linear
)
9163 fd
= p
->subs
[idx
].dfd
;
9166 if (size
> (linear
? READ_SIZE
* 2 : READ_SIZE
))
9167 size
= (linear
? READ_SIZE
* 2 : READ_SIZE
);
9168 res
= write(fd
, buf
, size
);
9170 ast_debug(1, "Write returned %d (%s) on channel %d\n", res
, strerror(errno
), p
->channel
);
9179 static int dahdi_write(struct ast_channel
*ast
, struct ast_frame
*frame
)
9181 struct dahdi_pvt
*p
;
9185 /* Write a frame of (presumably voice) data */
9186 if (frame
->frametype
!= AST_FRAME_VOICE
) {
9187 if (frame
->frametype
!= AST_FRAME_IMAGE
) {
9188 ast_log(LOG_WARNING
, "Don't know what to do with frame type '%u'\n",
9194 /* Return if it's not valid data */
9195 if (!frame
->data
.ptr
|| !frame
->datalen
) {
9199 p
= ast_channel_tech_pvt(ast
);
9200 ast_mutex_lock(&p
->lock
);
9202 idx
= dahdi_get_index(ast
, p
, 0);
9204 ast_mutex_unlock(&p
->lock
);
9205 ast_log(LOG_WARNING
, "%s doesn't really exist?\n", ast_channel_name(ast
));
9210 ast_mutex_unlock(&p
->lock
);
9211 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9212 ast_channel_name(ast
));
9216 ast_mutex_unlock(&p
->lock
);
9217 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9218 ast_channel_name(ast
));
9222 ast_mutex_unlock(&p
->lock
);
9223 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9224 ast_channel_name(ast
));
9228 if (ast_format_cmp(frame
->subclass
.format
, ast_format_slin
) == AST_FORMAT_CMP_EQUAL
) {
9229 if (!p
->subs
[idx
].linear
) {
9230 p
->subs
[idx
].linear
= 1;
9231 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
9233 ast_log(LOG_WARNING
, "Unable to set linear mode on channel %d\n", p
->channel
);
9235 res
= my_dahdi_write(p
, (unsigned char *)frame
->data
.ptr
, frame
->datalen
, idx
, 1);
9236 } else if (ast_format_cmp(frame
->subclass
.format
, ast_format_ulaw
) == AST_FORMAT_CMP_EQUAL
9237 || ast_format_cmp(frame
->subclass
.format
, ast_format_alaw
) == AST_FORMAT_CMP_EQUAL
) {
9239 if (p
->subs
[idx
].linear
) {
9240 p
->subs
[idx
].linear
= 0;
9241 res
= dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
9243 ast_log(LOG_WARNING
, "Unable to set companded mode on channel %d\n", p
->channel
);
9245 res
= my_dahdi_write(p
, (unsigned char *)frame
->data
.ptr
, frame
->datalen
, idx
, 0);
9247 ast_mutex_unlock(&p
->lock
);
9248 ast_log(LOG_WARNING
, "Cannot handle frames in %s format\n",
9249 ast_format_get_name(frame
->subclass
.format
));
9252 ast_mutex_unlock(&p
->lock
);
9254 ast_log(LOG_WARNING
, "write failed: %s\n", strerror(errno
));
9260 static int dahdi_indicate(struct ast_channel
*chan
, int condition
, const void *data
, size_t datalen
)
9262 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
9265 int func
= DAHDI_FLASH
;
9267 ast_mutex_lock(&p
->lock
);
9268 ast_debug(1, "Requested indication %d on channel %s\n", condition
, ast_channel_name(chan
));
9270 #if defined(HAVE_PRI)
9271 case SIG_PRI_LIB_HANDLE_CASES
:
9272 res
= sig_pri_indicate(p
->sig_pvt
, chan
, condition
, data
, datalen
);
9273 ast_mutex_unlock(&p
->lock
);
9275 #endif /* defined(HAVE_PRI) */
9276 #if defined(HAVE_SS7)
9278 res
= sig_ss7_indicate(p
->sig_pvt
, chan
, condition
, data
, datalen
);
9279 ast_mutex_unlock(&p
->lock
);
9281 #endif /* defined(HAVE_SS7) */
9286 if (p
->mfcr2
&& !p
->mfcr2_call_accepted
) {
9287 ast_mutex_unlock(&p
->lock
);
9288 /* if this is an R2 call and the call is not yet accepted, we don't want the
9289 tone indications to mess up with the MF tones */
9293 idx
= dahdi_get_index(chan
, p
, 0);
9294 if (idx
== SUB_REAL
) {
9295 switch (condition
) {
9296 case AST_CONTROL_BUSY
:
9297 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_BUSY
);
9299 case AST_CONTROL_RINGING
:
9300 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_RINGTONE
);
9302 if (ast_channel_state(chan
) != AST_STATE_UP
) {
9303 if ((ast_channel_state(chan
) != AST_STATE_RING
) ||
9304 ((p
->sig
!= SIG_FXSKS
) &&
9305 (p
->sig
!= SIG_FXSLS
) &&
9306 (p
->sig
!= SIG_FXSGS
)))
9307 ast_setstate(chan
, AST_STATE_RINGING
);
9310 case AST_CONTROL_INCOMPLETE
:
9311 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan
));
9312 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9315 case AST_CONTROL_PROCEEDING
:
9316 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan
));
9317 /* don't continue in ast_indicate */
9320 case AST_CONTROL_PROGRESS
:
9321 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan
));
9322 /* don't continue in ast_indicate */
9325 case AST_CONTROL_CONGESTION
:
9326 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9327 switch (ast_channel_hangupcause(chan
)) {
9328 case AST_CAUSE_USER_BUSY
:
9329 case AST_CAUSE_NORMAL_CLEARING
:
9330 case 0:/* Cause has not been set. */
9331 /* Supply a more appropriate cause. */
9332 ast_channel_hangupcause_set(chan
, AST_CAUSE_CONGESTION
);
9338 case AST_CONTROL_HOLD
:
9339 ast_moh_start(chan
, data
, p
->mohinterpret
);
9341 case AST_CONTROL_UNHOLD
:
9344 case AST_CONTROL_RADIO_KEY
:
9346 res
= dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_OFFHOOK
);
9349 case AST_CONTROL_RADIO_UNKEY
:
9351 res
= dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_RINGOFF
);
9354 case AST_CONTROL_FLASH
:
9355 /* flash hookswitch */
9356 if (ISTRUNK(p
) && (p
->sig
!= SIG_PRI
)) {
9357 /* Clear out the dial buffer */
9358 p
->dop
.dialstr
[0] = '\0';
9359 if ((ioctl(p
->subs
[SUB_REAL
].dfd
,DAHDI_HOOK
,&func
) == -1) && (errno
!= EINPROGRESS
)) {
9360 ast_log(LOG_WARNING
, "Unable to flash external trunk on channel %s: %s\n",
9361 ast_channel_name(chan
), strerror(errno
));
9367 case AST_CONTROL_SRCUPDATE
:
9371 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
9377 ast_mutex_unlock(&p
->lock
);
9381 #if defined(HAVE_PRI)
9382 static struct ast_str
*create_channel_name(struct dahdi_pvt
*i
, int is_outgoing
, char *address
)
9384 static struct ast_str
*create_channel_name(struct dahdi_pvt
*i
)
9385 #endif /* defined(HAVE_PRI) */
9387 struct ast_str
*chan_name
;
9390 /* Create the new channel name tail. */
9391 if (!(chan_name
= ast_str_create(32))) {
9394 if (i
->channel
== CHAN_PSEUDO
) {
9395 ast_str_set(&chan_name
, 0, "pseudo-%ld", ast_random());
9396 #if defined(HAVE_PRI)
9397 } else if (i
->pri
) {
9398 ast_mutex_lock(&i
->pri
->lock
);
9399 y
= ++i
->pri
->new_chan_seq
;
9401 ast_str_set(&chan_name
, 0, "i%d/%s-%x", i
->pri
->span
, address
, (unsigned)y
);
9403 } else if (ast_strlen_zero(i
->cid_subaddr
)) {
9404 /* Put in caller-id number only since there is no subaddress. */
9405 ast_str_set(&chan_name
, 0, "i%d/%s-%x", i
->pri
->span
, i
->cid_num
, (unsigned)y
);
9407 /* Put in caller-id number and subaddress. */
9408 ast_str_set(&chan_name
, 0, "i%d/%s:%s-%x", i
->pri
->span
, i
->cid_num
,
9409 i
->cid_subaddr
, (unsigned)y
);
9411 ast_mutex_unlock(&i
->pri
->lock
);
9412 #endif /* defined(HAVE_PRI) */
9416 ast_str_set(&chan_name
, 0, "%d-%d", i
->channel
, y
);
9417 for (x
= 0; x
< 3; ++x
) {
9418 if (i
->subs
[x
].owner
&& !strcasecmp(ast_str_buffer(chan_name
),
9419 ast_channel_name(i
->subs
[x
].owner
) + 6)) {
9429 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
)
9431 struct ast_channel
*new_channel
= dahdi_new(i
, state
, startpbx
, idx
, law
, assignedids
, requestor
, callid
);
9433 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
9438 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
)
9440 struct ast_channel
*tmp
;
9441 struct ast_format_cap
*caps
;
9442 struct ast_format
*deflaw
;
9445 struct ast_str
*chan_name
;
9446 struct ast_variable
*v
;
9448 char device_name
[AST_CHANNEL_NAME
];
9450 if (i
->subs
[idx
].owner
) {
9451 ast_log(LOG_WARNING
, "Channel %d already has a %s call\n", i
->channel
,subnames
[idx
]);
9455 #if defined(HAVE_PRI)
9457 * The dnid has been stuffed with the called-number[:subaddress]
9458 * by dahdi_request() for outgoing calls.
9460 chan_name
= create_channel_name(i
, i
->outgoing
, i
->dnid
);
9462 chan_name
= create_channel_name(i
);
9463 #endif /* defined(HAVE_PRI) */
9468 caps
= ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT
);
9470 ast_free(chan_name
);
9474 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
));
9475 ast_free(chan_name
);
9481 ast_channel_stage_snapshot(tmp
);
9484 ast_channel_callid_set(tmp
, callid
);
9487 ast_channel_tech_set(tmp
, &dahdi_tech
);
9488 #if defined(HAVE_PRI)
9490 ast_cc_copy_config_params(i
->cc_params
, i
->pri
->cc_params
);
9492 #endif /* defined(HAVE_PRI) */
9493 ast_channel_cc_params_init(tmp
, i
->cc_params
);
9496 if (law
== DAHDI_LAW_ALAW
) {
9497 deflaw
= ast_format_alaw
;
9499 deflaw
= ast_format_ulaw
;
9503 case SIG_PRI_LIB_HANDLE_CASES
:
9504 /* Make sure companding law is known. */
9505 i
->law
= (i
->law_default
== DAHDI_LAW_ALAW
)
9506 ? DAHDI_LAW_ALAW
: DAHDI_LAW_MULAW
;
9509 i
->law
= i
->law_default
;
9512 if (i
->law_default
== DAHDI_LAW_ALAW
) {
9513 deflaw
= ast_format_alaw
;
9515 deflaw
= ast_format_ulaw
;
9518 ast_channel_set_fd(tmp
, 0, i
->subs
[idx
].dfd
);
9519 ast_format_cap_append(caps
, deflaw
, 0);
9520 ast_channel_nativeformats_set(tmp
, caps
);
9522 /* Start out assuming ulaw since it's smaller :) */
9523 ast_channel_set_rawreadformat(tmp
, deflaw
);
9524 ast_channel_set_readformat(tmp
, deflaw
);
9525 ast_channel_set_rawwriteformat(tmp
, deflaw
);
9526 ast_channel_set_writeformat(tmp
, deflaw
);
9527 i
->subs
[idx
].linear
= 0;
9528 dahdi_setlinear(i
->subs
[idx
].dfd
, i
->subs
[idx
].linear
);
9530 if (idx
== SUB_REAL
) {
9531 if (i
->busydetect
&& CANBUSYDETECT(i
))
9532 features
|= DSP_FEATURE_BUSY_DETECT
;
9533 if ((i
->callprogress
& CALLPROGRESS_PROGRESS
) && CANPROGRESSDETECT(i
))
9534 features
|= DSP_FEATURE_CALL_PROGRESS
;
9535 if ((i
->waitfordialtone
|| i
->dialtone_detect
) && CANPROGRESSDETECT(i
))
9536 features
|= DSP_FEATURE_WAITDIALTONE
;
9537 if ((!i
->outgoing
&& (i
->callprogress
& CALLPROGRESS_FAX_INCOMING
)) ||
9538 (i
->outgoing
&& (i
->callprogress
& CALLPROGRESS_FAX_OUTGOING
))) {
9539 features
|= DSP_FEATURE_FAX_DETECT
;
9541 x
= DAHDI_TONEDETECT_ON
| DAHDI_TONEDETECT_MUTE
;
9542 if (ioctl(i
->subs
[idx
].dfd
, DAHDI_TONEDETECT
, &x
)) {
9543 i
->hardwaredtmf
= 0;
9544 features
|= DSP_FEATURE_DIGIT_DETECT
;
9545 } else if (NEED_MFDETECT(i
)) {
9546 i
->hardwaredtmf
= 1;
9547 features
|= DSP_FEATURE_DIGIT_DETECT
;
9552 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp
));
9554 if (i
->channel
!= CHAN_PSEUDO
)
9555 i
->dsp
= ast_dsp_new();
9559 i
->dsp_features
= features
;
9560 #if defined(HAVE_PRI) || defined(HAVE_SS7)
9561 /* We cannot do progress detection until receive PROGRESS message */
9562 if (i
->outgoing
&& (dahdi_sig_pri_lib_handles(i
->sig
) || (i
->sig
== SIG_SS7
))) {
9563 /* Remember requested DSP features, don't treat
9564 talking as ANSWER */
9565 i
->dsp_features
= features
& ~DSP_PROGRESS_TALK
;
9568 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9569 ast_dsp_set_features(i
->dsp
, features
);
9570 ast_dsp_set_digitmode(i
->dsp
, DSP_DIGITMODE_DTMF
| i
->dtmfrelax
);
9571 if (!ast_strlen_zero(progzone
))
9572 ast_dsp_set_call_progress_zone(i
->dsp
, progzone
);
9573 if (i
->busydetect
&& CANBUSYDETECT(i
)) {
9574 ast_dsp_set_busy_count(i
->dsp
, i
->busycount
);
9575 ast_dsp_set_busy_pattern(i
->dsp
, &i
->busy_cadence
);
9581 i
->dialtone_scanning_time_elapsed
= 0;
9583 if (state
== AST_STATE_RING
)
9584 ast_channel_rings_set(tmp
, 1);
9585 ast_channel_tech_pvt_set(tmp
, i
);
9586 if ((i
->sig
== SIG_FXOKS
) || (i
->sig
== SIG_FXOGS
) || (i
->sig
== SIG_FXOLS
)) {
9587 /* Only FXO signalled stuff can be picked up */
9588 ast_channel_callgroup_set(tmp
, i
->callgroup
);
9589 ast_channel_pickupgroup_set(tmp
, i
->pickupgroup
);
9590 ast_channel_named_callgroups_set(tmp
, i
->named_callgroups
);
9591 ast_channel_named_pickupgroups_set(tmp
, i
->named_pickupgroups
);
9593 if (!ast_strlen_zero(i
->parkinglot
))
9594 ast_channel_parkinglot_set(tmp
, i
->parkinglot
);
9595 if (!ast_strlen_zero(i
->language
))
9596 ast_channel_language_set(tmp
, i
->language
);
9599 if (!ast_strlen_zero(i
->accountcode
))
9600 ast_channel_accountcode_set(tmp
, i
->accountcode
);
9602 ast_channel_amaflags_set(tmp
, i
->amaflags
);
9603 i
->subs
[idx
].owner
= tmp
;
9604 ast_channel_context_set(tmp
, i
->context
);
9605 if (!dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
9606 ast_channel_call_forward_set(tmp
, i
->call_forward
);
9608 /* If we've been told "no ADSI" then enforce it */
9610 ast_channel_adsicpe_set(tmp
, AST_ADSI_UNAVAILABLE
);
9611 if (!ast_strlen_zero(i
->exten
))
9612 ast_channel_exten_set(tmp
, i
->exten
);
9613 if (!ast_strlen_zero(i
->rdnis
)) {
9614 ast_channel_redirecting(tmp
)->from
.number
.valid
= 1;
9615 ast_channel_redirecting(tmp
)->from
.number
.str
= ast_strdup(i
->rdnis
);
9617 if (!ast_strlen_zero(i
->dnid
)) {
9618 ast_channel_dialed(tmp
)->number
.str
= ast_strdup(i
->dnid
);
9621 /* Don't use ast_set_callerid() here because it will
9622 * generate a needless NewCallerID event */
9623 #if defined(HAVE_PRI) || defined(HAVE_SS7)
9624 if (!ast_strlen_zero(i
->cid_ani
)) {
9625 ast_channel_caller(tmp
)->ani
.number
.valid
= 1;
9626 ast_channel_caller(tmp
)->ani
.number
.str
= ast_strdup(i
->cid_ani
);
9627 } else if (!ast_strlen_zero(i
->cid_num
)) {
9628 ast_channel_caller(tmp
)->ani
.number
.valid
= 1;
9629 ast_channel_caller(tmp
)->ani
.number
.str
= ast_strdup(i
->cid_num
);
9632 if (!ast_strlen_zero(i
->cid_num
)) {
9633 ast_channel_caller(tmp
)->ani
.number
.valid
= 1;
9634 ast_channel_caller(tmp
)->ani
.number
.str
= ast_strdup(i
->cid_num
);
9636 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9637 ast_channel_caller(tmp
)->id
.name
.presentation
= i
->callingpres
;
9638 ast_channel_caller(tmp
)->id
.number
.presentation
= i
->callingpres
;
9639 ast_channel_caller(tmp
)->id
.number
.plan
= i
->cid_ton
;
9640 ast_channel_caller(tmp
)->ani2
= i
->cid_ani2
;
9641 ast_channel_caller(tmp
)->id
.tag
= ast_strdup(i
->cid_tag
);
9642 /* clear the fake event in case we posted one before we had ast_channel */
9644 /* Assure there is no confmute on this channel */
9645 dahdi_confmute(i
, 0);
9647 /* Configure the new channel jb */
9648 ast_jb_configure(tmp
, &global_jbconf
);
9650 /* Set initial device state */
9651 ast_copy_string(device_name
, ast_channel_name(tmp
), sizeof(device_name
));
9652 dashptr
= strrchr(device_name
, '-');
9656 ast_set_flag(ast_channel_flags(tmp
), AST_FLAG_DISABLE_DEVSTATE_CACHE
);
9657 ast_devstate_changed_literal(AST_DEVICE_UNKNOWN
, AST_DEVSTATE_NOT_CACHABLE
, device_name
);
9659 for (v
= i
->vars
; v
; v
= v
->next
)
9660 pbx_builtin_setvar_helper(tmp
, v
->name
, v
->value
);
9662 ast_channel_stage_snapshot_done(tmp
);
9664 ast_channel_unlock(tmp
);
9666 ast_module_ref(ast_module_info
->self
);
9668 dahdi_ami_channel_event(i
, tmp
);
9672 pbx_builtin_setvar_helper(tmp
, "MFCR2_CATEGORY", openr2_proto_get_category_string(i
->mfcr2_recvd_category
));
9675 if (ast_pbx_start(tmp
)) {
9676 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", ast_channel_name(tmp
));
9685 static int my_getsigstr(struct ast_channel
*chan
, char *str
, const char *term
, int ms
)
9689 *str
= 0; /* start with empty output buffer */
9692 /* Wait for the first digit (up to specified ms). */
9693 c
= ast_waitfordigit(chan
, ms
);
9694 /* if timeout, hangup or error, return as such */
9699 if (strchr(term
, c
))
9704 static int dahdi_wink(struct dahdi_pvt
*p
, int idx
)
9707 dahdi_set_hook(p
->subs
[idx
].dfd
, DAHDI_WINK
);
9710 /* set bits of interest */
9711 j
= DAHDI_IOMUX_SIGEVENT
;
9712 /* wait for some happening */
9713 if (ioctl(p
->subs
[idx
].dfd
,DAHDI_IOMUX
,&j
) == -1) return(-1);
9714 /* exit loop if we have it */
9715 if (j
& DAHDI_IOMUX_SIGEVENT
) break;
9717 /* get the event info */
9718 if (ioctl(p
->subs
[idx
].dfd
,DAHDI_GETEVENT
,&j
) == -1) return(-1);
9722 static void publish_dnd_state(int channel
, const char *status
)
9724 RAII_VAR(struct ast_json
*, body
, NULL
, ast_json_unref
);
9725 RAII_VAR(struct ast_str
*, dahdichan
, ast_str_create(32), ast_free
);
9730 ast_str_set(&dahdichan
, 0, "%d", channel
);
9732 body
= ast_json_pack("{s: s, s: s}",
9733 "DAHDIChannel", ast_str_buffer(dahdichan
),
9739 ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM
, body
);
9742 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9743 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9744 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9746 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9747 * DAHDI channel). Use this to enable or disable it.
9749 * \bug the use of the word "channel" for those dahdichans is really confusing.
9751 static int dahdi_dnd(struct dahdi_pvt
*dahdichan
, int flag
)
9753 if (dahdi_analog_lib_handles(dahdichan
->sig
, dahdichan
->radio
, dahdichan
->oprmode
)) {
9754 return analog_dnd(dahdichan
->sig_pvt
, flag
);
9758 return dahdichan
->dnd
;
9761 /* Do not disturb */
9762 dahdichan
->dnd
= flag
;
9763 ast_verb(3, "%s DND on channel %d\n",
9764 flag
? "Enabled" : "Disabled",
9765 dahdichan
->channel
);
9766 publish_dnd_state(dahdichan
->channel
, flag
? "enabled" : "disabled");
9770 static int canmatch_featurecode(const char *pickupexten
, const char *exten
)
9772 int extlen
= strlen(exten
);
9778 if (extlen
< strlen(pickupexten
) && !strncmp(pickupexten
, exten
, extlen
)) {
9781 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9782 if (exten
[0] == '*' && extlen
< 3) {
9786 /* "*0" should be processed before it gets here */
9797 static void *analog_ss_thread(void *data
)
9799 struct ast_channel
*chan
= data
;
9800 struct dahdi_pvt
*p
= ast_channel_tech_pvt(chan
);
9801 char exten
[AST_MAX_EXTENSION
] = "";
9802 char exten2
[AST_MAX_EXTENSION
] = "";
9803 unsigned char buf
[256];
9806 struct callerid_state
*cs
= NULL
;
9807 char *name
= NULL
, *number
= NULL
;
9814 struct ast_smdi_md_message
*smdi_msg
= NULL
;
9823 RAII_VAR(struct ast_features_pickup_config
*, pickup_cfg
, NULL
, ao2_cleanup
);
9824 const char *pickupexten
;
9826 ast_mutex_lock(&ss_thread_lock
);
9828 ast_mutex_unlock(&ss_thread_lock
);
9829 /* in the bizarre case where the channel has become a zombie before we
9830 even get started here, abort safely
9833 ast_log(LOG_WARNING
, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan
));
9837 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan
));
9838 idx
= dahdi_get_index(chan
, p
, 1);
9840 ast_log(LOG_WARNING
, "Huh?\n");
9845 ast_channel_lock(chan
);
9846 pickup_cfg
= ast_get_chan_features_pickup_config(chan
);
9848 ast_log(LOG_ERROR
, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
9851 pickupexten
= ast_strdupa(pickup_cfg
->pickupexten
);
9853 ast_channel_unlock(chan
);
9856 ast_dsp_digitreset(p
->dsp
);
9860 case SIG_FEATDMF_TA
:
9862 case SIG_FGC_CAMAMF
:
9866 case SIG_SF_FEATDMF
:
9869 if (dahdi_wink(p
, idx
))
9876 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
9878 ast_dsp_digitreset(p
->dsp
);
9879 /* set digit mode appropriately */
9881 if (NEED_MFDETECT(p
))
9882 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MF
| p
->dtmfrelax
);
9884 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
9886 memset(dtmfbuf
, 0, sizeof(dtmfbuf
));
9887 /* Wait for the first digit only if immediate=no */
9889 /* Wait for the first digit (up to 5 seconds). */
9890 res
= ast_waitfordigit(chan
, 5000);
9894 /* save first char */
9899 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "*", 3000);
9901 res
= my_getsigstr(chan
, dtmfbuf
+ strlen(dtmfbuf
), "*", 3000);
9902 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9904 case SIG_FEATDMF_TA
:
9905 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9906 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9907 if (dahdi_wink(p
, idx
)) goto quit
;
9909 /* Wait for the first digit (up to 5 seconds). */
9910 res
= ast_waitfordigit(chan
, 5000);
9911 if (res
<= 0) break;
9913 /* fall through intentionally */
9916 case SIG_FGC_CAMAMF
:
9917 case SIG_SF_FEATDMF
:
9918 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9919 /* if international caca, do it again to get real ANO */
9920 if ((p
->sig
== SIG_FEATDMF
) && (dtmfbuf
[1] != '0') && (strlen(dtmfbuf
) != 14))
9922 if (dahdi_wink(p
, idx
)) goto quit
;
9924 /* Wait for the first digit (up to 5 seconds). */
9925 res
= ast_waitfordigit(chan
, 5000);
9926 if (res
<= 0) break;
9928 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9931 /* if E911, take off hook */
9932 if (p
->sig
== SIG_E911
)
9933 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
9934 res
= my_getsigstr(chan
, dtmfbuf
+ strlen(dtmfbuf
), "#", 3000);
9936 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9940 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "#", 3000);
9941 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9944 /* if we received a '*', we are actually receiving Feature Group D
9945 dial syntax, so use that mode; otherwise, fall through to normal
9949 res
= my_getsigstr(chan
, dtmfbuf
+ 1, "*", 3000);
9951 res
= my_getsigstr(chan
, dtmfbuf
+ strlen(dtmfbuf
), "*", 3000);
9952 if ((res
< 1) && (p
->dsp
)) ast_dsp_digitreset(p
->dsp
);
9956 /* If we got the first digit, get the rest */
9958 dtmfbuf
[len
] = '\0';
9959 while ((len
< AST_MAX_EXTENSION
-1) && ast_matchmore_extension(chan
, ast_channel_context(chan
), dtmfbuf
, 1, p
->cid_num
)) {
9960 if (ast_exists_extension(chan
, ast_channel_context(chan
), dtmfbuf
, 1, p
->cid_num
)) {
9961 timeout
= p
->matchdigit_timeout
;
9963 timeout
= p
->interdigit_timeout
;
9965 res
= ast_waitfordigit(chan
, timeout
);
9967 ast_debug(1, "waitfordigit returned < 0...\n");
9971 dtmfbuf
[len
++] = res
;
9972 dtmfbuf
[len
] = '\0';
9981 ast_log(LOG_WARNING
, "getdtmf on channel %d: %s\n", p
->channel
, strerror(errno
));
9984 } else if (res
< 0) {
9985 ast_debug(1, "Got hung up before digits finished\n");
9990 if (p
->sig
== SIG_FGC_CAMA
) {
9993 if (ast_safe_sleep(chan
,1000) == -1) {
9997 dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
9998 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_MF
| p
->dtmfrelax
);
9999 res
= my_getsigstr(chan
, anibuf
, "#", 10000);
10000 if ((res
> 0) && (strlen(anibuf
) > 2)) {
10001 if (anibuf
[strlen(anibuf
) - 1] == '#')
10002 anibuf
[strlen(anibuf
) - 1] = 0;
10003 ast_set_callerid(chan
, anibuf
+ 2, NULL
, anibuf
+ 2);
10005 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
10008 ast_copy_string(exten
, dtmfbuf
, sizeof(exten
));
10009 if (ast_strlen_zero(exten
))
10010 ast_copy_string(exten
, "s", sizeof(exten
));
10011 if (p
->sig
== SIG_FEATD
|| p
->sig
== SIG_EMWINK
) {
10012 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10013 if (exten
[0] == '*') {
10014 char *stringp
=NULL
;
10015 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10016 /* Parse out extension and callerid */
10018 s1
= strsep(&stringp
, "*");
10019 s2
= strsep(&stringp
, "*");
10021 if (!ast_strlen_zero(p
->cid_num
))
10022 ast_set_callerid(chan
, p
->cid_num
, NULL
, p
->cid_num
);
10024 ast_set_callerid(chan
, s1
, NULL
, s1
);
10025 ast_copy_string(exten
, s2
, sizeof(exten
));
10027 ast_copy_string(exten
, s1
, sizeof(exten
));
10028 } else if (p
->sig
== SIG_FEATD
)
10029 ast_log(LOG_WARNING
, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10031 if ((p
->sig
== SIG_FEATDMF
) || (p
->sig
== SIG_FEATDMF_TA
)) {
10032 if (exten
[0] == '*') {
10033 char *stringp
=NULL
;
10034 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10035 /* Parse out extension and callerid */
10037 s1
= strsep(&stringp
, "#");
10038 s2
= strsep(&stringp
, "#");
10040 if (!ast_strlen_zero(p
->cid_num
))
10041 ast_set_callerid(chan
, p
->cid_num
, NULL
, p
->cid_num
);
10044 ast_set_callerid(chan
, s1
+ 2, NULL
, s1
+ 2);
10045 ast_copy_string(exten
, s2
+ 1, sizeof(exten
));
10047 ast_copy_string(exten
, s1
+ 2, sizeof(exten
));
10049 ast_log(LOG_WARNING
, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10051 if ((p
->sig
== SIG_E911
) || (p
->sig
== SIG_FGC_CAMAMF
)) {
10052 if (exten
[0] == '*') {
10053 char *stringp
=NULL
;
10054 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10055 /* Parse out extension and callerid */
10057 s1
= strsep(&stringp
, "#");
10058 s2
= strsep(&stringp
, "#");
10059 if (s2
&& (*(s2
+ 1) == '0')) {
10061 ast_set_callerid(chan
, s2
+ 2, NULL
, s2
+ 2);
10063 if (s1
) ast_copy_string(exten
, s1
, sizeof(exten
));
10064 else ast_copy_string(exten
, "911", sizeof(exten
));
10066 ast_log(LOG_WARNING
, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10068 if (p
->sig
== SIG_FEATB
) {
10069 if (exten
[0] == '*') {
10070 char *stringp
=NULL
;
10071 ast_copy_string(exten2
, exten
, sizeof(exten2
));
10072 /* Parse out extension and callerid */
10074 s1
= strsep(&stringp
, "#");
10075 ast_copy_string(exten
, exten2
+ 1, sizeof(exten
));
10077 ast_log(LOG_WARNING
, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p
->channel
);
10079 if ((p
->sig
== SIG_FEATDMF
) || (p
->sig
== SIG_FEATDMF_TA
)) {
10080 dahdi_wink(p
, idx
);
10081 /* some switches require a minimum guard time between
10082 the last FGD wink and something that answers
10083 immediately. This ensures it */
10084 if (ast_safe_sleep(chan
, 100)) {
10089 dahdi_ec_enable(p
);
10090 if (NEED_MFDETECT(p
)) {
10092 if (!p
->hardwaredtmf
)
10093 ast_dsp_set_digitmode(p
->dsp
, DSP_DIGITMODE_DTMF
| p
->dtmfrelax
);
10095 ast_dsp_free(p
->dsp
);
10101 if (ast_exists_extension(chan
, ast_channel_context(chan
), exten
, 1,
10102 S_COR(ast_channel_caller(chan
)->id
.number
.valid
, ast_channel_caller(chan
)->id
.number
.str
, NULL
))) {
10103 ast_channel_exten_set(chan
, exten
);
10104 if (p
->dsp
) ast_dsp_digitreset(p
->dsp
);
10105 res
= ast_pbx_run(chan
);
10107 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
10108 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10112 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten
, ast_channel_context(chan
));
10114 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_INFO
);
10116 ast_log(LOG_WARNING
, "Unable to start special tone on %d\n", p
->channel
);
10119 res
= ast_streamfile(chan
, "ss-noservice", ast_channel_language(chan
));
10121 ast_waitstream(chan
, "");
10122 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10130 /* Read the first digit */
10131 timeout
= p
->firstdigit_timeout
;
10132 /* If starting a threeway call, never timeout on the first digit so someone
10133 can use flash-hook as a "hold" feature */
10134 if (p
->subs
[SUB_THREEWAY
].owner
)
10136 while (len
< AST_MAX_EXTENSION
-1) {
10137 int is_exten_parking
= 0;
10139 /* Read digit unless it's supposed to be immediate, in which case the
10140 only answer is 's' */
10144 res
= ast_waitfordigit(chan
, timeout
);
10147 ast_debug(1, "waitfordigit returned < 0...\n");
10148 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10152 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res
, res
, timeout
);
10156 if (!ast_ignore_pattern(ast_channel_context(chan
), exten
)) {
10157 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10159 tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALTONE
);
10161 if (ast_parking_provider_registered()) {
10162 is_exten_parking
= ast_parking_is_exten_park(ast_channel_context(chan
), exten
);
10164 if (ast_exists_extension(chan
, ast_channel_context(chan
), exten
, 1, p
->cid_num
) && !is_exten_parking
) {
10165 if (!res
|| !ast_matchmore_extension(chan
, ast_channel_context(chan
), exten
, 1, p
->cid_num
)) {
10167 /* Record this as the forwarding extension */
10168 ast_copy_string(p
->call_forward
, exten
, sizeof(p
->call_forward
));
10169 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p
->call_forward
, p
->channel
);
10170 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10174 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10176 memset(exten
, 0, sizeof(exten
));
10177 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALTONE
);
10181 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10182 ast_channel_lock(chan
);
10183 ast_channel_exten_set(chan
, exten
);
10184 if (!ast_strlen_zero(p
->cid_num
)) {
10185 if (!p
->hidecallerid
)
10186 ast_set_callerid(chan
, p
->cid_num
, NULL
, p
->cid_num
);
10188 ast_set_callerid(chan
, NULL
, NULL
, p
->cid_num
);
10190 if (!ast_strlen_zero(p
->cid_name
)) {
10191 if (!p
->hidecallerid
)
10192 ast_set_callerid(chan
, NULL
, p
->cid_name
, NULL
);
10194 ast_setstate(chan
, AST_STATE_RING
);
10195 ast_channel_unlock(chan
);
10196 dahdi_ec_enable(p
);
10197 res
= ast_pbx_run(chan
);
10199 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
10200 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10205 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10206 so just set the timeout to matchdigit_timeout and wait some more */
10207 timeout
= p
->matchdigit_timeout
;
10209 } else if (res
== 0) {
10210 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10211 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10212 dahdi_wait_event(p
->subs
[idx
].dfd
);
10215 } else if (p
->callwaiting
&& !strcmp(exten
, "*70")) {
10216 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan
));
10217 /* Disable call waiting if enabled */
10218 p
->callwaiting
= 0;
10219 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10221 ast_log(LOG_WARNING
, "Unable to do dial recall on channel %s: %s\n",
10222 ast_channel_name(chan
), strerror(errno
));
10225 ioctl(p
->subs
[idx
].dfd
,DAHDI_CONFDIAG
,&len
);
10226 memset(exten
, 0, sizeof(exten
));
10227 timeout
= p
->firstdigit_timeout
;
10229 } else if (!strcmp(exten
, pickupexten
)) {
10230 /* Scan all channels and see if there are any
10231 * ringing channels that have call groups
10232 * that equal this channels pickup group
10234 if (idx
== SUB_REAL
) {
10235 /* Switch us from Third call to Call Wait */
10236 if (p
->subs
[SUB_THREEWAY
].owner
) {
10237 /* If you make a threeway call and the *8# a call, it should actually
10238 look like a callwait */
10239 alloc_sub(p
, SUB_CALLWAIT
);
10240 swap_subs(p
, SUB_CALLWAIT
, SUB_THREEWAY
);
10241 unalloc_sub(p
, SUB_THREEWAY
);
10243 dahdi_ec_enable(p
);
10244 if (ast_pickup_call(chan
)) {
10245 ast_debug(1, "No call pickup possible...\n");
10246 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10247 dahdi_wait_event(p
->subs
[idx
].dfd
);
10252 ast_log(LOG_WARNING
, "Huh? Got *8# on call not on real\n");
10257 } else if (!p
->hidecallerid
&& !strcmp(exten
, "*67")) {
10258 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan
));
10259 /* Disable Caller*ID if enabled */
10260 p
->hidecallerid
= 1;
10261 ast_party_number_free(&ast_channel_caller(chan
)->id
.number
);
10262 ast_party_number_init(&ast_channel_caller(chan
)->id
.number
);
10263 ast_party_name_free(&ast_channel_caller(chan
)->id
.name
);
10264 ast_party_name_init(&ast_channel_caller(chan
)->id
.name
);
10265 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10267 ast_log(LOG_WARNING
, "Unable to do dial recall on channel %s: %s\n",
10268 ast_channel_name(chan
), strerror(errno
));
10271 memset(exten
, 0, sizeof(exten
));
10272 timeout
= p
->firstdigit_timeout
;
10273 } else if (p
->callreturn
&& !strcmp(exten
, "*69")) {
10274 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10276 } else if (!strcmp(exten
, "*78")) {
10278 /* Do not disturb */
10279 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10281 memset(exten
, 0, sizeof(exten
));
10283 } else if (!strcmp(exten
, "*79")) {
10285 /* Do not disturb */
10286 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10288 memset(exten
, 0, sizeof(exten
));
10290 } else if (p
->cancallforward
&& !strcmp(exten
, "*72")) {
10291 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10293 memset(exten
, 0, sizeof(exten
));
10295 } else if (p
->cancallforward
&& !strcmp(exten
, "*73")) {
10296 ast_verb(3, "Cancelling call forwarding on channel %d\n", p
->channel
);
10297 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10298 memset(p
->call_forward
, 0, sizeof(p
->call_forward
));
10300 memset(exten
, 0, sizeof(exten
));
10302 } else if ((p
->transfer
|| p
->canpark
) && is_exten_parking
10303 && p
->subs
[SUB_THREEWAY
].owner
) {
10304 struct ast_bridge_channel
*bridge_channel
;
10307 * This is a three way call, the main call being a real channel,
10308 * and we're parking the first call.
10310 ast_channel_lock(p
->subs
[SUB_THREEWAY
].owner
);
10311 bridge_channel
= ast_channel_get_bridge_channel(p
->subs
[SUB_THREEWAY
].owner
);
10312 ast_channel_unlock(p
->subs
[SUB_THREEWAY
].owner
);
10313 if (bridge_channel
) {
10314 if (!ast_parking_blind_transfer_park(bridge_channel
, ast_channel_context(chan
), exten
, NULL
, NULL
)) {
10316 * Swap things around between the three-way and real call so we
10317 * can hear where the channel got parked.
10319 ast_mutex_lock(&p
->lock
);
10320 p
->owner
= p
->subs
[SUB_THREEWAY
].owner
;
10321 swap_subs(p
, SUB_THREEWAY
, SUB_REAL
);
10322 ast_mutex_unlock(&p
->lock
);
10324 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan
));
10326 ao2_ref(bridge_channel
, -1);
10329 ao2_ref(bridge_channel
, -1);
10332 } else if (p
->hidecallerid
&& !strcmp(exten
, "*82")) {
10333 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan
));
10334 /* Enable Caller*ID if enabled */
10335 p
->hidecallerid
= 0;
10336 ast_set_callerid(chan
, p
->cid_num
, p
->cid_name
, NULL
);
10337 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_DIALRECALL
);
10339 ast_log(LOG_WARNING
, "Unable to do dial recall on channel %s: %s\n",
10340 ast_channel_name(chan
), strerror(errno
));
10343 memset(exten
, 0, sizeof(exten
));
10344 timeout
= p
->firstdigit_timeout
;
10345 } else if (!strcmp(exten
, "*0")) {
10346 struct ast_channel
*nbridge
=
10347 p
->subs
[SUB_THREEWAY
].owner
;
10348 struct dahdi_pvt
*pbridge
= NULL
;
10349 RAII_VAR(struct ast_channel
*, bridged
, nbridge
? ast_channel_bridge_peer(nbridge
) : NULL
, ast_channel_cleanup
);
10351 /* set up the private struct of the bridged one, if any */
10352 if (nbridge
&& bridged
) {
10353 pbridge
= ast_channel_tech_pvt(bridged
);
10355 if (nbridge
&& pbridge
&&
10356 (ast_channel_tech(nbridge
) == &dahdi_tech
) &&
10357 (ast_channel_tech(bridged
) == &dahdi_tech
) &&
10358 ISTRUNK(pbridge
)) {
10359 int func
= DAHDI_FLASH
;
10360 /* Clear out the dial buffer */
10361 p
->dop
.dialstr
[0] = '\0';
10362 /* flash hookswitch */
10363 if ((ioctl(pbridge
->subs
[SUB_REAL
].dfd
,DAHDI_HOOK
,&func
) == -1) && (errno
!= EINPROGRESS
)) {
10364 ast_log(LOG_WARNING
, "Unable to flash external trunk on channel %s: %s\n",
10365 ast_channel_name(nbridge
), strerror(errno
));
10367 swap_subs(p
, SUB_REAL
, SUB_THREEWAY
);
10368 unalloc_sub(p
, SUB_THREEWAY
);
10369 p
->owner
= p
->subs
[SUB_REAL
].owner
;
10370 ast_queue_unhold(p
->subs
[SUB_REAL
].owner
);
10374 tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10375 dahdi_wait_event(p
->subs
[idx
].dfd
);
10376 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10377 swap_subs(p
, SUB_REAL
, SUB_THREEWAY
);
10378 unalloc_sub(p
, SUB_THREEWAY
);
10379 p
->owner
= p
->subs
[SUB_REAL
].owner
;
10383 } else if (!ast_canmatch_extension(chan
, ast_channel_context(chan
), exten
, 1,
10384 S_COR(ast_channel_caller(chan
)->id
.number
.valid
, ast_channel_caller(chan
)->id
.number
.str
, NULL
))
10385 && !canmatch_featurecode(pickupexten
, exten
)) {
10386 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten
,
10387 S_COR(ast_channel_caller(chan
)->id
.number
.valid
, ast_channel_caller(chan
)->id
.number
.str
, "<Unknown Caller>"),
10388 ast_channel_context(chan
));
10392 timeout
= p
->interdigit_timeout
;
10393 if (len
&& !ast_ignore_pattern(ast_channel_context(chan
), exten
))
10394 tone_zone_play_tone(p
->subs
[idx
].dfd
, -1);
10400 /* check for SMDI messages */
10401 if (p
->use_smdi
&& p
->smdi_iface
) {
10402 smdi_msg
= ast_smdi_md_message_wait(p
->smdi_iface
, SMDI_MD_WAIT_TIMEOUT
);
10404 if (smdi_msg
!= NULL
) {
10405 ast_channel_exten_set(chan
, smdi_msg
->fwd_st
);
10407 if (smdi_msg
->type
== 'B')
10408 pbx_builtin_setvar_helper(chan
, "_SMDI_VM_TYPE", "b");
10409 else if (smdi_msg
->type
== 'N')
10410 pbx_builtin_setvar_helper(chan
, "_SMDI_VM_TYPE", "u");
10412 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan
));
10414 ast_log(LOG_WARNING
, "SMDI enabled but no SMDI message present\n");
10418 if (p
->use_callerid
&& (p
->cid_signalling
== CID_SIG_SMDI
&& smdi_msg
)) {
10419 number
= smdi_msg
->calling_st
;
10421 /* If we want caller id, we're in a prering state due to a polarity reversal
10422 * and we're set to use a polarity reversal to trigger the start of caller id,
10423 * grab the caller id and wait for ringing to start... */
10424 } else if (p
->use_callerid
&& (ast_channel_state(chan
) == AST_STATE_PRERING
&&
10425 (p
->cid_start
== CID_START_POLARITY
|| p
->cid_start
== CID_START_POLARITY_IN
|| p
->cid_start
== CID_START_DTMF_NOALERT
))) {
10426 /* If set to use DTMF CID signalling, listen for DTMF */
10427 if (p
->cid_signalling
== CID_SIG_DTMF
) {
10430 struct timeval start
= ast_tvnow();
10433 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan
));
10434 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10436 * We are the only party interested in the Rx stream since
10437 * we have not answered yet. We don't need or even want DTMF
10438 * emulation. The DTMF digits can come so fast that emulation
10439 * can drop some of them.
10441 ast_channel_lock(chan
);
10442 ast_set_flag(ast_channel_flags(chan
), AST_FLAG_END_DTMF_ONLY
);
10443 ast_channel_unlock(chan
);
10444 off_ms
= 4000;/* This is a typical OFF time between rings. */
10446 struct ast_frame
*f
;
10448 ms
= ast_remaining_ms(start
, off_ms
);
10449 res
= ast_waitfor(chan
, ms
);
10452 * We do not need to restore the dahdi_setlinear()
10453 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10454 * are hanging up the channel.
10456 ast_log(LOG_WARNING
, "DTMFCID timed out waiting for ring. "
10457 "Exiting simple switch\n");
10461 f
= ast_read(chan
);
10464 if (f
->frametype
== AST_FRAME_DTMF
) {
10465 if (k
< ARRAY_LEN(dtmfbuf
) - 1) {
10466 dtmfbuf
[k
++] = f
->subclass
.integer
;
10468 ast_debug(1, "CID got digit '%c'\n", f
->subclass
.integer
);
10469 start
= ast_tvnow();
10472 if (ast_channel_state(chan
) == AST_STATE_RING
||
10473 ast_channel_state(chan
) == AST_STATE_RINGING
)
10474 break; /* Got ring */
10476 ast_channel_lock(chan
);
10477 ast_clear_flag(ast_channel_flags(chan
), AST_FLAG_END_DTMF_ONLY
);
10478 ast_channel_unlock(chan
);
10480 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10481 /* Got cid and ring. */
10482 ast_debug(1, "CID got string '%s'\n", dtmfbuf
);
10483 callerid_get_dtmf(dtmfbuf
, dtmfcid
, &flags
);
10484 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid
, flags
);
10485 /* If first byte is NULL, we have no cid */
10486 if (!ast_strlen_zero(dtmfcid
))
10490 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10491 } else if ((p
->cid_signalling
== CID_SIG_V23
) || (p
->cid_signalling
== CID_SIG_V23_JP
)) {
10492 cs
= callerid_new(p
->cid_signalling
);
10495 struct timeval start
;
10501 /* Take out of linear mode for Caller*ID processing */
10502 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10504 /* First we wait and listen for the Caller*ID */
10506 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10507 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10508 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10513 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10514 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10515 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10516 if (res
== DAHDI_EVENT_NOALARM
) {
10520 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
10521 if (res
== DAHDI_EVENT_RINGBEGIN
) {
10522 res
= dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
10529 } else if (i
& DAHDI_IOMUX_READ
) {
10530 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10532 if (errno
!= ELAST
) {
10533 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10542 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
10543 res
= callerid_feed_jp(cs
, buf
, res
, AST_LAW(p
));
10545 res
= callerid_feed(cs
, buf
, res
, AST_LAW(p
));
10549 * The previous diagnostic message output likely
10550 * explains why it failed.
10552 ast_log(LOG_WARNING
,
10553 "Failed to decode CallerID on channel '%s'\n",
10554 ast_channel_name(chan
));
10558 else if (samples
> (8000 * 10))
10563 callerid_get(cs
, &name
, &number
, &flags
);
10564 ast_log(LOG_NOTICE
, "CallerID number: %s, name: %s, flags=%d\n", number
, name
, flags
);
10567 if (p
->cid_signalling
== CID_SIG_V23_JP
) {
10568 res
= dahdi_set_hook(p
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
10572 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10573 start
= ast_tvnow();
10574 off_ms
= 4000;/* This is a typical OFF time between rings. */
10576 struct ast_frame
*f
;
10578 ms
= ast_remaining_ms(start
, off_ms
);
10579 res
= ast_waitfor(chan
, ms
);
10581 ast_log(LOG_WARNING
, "CID timed out waiting for ring. "
10582 "Exiting simple switch\n");
10586 if (!(f
= ast_read(chan
))) {
10587 ast_log(LOG_WARNING
, "Hangup received waiting for ring. Exiting simple switch\n");
10592 if (ast_channel_state(chan
) == AST_STATE_RING
||
10593 ast_channel_state(chan
) == AST_STATE_RINGING
)
10594 break; /* Got ring */
10597 /* We must have a ring by now, so, if configured, lets try to listen for
10598 * distinctive ringing */
10599 if (p
->usedistinctiveringdetection
) {
10602 /* Clear the current ring data array so we don't have old data in it. */
10603 for (receivedRingT
= 0; receivedRingT
< ARRAY_LEN(curRingData
); receivedRingT
++)
10604 curRingData
[receivedRingT
] = 0;
10608 /* Check to see if context is what it should be, if not set to be. */
10609 if (strcmp(p
->context
,p
->defcontext
) != 0) {
10610 ast_copy_string(p
->context
, p
->defcontext
, sizeof(p
->context
));
10611 ast_channel_context_set(chan
, p
->defcontext
);
10615 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10616 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10617 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10622 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10623 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10624 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10625 if (res
== DAHDI_EVENT_NOALARM
) {
10629 /* Let us detect distinctive ring */
10631 curRingData
[receivedRingT
] = p
->ringt
;
10633 if (p
->ringt
< p
->ringt_base
/2)
10635 /* Increment the ringT counter so we can match it against
10636 values in chan_dahdi.conf for distinctive ring */
10637 if (++receivedRingT
== ARRAY_LEN(curRingData
))
10639 } else if (i
& DAHDI_IOMUX_READ
) {
10640 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10642 if (errno
!= ELAST
) {
10643 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10650 if (p
->ringt
> 0) {
10651 if (!(--p
->ringt
)) {
10658 /* this only shows up if you have n of the dring patterns filled in */
10659 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData
[0],curRingData
[1],curRingData
[2]);
10660 for (counter
= 0; counter
< 3; counter
++) {
10661 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10664 for (counter1
= 0; counter1
< 3; counter1
++) {
10665 ast_verb(3, "Ring pattern check range: %d\n", p
->drings
.ringnum
[counter
].range
);
10666 if (p
->drings
.ringnum
[counter
].ring
[counter1
] == -1) {
10667 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10668 curRingData
[counter1
]);
10670 } else if (curRingData
[counter1
] <= (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
) &&
10671 curRingData
[counter1
] >= (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
)) {
10672 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10673 (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
),
10674 (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
));
10679 if (distMatches
== 3) {
10680 /* The ring matches, set the context to whatever is for distinctive ring.. */
10681 ast_copy_string(p
->context
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
), sizeof(p
->context
));
10682 ast_channel_context_set(chan
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
));
10683 ast_verb(3, "Distinctive Ring matched context %s\n",p
->context
);
10688 /* Restore linear mode (if appropriate) for Caller*ID processing */
10689 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10694 ast_log(LOG_WARNING
, "Unable to get caller ID space\n");
10696 ast_log(LOG_WARNING
, "Channel %s in prering "
10697 "state, but I have nothing to do. "
10698 "Terminating simple switch, should be "
10699 "restarted by the actual ring.\n",
10700 ast_channel_name(chan
));
10704 } else if (p
->use_callerid
&& p
->cid_start
== CID_START_RING
) {
10705 if (p
->cid_signalling
== CID_SIG_DTMF
) {
10708 struct timeval start
;
10711 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10713 start
= ast_tvnow();
10715 struct ast_frame
*f
;
10717 ms
= ast_remaining_ms(start
, off_ms
);
10718 res
= ast_waitfor(chan
, ms
);
10720 ast_log(LOG_WARNING
, "DTMFCID timed out waiting for ring. "
10721 "Exiting simple switch\n");
10725 f
= ast_read(chan
);
10727 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10731 if (f
->frametype
== AST_FRAME_DTMF
) {
10732 dtmfbuf
[k
++] = f
->subclass
.integer
;
10733 ast_debug(1, "CID got digit '%c'\n", f
->subclass
.integer
);
10734 start
= ast_tvnow();
10738 if (p
->ringt_base
== p
->ringt
)
10742 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10743 /* Got cid and ring. */
10744 callerid_get_dtmf(dtmfbuf
, dtmfcid
, &flags
);
10745 ast_debug(1, "CID is '%s', flags %d\n",
10747 /* If first byte is NULL, we have no cid */
10748 if (!ast_strlen_zero(dtmfcid
))
10752 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10754 /* FSK Bell202 callerID */
10755 cs
= callerid_new(p
->cid_signalling
);
10763 /* Clear the current ring data array so we don't have old data in it. */
10764 for (receivedRingT
= 0; receivedRingT
< ARRAY_LEN(curRingData
); receivedRingT
++)
10765 curRingData
[receivedRingT
] = 0;
10769 /* Check to see if context is what it should be, if not set to be. */
10770 if (strcmp(p
->context
,p
->defcontext
) != 0) {
10771 ast_copy_string(p
->context
, p
->defcontext
, sizeof(p
->context
));
10772 ast_channel_context_set(chan
, p
->defcontext
);
10775 /* Take out of linear mode for Caller*ID processing */
10776 dahdi_setlinear(p
->subs
[idx
].dfd
, 0);
10778 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10779 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10780 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10785 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10786 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10787 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10788 if (res
== DAHDI_EVENT_NOALARM
) {
10791 /* If we get a PR event, they hung up while processing calerid */
10792 if ( res
== DAHDI_EVENT_POLARITY
&& p
->hanguponpolarityswitch
&& p
->polarity
== POLARITY_REV
) {
10793 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p
->channel
);
10794 p
->polarity
= POLARITY_IDLE
;
10800 /* Let us detect callerid when the telco uses distinctive ring */
10802 curRingData
[receivedRingT
] = p
->ringt
;
10804 if (p
->ringt
< p
->ringt_base
/2)
10806 /* Increment the ringT counter so we can match it against
10807 values in chan_dahdi.conf for distinctive ring */
10808 if (++receivedRingT
== ARRAY_LEN(curRingData
))
10810 } else if (i
& DAHDI_IOMUX_READ
) {
10811 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10813 if (errno
!= ELAST
) {
10814 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10821 if (p
->ringt
> 0) {
10822 if (!(--p
->ringt
)) {
10828 res
= callerid_feed(cs
, buf
, res
, AST_LAW(p
));
10831 * The previous diagnostic message output likely
10832 * explains why it failed.
10834 ast_log(LOG_WARNING
,
10835 "Failed to decode CallerID on channel '%s'\n",
10836 ast_channel_name(chan
));
10840 else if (samples
> (8000 * 10))
10845 callerid_get(cs
, &name
, &number
, &flags
);
10846 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number
, name
, flags
);
10848 if (distinctiveringaftercid
== 1) {
10849 /* Clear the current ring data array so we don't have old data in it. */
10850 for (receivedRingT
= 0; receivedRingT
< 3; receivedRingT
++) {
10851 curRingData
[receivedRingT
] = 0;
10854 ast_verb(3, "Detecting post-CID distinctive ring\n");
10856 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
10857 if ((res
= ioctl(p
->subs
[idx
].dfd
, DAHDI_IOMUX
, &i
))) {
10858 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
10863 if (i
& DAHDI_IOMUX_SIGEVENT
) {
10864 res
= dahdi_get_event(p
->subs
[idx
].dfd
);
10865 ast_log(LOG_NOTICE
, "Got event %d (%s)...\n", res
, event2str(res
));
10866 if (res
== DAHDI_EVENT_NOALARM
) {
10870 /* Let us detect callerid when the telco uses distinctive ring */
10872 curRingData
[receivedRingT
] = p
->ringt
;
10874 if (p
->ringt
< p
->ringt_base
/2)
10876 /* Increment the ringT counter so we can match it against
10877 values in chan_dahdi.conf for distinctive ring */
10878 if (++receivedRingT
== ARRAY_LEN(curRingData
))
10880 } else if (i
& DAHDI_IOMUX_READ
) {
10881 res
= read(p
->subs
[idx
].dfd
, buf
, sizeof(buf
));
10883 if (errno
!= ELAST
) {
10884 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
10891 if (p
->ringt
> 0) {
10892 if (!(--p
->ringt
)) {
10900 if (p
->usedistinctiveringdetection
) {
10901 /* this only shows up if you have n of the dring patterns filled in */
10902 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData
[0],curRingData
[1],curRingData
[2]);
10904 for (counter
= 0; counter
< 3; counter
++) {
10905 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10907 /* this only shows up if you have n of the dring patterns filled in */
10908 ast_verb(3, "Checking %d,%d,%d\n",
10909 p
->drings
.ringnum
[counter
].ring
[0],
10910 p
->drings
.ringnum
[counter
].ring
[1],
10911 p
->drings
.ringnum
[counter
].ring
[2]);
10913 for (counter1
= 0; counter1
< 3; counter1
++) {
10914 ast_verb(3, "Ring pattern check range: %d\n", p
->drings
.ringnum
[counter
].range
);
10915 if (p
->drings
.ringnum
[counter
].ring
[counter1
] == -1) {
10916 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10917 curRingData
[counter1
]);
10920 else if (curRingData
[counter1
] <= (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
) &&
10921 curRingData
[counter1
] >= (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
)) {
10922 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10923 (p
->drings
.ringnum
[counter
].ring
[counter1
] - p
->drings
.ringnum
[counter
].range
),
10924 (p
->drings
.ringnum
[counter
].ring
[counter1
] + p
->drings
.ringnum
[counter
].range
));
10928 if (distMatches
== 3) {
10929 /* The ring matches, set the context to whatever is for distinctive ring.. */
10930 ast_copy_string(p
->context
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
), sizeof(p
->context
));
10931 ast_channel_context_set(chan
, S_OR(p
->drings
.ringContext
[counter
].contextData
, p
->defcontext
));
10932 ast_verb(3, "Distinctive Ring matched context %s\n",p
->context
);
10937 /* Restore linear mode (if appropriate) for Caller*ID processing */
10938 dahdi_setlinear(p
->subs
[idx
].dfd
, p
->subs
[idx
].linear
);
10943 ast_log(LOG_WARNING
, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan
));
10946 ast_log(LOG_WARNING
, "Unable to get caller ID space\n");
10952 ast_shrink_phone_number(number
);
10953 ast_set_callerid(chan
, number
, name
, number
);
10955 ao2_cleanup(smdi_msg
);
10960 my_handle_notify_message(chan
, p
, flags
, -1);
10962 ast_channel_lock(chan
);
10963 ast_setstate(chan
, AST_STATE_RING
);
10964 ast_channel_rings_set(chan
, 1);
10965 ast_channel_unlock(chan
);
10966 p
->ringt
= p
->ringt_base
;
10967 res
= ast_pbx_run(chan
);
10970 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
10974 ast_log(LOG_WARNING
, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p
->sig
), p
->channel
);
10975 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10977 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", p
->channel
);
10979 res
= tone_zone_play_tone(p
->subs
[idx
].dfd
, DAHDI_TONE_CONGESTION
);
10981 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", p
->channel
);
10984 ast_mutex_lock(&ss_thread_lock
);
10986 ast_cond_signal(&ss_thread_complete
);
10987 ast_mutex_unlock(&ss_thread_lock
);
10991 struct mwi_thread_data
{
10992 struct dahdi_pvt
*pvt
;
10993 unsigned char buf
[READ_SIZE
];
10997 static int calc_energy(const unsigned char *buf
, int len
, struct ast_format
*law
)
11005 for (x
= 0; x
< len
; x
++)
11006 sum
+= abs(law
== ast_format_ulaw
? AST_MULAW(buf
[x
]) : AST_ALAW(buf
[x
]));
11011 static void *mwi_thread(void *data
)
11013 struct mwi_thread_data
*mtd
= data
;
11014 struct callerid_state
*cs
;
11015 pthread_t threadid
;
11017 char *name
, *number
;
11020 unsigned int spill_done
= 0;
11021 int spill_result
= -1;
11023 if (!(cs
= callerid_new(mtd
->pvt
->cid_signalling
))) {
11024 goto quit_no_clean
;
11027 callerid_feed(cs
, mtd
->buf
, mtd
->len
, AST_LAW(mtd
->pvt
));
11029 bump_gains(mtd
->pvt
);
11032 i
= DAHDI_IOMUX_READ
| DAHDI_IOMUX_SIGEVENT
;
11033 if ((res
= ioctl(mtd
->pvt
->subs
[SUB_REAL
].dfd
, DAHDI_IOMUX
, &i
))) {
11034 ast_log(LOG_WARNING
, "I/O MUX failed: %s\n", strerror(errno
));
11038 if (i
& DAHDI_IOMUX_SIGEVENT
) {
11039 struct ast_channel
*chan
;
11040 ast_callid callid
= 0;
11041 int callid_created
;
11043 /* If we get an event, screen out events that we do not act on.
11044 * Otherwise, cancel and go to the simple switch to let it deal with it.
11046 res
= dahdi_get_event(mtd
->pvt
->subs
[SUB_REAL
].dfd
);
11049 case DAHDI_EVENT_NEONMWI_ACTIVE
:
11050 case DAHDI_EVENT_NEONMWI_INACTIVE
:
11051 case DAHDI_EVENT_NONE
:
11052 case DAHDI_EVENT_BITSCHANGED
:
11054 case DAHDI_EVENT_NOALARM
:
11055 if (dahdi_analog_lib_handles(mtd
->pvt
->sig
, mtd
->pvt
->radio
, mtd
->pvt
->oprmode
)) {
11056 struct analog_pvt
*analog_p
= mtd
->pvt
->sig_pvt
;
11058 analog_p
->inalarm
= 0;
11060 mtd
->pvt
->inalarm
= 0;
11061 handle_clear_alarms(mtd
->pvt
);
11063 case DAHDI_EVENT_ALARM
:
11064 if (dahdi_analog_lib_handles(mtd
->pvt
->sig
, mtd
->pvt
->radio
, mtd
->pvt
->oprmode
)) {
11065 struct analog_pvt
*analog_p
= mtd
->pvt
->sig_pvt
;
11067 analog_p
->inalarm
= 1;
11069 mtd
->pvt
->inalarm
= 1;
11070 res
= get_alarms(mtd
->pvt
);
11071 handle_alarms(mtd
->pvt
, res
);
11072 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11074 callid_created
= ast_callid_threadstorage_auto(&callid
);
11075 ast_log(LOG_NOTICE
, "Got event %d (%s)... Passing along to analog_ss_thread\n", res
, event2str(res
));
11078 restore_gains(mtd
->pvt
);
11079 mtd
->pvt
->ringt
= mtd
->pvt
->ringt_base
;
11081 if ((chan
= dahdi_new(mtd
->pvt
, AST_STATE_RING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
))) {
11084 if (dahdi_analog_lib_handles(mtd
->pvt
->sig
, mtd
->pvt
->radio
, mtd
->pvt
->oprmode
)) {
11085 result
= analog_ss_thread_start(mtd
->pvt
->sig_pvt
, chan
);
11087 result
= ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
);
11090 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", mtd
->pvt
->channel
);
11091 res
= tone_zone_play_tone(mtd
->pvt
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11093 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", mtd
->pvt
->channel
);
11097 ast_log(LOG_WARNING
, "Could not create channel to handle call\n");
11100 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11101 goto quit_no_clean
;
11103 } else if (i
& DAHDI_IOMUX_READ
) {
11104 if ((res
= read(mtd
->pvt
->subs
[SUB_REAL
].dfd
, mtd
->buf
, sizeof(mtd
->buf
))) < 0) {
11105 if (errno
!= ELAST
) {
11106 ast_log(LOG_WARNING
, "read returned error: %s\n", strerror(errno
));
11113 if ((spill_result
= callerid_feed(cs
, mtd
->buf
, res
, AST_LAW(mtd
->pvt
))) < 0) {
11115 * The previous diagnostic message output likely
11116 * explains why it failed.
11118 ast_log(LOG_WARNING
, "Failed to decode CallerID\n");
11120 } else if (spill_result
) {
11124 /* keep reading data until the energy level drops below the threshold
11125 so we don't get another 'trigger' on the remaining carrier signal
11127 if (calc_energy(mtd
->buf
, res
, AST_LAW(mtd
->pvt
)) <= mwilevel
)
11130 if (samples
> (8000 * 4)) /*Termination case - time to give up*/
11135 if (spill_result
== 1) {
11136 callerid_get(cs
, &name
, &number
, &flags
);
11137 if (flags
& CID_MSGWAITING
) {
11138 ast_log(LOG_NOTICE
, "mwi: Have Messages on channel %d\n", mtd
->pvt
->channel
);
11139 notify_message(mtd
->pvt
->mailbox
, 1);
11140 } else if (flags
& CID_NOMSGWAITING
) {
11141 ast_log(LOG_NOTICE
, "mwi: No Messages on channel %d\n", mtd
->pvt
->channel
);
11142 notify_message(mtd
->pvt
->mailbox
, 0);
11144 ast_log(LOG_NOTICE
, "mwi: Status unknown on channel %d\n", mtd
->pvt
->channel
);
11152 restore_gains(mtd
->pvt
);
11155 mtd
->pvt
->mwimonitoractive
= 0;
11162 * The following three functions (mwi_send_init, mwi_send_process_buffer,
11163 * mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11164 * that are sent out via FXS port on voicemail state change. The execution of
11165 * the mwi send is state driven and can either generate a ring pulse prior to
11166 * sending the fsk spill or simply send an fsk spill.
11168 static int mwi_send_init(struct dahdi_pvt
* pvt
)
11172 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11173 /* Determine how this spill is to be sent */
11174 if (pvt
->mwisend_rpas
) {
11175 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SA
;
11176 pvt
->mwisendactive
= 1;
11177 } else if (pvt
->mwisend_fsk
) {
11178 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SPILL
;
11179 pvt
->mwisendactive
= 1;
11181 pvt
->mwisendactive
= 0;
11185 if (mwisend_rpas
) {
11186 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SA
;
11188 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SPILL
;
11190 pvt
->mwisendactive
= 1;
11193 if (pvt
->cidspill
) {
11194 ast_log(LOG_WARNING
, "cidspill already exists when trying to send FSK MWI\n");
11195 ast_free(pvt
->cidspill
);
11196 pvt
->cidspill
= NULL
;
11200 pvt
->cidspill
= ast_calloc(1, MAX_CALLERID_SIZE
);
11201 if (!pvt
->cidspill
) {
11202 pvt
->mwisendactive
= 0;
11205 x
= DAHDI_FLUSH_BOTH
;
11206 ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_FLUSH
, &x
);
11208 ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOKTRANSFER
, &x
);
11209 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11210 if (pvt
->mwisend_fsk
) {
11212 pvt
->cidlen
= ast_callerid_vmwi_generate(pvt
->cidspill
, has_voicemail(pvt
),
11213 CID_MWI_TYPE_MDMF_FULL
, AST_LAW(pvt
), pvt
->cid_name
, pvt
->cid_num
, 0);
11215 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11221 static int mwi_send_process_buffer(struct dahdi_pvt
* pvt
, int num_read
)
11223 struct timeval now
;
11226 /* sanity check to catch if this had been interrupted previously
11227 * i.e. state says there is more to do but there is no spill allocated
11229 if (MWI_SEND_DONE
!= pvt
->mwisend_data
.mwisend_current
&& !pvt
->cidspill
) {
11230 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11231 } else if (MWI_SEND_DONE
!= pvt
->mwisend_data
.mwisend_current
) {
11232 /* Normal processing -- Perform mwi send action */
11233 switch ( pvt
->mwisend_data
.mwisend_current
) {
11235 /* Send the Ring Pulse Signal Alert */
11236 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_SETCADENCE
, &AS_RP_cadence
);
11238 ast_log(LOG_WARNING
, "Unable to set RP-AS ring cadence: %s\n", strerror(errno
));
11241 res
= dahdi_set_hook(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_RING
);
11242 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SA_WAIT
;
11244 case MWI_SEND_SA_WAIT
: /* do nothing until I get RINGEROFF event */
11246 case MWI_SEND_PAUSE
: /* Wait between alert and spill - min of 500 mS*/
11247 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11248 if (pvt
->mwisend_fsk
) {
11250 gettimeofday(&now
, NULL
);
11251 if ((int)(now
.tv_sec
- pvt
->mwisend_data
.pause
.tv_sec
) * 1000000 + (int)now
.tv_usec
- (int)pvt
->mwisend_data
.pause
.tv_usec
> 500000) {
11252 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_SPILL
;
11254 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11255 } else { /* support for mwisendtype=nofsk */
11256 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_CLEANUP
;
11260 case MWI_SEND_SPILL
:
11261 /* We read some number of bytes. Write an equal amount of data */
11262 if (0 < num_read
) {
11263 if (num_read
> pvt
->cidlen
- pvt
->cidpos
) {
11264 num_read
= pvt
->cidlen
- pvt
->cidpos
;
11266 res
= write(pvt
->subs
[SUB_REAL
].dfd
, pvt
->cidspill
+ pvt
->cidpos
, num_read
);
11268 pvt
->cidpos
+= res
;
11269 if (pvt
->cidpos
>= pvt
->cidlen
) {
11270 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_CLEANUP
;
11273 ast_log(LOG_WARNING
, "MWI FSK Send Write failed: %s\n", strerror(errno
));
11278 case MWI_SEND_CLEANUP
:
11279 /* For now, do nothing */
11280 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11283 /* Should not get here, punt*/
11288 if (MWI_SEND_DONE
== pvt
->mwisend_data
.mwisend_current
) {
11289 if (pvt
->cidspill
) {
11290 ast_free(pvt
->cidspill
);
11291 pvt
->cidspill
= NULL
;
11295 pvt
->mwisendactive
= 0;
11299 if (pvt
->cidspill
) {
11300 ast_free(pvt
->cidspill
);
11301 pvt
->cidspill
= NULL
;
11305 pvt
->mwisendactive
= 0;
11309 static int mwi_send_process_event(struct dahdi_pvt
* pvt
, int event
)
11313 if (MWI_SEND_DONE
!= pvt
->mwisend_data
.mwisend_current
) {
11315 case DAHDI_EVENT_RINGEROFF
:
11316 if (pvt
->mwisend_data
.mwisend_current
== MWI_SEND_SA_WAIT
) {
11319 if (dahdi_set_hook(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_RINGOFF
) ) {
11320 ast_log(LOG_WARNING
, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno
));
11321 ast_free(pvt
->cidspill
);
11322 pvt
->cidspill
= NULL
;
11323 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11324 pvt
->mwisendactive
= 0;
11326 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_PAUSE
;
11327 gettimeofday(&pvt
->mwisend_data
.pause
, NULL
);
11331 /* Going off hook, I need to punt this spill */
11332 case DAHDI_EVENT_RINGOFFHOOK
:
11333 if (pvt
->cidspill
) {
11334 ast_free(pvt
->cidspill
);
11335 pvt
->cidspill
= NULL
;
11339 pvt
->mwisend_data
.mwisend_current
= MWI_SEND_DONE
;
11340 pvt
->mwisendactive
= 0;
11342 case DAHDI_EVENT_RINGERON
:
11343 case DAHDI_EVENT_HOOKCOMPLETE
:
11352 /* destroy a range DAHDI channels, identified by their number */
11353 static void dahdi_destroy_channel_range(int start
, int end
)
11355 struct dahdi_pvt
*cur
;
11356 struct dahdi_pvt
*next
;
11357 int destroyed_first
= 0;
11358 int destroyed_last
= 0;
11360 ast_mutex_lock(&iflock
);
11361 ast_debug(1, "range: %d-%d\n", start
, end
);
11362 for (cur
= iflist
; cur
; cur
= next
) {
11364 if (cur
->channel
>= start
&& cur
->channel
<= end
) {
11365 int x
= DAHDI_FLASH
;
11367 if (cur
->channel
> destroyed_last
) {
11368 destroyed_last
= cur
->channel
;
11370 if (destroyed_first
< 1 || cur
->channel
< destroyed_first
) {
11371 destroyed_first
= cur
->channel
;
11373 ast_debug(3, "Destroying %d\n", cur
->channel
);
11374 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11375 ioctl(cur
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
11377 destroy_channel(cur
, 1);
11378 ast_module_unref(ast_module_info
->self
);
11381 ast_mutex_unlock(&iflock
);
11382 if (destroyed_first
> start
|| destroyed_last
< end
) {
11383 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11384 start
, end
, destroyed_first
, destroyed_last
);
11389 static void dahdi_r2_destroy_nodev(void)
11391 struct r2link_entry
*cur
;
11392 AST_LIST_LOCK(&nodev_r2links
);
11393 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links
, cur
, list
) {
11395 struct dahdi_mfcr2
*r2
= &cur
->mfcr2
;
11396 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2
->numchans
);
11397 for (i
= 0; i
< r2
->numchans
; i
++) {
11399 struct dahdi_pvt
*pvt
= r2
->pvts
[i
];
11403 channel
= pvt
->channel
;
11404 ast_debug(3, "About to destroy B-channel %d.\n", channel
);
11405 dahdi_destroy_channel_range(channel
, channel
);
11407 ast_debug(3, "Destroying R2 link\n");
11408 AST_LIST_REMOVE(&nodev_r2links
, cur
, list
);
11409 if (r2
->r2master
!= AST_PTHREADT_NULL
) {
11410 pthread_cancel(r2
->r2master
);
11411 pthread_join(r2
->r2master
, NULL
);
11412 r2
->r2master
= AST_PTHREADT_NULL
;
11413 openr2_context_delete(r2
->protocol_context
);
11417 AST_LIST_TRAVERSE_SAFE_END
;
11418 AST_LIST_UNLOCK(&nodev_r2links
);
11422 static int setup_dahdi(int reload
);
11423 static int setup_dahdi_int(int reload
, struct dahdi_chan_conf
*default_conf
, struct dahdi_chan_conf
*base_conf
, struct dahdi_chan_conf
*conf
);
11427 * \brief create a range of new DAHDI channels
11429 * \param start first channel in the range
11430 * \param end last channel in the range
11432 * \retval RESULT_SUCCESS on success.
11433 * \retval RESULT_FAILURE on error.
11435 static int dahdi_create_channel_range(int start
, int end
)
11437 struct dahdi_pvt
*cur
;
11438 struct dahdi_chan_conf default_conf
= dahdi_chan_conf_default();
11439 struct dahdi_chan_conf base_conf
= dahdi_chan_conf_default();
11440 struct dahdi_chan_conf conf
= dahdi_chan_conf_default();
11441 int ret
= RESULT_FAILURE
; /* be pessimistic */
11443 ast_debug(1, "channel range caps: %d - %d\n", start
, end
);
11444 ast_mutex_lock(&iflock
);
11445 for (cur
= iflist
; cur
; cur
= cur
->next
) {
11446 if (cur
->channel
>= start
&& cur
->channel
<= end
) {
11448 "channel range %d-%d is occupied\n",
11456 for (x
= 0; x
< NUM_SPANS
; x
++) {
11457 struct dahdi_pri
*pri
= pris
+ x
;
11459 if (!pris
[x
].pri
.pvts
[0]) {
11462 for (i
= 0; i
< SIG_PRI_NUM_DCHANS
; i
++) {
11463 int channo
= pri
->dchannels
[i
];
11468 if (!pri
->pri
.fds
[i
]) {
11471 if (channo
>= start
&& channo
<= end
) {
11473 "channel range %d-%d is occupied by span %d\n",
11474 start
, end
, x
+ 1);
11481 if (!default_conf
.chan
.cc_params
|| !base_conf
.chan
.cc_params
||
11482 !conf
.chan
.cc_params
) {
11485 default_conf
.wanted_channels_start
= start
;
11486 base_conf
.wanted_channels_start
= start
;
11487 conf
.wanted_channels_start
= start
;
11488 default_conf
.wanted_channels_end
= end
;
11489 base_conf
.wanted_channels_end
= end
;
11490 conf
.wanted_channels_end
= end
;
11491 if (setup_dahdi_int(0, &default_conf
, &base_conf
, &conf
) == 0) {
11492 ret
= RESULT_SUCCESS
;
11495 ast_cc_config_params_destroy(default_conf
.chan
.cc_params
);
11496 ast_cc_config_params_destroy(base_conf
.chan
.cc_params
);
11497 ast_cc_config_params_destroy(conf
.chan
.cc_params
);
11498 ast_mutex_unlock(&iflock
);
11503 static struct dahdi_pvt
*handle_init_event(struct dahdi_pvt
*i
, int event
)
11506 pthread_t threadid
;
11507 struct ast_channel
*chan
;
11508 ast_callid callid
= 0;
11509 int callid_created
;
11511 /* Handle an event on a given channel for the monitor thread. */
11514 case DAHDI_EVENT_NONE
:
11515 case DAHDI_EVENT_BITSCHANGED
:
11517 case DAHDI_EVENT_WINKFLASH
:
11518 case DAHDI_EVENT_RINGOFFHOOK
:
11519 if (i
->inalarm
) break;
11520 if (i
->radio
) break;
11521 /* Got a ring/answer. What kind of channel are we? */
11526 res
= dahdi_set_hook(i
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
11527 if (res
&& (errno
== EBUSY
)) {
11531 callid_created
= ast_callid_threadstorage_auto(&callid
);
11533 /* Cancel VMWI spill */
11534 ast_free(i
->cidspill
);
11535 i
->cidspill
= NULL
;
11536 restore_conference(i
);
11538 if (i
->immediate
) {
11539 dahdi_ec_enable(i
);
11540 /* The channel is immediately up. Start right away */
11541 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_RINGTONE
);
11542 chan
= dahdi_new(i
, AST_STATE_RING
, 1, SUB_REAL
, 0, NULL
, NULL
, callid
);
11544 ast_log(LOG_WARNING
, "Unable to start PBX on channel %d\n", i
->channel
);
11545 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11547 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11550 /* Check for callerid, digits, etc */
11551 chan
= dahdi_new(i
, AST_STATE_RESERVED
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11553 if (has_voicemail(i
))
11554 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_STUTTER
);
11556 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_DIALTONE
);
11558 ast_log(LOG_WARNING
, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i
->channel
);
11559 if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
11560 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
11561 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11563 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11567 ast_log(LOG_WARNING
, "Unable to create channel\n");
11570 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11575 i
->ringt
= i
->ringt_base
;
11580 case SIG_FEATDMF_TA
:
11583 case SIG_FGC_CAMAMF
:
11589 case SIG_SF_FEATDMF
:
11592 /* Check for callerid, digits, etc */
11593 callid_created
= ast_callid_threadstorage_auto(&callid
);
11594 if (i
->cid_start
== CID_START_POLARITY_IN
) {
11595 chan
= dahdi_new(i
, AST_STATE_PRERING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11597 chan
= dahdi_new(i
, AST_STATE_RING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11601 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", i
->channel
);
11602 } else if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
11603 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
11604 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11606 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11611 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11614 ast_log(LOG_WARNING
, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i
->sig
), i
->channel
);
11615 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, DAHDI_TONE_CONGESTION
);
11617 ast_log(LOG_WARNING
, "Unable to play congestion tone on channel %d\n", i
->channel
);
11621 case DAHDI_EVENT_NOALARM
:
11623 #if defined(HAVE_PRI)
11624 case SIG_PRI_LIB_HANDLE_CASES
:
11625 ast_mutex_lock(&i
->lock
);
11626 sig_pri_chan_alarm_notify(i
->sig_pvt
, 1);
11627 ast_mutex_unlock(&i
->lock
);
11629 #endif /* defined(HAVE_PRI) */
11630 #if defined(HAVE_SS7)
11632 sig_ss7_set_alarm(i
->sig_pvt
, 0);
11634 #endif /* defined(HAVE_SS7) */
11639 handle_clear_alarms(i
);
11641 case DAHDI_EVENT_ALARM
:
11643 #if defined(HAVE_PRI)
11644 case SIG_PRI_LIB_HANDLE_CASES
:
11645 ast_mutex_lock(&i
->lock
);
11646 sig_pri_chan_alarm_notify(i
->sig_pvt
, 0);
11647 ast_mutex_unlock(&i
->lock
);
11649 #endif /* defined(HAVE_PRI) */
11650 #if defined(HAVE_SS7)
11652 sig_ss7_set_alarm(i
->sig_pvt
, 1);
11654 #endif /* defined(HAVE_SS7) */
11659 res
= get_alarms(i
);
11660 handle_alarms(i
, res
);
11661 /* fall thru intentionally */
11662 case DAHDI_EVENT_ONHOOK
:
11665 /* Back on hook. Hang up. */
11671 case SIG_FEATDMF_TA
:
11674 case SIG_FGC_CAMAMF
:
11680 case SIG_SF_FEATDMF
:
11688 dahdi_ec_disable(i
);
11689 /* Diddle the battery for the zhone */
11691 dahdi_set_hook(i
->subs
[SUB_REAL
].dfd
, DAHDI_OFFHOOK
);
11694 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, -1);
11695 dahdi_set_hook(i
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
11698 case SIG_PRI_LIB_HANDLE_CASES
:
11699 dahdi_ec_disable(i
);
11700 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, -1);
11703 ast_log(LOG_WARNING
, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i
->sig
), i
->channel
);
11704 res
= tone_zone_play_tone(i
->subs
[SUB_REAL
].dfd
, -1);
11708 case DAHDI_EVENT_POLARITY
:
11713 /* We have already got a PR before the channel was
11714 created, but it wasn't handled. We need polarity
11715 to be REV for remote hangup detection to work.
11716 At least in Spain */
11717 callid_created
= ast_callid_threadstorage_auto(&callid
);
11718 if (i
->hanguponpolarityswitch
)
11719 i
->polarity
= POLARITY_REV
;
11720 if (i
->cid_start
== CID_START_POLARITY
|| i
->cid_start
== CID_START_POLARITY_IN
) {
11721 i
->polarity
= POLARITY_REV
;
11722 ast_verb(2, "Starting post polarity "
11723 "CID detection on channel %d\n",
11725 chan
= dahdi_new(i
, AST_STATE_PRERING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11727 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", i
->channel
);
11728 } else if (ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
)) {
11729 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
11733 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
11736 ast_log(LOG_WARNING
, "handle_init_event detected "
11737 "polarity reversal on non-FXO (SIG_FXS) "
11738 "interface %d\n", i
->channel
);
11741 case DAHDI_EVENT_REMOVED
: /* destroy channel, will actually do so in do_monitor */
11742 ast_log(LOG_NOTICE
,
11743 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11746 case DAHDI_EVENT_NEONMWI_ACTIVE
:
11747 if (i
->mwimonitor_neon
) {
11748 notify_message(i
->mailbox
, 1);
11749 ast_log(LOG_NOTICE
, "NEON MWI set for channel %d, mailbox %s \n", i
->channel
, i
->mailbox
);
11752 case DAHDI_EVENT_NEONMWI_INACTIVE
:
11753 if (i
->mwimonitor_neon
) {
11754 notify_message(i
->mailbox
, 0);
11755 ast_log(LOG_NOTICE
, "NEON MWI cleared for channel %d, mailbox %s\n", i
->channel
, i
->mailbox
);
11762 static void monitor_pfds_clean(void *arg
) {
11763 struct pollfd
**pfds
= arg
;
11767 static void *do_monitor(void *data
)
11769 int count
, res
, res2
, spoint
, pollres
=0;
11770 struct dahdi_pvt
*i
;
11771 struct dahdi_pvt
*last
= NULL
;
11772 struct dahdi_pvt
*doomed
;
11773 time_t thispass
= 0, lastpass
= 0;
11776 struct pollfd
*pfds
=NULL
;
11777 int lastalloc
= -1;
11778 /* This thread monitors all the frame relay interfaces which are not yet in use
11779 (and thus do not have a separate thread) indefinitely */
11780 /* From here on out, we die whenever asked */
11782 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
)) {
11783 ast_log(LOG_WARNING
, "Unable to set cancel type to asynchronous\n");
11786 ast_debug(1, "Monitor starting...\n");
11788 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
11790 pthread_cleanup_push(monitor_pfds_clean
, &pfds
);
11792 /* Lock the interface list */
11793 ast_mutex_lock(&iflock
);
11794 if (!pfds
|| (lastalloc
!= ifcount
)) {
11800 if (!(pfds
= ast_calloc(1, ifcount
* sizeof(*pfds
)))) {
11801 ast_mutex_unlock(&iflock
);
11805 lastalloc
= ifcount
;
11807 /* Build the stuff we're going to poll on, that is the socket of every
11808 dahdi_pvt that does not have an associated owner channel */
11810 for (i
= iflist
; i
; i
= i
->next
) {
11811 ast_mutex_lock(&i
->lock
);
11812 if (pfds
&& (i
->subs
[SUB_REAL
].dfd
> -1) && i
->sig
&& (!i
->radio
) && !(i
->sig
& SIG_MFCR2
)) {
11813 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
11814 struct analog_pvt
*p
= i
->sig_pvt
;
11817 ast_log(LOG_ERROR
, "No sig_pvt?\n");
11818 } else if (!p
->owner
&& !p
->subs
[SUB_REAL
].owner
) {
11819 /* This needs to be watched, as it lacks an owner */
11820 pfds
[count
].fd
= i
->subs
[SUB_REAL
].dfd
;
11821 pfds
[count
].events
= POLLPRI
;
11822 pfds
[count
].revents
= 0;
11823 /* Message waiting or r2 channels also get watched for reading */
11824 if (i
->cidspill
|| i
->mwisendactive
|| i
->mwimonitor_fsk
||
11825 (i
->cid_start
== CID_START_DTMF_NOALERT
&& (i
->sig
== SIG_FXSLS
|| i
->sig
== SIG_FXSGS
|| i
->sig
== SIG_FXSKS
))) {
11826 pfds
[count
].events
|= POLLIN
;
11831 if (!i
->owner
&& !i
->subs
[SUB_REAL
].owner
&& !i
->mwimonitoractive
) {
11832 /* This needs to be watched, as it lacks an owner */
11833 pfds
[count
].fd
= i
->subs
[SUB_REAL
].dfd
;
11834 pfds
[count
].events
= POLLPRI
;
11835 pfds
[count
].revents
= 0;
11836 /* If we are monitoring for VMWI or sending CID, we need to
11837 read from the channel as well */
11838 if (i
->cidspill
|| i
->mwisendactive
|| i
->mwimonitor_fsk
||
11839 (i
->cid_start
== CID_START_DTMF_NOALERT
&& (i
->sig
== SIG_FXSLS
|| i
->sig
== SIG_FXSGS
|| i
->sig
== SIG_FXSKS
))) {
11840 pfds
[count
].events
|= POLLIN
;
11846 ast_mutex_unlock(&i
->lock
);
11848 /* Okay, now that we know what to do, release the interface lock */
11849 ast_mutex_unlock(&iflock
);
11851 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
11852 pthread_testcancel();
11853 /* Wait at least a second for something to happen */
11854 res
= poll(pfds
, count
, 1000);
11855 pthread_testcancel();
11856 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
11858 /* Okay, poll has finished. Let's see what happened. */
11860 if ((errno
!= EAGAIN
) && (errno
!= EINTR
))
11861 ast_log(LOG_WARNING
, "poll return %d: %s\n", res
, strerror(errno
));
11864 /* Alright, lock the interface list again, and let's look and see what has
11866 ast_mutex_lock(&iflock
);
11869 lastpass
= thispass
;
11870 thispass
= time(NULL
);
11872 for (i
= iflist
;; i
= i
->next
) {
11874 dahdi_destroy_channel_range(doomed
->channel
, doomed
->channel
);
11881 if (thispass
!= lastpass
) {
11882 if (!found
&& ((i
== last
) || ((i
== iflist
) && !last
))) {
11885 struct analog_pvt
*analog_p
= last
->sig_pvt
;
11886 /* Only allow MWI to be initiated on a quiescent fxs port */
11888 && !last
->mwisendactive
11889 && (last
->sig
& __DAHDI_SIG_FXO
)
11890 && !analog_p
->fxsoffhookstate
11892 && !ast_strlen_zero(last
->mailbox
)
11893 && !analog_p
->subs
[SUB_REAL
].owner
/* could be a recall ring from a flash hook hold */
11894 && (thispass
- analog_p
->onhooktime
> 3)) {
11895 res
= has_voicemail(last
);
11896 if (analog_p
->msgstate
!= res
) {
11897 /* Set driver resources for signalling VMWI */
11898 res2
= ioctl(last
->subs
[SUB_REAL
].dfd
, DAHDI_VMWI
, &res
);
11900 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
11901 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last
->channel
, strerror(errno
));
11903 /* If enabled for FSK spill then initiate it */
11904 if (mwi_send_init(last
)) {
11905 ast_log(LOG_WARNING
, "Unable to initiate mwi send sequence on channel %d\n", last
->channel
);
11907 analog_p
->msgstate
= res
;
11915 if ((i
->subs
[SUB_REAL
].dfd
> -1) && i
->sig
) {
11916 if (i
->radio
&& !i
->owner
)
11918 res
= dahdi_get_event(i
->subs
[SUB_REAL
].dfd
);
11921 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res
), i
->channel
);
11922 /* Don't hold iflock while handling init events */
11923 ast_mutex_unlock(&iflock
);
11924 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
))
11925 doomed
= (struct dahdi_pvt
*) analog_handle_init_event(i
->sig_pvt
, dahdievent_to_analogevent(res
));
11927 doomed
= handle_init_event(i
, res
);
11928 ast_mutex_lock(&iflock
);
11932 pollres
= ast_fdisset(pfds
, i
->subs
[SUB_REAL
].dfd
, count
, &spoint
);
11933 if (pollres
& POLLIN
) {
11934 if (i
->owner
|| i
->subs
[SUB_REAL
].owner
) {
11938 ast_log(LOG_WARNING
, "Whoa.... I'm owned but found (%d) in read...\n", i
->subs
[SUB_REAL
].dfd
);
11941 if (!i
->mwimonitor_fsk
&& !i
->mwisendactive
&& i
->cid_start
!= CID_START_DTMF_NOALERT
) {
11942 ast_log(LOG_WARNING
, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i
->subs
[SUB_REAL
].dfd
);
11945 res
= read(i
->subs
[SUB_REAL
].dfd
, buf
, sizeof(buf
));
11947 if (i
->mwimonitor_fsk
) {
11948 if (calc_energy((unsigned char *) buf
, res
, AST_LAW(i
)) > mwilevel
) {
11949 pthread_attr_t attr
;
11950 pthread_t threadid
;
11951 struct mwi_thread_data
*mtd
;
11953 pthread_attr_init(&attr
);
11954 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
11956 ast_debug(1, "Maybe some MWI on port %d!\n", i
->channel
);
11957 if ((mtd
= ast_calloc(1, sizeof(*mtd
)))) {
11959 memcpy(mtd
->buf
, buf
, res
);
11961 i
->mwimonitoractive
= 1;
11962 if (ast_pthread_create_background(&threadid
, &attr
, mwi_thread
, mtd
)) {
11963 ast_log(LOG_WARNING
, "Unable to start mwi thread on channel %d\n", i
->channel
);
11964 i
->mwimonitoractive
= 0;
11969 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
11970 } else if (i
->cid_start
== CID_START_DTMF_NOALERT
) {
11972 struct timeval now
;
11973 /* State machine dtmfcid_holdoff_state allows for the line to settle
11974 * before checking agin for dtmf energy. Presently waits for 500 mS before checking again
11976 if (1 == i
->dtmfcid_holdoff_state
) {
11977 gettimeofday(&i
->dtmfcid_delay
, NULL
);
11978 i
->dtmfcid_holdoff_state
= 2;
11979 } else if (2 == i
->dtmfcid_holdoff_state
) {
11980 gettimeofday(&now
, NULL
);
11981 if ((int)(now
.tv_sec
- i
->dtmfcid_delay
.tv_sec
) * 1000000 + (int)now
.tv_usec
- (int)i
->dtmfcid_delay
.tv_usec
> 500000) {
11982 i
->dtmfcid_holdoff_state
= 0;
11985 energy
= calc_energy((unsigned char *) buf
, res
, AST_LAW(i
));
11986 if (!i
->mwisendactive
&& energy
> dtmfcid_level
) {
11987 pthread_t threadid
;
11988 struct ast_channel
*chan
;
11989 ast_mutex_unlock(&iflock
);
11990 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
11991 /* just in case this event changes or somehow destroys a channel, set doomed here too */
11992 doomed
= analog_handle_init_event(i
->sig_pvt
, ANALOG_EVENT_DTMFCID
);
11993 i
->dtmfcid_holdoff_state
= 1;
11995 ast_callid callid
= 0;
11996 int callid_created
= ast_callid_threadstorage_auto(&callid
);
11997 chan
= dahdi_new(i
, AST_STATE_PRERING
, 0, SUB_REAL
, 0, NULL
, NULL
, callid
);
11999 ast_log(LOG_WARNING
, "Cannot allocate new structure on channel %d\n", i
->channel
);
12001 res
= ast_pthread_create_detached(&threadid
, NULL
, analog_ss_thread
, chan
);
12003 ast_log(LOG_WARNING
, "Unable to start simple switch thread on channel %d\n", i
->channel
);
12006 i
->dtmfcid_holdoff_state
= 1;
12009 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
12011 ast_mutex_lock(&iflock
);
12015 if (i
->mwisendactive
) {
12016 mwi_send_process_buffer(i
, res
);
12019 ast_log(LOG_WARNING
, "Read failed with %d: %s\n", res
, strerror(errno
));
12022 if (pollres
& POLLPRI
) {
12023 if (i
->owner
|| i
->subs
[SUB_REAL
].owner
) {
12027 ast_log(LOG_WARNING
, "Whoa.... I'm owned but found (%d)...\n", i
->subs
[SUB_REAL
].dfd
);
12030 res
= dahdi_get_event(i
->subs
[SUB_REAL
].dfd
);
12031 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res
), i
->channel
);
12032 /* Don't hold iflock while handling init events */
12033 ast_mutex_unlock(&iflock
);
12034 if (0 == i
->mwisendactive
|| 0 == mwi_send_process_event(i
, res
)) {
12035 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
))
12036 doomed
= (struct dahdi_pvt
*) analog_handle_init_event(i
->sig_pvt
, dahdievent_to_analogevent(res
));
12038 doomed
= handle_init_event(i
, res
);
12040 if (i
->doreoriginate
&& res
== DAHDI_EVENT_HOOKCOMPLETE
) {
12041 /* Actually automatically reoriginate this FXS line, if directed to.
12042 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12043 * doing its thing (one reason why this is for FXOKS only: FXOLS
12044 * hangups don't give us any DAHDI events to piggyback off of)*/
12045 i
->doreoriginate
= 0;
12046 /* Double check the channel is still off-hook. There's only about a millisecond
12047 * between when doreoriginate is set high and we see that here, but just to be safe. */
12048 if (!my_is_off_hook(i
)) {
12049 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i
->channel
);
12051 ast_verb(3, "Automatic reorigination on channel %d\n", i
->channel
);
12052 res
= DAHDI_EVENT_RINGOFFHOOK
; /* Pretend that the physical channel just went off hook */
12053 if (dahdi_analog_lib_handles(i
->sig
, i
->radio
, i
->oprmode
)) {
12054 doomed
= (struct dahdi_pvt
*) analog_handle_init_event(i
->sig_pvt
, dahdievent_to_analogevent(res
));
12056 doomed
= handle_init_event(i
, res
);
12060 ast_mutex_lock(&iflock
);
12064 ast_mutex_unlock(&iflock
);
12065 release_doomed_pris();
12067 dahdi_r2_destroy_nodev();
12070 /* Never reached */
12071 pthread_cleanup_pop(1);
12076 static int restart_monitor(void)
12078 /* If we're supposed to be stopped -- stay stopped */
12079 if (monitor_thread
== AST_PTHREADT_STOP
)
12081 ast_mutex_lock(&monlock
);
12082 if (monitor_thread
== pthread_self()) {
12083 ast_mutex_unlock(&monlock
);
12084 ast_log(LOG_WARNING
, "Cannot kill myself\n");
12087 if (monitor_thread
!= AST_PTHREADT_NULL
) {
12088 /* Wake up the thread */
12089 pthread_kill(monitor_thread
, SIGURG
);
12091 /* Start a new monitor */
12092 if (ast_pthread_create_background(&monitor_thread
, NULL
, do_monitor
, NULL
) < 0) {
12093 ast_mutex_unlock(&monlock
);
12094 ast_log(LOG_ERROR
, "Unable to start monitor thread.\n");
12098 ast_mutex_unlock(&monlock
);
12102 #if defined(HAVE_PRI)
12103 static int pri_resolve_span(int *span
, int channel
, int offset
, struct dahdi_spaninfo
*si
)
12107 /* Get appropriate trunk group if there is one */
12108 trunkgroup
= pris
[*span
].mastertrunkgroup
;
12110 /* Select a specific trunk group */
12111 for (x
= 0; x
< NUM_SPANS
; x
++) {
12112 if (pris
[x
].pri
.trunkgroup
== trunkgroup
) {
12117 ast_log(LOG_WARNING
, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel
, *span
, trunkgroup
);
12120 if (pris
[*span
].pri
.trunkgroup
) {
12121 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
);
12123 } else if (pris
[*span
].mastertrunkgroup
) {
12124 ast_log(LOG_WARNING
, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span
, pris
[*span
].mastertrunkgroup
);
12127 if (si
->totalchans
== 31) {
12129 pris
[*span
].dchannels
[0] = 16 + offset
;
12130 } else if (si
->totalchans
== 24) {
12132 pris
[*span
].dchannels
[0] = 24 + offset
;
12133 } else if (si
->totalchans
== 3) {
12135 pris
[*span
].dchannels
[0] = 3 + offset
;
12137 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
);
12141 pris
[*span
].pri
.span
= *span
+ 1;
12146 #endif /* defined(HAVE_PRI) */
12148 #if defined(HAVE_PRI)
12149 static int pri_create_trunkgroup(int trunkgroup
, int *channels
)
12151 struct dahdi_spaninfo si
;
12152 struct dahdi_params p
;
12157 for (x
= 0; x
< NUM_SPANS
; x
++) {
12158 if (pris
[x
].pri
.trunkgroup
== trunkgroup
) {
12159 ast_log(LOG_WARNING
, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup
, x
+ 1, pris
[x
].dchannels
[0]);
12163 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
12166 memset(&si
, 0, sizeof(si
));
12167 memset(&p
, 0, sizeof(p
));
12168 fd
= open("/dev/dahdi/channel", O_RDWR
);
12170 ast_log(LOG_WARNING
, "Failed to open channel: %s\n", strerror(errno
));
12174 if (ioctl(fd
, DAHDI_SPECIFY
, &x
)) {
12175 ast_log(LOG_WARNING
, "Failed to specify channel %d: %s\n", channels
[y
], strerror(errno
));
12179 if (ioctl(fd
, DAHDI_GET_PARAMS
, &p
)) {
12180 ast_log(LOG_WARNING
, "Failed to get channel parameters for channel %d: %s\n", channels
[y
], strerror(errno
));
12184 if (ioctl(fd
, DAHDI_SPANSTAT
, &si
)) {
12185 ast_log(LOG_WARNING
, "Failed go get span information on channel %d (span %d): %s\n", channels
[y
], p
.spanno
, strerror(errno
));
12189 span
= p
.spanno
- 1;
12190 if (pris
[span
].pri
.trunkgroup
) {
12191 ast_log(LOG_WARNING
, "Span %d is already provisioned for trunk group %d\n", span
+ 1, pris
[span
].pri
.trunkgroup
);
12195 if (pris
[span
].pri
.pvts
[0]) {
12196 ast_log(LOG_WARNING
, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span
+ 1);
12201 pris
[span
].pri
.trunkgroup
= trunkgroup
;
12204 pris
[ospan
].dchannels
[y
] = channels
[y
];
12205 pris
[span
].pri
.span
= span
+ 1;
12210 #endif /* defined(HAVE_PRI) */
12212 #if defined(HAVE_PRI)
12213 static int pri_create_spanmap(int span
, int trunkgroup
, int logicalspan
)
12215 if (pris
[span
].mastertrunkgroup
) {
12216 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
);
12219 pris
[span
].mastertrunkgroup
= trunkgroup
;
12220 pris
[span
].prilogicalspan
= logicalspan
;
12223 #endif /* defined(HAVE_PRI) */
12225 #if defined(HAVE_SS7)
12226 static unsigned int parse_pointcode(const char *pcstring
)
12228 unsigned int code1
, code2
, code3
;
12231 numvals
= sscanf(pcstring
, "%30d-%30d-%30d", &code1
, &code2
, &code3
);
12235 return (code1
<< 16) | (code2
<< 8) | code3
;
12239 #endif /* defined(HAVE_SS7) */
12241 #if defined(HAVE_SS7)
12242 static struct dahdi_ss7
* ss7_resolve_linkset(int linkset
)
12244 if ((linkset
< 0) || (linkset
>= NUM_SPANS
))
12247 return &linksets
[linkset
- 1];
12249 #endif /* defined(HAVE_SS7) */
12252 static void dahdi_r2_destroy_links(void)
12254 struct r2link_entry
*cur
;
12256 /* Queue everything for removal */
12257 AST_LIST_LOCK(&r2links
);
12258 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links
, cur
, list
) {
12259 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur
->mfcr2
.index
);
12260 AST_LIST_MOVE_CURRENT(&nodev_r2links
, list
);
12262 AST_LIST_TRAVERSE_SAFE_END
;
12263 AST_LIST_UNLOCK(&r2links
);
12264 /* Now destroy properly */
12265 dahdi_r2_destroy_nodev();
12268 /* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12269 #define R2_LINK_CAPACITY 30
12270 static struct r2link_entry
*dahdi_r2_get_link(const struct dahdi_chan_conf
*conf
)
12272 struct r2link_entry
*cur
= NULL
;
12273 /* Only create a new R2 link if
12274 1. This is the first link requested
12275 2. Configuration changed
12276 3. We got more channels than supported per link */
12277 AST_LIST_LOCK(&r2links
);
12278 if (! AST_LIST_EMPTY(&r2links
)) {
12279 cur
= AST_LIST_LAST(&r2links
);
12280 if (memcmp(&conf
->mfcr2
, &cur
->mfcr2
.conf
, sizeof(conf
->mfcr2
))) {
12281 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12283 } else if (cur
->mfcr2
.numchans
== R2_LINK_CAPACITY
) {
12284 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY
);
12289 struct r2link_entry
*tmp
= NULL
;
12290 int new_idx
= r2links_count
+ 1;
12292 for (i
= 1; i
<= r2links_count
; i
++) {
12294 AST_LIST_TRAVERSE(&r2links
, tmp
, list
) {
12295 if (i
== tmp
->mfcr2
.index
) {
12305 cur
= ast_calloc(1, sizeof(*cur
));
12307 ast_log(LOG_ERROR
, "Cannot allocate R2 link!\n");
12310 cur
->mfcr2
.index
= new_idx
;
12311 cur
->mfcr2
.r2master
= AST_PTHREADT_NULL
;
12313 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx
, r2links_count
);
12314 AST_LIST_INSERT_TAIL(&r2links
, cur
, list
);
12316 AST_LIST_UNLOCK(&r2links
);
12320 static int dahdi_r2_set_context(struct dahdi_mfcr2
*r2_link
, const struct dahdi_chan_conf
*conf
)
12322 char tmplogdir
[] = "/tmp";
12323 char logdir
[OR2_MAX_PATH
];
12326 r2_link
->protocol_context
= openr2_context_new(NULL
, &dahdi_r2_event_iface
,
12327 &dahdi_r2_transcode_iface
, conf
->mfcr2
.variant
, conf
->mfcr2
.max_ani
,
12328 conf
->mfcr2
.max_dnis
);
12329 if (!r2_link
->protocol_context
) {
12332 openr2_context_set_log_level(r2_link
->protocol_context
, conf
->mfcr2
.loglevel
);
12333 openr2_context_set_ani_first(r2_link
->protocol_context
, conf
->mfcr2
.get_ani_first
);
12334 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12335 openr2_context_set_skip_category_request(r2_link
->protocol_context
, conf
->mfcr2
.skip_category_request
);
12337 openr2_context_set_mf_threshold(r2_link
->protocol_context
, threshold
);
12338 openr2_context_set_mf_back_timeout(r2_link
->protocol_context
, conf
->mfcr2
.mfback_timeout
);
12339 openr2_context_set_metering_pulse_timeout(r2_link
->protocol_context
, conf
->mfcr2
.metering_pulse_timeout
);
12340 openr2_context_set_double_answer(r2_link
->protocol_context
, conf
->mfcr2
.double_answer
);
12341 openr2_context_set_immediate_accept(r2_link
->protocol_context
, conf
->mfcr2
.immediate_accept
);
12342 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12343 openr2_context_set_dtmf_dialing(r2_link
->protocol_context
, conf
->mfcr2
.dtmf_dialing
, conf
->mfcr2
.dtmf_time_on
, conf
->mfcr2
.dtmf_time_off
);
12344 openr2_context_set_dtmf_detection(r2_link
->protocol_context
, conf
->mfcr2
.dtmf_detection
);
12346 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12347 openr2_context_set_dtmf_detection_end_timeout(r2_link
->protocol_context
, conf
->mfcr2
.dtmf_end_timeout
);
12349 if (ast_strlen_zero(conf
->mfcr2
.logdir
)) {
12350 if (openr2_context_set_log_directory(r2_link
->protocol_context
, tmplogdir
)) {
12351 ast_log(LOG_ERROR
, "Failed setting default MFC/R2 log directory %s\n", tmplogdir
);
12354 snres
= snprintf(logdir
, sizeof(logdir
), "%s/%s/%s", ast_config_AST_LOG_DIR
, "mfcr2", conf
->mfcr2
.logdir
);
12355 if (snres
>= sizeof(logdir
)) {
12356 ast_log(LOG_ERROR
, "MFC/R2 logging directory truncated, using %s\n", tmplogdir
);
12357 if (openr2_context_set_log_directory(r2_link
->protocol_context
, tmplogdir
)) {
12358 ast_log(LOG_ERROR
, "Failed setting default MFC/R2 log directory %s\n", tmplogdir
);
12361 if (openr2_context_set_log_directory(r2_link
->protocol_context
, logdir
)) {
12362 ast_log(LOG_ERROR
, "Failed setting MFC/R2 log directory %s\n", logdir
);
12366 if (!ast_strlen_zero(conf
->mfcr2
.r2proto_file
)) {
12367 if (openr2_context_configure_from_advanced_file(r2_link
->protocol_context
, conf
->mfcr2
.r2proto_file
)) {
12368 ast_log(LOG_ERROR
, "Failed to configure r2context from advanced configuration file %s\n", conf
->mfcr2
.r2proto_file
);
12371 /* Save the configuration used to setup this link */
12372 memcpy(&r2_link
->conf
, &conf
->mfcr2
, sizeof(r2_link
->conf
));
12377 /* converts a DAHDI sigtype to signalling as can be configured from
12379 * While both have basically the same values, this will later be the
12380 * place to add filters and sanity checks
12382 static int sigtype_to_signalling(int sigtype
)
12389 * \brief Initialize/create a channel interface.
12391 * \param channel Channel interface number to initialize/create.
12392 * \param conf Configuration parameters to initialize interface with.
12393 * \param reloading What we are doing now:
12394 * 0 - initial module load,
12395 * 1 - module reload,
12396 * 2 - module restart
12398 * \retval Interface-pointer initialized/created
12399 * \retval NULL if error
12401 static struct dahdi_pvt
*mkintf(int channel
, const struct dahdi_chan_conf
*conf
, int reloading
)
12403 /* Make a dahdi_pvt structure for this interface */
12404 struct dahdi_pvt
*tmp
;/*!< Current channel structure initializing */
12406 struct dahdi_bufferinfo bi
;
12409 #if defined(HAVE_PRI)
12411 #endif /* defined(HAVE_PRI) */
12412 int here
= 0;/*!< TRUE if the channel interface already exists. */
12414 struct analog_pvt
*analog_p
= NULL
;
12415 struct dahdi_params p
;
12416 #if defined(HAVE_PRI)
12417 struct dahdi_spaninfo si
;
12418 struct sig_pri_chan
*pri_chan
= NULL
;
12419 #endif /* defined(HAVE_PRI) */
12420 #if defined(HAVE_SS7)
12421 struct sig_ss7_chan
*ss7_chan
= NULL
;
12422 #endif /* defined(HAVE_SS7) */
12424 /* Search channel interface list to see if it already exists. */
12425 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
12426 if (!tmp
->destroy
) {
12427 if (tmp
->channel
== channel
) {
12428 /* The channel interface already exists. */
12432 if (tmp
->channel
> channel
) {
12433 /* No way it can be in the sorted list. */
12440 if (!here
&& reloading
!= 1) {
12441 tmp
= ast_calloc(1, sizeof(*tmp
));
12445 tmp
->cc_params
= ast_cc_config_params_init();
12446 if (!tmp
->cc_params
) {
12450 ast_mutex_init(&tmp
->lock
);
12452 for (x
= 0; x
< 3; x
++)
12453 tmp
->subs
[x
].dfd
= -1;
12454 tmp
->channel
= channel
;
12455 tmp
->priindication_oob
= conf
->chan
.priindication_oob
;
12459 int chan_sig
= conf
->chan
.sig
;
12461 /* If there are variables in tmp before it is updated to match the new config, clear them */
12462 if (reloading
&& tmp
->vars
) {
12463 ast_variables_destroy(tmp
->vars
);
12468 /* Can only get here if this is a new channel interface being created. */
12469 if ((channel
!= CHAN_PSEUDO
)) {
12472 snprintf(fn
, sizeof(fn
), "%d", channel
);
12473 /* Open non-blocking */
12474 tmp
->subs
[SUB_REAL
].dfd
= dahdi_open(fn
);
12475 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 */
12477 tmp
->subs
[SUB_REAL
].dfd
= dahdi_open(fn
);
12480 /* Allocate a DAHDI structure */
12481 if (tmp
->subs
[SUB_REAL
].dfd
< 0) {
12482 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
);
12483 destroy_dahdi_pvt(tmp
);
12486 memset(&p
, 0, sizeof(p
));
12487 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &p
);
12489 ast_log(LOG_ERROR
, "Unable to get parameters: %s\n", strerror(errno
));
12490 destroy_dahdi_pvt(tmp
);
12493 if (conf
->is_sig_auto
)
12494 chan_sig
= sigtype_to_signalling(p
.sigtype
);
12495 if (p
.sigtype
!= (chan_sig
& 0x3ffff)) {
12496 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
));
12497 destroy_dahdi_pvt(tmp
);
12500 tmp
->law_default
= p
.curlaw
;
12501 tmp
->law
= p
.curlaw
;
12502 tmp
->span
= p
.spanno
;
12503 #if defined(HAVE_PRI)
12504 span
= p
.spanno
- 1;
12505 #endif /* defined(HAVE_PRI) */
12509 tmp
->sig
= chan_sig
;
12510 tmp
->outsigmod
= conf
->chan
.outsigmod
;
12512 if (dahdi_analog_lib_handles(chan_sig
, tmp
->radio
, tmp
->oprmode
)) {
12513 analog_p
= analog_new(dahdisig_to_analogsig(chan_sig
), tmp
);
12515 destroy_dahdi_pvt(tmp
);
12518 tmp
->sig_pvt
= analog_p
;
12520 #if defined(HAVE_SS7)
12521 if (chan_sig
== SIG_SS7
) {
12522 struct dahdi_ss7
*ss7
;
12525 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &clear
)) {
12526 ast_log(LOG_ERROR
, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel
, p
.spanno
, strerror(errno
));
12527 destroy_dahdi_pvt(tmp
);
12531 ss7
= ss7_resolve_linkset(cur_linkset
);
12533 ast_log(LOG_ERROR
, "Unable to find linkset %d\n", cur_linkset
);
12534 destroy_dahdi_pvt(tmp
);
12537 ss7
->ss7
.span
= cur_linkset
;
12538 if (cur_cicbeginswith
< 0) {
12539 ast_log(LOG_ERROR
, "Need to set cicbeginswith for the channels!\n");
12540 destroy_dahdi_pvt(tmp
);
12543 ss7_chan
= sig_ss7_chan_new(tmp
, &ss7
->ss7
);
12545 destroy_dahdi_pvt(tmp
);
12548 tmp
->sig_pvt
= ss7_chan
;
12549 tmp
->ss7
= &ss7
->ss7
;
12551 ss7_chan
->channel
= tmp
->channel
;
12552 ss7_chan
->cic
= cur_cicbeginswith
++;
12554 /* DB: Add CIC's DPC information */
12555 ss7_chan
->dpc
= cur_defaultdpc
;
12557 ss7
->ss7
.pvts
[ss7
->ss7
.numchans
++] = ss7_chan
;
12559 ast_copy_string(ss7
->ss7
.internationalprefix
, conf
->ss7
.ss7
.internationalprefix
, sizeof(ss7
->ss7
.internationalprefix
));
12560 ast_copy_string(ss7
->ss7
.nationalprefix
, conf
->ss7
.ss7
.nationalprefix
, sizeof(ss7
->ss7
.nationalprefix
));
12561 ast_copy_string(ss7
->ss7
.subscriberprefix
, conf
->ss7
.ss7
.subscriberprefix
, sizeof(ss7
->ss7
.subscriberprefix
));
12562 ast_copy_string(ss7
->ss7
.unknownprefix
, conf
->ss7
.ss7
.unknownprefix
, sizeof(ss7
->ss7
.unknownprefix
));
12563 ast_copy_string(ss7
->ss7
.networkroutedprefix
, conf
->ss7
.ss7
.networkroutedprefix
, sizeof(ss7
->ss7
.networkroutedprefix
));
12565 ss7
->ss7
.called_nai
= conf
->ss7
.ss7
.called_nai
;
12566 ss7
->ss7
.calling_nai
= conf
->ss7
.ss7
.calling_nai
;
12568 #endif /* defined(HAVE_SS7) */
12570 if (chan_sig
== SIG_MFCR2
) {
12571 struct dahdi_mfcr2
*r2_link
;
12572 struct r2link_entry
*r2_le
= dahdi_r2_get_link(conf
);
12573 r2_link
= &r2_le
->mfcr2
;
12575 ast_log(LOG_WARNING
, "Cannot get another R2 DAHDI context!\n");
12576 destroy_dahdi_pvt(tmp
);
12579 if (!r2_link
->protocol_context
&& dahdi_r2_set_context(r2_link
, conf
)) {
12580 ast_log(LOG_ERROR
, "Cannot create OpenR2 protocol context.\n");
12581 destroy_dahdi_pvt(tmp
);
12584 if (r2_link
->numchans
== ARRAY_LEN(r2_link
->pvts
)) {
12585 ast_log(LOG_ERROR
, "Cannot add more channels to this link!\n");
12586 destroy_dahdi_pvt(tmp
);
12589 r2_link
->pvts
[r2_link
->numchans
++] = tmp
;
12590 tmp
->r2chan
= openr2_chan_new_from_fd(r2_link
->protocol_context
,
12591 tmp
->subs
[SUB_REAL
].dfd
,
12593 if (!tmp
->r2chan
) {
12594 openr2_liberr_t err
= openr2_context_get_last_error(r2_link
->protocol_context
);
12595 ast_log(LOG_ERROR
, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err
));
12596 destroy_dahdi_pvt(tmp
);
12599 r2_link
->live_chans
++;
12600 tmp
->mfcr2
= r2_link
;
12601 if (conf
->mfcr2
.call_files
) {
12602 openr2_chan_enable_call_files(tmp
->r2chan
);
12604 openr2_chan_set_client_data(tmp
->r2chan
, tmp
);
12605 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12606 openr2_chan_set_logging_func(tmp
->r2chan
, (openr2_logging_func_t
)dahdi_r2_on_chan_log
);
12607 openr2_chan_set_log_level(tmp
->r2chan
, conf
->mfcr2
.loglevel
);
12608 tmp
->mfcr2_category
= conf
->mfcr2
.category
;
12609 tmp
->mfcr2_charge_calls
= conf
->mfcr2
.charge_calls
;
12610 tmp
->mfcr2_allow_collect_calls
= conf
->mfcr2
.allow_collect_calls
;
12611 tmp
->mfcr2_forced_release
= conf
->mfcr2
.forced_release
;
12612 tmp
->mfcr2_accept_on_offer
= conf
->mfcr2
.accept_on_offer
;
12613 tmp
->mfcr2call
= 0;
12614 tmp
->mfcr2_dnis_index
= 0;
12615 tmp
->mfcr2_ani_index
= 0;
12619 if (dahdi_sig_pri_lib_handles(chan_sig
)) {
12623 int myswitchtype
= 0;
12626 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_AUDIOMODE
, &offset
)) {
12627 ast_log(LOG_ERROR
, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel
, p
.spanno
, strerror(errno
));
12628 destroy_dahdi_pvt(tmp
);
12631 if (span
>= NUM_SPANS
) {
12632 ast_log(LOG_ERROR
, "Channel %d does not lie on a span I know of (%d)\n", channel
, span
);
12633 destroy_dahdi_pvt(tmp
);
12637 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
,DAHDI_SPANSTAT
,&si
) == -1) {
12638 ast_log(LOG_ERROR
, "Unable to get span status: %s\n", strerror(errno
));
12639 destroy_dahdi_pvt(tmp
);
12642 /* Store the logical span first based upon the real span */
12643 tmp
->logicalspan
= pris
[span
].prilogicalspan
;
12644 pri_resolve_span(&span
, channel
, (channel
- p
.chanpos
), &si
);
12646 ast_log(LOG_WARNING
, "Channel %d: Unable to find locate channel/trunk group!\n", channel
);
12647 destroy_dahdi_pvt(tmp
);
12650 myswitchtype
= conf
->pri
.pri
.switchtype
;
12651 /* Make sure this isn't a d-channel */
12653 for (x
= 0; x
< NUM_SPANS
; x
++) {
12654 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
12655 if (pris
[x
].dchannels
[y
] == tmp
->channel
) {
12661 if (!matchesdchan
) {
12662 if (pris
[span
].pri
.nodetype
&& (pris
[span
].pri
.nodetype
!= conf
->pri
.pri
.nodetype
)) {
12663 ast_log(LOG_ERROR
, "Span %d is already a %s node\n", span
+ 1, pri_node2str(pris
[span
].pri
.nodetype
));
12664 destroy_dahdi_pvt(tmp
);
12667 if (pris
[span
].pri
.switchtype
&& (pris
[span
].pri
.switchtype
!= myswitchtype
)) {
12668 ast_log(LOG_ERROR
, "Span %d is already a %s switch\n", span
+ 1, pri_switch2str(pris
[span
].pri
.switchtype
));
12669 destroy_dahdi_pvt(tmp
);
12672 if ((pris
[span
].pri
.dialplan
) && (pris
[span
].pri
.dialplan
!= conf
->pri
.pri
.dialplan
)) {
12673 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
));
12674 destroy_dahdi_pvt(tmp
);
12677 if (!ast_strlen_zero(pris
[span
].pri
.idledial
) && strcmp(pris
[span
].pri
.idledial
, conf
->pri
.pri
.idledial
)) {
12678 ast_log(LOG_ERROR
, "Span %d already has idledial '%s'.\n", span
+ 1, conf
->pri
.pri
.idledial
);
12679 destroy_dahdi_pvt(tmp
);
12682 if (!ast_strlen_zero(pris
[span
].pri
.idleext
) && strcmp(pris
[span
].pri
.idleext
, conf
->pri
.pri
.idleext
)) {
12683 ast_log(LOG_ERROR
, "Span %d already has idleext '%s'.\n", span
+ 1, conf
->pri
.pri
.idleext
);
12684 destroy_dahdi_pvt(tmp
);
12687 if (pris
[span
].pri
.minunused
&& (pris
[span
].pri
.minunused
!= conf
->pri
.pri
.minunused
)) {
12688 ast_log(LOG_ERROR
, "Span %d already has minunused of %d.\n", span
+ 1, conf
->pri
.pri
.minunused
);
12689 destroy_dahdi_pvt(tmp
);
12692 if (pris
[span
].pri
.minidle
&& (pris
[span
].pri
.minidle
!= conf
->pri
.pri
.minidle
)) {
12693 ast_log(LOG_ERROR
, "Span %d already has minidle of %d.\n", span
+ 1, conf
->pri
.pri
.minidle
);
12694 destroy_dahdi_pvt(tmp
);
12697 if (pris
[span
].pri
.numchans
>= ARRAY_LEN(pris
[span
].pri
.pvts
)) {
12698 ast_log(LOG_ERROR
, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel
,
12699 pris
[span
].pri
.trunkgroup
);
12700 destroy_dahdi_pvt(tmp
);
12704 pri_chan
= sig_pri_chan_new(tmp
, &pris
[span
].pri
, tmp
->logicalspan
, p
.chanpos
, pris
[span
].mastertrunkgroup
);
12706 destroy_dahdi_pvt(tmp
);
12709 tmp
->sig_pvt
= pri_chan
;
12710 tmp
->pri
= &pris
[span
].pri
;
12712 tmp
->priexclusive
= conf
->chan
.priexclusive
;
12714 if (!tmp
->pri
->cc_params
) {
12715 tmp
->pri
->cc_params
= ast_cc_config_params_init();
12716 if (!tmp
->pri
->cc_params
) {
12717 destroy_dahdi_pvt(tmp
);
12721 ast_cc_copy_config_params(tmp
->pri
->cc_params
,
12722 conf
->chan
.cc_params
);
12724 pris
[span
].pri
.sig
= chan_sig
;
12725 pris
[span
].pri
.nodetype
= conf
->pri
.pri
.nodetype
;
12726 pris
[span
].pri
.switchtype
= myswitchtype
;
12727 pris
[span
].pri
.nsf
= conf
->pri
.pri
.nsf
;
12728 pris
[span
].pri
.dialplan
= conf
->pri
.pri
.dialplan
;
12729 pris
[span
].pri
.localdialplan
= conf
->pri
.pri
.localdialplan
;
12730 pris
[span
].pri
.cpndialplan
= conf
->pri
.pri
.cpndialplan
;
12731 pris
[span
].pri
.pvts
[pris
[span
].pri
.numchans
++] = tmp
->sig_pvt
;
12732 pris
[span
].pri
.minunused
= conf
->pri
.pri
.minunused
;
12733 pris
[span
].pri
.minidle
= conf
->pri
.pri
.minidle
;
12734 pris
[span
].pri
.overlapdial
= conf
->pri
.pri
.overlapdial
;
12735 pris
[span
].pri
.qsigchannelmapping
= conf
->pri
.pri
.qsigchannelmapping
;
12736 pris
[span
].pri
.discardremoteholdretrieval
= conf
->pri
.pri
.discardremoteholdretrieval
;
12737 #if defined(HAVE_PRI_SERVICE_MESSAGES)
12738 pris
[span
].pri
.enable_service_message_support
= conf
->pri
.pri
.enable_service_message_support
;
12739 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12740 #ifdef HAVE_PRI_INBANDDISCONNECT
12741 pris
[span
].pri
.inbanddisconnect
= conf
->pri
.pri
.inbanddisconnect
;
12743 #if defined(HAVE_PRI_CALL_HOLD)
12744 pris
[span
].pri
.hold_disconnect_transfer
=
12745 conf
->pri
.pri
.hold_disconnect_transfer
;
12746 #endif /* defined(HAVE_PRI_CALL_HOLD) */
12747 #if defined(HAVE_PRI_CCSS)
12748 pris
[span
].pri
.cc_ptmp_recall_mode
=
12749 conf
->pri
.pri
.cc_ptmp_recall_mode
;
12750 pris
[span
].pri
.cc_qsig_signaling_link_req
=
12751 conf
->pri
.pri
.cc_qsig_signaling_link_req
;
12752 pris
[span
].pri
.cc_qsig_signaling_link_rsp
=
12753 conf
->pri
.pri
.cc_qsig_signaling_link_rsp
;
12754 #endif /* defined(HAVE_PRI_CCSS) */
12755 #if defined(HAVE_PRI_CALL_WAITING)
12756 pris
[span
].pri
.max_call_waiting_calls
=
12757 conf
->pri
.pri
.max_call_waiting_calls
;
12758 pris
[span
].pri
.allow_call_waiting_calls
=
12759 conf
->pri
.pri
.allow_call_waiting_calls
;
12760 #endif /* defined(HAVE_PRI_CALL_WAITING) */
12761 pris
[span
].pri
.transfer
= conf
->chan
.transfer
;
12762 pris
[span
].pri
.facilityenable
= conf
->pri
.pri
.facilityenable
;
12763 #if defined(HAVE_PRI_L2_PERSISTENCE)
12764 pris
[span
].pri
.l2_persistence
= conf
->pri
.pri
.l2_persistence
;
12765 #endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12766 pris
[span
].pri
.colp_send
= conf
->pri
.pri
.colp_send
;
12767 #if defined(HAVE_PRI_AOC_EVENTS)
12768 pris
[span
].pri
.aoc_passthrough_flag
= conf
->pri
.pri
.aoc_passthrough_flag
;
12769 pris
[span
].pri
.aoce_delayhangup
= conf
->pri
.pri
.aoce_delayhangup
;
12770 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
12771 if (chan_sig
== SIG_BRI_PTMP
) {
12772 pris
[span
].pri
.layer1_ignored
= conf
->pri
.pri
.layer1_ignored
;
12774 /* Option does not apply to this line type. */
12775 pris
[span
].pri
.layer1_ignored
= 0;
12777 pris
[span
].pri
.append_msn_to_user_tag
= conf
->pri
.pri
.append_msn_to_user_tag
;
12778 pris
[span
].pri
.inband_on_setup_ack
= conf
->pri
.pri
.inband_on_setup_ack
;
12779 pris
[span
].pri
.inband_on_proceeding
= conf
->pri
.pri
.inband_on_proceeding
;
12780 ast_copy_string(pris
[span
].pri
.initial_user_tag
, conf
->chan
.cid_tag
, sizeof(pris
[span
].pri
.initial_user_tag
));
12781 ast_copy_string(pris
[span
].pri
.msn_list
, conf
->pri
.pri
.msn_list
, sizeof(pris
[span
].pri
.msn_list
));
12782 #if defined(HAVE_PRI_MWI)
12783 ast_copy_string(pris
[span
].pri
.mwi_mailboxes
,
12784 conf
->pri
.pri
.mwi_mailboxes
,
12785 sizeof(pris
[span
].pri
.mwi_mailboxes
));
12786 ast_copy_string(pris
[span
].pri
.mwi_vm_boxes
,
12787 conf
->pri
.pri
.mwi_vm_boxes
,
12788 sizeof(pris
[span
].pri
.mwi_vm_boxes
));
12789 ast_copy_string(pris
[span
].pri
.mwi_vm_numbers
,
12790 conf
->pri
.pri
.mwi_vm_numbers
,
12791 sizeof(pris
[span
].pri
.mwi_vm_numbers
));
12792 #endif /* defined(HAVE_PRI_MWI) */
12793 ast_copy_string(pris
[span
].pri
.idledial
, conf
->pri
.pri
.idledial
, sizeof(pris
[span
].pri
.idledial
));
12794 ast_copy_string(pris
[span
].pri
.idleext
, conf
->pri
.pri
.idleext
, sizeof(pris
[span
].pri
.idleext
));
12795 ast_copy_string(pris
[span
].pri
.internationalprefix
, conf
->pri
.pri
.internationalprefix
, sizeof(pris
[span
].pri
.internationalprefix
));
12796 ast_copy_string(pris
[span
].pri
.nationalprefix
, conf
->pri
.pri
.nationalprefix
, sizeof(pris
[span
].pri
.nationalprefix
));
12797 ast_copy_string(pris
[span
].pri
.localprefix
, conf
->pri
.pri
.localprefix
, sizeof(pris
[span
].pri
.localprefix
));
12798 ast_copy_string(pris
[span
].pri
.privateprefix
, conf
->pri
.pri
.privateprefix
, sizeof(pris
[span
].pri
.privateprefix
));
12799 ast_copy_string(pris
[span
].pri
.unknownprefix
, conf
->pri
.pri
.unknownprefix
, sizeof(pris
[span
].pri
.unknownprefix
));
12800 pris
[span
].pri
.moh_signaling
= conf
->pri
.pri
.moh_signaling
;
12801 pris
[span
].pri
.resetinterval
= conf
->pri
.pri
.resetinterval
;
12802 #if defined(HAVE_PRI_DISPLAY_TEXT)
12803 pris
[span
].pri
.display_flags_send
= conf
->pri
.pri
.display_flags_send
;
12804 pris
[span
].pri
.display_flags_receive
= conf
->pri
.pri
.display_flags_receive
;
12805 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
12806 #if defined(HAVE_PRI_MCID)
12807 pris
[span
].pri
.mcid_send
= conf
->pri
.pri
.mcid_send
;
12808 #endif /* defined(HAVE_PRI_MCID) */
12809 pris
[span
].pri
.force_restart_unavailable_chans
= conf
->pri
.pri
.force_restart_unavailable_chans
;
12810 #if defined(HAVE_PRI_DATETIME_SEND)
12811 pris
[span
].pri
.datetime_send
= conf
->pri
.pri
.datetime_send
;
12812 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
12814 for (x
= 0; x
< PRI_MAX_TIMERS
; x
++) {
12815 pris
[span
].pri
.pritimers
[x
] = conf
->pri
.pri
.pritimers
[x
];
12818 #if defined(HAVE_PRI_CALL_WAITING)
12819 /* Channel initial config parameters. */
12820 pris
[span
].pri
.ch_cfg
.stripmsd
= conf
->chan
.stripmsd
;
12821 pris
[span
].pri
.ch_cfg
.hidecallerid
= conf
->chan
.hidecallerid
;
12822 pris
[span
].pri
.ch_cfg
.hidecalleridname
= conf
->chan
.hidecalleridname
;
12823 pris
[span
].pri
.ch_cfg
.immediate
= conf
->chan
.immediate
;
12824 pris
[span
].pri
.ch_cfg
.priexclusive
= conf
->chan
.priexclusive
;
12825 pris
[span
].pri
.ch_cfg
.priindication_oob
= conf
->chan
.priindication_oob
;
12826 pris
[span
].pri
.ch_cfg
.use_callerid
= conf
->chan
.use_callerid
;
12827 pris
[span
].pri
.ch_cfg
.use_callingpres
= conf
->chan
.use_callingpres
;
12828 ast_copy_string(pris
[span
].pri
.ch_cfg
.context
, conf
->chan
.context
, sizeof(pris
[span
].pri
.ch_cfg
.context
));
12829 ast_copy_string(pris
[span
].pri
.ch_cfg
.mohinterpret
, conf
->chan
.mohinterpret
, sizeof(pris
[span
].pri
.ch_cfg
.mohinterpret
));
12830 #endif /* defined(HAVE_PRI_CALL_WAITING) */
12832 ast_log(LOG_ERROR
, "Channel %d is reserved for D-channel.\n", p
.chanpos
);
12833 destroy_dahdi_pvt(tmp
);
12840 /* already exists in interface list */
12841 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
));
12842 chan_sig
= tmp
->sig
;
12843 if (tmp
->subs
[SUB_REAL
].dfd
> -1) {
12844 memset(&p
, 0, sizeof(p
));
12845 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &p
);
12848 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
12849 switch (chan_sig
) {
12857 case SIG_FEATDMF_TA
:
12863 case SIG_FGC_CAMAMF
:
12865 case SIG_SF_FEATDMF
:
12872 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
12873 p
.channo
= channel
;
12877 p
.debouncetime
= 5;
12879 p
.channo
= channel
;
12880 /* Override timing settings based on config file */
12881 if (conf
->timing
.prewinktime
>= 0)
12882 p
.prewinktime
= conf
->timing
.prewinktime
;
12883 if (conf
->timing
.preflashtime
>= 0)
12884 p
.preflashtime
= conf
->timing
.preflashtime
;
12885 if (conf
->timing
.winktime
>= 0)
12886 p
.winktime
= conf
->timing
.winktime
;
12887 if (conf
->timing
.flashtime
>= 0)
12888 p
.flashtime
= conf
->timing
.flashtime
;
12889 if (conf
->timing
.starttime
>= 0)
12890 p
.starttime
= conf
->timing
.starttime
;
12891 if (conf
->timing
.rxwinktime
>= 0)
12892 p
.rxwinktime
= conf
->timing
.rxwinktime
;
12893 if (conf
->timing
.rxflashtime
>= 0)
12894 p
.rxflashtime
= conf
->timing
.rxflashtime
;
12895 if (conf
->timing
.debouncetime
>= 0)
12896 p
.debouncetime
= conf
->timing
.debouncetime
;
12899 /* don't set parms on a pseudo-channel */
12900 if (tmp
->subs
[SUB_REAL
].dfd
>= 0)
12902 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_SET_PARAMS
, &p
);
12904 ast_log(LOG_ERROR
, "Unable to set parameters: %s\n", strerror(errno
));
12905 destroy_dahdi_pvt(tmp
);
12910 if (!here
&& (tmp
->subs
[SUB_REAL
].dfd
> -1)) {
12911 memset(&bi
, 0, sizeof(bi
));
12912 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
12914 bi
.txbufpolicy
= conf
->chan
.buf_policy
;
12915 bi
.rxbufpolicy
= conf
->chan
.buf_policy
;
12916 bi
.numbufs
= conf
->chan
.buf_no
;
12917 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
12919 ast_log(LOG_WARNING
, "Unable to set buffer policy on channel %d: %s\n", channel
, strerror(errno
));
12922 ast_log(LOG_WARNING
, "Unable to check buffer policy on channel %d: %s\n", channel
, strerror(errno
));
12924 tmp
->buf_policy
= conf
->chan
.buf_policy
;
12925 tmp
->buf_no
= conf
->chan
.buf_no
;
12926 tmp
->usefaxbuffers
= conf
->chan
.usefaxbuffers
;
12927 tmp
->faxbuf_policy
= conf
->chan
.faxbuf_policy
;
12928 tmp
->faxbuf_no
= conf
->chan
.faxbuf_no
;
12929 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
12930 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
12931 * The reason the ioctl call above failed should to be determined before worrying about the
12932 * faxbuffer-related ioctl calls */
12933 tmp
->bufsize
= bi
.bufsize
;
12936 tmp
->immediate
= conf
->chan
.immediate
;
12937 tmp
->immediatering
= conf
->chan
.immediatering
;
12938 tmp
->transfertobusy
= conf
->chan
.transfertobusy
;
12939 tmp
->dialmode
= conf
->chan
.dialmode
;
12940 if (chan_sig
& __DAHDI_SIG_FXS
) {
12941 tmp
->mwimonitor_fsk
= conf
->chan
.mwimonitor_fsk
;
12942 tmp
->mwimonitor_neon
= conf
->chan
.mwimonitor_neon
;
12943 tmp
->mwimonitor_rpas
= conf
->chan
.mwimonitor_rpas
;
12945 tmp
->ringt_base
= ringt_base
;
12946 tmp
->firstradio
= 0;
12947 if ((chan_sig
== SIG_FXOKS
) || (chan_sig
== SIG_FXOLS
) || (chan_sig
== SIG_FXOGS
))
12948 tmp
->permcallwaiting
= conf
->chan
.callwaiting
;
12950 tmp
->permcallwaiting
= 0;
12951 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
12953 tmp
->drings
= conf
->chan
.drings
;
12955 /* 10 is a nice default. */
12956 if (tmp
->drings
.ringnum
[0].range
== 0)
12957 tmp
->drings
.ringnum
[0].range
= 10;
12958 if (tmp
->drings
.ringnum
[1].range
== 0)
12959 tmp
->drings
.ringnum
[1].range
= 10;
12960 if (tmp
->drings
.ringnum
[2].range
== 0)
12961 tmp
->drings
.ringnum
[2].range
= 10;
12963 tmp
->usedistinctiveringdetection
= usedistinctiveringdetection
;
12964 tmp
->callwaitingcallerid
= conf
->chan
.callwaitingcallerid
;
12965 tmp
->threewaycalling
= conf
->chan
.threewaycalling
;
12966 tmp
->threewaysilenthold
= conf
->chan
.threewaysilenthold
;
12967 tmp
->calledsubscriberheld
= conf
->chan
.calledsubscriberheld
; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
12968 tmp
->adsi
= conf
->chan
.adsi
;
12969 tmp
->use_smdi
= conf
->chan
.use_smdi
;
12970 tmp
->permhidecallerid
= conf
->chan
.hidecallerid
;
12971 tmp
->hidecalleridname
= conf
->chan
.hidecalleridname
;
12972 tmp
->callreturn
= conf
->chan
.callreturn
;
12973 tmp
->echocancel
= conf
->chan
.echocancel
;
12974 tmp
->echotraining
= conf
->chan
.echotraining
;
12975 tmp
->pulse
= conf
->chan
.pulse
;
12976 if (tmp
->echocancel
.head
.tap_length
) {
12977 tmp
->echocanbridged
= conf
->chan
.echocanbridged
;
12979 if (conf
->chan
.echocanbridged
)
12980 ast_log(LOG_NOTICE
, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
12981 tmp
->echocanbridged
= 0;
12983 tmp
->busydetect
= conf
->chan
.busydetect
;
12984 tmp
->busycount
= conf
->chan
.busycount
;
12985 tmp
->busy_cadence
= conf
->chan
.busy_cadence
;
12986 tmp
->callprogress
= conf
->chan
.callprogress
;
12987 tmp
->waitfordialtone
= conf
->chan
.waitfordialtone
;
12988 tmp
->dialtone_detect
= conf
->chan
.dialtone_detect
;
12989 tmp
->faxdetect_timeout
= conf
->chan
.faxdetect_timeout
;
12990 tmp
->firstdigit_timeout
= conf
->chan
.firstdigit_timeout
;
12991 tmp
->interdigit_timeout
= conf
->chan
.interdigit_timeout
;
12992 tmp
->matchdigit_timeout
= conf
->chan
.matchdigit_timeout
;
12993 tmp
->cancallforward
= conf
->chan
.cancallforward
;
12994 tmp
->dtmfrelax
= conf
->chan
.dtmfrelax
;
12995 tmp
->callwaiting
= tmp
->permcallwaiting
;
12996 tmp
->hidecallerid
= tmp
->permhidecallerid
;
12997 tmp
->channel
= channel
;
12998 tmp
->stripmsd
= conf
->chan
.stripmsd
;
12999 tmp
->use_callerid
= conf
->chan
.use_callerid
;
13000 tmp
->cid_signalling
= conf
->chan
.cid_signalling
;
13001 tmp
->cid_start
= conf
->chan
.cid_start
;
13002 tmp
->dahditrcallerid
= conf
->chan
.dahditrcallerid
;
13003 tmp
->restrictcid
= conf
->chan
.restrictcid
;
13004 tmp
->use_callingpres
= conf
->chan
.use_callingpres
;
13005 if (tmp
->usedistinctiveringdetection
) {
13006 if (!tmp
->use_callerid
) {
13007 ast_log(LOG_NOTICE
, "Distinctive Ring detect requires 'usecallerid' be on\n");
13008 tmp
->use_callerid
= 1;
13012 if (tmp
->cid_signalling
== CID_SIG_SMDI
) {
13013 if (!tmp
->use_smdi
) {
13014 ast_log(LOG_WARNING
, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13018 if (tmp
->use_smdi
) {
13019 tmp
->smdi_iface
= ast_smdi_interface_find(conf
->smdi_port
);
13020 if (!(tmp
->smdi_iface
)) {
13021 ast_log(LOG_ERROR
, "Invalid SMDI port specfied, disabling SMDI support\n");
13026 ast_copy_string(tmp
->accountcode
, conf
->chan
.accountcode
, sizeof(tmp
->accountcode
));
13027 tmp
->amaflags
= conf
->chan
.amaflags
;
13030 tmp
->propconfno
= -1;
13032 tmp
->canpark
= conf
->chan
.canpark
;
13033 tmp
->transfer
= conf
->chan
.transfer
;
13034 ast_copy_string(tmp
->defcontext
,conf
->chan
.context
,sizeof(tmp
->defcontext
));
13035 ast_copy_string(tmp
->language
, conf
->chan
.language
, sizeof(tmp
->language
));
13036 ast_copy_string(tmp
->mohinterpret
, conf
->chan
.mohinterpret
, sizeof(tmp
->mohinterpret
));
13037 ast_copy_string(tmp
->mohsuggest
, conf
->chan
.mohsuggest
, sizeof(tmp
->mohsuggest
));
13038 ast_copy_string(tmp
->context
, conf
->chan
.context
, sizeof(tmp
->context
));
13039 ast_copy_string(tmp
->description
, conf
->chan
.description
, sizeof(tmp
->description
));
13040 ast_copy_string(tmp
->parkinglot
, conf
->chan
.parkinglot
, sizeof(tmp
->parkinglot
));
13042 if (dahdi_analog_lib_handles(tmp
->sig
, tmp
->radio
, tmp
->oprmode
)) {
13043 ast_copy_string(tmp
->cid_num
, conf
->chan
.cid_num
, sizeof(tmp
->cid_num
));
13044 ast_copy_string(tmp
->cid_name
, conf
->chan
.cid_name
, sizeof(tmp
->cid_name
));
13046 tmp
->cid_num
[0] = '\0';
13047 tmp
->cid_name
[0] = '\0';
13049 #if defined(HAVE_PRI)
13050 if (dahdi_sig_pri_lib_handles(tmp
->sig
)) {
13051 tmp
->cid_tag
[0] = '\0';
13053 #endif /* defined(HAVE_PRI) */
13055 ast_copy_string(tmp
->cid_tag
, conf
->chan
.cid_tag
, sizeof(tmp
->cid_tag
));
13057 tmp
->cid_subaddr
[0] = '\0';
13058 ast_copy_string(tmp
->mailbox
, conf
->chan
.mailbox
, sizeof(tmp
->mailbox
));
13059 if (channel
!= CHAN_PSEUDO
&& !ast_strlen_zero(tmp
->mailbox
)) {
13060 /* This module does not handle MWI in an event-based manner. However, it
13061 * subscribes to MWI for each mailbox that is configured so that the core
13062 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13063 * event cache instead of checking the mailbox directly. */
13064 tmp
->mwi_event_sub
= ast_mwi_subscribe_pool(tmp
->mailbox
, stasis_subscription_cb_noop
, NULL
);
13066 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13067 tmp
->mwisend_setting
= conf
->chan
.mwisend_setting
;
13068 tmp
->mwisend_fsk
= conf
->chan
.mwisend_fsk
;
13069 tmp
->mwisend_rpas
= conf
->chan
.mwisend_rpas
;
13072 tmp
->group
= conf
->chan
.group
;
13073 tmp
->callgroup
= conf
->chan
.callgroup
;
13074 tmp
->pickupgroup
= conf
->chan
.pickupgroup
;
13075 ast_unref_namedgroups(tmp
->named_callgroups
);
13076 tmp
->named_callgroups
= ast_ref_namedgroups(conf
->chan
.named_callgroups
);
13077 ast_unref_namedgroups(tmp
->named_pickupgroups
);
13078 tmp
->named_pickupgroups
= ast_ref_namedgroups(conf
->chan
.named_pickupgroups
);
13079 if (conf
->chan
.vars
) {
13080 struct ast_variable
*v
, *tmpvar
;
13081 for (v
= conf
->chan
.vars
; v
; v
= v
->next
) {
13082 if ((tmpvar
= ast_variable_new(v
->name
, v
->value
, v
->file
))) {
13083 if (ast_variable_list_replace(&tmp
->vars
, tmpvar
)) {
13084 tmpvar
->next
= tmp
->vars
;
13085 tmp
->vars
= tmpvar
;
13090 tmp
->hwrxgain_enabled
= conf
->chan
.hwrxgain_enabled
;
13091 tmp
->hwtxgain_enabled
= conf
->chan
.hwtxgain_enabled
;
13092 tmp
->hwrxgain
= conf
->chan
.hwrxgain
;
13093 tmp
->hwtxgain
= conf
->chan
.hwtxgain
;
13094 tmp
->cid_rxgain
= conf
->chan
.cid_rxgain
;
13095 tmp
->rxgain
= conf
->chan
.rxgain
;
13096 tmp
->txgain
= conf
->chan
.txgain
;
13097 tmp
->txdrc
= conf
->chan
.txdrc
;
13098 tmp
->rxdrc
= conf
->chan
.rxdrc
;
13099 tmp
->tonezone
= conf
->chan
.tonezone
;
13100 if (tmp
->subs
[SUB_REAL
].dfd
> -1) {
13101 if (tmp
->hwrxgain_enabled
) {
13102 tmp
->hwrxgain_enabled
= !set_hwgain(tmp
->subs
[SUB_REAL
].dfd
, tmp
->hwrxgain
, 0);
13104 if (tmp
->hwtxgain_enabled
) {
13105 tmp
->hwtxgain_enabled
= !set_hwgain(tmp
->subs
[SUB_REAL
].dfd
, tmp
->hwtxgain
, 1);
13107 set_actual_gain(tmp
->subs
[SUB_REAL
].dfd
, tmp
->rxgain
, tmp
->txgain
, tmp
->rxdrc
, tmp
->txdrc
, tmp
->law
);
13109 ast_dsp_set_digitmode(tmp
->dsp
, DSP_DIGITMODE_DTMF
| tmp
->dtmfrelax
);
13110 dahdi_conf_update(tmp
);
13112 switch (chan_sig
) {
13113 case SIG_PRI_LIB_HANDLE_CASES
:
13118 /* Hang it up to be sure it's good */
13119 dahdi_set_hook(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_ONHOOK
);
13123 ioctl(tmp
->subs
[SUB_REAL
].dfd
,DAHDI_SETTONEZONE
,&tmp
->tonezone
);
13124 if ((res
= get_alarms(tmp
)) != DAHDI_ALARM_NONE
) {
13125 /* the dchannel is down so put the channel in alarm */
13126 switch (tmp
->sig
) {
13128 case SIG_PRI_LIB_HANDLE_CASES
:
13129 sig_pri_set_alarm(tmp
->sig_pvt
, 1);
13132 #if defined(HAVE_SS7)
13134 sig_ss7_set_alarm(tmp
->sig_pvt
, 1);
13136 #endif /* defined(HAVE_SS7) */
13138 /* The only sig submodule left should be sig_analog. */
13139 analog_p
= tmp
->sig_pvt
;
13141 analog_p
->inalarm
= 1;
13146 handle_alarms(tmp
, res
);
13150 tmp
->polarityonanswerdelay
= conf
->chan
.polarityonanswerdelay
;
13151 tmp
->answeronpolarityswitch
= conf
->chan
.answeronpolarityswitch
;
13152 tmp
->ani_info_digits
= conf
->chan
.ani_info_digits
;
13153 tmp
->ani_wink_time
= conf
->chan
.ani_wink_time
;
13154 tmp
->ani_timeout
= conf
->chan
.ani_timeout
;
13155 tmp
->hanguponpolarityswitch
= conf
->chan
.hanguponpolarityswitch
;
13156 tmp
->reoriginate
= conf
->chan
.reoriginate
;
13157 tmp
->sendcalleridafter
= conf
->chan
.sendcalleridafter
;
13158 ast_cc_copy_config_params(tmp
->cc_params
, conf
->chan
.cc_params
);
13161 tmp
->locallyblocked
= 0;
13162 tmp
->remotelyblocked
= 0;
13163 switch (tmp
->sig
) {
13164 #if defined(HAVE_PRI)
13165 case SIG_PRI_LIB_HANDLE_CASES
:
13166 tmp
->inservice
= 1;/* Inservice until actually implemented. */
13167 #if defined(HAVE_PRI_SERVICE_MESSAGES)
13168 ((struct sig_pri_chan
*) tmp
->sig_pvt
)->service_status
= 0;
13169 if (chan_sig
== SIG_PRI
) {
13170 char db_chan_name
[20];
13174 * Initialize the active out-of-service status
13175 * and delete any record if the feature is not enabled.
13177 snprintf(db_chan_name
, sizeof(db_chan_name
), "%s/%d:%d", dahdi_db
, tmp
->span
, tmp
->channel
);
13178 if (!ast_db_get(db_chan_name
, SRVST_DBKEY
, db_answer
, sizeof(db_answer
))) {
13181 why
= &((struct sig_pri_chan
*) tmp
->sig_pvt
)->service_status
;
13182 if (tmp
->pri
->enable_service_message_support
) {
13185 sscanf(db_answer
, "%1c:%30u", &state
, why
);
13187 /* Ensure that only the implemented bits could be set.*/
13188 *why
&= (SRVST_NEAREND
| SRVST_FAREND
);
13191 ast_db_del(db_chan_name
, SRVST_DBKEY
);
13195 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13197 #endif /* defined(HAVE_PRI) */
13198 #if defined(HAVE_SS7)
13200 tmp
->inservice
= 0;
13201 if (tmp
->ss7
->flags
& LINKSET_FLAG_INITIALHWBLO
) {
13202 tmp
->remotelyblocked
|= SS7_BLOCKED_HARDWARE
;
13205 #endif /* defined(HAVE_SS7) */
13207 /* We default to in service on protocols that don't have a reset */
13208 tmp
->inservice
= 1;
13213 switch (tmp
->sig
) {
13214 #if defined(HAVE_PRI)
13215 case SIG_PRI_LIB_HANDLE_CASES
:
13217 pri_chan
->channel
= tmp
->channel
;
13218 pri_chan
->hidecallerid
= tmp
->hidecallerid
;
13219 pri_chan
->hidecalleridname
= tmp
->hidecalleridname
;
13220 pri_chan
->immediate
= tmp
->immediate
;
13221 pri_chan
->inalarm
= tmp
->inalarm
;
13222 pri_chan
->priexclusive
= tmp
->priexclusive
;
13223 pri_chan
->priindication_oob
= tmp
->priindication_oob
;
13224 pri_chan
->use_callerid
= tmp
->use_callerid
;
13225 pri_chan
->use_callingpres
= tmp
->use_callingpres
;
13226 ast_copy_string(pri_chan
->context
, tmp
->context
,
13227 sizeof(pri_chan
->context
));
13228 ast_copy_string(pri_chan
->mohinterpret
, tmp
->mohinterpret
,
13229 sizeof(pri_chan
->mohinterpret
));
13230 pri_chan
->stripmsd
= tmp
->stripmsd
;
13233 #endif /* defined(HAVE_PRI) */
13234 #if defined(HAVE_SS7)
13237 ss7_chan
->inalarm
= tmp
->inalarm
;
13238 ss7_chan
->inservice
= tmp
->inservice
;
13240 ss7_chan
->stripmsd
= tmp
->stripmsd
;
13241 ss7_chan
->hidecallerid
= tmp
->hidecallerid
;
13242 ss7_chan
->use_callerid
= tmp
->use_callerid
;
13243 ss7_chan
->use_callingpres
= tmp
->use_callingpres
;
13244 ss7_chan
->immediate
= tmp
->immediate
;
13245 ss7_chan
->locallyblocked
= tmp
->locallyblocked
;
13246 ss7_chan
->remotelyblocked
= tmp
->remotelyblocked
;
13247 ast_copy_string(ss7_chan
->context
, tmp
->context
,
13248 sizeof(ss7_chan
->context
));
13249 ast_copy_string(ss7_chan
->mohinterpret
, tmp
->mohinterpret
,
13250 sizeof(ss7_chan
->mohinterpret
));
13253 #endif /* defined(HAVE_SS7) */
13255 /* The only sig submodule left should be sig_analog. */
13256 analog_p
= tmp
->sig_pvt
;
13258 analog_p
->channel
= tmp
->channel
;
13259 analog_p
->polarityonanswerdelay
= conf
->chan
.polarityonanswerdelay
;
13260 analog_p
->answeronpolarityswitch
= conf
->chan
.answeronpolarityswitch
;
13261 analog_p
->ani_info_digits
= conf
->chan
.ani_info_digits
;
13262 analog_p
->ani_timeout
= conf
->chan
.ani_timeout
;
13263 analog_p
->ani_wink_time
= conf
->chan
.ani_wink_time
;
13264 analog_p
->hanguponpolarityswitch
= conf
->chan
.hanguponpolarityswitch
;
13265 analog_p
->permcallwaiting
= conf
->chan
.callwaiting
; /* permcallwaiting possibly modified in analog_config_complete */
13266 analog_p
->calledsubscriberheld
= conf
->chan
.calledsubscriberheld
; /* Only actually used in analog pvt, not DAHDI pvt */
13267 analog_p
->callreturn
= conf
->chan
.callreturn
;
13268 analog_p
->cancallforward
= conf
->chan
.cancallforward
;
13269 analog_p
->canpark
= conf
->chan
.canpark
;
13270 analog_p
->dahditrcallerid
= conf
->chan
.dahditrcallerid
;
13271 analog_p
->immediate
= conf
->chan
.immediate
;
13272 analog_p
->immediatering
= conf
->chan
.immediatering
;
13273 analog_p
->permhidecallerid
= conf
->chan
.hidecallerid
; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13274 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13275 analog_p
->pulse
= conf
->chan
.pulse
;
13276 analog_p
->threewaycalling
= conf
->chan
.threewaycalling
;
13277 analog_p
->transfer
= conf
->chan
.transfer
;
13278 analog_p
->transfertobusy
= conf
->chan
.transfertobusy
;
13279 analog_p
->dialmode
= conf
->chan
.dialmode
;
13280 analog_p
->use_callerid
= tmp
->use_callerid
;
13281 analog_p
->usedistinctiveringdetection
= tmp
->usedistinctiveringdetection
;
13282 analog_p
->use_smdi
= tmp
->use_smdi
;
13283 analog_p
->smdi_iface
= tmp
->smdi_iface
;
13284 analog_p
->outsigmod
= ANALOG_SIG_NONE
;
13285 analog_p
->echotraining
= conf
->chan
.echotraining
;
13286 analog_p
->cid_signalling
= conf
->chan
.cid_signalling
;
13287 analog_p
->stripmsd
= conf
->chan
.stripmsd
;
13288 switch (conf
->chan
.cid_start
) {
13289 case CID_START_POLARITY
:
13290 analog_p
->cid_start
= ANALOG_CID_START_POLARITY
;
13292 case CID_START_POLARITY_IN
:
13293 analog_p
->cid_start
= ANALOG_CID_START_POLARITY_IN
;
13295 case CID_START_DTMF_NOALERT
:
13296 analog_p
->cid_start
= ANALOG_CID_START_DTMF_NOALERT
;
13299 analog_p
->cid_start
= ANALOG_CID_START_RING
;
13302 analog_p
->callwaitingcallerid
= conf
->chan
.callwaitingcallerid
;
13303 analog_p
->ringt
= conf
->chan
.ringt
;
13304 analog_p
->ringt_base
= ringt_base
;
13305 analog_p
->onhooktime
= time(NULL
);
13306 if (chan_sig
& __DAHDI_SIG_FXO
) {
13307 memset(&p
, 0, sizeof(p
));
13308 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &p
);
13310 analog_p
->fxsoffhookstate
= p
.rxisoffhook
;
13312 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13313 res
= ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_VMWI_CONFIG
, &tmp
->mwisend_setting
);
13316 analog_p
->msgstate
= -1;
13318 ast_copy_string(analog_p
->mohsuggest
, conf
->chan
.mohsuggest
, sizeof(analog_p
->mohsuggest
));
13319 ast_copy_string(analog_p
->cid_num
, conf
->chan
.cid_num
, sizeof(analog_p
->cid_num
));
13320 ast_copy_string(analog_p
->cid_name
, conf
->chan
.cid_name
, sizeof(analog_p
->cid_name
));
13322 analog_config_complete(analog_p
);
13326 #if defined(HAVE_PRI)
13327 if (tmp
->channel
== CHAN_PSEUDO
) {
13329 * Save off pseudo channel buffer policy values for dynamic creation of
13330 * no B channel interfaces.
13332 dahdi_pseudo_parms
.buf_no
= tmp
->buf_no
;
13333 dahdi_pseudo_parms
.buf_policy
= tmp
->buf_policy
;
13334 dahdi_pseudo_parms
.faxbuf_no
= tmp
->faxbuf_no
;
13335 dahdi_pseudo_parms
.faxbuf_policy
= tmp
->faxbuf_policy
;
13337 #endif /* defined(HAVE_PRI) */
13339 if (tmp
&& !here
) {
13340 /* Add the new channel interface to the sorted channel interface list. */
13341 dahdi_iflist_insert(tmp
);
13346 static int is_group_or_channel_match(struct dahdi_pvt
*p
, int span
, ast_group_t groupmatch
, int *groupmatched
, int channelmatch
, int *channelmatched
)
13348 #if defined(HAVE_PRI)
13350 /* The channel must be on the specified PRI span. */
13351 if (!p
->pri
|| p
->pri
->span
!= span
) {
13354 if (!groupmatch
&& channelmatch
== -1) {
13355 /* Match any group since it only needs to be on the PRI span. */
13360 #endif /* defined(HAVE_PRI) */
13361 /* check group matching */
13363 if ((p
->group
& groupmatch
) != groupmatch
)
13364 /* Doesn't match the specified group, try the next one */
13368 /* Check to see if we have a channel match */
13369 if (channelmatch
!= -1) {
13370 if (p
->channel
!= channelmatch
)
13371 /* Doesn't match the specified channel, try the next one */
13373 *channelmatched
= 1;
13379 static int available(struct dahdi_pvt
**pvt
, int is_specific_channel
)
13381 struct dahdi_pvt
*p
= *pvt
;
13386 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
))
13387 return analog_available(p
->sig_pvt
);
13390 #if defined(HAVE_PRI)
13391 case SIG_PRI_LIB_HANDLE_CASES
:
13393 struct sig_pri_chan
*pvt_chan
;
13396 pvt_chan
= p
->sig_pvt
;
13397 res
= sig_pri_available(&pvt_chan
, is_specific_channel
);
13398 *pvt
= pvt_chan
->chan_pvt
;
13401 #endif /* defined(HAVE_PRI) */
13402 #if defined(HAVE_SS7)
13404 return sig_ss7_available(p
->sig_pvt
);
13405 #endif /* defined(HAVE_SS7) */
13410 if (p
->locallyblocked
|| p
->remotelyblocked
) {
13414 /* If no owner definitely available */
13419 if (p
->mfcr2call
) {
13432 #if defined(HAVE_PRI)
13433 #if defined(HAVE_PRI_CALL_WAITING)
13436 * \brief Init the private channel configuration using the span controller.
13439 * \param priv Channel to init the configuration.
13440 * \param pri sig_pri PRI control structure.
13442 * \note Assumes the pri->lock is already obtained.
13444 static void my_pri_init_config(void *priv
, struct sig_pri_span
*pri
)
13446 struct dahdi_pvt
*pvt
= priv
;
13448 pvt
->stripmsd
= pri
->ch_cfg
.stripmsd
;
13449 pvt
->hidecallerid
= pri
->ch_cfg
.hidecallerid
;
13450 pvt
->hidecalleridname
= pri
->ch_cfg
.hidecalleridname
;
13451 pvt
->immediate
= pri
->ch_cfg
.immediate
;
13452 pvt
->priexclusive
= pri
->ch_cfg
.priexclusive
;
13453 pvt
->priindication_oob
= pri
->ch_cfg
.priindication_oob
;
13454 pvt
->use_callerid
= pri
->ch_cfg
.use_callerid
;
13455 pvt
->use_callingpres
= pri
->ch_cfg
.use_callingpres
;
13456 ast_copy_string(pvt
->context
, pri
->ch_cfg
.context
, sizeof(pvt
->context
));
13457 ast_copy_string(pvt
->mohinterpret
, pri
->ch_cfg
.mohinterpret
, sizeof(pvt
->mohinterpret
));
13459 #endif /* defined(HAVE_PRI_CALL_WAITING) */
13460 #endif /* defined(HAVE_PRI) */
13462 #if defined(HAVE_PRI)
13465 * \brief Create a no B channel interface.
13468 * \param pri sig_pri span controller to add interface.
13470 * \note Assumes the pri->lock is already obtained.
13472 * \retval array-index into private pointer array on success.
13473 * \retval -1 on error.
13475 static int dahdi_new_pri_nobch_channel(struct sig_pri_span
*pri
)
13480 struct dahdi_pvt
*pvt
;
13481 struct sig_pri_chan
*chan
;
13482 struct dahdi_bufferinfo bi
;
13484 static int nobch_channel
= CHAN_PSEUDO
;
13486 /* Find spot in the private pointer array for new interface. */
13487 for (pvt_idx
= 0; pvt_idx
< pri
->numchans
; ++pvt_idx
) {
13488 if (!pri
->pvts
[pvt_idx
]) {
13492 if (pri
->numchans
== pvt_idx
) {
13493 if (ARRAY_LEN(pri
->pvts
) <= pvt_idx
) {
13494 ast_log(LOG_ERROR
, "Unable to add a no-B-channel interface!\n");
13498 /* Add new spot to the private pointer array. */
13499 pri
->pvts
[pvt_idx
] = NULL
;
13503 pvt
= ast_calloc(1, sizeof(*pvt
));
13507 pvt
->cc_params
= ast_cc_config_params_init();
13508 if (!pvt
->cc_params
) {
13512 ast_mutex_init(&pvt
->lock
);
13513 for (idx
= 0; idx
< ARRAY_LEN(pvt
->subs
); ++idx
) {
13514 pvt
->subs
[idx
].dfd
= -1;
13516 pvt
->buf_no
= dahdi_pseudo_parms
.buf_no
;
13517 pvt
->buf_policy
= dahdi_pseudo_parms
.buf_policy
;
13518 pvt
->faxbuf_no
= dahdi_pseudo_parms
.faxbuf_no
;
13519 pvt
->faxbuf_policy
= dahdi_pseudo_parms
.faxbuf_policy
;
13521 chan
= sig_pri_chan_new(pvt
, pri
, 0, 0, 0);
13523 destroy_dahdi_pvt(pvt
);
13526 chan
->no_b_channel
= 1;
13529 * Pseudo channel companding law.
13530 * Needed for outgoing call waiting calls.
13531 * XXX May need to make this determined by switchtype or user option.
13533 pvt
->law_default
= DAHDI_LAW_ALAW
;
13535 pvt
->sig
= pri
->sig
;
13536 pvt
->outsigmod
= -1;
13538 pvt
->sig_pvt
= chan
;
13539 pri
->pvts
[pvt_idx
] = chan
;
13541 pvt
->subs
[SUB_REAL
].dfd
= dahdi_open("/dev/dahdi/pseudo");
13542 if (pvt
->subs
[SUB_REAL
].dfd
< 0) {
13543 ast_log(LOG_ERROR
, "Unable to open no B channel interface pseudo channel: %s\n",
13545 destroy_dahdi_pvt(pvt
);
13548 memset(&bi
, 0, sizeof(bi
));
13549 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
13551 pvt
->bufsize
= bi
.bufsize
;
13552 bi
.txbufpolicy
= pvt
->buf_policy
;
13553 bi
.rxbufpolicy
= pvt
->buf_policy
;
13554 bi
.numbufs
= pvt
->buf_no
;
13555 res
= ioctl(pvt
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
13557 ast_log(LOG_WARNING
,
13558 "Unable to set buffer policy on no B channel interface: %s\n",
13562 ast_log(LOG_WARNING
,
13563 "Unable to check buffer policy on no B channel interface: %s\n",
13567 if (CHAN_PSEUDO
< nobch_channel
) {
13568 nobch_channel
= CHAN_PSEUDO
- 1;
13570 pvt
->channel
= nobch_channel
;
13571 pvt
->span
= pri
->span
;
13572 chan
->channel
= pvt
->channel
;
13574 dahdi_nobch_insert(pri
, pvt
);
13578 #endif /* defined(HAVE_PRI) */
13580 /* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13581 structures; it makes no attempt to safely copy regular channel private
13582 structures that might contain reference-counted object pointers and other
13585 static struct dahdi_pvt
*duplicate_pseudo(struct dahdi_pvt
*src
)
13587 struct dahdi_pvt
*p
;
13588 struct dahdi_bufferinfo bi
;
13591 p
= ast_malloc(sizeof(*p
));
13597 /* Must deep copy the cc_params. */
13598 p
->cc_params
= ast_cc_config_params_init();
13599 if (!p
->cc_params
) {
13603 ast_cc_copy_config_params(p
->cc_params
, src
->cc_params
);
13605 p
->which_iflist
= DAHDI_IFLIST_NONE
;
13608 ast_mutex_init(&p
->lock
);
13609 p
->subs
[SUB_REAL
].dfd
= dahdi_open("/dev/dahdi/pseudo");
13610 if (p
->subs
[SUB_REAL
].dfd
< 0) {
13611 ast_log(LOG_ERROR
, "Unable to dup channel: %s\n", strerror(errno
));
13612 destroy_dahdi_pvt(p
);
13615 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_GET_BUFINFO
, &bi
);
13617 bi
.txbufpolicy
= src
->buf_policy
;
13618 bi
.rxbufpolicy
= src
->buf_policy
;
13619 bi
.numbufs
= src
->buf_no
;
13620 res
= ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_SET_BUFINFO
, &bi
);
13622 ast_log(LOG_WARNING
, "Unable to set buffer policy on dup channel: %s\n", strerror(errno
));
13625 ast_log(LOG_WARNING
, "Unable to check buffer policy on dup channel: %s\n", strerror(errno
));
13627 dahdi_iflist_insert(p
);
13631 struct dahdi_starting_point
{
13632 /*! Group matching mask. Zero if not specified. */
13633 ast_group_t groupmatch
;
13634 /*! DAHDI channel to match with. -1 if not specified. */
13636 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13637 int rr_starting_point
;
13638 /*! ISDN span where channels can be picked (Zero if not specified) */
13640 /*! Analog channel distinctive ring cadence index. */
13642 /*! Dialing option. c/r/d if present and valid. */
13644 /*! TRUE if to search the channel list backwards. */
13646 /*! TRUE if search is done with round robin sequence. */
13649 static struct dahdi_pvt
*determine_starting_point(const char *data
, struct dahdi_starting_point
*param
)
13655 struct dahdi_pvt
*p
;
13656 char *subdir
= NULL
;
13657 AST_DECLARE_APP_ARGS(args
,
13658 AST_APP_ARG(group
); /* channel/group token */
13659 //AST_APP_ARG(ext); /* extension token */
13660 //AST_APP_ARG(opts); /* options token */
13661 AST_APP_ARG(other
); /* Any remining unused arguments */
13666 * Dial(DAHDI/pseudo[/extension[/options]])
13667 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13668 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13669 * Dial(DAHDI/i<span>[/extension[/options]])
13670 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13672 * i - ISDN span channel restriction.
13673 * Used by CC to ensure that the CC recall goes out the same span.
13674 * Also to make ISDN channel names dialable when the sequence number
13675 * is stripped off. (Used by DTMF attended transfer feature.)
13677 * g - channel group allocation search forward
13678 * G - channel group allocation search backward
13679 * r - channel group allocation round robin search forward
13680 * R - channel group allocation round robin search backward
13682 * c - Wait for DTMF digit to confirm answer
13683 * r<cadence#> - Set distinctive ring cadence number
13684 * d - Force bearer capability for ISDN/SS7 call to digital.
13688 dest
= ast_strdupa(data
);
13690 ast_log(LOG_WARNING
, "Channel requested with no data\n");
13693 AST_NONSTANDARD_APP_ARGS(args
, dest
, '/');
13694 if (!args
.argc
|| ast_strlen_zero(args
.group
)) {
13695 ast_log(LOG_WARNING
, "No channel/group specified\n");
13699 /* Initialize the output parameters */
13700 memset(param
, 0, sizeof(*param
));
13701 param
->channelmatch
= -1;
13703 if (strchr(args
.group
, '!') != NULL
) {
13704 char *prev
= args
.group
;
13705 while ((s
= strchr(prev
, '!')) != NULL
) {
13709 *(prev
- 1) = '\0';
13710 subdir
= args
.group
;
13712 } else if (args
.group
[0] == 'i') {
13713 /* Extract the ISDN span channel restriction specifier. */
13714 res
= sscanf(args
.group
+ 1, "%30d", &x
);
13716 ast_log(LOG_WARNING
, "Unable to determine ISDN span for data %s\n", data
);
13721 /* Remove the ISDN span channel restriction specifier. */
13722 s
= strchr(args
.group
, '-');
13724 /* Search all groups since we are ISDN span restricted. */
13727 args
.group
= s
+ 1;
13730 if (toupper(args
.group
[0]) == 'G' || toupper(args
.group
[0])=='R') {
13731 /* Retrieve the group number */
13732 s
= args
.group
+ 1;
13733 res
= sscanf(s
, "%30d%1c%30d", &x
, ¶m
->opt
, ¶m
->cadence
);
13735 ast_log(LOG_WARNING
, "Unable to determine group for data %s\n", data
);
13738 param
->groupmatch
= ((ast_group_t
) 1 << x
);
13740 if (toupper(args
.group
[0]) == 'G') {
13741 if (args
.group
[0] == 'G') {
13742 param
->backwards
= 1;
13747 if (ARRAY_LEN(round_robin
) <= x
) {
13748 ast_log(LOG_WARNING
, "Round robin index %d out of range for data %s\n",
13752 if (args
.group
[0] == 'R') {
13753 param
->backwards
= 1;
13754 p
= round_robin
[x
] ? round_robin
[x
]->prev
: ifend
;
13758 p
= round_robin
[x
] ? round_robin
[x
]->next
: iflist
;
13762 param
->roundrobin
= 1;
13763 param
->rr_starting_point
= x
;
13767 if (!strcasecmp(s
, "pseudo")) {
13768 /* Special case for pseudo */
13770 param
->channelmatch
= x
;
13772 res
= sscanf(s
, "%30d%1c%30d", &x
, ¶m
->opt
, ¶m
->cadence
);
13774 ast_log(LOG_WARNING
, "Unable to determine channel for data %s\n", data
);
13777 param
->channelmatch
= x
;
13781 char path
[PATH_MAX
];
13784 snprintf(path
, sizeof(path
), "/dev/dahdi/%s/%d",
13785 subdir
, param
->channelmatch
);
13786 if (stat(path
, &stbuf
) < 0) {
13787 ast_log(LOG_WARNING
, "stat(%s) failed: %s\n",
13788 path
, strerror(errno
));
13791 if (!S_ISCHR(stbuf
.st_mode
)) {
13792 ast_log(LOG_ERROR
, "%s: Not a character device file\n",
13796 param
->channelmatch
= minor(stbuf
.st_rdev
);
13802 if (param
->opt
== 'r' && res
< 3) {
13803 ast_log(LOG_WARNING
, "Distinctive ring missing identifier in '%s'\n", data
);
13810 static struct ast_channel
*dahdi_request(const char *type
, struct ast_format_cap
*cap
,
13811 const struct ast_assigned_ids
*assignedids
, const struct ast_channel
*requestor
,
13812 const char *data
, int *cause
)
13815 struct dahdi_pvt
*p
;
13816 struct ast_channel
*tmp
= NULL
;
13817 struct dahdi_pvt
*exitpvt
;
13818 int channelmatched
= 0;
13819 int foundowner
= 0;
13820 int groupmatched
= 0;
13821 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13822 int transcapdigital
= 0;
13823 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
13824 struct dahdi_starting_point start
;
13825 ast_callid callid
= 0;
13826 int callid_created
= ast_callid_threadstorage_auto(&callid
);
13828 ast_mutex_lock(&iflock
);
13829 p
= determine_starting_point(data
, &start
);
13831 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
13832 ast_mutex_unlock(&iflock
);
13833 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
13837 /* Search for an unowned channel */
13839 while (p
&& !tmp
) {
13840 if (start
.roundrobin
)
13841 round_robin
[start
.rr_starting_point
] = p
;
13847 if (is_group_or_channel_match(p
, start
.span
, start
.groupmatch
, &groupmatched
, start
.channelmatch
, &channelmatched
)
13848 && available(&p
, channelmatched
)) {
13849 ast_debug(1, "Using channel %d\n", p
->channel
);
13851 callwait
= (p
->owner
!= NULL
);
13854 ast_mutex_lock(&p
->lock
);
13855 if (p
->mfcr2call
) {
13856 ast_mutex_unlock(&p
->lock
);
13857 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p
->channel
);
13861 ast_mutex_unlock(&p
->lock
);
13864 if (p
->channel
== CHAN_PSEUDO
) {
13865 p
= duplicate_pseudo(p
);
13871 p
->distinctivering
= 0;
13872 /* Make special notes */
13873 switch (start
.opt
) {
13875 /* No option present. */
13878 /* Confirm answer */
13879 p
->confirmanswer
= 1;
13882 /* Distinctive ring */
13883 p
->distinctivering
= start
.cadence
;
13886 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13887 /* If this is an ISDN call, make it digital */
13888 transcapdigital
= AST_TRANS_CAP_DIGITAL
;
13889 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
13892 ast_log(LOG_WARNING
, "Unknown option '%c' in '%s'\n", start
.opt
, data
);
13897 if (dahdi_analog_lib_handles(p
->sig
, p
->radio
, p
->oprmode
)) {
13898 tmp
= analog_request(p
->sig_pvt
, &callwait
, requestor
);
13900 } else if (dahdi_sig_pri_lib_handles(p
->sig
)) {
13902 * We already have the B channel reserved for this call. We
13903 * just need to make sure that dahdi_hangup() has completed
13904 * cleaning up before continuing.
13906 ast_mutex_lock(&p
->lock
);
13907 ast_mutex_unlock(&p
->lock
);
13909 sig_pri_extract_called_num_subaddr(p
->sig_pvt
, data
, p
->dnid
,
13911 tmp
= sig_pri_request(p
->sig_pvt
, SIG_PRI_DEFLAW
, assignedids
, requestor
, transcapdigital
);
13913 #if defined(HAVE_SS7)
13914 } else if (p
->sig
== SIG_SS7
) {
13915 tmp
= sig_ss7_request(p
->sig_pvt
, SIG_SS7_DEFLAW
, assignedids
, requestor
, transcapdigital
);
13916 #endif /* defined(HAVE_SS7) */
13918 tmp
= dahdi_new(p
, AST_STATE_RESERVED
, 0, p
->owner
? SUB_CALLWAIT
: SUB_REAL
, 0, assignedids
, requestor
, callid
);
13922 #if defined(HAVE_PRI)
13924 case SIG_PRI_LIB_HANDLE_CASES
:
13925 #if defined(HAVE_PRI_CALL_WAITING)
13926 if (((struct sig_pri_chan
*) p
->sig_pvt
)->is_call_waiting
) {
13927 ((struct sig_pri_chan
*) p
->sig_pvt
)->is_call_waiting
= 0;
13928 ast_atomic_fetchadd_int(&p
->pri
->num_call_waiting_calls
, -1);
13930 #endif /* defined(HAVE_PRI_CALL_WAITING) */
13932 * This should be the last thing to clear when we are done with
13935 ((struct sig_pri_chan
*) p
->sig_pvt
)->allocated
= 0;
13940 #endif /* defined(HAVE_PRI) */
13942 snprintf(p
->dialstring
, sizeof(p
->dialstring
), "DAHDI/%s", data
);
13949 if (start
.backwards
) {
13958 /* stop when you roll to the one that we started from */
13962 ast_mutex_unlock(&iflock
);
13964 if (cause
&& !tmp
) {
13965 if (callwait
|| (channelmatched
&& foundowner
)) {
13966 *cause
= AST_CAUSE_BUSY
;
13967 } else if (groupmatched
) {
13968 *cause
= AST_CAUSE_CONGESTION
;
13971 * We did not match any channel requested.
13972 * Dialplan error requesting non-existant channel?
13977 ast_callid_threadstorage_auto_clean(callid
, callid_created
);
13983 * \brief Determine the device state for a given DAHDI device if we can.
13986 * \param data DAHDI device name after "DAHDI/".
13988 * \retval device_state enum ast_device_state value.
13989 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
13991 static int dahdi_devicestate(const char *data
)
13993 #if defined(HAVE_PRI)
13994 const char *device
;
14000 if (*device
!= 'I') {
14001 /* The request is not for an ISDN span device. */
14002 return AST_DEVICE_UNKNOWN
;
14004 res
= sscanf(device
, "I%30u", &span
);
14005 if (res
!= 1 || !span
|| NUM_SPANS
< span
) {
14006 /* Bad format for ISDN span device name. */
14007 return AST_DEVICE_UNKNOWN
;
14009 device
= strchr(device
, '/');
14011 /* Bad format for ISDN span device name. */
14012 return AST_DEVICE_UNKNOWN
;
14016 * Since there are currently no other span devstate's defined,
14017 * it must be congestion.
14019 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14021 if (!strcmp(device
, "congestion"))
14022 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14024 return pris
[span
- 1].pri
.congestion_devstate
;
14026 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14027 else if (!strcmp(device
, "threshold")) {
14028 return pris
[span
- 1].pri
.threshold_devstate
;
14030 return AST_DEVICE_UNKNOWN
;
14031 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14033 return AST_DEVICE_UNKNOWN
;
14034 #endif /* defined(HAVE_PRI) */
14038 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14041 * \param inbound Incoming asterisk channel.
14042 * \param dest Same dial string passed to dahdi_request().
14043 * \param callback Callback into CC core to announce a busy channel available for CC.
14046 * This callback acts like a forked dial with all prongs of the fork busy.
14047 * Essentially, for each channel that could have taken the call, indicate that
14050 * \retval 0 on success.
14051 * \retval -1 on error.
14053 static int dahdi_cc_callback(struct ast_channel
*inbound
, const char *dest
, ast_cc_callback_fn callback
)
14055 struct dahdi_pvt
*p
;
14056 struct dahdi_pvt
*exitpvt
;
14057 struct dahdi_starting_point start
;
14058 int groupmatched
= 0;
14059 int channelmatched
= 0;
14061 ast_mutex_lock(&iflock
);
14062 p
= determine_starting_point(dest
, &start
);
14064 ast_mutex_unlock(&iflock
);
14069 if (is_group_or_channel_match(p
, start
.span
, start
.groupmatch
, &groupmatched
, start
.channelmatch
, &channelmatched
)) {
14070 /* We found a potential match. call the callback */
14071 struct ast_str
*device_name
;
14073 const char *monitor_type
;
14074 char dialstring
[AST_CHANNEL_NAME
];
14075 char full_device_name
[AST_CHANNEL_NAME
];
14077 switch (ast_get_cc_monitor_policy(p
->cc_params
)) {
14078 case AST_CC_MONITOR_NEVER
:
14080 case AST_CC_MONITOR_NATIVE
:
14081 case AST_CC_MONITOR_ALWAYS
:
14082 case AST_CC_MONITOR_GENERIC
:
14083 #if defined(HAVE_PRI)
14084 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
14086 * ISDN is in a trunk busy condition so we need to monitor
14087 * the span congestion device state.
14089 snprintf(full_device_name
, sizeof(full_device_name
),
14090 "DAHDI/I%d/congestion", p
->pri
->span
);
14092 #endif /* defined(HAVE_PRI) */
14094 #if defined(HAVE_PRI)
14095 device_name
= create_channel_name(p
, 1, "");
14097 device_name
= create_channel_name(p
);
14098 #endif /* defined(HAVE_PRI) */
14099 snprintf(full_device_name
, sizeof(full_device_name
), "DAHDI/%s",
14100 device_name
? ast_str_buffer(device_name
) : "");
14101 ast_free(device_name
);
14103 * The portion after the '-' in the channel name is either a random
14104 * number, a sequence number, or a subchannel number. None are
14105 * necessary so strip them off.
14107 dash
= strrchr(full_device_name
, '-');
14112 snprintf(dialstring
, sizeof(dialstring
), "DAHDI/%s", dest
);
14115 * Analog can only do generic monitoring.
14116 * ISDN is in a trunk busy condition and any "device" is going
14117 * to be busy until a B channel becomes available. The generic
14118 * monitor can do this task.
14120 monitor_type
= AST_CC_GENERIC_MONITOR_TYPE
;
14122 #if defined(HAVE_PRI)
14123 p
->pri
? p
->pri
->cc_params
: p
->cc_params
,
14126 #endif /* defined(HAVE_PRI) */
14127 monitor_type
, full_device_name
, dialstring
, NULL
);
14131 p
= start
.backwards
? p
->prev
: p
->next
;
14133 p
= start
.backwards
? ifend
: iflist
;
14135 if (p
== exitpvt
) {
14139 ast_mutex_unlock(&iflock
);
14143 #if defined(HAVE_SS7)
14144 static void dahdi_ss7_message(struct ss7
*ss7
, char *s
)
14149 for (i
= 0; i
< NUM_SPANS
; i
++) {
14150 if (linksets
[i
].ss7
.ss7
== ss7
) {
14151 ast_verbose_callid(0, "[%d] %s", i
+ 1, s
);
14156 ast_verbose_callid(0, "%s", s
);
14158 #endif /* defined(HAVE_SS7) */
14160 #if defined(HAVE_SS7)
14161 static void dahdi_ss7_error(struct ss7
*ss7
, char *s
)
14166 for (i
= 0; i
< NUM_SPANS
; i
++) {
14167 if (linksets
[i
].ss7
.ss7
== ss7
) {
14168 ast_log_callid(LOG_ERROR
, 0, "[%d] %s", i
+ 1, s
);
14173 ast_log_callid(LOG_ERROR
, 0, "%s", s
);
14175 #endif /* defined(HAVE_SS7) */
14177 #if defined(HAVE_OPENR2)
14178 static void *mfcr2_monitor(void *data
)
14180 struct dahdi_mfcr2
*mfcr2
= data
;
14181 struct dahdi_pvt
*pvt
;
14183 /* we should be using pthread_key_create
14184 and allocate pollers dynamically.
14185 I think do_monitor() could be leaking, since it
14186 could be cancelled at any time and is not
14187 using thread keys, why?, */
14188 struct pollfd pollers
[ARRAY_LEN(mfcr2
->pvts
)];
14196 /* now that we're ready to get calls, unblock our side and
14197 get current line state */
14198 for (i
= 0; i
< mfcr2
->numchans
; i
++) {
14199 pvt
= mfcr2
->pvts
[i
];
14203 openr2_chan_set_idle(pvt
->r2chan
);
14204 openr2_chan_handle_cas(pvt
->r2chan
);
14207 /* we trust here that the mfcr2 channel list will not ever change once
14208 the module is loaded */
14210 for (i
= 0; i
< mfcr2
->numchans
; i
++) {
14211 pollers
[i
].revents
= 0;
14212 pollers
[i
].events
= 0;
14213 pvt
= mfcr2
->pvts
[i
];
14220 if (mfcr2
->nodev
) {
14223 if (!pvt
->r2chan
) {
14224 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt
->channel
);
14228 openr2_chan_enable_read(pvt
->r2chan
);
14229 pollers
[i
].events
= POLLIN
| POLLPRI
;
14230 pollers
[i
].fd
= pvt
->subs
[SUB_REAL
].dfd
;
14236 if (pollsize
== 0) {
14238 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14241 poll(NULL
, 0, maxsleep
);
14245 /* probably poll() is a valid cancel point, lets just be on the safe side
14246 by calling pthread_testcancel */
14247 pthread_testcancel();
14248 res
= poll(pollers
, mfcr2
->numchans
, maxsleep
);
14249 pthread_testcancel();
14250 if ((res
< 0) && (errno
!= EINTR
)) {
14251 ast_log(LOG_ERROR
, "going out, poll failed: %s\n", strerror(errno
));
14254 /* do we want to allow to cancel while processing events? */
14255 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &oldstate
);
14256 for (i
= 0; i
< mfcr2
->numchans
; i
++) {
14257 pvt
= mfcr2
->pvts
[i
];
14261 if (pollers
[i
].revents
& POLLPRI
|| pollers
[i
].revents
& POLLIN
) {
14262 openr2_chan_process_event(pvt
->r2chan
);
14265 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
14267 ast_log(LOG_NOTICE
, "Quitting MFC/R2 monitor thread\n");
14270 #endif /* HAVE_OPENR2 */
14272 #if defined(HAVE_PRI)
14273 static void dahdi_pri_message(struct pri
*pri
, char *s
)
14279 int dchancount
= 0;
14282 for (x
= 0; x
< NUM_SPANS
; x
++) {
14283 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
14284 if (pris
[x
].pri
.dchans
[y
]) {
14288 if (pris
[x
].pri
.dchans
[y
] == pri
) {
14299 if (1 < dchancount
) {
14300 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span
+ 1, dchan
, s
);
14302 ast_verbose_callid(0, "PRI Span: %d %s", span
+ 1, s
);
14305 ast_verbose_callid(0, "PRI Span: ? %s", s
);
14308 ast_verbose_callid(0, "PRI Span: ? %s", s
);
14311 ast_mutex_lock(&pridebugfdlock
);
14313 if (pridebugfd
>= 0) {
14314 if (write(pridebugfd
, s
, strlen(s
)) < 0) {
14315 ast_log_callid(LOG_WARNING
, 0, "write() failed: %s\n", strerror(errno
));
14319 ast_mutex_unlock(&pridebugfdlock
);
14321 #endif /* defined(HAVE_PRI) */
14323 #if defined(HAVE_PRI)
14324 static void dahdi_pri_error(struct pri
*pri
, char *s
)
14330 int dchancount
= 0;
14333 for (x
= 0; x
< NUM_SPANS
; x
++) {
14334 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
14335 if (pris
[x
].pri
.dchans
[y
]) {
14339 if (pris
[x
].pri
.dchans
[y
] == pri
) {
14350 if (1 < dchancount
) {
14351 ast_log_callid(LOG_ERROR
, 0, "[PRI Span: %d D-Channel: %d] %s", span
+ 1, dchan
, s
);
14353 ast_log_callid(LOG_ERROR
, 0, "PRI Span: %d %s", span
+ 1, s
);
14356 ast_log_callid(LOG_ERROR
, 0, "PRI Span: ? %s", s
);
14359 ast_log_callid(LOG_ERROR
, 0, "PRI Span: ? %s", s
);
14362 ast_mutex_lock(&pridebugfdlock
);
14364 if (pridebugfd
>= 0) {
14365 if (write(pridebugfd
, s
, strlen(s
)) < 0) {
14366 ast_log_callid(LOG_WARNING
, 0, "write() failed: %s\n", strerror(errno
));
14370 ast_mutex_unlock(&pridebugfdlock
);
14372 #endif /* defined(HAVE_PRI) */
14374 #if defined(HAVE_PRI)
14375 static int prepare_pri(struct dahdi_pri
*pri
)
14378 struct dahdi_params p
;
14379 struct dahdi_bufferinfo bi
;
14380 struct dahdi_spaninfo si
;
14382 for (i
= 0; i
< SIG_PRI_NUM_DCHANS
; i
++) {
14383 if (!pri
->dchannels
[i
])
14385 if (pri
->pri
.fds
[i
] >= 0) {
14386 /* A partial range addition. Not a complete setup. */
14389 pri
->pri
.fds
[i
] = open("/dev/dahdi/channel", O_RDWR
);
14390 if ((pri
->pri
.fds
[i
] < 0)) {
14391 ast_log(LOG_ERROR
, "Unable to open D-channel (fd=%d) (%s)\n",
14392 pri
->pri
.fds
[i
], strerror(errno
));
14395 x
= pri
->dchannels
[i
];
14396 res
= ioctl(pri
->pri
.fds
[i
], DAHDI_SPECIFY
, &x
);
14398 dahdi_close_pri_fd(pri
, i
);
14399 ast_log(LOG_ERROR
, "Unable to SPECIFY channel %d (%s)\n", x
, strerror(errno
));
14402 memset(&p
, 0, sizeof(p
));
14403 res
= ioctl(pri
->pri
.fds
[i
], DAHDI_GET_PARAMS
, &p
);
14405 dahdi_close_pri_fd(pri
, i
);
14406 ast_log(LOG_ERROR
, "Unable to get parameters for D-channel %d (%s)\n", x
, strerror(errno
));
14409 if ((p
.sigtype
!= DAHDI_SIG_HDLCFCS
) && (p
.sigtype
!= DAHDI_SIG_HARDHDLC
)) {
14410 dahdi_close_pri_fd(pri
, i
);
14411 ast_log(LOG_ERROR
, "D-channel %d is not in HDLC/FCS mode.\n", x
);
14414 memset(&si
, 0, sizeof(si
));
14415 res
= ioctl(pri
->pri
.fds
[i
], DAHDI_SPANSTAT
, &si
);
14417 dahdi_close_pri_fd(pri
, i
);
14418 ast_log(LOG_ERROR
, "Unable to get span state for D-channel %d (%s)\n", x
, strerror(errno
));
14421 pri_event_noalarm(&pri
->pri
, i
, 1);
14423 pri_event_alarm(&pri
->pri
, i
, 1);
14425 memset(&bi
, 0, sizeof(bi
));
14426 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
14427 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
14430 if (ioctl(pri
->pri
.fds
[i
], DAHDI_SET_BUFINFO
, &bi
)) {
14431 ast_log(LOG_ERROR
, "Unable to set appropriate buffering on channel %d: %s\n", x
, strerror(errno
));
14432 dahdi_close_pri_fd(pri
, i
);
14435 pri
->pri
.dchan_logical_span
[i
] = pris
[p
.spanno
- 1].prilogicalspan
;
14439 #endif /* defined(HAVE_PRI) */
14441 #if defined(HAVE_PRI)
14442 static char *complete_span_helper(const char *line
, const char *word
, int pos
, int state
, int rpos
)
14450 for (which
= span
= 0; span
< NUM_SPANS
; span
++) {
14451 if (pris
[span
].pri
.pri
&& ++which
> state
) {
14452 if (ast_asprintf(&ret
, "%d", span
+ 1) < 0) { /* user indexes start from 1 */
14460 #endif /* defined(HAVE_PRI) */
14462 #if defined(HAVE_PRI)
14463 static char *complete_span_4(const char *line
, const char *word
, int pos
, int state
)
14465 return complete_span_helper(line
,word
,pos
,state
,3);
14467 #endif /* defined(HAVE_PRI) */
14469 #if defined(HAVE_PRI)
14470 static char *handle_pri_set_debug_file(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14475 e
->command
= "pri set debug file";
14476 e
->usage
= "Usage: pri set debug file [output-file]\n"
14477 " Sends PRI debug output to the specified output file\n";
14483 return CLI_SHOWUSAGE
;
14485 if (ast_strlen_zero(a
->argv
[4]))
14486 return CLI_SHOWUSAGE
;
14488 myfd
= open(a
->argv
[4], O_CREAT
|O_WRONLY
, AST_FILE_MODE
);
14490 ast_cli(a
->fd
, "Unable to open '%s' for writing\n", a
->argv
[4]);
14491 return CLI_SUCCESS
;
14494 ast_mutex_lock(&pridebugfdlock
);
14496 if (pridebugfd
>= 0)
14500 ast_copy_string(pridebugfilename
,a
->argv
[4],sizeof(pridebugfilename
));
14501 ast_mutex_unlock(&pridebugfdlock
);
14502 ast_cli(a
->fd
, "PRI debug output will be sent to '%s'\n", a
->argv
[4]);
14503 return CLI_SUCCESS
;
14505 #endif /* defined(HAVE_PRI) */
14507 #if defined(HAVE_PRI)
14508 static int action_pri_debug_file_set(struct mansession
*s
, const struct message
*m
)
14510 const char *output_file
= astman_get_header(m
, "File");
14513 if (ast_strlen_zero(output_file
)) {
14514 astman_send_error(s
, m
, "Action must define a 'File'");
14517 myfd
= open(output_file
, O_CREAT
|O_WRONLY
, AST_FILE_MODE
);
14519 astman_send_error(s
, m
, "Unable to open requested file for writing");
14523 ast_mutex_lock(&pridebugfdlock
);
14525 if (pridebugfd
>= 0) {
14530 ast_copy_string(pridebugfilename
, output_file
, sizeof(pridebugfilename
));
14531 ast_mutex_unlock(&pridebugfdlock
);
14532 astman_send_ack(s
, m
, "PRI debug output will now be sent to requested file.");
14536 #endif /* defined(HAVE_PRI) */
14538 #if defined(HAVE_PRI)
14539 static int action_pri_debug_file_unset(struct mansession
*s
, const struct message
*m
)
14541 ast_mutex_lock(&pridebugfdlock
);
14543 if (pridebugfd
>= 0) {
14549 ast_mutex_unlock(&pridebugfdlock
);
14551 astman_send_ack(s
, m
, "PRI Debug output to file disabled");
14554 #endif /* defined(HAVE_PRI) */
14556 #if defined(HAVE_PRI)
14557 static char *handle_pri_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14565 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";
14567 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14568 " Enables debugging on a given PRI span\n"
14569 " Level is a bitmap of the following values:\n"
14570 " 1 General debugging incl. state changes\n"
14571 " 2 Decoded Q.931 messages\n"
14572 " 4 Decoded Q.921 messages\n"
14573 " 8 Raw hex dumps of Q.921 frames\n"
14574 " on - equivalent to 3\n"
14575 " hex - equivalent to 8\n"
14576 " intense - equivalent to 15\n";
14579 return complete_span_4(a
->line
, a
->word
, a
->pos
, a
->n
);
14582 return CLI_SHOWUSAGE
;
14585 if (!strcasecmp(a
->argv
[3], "on")) {
14587 } else if (!strcasecmp(a
->argv
[3], "off")) {
14589 } else if (!strcasecmp(a
->argv
[3], "intense")) {
14591 } else if (!strcasecmp(a
->argv
[3], "hex")) {
14594 level
= atoi(a
->argv
[3]);
14596 span
= atoi(a
->argv
[5]);
14597 if ((span
< 1) || (span
> NUM_SPANS
)) {
14598 ast_cli(a
->fd
, "Invalid span %s. Should be a number %d to %d\n", a
->argv
[5], 1, NUM_SPANS
);
14599 return CLI_SUCCESS
;
14601 if (!pris
[span
-1].pri
.pri
) {
14602 ast_cli(a
->fd
, "No PRI running on span %d\n", span
);
14603 return CLI_SUCCESS
;
14606 if (level
& 1) debugmask
|= SIG_PRI_DEBUG_NORMAL
;
14607 if (level
& 2) debugmask
|= PRI_DEBUG_Q931_DUMP
;
14608 if (level
& 4) debugmask
|= PRI_DEBUG_Q921_DUMP
;
14609 if (level
& 8) debugmask
|= PRI_DEBUG_Q921_RAW
;
14611 /* Set debug level in libpri */
14612 for (x
= 0; x
< SIG_PRI_NUM_DCHANS
; x
++) {
14613 if (pris
[span
- 1].pri
.dchans
[x
]) {
14614 pri_set_debug(pris
[span
- 1].pri
.dchans
[x
], debugmask
);
14618 /* Close the debugging file if it's set */
14619 ast_mutex_lock(&pridebugfdlock
);
14620 if (0 <= pridebugfd
) {
14623 ast_cli(a
->fd
, "Disabled PRI debug output to file '%s'\n",
14626 ast_mutex_unlock(&pridebugfdlock
);
14628 pris
[span
- 1].pri
.debug
= (level
) ? 1 : 0;
14629 ast_cli(a
->fd
, "%s debugging on span %d\n", (level
) ? "Enabled" : "Disabled", span
);
14630 return CLI_SUCCESS
;
14632 #endif /* defined(HAVE_PRI) */
14634 #if defined(HAVE_PRI)
14635 static int action_pri_debug_set(struct mansession
*s
, const struct message
*m
)
14637 const char *level
= astman_get_header(m
, "Level");
14638 const char *span
= astman_get_header(m
, "Span");
14644 if (ast_strlen_zero(level
)) {
14645 astman_send_error(s
, m
, "'Level' was not specified");
14649 if (ast_strlen_zero(span
)) {
14650 astman_send_error(s
, m
, "'Span' was not specified");
14654 if (!strcasecmp(level
, "on")) {
14656 } else if (!strcasecmp(level
, "off")) {
14658 } else if (!strcasecmp(level
, "intense")) {
14660 } else if (!strcasecmp(level
, "hex")) {
14663 if (sscanf(level
, "%30d", &level_val
) != 1) {
14664 astman_send_error(s
, m
, "Invalid value for 'Level'");
14669 if (sscanf(span
, "%30d", &span_val
) != 1) {
14670 astman_send_error(s
, m
, "Invalid value for 'Span'");
14673 if ((span_val
< 1) || (span_val
> NUM_SPANS
)) {
14674 const char *id
= astman_get_header(m
, "ActionID");
14675 char id_text
[256] = "";
14677 if (!ast_strlen_zero(id
)) {
14678 snprintf(id_text
, sizeof(id_text
), "ActionID: %s\r\n", id
);
14681 astman_append(s
, "Response: Error\r\n"
14683 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14691 if (!pris
[span_val
-1].pri
.pri
) {
14692 astman_send_error(s
, m
, "No PRI running on requested span");
14696 if (level_val
& 1) {
14697 debugmask
|= SIG_PRI_DEBUG_NORMAL
;
14699 if (level_val
& 2) {
14700 debugmask
|= PRI_DEBUG_Q931_DUMP
;
14702 if (level_val
& 4) {
14703 debugmask
|= PRI_DEBUG_Q921_DUMP
;
14705 if (level_val
& 8) {
14706 debugmask
|= PRI_DEBUG_Q921_RAW
;
14709 /* Set debug level in libpri */
14710 for (x
= 0; x
< SIG_PRI_NUM_DCHANS
; x
++) {
14711 if (pris
[span_val
- 1].pri
.dchans
[x
]) {
14712 pri_set_debug(pris
[span_val
- 1].pri
.dchans
[x
], debugmask
);
14716 pris
[span_val
- 1].pri
.debug
= (level_val
) ? 1 : 0;
14717 astman_send_ack(s
, m
, "Debug level set for requested span");
14721 #endif /* defined(HAVE_PRI) */
14723 #if defined(HAVE_PRI)
14724 #if defined(HAVE_PRI_SERVICE_MESSAGES)
14725 static char *handle_pri_service_generic(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
, int changestatus
)
14730 int x
, y
, fd
= a
->fd
;
14731 int interfaceid
= 0;
14732 char db_chan_name
[20], db_answer
[15];
14733 struct dahdi_pvt
*tmp
;
14734 struct dahdi_pri
*pri
;
14736 if (a
->argc
< 5 || a
->argc
> 6)
14737 return CLI_SHOWUSAGE
;
14738 if (strchr(a
->argv
[4], ':')) {
14739 if (sscanf(a
->argv
[4], "%30d:%30d", &trunkgroup
, &channel
) != 2)
14740 return CLI_SHOWUSAGE
;
14741 if ((trunkgroup
< 1) || (channel
< 1))
14742 return CLI_SHOWUSAGE
;
14744 for (x
=0;x
<NUM_SPANS
;x
++) {
14745 if (pris
[x
].pri
.trunkgroup
== trunkgroup
) {
14751 ast_cli(fd
, "No such trunk group %d\n", trunkgroup
);
14752 return CLI_FAILURE
;
14755 channel
= atoi(a
->argv
[4]);
14758 interfaceid
= atoi(a
->argv
[5]);
14760 /* either servicing a D-Channel */
14761 for (x
= 0; x
< NUM_SPANS
; x
++) {
14762 for (y
= 0; y
< SIG_PRI_NUM_DCHANS
; y
++) {
14763 if (pris
[x
].dchannels
[y
] == channel
) {
14765 if (pri
->pri
.enable_service_message_support
) {
14766 ast_mutex_lock(&pri
->pri
.lock
);
14767 pri_maintenance_service(pri
->pri
.pri
, interfaceid
, -1, changestatus
);
14768 ast_mutex_unlock(&pri
->pri
.lock
);
14771 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14772 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14774 return CLI_SUCCESS
;
14779 /* or servicing a B-Channel */
14780 ast_mutex_lock(&iflock
);
14781 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
14782 if (tmp
->pri
&& tmp
->channel
== channel
) {
14783 ast_mutex_unlock(&iflock
);
14784 ast_mutex_lock(&tmp
->pri
->lock
);
14785 if (!tmp
->pri
->enable_service_message_support
) {
14786 ast_mutex_unlock(&tmp
->pri
->lock
);
14788 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14789 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14790 return CLI_SUCCESS
;
14792 snprintf(db_chan_name
, sizeof(db_chan_name
), "%s/%d:%d", dahdi_db
, tmp
->span
, channel
);
14793 why
= &((struct sig_pri_chan
*) tmp
->sig_pvt
)->service_status
;
14794 switch(changestatus
) {
14795 case 0: /* enable */
14796 /* Near end wants to be in service now. */
14797 ast_db_del(db_chan_name
, SRVST_DBKEY
);
14798 *why
&= ~SRVST_NEAREND
;
14800 snprintf(db_answer
, sizeof(db_answer
), "%s:%u", SRVST_TYPE_OOS
, *why
);
14801 ast_db_put(db_chan_name
, SRVST_DBKEY
, db_answer
);
14803 dahdi_pri_update_span_devstate(tmp
->pri
);
14806 /* case 1: -- loop */
14807 case 2: /* disable */
14808 /* Near end wants to be out-of-service now. */
14809 ast_db_del(db_chan_name
, SRVST_DBKEY
);
14810 *why
|= SRVST_NEAREND
;
14811 snprintf(db_answer
, sizeof(db_answer
), "%s:%u", SRVST_TYPE_OOS
, *why
);
14812 ast_db_put(db_chan_name
, SRVST_DBKEY
, db_answer
);
14813 dahdi_pri_update_span_devstate(tmp
->pri
);
14815 /* case 3: -- continuity */
14816 /* case 4: -- shutdown */
14818 ast_log(LOG_WARNING
, "Unsupported changestatus: '%d'\n", changestatus
);
14821 pri_maintenance_bservice(tmp
->pri
->pri
, tmp
->sig_pvt
, changestatus
);
14822 ast_mutex_unlock(&tmp
->pri
->lock
);
14823 return CLI_SUCCESS
;
14826 ast_mutex_unlock(&iflock
);
14828 ast_cli(fd
, "Unable to find given channel %d, possibly not a PRI\n", channel
);
14829 return CLI_FAILURE
;
14832 static char *handle_pri_service_enable_channel(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14836 e
->command
= "pri service enable channel";
14838 "Usage: pri service enable channel <channel> [<interface id>]\n"
14839 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
14840 " to restore a channel to service, with optional interface id\n"
14841 " as agreed upon with remote switch operator\n";
14846 return handle_pri_service_generic(e
, cmd
, a
, 0);
14849 static char *handle_pri_service_disable_channel(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14853 e
->command
= "pri service disable channel";
14855 "Usage: pri service disable channel <chan num> [<interface id>]\n"
14856 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
14857 " to remove a channel from service, with optional interface id\n"
14858 " as agreed upon with remote switch operator\n";
14863 return handle_pri_service_generic(e
, cmd
, a
, 2);
14865 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
14866 #endif /* defined(HAVE_PRI) */
14868 #if defined(HAVE_PRI)
14869 static char *handle_pri_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14875 e
->command
= "pri show channels";
14877 "Usage: pri show channels\n"
14878 " Displays PRI channel information such as the current mapping\n"
14879 " of DAHDI B channels to Asterisk channel names and which calls\n"
14880 " are on hold or call-waiting. Calls on hold or call-waiting\n"
14881 " are not associated with any B channel.\n";
14888 return CLI_SHOWUSAGE
;
14890 sig_pri_cli_show_channels_header(a
->fd
);
14891 for (span
= 0; span
< NUM_SPANS
; ++span
) {
14892 if (pris
[span
].pri
.pri
) {
14893 sig_pri_cli_show_channels(a
->fd
, &pris
[span
].pri
);
14896 return CLI_SUCCESS
;
14898 #endif /* defined(HAVE_PRI) */
14900 #if defined(HAVE_PRI)
14901 static char *handle_pri_show_spans(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
14907 e
->command
= "pri show spans";
14909 "Usage: pri show spans\n"
14910 " Displays PRI span information\n";
14917 return CLI_SHOWUSAGE
;
14919 for (span
= 0; span
< NUM_SPANS
; span
++) {
14920 if (pris
[span
].pri
.pri
) {
14921 sig_pri_cli_show_spans(a
->fd
, span
+ 1, &pris
[span
].pri
);
14924 return CLI_SUCCESS
;
14926 #endif /* defined(HAVE_PRI) */
14928 #if defined(HAVE_PRI)
14929 #define container_of(ptr, type, member) \
14930 ((type *)((char *)(ptr) - offsetof(type, member)))
14933 * \brief Destroy a D-Channel of a PRI span
14936 * \param pri the pri span
14938 * Shuts down a span and destroys its D-Channel. Further destruction
14939 * of the B-channels using dahdi_destroy_channel() would probably be required
14940 * for the B-Channels.
14942 static void pri_destroy_span(struct sig_pri_span
*pri
)
14947 struct dahdi_pri
* dahdi_pri
;
14948 pthread_t master
= pri
->master
;
14950 if (!master
|| (master
== AST_PTHREADT_NULL
)) {
14953 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri
->span
);
14954 for (i
= 0; i
< pri
->numchans
; i
++) {
14956 struct sig_pri_chan
*pvt
= pri
->pvts
[i
];
14961 channel
= pvt
->channel
;
14962 ast_debug(2, "About to destroy B-channel %d.\n", channel
);
14963 dahdi_destroy_channel_range(channel
, channel
);
14966 cancel_code
= pthread_cancel(master
);
14967 pthread_kill(master
, SIGURG
);
14969 "Waiting to join thread of span %d "
14970 "with pid=%p cancel_code=%d\n",
14971 pri
->span
, (void *)master
, cancel_code
);
14972 res
= pthread_join(master
, NULL
);
14974 ast_log(LOG_NOTICE
, "pthread_join failed: %d\n", res
);
14976 pri
->master
= AST_PTHREADT_NULL
;
14978 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
14979 dahdi_pri
= container_of(pri
, struct dahdi_pri
, pri
);
14980 for (i
= 0; i
< SIG_PRI_NUM_DCHANS
; i
++) {
14981 ast_debug(4, "closing pri_fd %d\n", i
);
14982 dahdi_close_pri_fd(dahdi_pri
, i
);
14983 dahdi_pri
->dchannels
[i
] = 0;
14985 sig_pri_init_pri(pri
);
14986 ast_debug(1, "PRI span %d destroyed\n", pri
->span
);
14989 static char *handle_pri_destroy_span(struct ast_cli_entry
*e
, int cmd
,
14990 struct ast_cli_args
*a
)
14994 struct sig_pri_span
*pri
;
14998 e
->command
= "pri destroy span";
15000 "Usage: pri destroy span <span>\n"
15001 " Destorys D-channel of span and its B-channels.\n"
15002 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15005 return complete_span_4(a
->line
, a
->word
, a
->pos
, a
->n
);
15009 return CLI_SHOWUSAGE
;
15011 res
= sscanf(a
->argv
[3], "%30d", &span
);
15012 if ((res
!= 1) || span
< 1 || span
> NUM_SPANS
) {
15014 "Invalid span '%s'. Should be a number from %d to %d\n",
15015 a
->argv
[3], 1, NUM_SPANS
);
15016 return CLI_SUCCESS
;
15018 pri
= &pris
[span
- 1].pri
;
15020 ast_cli(a
->fd
, "No PRI running on span %d\n", span
);
15021 return CLI_SUCCESS
;
15024 pri_destroy_span(pri
);
15025 return CLI_SUCCESS
;
15028 #endif /* defined(HAVE_PRI) */
15030 #if defined(HAVE_PRI)
15031 static char *handle_pri_show_span(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15037 e
->command
= "pri show span";
15039 "Usage: pri show span <span>\n"
15040 " Displays PRI Information on a given PRI span\n";
15043 return complete_span_4(a
->line
, a
->word
, a
->pos
, a
->n
);
15047 return CLI_SHOWUSAGE
;
15048 span
= atoi(a
->argv
[3]);
15049 if ((span
< 1) || (span
> NUM_SPANS
)) {
15050 ast_cli(a
->fd
, "Invalid span '%s'. Should be a number from %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
15051 return CLI_SUCCESS
;
15053 if (!pris
[span
-1].pri
.pri
) {
15054 ast_cli(a
->fd
, "No PRI running on span %d\n", span
);
15055 return CLI_SUCCESS
;
15058 sig_pri_cli_show_span(a
->fd
, pris
[span
-1].dchannels
, &pris
[span
-1].pri
);
15060 return CLI_SUCCESS
;
15062 #endif /* defined(HAVE_PRI) */
15064 #if defined(HAVE_PRI)
15065 static char *handle_pri_show_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15074 e
->command
= "pri show debug";
15076 "Usage: pri show debug\n"
15077 " Show the debug state of pri spans\n";
15083 for (span
= 0; span
< NUM_SPANS
; span
++) {
15084 if (pris
[span
].pri
.pri
) {
15085 for (x
= 0; x
< SIG_PRI_NUM_DCHANS
; x
++) {
15086 if (pris
[span
].pri
.dchans
[x
]) {
15087 debug
= pri_get_debug(pris
[span
].pri
.dchans
[x
]);
15088 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" );
15095 ast_mutex_lock(&pridebugfdlock
);
15096 if (pridebugfd
>= 0)
15097 ast_cli(a
->fd
, "Logging PRI debug to file %s\n", pridebugfilename
);
15098 ast_mutex_unlock(&pridebugfdlock
);
15101 ast_cli(a
->fd
, "No PRI running\n");
15102 return CLI_SUCCESS
;
15104 #endif /* defined(HAVE_PRI) */
15106 #if defined(HAVE_PRI)
15107 static char *handle_pri_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15111 e
->command
= "pri show version";
15113 "Usage: pri show version\n"
15114 "Show libpri version information\n";
15120 ast_cli(a
->fd
, "libpri version: %s\n", pri_get_version());
15122 return CLI_SUCCESS
;
15124 #endif /* defined(HAVE_PRI) */
15126 #if defined(HAVE_PRI)
15127 static struct ast_cli_entry dahdi_pri_cli
[] = {
15128 AST_CLI_DEFINE(handle_pri_debug
, "Enables PRI debugging on a span"),
15129 #if defined(HAVE_PRI_SERVICE_MESSAGES)
15130 AST_CLI_DEFINE(handle_pri_service_enable_channel
, "Return a channel to service"),
15131 AST_CLI_DEFINE(handle_pri_service_disable_channel
, "Remove a channel from service"),
15132 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15133 AST_CLI_DEFINE(handle_pri_show_channels
, "Displays PRI channel information"),
15134 AST_CLI_DEFINE(handle_pri_show_spans
, "Displays PRI span information"),
15135 AST_CLI_DEFINE(handle_pri_show_span
, "Displays PRI span information"),
15136 AST_CLI_DEFINE(handle_pri_destroy_span
, "Destroy a PRI span"),
15137 AST_CLI_DEFINE(handle_pri_show_debug
, "Displays current PRI debug settings"),
15138 AST_CLI_DEFINE(handle_pri_set_debug_file
, "Sends PRI debug output to the specified file"),
15139 AST_CLI_DEFINE(handle_pri_version
, "Displays libpri version"),
15141 #endif /* defined(HAVE_PRI) */
15145 static char *handle_mfcr2_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15149 e
->command
= "mfcr2 show version";
15151 "Usage: mfcr2 show version\n"
15152 " Shows the version of the OpenR2 library being used.\n";
15157 ast_cli(a
->fd
, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15158 return CLI_SUCCESS
;
15161 static char *handle_mfcr2_show_variants(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15163 #define FORMAT "%4s %40s\n"
15165 int numvariants
= 0;
15166 const openr2_variant_entry_t
*variants
;
15169 e
->command
= "mfcr2 show variants";
15171 "Usage: mfcr2 show variants\n"
15172 " Shows the list of MFC/R2 variants supported.\n";
15177 if (!(variants
= openr2_proto_get_variant_list(&numvariants
))) {
15178 ast_cli(a
->fd
, "Failed to get list of variants.\n");
15179 return CLI_FAILURE
;
15181 ast_cli(a
->fd
, FORMAT
, "Variant Code", "Country");
15182 for (i
= 0; i
< numvariants
; i
++) {
15183 ast_cli(a
->fd
, FORMAT
, variants
[i
].name
, variants
[i
].country
);
15185 return CLI_SUCCESS
;
15189 static char *handle_mfcr2_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15191 #define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15192 int filtertype
= 0;
15198 struct dahdi_pvt
*p
;
15199 openr2_context_t
*r2context
;
15200 openr2_variant_t r2variant
;
15203 e
->command
= "mfcr2 show channels [group|context]";
15205 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15206 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15211 if (!((a
->argc
== 3) || (a
->argc
== 5))) {
15212 return CLI_SHOWUSAGE
;
15214 if (a
->argc
== 5) {
15215 if (!strcasecmp(a
->argv
[3], "group")) {
15216 targetnum
= atoi(a
->argv
[4]);
15217 if ((targetnum
< 0) || (targetnum
> 63))
15218 return CLI_SHOWUSAGE
;
15219 targetnum
= 1 << targetnum
;
15221 } else if (!strcasecmp(a
->argv
[3], "context")) {
15224 return CLI_SHOWUSAGE
;
15227 ast_cli(a
->fd
, FORMAT
, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15228 ast_mutex_lock(&iflock
);
15229 for (p
= iflist
; p
; p
= p
->next
) {
15230 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15234 switch(filtertype
) {
15235 case 1: /* mfcr2 show channels group <group> */
15236 if (p
->group
!= targetnum
) {
15240 case 2: /* mfcr2 show channels context <context> */
15241 if (strcasecmp(p
->context
, a
->argv
[4])) {
15249 r2context
= openr2_chan_get_context(p
->r2chan
);
15250 r2variant
= openr2_context_get_variant(r2context
);
15251 snprintf(channo
, sizeof(channo
), "%d", p
->channel
);
15252 snprintf(linkno
, sizeof(linkno
), "%d", p
->mfcr2
->index
);
15253 snprintf(anino
, sizeof(anino
), "%d", openr2_context_get_max_ani(r2context
));
15254 snprintf(dnisno
, sizeof(dnisno
), "%d", openr2_context_get_max_dnis(r2context
));
15255 ast_cli(a
->fd
, FORMAT
, channo
, linkno
, openr2_proto_get_variant_string(r2variant
),
15256 anino
, dnisno
, openr2_context_get_ani_first(r2context
) ? "Yes" : "No",
15257 openr2_context_get_immediate_accept(r2context
) ? "Yes" : "No",
15258 openr2_chan_get_tx_cas_string(p
->r2chan
), openr2_chan_get_rx_cas_string(p
->r2chan
));
15260 ast_mutex_unlock(&iflock
);
15261 return CLI_SUCCESS
;
15265 static char *handle_mfcr2_set_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15267 struct dahdi_pvt
*p
= NULL
;
15269 char *toklevel
= NULL
;
15270 char *saveptr
= NULL
;
15271 char *logval
= NULL
;
15272 openr2_log_level_t loglevel
= OR2_LOG_NOTHING
;
15273 openr2_log_level_t tmplevel
= OR2_LOG_NOTHING
;
15276 e
->command
= "mfcr2 set debug";
15278 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15279 " Set a new logging level for the specified channel.\n"
15280 " If no channel is specified the logging level will be applied to all channels.\n";
15286 return CLI_SHOWUSAGE
;
15288 channo
= (a
->argc
== 5) ? atoi(a
->argv
[4]) : -1;
15289 logval
= ast_strdupa(a
->argv
[3]);
15290 toklevel
= strtok_r(logval
, ",", &saveptr
);
15291 if (-1 == (tmplevel
= openr2_log_get_level(toklevel
))) {
15292 ast_cli(a
->fd
, "Invalid MFC/R2 logging level '%s'.\n", a
->argv
[3]);
15293 return CLI_FAILURE
;
15294 } else if (OR2_LOG_NOTHING
== tmplevel
) {
15295 loglevel
= tmplevel
;
15297 loglevel
|= tmplevel
;
15298 while ((toklevel
= strtok_r(NULL
, ",", &saveptr
))) {
15299 if (-1 == (tmplevel
= openr2_log_get_level(toklevel
))) {
15300 ast_cli(a
->fd
, "Ignoring invalid logging level: '%s'.\n", toklevel
);
15303 loglevel
|= tmplevel
;
15306 ast_mutex_lock(&iflock
);
15307 for (p
= iflist
; p
; p
= p
->next
) {
15308 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15311 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15314 openr2_chan_set_log_level(p
->r2chan
, loglevel
);
15315 if (channo
!= -1) {
15316 ast_cli(a
->fd
, "MFC/R2 debugging set to '%s' for channel %d.\n", a
->argv
[3], p
->channel
);
15320 if ((channo
!= -1) && !p
) {
15321 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15323 if (channo
== -1) {
15324 ast_cli(a
->fd
, "MFC/R2 debugging set to '%s' for all channels.\n", a
->argv
[3]);
15326 ast_mutex_unlock(&iflock
);
15327 return CLI_SUCCESS
;
15330 static char *handle_mfcr2_call_files(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15332 struct dahdi_pvt
*p
= NULL
;
15336 e
->command
= "mfcr2 call files [on|off]";
15338 "Usage: mfcr2 call files [on|off] <channel>\n"
15339 " Enable call files creation on the specified channel.\n"
15340 " If no channel is specified call files creation policy will be applied to all channels.\n";
15346 return CLI_SHOWUSAGE
;
15348 channo
= (a
->argc
== 5) ? atoi(a
->argv
[4]) : -1;
15349 ast_mutex_lock(&iflock
);
15350 for (p
= iflist
; p
; p
= p
->next
) {
15351 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15354 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15357 if (ast_true(a
->argv
[3])) {
15358 openr2_chan_enable_call_files(p
->r2chan
);
15360 openr2_chan_disable_call_files(p
->r2chan
);
15362 if (channo
!= -1) {
15363 if (ast_true(a
->argv
[3])) {
15364 ast_cli(a
->fd
, "MFC/R2 call files enabled for channel %d.\n", p
->channel
);
15366 ast_cli(a
->fd
, "MFC/R2 call files disabled for channel %d.\n", p
->channel
);
15371 if ((channo
!= -1) && !p
) {
15372 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15374 if (channo
== -1) {
15375 if (ast_true(a
->argv
[3])) {
15376 ast_cli(a
->fd
, "MFC/R2 Call files enabled for all channels.\n");
15378 ast_cli(a
->fd
, "MFC/R2 Call files disabled for all channels.\n");
15381 ast_mutex_unlock(&iflock
);
15382 return CLI_SUCCESS
;
15385 static char *handle_mfcr2_set_idle(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15387 struct dahdi_pvt
*p
= NULL
;
15391 e
->command
= "mfcr2 set idle";
15393 "Usage: mfcr2 set idle <channel>\n"
15394 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15395 " Force the given channel into IDLE state.\n"
15396 " If no channel is specified, all channels will be set to IDLE.\n";
15401 channo
= (a
->argc
== 4) ? atoi(a
->argv
[3]) : -1;
15402 ast_mutex_lock(&iflock
);
15403 for (p
= iflist
; p
; p
= p
->next
) {
15404 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15407 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15410 openr2_chan_set_idle(p
->r2chan
);
15411 ast_mutex_lock(&p
->lock
);
15412 p
->locallyblocked
= 0;
15414 ast_mutex_unlock(&p
->lock
);
15415 if (channo
!= -1) {
15419 if ((channo
!= -1) && !p
) {
15420 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15422 ast_mutex_unlock(&iflock
);
15423 return CLI_SUCCESS
;
15426 static char *handle_mfcr2_set_blocked(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15428 struct dahdi_pvt
*p
= NULL
;
15432 e
->command
= "mfcr2 set blocked";
15434 "Usage: mfcr2 set blocked <channel>\n"
15435 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15436 " Force the given channel into BLOCKED state.\n"
15437 " If no channel is specified, all channels will be set to BLOCKED.\n";
15442 channo
= (a
->argc
== 4) ? atoi(a
->argv
[3]) : -1;
15443 ast_mutex_lock(&iflock
);
15444 for (p
= iflist
; p
; p
= p
->next
) {
15445 if (!(p
->sig
& SIG_MFCR2
) || !p
->r2chan
) {
15448 if ((channo
!= -1) && (p
->channel
!= channo
)) {
15451 openr2_chan_set_blocked(p
->r2chan
);
15452 ast_mutex_lock(&p
->lock
);
15453 p
->locallyblocked
= 1;
15454 ast_mutex_unlock(&p
->lock
);
15455 if (channo
!= -1) {
15459 if ((channo
!= -1) && !p
) {
15460 ast_cli(a
->fd
, "MFC/R2 channel %d not found.\n", channo
);
15462 ast_mutex_unlock(&iflock
);
15463 return CLI_SUCCESS
;
15466 static void mfcr2_show_links_of(struct ast_cli_args
*a
, struct r2links
*list_head
, const char *title
)
15468 #define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15469 AST_LIST_LOCK(list_head
);
15470 if (! AST_LIST_EMPTY(list_head
)) {
15473 char live_chans_str
[5];
15474 char channel_list
[R2_LINK_CAPACITY
* 4];
15475 struct r2link_entry
*cur
;
15476 ast_cli(a
->fd
, "%s\n", title
);
15477 ast_cli(a
->fd
, FORMAT
, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15478 AST_LIST_TRAVERSE(list_head
, cur
, list
) {
15479 struct dahdi_mfcr2
*mfcr2
= &cur
->mfcr2
;
15480 const char *thread_status
= NULL
;
15487 if (mfcr2
->r2master
== 0L) {
15488 thread_status
= "zero";
15489 } else if (mfcr2
->r2master
== AST_PTHREADT_NULL
) {
15490 thread_status
= "none";
15492 thread_status
= "created";
15494 snprintf(index
, sizeof(index
), "%d", mfcr2
->index
);
15495 snprintf(live_chans_str
, sizeof(live_chans_str
), "%d", mfcr2
->live_chans
);
15500 /* Prepare nice string in channel_list[] */
15501 for (i
= 0; i
< mfcr2
->numchans
&& len
< sizeof(channel_list
) - 1; i
++) {
15502 struct dahdi_pvt
*p
= mfcr2
->pvts
[i
];
15506 channo
= p
->channel
;
15507 /* Don't show a range until we know the last channel number */
15508 if (prev_channo
&& prev_channo
== channo
- 1) {
15509 prev_channo
= channo
;
15513 if (inside_range
) {
15515 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, "-%d,%d", prev_channo
, channo
);
15517 } else if (prev_channo
) {
15518 /* Non-sequential channel numbers */
15519 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, ",%d", channo
);
15521 /* First channel number */
15522 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, "%d", channo
);
15524 prev_channo
= channo
;
15526 /* Handle leftover channels */
15527 if (inside_range
) {
15529 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, "-%d", channo
);
15531 } else if (prev_channo
) {
15532 /* Non-sequential channel numbers */
15533 len
+= snprintf(channel_list
+ len
, sizeof(channel_list
) - len
- 1, ",%d", channo
);
15535 // channel_list[len] = '\0';
15536 ast_cli(a
->fd
, FORMAT
,
15539 (mfcr2
->nodev
) ? "MISSING" : "OK",
15544 AST_LIST_UNLOCK(list_head
);
15548 static char *handle_mfcr2_show_links(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15552 e
->command
= "mfcr2 show links";
15554 "Usage: mfcr2 show links\n"
15555 " Shows the DAHDI MFC/R2 links.\n";
15560 if (a
->argc
!= 3) {
15561 return CLI_SHOWUSAGE
;
15563 mfcr2_show_links_of(a
, &r2links
, "Live links\n");
15564 mfcr2_show_links_of(a
, &nodev_r2links
, "Links to be removed (device missing)\n");
15565 return CLI_SUCCESS
;
15568 static char *handle_mfcr2_destroy_link(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15571 int wanted_link_index
;
15572 int found_link
= 0;
15573 struct r2link_entry
*cur
= NULL
;
15577 e
->command
= "mfcr2 destroy link";
15579 "Usage: mfcr2 destroy link <index-number>\n"
15580 " Destorys D-channel of link and its B-channels.\n"
15581 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15587 return CLI_SHOWUSAGE
;
15589 res
= sscanf(a
->argv
[3], "%30d", &wanted_link_index
);
15590 if ((res
!= 1) || wanted_link_index
< 1) {
15592 "Invalid link index '%s'. Should be a positive number\n", a
->argv
[3]);
15593 return CLI_SUCCESS
;
15595 AST_LIST_LOCK(&r2links
);
15596 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links
, cur
, list
) {
15597 struct dahdi_mfcr2
*mfcr2
= &cur
->mfcr2
;
15598 if (wanted_link_index
== mfcr2
->index
) {
15599 AST_LIST_MOVE_CURRENT(&nodev_r2links
, list
);
15604 AST_LIST_TRAVERSE_SAFE_END
;
15605 AST_LIST_UNLOCK(&r2links
);
15606 if (! found_link
) {
15607 ast_cli(a
->fd
, "No link found with index %d.\n", wanted_link_index
);
15608 return CLI_FAILURE
;
15610 return CLI_SUCCESS
;
15613 static struct ast_cli_entry dahdi_mfcr2_cli
[] = {
15614 AST_CLI_DEFINE(handle_mfcr2_version
, "Show OpenR2 library version"),
15615 AST_CLI_DEFINE(handle_mfcr2_show_variants
, "Show supported MFC/R2 variants"),
15616 AST_CLI_DEFINE(handle_mfcr2_show_channels
, "Show MFC/R2 channels"),
15617 AST_CLI_DEFINE(handle_mfcr2_show_links
, "Show MFC/R2 links"),
15618 AST_CLI_DEFINE(handle_mfcr2_set_debug
, "Set MFC/R2 channel logging level"),
15619 AST_CLI_DEFINE(handle_mfcr2_call_files
, "Enable/Disable MFC/R2 call files"),
15620 AST_CLI_DEFINE(handle_mfcr2_set_idle
, "Reset MFC/R2 channel forcing it to IDLE"),
15621 AST_CLI_DEFINE(handle_mfcr2_set_blocked
, "Reset MFC/R2 channel forcing it to BLOCKED"),
15622 AST_CLI_DEFINE(handle_mfcr2_destroy_link
, "Destroy given MFC/R2 link"),
15625 #endif /* HAVE_OPENR2 */
15627 static char *dahdi_destroy_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15633 e
->command
= "dahdi destroy channels";
15635 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15636 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15641 if ((a
->argc
< 4) || a
->argc
> 5) {
15642 return CLI_SHOWUSAGE
;
15644 start
= atoi(a
->argv
[3]);
15646 ast_cli(a
->fd
, "Invalid starting channel number %s.\n",
15648 return CLI_FAILURE
;
15650 if (a
->argc
== 5) {
15651 end
= atoi(a
->argv
[4]);
15653 ast_cli(a
->fd
, "Invalid ending channel number %s.\n",
15655 return CLI_FAILURE
;
15663 "range end (%d) is smaller than range start (%d)\n",
15665 return CLI_FAILURE
;
15667 dahdi_destroy_channel_range(start
, end
);
15668 return CLI_SUCCESS
;
15671 static char *dahdi_create_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15679 e
->command
= "dahdi create channels";
15680 e
->usage
= "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15681 " dahdi create channels new - add channels not yet created\n"
15682 "For ISDN and SS7 the range should include complete spans.\n";
15687 if ((a
->argc
< 4) || a
->argc
> 5) {
15688 return CLI_SHOWUSAGE
;
15690 if (a
->argc
== 4 && !strcmp(a
->argv
[3], "new")) {
15691 ret
= dahdi_create_channel_range(0, 0);
15692 return (RESULT_SUCCESS
== ret
) ? CLI_SUCCESS
: CLI_FAILURE
;
15694 start
= atoi(a
->argv
[3]);
15696 ast_cli(a
->fd
, "Invalid starting channel number '%s'.\n",
15698 return CLI_FAILURE
;
15700 if (a
->argc
== 5) {
15701 end
= atoi(a
->argv
[4]);
15703 ast_cli(a
->fd
, "Invalid ending channel number '%s'.\n",
15705 return CLI_FAILURE
;
15712 "range end (%d) is smaller than range start (%d)\n",
15714 return CLI_FAILURE
;
15716 ret
= dahdi_create_channel_range(start
, end
);
15717 return (RESULT_SUCCESS
== ret
) ? CLI_SUCCESS
: CLI_FAILURE
;
15720 static void dahdi_softhangup_all(void)
15722 struct dahdi_pvt
*p
;
15724 ast_mutex_lock(&iflock
);
15725 for (p
= iflist
; p
; p
= p
->next
) {
15726 ast_mutex_lock(&p
->lock
);
15727 if (p
->owner
&& !p
->restartpending
) {
15728 if (ast_channel_trylock(p
->owner
)) {
15729 if (DEBUG_ATLEAST(3))
15730 ast_verbose("Avoiding deadlock\n");
15731 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15732 ast_mutex_unlock(&p
->lock
);
15733 ast_mutex_unlock(&iflock
);
15736 if (DEBUG_ATLEAST(3))
15737 ast_verbose("Softhanging up on %s\n", ast_channel_name(p
->owner
));
15738 ast_softhangup_nolock(p
->owner
, AST_SOFTHANGUP_EXPLICIT
);
15739 p
->restartpending
= 1;
15740 num_restart_pending
++;
15741 ast_channel_unlock(p
->owner
);
15743 ast_mutex_unlock(&p
->lock
);
15745 ast_mutex_unlock(&iflock
);
15748 static int dahdi_restart(void)
15750 #if defined(HAVE_PRI) || defined(HAVE_SS7)
15752 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15754 struct dahdi_pvt
*p
;
15756 ast_mutex_lock(&restart_lock
);
15757 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15758 dahdi_softhangup_all();
15759 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15761 dahdi_r2_destroy_links();
15764 #if defined(HAVE_PRI)
15765 for (i
= 0; i
< NUM_SPANS
; i
++) {
15766 if (pris
[i
].pri
.master
&& (pris
[i
].pri
.master
!= AST_PTHREADT_NULL
)) {
15767 cancel_code
= pthread_cancel(pris
[i
].pri
.master
);
15768 pthread_kill(pris
[i
].pri
.master
, SIGURG
);
15769 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
);
15770 pthread_join(pris
[i
].pri
.master
, NULL
);
15771 ast_debug(4, "Joined thread of span %d\n", i
);
15776 #if defined(HAVE_SS7)
15777 for (i
= 0; i
< NUM_SPANS
; i
++) {
15778 if (linksets
[i
].ss7
.master
&& (linksets
[i
].ss7
.master
!= AST_PTHREADT_NULL
)) {
15779 cancel_code
= pthread_cancel(linksets
[i
].ss7
.master
);
15780 pthread_kill(linksets
[i
].ss7
.master
, SIGURG
);
15781 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
);
15782 pthread_join(linksets
[i
].ss7
.master
, NULL
);
15783 ast_debug(4, "Joined thread of span %d\n", i
);
15786 #endif /* defined(HAVE_SS7) */
15788 ast_mutex_lock(&monlock
);
15789 if (monitor_thread
&& (monitor_thread
!= AST_PTHREADT_STOP
) && (monitor_thread
!= AST_PTHREADT_NULL
)) {
15790 cancel_code
= pthread_cancel(monitor_thread
);
15791 pthread_kill(monitor_thread
, SIGURG
);
15792 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread
, cancel_code
);
15793 pthread_join(monitor_thread
, NULL
);
15794 ast_debug(4, "Joined monitor thread\n");
15796 monitor_thread
= AST_PTHREADT_NULL
; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
15798 ast_mutex_lock(&ss_thread_lock
);
15799 while (ss_thread_count
> 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
15800 int x
= DAHDI_FLASH
;
15801 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count
);
15803 ast_mutex_lock(&iflock
);
15804 for (p
= iflist
; p
; p
= p
->next
) {
15806 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
15807 ioctl(p
->subs
[SUB_REAL
].dfd
, DAHDI_HOOK
, &x
);
15810 ast_mutex_unlock(&iflock
);
15811 ast_cond_wait(&ss_thread_complete
, &ss_thread_lock
);
15814 /* ensure any created channels before monitor threads were stopped are hungup */
15815 dahdi_softhangup_all();
15816 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
15817 destroy_all_channels();
15818 memset(round_robin
, 0, sizeof(round_robin
));
15819 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
15821 ast_mutex_unlock(&monlock
);
15824 for (i
= 0; i
< NUM_SPANS
; i
++) {
15825 for (j
= 0; j
< SIG_PRI_NUM_DCHANS
; j
++)
15826 dahdi_close_pri_fd(&(pris
[i
]), j
);
15829 memset(pris
, 0, sizeof(pris
));
15830 for (i
= 0; i
< NUM_SPANS
; i
++) {
15831 sig_pri_init_pri(&pris
[i
].pri
);
15833 pri_set_error(dahdi_pri_error
);
15834 pri_set_message(dahdi_pri_message
);
15836 #if defined(HAVE_SS7)
15837 for (i
= 0; i
< NUM_SPANS
; i
++) {
15838 for (j
= 0; j
< SIG_SS7_NUM_DCHANS
; j
++)
15839 dahdi_close_ss7_fd(&(linksets
[i
]), j
);
15842 memset(linksets
, 0, sizeof(linksets
));
15843 for (i
= 0; i
< NUM_SPANS
; i
++) {
15844 sig_ss7_init_linkset(&linksets
[i
].ss7
);
15846 ss7_set_error(dahdi_ss7_error
);
15847 ss7_set_message(dahdi_ss7_message
);
15848 ss7_set_hangup(sig_ss7_cb_hangup
);
15849 ss7_set_notinservice(sig_ss7_cb_notinservice
);
15850 ss7_set_call_null(sig_ss7_cb_call_null
);
15851 #endif /* defined(HAVE_SS7) */
15853 if (setup_dahdi(2) != 0) {
15854 ast_log(LOG_WARNING
, "Reload channels from dahdi config failed!\n");
15855 ast_mutex_unlock(&ss_thread_lock
);
15858 ast_mutex_unlock(&ss_thread_lock
);
15859 ast_mutex_unlock(&restart_lock
);
15863 static char *dahdi_restart_cmd(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15867 e
->command
= "dahdi restart";
15869 "Usage: dahdi restart\n"
15870 " Restarts the DAHDI channels: destroys them all and then\n"
15871 " re-reads them from chan_dahdi.conf.\n"
15872 " Note that this will STOP any running CALL on DAHDI channels.\n"
15879 return CLI_SHOWUSAGE
;
15881 if (dahdi_restart() != 0)
15882 return CLI_FAILURE
;
15883 return CLI_SUCCESS
;
15886 static int action_dahdirestart(struct mansession
*s
, const struct message
*m
)
15888 if (dahdi_restart() != 0) {
15889 astman_send_error(s
, m
, "Failed rereading DAHDI configuration");
15892 astman_send_ack(s
, m
, "DAHDIRestart: Success");
15896 static char *dahdi_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15898 #define FORMAT "%7s %-15.15s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
15899 #define FORMAT2 "%7s %-15.15s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
15900 ast_group_t targetnum
= 0;
15901 int filtertype
= 0;
15902 struct dahdi_pvt
*tmp
= NULL
;
15908 e
->command
= "dahdi show channels [group|context]";
15910 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
15911 " Shows a list of available channels with optional filtering\n"
15912 " <group> must be a number between 0 and 63\n";
15918 /* syntax: dahdi show channels [ group <group> | context <context> ] */
15920 if (!((a
->argc
== 3) || (a
->argc
== 5))) {
15921 return CLI_SHOWUSAGE
;
15924 if (a
->argc
== 5) {
15925 if (!strcasecmp(a
->argv
[3], "group")) {
15926 targetnum
= atoi(a
->argv
[4]);
15927 if (63 < targetnum
) {
15928 return CLI_SHOWUSAGE
;
15930 targetnum
= ((ast_group_t
) 1) << targetnum
;
15932 } else if (!strcasecmp(a
->argv
[3], "context")) {
15937 ast_cli(a
->fd
, FORMAT2
, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Description");
15938 ast_mutex_lock(&iflock
);
15939 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
15941 switch(filtertype
) {
15942 case 1: /* dahdi show channels group <group> */
15943 if (!(tmp
->group
& targetnum
)) {
15947 case 2: /* dahdi show channels context <context> */
15948 if (strcasecmp(tmp
->context
, a
->argv
[4])) {
15956 if (tmp
->channel
> 0) {
15957 snprintf(tmps
, sizeof(tmps
), "%d", tmp
->channel
);
15959 ast_copy_string(tmps
, "pseudo", sizeof(tmps
));
15962 blockstr
[0] = tmp
->locallyblocked
? 'L' : ' ';
15963 blockstr
[1] = tmp
->remotelyblocked
? 'R' : ' ';
15964 blockstr
[2] = '\0';
15966 ast_cli(a
->fd
, FORMAT
, tmps
, tmp
->exten
, tmp
->context
, tmp
->language
, tmp
->mohinterpret
, blockstr
, tmp
->inservice
? "Yes" : "No", tmp
->description
);
15968 ast_mutex_unlock(&iflock
);
15969 return CLI_SUCCESS
;
15974 static char *dahdi_show_channel(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
15977 struct dahdi_pvt
*tmp
= NULL
;
15978 struct dahdi_confinfo ci
;
15979 struct dahdi_params ps
;
15986 e
->command
= "dahdi show channel";
15988 "Usage: dahdi show channel <chan num>\n"
15989 " Detailed information about a given channel\n";
15996 return CLI_SHOWUSAGE
;
15998 channel
= atoi(a
->argv
[3]);
16000 ast_mutex_lock(&iflock
);
16001 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16002 if (tmp
->channel
== channel
) {
16003 ast_cli(a
->fd
, "Channel: %d\n", tmp
->channel
);
16004 ast_cli(a
->fd
, "Description: %s\n", tmp
->description
);
16005 ast_cli(a
->fd
, "File Descriptor: %d\n", tmp
->subs
[SUB_REAL
].dfd
);
16006 ast_cli(a
->fd
, "Span: %d\n", tmp
->span
);
16007 ast_cli(a
->fd
, "Extension: %s\n", tmp
->exten
);
16008 ast_cli(a
->fd
, "Dialing: %s\n", tmp
->dialing
? "yes" : "no");
16009 ast_cli(a
->fd
, "Context: %s\n", tmp
->context
);
16010 ast_cli(a
->fd
, "Caller ID: %s\n", tmp
->cid_num
);
16011 ast_cli(a
->fd
, "Calling TON: %d\n", tmp
->cid_ton
);
16012 #if defined(HAVE_PRI)
16013 #if defined(HAVE_PRI_SUBADDR)
16014 ast_cli(a
->fd
, "Caller ID subaddress: %s\n", tmp
->cid_subaddr
);
16015 #endif /* defined(HAVE_PRI_SUBADDR) */
16016 #endif /* defined(HAVE_PRI) */
16017 ast_cli(a
->fd
, "Caller ID name: %s\n", tmp
->cid_name
);
16018 ast_cli(a
->fd
, "Mailbox: %s\n", S_OR(tmp
->mailbox
, "none"));
16020 struct ast_variable
*v
;
16021 ast_cli(a
->fd
, "Variables:\n");
16022 for (v
= tmp
->vars
; v
; v
= v
->next
)
16023 ast_cli(a
->fd
, " %s = %s\n", v
->name
, v
->value
);
16025 ast_cli(a
->fd
, "Destroy: %d\n", tmp
->destroy
);
16026 ast_cli(a
->fd
, "InAlarm: %d\n", tmp
->inalarm
);
16027 ast_cli(a
->fd
, "Signalling Type: %s\n", sig2str(tmp
->sig
));
16028 ast_cli(a
->fd
, "Radio: %d\n", tmp
->radio
);
16029 ast_cli(a
->fd
, "Owner: %s\n", tmp
->owner
? ast_channel_name(tmp
->owner
) : "<None>");
16030 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)" : "");
16031 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)" : "");
16032 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)" : "");
16033 ast_cli(a
->fd
, "Confno: %d\n", tmp
->confno
);
16034 ast_cli(a
->fd
, "Propagated Conference: %d\n", tmp
->propconfno
);
16035 ast_cli(a
->fd
, "Real in conference: %d\n", tmp
->inconference
);
16036 ast_cli(a
->fd
, "DSP: %s\n", tmp
->dsp
? "yes" : "no");
16037 ast_cli(a
->fd
, "Busy Detection: %s\n", tmp
->busydetect
? "yes" : "no");
16038 if (tmp
->busydetect
) {
16039 #if defined(BUSYDETECT_TONEONLY)
16040 ast_cli(a
->fd
, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16041 #elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16042 ast_cli(a
->fd
, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16044 #ifdef BUSYDETECT_DEBUG
16045 ast_cli(a
->fd
, " Busy Detector Debug: Enabled\n");
16047 ast_cli(a
->fd
, " Busy Count: %d\n", tmp
->busycount
);
16048 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);
16050 ast_cli(a
->fd
, "TDD: %s\n", tmp
->tdd
? "yes" : "no");
16051 ast_cli(a
->fd
, "Relax DTMF: %s\n", tmp
->dtmfrelax
? "yes" : "no");
16052 ast_cli(a
->fd
, "Dialing/CallwaitCAS: %d/%d\n", tmp
->dialing
, tmp
->callwaitcas
);
16053 ast_cli(a
->fd
, "Default law: %s\n", tmp
->law_default
== DAHDI_LAW_MULAW
? "ulaw" : tmp
->law_default
== DAHDI_LAW_ALAW
? "alaw" : "unknown");
16054 ast_cli(a
->fd
, "Fax Handled: %s\n", tmp
->faxhandled
? "yes" : "no");
16055 ast_cli(a
->fd
, "Pulse phone: %s\n", tmp
->pulsedial
? "yes" : "no");
16056 if (tmp
->hwrxgain_enabled
) {
16057 snprintf(hwrxgain
, sizeof(hwrxgain
), "%.1f", tmp
->hwrxgain
);
16059 ast_copy_string(hwrxgain
, "Disabled", sizeof(hwrxgain
));
16061 if (tmp
->hwtxgain_enabled
) {
16062 snprintf(hwtxgain
, sizeof(hwtxgain
), "%.1f", tmp
->hwtxgain
);
16064 ast_copy_string(hwtxgain
, "Disabled", sizeof(hwtxgain
));
16066 ast_cli(a
->fd
, "HW Gains (RX/TX): %s/%s\n", hwrxgain
, hwtxgain
);
16067 ast_cli(a
->fd
, "SW Gains (RX/TX): %.2f/%.2f\n", tmp
->rxgain
, tmp
->txgain
);
16068 ast_cli(a
->fd
, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp
->rxdrc
, tmp
->txdrc
);
16069 ast_cli(a
->fd
, "DND: %s\n", dahdi_dnd(tmp
, -1) ? "yes" : "no");
16070 ast_cli(a
->fd
, "Echo Cancellation:\n");
16072 if (tmp
->echocancel
.head
.tap_length
) {
16073 ast_cli(a
->fd
, "\t%u taps\n", tmp
->echocancel
.head
.tap_length
);
16074 for (x
= 0; x
< tmp
->echocancel
.head
.param_count
; x
++) {
16075 ast_cli(a
->fd
, "\t\t%s: %dd\n", tmp
->echocancel
.params
[x
].name
, tmp
->echocancel
.params
[x
].value
);
16077 ast_cli(a
->fd
, "\t%scurrently %s\n", tmp
->echocanbridged
? "" : "(unless TDM bridged) ", tmp
->echocanon
? "ON" : "OFF");
16079 ast_cli(a
->fd
, "\tnone\n");
16081 ast_cli(a
->fd
, "Wait for dialtone: %dms\n", tmp
->waitfordialtone
);
16083 ast_cli(a
->fd
, "Master Channel: %d\n", tmp
->master
->channel
);
16084 for (x
= 0; x
< MAX_SLAVES
; x
++) {
16085 if (tmp
->slaves
[x
])
16086 ast_cli(a
->fd
, "Slave Channel: %d\n", tmp
->slaves
[x
]->channel
);
16090 char calldir
[OR2_MAX_PATH
];
16091 openr2_context_t
*r2context
= openr2_chan_get_context(tmp
->r2chan
);
16092 openr2_variant_t r2variant
= openr2_context_get_variant(r2context
);
16093 ast_cli(a
->fd
, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp
->r2chan
));
16094 ast_cli(a
->fd
, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp
->r2chan
));
16095 ast_cli(a
->fd
, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp
->r2chan
));
16096 ast_cli(a
->fd
, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp
->r2chan
));
16097 ast_cli(a
->fd
, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp
->r2chan
) ? "Yes" : "No");
16098 ast_cli(a
->fd
, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant
));
16099 ast_cli(a
->fd
, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context
));
16100 ast_cli(a
->fd
, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context
));
16101 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16102 ast_cli(a
->fd
, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context
, NULL
, NULL
) ? "Yes" : "No");
16103 ast_cli(a
->fd
, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context
) ? "Yes" : "No");
16105 ast_cli(a
->fd
, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context
) ? "Yes" : "No");
16106 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16107 ast_cli(a
->fd
, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context
) ? "Yes" : "No");
16109 ast_cli(a
->fd
, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context
) ? "Yes" : "No");
16110 ast_cli(a
->fd
, "MFC/R2 Accept on Offer: %s\n", tmp
->mfcr2_accept_on_offer
? "Yes" : "No");
16111 ast_cli(a
->fd
, "MFC/R2 Charge Calls: %s\n", tmp
->mfcr2_charge_calls
? "Yes" : "No");
16112 ast_cli(a
->fd
, "MFC/R2 Allow Collect Calls: %s\n", tmp
->mfcr2_allow_collect_calls
? "Yes" : "No");
16113 ast_cli(a
->fd
, "MFC/R2 Forced Release: %s\n", tmp
->mfcr2_forced_release
? "Yes" : "No");
16114 ast_cli(a
->fd
, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context
));
16115 ast_cli(a
->fd
, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context
));
16116 ast_cli(a
->fd
, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp
->r2chan
));
16117 ast_cli(a
->fd
, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp
->r2chan
));
16118 ast_cli(a
->fd
, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp
->r2chan
));
16119 ast_cli(a
->fd
, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp
->r2chan
));
16120 ast_cli(a
->fd
, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context
, calldir
, sizeof(calldir
)));
16123 #if defined(HAVE_SS7)
16125 struct sig_ss7_chan
*chan
= tmp
->sig_pvt
;
16127 ast_cli(a
->fd
, "CIC: %d\n", chan
->cic
);
16129 #endif /* defined(HAVE_SS7) */
16132 struct sig_pri_chan
*chan
= tmp
->sig_pvt
;
16134 ast_cli(a
->fd
, "PRI Flags: ");
16135 if (chan
->resetting
!= SIG_PRI_RESET_IDLE
) {
16136 ast_cli(a
->fd
, "Resetting=%u ", chan
->resetting
);
16139 ast_cli(a
->fd
, "Call ");
16140 if (chan
->allocated
) {
16141 ast_cli(a
->fd
, "Allocated ");
16143 ast_cli(a
->fd
, "\n");
16144 if (tmp
->logicalspan
)
16145 ast_cli(a
->fd
, "PRI Logical Span: %d\n", tmp
->logicalspan
);
16147 ast_cli(a
->fd
, "PRI Logical Span: Implicit\n");
16150 memset(&ci
, 0, sizeof(ci
));
16151 ps
.channo
= tmp
->channel
;
16152 if (tmp
->subs
[SUB_REAL
].dfd
> -1) {
16153 memset(&ci
, 0, sizeof(ci
));
16154 if (!ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONF
, &ci
)) {
16155 ast_cli(a
->fd
, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci
.confno
, (unsigned)ci
.confmode
);
16157 if (!ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GETCONFMUTE
, &x
)) {
16158 ast_cli(a
->fd
, "Actual Confmute: %s\n", x
? "Yes" : "No");
16160 memset(&ps
, 0, sizeof(ps
));
16161 if (ioctl(tmp
->subs
[SUB_REAL
].dfd
, DAHDI_GET_PARAMS
, &ps
) < 0) {
16162 ast_log(LOG_WARNING
, "Failed to get parameters on channel %d: %s\n", tmp
->channel
, strerror(errno
));
16164 ast_cli(a
->fd
, "Hookstate (FXS only): %s\n", ps
.rxisoffhook
? "Offhook" : "Onhook");
16167 ast_mutex_unlock(&iflock
);
16168 return CLI_SUCCESS
;
16171 ast_mutex_unlock(&iflock
);
16173 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16174 return CLI_FAILURE
;
16177 static char *handle_dahdi_show_cadences(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16182 e
->command
= "dahdi show cadences";
16184 "Usage: dahdi show cadences\n"
16185 " Shows all cadences currently defined\n";
16190 for (i
= 0; i
< num_cadence
; i
++) {
16192 char tmp
[16], tmp2
[64];
16193 snprintf(tmp
, sizeof(tmp
), "r%d: ", i
+ 1);
16194 term_color(output
, tmp
, COLOR_GREEN
, COLOR_BLACK
, sizeof(output
));
16196 for (j
= 0; j
< 16; j
++) {
16197 if (cadences
[i
].ringcadence
[j
] == 0)
16199 snprintf(tmp
, sizeof(tmp
), "%d", cadences
[i
].ringcadence
[j
]);
16200 if (cidrings
[i
] * 2 - 1 == j
)
16201 term_color(tmp2
, tmp
, COLOR_MAGENTA
, COLOR_BLACK
, sizeof(tmp2
) - 1);
16203 term_color(tmp2
, tmp
, COLOR_GREEN
, COLOR_BLACK
, sizeof(tmp2
) - 1);
16205 strncat(output
, ",", sizeof(output
) - strlen(output
) - 1);
16206 strncat(output
, tmp2
, sizeof(output
) - strlen(output
) - 1);
16208 ast_cli(a
->fd
,"%s\n",output
);
16210 return CLI_SUCCESS
;
16213 /* Based on irqmiss.c */
16214 static char *dahdi_show_status(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16216 #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16217 #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16223 struct dahdi_spaninfo s
;
16227 e
->command
= "dahdi show status";
16229 "Usage: dahdi show status\n"
16230 " Shows a list of DAHDI cards with status\n";
16235 ctl
= open("/dev/dahdi/ctl", O_RDWR
);
16237 ast_cli(a
->fd
, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno
));
16238 return CLI_FAILURE
;
16240 ast_cli(a
->fd
, FORMAT2
, "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16242 for (span
= 1; span
< DAHDI_MAX_SPANS
; ++span
) {
16244 res
= ioctl(ctl
, DAHDI_SPANSTAT
, &s
);
16248 alarmstr
[0] = '\0';
16249 if (s
.alarms
> 0) {
16250 if (s
.alarms
& DAHDI_ALARM_BLUE
)
16251 strcat(alarmstr
, "BLU/");
16252 if (s
.alarms
& DAHDI_ALARM_YELLOW
)
16253 strcat(alarmstr
, "YEL/");
16254 if (s
.alarms
& DAHDI_ALARM_RED
)
16255 strcat(alarmstr
, "RED/");
16256 if (s
.alarms
& DAHDI_ALARM_LOOPBACK
)
16257 strcat(alarmstr
, "LB/");
16258 if (s
.alarms
& DAHDI_ALARM_RECOVER
)
16259 strcat(alarmstr
, "REC/");
16260 if (s
.alarms
& DAHDI_ALARM_NOTOPEN
)
16261 strcat(alarmstr
, "NOP/");
16262 if (!strlen(alarmstr
))
16263 strcat(alarmstr
, "UUU/");
16264 if (strlen(alarmstr
)) {
16265 /* Strip trailing / */
16266 alarmstr
[strlen(alarmstr
) - 1] = '\0';
16270 strcpy(alarmstr
, "OK");
16272 strcpy(alarmstr
, "UNCONFIGURED");
16275 ast_cli(a
->fd
, FORMAT
, s
.desc
, alarmstr
, s
.irqmisses
, s
.bpvcount
, s
.crc4count
,
16276 s
.lineconfig
& DAHDI_CONFIG_D4
? "D4" :
16277 s
.lineconfig
& DAHDI_CONFIG_ESF
? "ESF" :
16278 s
.lineconfig
& DAHDI_CONFIG_CCS
? "CCS" :
16280 s
.lineconfig
& DAHDI_CONFIG_B8ZS
? "B8ZS" :
16281 s
.lineconfig
& DAHDI_CONFIG_HDB3
? "HDB3" :
16282 s
.lineconfig
& DAHDI_CONFIG_AMI
? "AMI" :
16284 s
.lineconfig
& DAHDI_CONFIG_CRC4
?
16285 s
.lineconfig
& DAHDI_CONFIG_NOTOPEN
? "CRC4/YEL" : "CRC4" :
16286 s
.lineconfig
& DAHDI_CONFIG_NOTOPEN
? "YEL" : "",
16292 return CLI_SUCCESS
;
16297 static char *dahdi_show_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16299 int pseudo_fd
= -1;
16300 struct dahdi_versioninfo vi
;
16304 e
->command
= "dahdi show version";
16306 "Usage: dahdi show version\n"
16307 " Shows the DAHDI version in use\n";
16312 if ((pseudo_fd
= open("/dev/dahdi/ctl", O_RDONLY
)) < 0) {
16313 ast_cli(a
->fd
, "Failed to open control file to get version.\n");
16314 return CLI_SUCCESS
;
16317 strcpy(vi
.version
, "Unknown");
16318 strcpy(vi
.echo_canceller
, "Unknown");
16320 if (ioctl(pseudo_fd
, DAHDI_GETVERSION
, &vi
))
16321 ast_cli(a
->fd
, "Failed to get DAHDI version: %s\n", strerror(errno
));
16323 ast_cli(a
->fd
, "DAHDI Version: %s Echo Canceller: %s\n", vi
.version
, vi
.echo_canceller
);
16327 return CLI_SUCCESS
;
16330 static char *dahdi_set_hwgain(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16335 struct dahdi_pvt
*tmp
= NULL
;
16339 e
->command
= "dahdi set hwgain {rx|tx}";
16341 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16342 " Sets the hardware gain on a given channel and overrides the\n"
16343 " value provided at module loadtime. Changes take effect\n"
16344 " immediately whether the channel is in use or not.\n"
16346 " <rx|tx> which direction do you want to change (relative to our module)\n"
16347 " <chan num> is the channel number relative to the device\n"
16348 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16351 " * hwgain is only supportable by hardware with analog ports because\n"
16352 " hwgain works on the analog side of an analog-digital conversion.\n";
16359 return CLI_SHOWUSAGE
;
16361 if (!strcasecmp("rx", a
->argv
[3]))
16363 else if (!strcasecmp("tx", a
->argv
[3]))
16366 return CLI_SHOWUSAGE
;
16368 channel
= atoi(a
->argv
[4]);
16369 gain
= atof(a
->argv
[5]);
16371 ast_mutex_lock(&iflock
);
16373 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16375 if (tmp
->channel
!= channel
)
16378 if (tmp
->subs
[SUB_REAL
].dfd
== -1)
16381 if (set_hwgain(tmp
->subs
[SUB_REAL
].dfd
, gain
, tx
)) {
16382 ast_cli(a
->fd
, "Unable to set the hardware gain for channel %d: %s\n", channel
, strerror(errno
));
16383 ast_mutex_unlock(&iflock
);
16384 return CLI_FAILURE
;
16386 ast_cli(a
->fd
, "Hardware %s gain set to %.1f dB on channel %d.\n",
16387 tx
? "tx" : "rx", gain
, channel
);
16390 tmp
->hwtxgain_enabled
= 1;
16391 tmp
->hwtxgain
= gain
;
16393 tmp
->hwrxgain_enabled
= 1;
16394 tmp
->hwrxgain
= gain
;
16399 ast_mutex_unlock(&iflock
);
16402 return CLI_SUCCESS
;
16404 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16405 return CLI_FAILURE
;
16409 static char *dahdi_set_swgain(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16415 struct dahdi_pvt
*tmp
= NULL
;
16419 e
->command
= "dahdi set swgain {rx|tx}";
16421 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16422 " Sets the software gain on a given channel and overrides the\n"
16423 " value provided at module loadtime. Changes take effect\n"
16424 " immediately whether the channel is in use or not.\n"
16426 " <rx|tx> which direction do you want to change (relative to our module)\n"
16427 " <chan num> is the channel number relative to the device\n"
16428 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16435 return CLI_SHOWUSAGE
;
16437 if (!strcasecmp("rx", a
->argv
[3]))
16439 else if (!strcasecmp("tx", a
->argv
[3]))
16442 return CLI_SHOWUSAGE
;
16444 channel
= atoi(a
->argv
[4]);
16445 gain
= atof(a
->argv
[5]);
16447 ast_mutex_lock(&iflock
);
16448 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16450 if (tmp
->channel
!= channel
)
16453 if (tmp
->subs
[SUB_REAL
].dfd
== -1)
16457 res
= set_actual_txgain(tmp
->subs
[SUB_REAL
].dfd
, gain
, tmp
->txdrc
, tmp
->law
);
16459 res
= set_actual_rxgain(tmp
->subs
[SUB_REAL
].dfd
, gain
, tmp
->rxdrc
, tmp
->law
);
16462 ast_cli(a
->fd
, "Unable to set the software gain for channel %d\n", channel
);
16463 ast_mutex_unlock(&iflock
);
16464 return CLI_FAILURE
;
16467 ast_cli(a
->fd
, "Software %s gain set to %.2f dB on channel %d.\n",
16468 tx
? "tx" : "rx", gain
, channel
);
16471 tmp
->txgain
= gain
;
16473 tmp
->rxgain
= gain
;
16477 ast_mutex_unlock(&iflock
);
16480 return CLI_SUCCESS
;
16482 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16483 return CLI_FAILURE
;
16487 static char *dahdi_set_dnd(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16491 struct dahdi_pvt
*dahdi_chan
= NULL
;
16495 e
->command
= "dahdi set dnd";
16497 "Usage: dahdi set dnd <chan#> <on|off>\n"
16498 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16499 " Changes take effect immediately.\n"
16500 " <chan num> is the channel number\n"
16501 " <on|off> Enable or disable DND mode?\n"
16509 return CLI_SHOWUSAGE
;
16511 if ((channel
= atoi(a
->argv
[3])) <= 0) {
16512 ast_cli(a
->fd
, "Expected channel number, got '%s'\n", a
->argv
[3]);
16513 return CLI_SHOWUSAGE
;
16516 if (ast_true(a
->argv
[4]))
16518 else if (ast_false(a
->argv
[4]))
16521 ast_cli(a
->fd
, "Expected 'on' or 'off', got '%s'\n", a
->argv
[4]);
16522 return CLI_SHOWUSAGE
;
16525 ast_mutex_lock(&iflock
);
16526 for (dahdi_chan
= iflist
; dahdi_chan
; dahdi_chan
= dahdi_chan
->next
) {
16527 if (dahdi_chan
->channel
!= channel
)
16530 /* Found the channel. Actually set it */
16531 dahdi_dnd(dahdi_chan
, on
);
16534 ast_mutex_unlock(&iflock
);
16537 ast_cli(a
->fd
, "Unable to find given channel %d\n", channel
);
16538 return CLI_FAILURE
;
16541 return CLI_SUCCESS
;
16544 static struct ast_cli_entry dahdi_cli
[] = {
16545 AST_CLI_DEFINE(handle_dahdi_show_cadences
, "List cadences"),
16546 AST_CLI_DEFINE(dahdi_show_channels
, "Show active DAHDI channels"),
16547 AST_CLI_DEFINE(dahdi_show_channel
, "Show information on a channel"),
16548 AST_CLI_DEFINE(dahdi_destroy_channels
, "Destroy channels"),
16549 AST_CLI_DEFINE(dahdi_create_channels
, "Create channels"),
16550 AST_CLI_DEFINE(dahdi_restart_cmd
, "Fully restart DAHDI channels"),
16551 AST_CLI_DEFINE(dahdi_show_status
, "Show all DAHDI cards status"),
16552 AST_CLI_DEFINE(dahdi_show_version
, "Show the DAHDI version in use"),
16553 AST_CLI_DEFINE(dahdi_set_hwgain
, "Set hardware gain on a channel"),
16554 AST_CLI_DEFINE(dahdi_set_swgain
, "Set software gain on a channel"),
16555 AST_CLI_DEFINE(dahdi_set_dnd
, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16561 static int dahdi_fake_event(struct dahdi_pvt
*p
, int mode
)
16566 p
->fake_event
= DAHDI_EVENT_WINKFLASH
;
16569 p
->fake_event
= DAHDI_EVENT_ONHOOK
;
16572 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
));
16577 static struct dahdi_pvt
*find_channel(int channel
)
16579 struct dahdi_pvt
*p
;
16581 ast_mutex_lock(&iflock
);
16582 for (p
= iflist
; p
; p
= p
->next
) {
16583 if (p
->channel
== channel
) {
16587 ast_mutex_unlock(&iflock
);
16593 * \brief Get private struct using given numeric channel string.
16595 * \param channel Numeric channel number string get private struct.
16597 * \retval pvt on success.
16598 * \retval NULL on error.
16600 static struct dahdi_pvt
*find_channel_from_str(const char *channel
)
16604 if (sscanf(channel
, "%30d", &chan_num
) != 1) {
16605 /* Not numeric string. */
16609 return find_channel(chan_num
);
16612 static int action_dahdidndon(struct mansession
*s
, const struct message
*m
)
16614 struct dahdi_pvt
*p
;
16615 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16617 if (ast_strlen_zero(channel
)) {
16618 astman_send_error(s
, m
, "No channel specified");
16621 p
= find_channel_from_str(channel
);
16623 astman_send_error(s
, m
, "No such channel");
16627 astman_send_ack(s
, m
, "DND Enabled");
16631 static int action_dahdidndoff(struct mansession
*s
, const struct message
*m
)
16633 struct dahdi_pvt
*p
;
16634 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16636 if (ast_strlen_zero(channel
)) {
16637 astman_send_error(s
, m
, "No channel specified");
16640 p
= find_channel_from_str(channel
);
16642 astman_send_error(s
, m
, "No such channel");
16646 astman_send_ack(s
, m
, "DND Disabled");
16650 static int action_transfer(struct mansession
*s
, const struct message
*m
)
16652 struct dahdi_pvt
*p
;
16653 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16655 if (ast_strlen_zero(channel
)) {
16656 astman_send_error(s
, m
, "No channel specified");
16659 p
= find_channel_from_str(channel
);
16661 astman_send_error(s
, m
, "No such channel");
16664 if (!dahdi_analog_lib_handles(p
->sig
, 0, 0)) {
16665 astman_send_error(s
, m
, "Channel signaling is not analog");
16668 dahdi_fake_event(p
,TRANSFER
);
16669 astman_send_ack(s
, m
, "DAHDITransfer");
16673 static int action_transferhangup(struct mansession
*s
, const struct message
*m
)
16675 struct dahdi_pvt
*p
;
16676 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16678 if (ast_strlen_zero(channel
)) {
16679 astman_send_error(s
, m
, "No channel specified");
16682 p
= find_channel_from_str(channel
);
16684 astman_send_error(s
, m
, "No such channel");
16687 if (!dahdi_analog_lib_handles(p
->sig
, 0, 0)) {
16688 astman_send_error(s
, m
, "Channel signaling is not analog");
16691 dahdi_fake_event(p
,HANGUP
);
16692 astman_send_ack(s
, m
, "DAHDIHangup");
16696 static int action_dahdidialoffhook(struct mansession
*s
, const struct message
*m
)
16698 struct dahdi_pvt
*p
;
16699 const char *channel
= astman_get_header(m
, "DAHDIChannel");
16700 const char *number
= astman_get_header(m
, "Number");
16703 if (ast_strlen_zero(channel
)) {
16704 astman_send_error(s
, m
, "No channel specified");
16707 if (ast_strlen_zero(number
)) {
16708 astman_send_error(s
, m
, "No number specified");
16711 p
= find_channel_from_str(channel
);
16713 astman_send_error(s
, m
, "No such channel");
16717 astman_send_error(s
, m
, "Channel does not have it's owner");
16720 for (i
= 0; i
< strlen(number
); i
++) {
16721 struct ast_frame f
= { AST_FRAME_DTMF
, .subclass
.integer
= number
[i
] };
16722 dahdi_queue_frame(p
, &f
);
16724 astman_send_ack(s
, m
, "DAHDIDialOffhook");
16728 static int action_dahdishowchannels(struct mansession
*s
, const struct message
*m
)
16730 struct dahdi_pvt
*tmp
= NULL
;
16731 const char *id
= astman_get_header(m
, "ActionID");
16732 const char *dahdichannel
= astman_get_header(m
, "DAHDIChannel");
16735 int dahdichanquery
;
16737 if (!dahdichannel
|| sscanf(dahdichannel
, "%30d", &dahdichanquery
) != 1) {
16738 /* Not numeric string. */
16739 dahdichanquery
= -1;
16743 if (!ast_strlen_zero(id
)) {
16744 snprintf(idText
, sizeof(idText
), "ActionID: %s\r\n", id
);
16747 astman_send_listack(s
, m
, "DAHDI channel status will follow", "start");
16749 ast_mutex_lock(&iflock
);
16751 for (tmp
= iflist
; tmp
; tmp
= tmp
->next
) {
16752 if (tmp
->channel
> 0) {
16755 /* If a specific channel is queried for, only deliver status for that channel */
16756 if (dahdichanquery
> 0 && tmp
->channel
!= dahdichanquery
)
16759 alm
= get_alarms(tmp
);
16762 /* Add data if we have a current call */
16764 "Event: DAHDIShowChannels\r\n"
16765 "DAHDIChannel: %d\r\n"
16768 "AccountCode: %s\r\n"
16769 "Signalling: %s\r\n"
16770 "SignallingCode: %d\r\n"
16774 "Description: %s\r\n"
16778 ast_channel_name(tmp
->owner
),
16779 ast_channel_uniqueid(tmp
->owner
),
16780 ast_channel_accountcode(tmp
->owner
),
16784 dahdi_dnd(tmp
, -1) ? "Enabled" : "Disabled",
16786 tmp
->description
, idText
);
16789 "Event: DAHDIShowChannels\r\n"
16790 "DAHDIChannel: %d\r\n"
16791 "Signalling: %s\r\n"
16792 "SignallingCode: %d\r\n"
16796 "Description: %s\r\n"
16799 tmp
->channel
, sig2str(tmp
->sig
), tmp
->sig
,
16801 dahdi_dnd(tmp
, -1) ? "Enabled" : "Disabled",
16803 tmp
->description
, idText
);
16808 ast_mutex_unlock(&iflock
);
16810 astman_send_list_complete_start(s
, m
, "DAHDIShowChannelsComplete", channels
);
16811 astman_append(s
, "Items: %d\r\n", channels
);
16812 astman_send_list_complete_end(s
);
16816 #if defined(HAVE_PRI)
16817 static int action_prishowspans(struct mansession
*s
, const struct message
*m
)
16822 struct dahdi_pri
*dspan
;
16823 const char *id
= astman_get_header(m
, "ActionID");
16824 const char *span_str
= astman_get_header(m
, "Span");
16825 char action_id
[256];
16826 const char *show_cmd
= "PRIShowSpans";
16828 /* NOTE: Asking for span 0 gets all spans. */
16829 if (!ast_strlen_zero(span_str
)) {
16830 span_query
= atoi(span_str
);
16835 if (!ast_strlen_zero(id
)) {
16836 snprintf(action_id
, sizeof(action_id
), "ActionID: %s\r\n", id
);
16838 action_id
[0] = '\0';
16841 astman_send_listack(s
, m
, "Span status will follow", "start");
16844 for (idx
= 0; idx
< ARRAY_LEN(pris
); ++idx
) {
16845 dspan
= &pris
[idx
];
16847 /* If a specific span is asked for, only deliver status for that span. */
16848 if (0 < span_query
&& dspan
->pri
.span
!= span_query
) {
16852 if (dspan
->pri
.pri
) {
16853 count
+= sig_pri_ami_show_spans(s
, show_cmd
, &dspan
->pri
, dspan
->dchannels
,
16858 astman_send_list_complete_start(s
, m
, "PRIShowSpansComplete", count
);
16859 astman_append(s
, "Items: %d\r\n", count
);
16860 astman_send_list_complete_end(s
);
16863 #endif /* defined(HAVE_PRI) */
16865 #if defined(HAVE_SS7)
16866 static int linkset_addsigchan(int sigchan
)
16868 struct dahdi_ss7
*link
;
16871 struct dahdi_params params
;
16872 struct dahdi_bufferinfo bi
;
16873 struct dahdi_spaninfo si
;
16876 ast_log(LOG_ERROR
, "Invalid sigchan!\n");
16879 if (cur_ss7type
< 0) {
16880 ast_log(LOG_ERROR
, "Unspecified or invalid ss7type\n");
16883 if (cur_pointcode
< 0) {
16884 ast_log(LOG_ERROR
, "Unspecified pointcode!\n");
16887 if (cur_adjpointcode
< 0) {
16888 ast_log(LOG_ERROR
, "Unspecified adjpointcode!\n");
16891 if (cur_defaultdpc
< 0) {
16892 ast_log(LOG_ERROR
, "Unspecified defaultdpc!\n");
16895 if (cur_networkindicator
< 0) {
16896 ast_log(LOG_ERROR
, "Invalid networkindicator!\n");
16899 link
= ss7_resolve_linkset(cur_linkset
);
16901 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
16904 if (link
->ss7
.numsigchans
>= SIG_SS7_NUM_DCHANS
) {
16905 ast_log(LOG_ERROR
, "Too many sigchans on linkset %d\n", cur_linkset
);
16909 curfd
= link
->ss7
.numsigchans
;
16911 /* Open signaling channel */
16912 link
->ss7
.fds
[curfd
] = open("/dev/dahdi/channel", O_RDWR
, 0600);
16913 if (link
->ss7
.fds
[curfd
] < 0) {
16914 ast_log(LOG_ERROR
, "Unable to open SS7 sigchan %d (%s)\n", sigchan
,
16918 if (ioctl(link
->ss7
.fds
[curfd
], DAHDI_SPECIFY
, &sigchan
) == -1) {
16919 dahdi_close_ss7_fd(link
, curfd
);
16920 ast_log(LOG_ERROR
, "Unable to specify SS7 sigchan %d (%s)\n", sigchan
,
16925 /* Get signaling channel parameters */
16926 memset(¶ms
, 0, sizeof(params
));
16927 res
= ioctl(link
->ss7
.fds
[curfd
], DAHDI_GET_PARAMS
, ¶ms
);
16929 dahdi_close_ss7_fd(link
, curfd
);
16930 ast_log(LOG_ERROR
, "Unable to get parameters for sigchan %d (%s)\n", sigchan
,
16934 if (params
.sigtype
!= DAHDI_SIG_HDLCFCS
16935 && params
.sigtype
!= DAHDI_SIG_HARDHDLC
16936 && params
.sigtype
!= DAHDI_SIG_MTP2
) {
16937 dahdi_close_ss7_fd(link
, curfd
);
16938 ast_log(LOG_ERROR
, "sigchan %d is not in HDLC/FCS mode.\n", sigchan
);
16942 /* Set signaling channel buffer policy. */
16943 memset(&bi
, 0, sizeof(bi
));
16944 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
16945 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
16948 if (ioctl(link
->ss7
.fds
[curfd
], DAHDI_SET_BUFINFO
, &bi
)) {
16949 ast_log(LOG_ERROR
, "Unable to set appropriate buffering on channel %d: %s\n",
16950 sigchan
, strerror(errno
));
16951 dahdi_close_ss7_fd(link
, curfd
);
16955 /* Get current signaling channel alarm status. */
16956 memset(&si
, 0, sizeof(si
));
16957 res
= ioctl(link
->ss7
.fds
[curfd
], DAHDI_SPANSTAT
, &si
);
16959 dahdi_close_ss7_fd(link
, curfd
);
16960 ast_log(LOG_ERROR
, "Unable to get span state for sigchan %d (%s)\n", sigchan
,
16964 res
= sig_ss7_add_sigchan(&link
->ss7
, curfd
, cur_ss7type
,
16965 (params
.sigtype
== DAHDI_SIG_MTP2
)
16966 ? SS7_TRANSPORT_DAHDIMTP2
16967 : SS7_TRANSPORT_DAHDIDCHAN
,
16968 si
.alarms
, cur_networkindicator
, cur_pointcode
, cur_adjpointcode
, cur_slc
);
16970 dahdi_close_ss7_fd(link
, curfd
);
16974 ++link
->ss7
.numsigchans
;
16978 #endif /* defined(HAVE_SS7) */
16980 #if defined(HAVE_SS7)
16981 static char *handle_ss7_debug(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
16986 e
->command
= "ss7 set debug {on|off} linkset";
16988 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
16989 " Enables debugging on a given SS7 linkset\n";
16996 return CLI_SHOWUSAGE
;
16999 span
= atoi(a
->argv
[5]);
17000 if ((span
< 1) || (span
> NUM_SPANS
)) {
17001 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number from %d to %d\n", a
->argv
[5], 1, NUM_SPANS
);
17002 return CLI_SUCCESS
;
17004 if (!linksets
[span
-1].ss7
.ss7
) {
17005 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", span
);
17007 if (!strcasecmp(a
->argv
[3], "on")) {
17008 linksets
[span
- 1].ss7
.debug
= 1;
17009 ss7_set_debug(linksets
[span
-1].ss7
.ss7
, SIG_SS7_DEBUG
);
17010 ast_cli(a
->fd
, "Enabled debugging on linkset %d\n", span
);
17012 linksets
[span
- 1].ss7
.debug
= 0;
17013 ss7_set_debug(linksets
[span
-1].ss7
.ss7
, 0);
17014 ast_cli(a
->fd
, "Disabled debugging on linkset %d\n", span
);
17018 return CLI_SUCCESS
;
17020 #endif /* defined(HAVE_SS7) */
17022 #if defined(HAVE_SS7)
17023 static char *handle_ss7_cic_blocking(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17032 e
->command
= "ss7 {block|unblock} cic";
17034 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17035 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17041 if (a
->argc
== 6) {
17042 linkset
= atoi(a
->argv
[3]);
17044 return CLI_SHOWUSAGE
;
17047 if (!strcasecmp(a
->argv
[1], "block")) {
17049 } else if (strcasecmp(a
->argv
[1], "unblock")) {
17050 return CLI_SHOWUSAGE
;
17053 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17054 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17055 return CLI_SUCCESS
;
17058 if (!linksets
[linkset
-1].ss7
.ss7
) {
17059 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17060 return CLI_SUCCESS
;
17063 cic
= atoi(a
->argv
[5]);
17065 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17066 return CLI_SUCCESS
;
17069 dpc
= atoi(a
->argv
[4]);
17071 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17072 return CLI_SUCCESS
;
17075 for (i
= 0; i
< linksets
[linkset
-1].ss7
.numchans
; i
++) {
17076 if (linksets
[linkset
-1].ss7
.pvts
[i
] && linksets
[linkset
-1].ss7
.pvts
[i
]->cic
== cic
&& linksets
[linkset
-1].ss7
.pvts
[i
]->dpc
== dpc
) {
17077 blocked
= linksets
[linkset
-1].ss7
.pvts
[i
]->locallyblocked
;
17078 if (!do_block
^ !(blocked
& SS7_BLOCKED_MAINTENANCE
)) {
17079 if (sig_ss7_cic_blocking(&linksets
[linkset
-1].ss7
, do_block
, i
) < 0) {
17080 ast_cli(a
->fd
, "Unable to allocate new ss7call\n");
17082 ast_cli(a
->fd
, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block
) ? "" : "un", linkset
, cic
, dpc
);
17084 } else if (!do_block
&& blocked
) {
17085 ast_cli(a
->fd
, "CIC %d is hardware locally blocked!\n", cic
);
17087 ast_cli(a
->fd
, "CIC %d %s locally blocked\n", cic
, do_block
? "already" : "is not");
17089 return CLI_SUCCESS
;
17093 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17094 return CLI_SUCCESS
;
17096 #endif /* defined(HAVE_SS7) */
17098 #if defined(HAVE_SS7)
17099 static char *handle_ss7_linkset_mng(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17110 e
->command
= "ss7 {reset|block|unblock} linkset";
17112 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17113 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17119 if (a
->argc
== 4) {
17120 linkset
= atoi(a
->argv
[3]);
17122 return CLI_SHOWUSAGE
;
17125 if (!strcasecmp(a
->argv
[1], "block")) {
17126 do_what
= DO_BLOCK
;
17127 } else if (!strcasecmp(a
->argv
[1], "unblock")) {
17128 do_what
= DO_UNBLOCK
;
17129 } else if (!strcasecmp(a
->argv
[1], "reset")) {
17130 do_what
= DO_RESET
;
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 for (i
= 0; i
< linksets
[linkset
- 1].ss7
.numchans
; i
++) {
17146 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17147 if (linksets
[linkset
- 1].ss7
.pvts
[i
]) {
17151 if (sig_ss7_cic_blocking(&linksets
[linkset
- 1].ss7
, do_what
== DO_BLOCK
, i
)) {
17152 ast_cli(a
->fd
, "Sent remote %s request on CIC %d\n",
17153 (do_what
== DO_BLOCK
) ? "blocking" : "unblocking",
17154 linksets
[linkset
- 1].ss7
.pvts
[i
]->cic
);
17158 if (sig_ss7_reset_cic(&linksets
[linkset
- 1].ss7
,
17159 linksets
[linkset
- 1].ss7
.pvts
[i
]->cic
,
17160 linksets
[linkset
- 1].ss7
.pvts
[i
]->dpc
)) {
17161 ast_cli(a
->fd
, "Sent reset request on CIC %d\n",
17162 linksets
[linkset
- 1].ss7
.pvts
[i
]->cic
);
17169 return CLI_SUCCESS
;
17171 #endif /* defined(HAVE_SS7) */
17173 #if defined(HAVE_SS7)
17174 static char *handle_ss7_group_blocking(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17176 int linkset
, cic
, range
, chanpos
;
17177 int i
, dpc
, orient
= 0;
17179 unsigned char state
[255];
17183 e
->command
= "ss7 {block|unblock} group";
17185 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17186 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17192 if (a
->argc
== 7 || a
->argc
== 8) {
17193 linkset
= atoi(a
->argv
[3]);
17195 return CLI_SHOWUSAGE
;
17198 if (!strcasecmp(a
->argv
[1], "block")) {
17200 } else if (strcasecmp(a
->argv
[1], "unblock")) {
17201 return CLI_SHOWUSAGE
;
17204 if (a
->argc
== 8) {
17205 if (!strcasecmp(a
->argv
[7], "H")) {
17208 return CLI_SHOWUSAGE
;
17212 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17213 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[4], 1, NUM_SPANS
);
17214 return CLI_SUCCESS
;
17217 if (!linksets
[linkset
-1].ss7
.ss7
) {
17218 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17219 return CLI_SUCCESS
;
17222 cic
= atoi(a
->argv
[5]);
17224 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17225 return CLI_SUCCESS
;
17228 range
= atoi(a
->argv
[6]);
17229 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17230 if (range
< 1 || range
> (linksets
[linkset
- 1].ss7
.type
== SS7_ANSI
? 24 : 31)) {
17231 ast_cli(a
->fd
, "Invalid range specified!\n");
17232 return CLI_SUCCESS
;
17235 dpc
= atoi(a
->argv
[4]);
17237 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17238 return CLI_SUCCESS
;
17241 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17242 if (!sig_ss7_find_cic_range(&linksets
[linkset
-1].ss7
, cic
, cic
+ range
, dpc
)) {
17243 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17244 ast_cli(a
->fd
, "Invalid CIC/RANGE\n");
17245 return CLI_SHOWUSAGE
;
17248 memset(state
, 0, sizeof(state
));
17249 for (i
= 0; i
<= range
; ++i
) {
17253 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17254 chanpos
= sig_ss7_find_cic(&linksets
[linkset
-1].ss7
, cic
, dpc
);
17255 if (sig_ss7_group_blocking(&linksets
[linkset
-1].ss7
, do_block
, chanpos
, cic
+ range
, state
, orient
)) {
17256 ast_cli(a
->fd
, "Unable allocate new ss7call\n");
17258 ast_cli(a
->fd
, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17259 orient
? " hardware" : "", do_block
? "" : "un", linkset
, cic
, range
);
17262 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17264 /* Break poll on the linkset so it sends our messages */
17265 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17266 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17268 return CLI_SUCCESS
;
17270 #endif /* defined(HAVE_SS7) */
17272 #if defined(HAVE_SS7)
17273 static char *handle_ss7_group_reset(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17275 int linkset
, cic
, range
;
17280 e
->command
= "ss7 reset group";
17282 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17283 " Send a GRS for the given CIC range on the specified linkset\n";
17289 if (a
->argc
== 7) {
17290 linkset
= atoi(a
->argv
[3]);
17292 return CLI_SHOWUSAGE
;
17295 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17296 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[4], 1, NUM_SPANS
);
17297 return CLI_SUCCESS
;
17300 if (!linksets
[linkset
-1].ss7
.ss7
) {
17301 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17302 return CLI_SUCCESS
;
17305 cic
= atoi(a
->argv
[5]);
17308 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17309 return CLI_SUCCESS
;
17312 range
= atoi(a
->argv
[6]);
17313 if (range
< 1 || range
> (linksets
[linkset
- 1].ss7
.type
== SS7_ANSI
? 24 : 31)) {
17314 ast_cli(a
->fd
, "Invalid range specified!\n");
17315 return CLI_SUCCESS
;
17318 dpc
= atoi(a
->argv
[4]);
17320 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17321 return CLI_SUCCESS
;
17324 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17325 if (!sig_ss7_find_cic_range(&linksets
[linkset
-1].ss7
, cic
, cic
+ range
, dpc
)) {
17326 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17327 ast_cli(a
->fd
, "Invalid CIC/RANGE\n");
17328 return CLI_SHOWUSAGE
;
17331 if (sig_ss7_reset_group(&linksets
[linkset
-1].ss7
, cic
, dpc
, range
)) {
17332 ast_cli(a
->fd
, "Unable to allocate new ss7call\n");
17334 ast_cli(a
->fd
, "GRS sent ... \n");
17337 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17339 /* Break poll on the linkset so it sends our messages */
17340 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17341 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17343 return CLI_SUCCESS
;
17345 #endif /* defined(HAVE_SS7) */
17347 #if defined(HAVE_SS7)
17348 static char *handle_ss7_show_calls(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17354 e
->command
= "ss7 show calls";
17356 "Usage: ss7 show calls <linkset>\n"
17357 " Show SS7 calls on the specified linkset\n";
17363 if (a
->argc
== 4) {
17364 linkset
= atoi(a
->argv
[3]);
17366 return CLI_SHOWUSAGE
;
17369 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17370 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17371 return CLI_SUCCESS
;
17374 if (!linksets
[linkset
-1].ss7
.ss7
) {
17375 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17376 return CLI_SUCCESS
;
17379 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17380 isup_show_calls(linksets
[linkset
-1].ss7
.ss7
, &ast_cli
, a
->fd
);
17381 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17383 return CLI_SUCCESS
;
17385 #endif /* defined(HAVE_SS7) */
17387 #if defined(HAVE_SS7)
17388 static char *handle_ss7_reset_cic(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17390 int linkset
, cic
, res
;
17395 e
->command
= "ss7 reset cic";
17397 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17398 " Send a RSC for the given CIC on the specified linkset\n";
17404 if (a
->argc
== 6) {
17405 linkset
= atoi(a
->argv
[3]);
17407 return CLI_SHOWUSAGE
;
17410 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17411 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17412 return CLI_SUCCESS
;
17415 if (!linksets
[linkset
-1].ss7
.ss7
) {
17416 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17417 return CLI_SUCCESS
;
17420 cic
= atoi(a
->argv
[5]);
17423 ast_cli(a
->fd
, "Invalid CIC specified!\n");
17424 return CLI_SUCCESS
;
17427 dpc
= atoi(a
->argv
[4]);
17429 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17430 return CLI_SUCCESS
;
17433 res
= sig_ss7_reset_cic(&linksets
[linkset
-1].ss7
, cic
, dpc
);
17435 ast_cli(a
->fd
, "%s RSC for linkset %d on CIC %d DPC %d\n", res
? "Sent" : "Failed", linkset
, cic
, dpc
);
17437 return CLI_SUCCESS
;
17439 #endif /* defined(HAVE_SS7) */
17441 #if defined(HAVE_SS7)
17442 static char *handle_ss7_net_mng(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17446 unsigned int arg
= 0;
17451 e
->command
= "ss7 mtp3";
17453 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
17454 " Send a NET MNG message\n"
17455 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
17462 return CLI_SHOWUSAGE
;
17465 linkset
= atoi(a
->argv
[2]);
17466 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17467 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[2], 1, NUM_SPANS
);
17468 return CLI_SUCCESS
;
17470 if (!linksets
[linkset
-1].ss7
.ss7
) {
17471 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17472 return CLI_SUCCESS
;
17475 slc
= atoi(a
->argv
[3]);
17477 if (a
->argc
== 6) {
17478 arg
= atoi(a
->argv
[5]);
17481 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17482 res
= mtp3_net_mng(linksets
[linkset
-1].ss7
.ss7
, slc
, a
->argv
[4], arg
);
17483 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17485 /* Break poll on the linkset so it sends our messages */
17486 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17487 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17490 ast_cli(a
->fd
, "%s", res
);
17492 return CLI_SUCCESS
;
17494 #endif /* defined(HAVE_SS7) */
17496 #if defined(HAVE_SS7)
17497 static char *handle_ss7_mtp3_restart(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17500 unsigned int slc
= 0;
17504 e
->command
= "ss7 restart mtp3";
17506 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
17514 return CLI_SHOWUSAGE
;
17517 linkset
= atoi(a
->argv
[3]);
17518 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17519 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[2], 1, NUM_SPANS
);
17520 return CLI_SUCCESS
;
17522 if (!linksets
[linkset
-1].ss7
.ss7
) {
17523 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17524 return CLI_SUCCESS
;
17527 slc
= atoi(a
->argv
[4]);
17529 ast_mutex_lock(&linksets
[linkset
-1].ss7
.lock
);
17530 mtp3_init_restart(linksets
[linkset
-1].ss7
.ss7
, slc
);
17531 ast_mutex_unlock(&linksets
[linkset
-1].ss7
.lock
);
17533 /* Break poll on the linkset so it sends our messages */
17534 if (linksets
[linkset
-1].ss7
.master
!= AST_PTHREADT_NULL
) {
17535 pthread_kill(linksets
[linkset
-1].ss7
.master
, SIGURG
);
17538 return CLI_SUCCESS
;
17540 #endif /* defined(HAVE_SS7) */
17542 #if defined(HAVE_SS7)
17543 static char *handle_ss7_show_linkset(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17546 struct sig_ss7_linkset
*ss7
;
17549 e
->command
= "ss7 show linkset";
17551 "Usage: ss7 show linkset <span>\n"
17552 " Shows the status of an SS7 linkset.\n";
17559 return CLI_SHOWUSAGE
;
17562 linkset
= atoi(a
->argv
[3]);
17563 if ((linkset
< 1) || (linkset
> NUM_SPANS
)) {
17564 ast_cli(a
->fd
, "Invalid linkset %s. Should be a number %d to %d\n", a
->argv
[3], 1, NUM_SPANS
);
17565 return CLI_SUCCESS
;
17567 ss7
= &linksets
[linkset
- 1].ss7
;
17569 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17570 return CLI_SUCCESS
;
17573 ast_cli(a
->fd
, "SS7 flags: 0x%x\n", ss7
->flags
);
17574 ast_cli(a
->fd
, "SS7 linkset %d status: %s\n", linkset
, (ss7
->state
== LINKSET_STATE_UP
) ? "Up" : "Down");
17575 ast_cli(a
->fd
, "SS7 calling nai: %i\n", ss7
->calling_nai
);
17576 ast_cli(a
->fd
, "SS7 called nai: %i\n", ss7
->called_nai
);
17577 ast_cli(a
->fd
, "SS7 nationalprefix: %s\n", ss7
->nationalprefix
);
17578 ast_cli(a
->fd
, "SS7 internationalprefix: %s\n", ss7
->internationalprefix
);
17579 ast_cli(a
->fd
, "SS7 unknownprefix: %s\n", ss7
->unknownprefix
);
17580 ast_cli(a
->fd
, "SS7 networkroutedprefix: %s\n", ss7
->networkroutedprefix
);
17581 ast_cli(a
->fd
, "SS7 subscriberprefix: %s\n", ss7
->subscriberprefix
);
17582 ss7_show_linkset(ss7
->ss7
, &ast_cli
, a
->fd
);
17584 return CLI_SUCCESS
;
17586 #endif /* defined(HAVE_SS7) */
17588 #if defined(HAVE_SS7)
17589 static char *handle_ss7_show_channels(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17595 e
->command
= "ss7 show channels";
17597 "Usage: ss7 show channels\n"
17598 " Displays SS7 channel information at a glance.\n";
17604 if (a
->argc
!= 3) {
17605 return CLI_SHOWUSAGE
;
17608 sig_ss7_cli_show_channels_header(a
->fd
);
17609 for (linkset
= 0; linkset
< NUM_SPANS
; ++linkset
) {
17610 if (linksets
[linkset
].ss7
.ss7
) {
17611 sig_ss7_cli_show_channels(a
->fd
, &linksets
[linkset
].ss7
);
17614 return CLI_SUCCESS
;
17616 #endif /* defined(HAVE_SS7) */
17618 #if defined(HAVE_SS7)
17619 static char *handle_ss7_show_cics(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17621 #define FORMAT "%5s %5s %6s %12s %-12s\n"
17622 #define FORMAT2 "%5i %5i %6i %12s %-12s\n"
17623 int i
, linkset
, dpc
= 0;
17624 struct sig_ss7_linkset
*ss7
;
17630 e
->command
= "ss7 show cics";
17632 "Usage: ss7 show cics <linkset> [dpc]\n"
17633 " Shows the cics of an SS7 linkset.\n";
17639 if (a
->argc
< 4 || a
->argc
> 5) {
17640 return CLI_SHOWUSAGE
;
17643 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
;
17650 if (!linksets
[linkset
-1].ss7
.ss7
) {
17651 ast_cli(a
->fd
, "No SS7 running on linkset %d\n", linkset
);
17652 return CLI_SUCCESS
;
17654 ss7
= &linksets
[linkset
-1].ss7
;
17656 if (a
->argc
== 5) {
17657 dpc
= atoi(a
->argv
[4]);
17659 ast_cli(a
->fd
, "Invalid DPC specified!\n");
17660 return CLI_SUCCESS
;
17664 ast_cli(a
->fd
, FORMAT
, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
17666 for (i
= 0; i
< ss7
->numchans
; i
++) {
17667 if (!dpc
|| (ss7
->pvts
[i
] && ss7
->pvts
[i
]->dpc
== dpc
)) {
17668 struct dahdi_pvt
*p
= ss7
->pvts
[i
]->chan_pvt
;
17670 if (ss7
->pvts
[i
]->owner
) {
17672 } else if (ss7
->pvts
[i
]->ss7call
) {
17674 } else if (!p
->inservice
) {
17675 state
= "NotInServ";
17680 if (p
->locallyblocked
) {
17681 strcpy(blocking
, "L:");
17682 if (p
->locallyblocked
& SS7_BLOCKED_MAINTENANCE
) {
17683 strcat(blocking
, "M");
17685 strcat(blocking
, " ");
17688 if (p
->locallyblocked
& SS7_BLOCKED_HARDWARE
) {
17689 strcat(blocking
, "H");
17691 strcat(blocking
, " ");
17694 strcpy(blocking
, " ");
17697 if (p
->remotelyblocked
) {
17698 strcat(blocking
, " R:");
17699 if (p
->remotelyblocked
& SS7_BLOCKED_MAINTENANCE
) {
17700 strcat(blocking
, "M");
17702 strcat(blocking
, " ");
17705 if (p
->remotelyblocked
& SS7_BLOCKED_HARDWARE
) {
17706 strcat(blocking
, "H");
17708 strcat(blocking
, " ");
17712 ast_cli(a
->fd
, FORMAT2
, ss7
->pvts
[i
]->cic
, ss7
->pvts
[i
]->dpc
, ss7
->pvts
[i
]->channel
, state
, blocking
);
17716 return CLI_SUCCESS
;
17720 #endif /* defined(HAVE_SS7) */
17722 #if defined(HAVE_SS7)
17723 static char *handle_ss7_version(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
17727 e
->command
= "ss7 show version";
17729 "Usage: ss7 show version\n"
17730 " Show the libss7 version\n";
17736 ast_cli(a
->fd
, "libss7 version: %s\n", ss7_get_version());
17738 return CLI_SUCCESS
;
17740 #endif /* defined(HAVE_SS7) */
17742 #if defined(HAVE_SS7)
17743 static struct ast_cli_entry dahdi_ss7_cli
[] = {
17744 AST_CLI_DEFINE(handle_ss7_debug
, "Enables SS7 debugging on a linkset"),
17745 AST_CLI_DEFINE(handle_ss7_cic_blocking
, "Blocks/Unblocks the given CIC"),
17746 AST_CLI_DEFINE(handle_ss7_linkset_mng
, "Resets/Blocks/Unblocks all CICs on a linkset"),
17747 AST_CLI_DEFINE(handle_ss7_group_blocking
, "Blocks/Unblocks the given CIC range"),
17748 AST_CLI_DEFINE(handle_ss7_reset_cic
, "Resets the given CIC"),
17749 AST_CLI_DEFINE(handle_ss7_group_reset
, "Resets the given CIC range"),
17750 AST_CLI_DEFINE(handle_ss7_mtp3_restart
, "Restart a link"),
17751 AST_CLI_DEFINE(handle_ss7_net_mng
, "Send an NET MNG message"),
17752 AST_CLI_DEFINE(handle_ss7_show_linkset
, "Shows the status of a linkset"),
17753 AST_CLI_DEFINE(handle_ss7_show_channels
, "Displays SS7 channel information"),
17754 AST_CLI_DEFINE(handle_ss7_show_calls
, "Show ss7 calls"),
17755 AST_CLI_DEFINE(handle_ss7_show_cics
, "Show cics on a linkset"),
17756 AST_CLI_DEFINE(handle_ss7_version
, "Displays libss7 version"),
17758 #endif /* defined(HAVE_SS7) */
17760 #if defined(HAVE_PRI)
17761 #if defined(HAVE_PRI_CCSS)
17764 * \brief CC agent initialization.
17767 * \param agent CC core agent control.
17768 * \param chan Original channel the agent will attempt to recall.
17771 * This callback is called when the CC core is initialized. Agents should allocate
17772 * any private data necessary for the call and assign it to the private_data
17773 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
17774 * specific agent type, they should be set in this function as well.
17776 * \retval 0 on success.
17777 * \retval -1 on error.
17779 static int dahdi_pri_cc_agent_init(struct ast_cc_agent
*agent
, struct ast_channel
*chan
)
17781 struct dahdi_pvt
*pvt
;
17782 struct sig_pri_chan
*pvt_chan
;
17785 ast_assert(!strcmp(ast_channel_tech(chan
)->type
, "DAHDI"));
17787 pvt
= ast_channel_tech_pvt(chan
);
17788 if (dahdi_sig_pri_lib_handles(pvt
->sig
)) {
17789 pvt_chan
= pvt
->sig_pvt
;
17797 ast_module_ref(ast_module_info
->self
);
17799 res
= sig_pri_cc_agent_init(agent
, pvt_chan
);
17801 ast_module_unref(ast_module_info
->self
);
17805 #endif /* defined(HAVE_PRI_CCSS) */
17806 #endif /* defined(HAVE_PRI) */
17808 #if defined(HAVE_PRI)
17809 #if defined(HAVE_PRI_CCSS)
17812 * \brief Destroy private data on the agent.
17815 * \param agent CC core agent control.
17818 * The core will call this function upon completion
17819 * or failure of CC.
17821 static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent
*agent
)
17823 sig_pri_cc_agent_destructor(agent
);
17825 ast_module_unref(ast_module_info
->self
);
17827 #endif /* defined(HAVE_PRI_CCSS) */
17828 #endif /* defined(HAVE_PRI) */
17830 #if defined(HAVE_PRI)
17831 #if defined(HAVE_PRI_CCSS)
17832 static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks
= {
17833 .type
= dahdi_pri_cc_type
,
17834 .init
= dahdi_pri_cc_agent_init
,
17835 .start_offer_timer
= sig_pri_cc_agent_start_offer_timer
,
17836 .stop_offer_timer
= sig_pri_cc_agent_stop_offer_timer
,
17837 .respond
= sig_pri_cc_agent_req_rsp
,
17838 .status_request
= sig_pri_cc_agent_status_req
,
17839 .stop_ringing
= sig_pri_cc_agent_stop_ringing
,
17840 .party_b_free
= sig_pri_cc_agent_party_b_free
,
17841 .start_monitoring
= sig_pri_cc_agent_start_monitoring
,
17842 .callee_available
= sig_pri_cc_agent_callee_available
,
17843 .destructor
= dahdi_pri_cc_agent_destructor
,
17845 #endif /* defined(HAVE_PRI_CCSS) */
17846 #endif /* defined(HAVE_PRI) */
17848 #if defined(HAVE_PRI)
17849 #if defined(HAVE_PRI_CCSS)
17850 static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks
= {
17851 .type
= dahdi_pri_cc_type
,
17852 .request_cc
= sig_pri_cc_monitor_req_cc
,
17853 .suspend
= sig_pri_cc_monitor_suspend
,
17854 .unsuspend
= sig_pri_cc_monitor_unsuspend
,
17855 .status_response
= sig_pri_cc_monitor_status_rsp
,
17856 .cancel_available_timer
= sig_pri_cc_monitor_cancel_available_timer
,
17857 .destructor
= sig_pri_cc_monitor_destructor
,
17859 #endif /* defined(HAVE_PRI_CCSS) */
17860 #endif /* defined(HAVE_PRI) */
17862 static int __unload_module(void)
17864 struct dahdi_pvt
*p
;
17865 #if defined(HAVE_PRI) || defined(HAVE_SS7)
17867 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
17870 for (i
= 0; i
< NUM_SPANS
; i
++) {
17871 if (pris
[i
].pri
.master
!= AST_PTHREADT_NULL
) {
17872 pthread_cancel(pris
[i
].pri
.master
);
17873 pthread_kill(pris
[i
].pri
.master
, SIGURG
);
17876 ast_cli_unregister_multiple(dahdi_pri_cli
, ARRAY_LEN(dahdi_pri_cli
));
17877 ast_unregister_application(dahdi_send_keypad_facility_app
);
17878 #ifdef HAVE_PRI_PROG_W_CAUSE
17879 ast_unregister_application(dahdi_send_callrerouting_facility_app
);
17882 #if defined(HAVE_SS7)
17883 for (i
= 0; i
< NUM_SPANS
; i
++) {
17884 if (linksets
[i
].ss7
.master
!= AST_PTHREADT_NULL
) {
17885 pthread_cancel(linksets
[i
].ss7
.master
);
17886 pthread_kill(linksets
[i
].ss7
.master
, SIGURG
);
17889 ast_cli_unregister_multiple(dahdi_ss7_cli
, ARRAY_LEN(dahdi_ss7_cli
));
17890 #endif /* defined(HAVE_SS7) */
17891 #if defined(HAVE_OPENR2)
17892 dahdi_r2_destroy_links();
17893 ast_cli_unregister_multiple(dahdi_mfcr2_cli
, ARRAY_LEN(dahdi_mfcr2_cli
));
17894 ast_unregister_application(dahdi_accept_r2_call_app
);
17897 ast_custom_function_unregister(&polarity_function
);
17899 ast_cli_unregister_multiple(dahdi_cli
, ARRAY_LEN(dahdi_cli
));
17900 ast_manager_unregister("DAHDIDialOffhook");
17901 ast_manager_unregister("DAHDIHangup");
17902 ast_manager_unregister("DAHDITransfer");
17903 ast_manager_unregister("DAHDIDNDoff");
17904 ast_manager_unregister("DAHDIDNDon");
17905 ast_manager_unregister("DAHDIShowChannels");
17906 ast_manager_unregister("DAHDIRestart");
17907 #if defined(HAVE_PRI)
17908 ast_manager_unregister("PRIShowSpans");
17909 ast_manager_unregister("PRIDebugSet");
17910 ast_manager_unregister("PRIDebugFileSet");
17911 ast_manager_unregister("PRIDebugFileUnset");
17912 #endif /* defined(HAVE_PRI) */
17913 ast_channel_unregister(&dahdi_tech
);
17915 /* Hangup all interfaces if they have an owner */
17916 ast_mutex_lock(&iflock
);
17917 for (p
= iflist
; p
; p
= p
->next
) {
17919 ast_softhangup(p
->owner
, AST_SOFTHANGUP_APPUNLOAD
);
17921 ast_mutex_unlock(&iflock
);
17923 ast_mutex_lock(&monlock
);
17924 if (monitor_thread
&& (monitor_thread
!= AST_PTHREADT_STOP
) && (monitor_thread
!= AST_PTHREADT_NULL
)) {
17925 pthread_cancel(monitor_thread
);
17926 pthread_kill(monitor_thread
, SIGURG
);
17927 pthread_join(monitor_thread
, NULL
);
17929 monitor_thread
= AST_PTHREADT_STOP
;
17930 ast_mutex_unlock(&monlock
);
17932 destroy_all_channels();
17934 #if defined(HAVE_PRI)
17935 for (i
= 0; i
< NUM_SPANS
; i
++) {
17936 if (pris
[i
].pri
.master
&& (pris
[i
].pri
.master
!= AST_PTHREADT_NULL
)) {
17937 pthread_join(pris
[i
].pri
.master
, NULL
);
17939 for (j
= 0; j
< SIG_PRI_NUM_DCHANS
; j
++) {
17940 dahdi_close_pri_fd(&(pris
[i
]), j
);
17942 sig_pri_stop_pri(&pris
[i
].pri
);
17944 #if defined(HAVE_PRI_CCSS)
17945 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks
);
17946 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks
);
17947 #endif /* defined(HAVE_PRI_CCSS) */
17951 #if defined(HAVE_SS7)
17952 for (i
= 0; i
< NUM_SPANS
; i
++) {
17953 if (linksets
[i
].ss7
.master
&& (linksets
[i
].ss7
.master
!= AST_PTHREADT_NULL
)) {
17954 pthread_join(linksets
[i
].ss7
.master
, NULL
);
17956 for (j
= 0; j
< SIG_SS7_NUM_DCHANS
; j
++) {
17957 dahdi_close_ss7_fd(&(linksets
[i
]), j
);
17959 if (linksets
[i
].ss7
.ss7
) {
17960 ss7_destroy(linksets
[i
].ss7
.ss7
);
17961 linksets
[i
].ss7
.ss7
= NULL
;
17964 #endif /* defined(HAVE_SS7) */
17965 ast_cond_destroy(&ss_thread_complete
);
17967 dahdi_native_unload();
17969 ao2_cleanup(dahdi_tech
.capabilities
);
17970 dahdi_tech
.capabilities
= NULL
;
17971 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type
);
17975 static int unload_module(void)
17977 #if defined(HAVE_PRI) || defined(HAVE_SS7)
17979 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
17981 for (y
= 0; y
< NUM_SPANS
; y
++)
17982 ast_mutex_destroy(&pris
[y
].pri
.lock
);
17984 #if defined(HAVE_SS7)
17985 for (y
= 0; y
< NUM_SPANS
; y
++)
17986 ast_mutex_destroy(&linksets
[y
].ss7
.lock
);
17987 #endif /* defined(HAVE_SS7) */
17988 return __unload_module();
17991 static int build_channels(struct dahdi_chan_conf
*conf
, const char *value
, int reload
, int lineno
)
17994 int x
, start
, finish
;
17995 struct dahdi_pvt
*tmp
;
17997 if ((reload
== 0) && (conf
->chan
.sig
< 0) && !conf
->is_sig_auto
) {
17998 ast_log(LOG_ERROR
, "Signalling must be specified before any channels are.\n");
18002 c
= ast_strdupa(value
);
18004 while ((chan
= strsep(&c
, ","))) {
18005 if (sscanf(chan
, "%30d-%30d", &start
, &finish
) == 2) {
18007 } else if (sscanf(chan
, "%30d", &start
)) {
18010 } else if (!strcasecmp(chan
, "pseudo")) {
18011 finish
= start
= CHAN_PSEUDO
;
18013 ast_log(LOG_ERROR
, "Syntax error parsing '%s' at '%s'\n", value
, chan
);
18016 if (finish
< start
) {
18017 ast_log(LOG_WARNING
, "Silliness: %d < %d\n", start
, finish
);
18023 for (x
= start
; x
<= finish
; x
++) {
18024 if (conf
->wanted_channels_start
&&
18025 (x
< conf
->wanted_channels_start
||
18026 x
> conf
->wanted_channels_end
)
18030 tmp
= mkintf(x
, conf
, reload
);
18033 ast_verb(3, "%s channel %d, %s signalling\n", reload
? "Reconfigured" : "Registered", x
, sig2str(tmp
->sig
));
18035 ast_log(LOG_ERROR
, "Unable to %s channel '%s'\n",
18036 (reload
== 1) ? "reconfigure" : "register", value
);
18039 if (x
== CHAN_PSEUDO
) {
18048 /** The length of the parameters list of 'dahdichan'.
18049 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18050 #define MAX_CHANLIST_LEN 80
18052 static void process_echocancel(struct dahdi_chan_conf
*confp
, const char *data
, unsigned int line
)
18054 char *parse
= ast_strdupa(data
);
18055 char *params
[DAHDI_MAX_ECHOCANPARAMS
+ 1];
18056 unsigned int param_count
;
18059 if (!(param_count
= ast_app_separate_args(parse
, ',', params
, ARRAY_LEN(params
))))
18062 memset(&confp
->chan
.echocancel
, 0, sizeof(confp
->chan
.echocancel
));
18064 /* first parameter is tap length, process it here */
18066 x
= ast_strlen_zero(params
[0]) ? 0 : atoi(params
[0]);
18068 if ((x
== 32) || (x
== 64) || (x
== 128) || (x
== 256) || (x
== 512) || (x
== 1024))
18069 confp
->chan
.echocancel
.head
.tap_length
= x
;
18070 else if ((confp
->chan
.echocancel
.head
.tap_length
= ast_true(params
[0])))
18071 confp
->chan
.echocancel
.head
.tap_length
= 128;
18073 /* now process any remaining parameters */
18075 for (x
= 1; x
< param_count
; x
++) {
18081 if (ast_app_separate_args(params
[x
], '=', (char **) ¶m
, 2) < 1) {
18082 ast_log(LOG_WARNING
, "Invalid echocancel parameter supplied at line %u: '%s'\n", line
, params
[x
]);
18086 if (ast_strlen_zero(param
.name
) || (strlen(param
.name
) > sizeof(confp
->chan
.echocancel
.params
[0].name
)-1)) {
18087 ast_log(LOG_WARNING
, "Invalid echocancel parameter supplied at line %u: '%s'\n", line
, param
.name
);
18091 strcpy(confp
->chan
.echocancel
.params
[confp
->chan
.echocancel
.head
.param_count
].name
, param
.name
);
18094 if (sscanf(param
.value
, "%30d", &confp
->chan
.echocancel
.params
[confp
->chan
.echocancel
.head
.param_count
].value
) != 1) {
18095 ast_log(LOG_WARNING
, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line
, param
.value
);
18099 confp
->chan
.echocancel
.head
.param_count
++;
18103 #if defined(HAVE_PRI)
18104 #if defined(HAVE_PRI_DISPLAY_TEXT)
18107 * \brief Determine the configured display text options.
18110 * \param value Configuration value string.
18112 * \return Configured display text option flags.
18114 static unsigned long dahdi_display_text_option(const char *value
)
18118 unsigned long options
;
18121 val_str
= ast_strdupa(value
);
18124 opt_str
= strsep(&val_str
, ",");
18128 opt_str
= ast_strip(opt_str
);
18133 if (!strcasecmp(opt_str
, "block")) {
18134 options
|= PRI_DISPLAY_OPTION_BLOCK
;
18135 } else if (!strcasecmp(opt_str
, "name_initial")) {
18136 options
|= PRI_DISPLAY_OPTION_NAME_INITIAL
;
18137 } else if (!strcasecmp(opt_str
, "name_update")) {
18138 options
|= PRI_DISPLAY_OPTION_NAME_UPDATE
;
18139 } else if (!strcasecmp(opt_str
, "name")) {
18140 options
|= (PRI_DISPLAY_OPTION_NAME_INITIAL
| PRI_DISPLAY_OPTION_NAME_UPDATE
);
18141 } else if (!strcasecmp(opt_str
, "text")) {
18142 options
|= PRI_DISPLAY_OPTION_TEXT
;
18147 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18148 #endif /* defined(HAVE_PRI) */
18150 #if defined(HAVE_PRI)
18151 #if defined(HAVE_PRI_DATETIME_SEND)
18154 * \brief Determine the configured date/time send policy option.
18157 * \param value Configuration value string.
18159 * \return Configured date/time send policy option.
18161 static int dahdi_datetime_send_option(const char *value
)
18165 option
= PRI_DATE_TIME_SEND_DEFAULT
;
18167 if (ast_false(value
)) {
18168 option
= PRI_DATE_TIME_SEND_NO
;
18169 } else if (!strcasecmp(value
, "date")) {
18170 option
= PRI_DATE_TIME_SEND_DATE
;
18171 } else if (!strcasecmp(value
, "date_hh")) {
18172 option
= PRI_DATE_TIME_SEND_DATE_HH
;
18173 } else if (!strcasecmp(value
, "date_hhmm")) {
18174 option
= PRI_DATE_TIME_SEND_DATE_HHMM
;
18175 } else if (!strcasecmp(value
, "date_hhmmss")) {
18176 option
= PRI_DATE_TIME_SEND_DATE_HHMMSS
;
18181 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
18182 #endif /* defined(HAVE_PRI) */
18184 /*! process_dahdi() - ignore keyword 'channel' and similar */
18185 #define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18186 /*! process_dahdi() - No warnings on non-existing cofiguration keywords */
18187 #define PROC_DAHDI_OPT_NOWARN (1 << 1)
18189 static void parse_busy_pattern(struct ast_variable
*v
, struct ast_dsp_busy_pattern
*busy_cadence
)
18191 int count_pattern
= 0;
18196 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18197 if (!sscanf(v
->value
, "%30d", &norval
) && count_pattern
== 0) {
18198 ast_log(LOG_ERROR
, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v
->lineno
);
18202 busy_cadence
->pattern
[count_pattern
] = norval
;
18205 if (count_pattern
== 4) {
18209 temp
= strchr(v
->value
, ',');
18210 if (temp
== NULL
) {
18213 v
->value
= temp
+ 1;
18215 busy_cadence
->length
= count_pattern
;
18217 if (count_pattern
% 2 != 0) {
18218 /* The pattern length must be divisible by two */
18219 ast_log(LOG_ERROR
, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v
->lineno
);
18224 static int process_dahdi(struct dahdi_chan_conf
*confp
, const char *cat
, struct ast_variable
*v
, int reload
, int options
)
18226 struct dahdi_pvt
*tmp
;
18228 struct ast_variable
*dahdichan
= NULL
;
18230 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18231 user_has_defined_cadences
= 0;
18233 for (; v
; v
= v
->next
) {
18234 if (!ast_jb_read_conf(&global_jbconf
, v
->name
, v
->value
))
18237 /* Create the interface list */
18238 if (!strcasecmp(v
->name
, "channel") || !strcasecmp(v
->name
, "channels")) {
18239 if (options
& PROC_DAHDI_OPT_NOCHAN
) {
18240 ast_log(LOG_WARNING
, "Channel '%s' ignored.\n", v
->value
);
18243 if (build_channels(confp
, v
->value
, reload
, v
->lineno
)) {
18244 if (confp
->ignore_failed_channels
) {
18245 ast_log(LOG_WARNING
, "Channel '%s' failure ignored: ignore_failed_channels.\n", v
->value
);
18251 ast_debug(1, "Channel '%s' configured.\n", v
->value
);
18252 } else if (!strcasecmp(v
->name
, "ignore_failed_channels")) {
18253 confp
->ignore_failed_channels
= ast_true(v
->value
);
18254 } else if (!strcasecmp(v
->name
, "buffers")) {
18255 if (parse_buffers_policy(v
->value
, &confp
->chan
.buf_no
, &confp
->chan
.buf_policy
)) {
18256 ast_log(LOG_WARNING
, "Using default buffer policy.\n");
18257 confp
->chan
.buf_no
= numbufs
;
18258 confp
->chan
.buf_policy
= DAHDI_POLICY_IMMEDIATE
;
18260 } else if (!strcasecmp(v
->name
, "faxbuffers")) {
18261 if (!parse_buffers_policy(v
->value
, &confp
->chan
.faxbuf_no
, &confp
->chan
.faxbuf_policy
)) {
18262 confp
->chan
.usefaxbuffers
= 1;
18264 } else if (!strcasecmp(v
->name
, "dahdichan")) {
18265 /* Only process the last dahdichan value. */
18267 } else if (!strcasecmp(v
->name
, "usedistinctiveringdetection")) {
18268 usedistinctiveringdetection
= ast_true(v
->value
);
18269 } else if (!strcasecmp(v
->name
, "distinctiveringaftercid")) {
18270 distinctiveringaftercid
= ast_true(v
->value
);
18271 } else if (!strcasecmp(v
->name
, "dring1context")) {
18272 ast_copy_string(confp
->chan
.drings
.ringContext
[0].contextData
,v
->value
,sizeof(confp
->chan
.drings
.ringContext
[0].contextData
));
18273 } else if (!strcasecmp(v
->name
, "dring2context")) {
18274 ast_copy_string(confp
->chan
.drings
.ringContext
[1].contextData
,v
->value
,sizeof(confp
->chan
.drings
.ringContext
[1].contextData
));
18275 } else if (!strcasecmp(v
->name
, "dring3context")) {
18276 ast_copy_string(confp
->chan
.drings
.ringContext
[2].contextData
,v
->value
,sizeof(confp
->chan
.drings
.ringContext
[2].contextData
));
18277 } else if (!strcasecmp(v
->name
, "dring1range")) {
18278 confp
->chan
.drings
.ringnum
[0].range
= atoi(v
->value
);
18279 } else if (!strcasecmp(v
->name
, "dring2range")) {
18280 confp
->chan
.drings
.ringnum
[1].range
= atoi(v
->value
);
18281 } else if (!strcasecmp(v
->name
, "dring3range")) {
18282 confp
->chan
.drings
.ringnum
[2].range
= atoi(v
->value
);
18283 } else if (!strcasecmp(v
->name
, "dring1")) {
18284 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]);
18285 } else if (!strcasecmp(v
->name
, "dring2")) {
18286 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]);
18287 } else if (!strcasecmp(v
->name
, "dring3")) {
18288 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]);
18289 } else if (!strcasecmp(v
->name
, "usecallerid")) {
18290 confp
->chan
.use_callerid
= ast_true(v
->value
);
18291 } else if (!strcasecmp(v
->name
, "cidsignalling")) {
18292 if (!strcasecmp(v
->value
, "bell"))
18293 confp
->chan
.cid_signalling
= CID_SIG_BELL
;
18294 else if (!strcasecmp(v
->value
, "v23"))
18295 confp
->chan
.cid_signalling
= CID_SIG_V23
;
18296 else if (!strcasecmp(v
->value
, "dtmf"))
18297 confp
->chan
.cid_signalling
= CID_SIG_DTMF
;
18298 else if (!strcasecmp(v
->value
, "smdi"))
18299 confp
->chan
.cid_signalling
= CID_SIG_SMDI
;
18300 else if (!strcasecmp(v
->value
, "v23_jp"))
18301 confp
->chan
.cid_signalling
= CID_SIG_V23_JP
;
18302 else if (ast_true(v
->value
))
18303 confp
->chan
.cid_signalling
= CID_SIG_BELL
;
18304 } else if (!strcasecmp(v
->name
, "cidstart")) {
18305 if (!strcasecmp(v
->value
, "ring"))
18306 confp
->chan
.cid_start
= CID_START_RING
;
18307 else if (!strcasecmp(v
->value
, "polarity_in"))
18308 confp
->chan
.cid_start
= CID_START_POLARITY_IN
;
18309 else if (!strcasecmp(v
->value
, "polarity"))
18310 confp
->chan
.cid_start
= CID_START_POLARITY
;
18311 else if (!strcasecmp(v
->value
, "dtmf"))
18312 confp
->chan
.cid_start
= CID_START_DTMF_NOALERT
;
18313 else if (ast_true(v
->value
))
18314 confp
->chan
.cid_start
= CID_START_RING
;
18315 } else if (!strcasecmp(v
->name
, "threewaycalling")) {
18316 confp
->chan
.threewaycalling
= ast_true(v
->value
);
18317 } else if (!strcasecmp(v
->name
, "threewaysilenthold")) {
18318 confp
->chan
.threewaysilenthold
= ast_true(v
->value
);
18319 } else if (!strcasecmp(v
->name
, "cancallforward")) {
18320 confp
->chan
.cancallforward
= ast_true(v
->value
);
18321 } else if (!strcasecmp(v
->name
, "relaxdtmf")) {
18322 if (ast_true(v
->value
))
18323 confp
->chan
.dtmfrelax
= DSP_DIGITMODE_RELAXDTMF
;
18325 confp
->chan
.dtmfrelax
= 0;
18326 } else if (!strcasecmp(v
->name
, "mailbox")) {
18327 ast_copy_string(confp
->chan
.mailbox
, v
->value
, sizeof(confp
->chan
.mailbox
));
18328 } else if (!strcasecmp(v
->name
, "description")) {
18329 ast_copy_string(confp
->chan
.description
, v
->value
, sizeof(confp
->chan
.description
));
18330 } else if (!strcasecmp(v
->name
, "hasvoicemail")) {
18331 if (ast_true(v
->value
) && ast_strlen_zero(confp
->chan
.mailbox
)) {
18333 * hasvoicemail is a users.conf legacy voicemail enable method.
18334 * hasvoicemail is only going to work for app_voicemail mailboxes.
18336 if (strchr(cat
, '@')) {
18337 ast_copy_string(confp
->chan
.mailbox
, cat
, sizeof(confp
->chan
.mailbox
));
18339 snprintf(confp
->chan
.mailbox
, sizeof(confp
->chan
.mailbox
),
18340 "%s@default", cat
);
18343 } else if (!strcasecmp(v
->name
, "adsi")) {
18344 confp
->chan
.adsi
= ast_true(v
->value
);
18345 } else if (!strcasecmp(v
->name
, "usesmdi")) {
18346 confp
->chan
.use_smdi
= ast_true(v
->value
);
18347 } else if (!strcasecmp(v
->name
, "smdiport")) {
18348 ast_copy_string(confp
->smdi_port
, v
->value
, sizeof(confp
->smdi_port
));
18349 } else if (!strcasecmp(v
->name
, "transfer")) {
18350 confp
->chan
.transfer
= ast_true(v
->value
);
18351 } else if (!strcasecmp(v
->name
, "canpark")) {
18352 confp
->chan
.canpark
= ast_true(v
->value
);
18353 } else if (!strcasecmp(v
->name
, "echocancelwhenbridged")) {
18354 confp
->chan
.echocanbridged
= ast_true(v
->value
);
18355 } else if (!strcasecmp(v
->name
, "busydetect")) {
18356 confp
->chan
.busydetect
= ast_true(v
->value
);
18357 } else if (!strcasecmp(v
->name
, "busycount")) {
18358 confp
->chan
.busycount
= atoi(v
->value
);
18359 } else if (!strcasecmp(v
->name
, "busypattern")) {
18360 parse_busy_pattern(v
, &confp
->chan
.busy_cadence
);
18361 } else if (!strcasecmp(v
->name
, "calledsubscriberheld")) {
18362 confp
->chan
.calledsubscriberheld
= ast_true(v
->value
);
18363 } else if (!strcasecmp(v
->name
, "callprogress")) {
18364 confp
->chan
.callprogress
&= ~CALLPROGRESS_PROGRESS
;
18365 if (ast_true(v
->value
))
18366 confp
->chan
.callprogress
|= CALLPROGRESS_PROGRESS
;
18367 } else if (!strcasecmp(v
->name
, "waitfordialtone")) {
18368 confp
->chan
.waitfordialtone
= atoi(v
->value
);
18369 } else if (!strcasecmp(v
->name
, "dialtone_detect")) {
18370 if (!strcasecmp(v
->value
, "always")) {
18371 confp
->chan
.dialtone_detect
= -1;
18372 } else if (ast_true(v
->value
)) {
18373 confp
->chan
.dialtone_detect
= DEFAULT_DIALTONE_DETECT_TIMEOUT
;
18374 } else if (ast_false(v
->value
)) {
18375 confp
->chan
.dialtone_detect
= 0;
18377 confp
->chan
.dialtone_detect
= ast_strlen_zero(v
->value
) ? 0 : (8 * atoi(v
->value
)) / READ_SIZE
;
18379 } else if (!strcasecmp(v
->name
, "faxdetect")) {
18380 confp
->chan
.callprogress
&= ~CALLPROGRESS_FAX
;
18381 if (!strcasecmp(v
->value
, "incoming")) {
18382 confp
->chan
.callprogress
|= CALLPROGRESS_FAX_INCOMING
;
18383 } else if (!strcasecmp(v
->value
, "outgoing")) {
18384 confp
->chan
.callprogress
|= CALLPROGRESS_FAX_OUTGOING
;
18385 } else if (!strcasecmp(v
->value
, "both") || ast_true(v
->value
))
18386 confp
->chan
.callprogress
|= CALLPROGRESS_FAX_INCOMING
| CALLPROGRESS_FAX_OUTGOING
;
18387 } else if (!strcasecmp(v
->name
, "faxdetect_timeout")) {
18388 if (sscanf(v
->value
, "%30u", &confp
->chan
.faxdetect_timeout
) != 1) {
18389 confp
->chan
.faxdetect_timeout
= 0;
18391 } else if (!strcasecmp(v
->name
, "firstdigit_timeout")) {
18392 if (sscanf(v
->value
, "%30d", &confp
->chan
.firstdigit_timeout
) != 1
18393 || confp
->chan
.firstdigit_timeout
<= 0) {
18394 confp
->chan
.firstdigit_timeout
= ANALOG_FIRST_DIGIT_TIMEOUT
;
18396 } else if (!strcasecmp(v
->name
, "interdigit_timeout")) {
18397 if (sscanf(v
->value
, "%30d", &confp
->chan
.interdigit_timeout
) != 1
18398 || confp
->chan
.interdigit_timeout
<= 0) {
18399 confp
->chan
.interdigit_timeout
= ANALOG_INTER_DIGIT_TIMEOUT
;
18401 } else if (!strcasecmp(v
->name
, "matchdigit_timeout")) {
18402 if (sscanf(v
->value
, "%30d", &confp
->chan
.matchdigit_timeout
) != 1
18403 || confp
->chan
.matchdigit_timeout
<= 0) {
18404 confp
->chan
.matchdigit_timeout
= ANALOG_MATCH_DIGIT_TIMEOUT
;
18406 } else if (!strcasecmp(v
->name
, "echocancel")) {
18407 process_echocancel(confp
, v
->value
, v
->lineno
);
18408 } else if (!strcasecmp(v
->name
, "echotraining")) {
18409 if (sscanf(v
->value
, "%30d", &y
) == 1) {
18410 if ((y
< 10) || (y
> 4000)) {
18411 ast_log(LOG_WARNING
, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v
->lineno
);
18413 confp
->chan
.echotraining
= y
;
18415 } else if (ast_true(v
->value
)) {
18416 confp
->chan
.echotraining
= 400;
18418 confp
->chan
.echotraining
= 0;
18419 } else if (!strcasecmp(v
->name
, "hidecallerid")) {
18420 confp
->chan
.hidecallerid
= ast_true(v
->value
);
18421 } else if (!strcasecmp(v
->name
, "hidecalleridname")) {
18422 confp
->chan
.hidecalleridname
= ast_true(v
->value
);
18423 } else if (!strcasecmp(v
->name
, "pulsedial")) {
18424 confp
->chan
.pulse
= ast_true(v
->value
);
18425 } else if (!strcasecmp(v
->name
, "callreturn")) {
18426 confp
->chan
.callreturn
= ast_true(v
->value
);
18427 } else if (!strcasecmp(v
->name
, "callwaiting")) {
18428 confp
->chan
.callwaiting
= ast_true(v
->value
);
18429 } else if (!strcasecmp(v
->name
, "callwaitingcallerid")) {
18430 confp
->chan
.callwaitingcallerid
= ast_true(v
->value
);
18431 } else if (!strcasecmp(v
->name
, "context")) {
18432 ast_copy_string(confp
->chan
.context
, v
->value
, sizeof(confp
->chan
.context
));
18433 } else if (!strcasecmp(v
->name
, "language")) {
18434 ast_copy_string(confp
->chan
.language
, v
->value
, sizeof(confp
->chan
.language
));
18435 } else if (!strcasecmp(v
->name
, "progzone")) {
18436 ast_copy_string(progzone
, v
->value
, sizeof(progzone
));
18437 } else if (!strcasecmp(v
->name
, "mohinterpret")
18438 ||!strcasecmp(v
->name
, "musiconhold") || !strcasecmp(v
->name
, "musicclass")) {
18439 ast_copy_string(confp
->chan
.mohinterpret
, v
->value
, sizeof(confp
->chan
.mohinterpret
));
18440 } else if (!strcasecmp(v
->name
, "mohsuggest")) {
18441 ast_copy_string(confp
->chan
.mohsuggest
, v
->value
, sizeof(confp
->chan
.mohsuggest
));
18442 } else if (!strcasecmp(v
->name
, "parkinglot")) {
18443 ast_copy_string(confp
->chan
.parkinglot
, v
->value
, sizeof(confp
->chan
.parkinglot
));
18444 } else if (!strcasecmp(v
->name
, "stripmsd")) {
18445 ast_log(LOG_NOTICE
, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v
->name
);
18446 confp
->chan
.stripmsd
= atoi(v
->value
);
18447 } else if (!strcasecmp(v
->name
, "jitterbuffers")) {
18448 numbufs
= atoi(v
->value
);
18449 } else if (!strcasecmp(v
->name
, "group")) {
18450 confp
->chan
.group
= ast_get_group(v
->value
);
18451 } else if (!strcasecmp(v
->name
, "callgroup")) {
18452 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18453 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a call group\n");
18455 if (!strcasecmp(v
->value
, "none"))
18456 confp
->chan
.callgroup
= 0;
18458 confp
->chan
.callgroup
= ast_get_group(v
->value
);
18459 } else if (!strcasecmp(v
->name
, "pickupgroup")) {
18460 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18461 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a pickup group\n");
18463 if (!strcasecmp(v
->value
, "none"))
18464 confp
->chan
.pickupgroup
= 0;
18466 confp
->chan
.pickupgroup
= ast_get_group(v
->value
);
18467 } else if (!strcasecmp(v
->name
, "namedcallgroup")) {
18468 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18469 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a named call group\n");
18471 confp
->chan
.named_callgroups
= ast_get_namedgroups(v
->value
);
18472 } else if (!strcasecmp(v
->name
, "namedpickupgroup")) {
18473 if (!((confp
->chan
.sig
== SIG_FXOKS
) || (confp
->chan
.sig
== SIG_FXOGS
) || (confp
->chan
.sig
== SIG_FXOLS
))) {
18474 ast_log(LOG_WARNING
, "Only FXO signalled channels may belong to a named pickup group\n");
18476 confp
->chan
.named_pickupgroups
= ast_get_namedgroups(v
->value
);
18477 } else if (!strcasecmp(v
->name
, "setvar")) {
18479 char *varval
= NULL
;
18480 struct ast_variable
*tmpvar
;
18481 char varname
[strlen(v
->value
) + 1];
18482 strcpy(varname
, v
->value
); /* safe */
18483 if ((varval
= strchr(varname
, '='))) {
18485 if ((tmpvar
= ast_variable_new(varname
, varval
, ""))) {
18486 if (ast_variable_list_replace(&confp
->chan
.vars
, tmpvar
)) {
18487 tmpvar
->next
= confp
->chan
.vars
;
18488 confp
->chan
.vars
= tmpvar
;
18493 } else if (!strcasecmp(v
->name
, "immediate")) {
18494 confp
->chan
.immediate
= ast_true(v
->value
);
18495 } else if (!strcasecmp(v
->name
, "immediatering")) {
18496 confp
->chan
.immediatering
= ast_true(v
->value
);
18497 } else if (!strcasecmp(v
->name
, "transfertobusy")) {
18498 confp
->chan
.transfertobusy
= ast_true(v
->value
);
18499 } else if (!strcasecmp(v
->name
, "dialmode")) {
18500 if (!strcasecmp(v
->value
, "pulse")) {
18501 confp
->chan
.dialmode
= ANALOG_DIALMODE_PULSE
;
18502 } else if (!strcasecmp(v
->value
, "dtmf") || !strcasecmp(v
->value
, "tone")) {
18503 confp
->chan
.dialmode
= ANALOG_DIALMODE_DTMF
;
18504 } else if (!strcasecmp(v
->value
, "none")) {
18505 confp
->chan
.dialmode
= ANALOG_DIALMODE_NONE
;
18507 confp
->chan
.dialmode
= ANALOG_DIALMODE_BOTH
;
18509 } else if (!strcasecmp(v
->name
, "mwimonitor")) {
18510 confp
->chan
.mwimonitor_neon
= 0;
18511 confp
->chan
.mwimonitor_fsk
= 0;
18512 confp
->chan
.mwimonitor_rpas
= 0;
18513 if (strcasestr(v
->value
, "fsk")) {
18514 confp
->chan
.mwimonitor_fsk
= 1;
18516 if (strcasestr(v
->value
, "rpas")) {
18517 confp
->chan
.mwimonitor_rpas
= 1;
18519 if (strcasestr(v
->value
, "neon")) {
18520 confp
->chan
.mwimonitor_neon
= 1;
18522 /* If set to true or yes, assume that simple fsk is desired */
18523 if (ast_true(v
->value
)) {
18524 confp
->chan
.mwimonitor_fsk
= 1;
18526 } else if (!strcasecmp(v
->name
, "hwrxgain")) {
18527 confp
->chan
.hwrxgain_enabled
= 0;
18528 if (strcasecmp(v
->value
, "disabled")) {
18529 if (sscanf(v
->value
, "%30f", &confp
->chan
.hwrxgain
) == 1) {
18530 confp
->chan
.hwrxgain_enabled
= 1;
18532 ast_log(LOG_WARNING
, "Invalid hwrxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18535 } else if (!strcasecmp(v
->name
, "hwtxgain")) {
18536 confp
->chan
.hwtxgain_enabled
= 0;
18537 if (strcasecmp(v
->value
, "disabled")) {
18538 if (sscanf(v
->value
, "%30f", &confp
->chan
.hwtxgain
) == 1) {
18539 confp
->chan
.hwtxgain_enabled
= 1;
18541 ast_log(LOG_WARNING
, "Invalid hwtxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18544 } else if (!strcasecmp(v
->name
, "cid_rxgain")) {
18545 if (sscanf(v
->value
, "%30f", &confp
->chan
.cid_rxgain
) != 1) {
18546 ast_log(LOG_WARNING
, "Invalid cid_rxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18548 } else if (!strcasecmp(v
->name
, "rxgain")) {
18549 if (sscanf(v
->value
, "%30f", &confp
->chan
.rxgain
) != 1) {
18550 ast_log(LOG_WARNING
, "Invalid rxgain: %s at line %d.\n", v
->value
, v
->lineno
);
18552 } else if (!strcasecmp(v
->name
, "txgain")) {
18553 if (sscanf(v
->value
, "%30f", &confp
->chan
.txgain
) != 1) {
18554 ast_log(LOG_WARNING
, "Invalid txgain: %s at line %d.\n", v
->value
, v
->lineno
);
18556 } else if (!strcasecmp(v
->name
, "txdrc")) {
18557 if (sscanf(v
->value
, "%f", &confp
->chan
.txdrc
) != 1) {
18558 ast_log(LOG_WARNING
, "Invalid txdrc: %s\n", v
->value
);
18560 } else if (!strcasecmp(v
->name
, "rxdrc")) {
18561 if (sscanf(v
->value
, "%f", &confp
->chan
.rxdrc
) != 1) {
18562 ast_log(LOG_WARNING
, "Invalid rxdrc: %s\n", v
->value
);
18564 } else if (!strcasecmp(v
->name
, "tonezone")) {
18565 if (sscanf(v
->value
, "%30d", &confp
->chan
.tonezone
) != 1) {
18566 ast_log(LOG_WARNING
, "Invalid tonezone: %s at line %d.\n", v
->value
, v
->lineno
);
18568 } else if (!strcasecmp(v
->name
, "callerid")) {
18569 if (!strcasecmp(v
->value
, "asreceived")) {
18570 confp
->chan
.cid_num
[0] = '\0';
18571 confp
->chan
.cid_name
[0] = '\0';
18573 ast_callerid_split(v
->value
, confp
->chan
.cid_name
, sizeof(confp
->chan
.cid_name
), confp
->chan
.cid_num
, sizeof(confp
->chan
.cid_num
));
18575 } else if (!strcasecmp(v
->name
, "fullname")) {
18576 ast_copy_string(confp
->chan
.cid_name
, v
->value
, sizeof(confp
->chan
.cid_name
));
18577 } else if (!strcasecmp(v
->name
, "cid_number")) {
18578 ast_copy_string(confp
->chan
.cid_num
, v
->value
, sizeof(confp
->chan
.cid_num
));
18579 } else if (!strcasecmp(v
->name
, "cid_tag")) {
18580 ast_copy_string(confp
->chan
.cid_tag
, v
->value
, sizeof(confp
->chan
.cid_tag
));
18581 } else if (!strcasecmp(v
->name
, "useincomingcalleridondahditransfer")) {
18582 confp
->chan
.dahditrcallerid
= ast_true(v
->value
);
18583 } else if (!strcasecmp(v
->name
, "restrictcid")) {
18584 confp
->chan
.restrictcid
= ast_true(v
->value
);
18585 } else if (!strcasecmp(v
->name
, "usecallingpres")) {
18586 confp
->chan
.use_callingpres
= ast_true(v
->value
);
18587 } else if (!strcasecmp(v
->name
, "accountcode")) {
18588 ast_copy_string(confp
->chan
.accountcode
, v
->value
, sizeof(confp
->chan
.accountcode
));
18589 } else if (!strcasecmp(v
->name
, "amaflags")) {
18590 y
= ast_channel_string2amaflag(v
->value
);
18592 ast_log(LOG_WARNING
, "Invalid AMA flags: %s at line %d.\n", v
->value
, v
->lineno
);
18594 confp
->chan
.amaflags
= y
;
18595 } else if (!strcasecmp(v
->name
, "polarityonanswerdelay")) {
18596 confp
->chan
.polarityonanswerdelay
= atoi(v
->value
);
18597 } else if (!strcasecmp(v
->name
, "answeronpolarityswitch")) {
18598 confp
->chan
.answeronpolarityswitch
= ast_true(v
->value
);
18599 } else if (!strcasecmp(v
->name
, "ani_info_digits")) {
18600 confp
->chan
.ani_info_digits
= atoi(v
->value
);
18601 } else if (!strcasecmp(v
->name
, "ani_wink_time")) {
18602 confp
->chan
.ani_wink_time
= atoi(v
->value
);
18603 } else if (!strcasecmp(v
->name
, "ani_timeout")) {
18604 confp
->chan
.ani_timeout
= atoi(v
->value
);
18605 } else if (!strcasecmp(v
->name
, "hanguponpolarityswitch")) {
18606 confp
->chan
.hanguponpolarityswitch
= ast_true(v
->value
);
18607 } else if (!strcasecmp(v
->name
, "autoreoriginate")) {
18608 confp
->chan
.reoriginate
= ast_true(v
->value
);
18609 } else if (!strcasecmp(v
->name
, "sendcalleridafter")) {
18610 confp
->chan
.sendcalleridafter
= atoi(v
->value
);
18611 } else if (!strcasecmp(v
->name
, "mwimonitornotify")) {
18612 ast_copy_string(mwimonitornotify
, v
->value
, sizeof(mwimonitornotify
));
18613 } else if (ast_cc_is_config_param(v
->name
)) {
18614 ast_cc_set_param(confp
->chan
.cc_params
, v
->name
, v
->value
);
18615 } else if (!strcasecmp(v
->name
, "mwisendtype")) {
18616 #ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
18617 if (!strcasecmp(v
->value
, "rpas")) { /* Ring Pulse Alert Signal */
18623 /* Default is fsk, to turn it off you must specify nofsk */
18624 memset(&confp
->chan
.mwisend_setting
, 0, sizeof(confp
->chan
.mwisend_setting
));
18625 if (strcasestr(v
->value
, "nofsk")) { /* NoFSK */
18626 confp
->chan
.mwisend_fsk
= 0;
18627 } else { /* Default FSK */
18628 confp
->chan
.mwisend_fsk
= 1;
18630 if (strcasestr(v
->value
, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
18631 confp
->chan
.mwisend_rpas
= 1;
18633 confp
->chan
.mwisend_rpas
= 0;
18635 if (strcasestr(v
->value
, "lrev")) { /* Line Reversal */
18636 confp
->chan
.mwisend_setting
.vmwi_type
|= DAHDI_VMWI_LREV
;
18638 if (strcasestr(v
->value
, "hvdc")) { /* HV 90VDC */
18639 confp
->chan
.mwisend_setting
.vmwi_type
|= DAHDI_VMWI_HVDC
;
18641 if ( (strcasestr(v
->value
, "neon")) || (strcasestr(v
->value
, "hvac")) ) { /* 90V DC pulses */
18642 confp
->chan
.mwisend_setting
.vmwi_type
|= DAHDI_VMWI_HVAC
;
18645 } else if (reload
!= 1) {
18646 if (!strcasecmp(v
->name
, "signalling") || !strcasecmp(v
->name
, "signaling")) {
18647 int orig_radio
= confp
->chan
.radio
;
18648 int orig_outsigmod
= confp
->chan
.outsigmod
;
18649 int orig_auto
= confp
->is_sig_auto
;
18651 confp
->chan
.radio
= 0;
18652 confp
->chan
.outsigmod
= -1;
18653 confp
->is_sig_auto
= 0;
18654 if (!strcasecmp(v
->value
, "em")) {
18655 confp
->chan
.sig
= SIG_EM
;
18656 } else if (!strcasecmp(v
->value
, "em_e1")) {
18657 confp
->chan
.sig
= SIG_EM_E1
;
18658 } else if (!strcasecmp(v
->value
, "em_w")) {
18659 confp
->chan
.sig
= SIG_EMWINK
;
18660 } else if (!strcasecmp(v
->value
, "fxs_ls")) {
18661 confp
->chan
.sig
= SIG_FXSLS
;
18662 } else if (!strcasecmp(v
->value
, "fxs_gs")) {
18663 confp
->chan
.sig
= SIG_FXSGS
;
18664 } else if (!strcasecmp(v
->value
, "fxs_ks")) {
18665 confp
->chan
.sig
= SIG_FXSKS
;
18666 } else if (!strcasecmp(v
->value
, "fxo_ls")) {
18667 confp
->chan
.sig
= SIG_FXOLS
;
18668 } else if (!strcasecmp(v
->value
, "fxo_gs")) {
18669 confp
->chan
.sig
= SIG_FXOGS
;
18670 } else if (!strcasecmp(v
->value
, "fxo_ks")) {
18671 confp
->chan
.sig
= SIG_FXOKS
;
18672 } else if (!strcasecmp(v
->value
, "fxs_rx")) {
18673 confp
->chan
.sig
= SIG_FXSKS
;
18674 confp
->chan
.radio
= 1;
18675 } else if (!strcasecmp(v
->value
, "fxo_rx")) {
18676 confp
->chan
.sig
= SIG_FXOLS
;
18677 confp
->chan
.radio
= 1;
18678 } else if (!strcasecmp(v
->value
, "fxs_tx")) {
18679 confp
->chan
.sig
= SIG_FXSLS
;
18680 confp
->chan
.radio
= 1;
18681 } else if (!strcasecmp(v
->value
, "fxo_tx")) {
18682 confp
->chan
.sig
= SIG_FXOGS
;
18683 confp
->chan
.radio
= 1;
18684 } else if (!strcasecmp(v
->value
, "em_rx")) {
18685 confp
->chan
.sig
= SIG_EM
;
18686 confp
->chan
.radio
= 1;
18687 } else if (!strcasecmp(v
->value
, "em_tx")) {
18688 confp
->chan
.sig
= SIG_EM
;
18689 confp
->chan
.radio
= 1;
18690 } else if (!strcasecmp(v
->value
, "em_rxtx")) {
18691 confp
->chan
.sig
= SIG_EM
;
18692 confp
->chan
.radio
= 2;
18693 } else if (!strcasecmp(v
->value
, "em_txrx")) {
18694 confp
->chan
.sig
= SIG_EM
;
18695 confp
->chan
.radio
= 2;
18696 } else if (!strcasecmp(v
->value
, "sf")) {
18697 confp
->chan
.sig
= SIG_SF
;
18698 } else if (!strcasecmp(v
->value
, "sf_w")) {
18699 confp
->chan
.sig
= SIG_SFWINK
;
18700 } else if (!strcasecmp(v
->value
, "sf_featd")) {
18701 confp
->chan
.sig
= SIG_FEATD
;
18702 } else if (!strcasecmp(v
->value
, "sf_featdmf")) {
18703 confp
->chan
.sig
= SIG_FEATDMF
;
18704 } else if (!strcasecmp(v
->value
, "sf_featb")) {
18705 confp
->chan
.sig
= SIG_SF_FEATB
;
18706 } else if (!strcasecmp(v
->value
, "sf")) {
18707 confp
->chan
.sig
= SIG_SF
;
18708 } else if (!strcasecmp(v
->value
, "sf_rx")) {
18709 confp
->chan
.sig
= SIG_SF
;
18710 confp
->chan
.radio
= 1;
18711 } else if (!strcasecmp(v
->value
, "sf_tx")) {
18712 confp
->chan
.sig
= SIG_SF
;
18713 confp
->chan
.radio
= 1;
18714 } else if (!strcasecmp(v
->value
, "sf_rxtx")) {
18715 confp
->chan
.sig
= SIG_SF
;
18716 confp
->chan
.radio
= 2;
18717 } else if (!strcasecmp(v
->value
, "sf_txrx")) {
18718 confp
->chan
.sig
= SIG_SF
;
18719 confp
->chan
.radio
= 2;
18720 } else if (!strcasecmp(v
->value
, "featd")) {
18721 confp
->chan
.sig
= SIG_FEATD
;
18722 } else if (!strcasecmp(v
->value
, "featdmf")) {
18723 confp
->chan
.sig
= SIG_FEATDMF
;
18724 } else if (!strcasecmp(v
->value
, "featdmf_ta")) {
18725 confp
->chan
.sig
= SIG_FEATDMF_TA
;
18726 } else if (!strcasecmp(v
->value
, "e911")) {
18727 confp
->chan
.sig
= SIG_E911
;
18728 } else if (!strcasecmp(v
->value
, "fgccama")) {
18729 confp
->chan
.sig
= SIG_FGC_CAMA
;
18730 } else if (!strcasecmp(v
->value
, "fgccamamf")) {
18731 confp
->chan
.sig
= SIG_FGC_CAMAMF
;
18732 } else if (!strcasecmp(v
->value
, "featb")) {
18733 confp
->chan
.sig
= SIG_FEATB
;
18735 } else if (!strcasecmp(v
->value
, "pri_net")) {
18736 confp
->chan
.sig
= SIG_PRI
;
18737 confp
->pri
.pri
.nodetype
= PRI_NETWORK
;
18738 } else if (!strcasecmp(v
->value
, "pri_cpe")) {
18739 confp
->chan
.sig
= SIG_PRI
;
18740 confp
->pri
.pri
.nodetype
= PRI_CPE
;
18741 } else if (!strcasecmp(v
->value
, "bri_cpe")) {
18742 confp
->chan
.sig
= SIG_BRI
;
18743 confp
->pri
.pri
.nodetype
= PRI_CPE
;
18744 } else if (!strcasecmp(v
->value
, "bri_net")) {
18745 confp
->chan
.sig
= SIG_BRI
;
18746 confp
->pri
.pri
.nodetype
= PRI_NETWORK
;
18747 } else if (!strcasecmp(v
->value
, "bri_cpe_ptmp")) {
18748 confp
->chan
.sig
= SIG_BRI_PTMP
;
18749 confp
->pri
.pri
.nodetype
= PRI_CPE
;
18750 } else if (!strcasecmp(v
->value
, "bri_net_ptmp")) {
18751 #if defined(HAVE_PRI_CALL_HOLD)
18752 confp
->chan
.sig
= SIG_BRI_PTMP
;
18753 confp
->pri
.pri
.nodetype
= PRI_NETWORK
;
18755 ast_log(LOG_WARNING
, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v
->lineno
);
18756 #endif /* !defined(HAVE_PRI_CALL_HOLD) */
18758 #if defined(HAVE_SS7)
18759 } else if (!strcasecmp(v
->value
, "ss7")) {
18760 confp
->chan
.sig
= SIG_SS7
;
18761 #endif /* defined(HAVE_SS7) */
18763 } else if (!strcasecmp(v
->value
, "mfcr2")) {
18764 confp
->chan
.sig
= SIG_MFCR2
;
18766 } else if (!strcasecmp(v
->value
, "auto")) {
18767 confp
->is_sig_auto
= 1;
18769 confp
->chan
.outsigmod
= orig_outsigmod
;
18770 confp
->chan
.radio
= orig_radio
;
18771 confp
->is_sig_auto
= orig_auto
;
18772 ast_log(LOG_ERROR
, "Unknown signalling method '%s' at line %d.\n", v
->value
, v
->lineno
);
18774 } else if (!strcasecmp(v
->name
, "outsignalling") || !strcasecmp(v
->name
, "outsignaling")) {
18775 if (!strcasecmp(v
->value
, "em")) {
18776 confp
->chan
.outsigmod
= SIG_EM
;
18777 } else if (!strcasecmp(v
->value
, "em_e1")) {
18778 confp
->chan
.outsigmod
= SIG_EM_E1
;
18779 } else if (!strcasecmp(v
->value
, "em_w")) {
18780 confp
->chan
.outsigmod
= SIG_EMWINK
;
18781 } else if (!strcasecmp(v
->value
, "sf")) {
18782 confp
->chan
.outsigmod
= SIG_SF
;
18783 } else if (!strcasecmp(v
->value
, "sf_w")) {
18784 confp
->chan
.outsigmod
= SIG_SFWINK
;
18785 } else if (!strcasecmp(v
->value
, "sf_featd")) {
18786 confp
->chan
.outsigmod
= SIG_FEATD
;
18787 } else if (!strcasecmp(v
->value
, "sf_featdmf")) {
18788 confp
->chan
.outsigmod
= SIG_FEATDMF
;
18789 } else if (!strcasecmp(v
->value
, "sf_featb")) {
18790 confp
->chan
.outsigmod
= SIG_SF_FEATB
;
18791 } else if (!strcasecmp(v
->value
, "sf")) {
18792 confp
->chan
.outsigmod
= SIG_SF
;
18793 } else if (!strcasecmp(v
->value
, "featd")) {
18794 confp
->chan
.outsigmod
= SIG_FEATD
;
18795 } else if (!strcasecmp(v
->value
, "featdmf")) {
18796 confp
->chan
.outsigmod
= SIG_FEATDMF
;
18797 } else if (!strcasecmp(v
->value
, "featdmf_ta")) {
18798 confp
->chan
.outsigmod
= SIG_FEATDMF_TA
;
18799 } else if (!strcasecmp(v
->value
, "e911")) {
18800 confp
->chan
.outsigmod
= SIG_E911
;
18801 } else if (!strcasecmp(v
->value
, "fgccama")) {
18802 confp
->chan
.outsigmod
= SIG_FGC_CAMA
;
18803 } else if (!strcasecmp(v
->value
, "fgccamamf")) {
18804 confp
->chan
.outsigmod
= SIG_FGC_CAMAMF
;
18805 } else if (!strcasecmp(v
->value
, "featb")) {
18806 confp
->chan
.outsigmod
= SIG_FEATB
;
18808 ast_log(LOG_ERROR
, "Unknown signalling method '%s' at line %d.\n", v
->value
, v
->lineno
);
18811 } else if (!strcasecmp(v
->name
, "pridialplan")) {
18812 if (!strcasecmp(v
->value
, "national")) {
18813 confp
->pri
.pri
.dialplan
= PRI_NATIONAL_ISDN
+ 1;
18814 } else if (!strcasecmp(v
->value
, "unknown")) {
18815 confp
->pri
.pri
.dialplan
= PRI_UNKNOWN
+ 1;
18816 } else if (!strcasecmp(v
->value
, "private")) {
18817 confp
->pri
.pri
.dialplan
= PRI_PRIVATE
+ 1;
18818 } else if (!strcasecmp(v
->value
, "international")) {
18819 confp
->pri
.pri
.dialplan
= PRI_INTERNATIONAL_ISDN
+ 1;
18820 } else if (!strcasecmp(v
->value
, "local")) {
18821 confp
->pri
.pri
.dialplan
= PRI_LOCAL_ISDN
+ 1;
18822 } else if (!strcasecmp(v
->value
, "dynamic")) {
18823 confp
->pri
.pri
.dialplan
= -1;
18824 } else if (!strcasecmp(v
->value
, "redundant")) {
18825 confp
->pri
.pri
.dialplan
= -2;
18827 ast_log(LOG_WARNING
, "Unknown PRI dialplan '%s' at line %d.\n", v
->value
, v
->lineno
);
18829 } else if (!strcasecmp(v
->name
, "prilocaldialplan")) {
18830 if (!strcasecmp(v
->value
, "national")) {
18831 confp
->pri
.pri
.localdialplan
= PRI_NATIONAL_ISDN
+ 1;
18832 } else if (!strcasecmp(v
->value
, "unknown")) {
18833 confp
->pri
.pri
.localdialplan
= PRI_UNKNOWN
+ 1;
18834 } else if (!strcasecmp(v
->value
, "private")) {
18835 confp
->pri
.pri
.localdialplan
= PRI_PRIVATE
+ 1;
18836 } else if (!strcasecmp(v
->value
, "international")) {
18837 confp
->pri
.pri
.localdialplan
= PRI_INTERNATIONAL_ISDN
+ 1;
18838 } else if (!strcasecmp(v
->value
, "local")) {
18839 confp
->pri
.pri
.localdialplan
= PRI_LOCAL_ISDN
+ 1;
18840 } else if (!strcasecmp(v
->value
, "from_channel")) {
18841 confp
->pri
.pri
.localdialplan
= 0;
18842 } else if (!strcasecmp(v
->value
, "dynamic")) {
18843 confp
->pri
.pri
.localdialplan
= -1;
18844 } else if (!strcasecmp(v
->value
, "redundant")) {
18845 confp
->pri
.pri
.localdialplan
= -2;
18847 ast_log(LOG_WARNING
, "Unknown PRI localdialplan '%s' at line %d.\n", v
->value
, v
->lineno
);
18849 } else if (!strcasecmp(v
->name
, "pricpndialplan")) {
18850 if (!strcasecmp(v
->value
, "national")) {
18851 confp
->pri
.pri
.cpndialplan
= PRI_NATIONAL_ISDN
+ 1;
18852 } else if (!strcasecmp(v
->value
, "unknown")) {
18853 confp
->pri
.pri
.cpndialplan
= PRI_UNKNOWN
+ 1;
18854 } else if (!strcasecmp(v
->value
, "private")) {
18855 confp
->pri
.pri
.cpndialplan
= PRI_PRIVATE
+ 1;
18856 } else if (!strcasecmp(v
->value
, "international")) {
18857 confp
->pri
.pri
.cpndialplan
= PRI_INTERNATIONAL_ISDN
+ 1;
18858 } else if (!strcasecmp(v
->value
, "local")) {
18859 confp
->pri
.pri
.cpndialplan
= PRI_LOCAL_ISDN
+ 1;
18860 } else if (!strcasecmp(v
->value
, "from_channel")) {
18861 confp
->pri
.pri
.cpndialplan
= 0;
18862 } else if (!strcasecmp(v
->value
, "dynamic")) {
18863 confp
->pri
.pri
.cpndialplan
= -1;
18864 } else if (!strcasecmp(v
->value
, "redundant")) {
18865 confp
->pri
.pri
.cpndialplan
= -2;
18867 ast_log(LOG_WARNING
, "Unknown PRI cpndialplan '%s' at line %d.\n", v
->value
, v
->lineno
);
18869 } else if (!strcasecmp(v
->name
, "switchtype")) {
18870 if (!strcasecmp(v
->value
, "national"))
18871 confp
->pri
.pri
.switchtype
= PRI_SWITCH_NI2
;
18872 else if (!strcasecmp(v
->value
, "ni1"))
18873 confp
->pri
.pri
.switchtype
= PRI_SWITCH_NI1
;
18874 else if (!strcasecmp(v
->value
, "dms100"))
18875 confp
->pri
.pri
.switchtype
= PRI_SWITCH_DMS100
;
18876 else if (!strcasecmp(v
->value
, "4ess"))
18877 confp
->pri
.pri
.switchtype
= PRI_SWITCH_ATT4ESS
;
18878 else if (!strcasecmp(v
->value
, "5ess"))
18879 confp
->pri
.pri
.switchtype
= PRI_SWITCH_LUCENT5E
;
18880 else if (!strcasecmp(v
->value
, "euroisdn"))
18881 confp
->pri
.pri
.switchtype
= PRI_SWITCH_EUROISDN_E1
;
18882 else if (!strcasecmp(v
->value
, "qsig"))
18883 confp
->pri
.pri
.switchtype
= PRI_SWITCH_QSIG
;
18885 ast_log(LOG_ERROR
, "Unknown switchtype '%s' at line %d.\n", v
->value
, v
->lineno
);
18888 } else if (!strcasecmp(v
->name
, "msn")) {
18889 ast_copy_string(confp
->pri
.pri
.msn_list
, v
->value
,
18890 sizeof(confp
->pri
.pri
.msn_list
));
18891 } else if (!strcasecmp(v
->name
, "nsf")) {
18892 if (!strcasecmp(v
->value
, "sdn"))
18893 confp
->pri
.pri
.nsf
= PRI_NSF_SDN
;
18894 else if (!strcasecmp(v
->value
, "megacom"))
18895 confp
->pri
.pri
.nsf
= PRI_NSF_MEGACOM
;
18896 else if (!strcasecmp(v
->value
, "tollfreemegacom"))
18897 confp
->pri
.pri
.nsf
= PRI_NSF_TOLL_FREE_MEGACOM
;
18898 else if (!strcasecmp(v
->value
, "accunet"))
18899 confp
->pri
.pri
.nsf
= PRI_NSF_ACCUNET
;
18900 else if (!strcasecmp(v
->value
, "none"))
18901 confp
->pri
.pri
.nsf
= PRI_NSF_NONE
;
18903 ast_log(LOG_WARNING
, "Unknown network-specific facility '%s' at line %d.\n", v
->value
, v
->lineno
);
18904 confp
->pri
.pri
.nsf
= PRI_NSF_NONE
;
18906 } else if (!strcasecmp(v
->name
, "priindication")) {
18907 if (!strcasecmp(v
->value
, "outofband"))
18908 confp
->chan
.priindication_oob
= 1;
18909 else if (!strcasecmp(v
->value
, "inband"))
18910 confp
->chan
.priindication_oob
= 0;
18912 ast_log(LOG_WARNING
, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
18913 v
->value
, v
->lineno
);
18914 } else if (!strcasecmp(v
->name
, "priexclusive")) {
18915 confp
->chan
.priexclusive
= ast_true(v
->value
);
18916 } else if (!strcasecmp(v
->name
, "internationalprefix")) {
18917 ast_copy_string(confp
->pri
.pri
.internationalprefix
, v
->value
, sizeof(confp
->pri
.pri
.internationalprefix
));
18918 } else if (!strcasecmp(v
->name
, "nationalprefix")) {
18919 ast_copy_string(confp
->pri
.pri
.nationalprefix
, v
->value
, sizeof(confp
->pri
.pri
.nationalprefix
));
18920 } else if (!strcasecmp(v
->name
, "localprefix")) {
18921 ast_copy_string(confp
->pri
.pri
.localprefix
, v
->value
, sizeof(confp
->pri
.pri
.localprefix
));
18922 } else if (!strcasecmp(v
->name
, "privateprefix")) {
18923 ast_copy_string(confp
->pri
.pri
.privateprefix
, v
->value
, sizeof(confp
->pri
.pri
.privateprefix
));
18924 } else if (!strcasecmp(v
->name
, "unknownprefix")) {
18925 ast_copy_string(confp
->pri
.pri
.unknownprefix
, v
->value
, sizeof(confp
->pri
.pri
.unknownprefix
));
18926 } else if (!strcasecmp(v
->name
, "resetinterval")) {
18927 if (!strcasecmp(v
->value
, "never"))
18928 confp
->pri
.pri
.resetinterval
= -1;
18929 else if (atoi(v
->value
) >= 60)
18930 confp
->pri
.pri
.resetinterval
= atoi(v
->value
);
18932 ast_log(LOG_WARNING
, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
18933 v
->value
, v
->lineno
);
18934 } else if (!strcasecmp(v
->name
, "force_restart_unavailable_chans")) {
18935 confp
->pri
.pri
.force_restart_unavailable_chans
= ast_true(v
->value
);
18936 } else if (!strcasecmp(v
->name
, "minunused")) {
18937 confp
->pri
.pri
.minunused
= atoi(v
->value
);
18938 } else if (!strcasecmp(v
->name
, "minidle")) {
18939 confp
->pri
.pri
.minidle
= atoi(v
->value
);
18940 } else if (!strcasecmp(v
->name
, "idleext")) {
18941 ast_copy_string(confp
->pri
.pri
.idleext
, v
->value
, sizeof(confp
->pri
.pri
.idleext
));
18942 } else if (!strcasecmp(v
->name
, "idledial")) {
18943 ast_copy_string(confp
->pri
.pri
.idledial
, v
->value
, sizeof(confp
->pri
.pri
.idledial
));
18944 } else if (!strcasecmp(v
->name
, "overlapdial")) {
18945 if (ast_true(v
->value
)) {
18946 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_BOTH
;
18947 } else if (!strcasecmp(v
->value
, "incoming")) {
18948 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_INCOMING
;
18949 } else if (!strcasecmp(v
->value
, "outgoing")) {
18950 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_OUTGOING
;
18951 } else if (!strcasecmp(v
->value
, "both") || ast_true(v
->value
)) {
18952 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_BOTH
;
18954 confp
->pri
.pri
.overlapdial
= DAHDI_OVERLAPDIAL_NONE
;
18956 #ifdef HAVE_PRI_PROG_W_CAUSE
18957 } else if (!strcasecmp(v
->name
, "qsigchannelmapping")) {
18958 if (!strcasecmp(v
->value
, "logical")) {
18959 confp
->pri
.pri
.qsigchannelmapping
= DAHDI_CHAN_MAPPING_LOGICAL
;
18960 } else if (!strcasecmp(v
->value
, "physical")) {
18961 confp
->pri
.pri
.qsigchannelmapping
= DAHDI_CHAN_MAPPING_PHYSICAL
;
18963 confp
->pri
.pri
.qsigchannelmapping
= DAHDI_CHAN_MAPPING_PHYSICAL
;
18966 } else if (!strcasecmp(v
->name
, "discardremoteholdretrieval")) {
18967 confp
->pri
.pri
.discardremoteholdretrieval
= ast_true(v
->value
);
18968 #if defined(HAVE_PRI_SERVICE_MESSAGES)
18969 } else if (!strcasecmp(v
->name
, "service_message_support")) {
18970 /* assuming switchtype for this channel group has been configured already */
18971 if ((confp
->pri
.pri
.switchtype
== PRI_SWITCH_ATT4ESS
18972 || confp
->pri
.pri
.switchtype
== PRI_SWITCH_LUCENT5E
18973 || confp
->pri
.pri
.switchtype
== PRI_SWITCH_NI2
) && ast_true(v
->value
)) {
18974 confp
->pri
.pri
.enable_service_message_support
= 1;
18976 confp
->pri
.pri
.enable_service_message_support
= 0;
18978 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
18979 #ifdef HAVE_PRI_INBANDDISCONNECT
18980 } else if (!strcasecmp(v
->name
, "inbanddisconnect")) {
18981 confp
->pri
.pri
.inbanddisconnect
= ast_true(v
->value
);
18983 } else if (!strcasecmp(v
->name
, "pritimer")) {
18984 #ifdef PRI_GETSET_TIMERS
18991 ast_copy_string(tmp
, v
->value
, sizeof(tmp
));
18993 timerc
= strsep(&c
, ",");
18994 if (!ast_strlen_zero(timerc
) && !ast_strlen_zero(c
)) {
18995 timeridx
= pri_timer2idx(timerc
);
18997 if (timeridx
< 0 || PRI_MAX_TIMERS
<= timeridx
) {
18998 ast_log(LOG_WARNING
,
18999 "'%s' is not a valid ISDN timer at line %d.\n", timerc
,
19001 } else if (!timer
) {
19002 ast_log(LOG_WARNING
,
19003 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19004 c
, timerc
, v
->lineno
);
19006 confp
->pri
.pri
.pritimers
[timeridx
] = timer
;
19009 ast_log(LOG_WARNING
,
19010 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19011 v
->value
, v
->lineno
);
19013 #endif /* PRI_GETSET_TIMERS */
19014 } else if (!strcasecmp(v
->name
, "facilityenable")) {
19015 confp
->pri
.pri
.facilityenable
= ast_true(v
->value
);
19016 #if defined(HAVE_PRI_AOC_EVENTS)
19017 } else if (!strcasecmp(v
->name
, "aoc_enable")) {
19018 confp
->pri
.pri
.aoc_passthrough_flag
= 0;
19019 if (strchr(v
->value
, 's') || strchr(v
->value
, 'S')) {
19020 confp
->pri
.pri
.aoc_passthrough_flag
|= SIG_PRI_AOC_GRANT_S
;
19022 if (strchr(v
->value
, 'd') || strchr(v
->value
, 'D')) {
19023 confp
->pri
.pri
.aoc_passthrough_flag
|= SIG_PRI_AOC_GRANT_D
;
19025 if (strchr(v
->value
, 'e') || strchr(v
->value
, 'E')) {
19026 confp
->pri
.pri
.aoc_passthrough_flag
|= SIG_PRI_AOC_GRANT_E
;
19028 } else if (!strcasecmp(v
->name
, "aoce_delayhangup")) {
19029 confp
->pri
.pri
.aoce_delayhangup
= ast_true(v
->value
);
19030 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
19031 #if defined(HAVE_PRI_CALL_HOLD)
19032 } else if (!strcasecmp(v
->name
, "hold_disconnect_transfer")) {
19033 confp
->pri
.pri
.hold_disconnect_transfer
= ast_true(v
->value
);
19034 #endif /* defined(HAVE_PRI_CALL_HOLD) */
19035 } else if (!strcasecmp(v
->name
, "moh_signaling")
19036 || !strcasecmp(v
->name
, "moh_signalling")) {
19037 if (!strcasecmp(v
->value
, "moh")) {
19038 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_MOH
;
19039 } else if (!strcasecmp(v
->value
, "notify")) {
19040 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_NOTIFY
;
19041 #if defined(HAVE_PRI_CALL_HOLD)
19042 } else if (!strcasecmp(v
->value
, "hold")) {
19043 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_HOLD
;
19044 #endif /* defined(HAVE_PRI_CALL_HOLD) */
19046 confp
->pri
.pri
.moh_signaling
= SIG_PRI_MOH_SIGNALING_MOH
;
19048 #if defined(HAVE_PRI_CCSS)
19049 } else if (!strcasecmp(v
->name
, "cc_ptmp_recall_mode")) {
19050 if (!strcasecmp(v
->value
, "global")) {
19051 confp
->pri
.pri
.cc_ptmp_recall_mode
= 0;/* globalRecall */
19052 } else if (!strcasecmp(v
->value
, "specific")) {
19053 confp
->pri
.pri
.cc_ptmp_recall_mode
= 1;/* specificRecall */
19055 confp
->pri
.pri
.cc_ptmp_recall_mode
= 1;/* specificRecall */
19057 } else if (!strcasecmp(v
->name
, "cc_qsig_signaling_link_req")) {
19058 if (!strcasecmp(v
->value
, "release")) {
19059 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 0;/* release */
19060 } else if (!strcasecmp(v
->value
, "retain")) {
19061 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 1;/* retain */
19062 } else if (!strcasecmp(v
->value
, "do_not_care")) {
19063 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 2;/* do-not-care */
19065 confp
->pri
.pri
.cc_qsig_signaling_link_req
= 1;/* retain */
19067 } else if (!strcasecmp(v
->name
, "cc_qsig_signaling_link_rsp")) {
19068 if (!strcasecmp(v
->value
, "release")) {
19069 confp
->pri
.pri
.cc_qsig_signaling_link_rsp
= 0;/* release */
19070 } else if (!strcasecmp(v
->value
, "retain")) {
19071 confp
->pri
.pri
.cc_qsig_signaling_link_rsp
= 1;/* retain */
19073 confp
->pri
.pri
.cc_qsig_signaling_link_rsp
= 1;/* retain */
19075 #endif /* defined(HAVE_PRI_CCSS) */
19076 #if defined(HAVE_PRI_CALL_WAITING)
19077 } else if (!strcasecmp(v
->name
, "max_call_waiting_calls")) {
19078 confp
->pri
.pri
.max_call_waiting_calls
= atoi(v
->value
);
19079 if (confp
->pri
.pri
.max_call_waiting_calls
< 0) {
19080 /* Negative values are not allowed. */
19081 confp
->pri
.pri
.max_call_waiting_calls
= 0;
19083 } else if (!strcasecmp(v
->name
, "allow_call_waiting_calls")) {
19084 confp
->pri
.pri
.allow_call_waiting_calls
= ast_true(v
->value
);
19085 #endif /* defined(HAVE_PRI_CALL_WAITING) */
19086 #if defined(HAVE_PRI_MWI)
19087 } else if (!strcasecmp(v
->name
, "mwi_mailboxes")) {
19088 ast_copy_string(confp
->pri
.pri
.mwi_mailboxes
, v
->value
,
19089 sizeof(confp
->pri
.pri
.mwi_mailboxes
));
19090 } else if (!strcasecmp(v
->name
, "mwi_vm_boxes")) {
19091 ast_copy_string(confp
->pri
.pri
.mwi_vm_boxes
, v
->value
,
19092 sizeof(confp
->pri
.pri
.mwi_vm_boxes
));
19093 } else if (!strcasecmp(v
->name
, "mwi_vm_numbers")) {
19094 ast_copy_string(confp
->pri
.pri
.mwi_vm_numbers
, v
->value
,
19095 sizeof(confp
->pri
.pri
.mwi_vm_numbers
));
19096 #endif /* defined(HAVE_PRI_MWI) */
19097 } else if (!strcasecmp(v
->name
, "append_msn_to_cid_tag")) {
19098 confp
->pri
.pri
.append_msn_to_user_tag
= ast_true(v
->value
);
19099 } else if (!strcasecmp(v
->name
, "inband_on_setup_ack")) {
19100 confp
->pri
.pri
.inband_on_setup_ack
= ast_true(v
->value
);
19101 } else if (!strcasecmp(v
->name
, "inband_on_proceeding")) {
19102 confp
->pri
.pri
.inband_on_proceeding
= ast_true(v
->value
);
19103 #if defined(HAVE_PRI_DISPLAY_TEXT)
19104 } else if (!strcasecmp(v
->name
, "display_send")) {
19105 confp
->pri
.pri
.display_flags_send
= dahdi_display_text_option(v
->value
);
19106 } else if (!strcasecmp(v
->name
, "display_receive")) {
19107 confp
->pri
.pri
.display_flags_receive
= dahdi_display_text_option(v
->value
);
19108 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19109 #if defined(HAVE_PRI_MCID)
19110 } else if (!strcasecmp(v
->name
, "mcid_send")) {
19111 confp
->pri
.pri
.mcid_send
= ast_true(v
->value
);
19112 #endif /* defined(HAVE_PRI_MCID) */
19113 #if defined(HAVE_PRI_DATETIME_SEND)
19114 } else if (!strcasecmp(v
->name
, "datetime_send")) {
19115 confp
->pri
.pri
.datetime_send
= dahdi_datetime_send_option(v
->value
);
19116 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
19117 } else if (!strcasecmp(v
->name
, "layer1_presence")) {
19118 if (!strcasecmp(v
->value
, "required")) {
19119 confp
->pri
.pri
.layer1_ignored
= 0;
19120 } else if (!strcasecmp(v
->value
, "ignore")) {
19121 confp
->pri
.pri
.layer1_ignored
= 1;
19124 confp
->pri
.pri
.layer1_ignored
= 0;
19126 #if defined(HAVE_PRI_L2_PERSISTENCE)
19127 } else if (!strcasecmp(v
->name
, "layer2_persistence")) {
19128 if (!strcasecmp(v
->value
, "keep_up")) {
19129 confp
->pri
.pri
.l2_persistence
= PRI_L2_PERSISTENCE_KEEP_UP
;
19130 } else if (!strcasecmp(v
->value
, "leave_down")) {
19131 confp
->pri
.pri
.l2_persistence
= PRI_L2_PERSISTENCE_LEAVE_DOWN
;
19133 confp
->pri
.pri
.l2_persistence
= PRI_L2_PERSISTENCE_DEFAULT
;
19135 #endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19136 } else if (!strcasecmp(v
->name
, "colp_send")) {
19137 if (!strcasecmp(v
->value
, "block")) {
19138 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_BLOCK
;
19139 } else if (!strcasecmp(v
->value
, "connect")) {
19140 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_CONNECT
;
19141 } else if (!strcasecmp(v
->value
, "update")) {
19142 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_UPDATE
;
19144 confp
->pri
.pri
.colp_send
= SIG_PRI_COLP_UPDATE
;
19146 #endif /* HAVE_PRI */
19147 #if defined(HAVE_SS7)
19148 } else if (!strcasecmp(v
->name
, "ss7type")) {
19149 if (!strcasecmp(v
->value
, "itu")) {
19150 cur_ss7type
= SS7_ITU
;
19151 } else if (!strcasecmp(v
->value
, "ansi")) {
19152 cur_ss7type
= SS7_ANSI
;
19154 ast_log(LOG_WARNING
, "'%s' is an unknown ss7 switch type at line %d.!\n", v
->value
, v
->lineno
);
19156 } else if (!strcasecmp(v
->name
, "slc")) {
19157 cur_slc
= atoi(v
->value
);
19158 } else if (!strcasecmp(v
->name
, "linkset")) {
19159 cur_linkset
= atoi(v
->value
);
19160 } else if (!strcasecmp(v
->name
, "pointcode")) {
19161 cur_pointcode
= parse_pointcode(v
->value
);
19162 } else if (!strcasecmp(v
->name
, "adjpointcode")) {
19163 cur_adjpointcode
= parse_pointcode(v
->value
);
19164 } else if (!strcasecmp(v
->name
, "defaultdpc")) {
19165 cur_defaultdpc
= parse_pointcode(v
->value
);
19166 } else if (!strcasecmp(v
->name
, "cicbeginswith")) {
19167 cur_cicbeginswith
= atoi(v
->value
);
19168 } else if (!strcasecmp(v
->name
, "networkindicator")) {
19169 if (!strcasecmp(v
->value
, "national")) {
19170 cur_networkindicator
= SS7_NI_NAT
;
19171 } else if (!strcasecmp(v
->value
, "national_spare")) {
19172 cur_networkindicator
= SS7_NI_NAT_SPARE
;
19173 } else if (!strcasecmp(v
->value
, "international")) {
19174 cur_networkindicator
= SS7_NI_INT
;
19175 } else if (!strcasecmp(v
->value
, "international_spare")) {
19176 cur_networkindicator
= SS7_NI_INT_SPARE
;
19178 cur_networkindicator
= -1;
19180 } else if (!strcasecmp(v
->name
, "ss7_internationalprefix")) {
19181 ast_copy_string(confp
->ss7
.ss7
.internationalprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.internationalprefix
));
19182 } else if (!strcasecmp(v
->name
, "ss7_nationalprefix")) {
19183 ast_copy_string(confp
->ss7
.ss7
.nationalprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.nationalprefix
));
19184 } else if (!strcasecmp(v
->name
, "ss7_subscriberprefix")) {
19185 ast_copy_string(confp
->ss7
.ss7
.subscriberprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.subscriberprefix
));
19186 } else if (!strcasecmp(v
->name
, "ss7_unknownprefix")) {
19187 ast_copy_string(confp
->ss7
.ss7
.unknownprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.unknownprefix
));
19188 } else if (!strcasecmp(v
->name
, "ss7_networkroutedprefix")) {
19189 ast_copy_string(confp
->ss7
.ss7
.networkroutedprefix
, v
->value
, sizeof(confp
->ss7
.ss7
.networkroutedprefix
));
19190 } else if (!strcasecmp(v
->name
, "ss7_called_nai")) {
19191 if (!strcasecmp(v
->value
, "national")) {
19192 confp
->ss7
.ss7
.called_nai
= SS7_NAI_NATIONAL
;
19193 } else if (!strcasecmp(v
->value
, "international")) {
19194 confp
->ss7
.ss7
.called_nai
= SS7_NAI_INTERNATIONAL
;
19195 } else if (!strcasecmp(v
->value
, "subscriber")) {
19196 confp
->ss7
.ss7
.called_nai
= SS7_NAI_SUBSCRIBER
;
19197 } else if (!strcasecmp(v
->value
, "unknown")) {
19198 confp
->ss7
.ss7
.called_nai
= SS7_NAI_UNKNOWN
;
19199 } else if (!strcasecmp(v
->value
, "dynamic")) {
19200 confp
->ss7
.ss7
.called_nai
= SS7_NAI_DYNAMIC
;
19202 ast_log(LOG_WARNING
, "Unknown SS7 called_nai '%s' at line %d.\n", v
->value
, v
->lineno
);
19204 } else if (!strcasecmp(v
->name
, "ss7_calling_nai")) {
19205 if (!strcasecmp(v
->value
, "national")) {
19206 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_NATIONAL
;
19207 } else if (!strcasecmp(v
->value
, "international")) {
19208 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_INTERNATIONAL
;
19209 } else if (!strcasecmp(v
->value
, "subscriber")) {
19210 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_SUBSCRIBER
;
19211 } else if (!strcasecmp(v
->value
, "unknown")) {
19212 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_UNKNOWN
;
19213 } else if (!strcasecmp(v
->value
, "dynamic")) {
19214 confp
->ss7
.ss7
.calling_nai
= SS7_NAI_DYNAMIC
;
19216 ast_log(LOG_WARNING
, "Unknown SS7 calling_nai '%s' at line %d.\n", v
->value
, v
->lineno
);
19218 } else if (!strcasecmp(v
->name
, "sigchan")) {
19220 sigchan
= atoi(v
->value
);
19221 res
= linkset_addsigchan(sigchan
);
19225 } else if (!strcasecmp(v
->name
, "ss7_explicitacm")) {
19226 struct dahdi_ss7
*link
;
19227 link
= ss7_resolve_linkset(cur_linkset
);
19229 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19232 if (ast_true(v
->value
)) {
19233 link
->ss7
.flags
|= LINKSET_FLAG_EXPLICITACM
;
19235 link
->ss7
.flags
&= ~LINKSET_FLAG_EXPLICITACM
;
19237 } else if (!strcasecmp(v
->name
, "ss7_autoacm")) {
19238 struct dahdi_ss7
*link
;
19239 link
= ss7_resolve_linkset(cur_linkset
);
19241 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19244 if (ast_true(v
->value
)) {
19245 link
->ss7
.flags
|= LINKSET_FLAG_AUTOACM
;
19247 link
->ss7
.flags
&= ~LINKSET_FLAG_AUTOACM
;
19249 } else if (!strcasecmp(v
->name
, "ss7_initialhwblo")) {
19250 struct dahdi_ss7
*link
;
19251 link
= ss7_resolve_linkset(cur_linkset
);
19253 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19256 if (ast_true(v
->value
)) {
19257 link
->ss7
.flags
|= LINKSET_FLAG_INITIALHWBLO
;
19259 link
->ss7
.flags
&= ~LINKSET_FLAG_INITIALHWBLO
;
19261 } else if (!strcasecmp(v
->name
, "ss7_use_echocontrol")) {
19262 struct dahdi_ss7
*link
;
19263 link
= ss7_resolve_linkset(cur_linkset
);
19265 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19268 if (ast_true(v
->value
)) {
19269 link
->ss7
.flags
|= LINKSET_FLAG_USEECHOCONTROL
;
19271 link
->ss7
.flags
&= ~LINKSET_FLAG_USEECHOCONTROL
;
19273 } else if (!strcasecmp(v
->name
, "ss7_default_echocontrol")) {
19274 struct dahdi_ss7
*link
;
19275 link
= ss7_resolve_linkset(cur_linkset
);
19277 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19280 if (ast_true(v
->value
)) {
19281 link
->ss7
.flags
|= LINKSET_FLAG_DEFAULTECHOCONTROL
;
19283 link
->ss7
.flags
&= ~LINKSET_FLAG_DEFAULTECHOCONTROL
;
19285 } else if (!strncasecmp(v
->name
, "isup_timer.", 11)) {
19286 struct dahdi_ss7
*link
;
19287 link
= ss7_resolve_linkset(cur_linkset
);
19289 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19292 if (!link
->ss7
.ss7
) {
19293 ast_log(LOG_ERROR
, "Please specify isup timers after sigchan!\n");
19294 } else if (!ss7_set_isup_timer(link
->ss7
.ss7
, strstr(v
->name
, ".") + 1, atoi(v
->value
))) {
19295 ast_log(LOG_ERROR
, "Invalid isup timer %s\n", v
->name
);
19297 } else if (!strncasecmp(v
->name
, "mtp3_timer.", 11)) {
19298 struct dahdi_ss7
*link
;
19299 link
= ss7_resolve_linkset(cur_linkset
);
19301 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19304 if (!link
->ss7
.ss7
) {
19305 ast_log(LOG_ERROR
, "Please specify mtp3 timers after sigchan!\n");
19306 } else if (!ss7_set_mtp3_timer(link
->ss7
.ss7
, strstr(v
->name
, ".") + 1, atoi(v
->value
))) {
19307 ast_log(LOG_ERROR
, "Invalid mtp3 timer %s\n", v
->name
);
19309 } else if (!strcasecmp(v
->name
, "inr_if_no_calling")) {
19310 struct dahdi_ss7
*link
;
19311 link
= ss7_resolve_linkset(cur_linkset
);
19313 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19316 if (!link
->ss7
.ss7
) {
19317 ast_log(LOG_ERROR
, "Please specify inr_if_no_calling after sigchan!\n");
19318 } else if (ast_true(v
->value
)) {
19319 ss7_set_flags(link
->ss7
.ss7
, SS7_INR_IF_NO_CALLING
);
19321 ss7_clear_flags(link
->ss7
.ss7
, SS7_INR_IF_NO_CALLING
);
19323 } else if (!strcasecmp(v
->name
, "non_isdn_access")) {
19324 struct dahdi_ss7
*link
;
19325 link
= ss7_resolve_linkset(cur_linkset
);
19327 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19330 if (!link
->ss7
.ss7
) {
19331 ast_log(LOG_ERROR
, "Please specify non_isdn_access after sigchan!\n");
19332 } else if (ast_true(v
->value
)) {
19333 ss7_clear_flags(link
->ss7
.ss7
, SS7_ISDN_ACCESS_INDICATOR
);
19335 ss7_set_flags(link
->ss7
.ss7
, SS7_ISDN_ACCESS_INDICATOR
);
19337 } else if (!strcasecmp(v
->name
, "sls_shift")) {
19338 struct dahdi_ss7
*link
;
19339 int sls_shift
= atoi(v
->value
);
19341 if (sls_shift
< 0 || sls_shift
> 7) {
19342 ast_log(LOG_ERROR
, "Invalid sls_shift value. Must be between 0 and 7\n");
19346 link
= ss7_resolve_linkset(cur_linkset
);
19348 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19351 if (!link
->ss7
.ss7
) {
19352 ast_log(LOG_ERROR
, "Please specify sls_shift after sigchan!\n");
19354 ss7_set_sls_shift(link
->ss7
.ss7
, sls_shift
);
19356 } else if (!strcasecmp(v
->name
, "cause_location")) {
19357 struct dahdi_ss7
*link
;
19358 int cause_location
= atoi(v
->value
);
19360 if (cause_location
< 0 || cause_location
> 15) {
19361 ast_log(LOG_ERROR
, "Invalid cause_location value. Must be between 0 and 15\n");
19364 link
= ss7_resolve_linkset(cur_linkset
);
19366 ast_log(LOG_ERROR
, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS
+ 1);
19369 if (!link
->ss7
.ss7
) {
19370 ast_log(LOG_ERROR
, "Please specify cause_location after sigchan!\n");
19372 ss7_set_cause_location(link
->ss7
.ss7
, cause_location
);
19374 #endif /* defined(HAVE_SS7) */
19376 } else if (!strcasecmp(v
->name
, "mfcr2_advanced_protocol_file")) {
19377 ast_copy_string(confp
->mfcr2
.r2proto_file
, v
->value
, sizeof(confp
->mfcr2
.r2proto_file
));
19378 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
);
19379 } else if (!strcasecmp(v
->name
, "mfcr2_logdir")) {
19380 ast_copy_string(confp
->mfcr2
.logdir
, v
->value
, sizeof(confp
->mfcr2
.logdir
));
19381 } else if (!strcasecmp(v
->name
, "mfcr2_variant")) {
19382 confp
->mfcr2
.variant
= openr2_proto_get_variant(v
->value
);
19383 if (OR2_VAR_UNKNOWN
== confp
->mfcr2
.variant
) {
19384 ast_log(LOG_WARNING
, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v
->value
, v
->lineno
);
19385 confp
->mfcr2
.variant
= OR2_VAR_ITU
;
19387 } else if (!strcasecmp(v
->name
, "mfcr2_mfback_timeout")) {
19388 confp
->mfcr2
.mfback_timeout
= atoi(v
->value
);
19389 if (!confp
->mfcr2
.mfback_timeout
) {
19390 ast_log(LOG_WARNING
, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19391 confp
->mfcr2
.mfback_timeout
= -1;
19392 } else if (confp
->mfcr2
.mfback_timeout
> 0 && confp
->mfcr2
.mfback_timeout
< 500) {
19393 ast_log(LOG_WARNING
, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19395 } else if (!strcasecmp(v
->name
, "mfcr2_metering_pulse_timeout")) {
19396 confp
->mfcr2
.metering_pulse_timeout
= atoi(v
->value
);
19397 if (confp
->mfcr2
.metering_pulse_timeout
> 500) {
19398 ast_log(LOG_WARNING
, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19400 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19401 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_detection")) {
19402 confp
->mfcr2
.dtmf_detection
= ast_true(v
->value
) ? 1 : 0;
19403 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_dialing")) {
19404 confp
->mfcr2
.dtmf_dialing
= ast_true(v
->value
) ? 1 : 0;
19405 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_time_on")) {
19406 confp
->mfcr2
.dtmf_time_on
= atoi(v
->value
);
19407 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_time_off")) {
19408 confp
->mfcr2
.dtmf_time_off
= atoi(v
->value
);
19410 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19411 } else if (!strcasecmp(v
->name
, "mfcr2_dtmf_end_timeout")) {
19412 confp
->mfcr2
.dtmf_end_timeout
= atoi(v
->value
);
19414 } else if (!strcasecmp(v
->name
, "mfcr2_get_ani_first")) {
19415 confp
->mfcr2
.get_ani_first
= ast_true(v
->value
) ? 1 : 0;
19416 } else if (!strcasecmp(v
->name
, "mfcr2_double_answer")) {
19417 confp
->mfcr2
.double_answer
= ast_true(v
->value
) ? 1 : 0;
19418 } else if (!strcasecmp(v
->name
, "mfcr2_charge_calls")) {
19419 confp
->mfcr2
.charge_calls
= ast_true(v
->value
) ? 1 : 0;
19420 } else if (!strcasecmp(v
->name
, "mfcr2_accept_on_offer")) {
19421 confp
->mfcr2
.accept_on_offer
= ast_true(v
->value
) ? 1 : 0;
19422 } else if (!strcasecmp(v
->name
, "mfcr2_allow_collect_calls")) {
19423 confp
->mfcr2
.allow_collect_calls
= ast_true(v
->value
) ? 1 : 0;
19424 } else if (!strcasecmp(v
->name
, "mfcr2_forced_release")) {
19425 confp
->mfcr2
.forced_release
= ast_true(v
->value
) ? 1 : 0;
19426 } else if (!strcasecmp(v
->name
, "mfcr2_immediate_accept")) {
19427 confp
->mfcr2
.immediate_accept
= ast_true(v
->value
) ? 1 : 0;
19428 #if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19429 } else if (!strcasecmp(v
->name
, "mfcr2_skip_category")) {
19430 confp
->mfcr2
.skip_category_request
= ast_true(v
->value
) ? 1 : 0;
19432 } else if (!strcasecmp(v
->name
, "mfcr2_call_files")) {
19433 confp
->mfcr2
.call_files
= ast_true(v
->value
) ? 1 : 0;
19434 } else if (!strcasecmp(v
->name
, "mfcr2_max_ani")) {
19435 confp
->mfcr2
.max_ani
= atoi(v
->value
);
19436 if (confp
->mfcr2
.max_ani
>= AST_MAX_EXTENSION
) {
19437 confp
->mfcr2
.max_ani
= AST_MAX_EXTENSION
- 1;
19439 } else if (!strcasecmp(v
->name
, "mfcr2_max_dnis")) {
19440 confp
->mfcr2
.max_dnis
= atoi(v
->value
);
19441 if (confp
->mfcr2
.max_dnis
>= AST_MAX_EXTENSION
) {
19442 confp
->mfcr2
.max_dnis
= AST_MAX_EXTENSION
- 1;
19444 } else if (!strcasecmp(v
->name
, "mfcr2_category")) {
19445 confp
->mfcr2
.category
= openr2_proto_get_category(v
->value
);
19446 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN
== confp
->mfcr2
.category
) {
19447 confp
->mfcr2
.category
= OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
;
19448 ast_log(LOG_WARNING
, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19449 v
->value
, v
->lineno
);
19451 } else if (!strcasecmp(v
->name
, "mfcr2_logging")) {
19452 openr2_log_level_t tmplevel
;
19455 char copy
[strlen(v
->value
) + 1];
19456 strcpy(copy
, v
->value
); /* safe */
19459 clevel
= strsep(&logval
,",");
19460 if (-1 == (tmplevel
= openr2_log_get_level(clevel
))) {
19461 ast_log(LOG_WARNING
, "Ignoring invalid logging level: '%s' at line %d.\n", clevel
, v
->lineno
);
19464 confp
->mfcr2
.loglevel
|= tmplevel
;
19466 #endif /* HAVE_OPENR2 */
19467 } else if (!strcasecmp(v
->name
, "cadence")) {
19468 /* setup to scan our argument */
19469 int element_count
, c
[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
19471 struct dahdi_ring_cadence new_cadence
;
19472 int cid_location
= -1;
19473 int firstcadencepos
= 0;
19474 char original_args
[80];
19475 int cadence_is_ok
= 1;
19477 ast_copy_string(original_args
, v
->value
, sizeof(original_args
));
19478 /* 16 cadences allowed (8 pairs) */
19479 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]);
19481 /* Cadence must be even (on/off) */
19482 if (element_count
% 2 == 1) {
19483 ast_log(LOG_ERROR
, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args
, v
->lineno
);
19487 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
19488 if (element_count
> ARRAY_LEN(c
)) {
19489 element_count
= ARRAY_LEN(c
);
19492 /* Ring cadences cannot be negative */
19493 for (i
= 0; i
< element_count
; i
++) {
19495 ast_log(LOG_ERROR
, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args
, v
->lineno
);
19498 } else if (c
[i
] < 0) {
19500 /* Silence duration, negative possibly okay */
19501 if (cid_location
== -1) {
19505 ast_log(LOG_ERROR
, "CID location specified twice: %s at line %d.\n", original_args
, v
->lineno
);
19510 if (firstcadencepos
== 0) {
19511 firstcadencepos
= i
; /* only recorded to avoid duplicate specification */
19512 /* duration will be passed negative to the DAHDI driver */
19514 ast_log(LOG_ERROR
, "First cadence position specified twice: %s at line %d.\n", original_args
, v
->lineno
);
19522 /* Substitute our scanned cadence */
19523 for (i
= 0; i
< 16; i
++) {
19524 new_cadence
.ringcadence
[i
] = c
[i
];
19527 if (cadence_is_ok
) {
19528 /* ---we scanned it without getting annoyed; now some sanity checks--- */
19529 if (element_count
< 2) {
19530 ast_log(LOG_ERROR
, "Minimum cadence is ring,pause: %s at line %d.\n", original_args
, v
->lineno
);
19532 if (cid_location
== -1) {
19533 /* user didn't say; default to first pause */
19536 /* convert element_index to cidrings value */
19537 cid_location
= (cid_location
+ 1) / 2;
19539 /* ---we like their cadence; try to install it--- */
19540 if (!user_has_defined_cadences
++)
19541 /* this is the first user-defined cadence; clear the default user cadences */
19543 if ((num_cadence
+1) >= NUM_CADENCE_MAX
)
19544 ast_log(LOG_ERROR
, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX
, original_args
, v
->lineno
);
19546 cadences
[num_cadence
] = new_cadence
;
19547 cidrings
[num_cadence
++] = cid_location
;
19548 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence
,original_args
);
19552 } else if (!strcasecmp(v
->name
, "ringtimeout")) {
19553 ringt_base
= (atoi(v
->value
) * 8) / READ_SIZE
;
19554 } else if (!strcasecmp(v
->name
, "prewink")) {
19555 confp
->timing
.prewinktime
= atoi(v
->value
);
19556 } else if (!strcasecmp(v
->name
, "preflash")) {
19557 confp
->timing
.preflashtime
= atoi(v
->value
);
19558 } else if (!strcasecmp(v
->name
, "wink")) {
19559 confp
->timing
.winktime
= atoi(v
->value
);
19560 } else if (!strcasecmp(v
->name
, "flash")) {
19561 confp
->timing
.flashtime
= atoi(v
->value
);
19562 } else if (!strcasecmp(v
->name
, "start")) {
19563 confp
->timing
.starttime
= atoi(v
->value
);
19564 } else if (!strcasecmp(v
->name
, "rxwink")) {
19565 confp
->timing
.rxwinktime
= atoi(v
->value
);
19566 } else if (!strcasecmp(v
->name
, "rxflash")) {
19567 confp
->timing
.rxflashtime
= atoi(v
->value
);
19568 } else if (!strcasecmp(v
->name
, "debounce")) {
19569 confp
->timing
.debouncetime
= atoi(v
->value
);
19570 } else if (!strcasecmp(v
->name
, "toneduration")) {
19574 struct dahdi_dialparams dps
;
19576 ctlfd
= open("/dev/dahdi/ctl", O_RDWR
);
19578 ast_log(LOG_ERROR
, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v
->lineno
);
19582 toneduration
= atoi(v
->value
);
19583 if (toneduration
> -1) {
19584 memset(&dps
, 0, sizeof(dps
));
19586 dps
.dtmf_tonelen
= dps
.mfv1_tonelen
= toneduration
;
19587 res
= ioctl(ctlfd
, DAHDI_SET_DIALPARAMS
, &dps
);
19589 ast_log(LOG_ERROR
, "Invalid tone duration: %d ms at line %d: %s\n", toneduration
, v
->lineno
, strerror(errno
));
19595 } else if (!strcasecmp(v
->name
, "defaultcic")) {
19596 ast_copy_string(defaultcic
, v
->value
, sizeof(defaultcic
));
19597 } else if (!strcasecmp(v
->name
, "defaultozz")) {
19598 ast_copy_string(defaultozz
, v
->value
, sizeof(defaultozz
));
19599 } else if (!strcasecmp(v
->name
, "mwilevel")) {
19600 mwilevel
= atoi(v
->value
);
19601 } else if (!strcasecmp(v
->name
, "dtmfcidlevel")) {
19602 dtmfcid_level
= atoi(v
->value
);
19603 } else if (!strcasecmp(v
->name
, "reportalarms")) {
19604 if (!strcasecmp(v
->value
, "all"))
19605 report_alarms
= REPORT_CHANNEL_ALARMS
| REPORT_SPAN_ALARMS
;
19606 if (!strcasecmp(v
->value
, "none"))
19608 else if (!strcasecmp(v
->value
, "channels"))
19609 report_alarms
= REPORT_CHANNEL_ALARMS
;
19610 else if (!strcasecmp(v
->value
, "spans"))
19611 report_alarms
= REPORT_SPAN_ALARMS
;
19613 } else if (!(options
& PROC_DAHDI_OPT_NOWARN
) )
19614 ast_log(LOG_NOTICE
, "Ignoring any changes to '%s' (on reload) at line %d.\n", v
->name
, v
->lineno
);
19618 /* Process the deferred dahdichan value. */
19619 if (build_channels(confp
, dahdichan
->value
, reload
, dahdichan
->lineno
)) {
19620 if (confp
->ignore_failed_channels
) {
19621 ast_log(LOG_WARNING
,
19622 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
19631 * Since confp has already filled individual dahdi_pvt objects with channels
19632 * at this point, clear the variables in confp's pvt.
19634 if (confp
->chan
.vars
) {
19635 ast_variables_destroy(confp
->chan
.vars
);
19636 confp
->chan
.vars
= NULL
;
19639 /* mark the first channels of each DAHDI span to watch for their span alarms */
19640 for (tmp
= iflist
, y
=-1; tmp
; tmp
= tmp
->next
) {
19641 if (!tmp
->destroy
&& tmp
->span
!= y
) {
19642 tmp
->manages_span_alarms
= 1;
19645 tmp
->manages_span_alarms
= 0;
19649 /*< \todo why check for the pseudo in the per-channel section.
19650 * Any actual use for manual setup of the pseudo channel? */
19651 if (!has_pseudo
&& reload
!= 1 && !(options
& PROC_DAHDI_OPT_NOCHAN
)) {
19652 /* use the default configuration for a channel, so
19653 that any settings from real configured channels
19654 don't "leak" into the pseudo channel config
19656 struct dahdi_chan_conf conf
= dahdi_chan_conf_default();
19658 if (conf
.chan
.cc_params
) {
19659 tmp
= mkintf(CHAN_PSEUDO
, &conf
, reload
);
19664 ast_verb(3, "Automatically generated pseudo channel\n");
19667 ast_log(LOG_WARNING
, "Unable to register pseudo channel!\n");
19669 ast_cc_config_params_destroy(conf
.chan
.cc_params
);
19672 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
19673 confp
->chan
.named_callgroups
= ast_unref_namedgroups(confp
->chan
.named_callgroups
);
19674 confp
->chan
.named_pickupgroups
= ast_unref_namedgroups(confp
->chan
.named_pickupgroups
);
19681 * \brief Deep copy struct dahdi_chan_conf.
19684 * \param dest Destination.
19685 * \param src Source.
19687 static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf
*dest
, const struct dahdi_chan_conf
*src
)
19689 struct ast_cc_config_params
*cc_params
;
19691 cc_params
= dest
->chan
.cc_params
;
19693 dest
->chan
.cc_params
= cc_params
;
19694 ast_cc_copy_config_params(dest
->chan
.cc_params
, src
->chan
.cc_params
);
19699 * \brief Setup DAHDI channel driver.
19701 * \param reload enum: load_module(0), reload(1), restart(2).
19702 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
19703 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
19704 * \param conf Local config parameters. So cc_params can be properly destroyed.
19706 * \retval 0 on success.
19707 * \retval -1 on error.
19709 static int setup_dahdi_int(int reload
, struct dahdi_chan_conf
*default_conf
, struct dahdi_chan_conf
*base_conf
, struct dahdi_chan_conf
*conf
)
19711 struct ast_config
*cfg
;
19712 struct ast_config
*ucfg
;
19713 struct ast_variable
*v
;
19714 struct ast_flags config_flags
= { reload
== 1 ? CONFIG_FLAG_FILEUNCHANGED
: 0 };
19725 int dchannels
[SIG_PRI_NUM_DCHANS
];
19728 static int had_cfg_before
= 1;/* So initial load will complain if we don't have cfg. */
19730 cfg
= ast_config_load(config
, config_flags
);
19731 have_cfg_now
= !!cfg
;
19733 /* Error if we have no config file */
19734 if (had_cfg_before
) {
19735 ast_log(LOG_ERROR
, "Unable to load config %s\n", config
);
19736 ast_clear_flag(&config_flags
, CONFIG_FLAG_FILEUNCHANGED
);
19738 cfg
= ast_config_new();/* Dummy config */
19742 ucfg
= ast_config_load("users.conf", config_flags
);
19743 if (ucfg
== CONFIG_STATUS_FILEUNCHANGED
) {
19744 ast_config_destroy(cfg
);
19747 if (ucfg
== CONFIG_STATUS_FILEINVALID
) {
19748 ast_log(LOG_ERROR
, "File users.conf cannot be parsed. Aborting.\n");
19749 ast_config_destroy(cfg
);
19752 } else if (cfg
== CONFIG_STATUS_FILEUNCHANGED
) {
19753 ucfg
= ast_config_load("users.conf", config_flags
);
19754 if (ucfg
== CONFIG_STATUS_FILEUNCHANGED
) {
19757 if (ucfg
== CONFIG_STATUS_FILEINVALID
) {
19758 ast_log(LOG_ERROR
, "File users.conf cannot be parsed. Aborting.\n");
19761 ast_clear_flag(&config_flags
, CONFIG_FLAG_FILEUNCHANGED
);
19762 cfg
= ast_config_load(config
, config_flags
);
19763 have_cfg_now
= !!cfg
;
19765 if (had_cfg_before
) {
19766 /* We should have been able to load the config. */
19767 ast_log(LOG_ERROR
, "Bad. Unable to load config %s\n", config
);
19768 ast_config_destroy(ucfg
);
19771 cfg
= ast_config_new();/* Dummy config */
19773 ast_config_destroy(ucfg
);
19776 } else if (cfg
== CONFIG_STATUS_FILEINVALID
) {
19777 ast_log(LOG_ERROR
, "File %s cannot be parsed. Aborting.\n", config
);
19778 ast_config_destroy(ucfg
);
19781 } else if (cfg
== CONFIG_STATUS_FILEINVALID
) {
19782 ast_log(LOG_ERROR
, "File %s cannot be parsed. Aborting.\n", config
);
19785 ast_clear_flag(&config_flags
, CONFIG_FLAG_FILEUNCHANGED
);
19786 ucfg
= ast_config_load("users.conf", config_flags
);
19787 if (ucfg
== CONFIG_STATUS_FILEINVALID
) {
19788 ast_log(LOG_ERROR
, "File users.conf cannot be parsed. Aborting.\n");
19789 ast_config_destroy(cfg
);
19793 had_cfg_before
= have_cfg_now
;
19795 /* It's a little silly to lock it, but we might as well just to be sure */
19796 ast_mutex_lock(&iflock
);
19799 /* Process trunkgroups first */
19800 v
= ast_variable_browse(cfg
, "trunkgroups");
19802 if (!strcasecmp(v
->name
, "trunkgroup")) {
19803 trunkgroup
= atoi(v
->value
);
19804 if (trunkgroup
> 0) {
19805 if ((c
= strchr(v
->value
, ','))) {
19807 memset(dchannels
, 0, sizeof(dchannels
));
19808 while (c
&& (i
< SIG_PRI_NUM_DCHANS
)) {
19809 dchannels
[i
] = atoi(c
+ 1);
19810 if (dchannels
[i
] < 0) {
19811 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
);
19814 c
= strchr(c
+ 1, ',');
19817 if (pri_create_trunkgroup(trunkgroup
, dchannels
)) {
19818 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
);
19820 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");
19822 ast_log(LOG_WARNING
, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup
, v
->lineno
);
19824 ast_log(LOG_WARNING
, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup
, v
->lineno
);
19826 ast_log(LOG_WARNING
, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v
->lineno
);
19827 } else if (!strcasecmp(v
->name
, "spanmap")) {
19828 spanno
= atoi(v
->value
);
19830 if ((c
= strchr(v
->value
, ','))) {
19831 trunkgroup
= atoi(c
+ 1);
19832 if (trunkgroup
> 0) {
19833 if ((c
= strchr(c
+ 1, ',')))
19834 logicalspan
= atoi(c
+ 1);
19837 if (logicalspan
>= 0) {
19838 if (pri_create_spanmap(spanno
- 1, trunkgroup
, logicalspan
)) {
19839 ast_log(LOG_WARNING
, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno
, trunkgroup
, logicalspan
);
19841 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno
, trunkgroup
, logicalspan
);
19843 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
);
19845 ast_log(LOG_WARNING
, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v
->lineno
);
19847 ast_log(LOG_WARNING
, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v
->lineno
);
19849 ast_log(LOG_WARNING
, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v
->lineno
);
19851 ast_log(LOG_NOTICE
, "Ignoring unknown keyword '%s' in trunkgroups\n", v
->name
);
19858 /* Copy the default jb config over global_jbconf */
19859 memcpy(&global_jbconf
, &default_jbconf
, sizeof(global_jbconf
));
19861 mwimonitornotify
[0] = '\0';
19863 v
= ast_variable_browse(cfg
, "channels");
19864 if ((res
= process_dahdi(base_conf
,
19865 "" /* Must be empty for the channels category. Silly voicemail mailbox. */,
19867 ast_mutex_unlock(&iflock
);
19868 ast_config_destroy(cfg
);
19870 ast_config_destroy(ucfg
);
19875 /* Now get configuration from all normal sections in chan_dahdi.conf: */
19876 for (cat
= ast_category_browse(cfg
, NULL
); cat
; cat
= ast_category_browse(cfg
, cat
)) {
19877 /* [channels] and [trunkgroups] are used. Let's also reserve
19878 * [globals] and [general] for future use
19880 if (!strcasecmp(cat
, "general") ||
19881 !strcasecmp(cat
, "trunkgroups") ||
19882 !strcasecmp(cat
, "globals") ||
19883 !strcasecmp(cat
, "channels")) {
19887 chans
= ast_variable_retrieve(cfg
, cat
, "dahdichan");
19888 if (ast_strlen_zero(chans
)) {
19889 /* Section is useless without a dahdichan value present. */
19893 /* Copy base_conf to conf. */
19894 deep_copy_dahdi_chan_conf(conf
, base_conf
);
19896 if ((res
= process_dahdi(conf
, cat
, ast_variable_browse(cfg
, cat
), reload
, PROC_DAHDI_OPT_NOCHAN
))) {
19897 ast_mutex_unlock(&iflock
);
19898 ast_config_destroy(cfg
);
19900 ast_config_destroy(ucfg
);
19906 ast_config_destroy(cfg
);
19909 /* Reset base_conf, so things don't leak from chan_dahdi.conf */
19910 deep_copy_dahdi_chan_conf(base_conf
, default_conf
);
19911 process_dahdi(base_conf
,
19912 "" /* Must be empty for the general category. Silly voicemail mailbox. */,
19913 ast_variable_browse(ucfg
, "general"), 1, 0);
19915 for (cat
= ast_category_browse(ucfg
, NULL
); cat
; cat
= ast_category_browse(ucfg
, cat
)) {
19916 if (!strcasecmp(cat
, "general")) {
19920 chans
= ast_variable_retrieve(ucfg
, cat
, "dahdichan");
19921 if (ast_strlen_zero(chans
)) {
19922 /* Section is useless without a dahdichan value present. */
19926 /* Copy base_conf to conf. */
19927 deep_copy_dahdi_chan_conf(conf
, base_conf
);
19929 if ((res
= process_dahdi(conf
, cat
, ast_variable_browse(ucfg
, cat
), reload
, PROC_DAHDI_OPT_NOCHAN
| PROC_DAHDI_OPT_NOWARN
))) {
19930 ast_config_destroy(ucfg
);
19931 ast_mutex_unlock(&iflock
);
19935 ast_config_destroy(ucfg
);
19937 ast_mutex_unlock(&iflock
);
19942 for (x
= 0; x
< NUM_SPANS
; x
++) {
19943 if (pris
[x
].pri
.pvts
[0] &&
19944 pris
[x
].pri
.master
== AST_PTHREADT_NULL
) {
19945 prepare_pri(pris
+ x
);
19946 if (sig_pri_start_pri(&pris
[x
].pri
)) {
19947 ast_log(LOG_ERROR
, "Unable to start D-channel on span %d\n", x
+ 1);
19950 ast_verb(2, "Starting D-Channel on span %d\n", x
+ 1);
19955 #if defined(HAVE_SS7)
19958 for (x
= 0; x
< NUM_SPANS
; x
++) {
19959 if (linksets
[x
].ss7
.ss7
) {
19960 if (ast_pthread_create(&linksets
[x
].ss7
.master
, NULL
, ss7_linkset
, &linksets
[x
].ss7
)) {
19961 ast_log(LOG_ERROR
, "Unable to start SS7 linkset on span %d\n", x
+ 1);
19964 ast_verb(2, "Starting SS7 linkset on span %d\n", x
+ 1);
19968 #endif /* defined(HAVE_SS7) */
19971 struct r2link_entry
*cur
;
19973 AST_LIST_LOCK(&r2links
);
19974 AST_LIST_TRAVERSE(&r2links
, cur
, list
) {
19975 struct dahdi_mfcr2
*r2
= &cur
->mfcr2
;
19976 if (r2
->r2master
== AST_PTHREADT_NULL
) {
19977 if (ast_pthread_create(&r2
->r2master
, NULL
, mfcr2_monitor
, r2
)) {
19978 ast_log(LOG_ERROR
, "Unable to start R2 monitor on channel group %d\n", x
+ 1);
19981 ast_verb(2, "Starting R2 monitor on channel group %d\n", x
+ 1);
19986 AST_LIST_UNLOCK(&r2links
);
19989 /* And start the monitor for the first time */
19996 * \brief Setup DAHDI channel driver.
19998 * \param reload enum: load_module(0), reload(1), restart(2).
20000 * \retval 0 on success.
20001 * \retval -1 on error.
20003 static int setup_dahdi(int reload
)
20006 struct dahdi_chan_conf default_conf
= dahdi_chan_conf_default();
20007 struct dahdi_chan_conf base_conf
= dahdi_chan_conf_default();
20008 struct dahdi_chan_conf conf
= dahdi_chan_conf_default();
20010 if (default_conf
.chan
.cc_params
&& base_conf
.chan
.cc_params
&& conf
.chan
.cc_params
) {
20011 res
= setup_dahdi_int(reload
, &default_conf
, &base_conf
, &conf
);
20015 ast_cc_config_params_destroy(default_conf
.chan
.cc_params
);
20016 ast_cc_config_params_destroy(base_conf
.chan
.cc_params
);
20017 ast_cc_config_params_destroy(conf
.chan
.cc_params
);
20023 * \brief Load the module
20025 * Module loading including tests for configuration or dependencies.
20026 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20027 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20028 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20029 * configuration file or other non-critical problem return
20030 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20032 static int load_module(void)
20035 #if defined(HAVE_PRI) || defined(HAVE_SS7)
20037 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20039 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type
)) {
20040 return AST_MODULE_LOAD_DECLINE
;
20043 if (!(dahdi_tech
.capabilities
= ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT
))) {
20044 return AST_MODULE_LOAD_DECLINE
;
20046 ast_format_cap_append(dahdi_tech
.capabilities
, ast_format_slin
, 0);
20047 ast_format_cap_append(dahdi_tech
.capabilities
, ast_format_ulaw
, 0);
20048 ast_format_cap_append(dahdi_tech
.capabilities
, ast_format_alaw
, 0);
20050 if (dahdi_native_load(&dahdi_tech
)) {
20051 ao2_ref(dahdi_tech
.capabilities
, -1);
20052 return AST_MODULE_LOAD_DECLINE
;
20056 memset(pris
, 0, sizeof(pris
));
20057 for (y
= 0; y
< NUM_SPANS
; y
++) {
20058 sig_pri_init_pri(&pris
[y
].pri
);
20060 pri_set_error(dahdi_pri_error
);
20061 pri_set_message(dahdi_pri_message
);
20062 ast_register_application_xml(dahdi_send_keypad_facility_app
, dahdi_send_keypad_facility_exec
);
20063 #ifdef HAVE_PRI_PROG_W_CAUSE
20064 ast_register_application_xml(dahdi_send_callrerouting_facility_app
, dahdi_send_callrerouting_facility_exec
);
20066 #if defined(HAVE_PRI_CCSS)
20067 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks
)
20068 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks
)) {
20070 return AST_MODULE_LOAD_DECLINE
;
20072 #endif /* defined(HAVE_PRI_CCSS) */
20074 #if defined(HAVE_PRI_CCSS)
20078 #endif /* defined(HAVE_PRI_CCSS) */
20081 return AST_MODULE_LOAD_DECLINE
;
20084 #if defined(HAVE_SS7)
20085 memset(linksets
, 0, sizeof(linksets
));
20086 for (y
= 0; y
< NUM_SPANS
; y
++) {
20087 sig_ss7_init_linkset(&linksets
[y
].ss7
);
20089 ss7_set_error(dahdi_ss7_error
);
20090 ss7_set_message(dahdi_ss7_message
);
20091 ss7_set_hangup(sig_ss7_cb_hangup
);
20092 ss7_set_notinservice(sig_ss7_cb_notinservice
);
20093 ss7_set_call_null(sig_ss7_cb_call_null
);
20094 #endif /* defined(HAVE_SS7) */
20095 res
= setup_dahdi(0);
20096 /* Make sure we can register our DAHDI channel type */
20099 return AST_MODULE_LOAD_DECLINE
;
20101 if (ast_channel_register(&dahdi_tech
)) {
20102 ast_log(LOG_ERROR
, "Unable to register channel class 'DAHDI'\n");
20104 return AST_MODULE_LOAD_DECLINE
;
20107 ast_cli_register_multiple(dahdi_pri_cli
, ARRAY_LEN(dahdi_pri_cli
));
20109 #if defined(HAVE_SS7)
20110 ast_cli_register_multiple(dahdi_ss7_cli
, ARRAY_LEN(dahdi_ss7_cli
));
20111 #endif /* defined(HAVE_SS7) */
20113 ast_cli_register_multiple(dahdi_mfcr2_cli
, ARRAY_LEN(dahdi_mfcr2_cli
));
20114 ast_register_application_xml(dahdi_accept_r2_call_app
, dahdi_accept_r2_call_exec
);
20117 ast_custom_function_register(&polarity_function
);
20119 ast_cli_register_multiple(dahdi_cli
, ARRAY_LEN(dahdi_cli
));
20120 memset(round_robin
, 0, sizeof(round_robin
));
20121 ast_manager_register_xml("DAHDITransfer", 0, action_transfer
);
20122 ast_manager_register_xml("DAHDIHangup", 0, action_transferhangup
);
20123 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook
);
20124 ast_manager_register_xml("DAHDIDNDon", 0, action_dahdidndon
);
20125 ast_manager_register_xml("DAHDIDNDoff", 0, action_dahdidndoff
);
20126 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels
);
20127 ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart
);
20128 #if defined(HAVE_PRI)
20129 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans
);
20130 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set
);
20131 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM
, action_pri_debug_file_set
);
20132 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset
);
20133 #endif /* defined(HAVE_PRI) */
20135 ast_cond_init(&ss_thread_complete
, NULL
);
20140 static int dahdi_sendtext(struct ast_channel
*c
, const char *text
)
20142 #define END_SILENCE_LEN 400
20143 #define HEADER_MS 50
20144 #define TRAILER_MS 5
20145 #define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20146 #define ASCII_BYTES_PER_CHAR 80
20148 unsigned char *buf
,*mybuf
;
20149 struct dahdi_pvt
*p
= ast_channel_tech_pvt(c
);
20150 struct pollfd fds
[1];
20151 int size
,res
,fd
,len
,x
;
20156 * Initial carrier (imaginary)
20158 * Note: The following float variables are used by the
20159 * PUT_CLID_MARKMS and PUT_CLID() macros.
20166 return(0); /* if nothing to send, don't */
20168 idx
= dahdi_get_index(c
, p
, 0);
20170 ast_log(LOG_WARNING
, "Huh? I don't exist?\n");
20173 if ((!p
->tdd
) && (!p
->mate
)) {
20174 #if defined(HAVE_PRI)
20175 #if defined(HAVE_PRI_DISPLAY_TEXT)
20176 ast_mutex_lock(&p
->lock
);
20177 if (dahdi_sig_pri_lib_handles(p
->sig
)) {
20178 sig_pri_sendtext(p
->sig_pvt
, text
);
20180 ast_mutex_unlock(&p
->lock
);
20181 #endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20182 #endif /* defined(HAVE_PRI) */
20183 return(0); /* if not in TDD mode, just return */
20186 buf
= ast_malloc(((strlen(text
) + 1) * ASCII_BYTES_PER_CHAR
) + END_SILENCE_LEN
+ HEADER_LEN
);
20188 buf
= ast_malloc(((strlen(text
) + 1) * TDD_BYTES_PER_CHAR
) + END_SILENCE_LEN
);
20193 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20194 struct ast_format
*codec
= AST_LAW(p
);
20196 for (x
= 0; x
< HEADER_MS
; x
++) { /* 50 ms of Mark */
20199 /* Put actual message */
20200 for (x
= 0; text
[x
]; x
++) {
20203 for (x
= 0; x
< TRAILER_MS
; x
++) { /* 5 ms of Mark */
20209 len
= tdd_generate(p
->tdd
, buf
, text
);
20211 ast_log(LOG_ERROR
, "TDD generate (len %d) failed!!\n", (int)strlen(text
));
20216 memset(buf
+ len
, 0x7f, END_SILENCE_LEN
);
20217 len
+= END_SILENCE_LEN
;
20218 fd
= p
->subs
[idx
].dfd
;
20220 if (ast_check_hangup(c
)) {
20225 if (size
> READ_SIZE
)
20228 fds
[0].events
= POLLOUT
| POLLPRI
;
20229 fds
[0].revents
= 0;
20230 res
= poll(fds
, 1, -1);
20232 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p
->channel
);
20235 /* if got exception */
20236 if (fds
[0].revents
& POLLPRI
) {
20240 if (!(fds
[0].revents
& POLLOUT
)) {
20241 ast_debug(1, "write fd not ready on channel %d\n", p
->channel
);
20244 res
= write(fd
, buf
, size
);
20250 ast_debug(1, "Write returned %d (%s) on channel %d\n", res
, strerror(errno
), p
->channel
);
20261 static int reload(void)
20265 res
= setup_dahdi(1);
20267 ast_log(LOG_WARNING
, "Reload of chan_dahdi.so is unsuccessful!\n");
20273 /* This is a workaround so that menuselect displays a proper description
20274 * AST_MODULE_INFO(, , "DAHDI Telephony"
20277 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_LOAD_ORDER
, tdesc
,
20278 .support_level
= AST_MODULE_SUPPORT_CORE
,
20279 .load
= load_module
,
20280 .unload
= unload_module
,
20282 .load_pri
= AST_MODPRI_CHANNEL_DRIVER
,
20283 .requires
= "ccss",
20284 .optional_modules
= "res_smdi",