Asterisk - The Open Source Telephony Project GIT-master-27fb039
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
chan_dahdi.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2008, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief DAHDI for Pseudo TDM
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
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.
28 *
29 * You need to install libraries before you attempt to compile
30 * and install the DAHDI channel.
31 *
32 * \ingroup channel_drivers
33 *
34 * \todo Deprecate the "musiconhold" configuration option post 1.4
35 */
36
37/*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
38 * \addtogroup configuration_file
39 */
40
41/*! \page chan_dahdi.conf chan_dahdi.conf
42 * \verbinclude chan_dahdi.conf.sample
43 */
44
45/*** MODULEINFO
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>
53 ***/
54
55#include "asterisk.h"
56
57#if defined(__NetBSD__) || defined(__FreeBSD__)
58#include <pthread.h>
59#else
60#include <sys/sysmacros.h>
61#endif
62#include <signal.h>
63#include <sys/stat.h>
64#include <math.h>
65
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.
71 */
72
73#if defined(HAVE_PRI)
74#include "sig_pri.h"
75#ifndef PRI_RESTART
76#error "Upgrade your libpri"
77#endif
78#endif /* defined(HAVE_PRI) */
79
80#if defined(HAVE_SS7)
81#include "sig_ss7.h"
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"
86#endif
87#endif /* defined(HAVE_SS7) */
88
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) */
93
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"
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"
125#include "asterisk/bridge.h"
127#include "asterisk/parking.h"
129#include "chan_dahdi.h"
131
132/*** DOCUMENTATION
133 <application name="DAHDISendKeypadFacility" language="en_US">
134 <since>
135 <version>1.4.22</version>
136 </since>
137 <synopsis>
138 Send digits out of band over a PRI.
139 </synopsis>
140 <syntax>
141 <parameter name="digits" required="true" />
142 </syntax>
143 <description>
144 <para>This application will send the given string of digits in a Keypad
145 Facility IE over the current channel.</para>
146 </description>
147 </application>
148 <application name="DAHDISendCallreroutingFacility" language="en_US">
149 <since>
150 <version>1.6.2.0</version>
151 </since>
152 <synopsis>
153 Send an ISDN call rerouting/deflection facility message.
154 </synopsis>
155 <syntax argsep=",">
156 <parameter name="destination" required="true">
157 <para>Destination number.</para>
158 </parameter>
159 <parameter name="original">
160 <para>Original called number.</para>
161 </parameter>
162 <parameter name="reason">
163 <para>Diversion reason, if not specified defaults to <literal>unknown</literal></para>
164 </parameter>
165 </syntax>
166 <description>
167 <para>This application will send an ISDN switch specific call
168 rerouting/deflection facility message over the current channel.
169 Supported switches depend upon the version of libpri in use.</para>
170 </description>
171 </application>
172 <application name="DAHDIAcceptR2Call" language="en_US">
173 <since>
174 <version>1.6.1.0</version>
175 </since>
176 <synopsis>
177 Accept an R2 call if its not already accepted (you still need to answer it)
178 </synopsis>
179 <syntax>
180 <parameter name="charge" required="true">
181 <para>Yes or No.</para>
182 <para>Whether you want to accept the call with charge or without charge.</para>
183 </parameter>
184 </syntax>
185 <description>
186 <para>This application will Accept the R2 call either with charge or no charge.</para>
187 </description>
188 </application>
189 <function name="POLARITY" language="en_US">
190 <since>
191 <version>16.28.0</version>
192 <version>18.14.0</version>
193 <version>19.6.0</version>
194 </since>
195 <synopsis>
196 Set or get the polarity of a DAHDI channel.
197 </synopsis>
198 <syntax />
199 <description>
200 <para>The POLARITY function can be used to set the polarity of a DAHDI channel.</para>
201 <para>Applies only to FXS channels (using FXO signalling) with supporting hardware.</para>
202 <para>The polarity can be set to the following numeric or named values:</para>
203 <enumlist>
204 <enum name="0" />
205 <enum name="idle" />
206 <enum name="1" />
207 <enum name="reverse" />
208 </enumlist>
209 <para>However, when read, the function will always return 0 or 1.</para>
210 <example title="Set idle polarity">
211 same => n,Set(POLARITY()=0)
212 </example>
213 <example title="Set reverse polarity">
214 same => n,NoOp(Current Polarity: ${POLARITY()})
215 same => n,Set(POLARITY()=reverse)
216 same => n,NoOp(New Polarity: ${POLARITY()})
217 </example>
218 <example title="Reverse the polarity from whatever it is currently">
219 same => n,Set(POLARITY()=${IF($[ "${POLARITY()}" = "1" ]?0:1)})
220 </example>
221 </description>
222 </function>
223 <function name="DAHDI_CHANNEL" language="en_US">
224 <synopsis>
225 Set or get a property of a DAHDI channel.
226 </synopsis>
227 <syntax>
228 <parameter name="property" required="true">
229 <para>The property to set or get.</para>
230 <enumlist>
231 <enum name="owner">
232 <para>R/O The name of the active channel on this DAHDI device.</para>
233 </enum>
234 <enum name="callwait">
235 <para>R/O The name of the call waiting channel on this DAHDI device.</para>
236 </enum>
237 <enum name="threeway">
238 <para>R/O The name of the three-way channel on this DAHDI device.</para>
239 </enum>
240 <enum name="polarity">
241 <para>R/W The polarity of the channel (0 or 1, idle or reverse can also be used for setting).</para>
242 <para>Only valid on FXO-signalled channels.</para>
243 </enum>
244 <enum name="dnd">
245 <para>R/W Whether Do Not Disturb is active.</para>
246 <para>Only valid on FXO-signalled channels.</para>
247 </enum>
248 <enum name="callforward">
249 <para>R/W The call forwarding target number.</para>
250 <para>Only valid on FXO-signalled channels.</para>
251 </enum>
252 <enum name="lastexten">
253 <para>R/W The last number dialed.</para>
254 <para>Only valid on FXO-signalled channels.</para>
255 </enum>
256 </enumlist>
257 </parameter>
258 <parameter name="channel" required="false">
259 <para>The DAHDI channel number.</para>
260 <para>If not specified, the DAHDI channel number of the current channel
261 will be used (in which case it must be a DAHDI channel).</para>
262 </parameter>
263 </syntax>
264 <description>
265 <para>The DAHDI_CHANNEL function can be used to set or get properties of DAHDI channels
266 that are not specific to Asterisk channels.</para>
267 <para>This function may also be called from non-DAHDI channels.</para>
268 <example title="Set reverse polarity on current DAHDI channel">
269 same => n,Set(DAHDI_CHANNEL(polarity)=1)
270 same => n,NoOp(${DAHDI_CHANNEL(polarity)})
271 </example>
272 <example title="Set call forwarding target for channel 1">
273 same => n,Set(DAHDI_CHANNEL(callforwardnumber,1)=5552368)
274 same => n,NoOp(Calls now forwarding to ${DAHDI_CHANNEL(callforwardnumber,1)})
275 </example>
276 </description>
277 </function>
278 <info name="CHANNEL" language="en_US" tech="DAHDI">
279 <enumlist>
280 <enum name="dahdi_channel">
281 <para>R/O DAHDI channel related to this channel.</para>
282 </enum>
283 <enum name="dahdi_span">
284 <para>R/O DAHDI span related to this channel.</para>
285 </enum>
286 <enum name="dahdi_group">
287 <para>R/O DAHDI logical group related to this channel.</para>
288 </enum>
289 <enum name="dahdi_type">
290 <para>R/O DAHDI channel type, one of:</para>
291 <enumlist>
292 <enum name="analog" />
293 <enum name="mfc/r2" />
294 <enum name="pri" />
295 <enum name="pseudo" />
296 <enum name="ss7" />
297 </enumlist>
298 </enum>
299 <enum name="keypad_digits">
300 <para>R/O PRI Keypad digits that came in with the SETUP message.</para>
301 </enum>
302 <enum name="reversecharge">
303 <para>R/O PRI Reverse Charging Indication, one of:</para>
304 <enumlist>
305 <enum name="-1"> <para>None</para></enum>
306 <enum name=" 1"> <para>Reverse Charging Requested</para></enum>
307 </enumlist>
308 </enum>
309 <enum name="no_media_path">
310 <para>R/O PRI Nonzero if the channel has no B channel.
311 The channel is either on hold or a call waiting call.</para>
312 </enum>
313 <enum name="buffers">
314 <para>W/O Change the channel's buffer policy (for the current call only)</para>
315 <para>This option takes two arguments:</para>
316 <para> Number of buffers,</para>
317 <para> Buffer policy being one of:</para>
318 <para> <literal>full</literal></para>
319 <para> <literal>immediate</literal></para>
320 <para> <literal>half</literal></para>
321 </enum>
322 <enum name="echocan_mode">
323 <para>W/O Change the configuration of the active echo
324 canceller on the channel (if any), for the current call
325 only.</para>
326 <para>Possible values are:</para>
327 <para> <literal>on</literal> Normal mode (the echo canceller is actually reinitialized)</para>
328 <para> <literal>off</literal> Disabled</para>
329 <para> <literal>fax</literal> FAX/data mode (NLP disabled if possible, otherwise
330 completely disabled)</para>
331 <para> <literal>voice</literal> Voice mode (returns from FAX mode, reverting the changes that were made)</para>
332 </enum>
333 <enum name="dialmode">
334 <para>R/W Pulse and tone dialing mode of the channel.</para>
335 <para>Disabling tone dialing using this option will not automatically disable the DSP used for DTMF detection.
336 To do that, also set the <literal>digitdetect</literal> option. If digit detection is disabled,
337 DTMF will not be detected, regardless of the <literal>dialmode</literal> setting.
338 The <literal>digitdetect</literal> setting has no impact on pulse dialing detection.</para>
339 <para>If set, overrides the setting in <literal>chan_dahdi.conf</literal> for that channel.</para>
340 <para>The <literal>dialmode</literal> setting applies to the DAHDI channel as a whole, but is reset for each call,
341 so modifications made using the <literal>CHANNEL</literal> function apply temporarily per-call.
342 The <literal>digitdetect</literal> setting applies to the entire DAHDI channel,
343 so any changes made to this setting will affect all calls concurrently on the same DAHDI channel.
344 <literal>digitdetect</literal> is reset once all calls on the line have cleared.</para>
345 <enumlist>
346 <enum name="both" />
347 <enum name="pulse" />
348 <enum name="dtmf" />
349 <enum name="tone" />
350 <enum name="none" />
351 </enumlist>
352 </enum>
353 <enum name="waitfordialtone">
354 <para>W/O Duration in ms for which to wait for dial tone on the current call.</para>
355 <para>This setting is will temporarily override the <literal>waitfordialtone</literal>
356 setting in <literal>chan_dahdi.conf</literal> (typically if that setting is disabled).
357 You must call this in a pre-dial handler when making a call on an analog trunk
358 (e.g. FXS-signalled interface).</para>
359 <para>This allows, for example, being able to barge in on an in-use trunk,
360 if dialed specifically, but allows skipping the trunk when routing calls
361 if dial tone is not present on a channel.</para>
362 <para>This setting will only apply to the current (next) call made on the
363 DAHDI channel, and will not persist for future calls.</para>
364 <para>Please keep in mind that due to the way that chan_dahdi implements dial tone detection,
365 DTMF digits on an in-use channel will temporarily relay to any other channels attempting to use the channel for a call.
366 However, voice transmission will not leak.</para>
367 </enum>
368 </enumlist>
369 </info>
370 <info name="Dial_Resource" language="en_US" tech="DAHDI">
371 <para>DAHDI allows several modifiers to be specified as part of the resource.</para>
372 <para>The general syntax is :</para>
373 <para><literal>Dial(DAHDI/pseudo[/extension])</literal></para>
374 <para><literal>Dial(DAHDI/&lt;channel#&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
375 <para><literal>Dial(DAHDI/(g|G|r|R)&lt;group#(0-63)&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
376 <para>The following modifiers may be used before the channel number:</para>
377 <enumlist>
378 <enum name="g">
379 <para>Search forward, dialing on first available channel in group (lowest to highest).</para>
380 </enum>
381 <enum name="G">
382 <para>Search backward, dialing on first available channel in group (highest to lowest).</para>
383 </enum>
384 <enum name="r">
385 <para>Round robin search forward, picking up from where last left off (lowest to highest).</para>
386 </enum>
387 <enum name="R">
388 <para>Round robin search backward, picking up from where last left off (highest to lowest).</para>
389 </enum>
390 </enumlist>
391 <para>The following modifiers may be used after the channel number:</para>
392 <enumlist>
393 <enum name="c">
394 <para>Wait for DTMF digit <literal>#</literal> before providing answer supervision.</para>
395 <para>This can be useful on outbound calls via FXO ports, as otherwise
396 they would indicate answer immediately.</para>
397 </enum>
398 <enum name="d">
399 <para>Force bearer capability for ISDN/SS7 call to digital.</para>
400 </enum>
401 <enum name="i">
402 <para>ISDN span channel restriction.</para>
403 <para>Used by CC to ensure that the CC recall goes out the same span.
404 Also to make ISDN channel names dialable when the sequence number
405 is stripped off. (Used by DTMF attended transfer feature.)</para>
406 </enum>
407 <enum name="r">
408 <para>Specifies the distinctive ring cadence number to use immediately after
409 specifying this option. There are 4 default built-in cadences, and up to 24
410 total cadences may be configured.</para>
411 </enum>
412 </enumlist>
413 <example title="Dial 555-1212 on first available channel in group 1, searching from highest to lowest">
414 same => n,Dial(DAHDI/g1/5551212)
415 </example>
416 <example title="Ringing FXS channel 4 with ring cadence 2">
417 same => n,Dial(DAHDI/4r2)
418 </example>
419 <example title="Dial 555-1212 on channel 3 and require answer confirmation">
420 same => n,Dial(DAHDI/3c/5551212)
421 </example>
422 </info>
423 <manager name="DAHDITransfer" language="en_US">
424 <since>
425 <version>1.4.22</version>
426 </since>
427 <synopsis>
428 Transfer DAHDI Channel.
429 </synopsis>
430 <syntax>
431 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
432 <parameter name="DAHDIChannel" required="true">
433 <para>DAHDI channel number to transfer.</para>
434 </parameter>
435 </syntax>
436 <description>
437 <para>Simulate a flash hook event by the user connected to the channel.</para>
438 <note><para>Valid only for analog channels.</para></note>
439 </description>
440 </manager>
441 <manager name="DAHDIHangup" language="en_US">
442 <since>
443 <version>1.4.22</version>
444 </since>
445 <synopsis>
446 Hangup DAHDI Channel.
447 </synopsis>
448 <syntax>
449 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
450 <parameter name="DAHDIChannel" required="true">
451 <para>DAHDI channel number to hangup.</para>
452 </parameter>
453 </syntax>
454 <description>
455 <para>Simulate an on-hook event by the user connected to the channel.</para>
456 <note><para>Valid only for analog channels.</para></note>
457 </description>
458 </manager>
459 <manager name="DAHDIDialOffhook" language="en_US">
460 <since>
461 <version>1.4.22</version>
462 </since>
463 <synopsis>
464 Dial over DAHDI channel while offhook.
465 </synopsis>
466 <syntax>
467 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
468 <parameter name="DAHDIChannel" required="true">
469 <para>DAHDI channel number to dial digits.</para>
470 </parameter>
471 <parameter name="Number" required="true">
472 <para>Digits to dial.</para>
473 </parameter>
474 </syntax>
475 <description>
476 <para>Generate DTMF control frames to the bridged peer.</para>
477 </description>
478 </manager>
479 <manager name="DAHDIDNDon" language="en_US">
480 <since>
481 <version>1.4.22</version>
482 </since>
483 <synopsis>
484 Toggle DAHDI channel Do Not Disturb status ON.
485 </synopsis>
486 <syntax>
487 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
488 <parameter name="DAHDIChannel" required="true">
489 <para>DAHDI channel number to set DND on.</para>
490 </parameter>
491 </syntax>
492 <description>
493 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> on".</para>
494 <note><para>Feature only supported by analog channels.</para></note>
495 </description>
496 </manager>
497 <manager name="DAHDIDNDoff" language="en_US">
498 <since>
499 <version>1.4.22</version>
500 </since>
501 <synopsis>
502 Toggle DAHDI channel Do Not Disturb status OFF.
503 </synopsis>
504 <syntax>
505 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
506 <parameter name="DAHDIChannel" required="true">
507 <para>DAHDI channel number to set DND off.</para>
508 </parameter>
509 </syntax>
510 <description>
511 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> off".</para>
512 <note><para>Feature only supported by analog channels.</para></note>
513 </description>
514 </manager>
515 <manager name="DAHDIShowChannels" language="en_US">
516 <since>
517 <version>1.4.22</version>
518 </since>
519 <synopsis>
520 Show status of DAHDI channels.
521 </synopsis>
522 <syntax>
523 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
524 <parameter name="DAHDIChannel">
525 <para>Specify the specific channel number to show. Show all channels if zero or not present.</para>
526 </parameter>
527 </syntax>
528 <description>
529 <para>Similar to the CLI command "dahdi show channels".</para>
530 </description>
531 </manager>
532 <manager name="DAHDIShowStatus" language="en_US">
533 <since>
534 <version>21.3.0</version>
535 <version>20.8.0</version>
536 <version>18.23.0</version>
537 </since>
538 <synopsis>
539 Show status of DAHDI spans.
540 </synopsis>
541 <syntax/>
542 <description>
543 <para>Similar to the CLI command "dahdi show status".</para>
544 </description>
545 </manager>
546 <manager name="DAHDIRestart" language="en_US">
547 <since>
548 <version>1.4.22</version>
549 </since>
550 <synopsis>
551 Fully Restart DAHDI channels (terminates calls).
552 </synopsis>
553 <syntax>
554 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
555 </syntax>
556 <description>
557 <para>Equivalent to the CLI command "dahdi restart".</para>
558 </description>
559 </manager>
560 <manager name="PRIShowSpans" language="en_US">
561 <since>
562 <version>10.0.0</version>
563 </since>
564 <synopsis>
565 Show status of PRI spans.
566 </synopsis>
567 <syntax>
568 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
569 <parameter name="Span">
570 <para>Specify the specific span to show. Show all spans if zero or not present.</para>
571 </parameter>
572 </syntax>
573 <description>
574 <para>Similar to the CLI command "pri show spans".</para>
575 </description>
576 </manager>
577 <manager name="PRIDebugSet" language="en_US">
578 <since>
579 <version>13.0.0</version>
580 </since>
581 <synopsis>
582 Set PRI debug levels for a span
583 </synopsis>
584 <syntax>
585 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
586 <parameter name="Span" required="true">
587 <para>Which span to affect.</para>
588 </parameter>
589 <parameter name="Level" required="true">
590 <para>What debug level to set. May be a numerical value or a text value from the list below</para>
591 <enumlist>
592 <enum name="off" />
593 <enum name="on" />
594 <enum name="hex" />
595 <enum name="intense" />
596 </enumlist>
597 </parameter>
598 </syntax>
599 <description>
600 <para>Equivalent to the CLI command "pri set debug &lt;level&gt; span &lt;span&gt;".</para>
601 </description>
602 </manager>
603 <manager name="PRIDebugFileSet" language="en_US">
604 <since>
605 <version>13.0.0</version>
606 </since>
607 <synopsis>
608 Set the file used for PRI debug message output
609 </synopsis>
610 <syntax>
611 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
612 <parameter name="File" required="true">
613 <para>Path of file to write debug output.</para>
614 </parameter>
615 </syntax>
616 <description>
617 <para>Equivalent to the CLI command "pri set debug file &lt;output-file&gt;"</para>
618 </description>
619 </manager>
620 <manager name="PRIDebugFileUnset" language="en_US">
621 <since>
622 <version>13.0.0</version>
623 </since>
624 <synopsis>
625 Disables file output for PRI debug messages
626 </synopsis>
627 <syntax>
628 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
629 </syntax>
630 </manager>
631 <managerEvent language="en_US" name="AlarmClear">
632 <managerEventInstance class="EVENT_FLAG_SYSTEM">
633 <since>
634 <version>12.0.0</version>
635 </since>
636 <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
637 <syntax>
638 <parameter name="DAHDIChannel">
639 <para>The DAHDI channel on which the alarm was cleared.</para>
640 <note><para>This is not an Asterisk channel identifier.</para></note>
641 </parameter>
642 </syntax>
643 </managerEventInstance>
644 </managerEvent>
645 <managerEvent language="en_US" name="SpanAlarmClear">
646 <managerEventInstance class="EVENT_FLAG_SYSTEM">
647 <since>
648 <version>12.0.0</version>
649 </since>
650 <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
651 <syntax>
652 <parameter name="Span">
653 <para>The span on which the alarm was cleared.</para>
654 </parameter>
655 </syntax>
656 </managerEventInstance>
657 </managerEvent>
658 <managerEvent language="en_US" name="DNDState">
659 <managerEventInstance class="EVENT_FLAG_SYSTEM">
660 <since>
661 <version>12.0.0</version>
662 </since>
663 <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
664 <syntax>
665 <parameter name="DAHDIChannel">
666 <para>The DAHDI channel on which DND status changed.</para>
667 <note><para>This is not an Asterisk channel identifier.</para></note>
668 </parameter>
669 <parameter name="Status">
670 <enumlist>
671 <enum name="enabled"/>
672 <enum name="disabled"/>
673 </enumlist>
674 </parameter>
675 </syntax>
676 </managerEventInstance>
677 </managerEvent>
678 <managerEvent language="en_US" name="Alarm">
679 <managerEventInstance class="EVENT_FLAG_SYSTEM">
680 <since>
681 <version>12.0.0</version>
682 </since>
683 <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
684 <syntax>
685 <parameter name="DAHDIChannel">
686 <para>The channel on which the alarm occurred.</para>
687 <note><para>This is not an Asterisk channel identifier.</para></note>
688 </parameter>
689 <parameter name="Alarm">
690 <para>A textual description of the alarm that occurred.</para>
691 </parameter>
692 </syntax>
693 </managerEventInstance>
694 </managerEvent>
695 <managerEvent language="en_US" name="SpanAlarm">
696 <managerEventInstance class="EVENT_FLAG_SYSTEM">
697 <since>
698 <version>12.0.0</version>
699 </since>
700 <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
701 <syntax>
702 <parameter name="Span">
703 <para>The span on which the alarm occurred.</para>
704 </parameter>
705 <parameter name="Alarm">
706 <para>A textual description of the alarm that occurred.</para>
707 </parameter>
708 </syntax>
709 </managerEventInstance>
710 </managerEvent>
711 <managerEvent language="en_US" name="DAHDIChannel">
712 <managerEventInstance class="EVENT_FLAG_CALL">
713 <since>
714 <version>12.0.0</version>
715 </since>
716 <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
717 <syntax>
718 <channel_snapshot/>
719 <parameter name="DAHDIGroup">
720 <para>The DAHDI logical group associated with this channel.</para>
721 </parameter>
722 <parameter name="DAHDISpan">
723 <para>The DAHDI span associated with this channel.</para>
724 </parameter>
725 <parameter name="DAHDIChannel">
726 <para>The DAHDI channel associated with this channel.</para>
727 </parameter>
728 </syntax>
729 </managerEventInstance>
730 </managerEvent>
731 ***/
732
733#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
734
735static const char * const lbostr[] = {
736"0 db (CSU)/0-133 feet (DSX-1)",
737"133-266 feet (DSX-1)",
738"266-399 feet (DSX-1)",
739"399-533 feet (DSX-1)",
740"533-655 feet (DSX-1)",
741"-7.5db (CSU)",
742"-15db (CSU)",
743"-22.5db (CSU)"
744};
745
746/*! Global jitterbuffer configuration - by default, jb is disabled
747 * \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
749{
750 .flags = 0,
751 .max_size = 200,
752 .resync_threshold = 1000,
753 .impl = "fixed",
754 .target_extra = 40,
755};
757
758/*!
759 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
760 * the user hangs up to reset the state machine so ring works properly.
761 * This is used to be able to support kewlstart by putting the zhone in
762 * groundstart mode since their forward disconnect supervision is entirely
763 * broken even though their documentation says it isn't and their support
764 * is entirely unwilling to provide any assistance with their channel banks
765 * even though their web site says they support their products for life.
766 */
767/* #define ZHONE_HACK */
768
769/*! \brief Typically, how many rings before we should send Caller*ID */
770#define DEFAULT_CIDRINGS 1
771
772#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
773
774
775/*! \brief Signaling types that need to use MF detection should be placed in this macro */
776#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))
777
778static const char tdesc[] = "DAHDI Telephony"
779#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
780 " w/"
781 #if defined(HAVE_PRI)
782 "PRI"
783 #endif /* defined(HAVE_PRI) */
784 #if defined(HAVE_SS7)
785 #if defined(HAVE_PRI)
786 " & "
787 #endif /* defined(HAVE_PRI) */
788 "SS7"
789 #endif /* defined(HAVE_SS7) */
790 #if defined(HAVE_OPENR2)
791 #if defined(HAVE_PRI) || defined(HAVE_SS7)
792 " & "
793 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
794 "MFC/R2"
795 #endif /* defined(HAVE_OPENR2) */
796#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2) */
797;
798
799static const char config[] = "chan_dahdi.conf";
800
801#ifdef LOTS_OF_SPANS
802#define NUM_SPANS DAHDI_MAX_SPANS
803#else
804#define NUM_SPANS 32
805#endif
806
807#define CHAN_PSEUDO -2
808
809#define CALLPROGRESS_PROGRESS 1
810#define CALLPROGRESS_FAX_OUTGOING 2
811#define CALLPROGRESS_FAX_INCOMING 4
812#define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
813
814#define NUM_CADENCE_MAX 25
815static int num_cadence = 4;
817
818static int has_pseudo;
819
820static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
821 { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
822 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
823 { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
824 { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
825};
826
827/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
828 * is 1, the second pause is 2 and so on.
829 */
830
832 2, /*!< Right after first long ring */
833 4, /*!< Right after long part */
834 3, /*!< After third chirp */
835 2, /*!< Second spell */
836};
837
838/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
839static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
840
841#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
842 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
843
844#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
845#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
846
847static char defaultcic[64] = "";
848static char defaultozz[64] = "";
849
850/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
851static char mwimonitornotify[PATH_MAX] = "";
852#ifndef HAVE_DAHDI_LINEREVERSE_VMWI
853static int mwisend_rpas = 0;
854#endif
855
856static char progzone[10] = "";
857
860
861static int numbufs = 4;
862
863static int mwilevel = 512;
864static int dtmfcid_level = 256;
865
866#define REPORT_CHANNEL_ALARMS 1
867#define REPORT_SPAN_ALARMS 2
869
870#ifdef HAVE_PRI
871static int pridebugfd = -1;
872static char pridebugfilename[1024] = "";
873#endif
874
875/*! \brief Protect the interface list (of dahdi_pvt's) */
877
878
879static int ifcount = 0;
880
881#ifdef HAVE_PRI
882AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
883#endif
884
885/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
886 when it's doing something critical. */
888
889/*! \brief This is the thread for the monitor which checks for input on the channels
890 which are not currently in use. */
895static int ss_thread_count = 0;
896static int num_restart_pending = 0;
897
898static int restart_monitor(void);
899
900static int dahdi_sendtext(struct ast_channel *c, const char *text);
901
902/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
903static inline int dahdi_get_event(int fd)
904{
905 int j;
906 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
907 return -1;
908 return j;
909}
910
911/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
912static inline int dahdi_wait_event(int fd)
913{
914 int i, j = 0;
915 i = DAHDI_IOMUX_SIGEVENT;
916 if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
917 return -1;
918 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
919 return -1;
920 return j;
921}
922
923/*! Chunk size to read -- we use 20ms chunks to make things happy. */
924#define READ_SIZE 160
925
926#define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
927#define MASK_INUSE (1 << 1) /*!< Channel currently in use */
928
929#define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE) /*!< 300 ms */
930#define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
931#define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE) /*!< 100 ms */
932#define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE) /*!< 500 ms */
933#define MIN_MS_SINCE_FLASH ((2000) ) /*!< 2000 ms */
934#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
935#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
936
937/*!
938 * \brief Configured ring timeout base.
939 * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
940 */
942
943#if defined(HAVE_SS7)
944
945struct dahdi_ss7 {
946 struct sig_ss7_linkset ss7;
947};
948
949static struct dahdi_ss7 linksets[NUM_SPANS];
950
951static int cur_ss7type = -1;
952static int cur_slc = -1;
953static int cur_linkset = -1;
954static int cur_pointcode = -1;
955static int cur_cicbeginswith = -1;
956static int cur_adjpointcode = -1;
957static int cur_networkindicator = -1;
958static int cur_defaultdpc = -1;
959#endif /* defined(HAVE_SS7) */
960
961#ifdef HAVE_OPENR2
962struct dahdi_mfcr2_conf {
963 openr2_variant_t variant;
964 int mfback_timeout;
965 int metering_pulse_timeout;
966 int max_ani;
967 int max_dnis;
968#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
969 int dtmf_time_on;
970 int dtmf_time_off;
971#endif
972#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
973 int dtmf_end_timeout;
974#endif
975 signed int get_ani_first:2;
976#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
977 signed int skip_category_request:2;
978#endif
979 unsigned int call_files:1;
980 unsigned int allow_collect_calls:1;
981 unsigned int charge_calls:1;
982 unsigned int accept_on_offer:1;
983 unsigned int forced_release:1;
984 unsigned int double_answer:1;
985 signed int immediate_accept:2;
986#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
987 signed int dtmf_dialing:2;
988 signed int dtmf_detection:2;
989#endif
990 char logdir[OR2_MAX_PATH];
991 char r2proto_file[OR2_MAX_PATH];
992 openr2_log_level_t loglevel;
993 openr2_calling_party_category_t category;
994};
995
996/* MFC-R2 pseudo-link structure */
997struct dahdi_mfcr2 {
998 int index; /*!< Unique index for CLI */
999 pthread_t r2master; /*!< Thread of master */
1000 openr2_context_t *protocol_context; /*!< OpenR2 context handle */
1001 struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
1002 int numchans; /*!< Number of channels in this R2 block */
1003 int live_chans; /*!< Number of unremoved channels in this R2 block */
1004 int nodev; /*!< Link disconnected? */
1005 struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
1006};
1007
1008struct r2link_entry {
1009 struct dahdi_mfcr2 mfcr2;
1010 AST_LIST_ENTRY(r2link_entry) list;
1011};
1012static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
1013static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
1014
1015
1016/* how many r2links have been malloc'd */
1017static int r2links_count = 0;
1018
1019#endif /* HAVE_OPENR2 */
1020
1021#ifdef HAVE_PRI
1022
1023struct dahdi_pri {
1024 int dchannels[SIG_PRI_NUM_DCHANS]; /*!< What channel are the dchannels on */
1025 int mastertrunkgroup; /*!< What trunk group is our master */
1026 int prilogicalspan; /*!< Logical span number within trunk group */
1027 struct sig_pri_span pri;
1028};
1029
1030static struct dahdi_pri pris[NUM_SPANS];
1031
1032#if defined(HAVE_PRI_CCSS)
1033/*! DAHDI PRI CCSS agent and monitor type name. */
1034static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
1035#endif /* defined(HAVE_PRI_CCSS) */
1036
1037#else
1038/*! Shut up the compiler */
1039struct dahdi_pri;
1040#endif
1041
1042/* Polarity states */
1043#define POLARITY_IDLE 0
1044#define POLARITY_REV 1
1045
1046const char * const subnames[] = {
1047 "Real",
1048 "Callwait",
1049 "Threeway"
1050};
1051
1052static struct dahdi_pvt *iflist = NULL; /*!< Main interface list start */
1053static struct dahdi_pvt *ifend = NULL; /*!< Main interface list end */
1054
1055#if defined(HAVE_PRI)
1056struct doomed_pri {
1057 struct sig_pri_span *pri;
1058 AST_LIST_ENTRY(doomed_pri) list;
1059};
1060static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);
1061
1062static void pri_destroy_span(struct sig_pri_span *pri);
1063
1064static struct dahdi_parms_pseudo {
1065 int buf_no; /*!< Number of buffers */
1066 int buf_policy; /*!< Buffer policy */
1067 int faxbuf_no; /*!< Number of Fax buffers */
1068 int faxbuf_policy; /*!< Fax buffer policy */
1069} dahdi_pseudo_parms;
1070#endif /* defined(HAVE_PRI) */
1071
1072/*! \brief Channel configuration from chan_dahdi.conf .
1073 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
1074 * Generally there is a field here for every possible configuration item.
1075 *
1076 * The state of fields is saved along the parsing and whenever a 'channel'
1077 * statement is reached, the current dahdi_chan_conf is used to configure the
1078 * channel (struct dahdi_pvt)
1079 *
1080 * \see dahdi_chan_init for the default values.
1081 */
1084#ifdef HAVE_PRI
1085 struct dahdi_pri pri;
1086#endif
1087
1088#if defined(HAVE_SS7)
1089 struct dahdi_ss7 ss7;
1090#endif /* defined(HAVE_SS7) */
1091
1092#ifdef HAVE_OPENR2
1093 struct dahdi_mfcr2_conf mfcr2;
1094#endif
1095 struct dahdi_params timing;
1096 int is_sig_auto; /*!< Use channel signalling from DAHDI? */
1097 /*! Continue configuration even if a channel is not there. */
1099
1100 /*!
1101 * \brief The serial port to listen for SMDI data on
1102 * \note Set from the "smdiport" string read in from chan_dahdi.conf
1103 */
1105
1106 /*!
1107 * \brief Don't create channels below this number
1108 * \note by default is 0 (no limit)
1109 */
1111
1112 /*!
1113 * \brief Don't create channels above this number (infinity by default)
1114 * \note by default is 0 (special value that means "no limit").
1115 */
1117};
1118
1119/*! returns a new dahdi_chan_conf with default values (by-value) */
1121{
1122 /* recall that if a field is not included here it is initialized
1123 * to 0 or equivalent
1124 */
1125 struct dahdi_chan_conf conf = {
1126#ifdef HAVE_PRI
1127 .pri.pri = {
1128 .nsf = PRI_NSF_NONE,
1129 .switchtype = PRI_SWITCH_NI2,
1130 .dialplan = PRI_UNKNOWN + 1,
1131 .localdialplan = PRI_NATIONAL_ISDN + 1,
1132 .nodetype = PRI_CPE,
1133 .qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
1134
1135#if defined(HAVE_PRI_CCSS)
1136 .cc_ptmp_recall_mode = 1,/* specificRecall */
1137 .cc_qsig_signaling_link_req = 1,/* retain */
1138 .cc_qsig_signaling_link_rsp = 1,/* retain */
1139#endif /* defined(HAVE_PRI_CCSS) */
1140
1141 .minunused = 2,
1142 .idleext = "",
1143 .idledial = "",
1144 .internationalprefix = "",
1145 .nationalprefix = "",
1146 .localprefix = "",
1147 .privateprefix = "",
1148 .unknownprefix = "",
1149 .colp_send = SIG_PRI_COLP_UPDATE,
1150 .resetinterval = -1,
1151 },
1152#endif
1153#if defined(HAVE_SS7)
1154 .ss7.ss7 = {
1155 .called_nai = SS7_NAI_NATIONAL,
1156 .calling_nai = SS7_NAI_NATIONAL,
1157 .internationalprefix = "",
1158 .nationalprefix = "",
1159 .subscriberprefix = "",
1160 .unknownprefix = "",
1161 .networkroutedprefix = ""
1162 },
1163#endif /* defined(HAVE_SS7) */
1164#ifdef HAVE_OPENR2
1165 .mfcr2 = {
1166 .variant = OR2_VAR_ITU,
1167 .mfback_timeout = -1,
1168 .metering_pulse_timeout = -1,
1169 .max_ani = 10,
1170 .max_dnis = 4,
1171 .get_ani_first = -1,
1172#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
1173 .skip_category_request = -1,
1174#endif
1175 .call_files = 0,
1176 .allow_collect_calls = 0,
1177 .charge_calls = 1,
1178 .accept_on_offer = 1,
1179 .forced_release = 0,
1180 .double_answer = 0,
1181 .immediate_accept = -1,
1182#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
1183 .dtmf_dialing = -1,
1184 .dtmf_detection = -1,
1185 .dtmf_time_on = OR2_DEFAULT_DTMF_ON,
1186 .dtmf_time_off = OR2_DEFAULT_DTMF_OFF,
1187#endif
1188#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
1189 .dtmf_end_timeout = -1,
1190#endif
1191 .logdir = "",
1192 .r2proto_file = "",
1193 .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
1194 .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
1195 },
1196#endif
1197 .chan = {
1198 .context = "default",
1199 .immediatering = 1,
1200 .cid_num = "",
1201 .cid_name = "",
1202 .cid_tag = "",
1203 .mohinterpret = "default",
1204 .mohsuggest = "",
1205 .parkinglot = "",
1206 .transfertobusy = 1,
1207 .permdialmode = ANALOG_DIALMODE_BOTH,
1208
1209 .ani_info_digits = 2,
1210 .ani_wink_time = 1000,
1211 .ani_timeout = 10000,
1212
1213 .cid_signalling = CID_SIG_BELL,
1214 .cid_start = CID_START_RING,
1215 .dahditrcallerid = 0,
1216 .use_callerid = 1,
1217 .sig = -1,
1218 .outsigmod = -1,
1219
1220 .cid_rxgain = +5.0,
1221
1222 .tonezone = -1,
1223
1224 .echocancel.head.tap_length = 1,
1225
1226 .busycount = 3,
1227
1228 .accountcode = "",
1229
1230 .mailbox = "",
1231
1232#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
1233 .mwisend_fsk = 1,
1234#endif
1235 .polarityonanswerdelay = 600,
1236
1237 .sendcalleridafter = DEFAULT_CIDRINGS,
1238
1239 .buf_policy = DAHDI_POLICY_IMMEDIATE,
1240 .buf_no = numbufs,
1241 .usefaxbuffers = 0,
1242 .cc_params = ast_cc_config_params_init(),
1243 .firstdigit_timeout = ANALOG_FIRST_DIGIT_TIMEOUT,
1244 .interdigit_timeout = ANALOG_INTER_DIGIT_TIMEOUT,
1245 .matchdigit_timeout = ANALOG_MATCH_DIGIT_TIMEOUT,
1246 },
1247 .timing = {
1248 .prewinktime = -1,
1249 .preflashtime = -1,
1250 .winktime = -1,
1251 .flashtime = -1,
1252 .starttime = -1,
1253 .rxwinktime = -1,
1254 .rxflashtime = -1,
1255 .debouncetime = -1
1256 },
1257 .is_sig_auto = 1,
1258 .ignore_failed_channels = 1,
1259 .smdi_port = "/dev/ttyS0",
1260 };
1261
1262 return conf;
1263}
1264
1265
1266static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
1267 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
1268 const char *data, int *cause);
1269static int dahdi_digit_begin(struct ast_channel *ast, char digit);
1270static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
1271static int dahdi_sendtext(struct ast_channel *c, const char *text);
1272static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout);
1273static int dahdi_hangup(struct ast_channel *ast);
1274static int dahdi_answer(struct ast_channel *ast);
1275static struct ast_frame *dahdi_read(struct ast_channel *ast);
1276static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
1277static struct ast_frame *dahdi_exception(struct ast_channel *ast);
1278static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
1279static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1280static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
1281static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
1282static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
1283static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
1284static int dahdi_devicestate(const char *data);
1285static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
1286
1288 .type = "DAHDI",
1289 .description = tdesc,
1290 .requester = dahdi_request,
1291 .send_digit_begin = dahdi_digit_begin,
1292 .send_digit_end = dahdi_digit_end,
1293 .send_text = dahdi_sendtext,
1294 .call = dahdi_call,
1295 .hangup = dahdi_hangup,
1296 .answer = dahdi_answer,
1297 .read = dahdi_read,
1298 .write = dahdi_write,
1299 .exception = dahdi_exception,
1300 .indicate = dahdi_indicate,
1301 .fixup = dahdi_fixup,
1302 .setoption = dahdi_setoption,
1303 .queryoption = dahdi_queryoption,
1304 .func_channel_read = dahdi_func_read,
1305 .func_channel_write = dahdi_func_write,
1306 .devicestate = dahdi_devicestate,
1307 .cc_callback = dahdi_cc_callback,
1308};
1309
1310#define GET_CHANNEL(p) ((p)->channel)
1311
1313{
1314 switch (sig) {
1315 case SIG_FXOLS:
1316 return ANALOG_SIG_FXOLS;
1317 case SIG_FXOGS:
1318 return ANALOG_SIG_FXOGS;
1319 case SIG_FXOKS:
1320 return ANALOG_SIG_FXOKS;
1321 case SIG_FXSLS:
1322 return ANALOG_SIG_FXSLS;
1323 case SIG_FXSGS:
1324 return ANALOG_SIG_FXSGS;
1325 case SIG_FXSKS:
1326 return ANALOG_SIG_FXSKS;
1327 case SIG_EMWINK:
1328 return ANALOG_SIG_EMWINK;
1329 case SIG_EM:
1330 return ANALOG_SIG_EM;
1331 case SIG_EM_E1:
1332 return ANALOG_SIG_EM_E1;
1333 case SIG_FEATD:
1334 return ANALOG_SIG_FEATD;
1335 case SIG_FEATDMF:
1336 return ANALOG_SIG_FEATDMF;
1337 case SIG_E911:
1338 return SIG_E911;
1339 case SIG_FGC_CAMA:
1340 return ANALOG_SIG_FGC_CAMA;
1341 case SIG_FGC_CAMAMF:
1342 return ANALOG_SIG_FGC_CAMAMF;
1343 case SIG_FEATB:
1344 return ANALOG_SIG_FEATB;
1345 case SIG_SFWINK:
1346 return ANALOG_SIG_SFWINK;
1347 case SIG_SF:
1348 return ANALOG_SIG_SF;
1349 case SIG_SF_FEATD:
1350 return ANALOG_SIG_SF_FEATD;
1351 case SIG_SF_FEATDMF:
1352 return ANALOG_SIG_SF_FEATDMF;
1353 case SIG_FEATDMF_TA:
1354 return ANALOG_SIG_FEATDMF_TA;
1355 case SIG_SF_FEATB:
1356 return ANALOG_SIG_FEATB;
1357 default:
1358 return -1;
1359 }
1360}
1361
1362
1364{
1365 switch (tone) {
1367 return DAHDI_TONE_RINGTONE;
1369 return DAHDI_TONE_STUTTER;
1371 return DAHDI_TONE_CONGESTION;
1373 return DAHDI_TONE_DIALTONE;
1375 return DAHDI_TONE_DIALRECALL;
1376 case ANALOG_TONE_INFO:
1377 return DAHDI_TONE_INFO;
1378 default:
1379 return -1;
1380 }
1381}
1382
1383static int analogsub_to_dahdisub(enum analog_sub analogsub)
1384{
1385 int index;
1386
1387 switch (analogsub) {
1388 case ANALOG_SUB_REAL:
1389 index = SUB_REAL;
1390 break;
1392 index = SUB_CALLWAIT;
1393 break;
1395 index = SUB_THREEWAY;
1396 break;
1397 default:
1398 ast_log(LOG_ERROR, "Unidentified sub!\n");
1399 index = SUB_REAL;
1400 }
1401
1402 return index;
1403}
1404
1405/*!
1406 * \internal
1407 * \brief release all members on the doomed pris list
1408 * \since 13.0
1409 *
1410 * Called periodically by the monitor threads to release spans marked for
1411 * removal.
1412 */
1413static void release_doomed_pris(void)
1414{
1415#ifdef HAVE_PRI
1416 struct doomed_pri *entry;
1417
1418 AST_LIST_LOCK(&doomed_pris);
1419 while ((entry = AST_LIST_REMOVE_HEAD(&doomed_pris, list))) {
1420 /* The span destruction must be done with this lock not held */
1421 AST_LIST_UNLOCK(&doomed_pris);
1422 ast_debug(4, "Destroying span %d from doomed queue.\n",
1423 entry->pri->span);
1424 pri_destroy_span(entry->pri);
1425 ast_free(entry);
1426 AST_LIST_LOCK(&doomed_pris);
1427 }
1428 AST_LIST_UNLOCK(&doomed_pris);
1429#endif
1430}
1431
1432#ifdef HAVE_PRI
1433/*!
1434 * \brief Queue a span for destruction
1435 * \since 13.0
1436 *
1437 * \param pri the span to destroy
1438 *
1439 * Add a span to the list of spans to be destroyed later on
1440 * by the monitor thread. Allows destroying a span while holding its
1441 * lock.
1442 */
1443static void pri_queue_for_destruction(struct sig_pri_span *pri)
1444{
1445 struct doomed_pri *entry;
1446
1447 AST_LIST_LOCK(&doomed_pris);
1448 AST_LIST_TRAVERSE(&doomed_pris, entry, list) {
1449 if (entry->pri == pri) {
1450 AST_LIST_UNLOCK(&doomed_pris);
1451 return;
1452 }
1453 }
1454 entry = ast_calloc(sizeof(struct doomed_pri), 1);
1455 if (!entry) {
1456 /* Nothing useful to do here. Panic? */
1457 ast_log(LOG_WARNING, "Failed allocating memory for a doomed_pri.\n");
1458 AST_LIST_UNLOCK(&doomed_pris);
1459 return;
1460 }
1461 entry->pri = pri;
1462 ast_debug(4, "Queue span %d for destruction.\n", pri->span);
1463 AST_LIST_INSERT_TAIL(&doomed_pris, entry, list);
1464 AST_LIST_UNLOCK(&doomed_pris);
1465}
1466#endif
1467
1468/*!
1469 * \internal
1470 * \brief Send a dial string to DAHDI.
1471 * \since 12.0.0
1472 *
1473 * \param pvt DAHDI private pointer
1474 * \param operation DAHDI dial operation to do to string
1475 * \param dial_str Dial string to send
1476 *
1477 * \retval 0 on success.
1478 * \retval non-zero on error.
1479 */
1480static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
1481{
1482 int res;
1483 int offset;
1484 const char *pos;
1485 struct dahdi_dialoperation zo = {
1486 .op = operation,
1487 };
1488
1489 /* Convert the W's to ww. */
1490 pos = dial_str;
1491 for (offset = 0; offset < sizeof(zo.dialstr) - 1; ++offset) {
1492 if (!*pos) {
1493 break;
1494 }
1495 if (*pos == 'W') {
1496 /* Convert 'W' to "ww" */
1497 ++pos;
1498 if (offset >= sizeof(zo.dialstr) - 3) {
1499 /* No room to expand */
1500 break;
1501 }
1502 zo.dialstr[offset] = 'w';
1503 ++offset;
1504 zo.dialstr[offset] = 'w';
1505 continue;
1506 }
1507 zo.dialstr[offset] = *pos++;
1508 }
1509 /* The zo initialization has already terminated the dialstr. */
1510
1511 ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
1512 pvt->channel, dial_str, zo.dialstr);
1513 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
1514 if (res) {
1515 ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
1516 pvt->channel, dial_str, strerror(errno));
1517 }
1518
1519 return res;
1520}
1521
1523static int bump_gains(struct dahdi_pvt *p);
1524static int dahdi_setlinear(int dfd, int linear);
1525
1526static int my_start_cid_detect(void *pvt, int cid_signalling)
1527{
1528 struct dahdi_pvt *p = pvt;
1529 int index = SUB_REAL;
1531 if (!p->cs) {
1532 ast_log(LOG_ERROR, "Unable to alloc callerid\n");
1533 return -1;
1534 }
1535 bump_gains(p);
1536 dahdi_setlinear(p->subs[index].dfd, 0);
1537
1538 return 0;
1539}
1540
1541static int restore_gains(struct dahdi_pvt *p);
1542
1543static int my_stop_cid_detect(void *pvt)
1544{
1545 struct dahdi_pvt *p = pvt;
1546 int index = SUB_REAL;
1547
1548 if (p->cs) {
1549 callerid_free(p->cs);
1550 }
1551
1552 /* Restore linear mode after Caller*ID processing */
1553 dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
1554 restore_gains(p);
1555
1556 return 0;
1557}
1558
1559static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
1560{
1561 struct dahdi_pvt *p = pvt;
1562 struct analog_pvt *analog_p = p->sig_pvt;
1563 struct pollfd poller;
1564 char *name, *num;
1565 int index = SUB_REAL;
1566 int res;
1567 unsigned char buf[256];
1568 int flags;
1569 int redirecting;
1570
1571 poller.fd = p->subs[SUB_REAL].dfd;
1572 poller.events = POLLPRI | POLLIN;
1573 poller.revents = 0;
1574
1575 res = poll(&poller, 1, timeout);
1576
1577 if (poller.revents & POLLPRI) {
1579 return 1;
1580 }
1581
1582 if (poller.revents & POLLIN) {
1583 /*** NOTES ***/
1584 /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
1585 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
1586 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
1587 * a failure and die, and returning 2 means no event was received. */
1588 res = read(p->subs[index].dfd, buf, sizeof(buf));
1589 if (res < 0) {
1590 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1591 return -1;
1592 }
1593
1594 if (analog_p->ringt > 0) {
1595 if (!(--analog_p->ringt)) {
1596 /* only return if we timeout from a ring event */
1597 return -1;
1598 }
1599 }
1600
1601 if (p->cid_signalling == CID_SIG_V23_JP) {
1602 res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
1603 } else {
1604 res = callerid_feed(p->cs, buf, res, AST_LAW(p));
1605 }
1606 if (res < 0) {
1607 /*
1608 * The previous diagnostic message output likely
1609 * explains why it failed.
1610 */
1611 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
1612 return -1;
1613 }
1614
1615 if (res == 1) {
1616 struct ast_channel *chan = analog_p->ss_astchan;
1618 if (name)
1620 if (num)
1621 ast_copy_string(numbuf, num, ANALOG_MAX_CID);
1622
1624 /* If we got a presentation, we must set it on the channel */
1625 struct ast_party_caller caller;
1626
1628 caller.id.name.presentation = caller.id.number.presentation = (flags & CID_PRIVATE_NUMBER) ?
1631 ast_party_caller_free(&caller);
1632 }
1633 if (redirecting) {
1634 /* There is a redirecting reason available in the Caller*ID received.
1635 * No idea what the redirecting number is, since the Caller*ID protocol
1636 * has no parameter for that, but at least we know WHY it was redirected. */
1637 ast_channel_redirecting(chan)->reason.code = redirecting;
1638 }
1639
1640 if (flags & CID_QUALIFIER) {
1641 /* This is the inverse of how the qualifier is set in sig_analog */
1642 pbx_builtin_setvar_helper(chan, "CALL_QUALIFIER", "1");
1643 }
1644
1645 ast_debug(1, "CallerID number: %s, name: %s, flags=%d, redirecting=%s\n", num, name, flags, ast_redirecting_reason_name(&ast_channel_redirecting(chan)->reason));
1646 return 0;
1647 }
1648 }
1649
1650 *ev = ANALOG_EVENT_NONE;
1651 return 2;
1652}
1653
1654static const char *event2str(int event);
1655
1656static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
1657{
1658 unsigned char buf[256];
1659 int distMatches;
1660 int curRingData[RING_PATTERNS];
1661 int receivedRingT;
1662 int counter1;
1663 int counter;
1664 int i;
1665 int res;
1666 int checkaftercid = 0;
1667 const char *matched_context;
1668 struct dahdi_pvt *p = pvt;
1669 struct analog_pvt *analog_p = p->sig_pvt;
1670
1671 if (ringdata == NULL) {
1672 ringdata = curRingData;
1673 } else {
1674 checkaftercid = 1;
1675 }
1676
1677 /* We must have a ring by now so lets try to listen for distinctive ringing */
1678 if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
1679 /* Clear the current ring data array so we don't have old data in it. */
1680 for (receivedRingT = 0; receivedRingT < RING_PATTERNS; receivedRingT++)
1681 ringdata[receivedRingT] = 0;
1682 receivedRingT = 0;
1683
1684 if (checkaftercid && distinctiveringaftercid) {
1685 ast_verb(3, "Detecting post-CID distinctive ring\n");
1686 }
1687
1688 for (;;) {
1689 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
1690 res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i);
1691 if (res) {
1692 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
1693 ast_hangup(chan);
1694 return 1;
1695 }
1696 if (i & DAHDI_IOMUX_SIGEVENT) {
1697 res = dahdi_get_event(p->subs[idx].dfd);
1698 ast_debug(3, "Got event %d (%s)...\n", res, event2str(res));
1699 if (res == DAHDI_EVENT_NOALARM) {
1700 p->inalarm = 0;
1701 analog_p->inalarm = 0;
1702 } else if (res == DAHDI_EVENT_RINGOFFHOOK) {
1703 /* Let us detect distinctive ring */
1704 ringdata[receivedRingT] = analog_p->ringt;
1705
1706 if (analog_p->ringt < analog_p->ringt_base / 2) {
1707 break;
1708 }
1709 /* Increment the ringT counter so we can match it against
1710 values in chan_dahdi.conf for distinctive ring */
1711 if (++receivedRingT == RING_PATTERNS) {
1712 break;
1713 }
1714 }
1715 } else if (i & DAHDI_IOMUX_READ) {
1716 res = read(p->subs[idx].dfd, buf, sizeof(buf));
1717 if (res < 0) {
1718 if (errno != ELAST) {
1719 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1720 ast_hangup(chan);
1721 return 1;
1722 }
1723 break;
1724 }
1725 if (analog_p->ringt > 0) {
1726 if (!(--analog_p->ringt)) {
1727 break;
1728 }
1729 }
1730 }
1731 }
1732 }
1733
1734 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
1735 ast_verb(3, "Detected ring pattern: %d,%d,%d\n", ringdata[0], ringdata[1], ringdata[2]);
1736 matched_context = p->defcontext;
1737 for (counter = 0; counter < 3; counter++) {
1738 int range = p->drings.ringnum[counter].range;
1739
1740 distMatches = 0;
1741 ast_verb(3, "Checking %d,%d,%d with +/- %d range\n",
1742 p->drings.ringnum[counter].ring[0],
1743 p->drings.ringnum[counter].ring[1],
1744 p->drings.ringnum[counter].ring[2],
1745 range);
1746 for (counter1 = 0; counter1 < 3; counter1++) {
1747 int ring = p->drings.ringnum[counter].ring[counter1];
1748
1749 if (ring == -1) {
1750 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
1751 ringdata[counter1]);
1752 distMatches++;
1753 } else if (ring - range <= ringdata[counter1] && ringdata[counter1] <= ring + range) {
1754 ast_verb(3, "Ring pattern %d is in range: %d to %d\n",
1755 ringdata[counter1], ring - range, ring + range);
1756 distMatches++;
1757 } else {
1758 /* The current dring pattern cannot match. */
1759 break;
1760 }
1761 }
1762
1763 if (distMatches == 3) {
1764 /* The ring matches, set the context to whatever is for distinctive ring.. */
1765 matched_context = S_OR(p->drings.ringContext[counter].contextData, p->defcontext);
1766 ast_verb(3, "Matched Distinctive Ring context %s\n", matched_context);
1767 break;
1768 }
1769 }
1770
1771 /* Set selected distinctive ring context if not already set. */
1772 if (strcmp(p->context, matched_context) != 0) {
1773 ast_copy_string(p->context, matched_context, sizeof(p->context));
1774 ast_channel_context_set(chan, matched_context);
1775 }
1776
1777 return 0;
1778}
1779
1780static int my_stop_callwait(void *pvt)
1781{
1782 struct dahdi_pvt *p = pvt;
1783 p->callwaitingrepeat = 0;
1784 p->cidcwexpire = 0;
1785 p->cid_suppress_expire = 0;
1786
1787 return 0;
1788}
1789
1790static int send_callerid(struct dahdi_pvt *p);
1791static int save_conference(struct dahdi_pvt *p);
1792static int restore_conference(struct dahdi_pvt *p);
1793
1794static int my_callwait(void *pvt)
1795{
1796 struct dahdi_pvt *p = pvt;
1797
1799 if (p->cidspill) {
1800 ast_log(LOG_WARNING, "Spill already exists?!?\n");
1801 ast_free(p->cidspill);
1802 }
1803
1804 /*
1805 * SAS: Subscriber Alert Signal, 440Hz for 300ms
1806 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
1807 */
1808 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
1809 return -1;
1810 save_conference(p);
1811 /* Silence */
1812 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
1813 if (!p->callwaitrings && p->callwaitingcallerid) {
1814 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
1815 p->callwaitcas = 1;
1816 p->cidlen = 2400 + 680 + READ_SIZE * 4;
1817 } else {
1818 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
1819 p->callwaitcas = 0;
1820 p->cidlen = 2400 + READ_SIZE * 4;
1821 }
1822 p->cidpos = 0;
1823 send_callerid(p);
1824
1825 return 0;
1826}
1827
1828static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
1829{
1830 struct dahdi_pvt *p = pvt;
1831 struct analog_pvt *analog_p = p->sig_pvt;
1832
1833 ast_debug(2, "Starting cid spill\n");
1834
1835 if (p->cidspill) {
1836 ast_log(LOG_WARNING, "cidspill already exists??\n");
1837 ast_free(p->cidspill);
1838 }
1839
1841 int pres = ast_party_id_presentation(&caller->id);
1842 if (cwcid == 0) {
1843 /* Some CPE support additional parameters for on-hook Caller*ID,
1844 * such as redirecting reason and call qualifier, so send those
1845 * if available.
1846 * I don't know of any CPE that supports this for Call Waiting (unfortunately),
1847 * so don't send those for call waiting as that will just lengthen the CID spill
1848 * for no good reason.
1849 */
1851 caller->id.name.str,
1853 NULL,
1854 analog_p->redirecting_reason,
1855 pres,
1856 analog_p->call_qualifier,
1858 AST_LAW(p));
1859 } else {
1860 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
1862 p->callwaitcas = 0;
1863 p->cidcwexpire = 0;
1865 caller->id.name.str,
1867 NULL,
1868 -1,
1869 pres,
1870 0,
1871 AST_LAW(p));
1872 p->cidlen += READ_SIZE * 4;
1873 }
1874 p->cidpos = 0;
1875 p->cid_suppress_expire = 0;
1876 send_callerid(p);
1877 }
1878 return 0;
1879}
1880
1882{
1883 struct dahdi_pvt *p = pvt;
1884 if (p->dsp)
1886
1887 return 0;
1888}
1889
1890static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
1891{
1892 struct dahdi_pvt *p = pvt;
1893
1894 if (p->channel == CHAN_PSEUDO)
1895 ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
1896
1897 if (mode == ANALOG_DIGITMODE_DTMF) {
1898 /* If we do hardware dtmf, no need for a DSP */
1899 if (p->hardwaredtmf) {
1900 if (p->dsp) {
1901 ast_dsp_free(p->dsp);
1902 p->dsp = NULL;
1903 }
1904 return 0;
1905 }
1906
1907 if (!p->dsp) {
1908 p->dsp = ast_dsp_new();
1909 if (!p->dsp) {
1910 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1911 return -1;
1912 }
1913 }
1914
1916 } else if (mode == ANALOG_DIGITMODE_MF) {
1917 if (!p->dsp) {
1918 p->dsp = ast_dsp_new();
1919 if (!p->dsp) {
1920 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1921 return -1;
1922 }
1923 }
1925 }
1926 return 0;
1927}
1928
1929static int dahdi_wink(struct dahdi_pvt *p, int index);
1930
1931static int my_wink(void *pvt, enum analog_sub sub)
1932{
1933 struct dahdi_pvt *p = pvt;
1934 int index = analogsub_to_dahdisub(sub);
1935 if (index != SUB_REAL) {
1936 ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
1937 }
1938 return dahdi_wink(p, index);
1939}
1940
1941static void wakeup_sub(struct dahdi_pvt *p, int a);
1942
1943static int reset_conf(struct dahdi_pvt *p);
1944
1945static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
1946
1947static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
1948{
1949 struct ast_frame *f = *dest;
1950 struct dahdi_pvt *p = pvt;
1951 int idx = analogsub_to_dahdisub(analog_index);
1952
1953 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
1954 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
1955 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
1956
1957 if (f->subclass.integer == 'f') {
1958 if (f->frametype == AST_FRAME_DTMF_END) {
1959 /* Fax tone -- Handle and return NULL */
1960 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
1961 /* If faxbuffers are configured, use them for the fax transmission */
1962 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
1963 struct dahdi_bufferinfo bi = {
1964 .txbufpolicy = p->faxbuf_policy,
1965 .bufsize = p->bufsize,
1966 .numbufs = p->faxbuf_no
1967 };
1968 int res;
1969
1970 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
1971 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
1972 } else {
1973 p->bufferoverrideinuse = 1;
1974 }
1975 }
1976 p->faxhandled = 1;
1977 if (p->dsp) {
1978 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
1980 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
1981 }
1982 if (strcmp(ast_channel_exten(ast), "fax")) {
1983 const char *target_context = ast_channel_context(ast);
1984
1985 /*
1986 * We need to unlock 'ast' here because ast_exists_extension has the
1987 * potential to start autoservice on the channel. Such action is prone
1988 * to deadlock if the channel is locked.
1989 *
1990 * ast_async_goto() has its own restriction on not holding the
1991 * channel lock.
1992 */
1994 ast_channel_unlock(ast);
1995 if (ast_exists_extension(ast, target_context, "fax", 1,
1996 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
1997 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
1998 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
1999 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
2000 if (ast_async_goto(ast, target_context, "fax", 1))
2001 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
2002 } else {
2003 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
2004 }
2005 ast_channel_lock(ast);
2006 ast_mutex_lock(&p->lock);
2007 } else {
2008 ast_debug(1, "Already in a fax extension, not redirecting\n");
2009 }
2010 } else {
2011 ast_debug(1, "Fax already handled\n");
2012 }
2013 dahdi_confmute(p, 0);
2014 }
2015 p->subs[idx].f.frametype = AST_FRAME_NULL;
2016 p->subs[idx].f.subclass.integer = 0;
2017 *dest = &p->subs[idx].f;
2018 }
2019}
2020
2021static void my_lock_private(void *pvt)
2022{
2023 struct dahdi_pvt *p = pvt;
2024 ast_mutex_lock(&p->lock);
2025}
2026
2027static void my_unlock_private(void *pvt)
2028{
2029 struct dahdi_pvt *p = pvt;
2031}
2032
2033static void my_deadlock_avoidance_private(void *pvt)
2034{
2035 struct dahdi_pvt *p = pvt;
2036
2038}
2039
2041{
2042 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2043 struct ast_channel_blob *obj = stasis_message_data(msg);
2044 struct ast_json *group, *span, *channel;
2045
2046 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2047 if (!channel_string) {
2048 return NULL;
2049 }
2050
2051 group = ast_json_object_get(obj->blob, "group");
2052 span = ast_json_object_get(obj->blob, "span");
2053 channel = ast_json_object_get(obj->blob, "channel");
2054
2055 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
2056 "%s"
2057 "DAHDIGroup: %llu\r\n"
2058 "DAHDISpan: %u\r\n"
2059 "DAHDIChannel: %s\r\n",
2060 ast_str_buffer(channel_string),
2062 (unsigned int)ast_json_integer_get(span),
2063 ast_json_string_get(channel));
2064}
2065
2068 );
2069
2070/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
2071static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
2072{
2073 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
2074
2075 ast_assert(dahdi_channel != NULL);
2076
2077 blob = ast_json_pack("{s: I, s: i, s: s}",
2078 "group", (ast_json_int_t)group,
2079 "span", span,
2080 "channel", dahdi_channel);
2081 if (!blob) {
2082 return;
2083 }
2084
2085 ast_channel_lock(chan);
2086 ast_channel_publish_blob(chan, dahdichannel_type(), blob);
2087 ast_channel_unlock(chan);
2088}
2089
2090/*!
2091 * \internal
2092 * \brief Post an AMI DAHDI channel association event.
2093 * \since 1.8
2094 *
2095 * \param p DAHDI private pointer
2096 * \param chan Channel associated with the private pointer
2097 */
2098static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
2099{
2100 char ch_name[23];
2101
2102 if (p->channel < CHAN_PSEUDO) {
2103 /* No B channel */
2104 snprintf(ch_name, sizeof(ch_name), "no-media (%d)", p->channel);
2105 } else if (p->channel == CHAN_PSEUDO) {
2106 /* Pseudo channel */
2107 strcpy(ch_name, "pseudo");
2108 } else {
2109 /* Real channel */
2110 snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
2111 }
2112 publish_dahdichannel(chan, p->group, p->span, ch_name);
2113}
2114
2115#ifdef HAVE_PRI
2116/*!
2117 * \internal
2118 * \brief Post an AMI DAHDI channel association event.
2119 * \since 1.8
2120 *
2121 * \param pvt DAHDI private pointer
2122 * \param chan Channel associated with the private pointer
2123 */
2124static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
2125{
2126 struct dahdi_pvt *p = pvt;
2127
2128 dahdi_ami_channel_event(p, chan);
2129}
2130#endif
2131
2132/* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
2133* returns the last value of the linear setting
2134*/
2135static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
2136{
2137 struct dahdi_pvt *p = pvt;
2138 int oldval;
2139 int idx = analogsub_to_dahdisub(sub);
2140
2141 dahdi_setlinear(p->subs[idx].dfd, linear_mode);
2142 oldval = p->subs[idx].linear;
2143 p->subs[idx].linear = linear_mode ? 1 : 0;
2144 return oldval;
2145}
2146
2147static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
2148{
2149 struct dahdi_pvt *p = pvt;
2150 int idx = analogsub_to_dahdisub(sub);
2151
2152 p->subs[idx].inthreeway = inthreeway;
2153}
2154
2155static int get_alarms(struct dahdi_pvt *p);
2156static void handle_alarms(struct dahdi_pvt *p, int alms);
2157static void my_get_and_handle_alarms(void *pvt)
2158{
2159 int res;
2160 struct dahdi_pvt *p = pvt;
2161
2162 res = get_alarms(p);
2163 handle_alarms(p, res);
2164}
2165
2167{
2169
2170 if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
2171 struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
2172
2173 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
2174 return p->sig_pvt;
2175 }
2176 }
2177 return NULL;
2178}
2179
2180static int my_get_sub_fd(void *pvt, enum analog_sub sub)
2181{
2182 struct dahdi_pvt *p = pvt;
2183 int dahdi_sub = analogsub_to_dahdisub(sub);
2184 return p->subs[dahdi_sub].dfd;
2185}
2186
2187static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
2188{
2189 struct dahdi_pvt *p = pvt;
2190
2191 /* Choose proper cadence */
2192 if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
2193 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
2194 ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast_channel_name(ast), strerror(errno));
2195 *cid_rings = cidrings[p->distinctivering - 1];
2196 } else {
2197 if (p->distinctivering > 0) {
2198 ast_log(LOG_WARNING, "Cadence %d is not defined, falling back to default ring cadence\n", p->distinctivering);
2199 }
2200 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
2201 ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast), strerror(errno));
2202 *cid_rings = p->sendcalleridafter;
2203 }
2204}
2205
2206static void my_set_alarm(void *pvt, int in_alarm)
2207{
2208 struct dahdi_pvt *p = pvt;
2209
2210 p->inalarm = in_alarm;
2211}
2212
2213static void my_set_dialing(void *pvt, int is_dialing)
2214{
2215 struct dahdi_pvt *p = pvt;
2216
2217 p->dialing = is_dialing;
2218}
2219
2220static void my_set_outgoing(void *pvt, int is_outgoing)
2221{
2222 struct dahdi_pvt *p = pvt;
2223
2224 p->outgoing = is_outgoing;
2225}
2226
2227#if defined(HAVE_PRI) || defined(HAVE_SS7)
2228static void my_set_digital(void *pvt, int is_digital)
2229{
2230 struct dahdi_pvt *p = pvt;
2231
2232 p->digital = is_digital;
2233}
2234#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2235
2236#if defined(HAVE_SS7)
2237static void my_set_inservice(void *pvt, int is_inservice)
2238{
2239 struct dahdi_pvt *p = pvt;
2240
2241 p->inservice = is_inservice;
2242}
2243#endif /* defined(HAVE_SS7) */
2244
2245#if defined(HAVE_SS7)
2246static void my_set_locallyblocked(void *pvt, int is_blocked)
2247{
2248 struct dahdi_pvt *p = pvt;
2249
2250 p->locallyblocked = is_blocked;
2251}
2252#endif /* defined(HAVE_SS7) */
2253
2254#if defined(HAVE_SS7)
2255static void my_set_remotelyblocked(void *pvt, int is_blocked)
2256{
2257 struct dahdi_pvt *p = pvt;
2258
2259 p->remotelyblocked = is_blocked;
2260}
2261#endif /* defined(HAVE_SS7) */
2262
2263static void my_set_ringtimeout(void *pvt, int ringt)
2264{
2265 struct dahdi_pvt *p = pvt;
2266 p->ringt = ringt;
2267}
2268
2269static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
2270{
2271 struct dahdi_pvt *p = pvt;
2272
2273 /* We reset p->waitfordialtonetemp here, to prevent leaking to future calls,
2274 * but we also need to check against this value until we get dialtone
2275 * or the timer expires, since waitingfordt is when the timer started,
2276 * not when it should expire.
2277 *
2278 * Critically, we only set p->waitingfordt here if waitfordialtone or waitfordialtonetemp
2279 * has already been set, as waitingfordt is what is checked at runtime to determine
2280 * if we should be waiting for dial tone. This ensures that if a second call
2281 * is initiated concurrently, the first one "consumes" waitfordialtonetemp and resets it,
2282 * preventing leaking to other calls while remaining available to check on the first one while dialing.
2283 */
2285 p->waitfordialtonetemp = 0;
2286
2288 return;
2289 }
2290
2291 /* Because the DSP is allocated when the channel is created,
2292 * if we requested waitfordialtone later (in a predial handler),
2293 * we need to create it now */
2294 if (!p->dsp) {
2295 p->dsp = ast_dsp_new();
2296 if (!p->dsp) {
2297 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
2298 return;
2299 }
2300 }
2303
2304 ast_debug(1, "Defer dialing for %dms or dialtone\n", p->waitfordialtoneduration);
2305 gettimeofday(&p->waitingfordt, NULL);
2307}
2308
2309static int my_check_waitingfordt(void *pvt)
2310{
2311 struct dahdi_pvt *p = pvt;
2312
2313 if (p->waitingfordt.tv_sec) {
2314 return 1;
2315 }
2316
2317 return 0;
2318}
2319
2320static void my_set_confirmanswer(void *pvt, int flag)
2321{
2322 struct dahdi_pvt *p = pvt;
2323 p->confirmanswer = flag;
2324}
2325
2326static int my_check_confirmanswer(void *pvt)
2327{
2328 struct dahdi_pvt *p = pvt;
2329 if (p->confirmanswer) {
2330 return 1;
2331 }
2332
2333 return 0;
2334}
2335
2336static void my_set_callwaiting(void *pvt, int callwaiting_enable)
2337{
2338 struct dahdi_pvt *p = pvt;
2339
2340 p->callwaiting = callwaiting_enable;
2341}
2342
2343static void my_cancel_cidspill(void *pvt)
2344{
2345 struct dahdi_pvt *p = pvt;
2346
2347 ast_free(p->cidspill);
2348 p->cidspill = NULL;
2350}
2351
2352static int my_confmute(void *pvt, int mute)
2353{
2354 struct dahdi_pvt *p = pvt;
2355 return dahdi_confmute(p, mute);
2356}
2357
2358static void my_set_pulsedial(void *pvt, int flag)
2359{
2360 struct dahdi_pvt *p = pvt;
2361 p->pulsedial = flag;
2362}
2363
2364static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
2365{
2366 struct dahdi_pvt *p = pvt;
2367
2368 p->owner = new_owner;
2369}
2370
2371static const char *my_get_orig_dialstring(void *pvt)
2372{
2373 struct dahdi_pvt *p = pvt;
2374
2375 return p->dialstring;
2376}
2377
2384
2392
2393static void my_all_subchannels_hungup(void *pvt)
2394{
2395 struct dahdi_pvt *p = pvt;
2396 int res, law;
2397
2398 p->faxhandled = 0;
2399 p->didtdd = 0;
2400
2401 if (p->dsp) {
2402 ast_dsp_free(p->dsp);
2403 p->dsp = NULL;
2404 }
2405
2406 p->law = p->law_default;
2407 law = p->law_default;
2408 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
2409 if (res < 0)
2410 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
2411
2413
2414#if 1
2415 {
2416 int i;
2417 p->owner = NULL;
2418 /* Cleanup owners here */
2419 for (i = 0; i < 3; i++) {
2420 p->subs[i].owner = NULL;
2421 }
2422 }
2423#endif
2424
2425 reset_conf(p);
2426 if (num_restart_pending == 0) {
2428 }
2429}
2430
2431static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
2432
2433static int my_conf_del(void *pvt, enum analog_sub sub)
2434{
2435 struct dahdi_pvt *p = pvt;
2436 int x = analogsub_to_dahdisub(sub);
2437
2438 return conf_del(p, &p->subs[x], x);
2439}
2440
2441static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
2442
2443static int my_conf_add(void *pvt, enum analog_sub sub)
2444{
2445 struct dahdi_pvt *p = pvt;
2446 int x = analogsub_to_dahdisub(sub);
2447
2448 return conf_add(p, &p->subs[x], x, 0);
2449}
2450
2451static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
2452
2453static int my_complete_conference_update(void *pvt, int needconference)
2454{
2455 struct dahdi_pvt *p = pvt;
2456 int needconf = needconference;
2457 int x;
2458 int useslavenative;
2459 struct dahdi_pvt *slave = NULL;
2460
2461 useslavenative = isslavenative(p, &slave);
2462
2463 /* If we have a slave, add him to our conference now. or DAX
2464 if this is slave native */
2465 for (x = 0; x < MAX_SLAVES; x++) {
2466 if (p->slaves[x]) {
2467 if (useslavenative)
2468 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
2469 else {
2470 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
2471 needconf++;
2472 }
2473 }
2474 }
2475 /* If we're supposed to be in there, do so now */
2476 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
2477 if (useslavenative)
2478 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
2479 else {
2480 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
2481 needconf++;
2482 }
2483 }
2484 /* If we have a master, add ourselves to his conference */
2485 if (p->master) {
2486 if (isslavenative(p->master, NULL)) {
2488 } else {
2489 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
2490 }
2491 }
2492 if (!needconf) {
2493 /* Nobody is left (or should be left) in our conference.
2494 Kill it. */
2495 p->confno = -1;
2496 }
2497
2498 return 0;
2499}
2500
2501static int check_for_conference(struct dahdi_pvt *p);
2502
2503static int my_check_for_conference(void *pvt)
2504{
2505 struct dahdi_pvt *p = pvt;
2506 return check_for_conference(p);
2507}
2508
2509static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
2510{
2511 struct dahdi_pvt *p = pvt;
2512 int da, db;
2513 int tchan;
2514 int tinthreeway;
2515
2518
2519 tchan = p->subs[da].chan;
2520 p->subs[da].chan = p->subs[db].chan;
2521 p->subs[db].chan = tchan;
2522
2523 tinthreeway = p->subs[da].inthreeway;
2524 p->subs[da].inthreeway = p->subs[db].inthreeway;
2525 p->subs[db].inthreeway = tinthreeway;
2526
2527 p->subs[da].owner = ast_a;
2528 p->subs[db].owner = ast_b;
2529
2530 if (ast_a)
2531 ast_channel_set_fd(ast_a, 0, p->subs[da].dfd);
2532 if (ast_b)
2533 ast_channel_set_fd(ast_b, 0, p->subs[db].dfd);
2534
2535 wakeup_sub(p, a);
2536 wakeup_sub(p, b);
2537
2538 return;
2539}
2540
2541/*!
2542 * \internal
2543 * \brief performs duties of dahdi_new, but also removes and possibly unbinds (if callid_created is 1) before returning
2544 * \note this variant of dahdi should only be used in conjunction with ast_callid_threadstorage_auto()
2545 *
2546 * \param callid_created value returned from ast_callid_threadstorage_auto()
2547 * \param i, state, startpbx, idx, law, assignedids, requestor, callid
2548 */
2549static 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);
2550
2551static 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);
2552
2553static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
2554{
2555 ast_callid callid = 0;
2556 int callid_created = ast_callid_threadstorage_auto(&callid);
2557 struct dahdi_pvt *p = pvt;
2558 int dsub = analogsub_to_dahdisub(sub);
2559
2560 return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, NULL, requestor, callid, callid_created);
2561}
2562
2563#if defined(HAVE_PRI) || defined(HAVE_SS7)
2564static int dahdi_setlaw(int dfd, int law)
2565{
2566 int res;
2567 res = ioctl(dfd, DAHDI_SETLAW, &law);
2568 if (res)
2569 return res;
2570 return 0;
2571}
2572#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2573
2574#if defined(HAVE_PRI)
2575static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state,
2576 enum sig_pri_law law, char *exten, const struct ast_assigned_ids *assignedids,
2577 const struct ast_channel *requestor)
2578{
2579 struct dahdi_pvt *p = pvt;
2580 int audio;
2581 int newlaw = -1;
2582 ast_callid callid = 0;
2583 int callid_created = ast_callid_threadstorage_auto(&callid);
2584
2585 switch (p->sig) {
2587 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
2588 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
2589 break;
2590 }
2591 /* Fall through */
2592 default:
2593 /* Set to audio mode at this point */
2594 audio = 1;
2595 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) {
2596 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
2597 p->channel, audio, strerror(errno));
2598 }
2599 break;
2600 }
2601
2602 if (law != SIG_PRI_DEFLAW) {
2603 dahdi_setlaw(p->subs[SUB_REAL].dfd, (law == SIG_PRI_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
2604 }
2605
2606 ast_copy_string(p->exten, exten, sizeof(p->exten));
2607
2608 switch (law) {
2609 case SIG_PRI_DEFLAW:
2610 newlaw = 0;
2611 break;
2612 case SIG_PRI_ALAW:
2613 newlaw = DAHDI_LAW_ALAW;
2614 break;
2615 case SIG_PRI_ULAW:
2616 newlaw = DAHDI_LAW_MULAW;
2617 break;
2618 }
2619
2620 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
2621}
2622#endif /* defined(HAVE_PRI) */
2623
2624static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law);
2625
2626#if defined(HAVE_PRI) || defined(HAVE_SS7)
2627/*!
2628 * \internal
2629 * \brief Open the PRI/SS7 channel media path.
2630 * \since 1.8
2631 *
2632 * \param p Channel private control structure.
2633 */
2634static void my_pri_ss7_open_media(void *p)
2635{
2636 struct dahdi_pvt *pvt = p;
2637 int res;
2638 int dfd;
2639 int set_val;
2640
2641 dfd = pvt->subs[SUB_REAL].dfd;
2642
2643 /* Open the media path. */
2644 set_val = 1;
2645 res = ioctl(dfd, DAHDI_AUDIOMODE, &set_val);
2646 if (res < 0) {
2647 ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n",
2648 pvt->channel, strerror(errno));
2649 }
2650
2651 /* Set correct companding law for this call. */
2652 res = dahdi_setlaw(dfd, pvt->law);
2653 if (res < 0) {
2654 ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pvt->channel);
2655 }
2656
2657 /* Set correct gain for this call. */
2658 if (pvt->digital) {
2659 res = set_actual_gain(dfd, 0, 0, pvt->rxdrc, pvt->txdrc, pvt->law);
2660 } else {
2661 res = set_actual_gain(dfd, pvt->rxgain, pvt->txgain, pvt->rxdrc, pvt->txdrc,
2662 pvt->law);
2663 }
2664 if (res < 0) {
2665 ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pvt->channel);
2666 }
2667
2668 if (pvt->dsp_features && pvt->dsp) {
2670 }
2671}
2672#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2673
2674#if defined(HAVE_PRI)
2675/*!
2676 * \internal
2677 * \brief Ask DAHDI to dial the given dial string.
2678 * \since 1.8.11
2679 *
2680 * \param p Channel private control structure.
2681 * \param dial_string String to pass to DAHDI to dial.
2682 *
2683 * \note The channel private lock needs to be held when calling.
2684 */
2685static void my_pri_dial_digits(void *p, const char *dial_string)
2686{
2687 char dial_str[DAHDI_MAX_DTMF_BUF];
2688 struct dahdi_pvt *pvt = p;
2689 int res;
2690
2691 snprintf(dial_str, sizeof(dial_str), "T%s", dial_string);
2692 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
2693 if (!res) {
2694 pvt->dialing = 1;
2695 }
2696}
2697#endif /* defined(HAVE_PRI) */
2698
2699static int unalloc_sub(struct dahdi_pvt *p, int x);
2700
2701static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
2702{
2703 struct dahdi_pvt *p = pvt;
2704
2705 return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
2706}
2707
2708static int alloc_sub(struct dahdi_pvt *p, int x);
2709
2710static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
2711{
2712 struct dahdi_pvt *p = pvt;
2713
2714 return alloc_sub(p, analogsub_to_dahdisub(analogsub));
2715}
2716
2717static int has_voicemail(struct dahdi_pvt *p);
2718
2719static int my_has_voicemail(void *pvt)
2720{
2721 struct dahdi_pvt *p = pvt;
2722
2723 return has_voicemail(p);
2724}
2725
2726static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
2727{
2728 struct dahdi_pvt *p = pvt;
2729 int index;
2730
2731 index = analogsub_to_dahdisub(sub);
2732
2733 return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
2734}
2735
2737{
2738 enum analog_event res;
2739
2740 switch (event) {
2741 case DAHDI_EVENT_ONHOOK:
2742 res = ANALOG_EVENT_ONHOOK;
2743 break;
2744 case DAHDI_EVENT_RINGOFFHOOK:
2746 break;
2747 case DAHDI_EVENT_WINKFLASH:
2749 break;
2750 case DAHDI_EVENT_ALARM:
2751 res = ANALOG_EVENT_ALARM;
2752 break;
2753 case DAHDI_EVENT_NOALARM:
2755 break;
2756 case DAHDI_EVENT_DIALCOMPLETE:
2758 break;
2759 case DAHDI_EVENT_RINGERON:
2761 break;
2762 case DAHDI_EVENT_RINGEROFF:
2764 break;
2765 case DAHDI_EVENT_HOOKCOMPLETE:
2767 break;
2768 case DAHDI_EVENT_PULSE_START:
2770 break;
2771 case DAHDI_EVENT_POLARITY:
2773 break;
2774 case DAHDI_EVENT_RINGBEGIN:
2776 break;
2777 case DAHDI_EVENT_EC_DISABLED:
2779 break;
2780 case DAHDI_EVENT_REMOVED:
2782 break;
2783 case DAHDI_EVENT_NEONMWI_ACTIVE:
2785 break;
2786 case DAHDI_EVENT_NEONMWI_INACTIVE:
2788 break;
2789#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
2790 case DAHDI_EVENT_TX_CED_DETECTED:
2792 break;
2793 case DAHDI_EVENT_RX_CED_DETECTED:
2795 break;
2796 case DAHDI_EVENT_EC_NLP_DISABLED:
2798 break;
2799 case DAHDI_EVENT_EC_NLP_ENABLED:
2801 break;
2802#endif
2803 case DAHDI_EVENT_PULSEDIGIT:
2805 break;
2806 case DAHDI_EVENT_DTMFDOWN:
2808 break;
2809 case DAHDI_EVENT_DTMFUP:
2810 res = ANALOG_EVENT_DTMFUP;
2811 break;
2812 default:
2813 switch(event & 0xFFFF0000) {
2814 case DAHDI_EVENT_PULSEDIGIT:
2815 case DAHDI_EVENT_DTMFDOWN:
2816 case DAHDI_EVENT_DTMFUP:
2817 /* The event includes a digit number in the low word.
2818 * Converting it to a 'enum analog_event' would remove
2819 * that information. Thus it is returned as-is.
2820 */
2821 return event;
2822 }
2823
2824 res = ANALOG_EVENT_ERROR;
2825 break;
2826 }
2827
2828 return res;
2829}
2830
2831static inline int dahdi_wait_event(int fd);
2832
2833static int my_wait_event(void *pvt)
2834{
2835 struct dahdi_pvt *p = pvt;
2836
2837 return dahdi_wait_event(p->subs[SUB_REAL].dfd);
2838}
2839
2840static int my_get_event(void *pvt)
2841{
2842 struct dahdi_pvt *p = pvt;
2843 int res;
2844
2845 if (p->fake_event) {
2846 res = p->fake_event;
2847 p->fake_event = 0;
2848 } else
2849 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
2850
2851 return dahdievent_to_analogevent(res);
2852}
2853
2854static int my_is_off_hook(void *pvt)
2855{
2856 struct dahdi_pvt *p = pvt;
2857 int res;
2858 struct dahdi_params par;
2859
2860 memset(&par, 0, sizeof(par));
2861
2862 if (p->subs[SUB_REAL].dfd > -1)
2863 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
2864 else {
2865 /* Assume not off hook on CVRS */
2866 res = 0;
2867 par.rxisoffhook = 0;
2868 }
2869 if (res) {
2870 ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
2871 }
2872
2873 if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
2874 /* When "onhook" that means no battery on the line, and thus
2875 it is out of service..., if it's on a TDM card... If it's a channel
2876 bank, there is no telling... */
2877 return (par.rxbits > -1) || par.rxisoffhook;
2878 }
2879
2880 return par.rxisoffhook;
2881}
2882
2883static int my_set_echocanceller(void *pvt, int enable)
2884{
2885 struct dahdi_pvt *p = pvt;
2886
2887 if (enable)
2888 dahdi_ec_enable(p);
2889 else
2891
2892 return 0;
2893}
2894
2895static int dahdi_ring_phone(struct dahdi_pvt *p);
2896
2897static int my_ring(void *pvt)
2898{
2899 struct dahdi_pvt *p = pvt;
2900
2901 return dahdi_ring_phone(p);
2902}
2903
2904static int my_flash(void *pvt)
2905{
2906 struct dahdi_pvt *p = pvt;
2907 int func = DAHDI_FLASH;
2908 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &func);
2909}
2910
2911static inline int dahdi_set_hook(int fd, int hs);
2912
2913static int my_off_hook(void *pvt)
2914{
2915 struct dahdi_pvt *p = pvt;
2916 return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
2917}
2918
2919static void my_set_needringing(void *pvt, int value)
2920{
2921 struct dahdi_pvt *p = pvt;
2923}
2924
2925static void my_set_polarity(void *pvt, int value)
2926{
2927 struct dahdi_pvt *p = pvt;
2928
2929 if (p->channel == CHAN_PSEUDO) {
2930 return;
2931 }
2932 p->polarity = value;
2933 ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETPOLARITY, &value);
2934}
2935
2936static void my_start_polarityswitch(void *pvt)
2937{
2938 struct dahdi_pvt *p = pvt;
2939
2941 my_set_polarity(pvt, 0);
2942 }
2943}
2944
2945static void my_answer_polarityswitch(void *pvt)
2946{
2947 struct dahdi_pvt *p = pvt;
2948
2949 if (!p->answeronpolarityswitch) {
2950 return;
2951 }
2952
2953 my_set_polarity(pvt, 1);
2954}
2955
2956static void my_hangup_polarityswitch(void *pvt)
2957{
2958 struct dahdi_pvt *p = pvt;
2959
2960 if (!p->hanguponpolarityswitch) {
2961 return;
2962 }
2963
2964 if (p->answeronpolarityswitch) {
2965 my_set_polarity(pvt, 0);
2966 } else {
2967 my_set_polarity(pvt, 1);
2968 }
2969}
2970
2971static int my_start(void *pvt)
2972{
2973 struct dahdi_pvt *p = pvt;
2974 int x = DAHDI_START;
2975
2976 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
2977}
2978
2979static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
2980{
2981 struct dahdi_pvt *p = pvt;
2982
2983 if (dop->op != ANALOG_DIAL_OP_REPLACE) {
2984 ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
2985 return -1;
2986 }
2987
2988 if (sub != ANALOG_SUB_REAL) {
2989 ast_log(LOG_ERROR, "Trying to dial_digits '%s' on channel %d subchannel %u\n",
2990 dop->dialstr, p->channel, sub);
2991 return -1;
2992 }
2993
2994 return dahdi_dial_str(p, DAHDI_DIAL_OP_REPLACE, dop->dialstr);
2995}
2996
2997static void dahdi_train_ec(struct dahdi_pvt *p);
2998
2999static int my_train_echocanceller(void *pvt)
3000{
3001 struct dahdi_pvt *p = pvt;
3002
3003 dahdi_train_ec(p);
3004
3005 return 0;
3006}
3007
3008static int my_is_dialing(void *pvt, enum analog_sub sub)
3009{
3010 struct dahdi_pvt *p = pvt;
3011 int index;
3012 int x;
3013
3014 index = analogsub_to_dahdisub(sub);
3015
3016 if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
3017 ast_debug(1, "DAHDI_DIALING ioctl failed!\n");
3018 return -1;
3019 }
3020
3021 return x;
3022}
3023
3024static int my_on_hook(void *pvt)
3025{
3026 struct dahdi_pvt *p = pvt;
3027 return dahdi_set_hook(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_ONHOOK);
3028}
3029
3030#if defined(HAVE_PRI)
3031static void my_pri_fixup_chans(void *chan_old, void *chan_new)
3032{
3033 struct dahdi_pvt *old_chan = chan_old;
3034 struct dahdi_pvt *new_chan = chan_new;
3035
3036 new_chan->owner = old_chan->owner;
3037 old_chan->owner = NULL;
3038 if (new_chan->owner) {
3039 ast_channel_tech_pvt_set(new_chan->owner, new_chan);
3040 ast_channel_internal_fd_set(new_chan->owner, 0, new_chan->subs[SUB_REAL].dfd);
3041 new_chan->subs[SUB_REAL].owner = old_chan->subs[SUB_REAL].owner;
3042 old_chan->subs[SUB_REAL].owner = NULL;
3043 }
3044 /* Copy any DSP that may be present */
3045 new_chan->dsp = old_chan->dsp;
3046 new_chan->dsp_features = old_chan->dsp_features;
3047 old_chan->dsp = NULL;
3048 old_chan->dsp_features = 0;
3049
3050 /* Transfer flags from the old channel. */
3051 new_chan->dialing = old_chan->dialing;
3052 new_chan->digital = old_chan->digital;
3053 new_chan->outgoing = old_chan->outgoing;
3054 old_chan->dialing = 0;
3055 old_chan->digital = 0;
3056 old_chan->outgoing = 0;
3057
3058 /* More stuff to transfer to the new channel. */
3059 new_chan->law = old_chan->law;
3060 strcpy(new_chan->dialstring, old_chan->dialstring);
3061}
3062#endif /* defined(HAVE_PRI) */
3063
3064#if defined(HAVE_PRI)
3065static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
3066{
3067 switch (tone) {
3069 return DAHDI_TONE_RINGTONE;
3071 return DAHDI_TONE_STUTTER;
3073 return DAHDI_TONE_CONGESTION;
3075 return DAHDI_TONE_DIALTONE;
3077 return DAHDI_TONE_DIALRECALL;
3078 case SIG_PRI_TONE_INFO:
3079 return DAHDI_TONE_INFO;
3080 case SIG_PRI_TONE_BUSY:
3081 return DAHDI_TONE_BUSY;
3082 default:
3083 return -1;
3084 }
3085}
3086#endif /* defined(HAVE_PRI) */
3087
3088#if defined(HAVE_PRI)
3089static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
3090{
3091 int x;
3092
3093 ioctl(pri->fds[index], DAHDI_GETEVENT, &x);
3094 switch (x) {
3095 case DAHDI_EVENT_NONE:
3096 break;
3097 case DAHDI_EVENT_ALARM:
3098 case DAHDI_EVENT_NOALARM:
3099 if (sig_pri_is_alarm_ignored(pri)) {
3100 break;
3101 }
3102 /* Fall through */
3103 default:
3104 ast_log(LOG_NOTICE, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
3105 event2str(x), x, pri->span);
3106 break;
3107 }
3108 /* Keep track of alarm state */
3109 switch (x) {
3110 case DAHDI_EVENT_ALARM:
3111 pri_event_alarm(pri, index, 0);
3112 break;
3113 case DAHDI_EVENT_NOALARM:
3114 pri_event_noalarm(pri, index, 0);
3115 break;
3116 case DAHDI_EVENT_REMOVED:
3117 pri_queue_for_destruction(pri);
3118 break;
3119 default:
3120 break;
3121 }
3122}
3123#endif /* defined(HAVE_PRI) */
3124
3125#if defined(HAVE_PRI)
3126static int my_pri_play_tone(void *pvt, enum sig_pri_tone tone)
3127{
3128 struct dahdi_pvt *p = pvt;
3129
3130 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_pri_tone_to_dahditone(tone));
3131}
3132#endif /* defined(HAVE_PRI) */
3133
3134#if defined(HAVE_PRI) || defined(HAVE_SS7)
3135/*!
3136 * \internal
3137 * \brief Set the caller id information.
3138 * \since 1.8
3139 *
3140 * \param pvt DAHDI private structure
3141 * \param caller Caller-id information to set.
3142 */
3143static void my_set_callerid(void *pvt, const struct ast_party_caller *caller)
3144{
3145 struct dahdi_pvt *p = pvt;
3146
3148 S_COR(caller->id.number.valid, caller->id.number.str, ""),
3149 sizeof(p->cid_num));
3151 S_COR(caller->id.name.valid, caller->id.name.str, ""),
3152 sizeof(p->cid_name));
3154 S_COR(caller->id.subaddress.valid, caller->id.subaddress.str, ""),
3155 sizeof(p->cid_subaddr));
3156 p->cid_ton = caller->id.number.plan;
3158 if (caller->id.tag) {
3159 ast_copy_string(p->cid_tag, caller->id.tag, sizeof(p->cid_tag));
3160 }
3161 ast_copy_string(p->cid_ani,
3162 S_COR(caller->ani.number.valid, caller->ani.number.str, ""),
3163 sizeof(p->cid_ani));
3164 p->cid_ani2 = caller->ani2;
3165}
3166#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3167
3168#if defined(HAVE_PRI) || defined(HAVE_SS7)
3169/*!
3170 * \internal
3171 * \brief Set the Dialed Number Identifier.
3172 * \since 1.8
3173 *
3174 * \param pvt DAHDI private structure
3175 * \param dnid Dialed Number Identifier string.
3176 */
3177static void my_set_dnid(void *pvt, const char *dnid)
3178{
3179 struct dahdi_pvt *p = pvt;
3180
3181 ast_copy_string(p->dnid, dnid, sizeof(p->dnid));
3182}
3183#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3184
3185#if defined(HAVE_PRI)
3186/*!
3187 * \internal
3188 * \brief Set the Redirecting Directory Number Information Service (RDNIS).
3189 * \since 1.8
3190 *
3191 * \param pvt DAHDI private structure
3192 * \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
3193 */
3194static void my_set_rdnis(void *pvt, const char *rdnis)
3195{
3196 struct dahdi_pvt *p = pvt;
3197
3198 ast_copy_string(p->rdnis, rdnis, sizeof(p->rdnis));
3199}
3200#endif /* defined(HAVE_PRI) */
3201
3202#if defined(HAVE_PRI)
3203/*!
3204 * \internal
3205 * \brief Make a dialstring for native ISDN CC to recall properly.
3206 * \since 1.8
3207 *
3208 * \param priv Channel private control structure.
3209 * \param buf Where to put the modified dialstring.
3210 * \param buf_size Size of modified dialstring buffer.
3211 *
3212 * \details
3213 * original dialstring:
3214 * \verbatim
3215 DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3216 \endverbatim
3217 *
3218 * The modified dialstring will have prefixed the channel-group section
3219 * with the ISDN channel restriction.
3220 *
3221 * buf:
3222 * \verbatim
3223 DAHDI/i<span>-(g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3224 \endverbatim
3225 *
3226 * The routine will check to see if the ISDN channel restriction is already
3227 * in the original dialstring.
3228 */
3229static void my_pri_make_cc_dialstring(void *priv, char *buf, size_t buf_size)
3230{
3231 char *dial;
3232 struct dahdi_pvt *pvt;
3234 AST_APP_ARG(tech); /* channel technology token */
3235 AST_APP_ARG(group); /* channel/group token */
3236 //AST_APP_ARG(ext); /* extension token */
3237 //AST_APP_ARG(opts); /* options token */
3238 //AST_APP_ARG(other); /* Any remaining unused arguments */
3239 );
3240
3241 pvt = priv;
3242 dial = ast_strdupa(pvt->dialstring);
3243 AST_NONSTANDARD_APP_ARGS(args, dial, '/');
3244 if (!args.tech) {
3245 ast_copy_string(buf, pvt->dialstring, buf_size);
3246 return;
3247 }
3248 if (!args.group) {
3249 /* Append the ISDN span channel restriction to the dialstring. */
3250 snprintf(buf, buf_size, "%s/i%d-", args.tech, pvt->pri->span);
3251 return;
3252 }
3253 if (isdigit(args.group[0]) || args.group[0] == 'i' || strchr(args.group, '!')) {
3254 /* The ISDN span channel restriction is not needed or already
3255 * in the dialstring. */
3256 ast_copy_string(buf, pvt->dialstring, buf_size);
3257 return;
3258 }
3259 /* Insert the ISDN span channel restriction into the dialstring. */
3260 snprintf(buf, buf_size, "%s/i%d-%s", args.tech, pvt->pri->span, args.group);
3261}
3262#endif /* defined(HAVE_PRI) */
3263
3264#if defined(HAVE_PRI)
3265/*!
3266 * \internal
3267 * \brief Reevaluate the PRI span device state.
3268 * \since 1.8
3269 *
3270 * \param pri Asterisk D channel control structure.
3271 *
3272 * \note Assumes the pri->lock is already obtained.
3273 */
3274static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
3275{
3276 unsigned idx;
3277 unsigned num_b_chans; /* Number of B channels provisioned on the span. */
3278 unsigned in_use; /* Number of B channels in use on the span. */
3279 unsigned in_alarm; /* TRUE if the span is in alarm condition. */
3280 enum ast_device_state new_state;
3281
3282 /* Count the number of B channels and the number of B channels in use. */
3283 num_b_chans = 0;
3284 in_use = 0;
3285 in_alarm = 1;
3286 for (idx = pri->numchans; idx--;) {
3287 if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
3288 /* This is a B channel interface. */
3289 ++num_b_chans;
3290 if (!sig_pri_is_chan_available(pri->pvts[idx])) {
3291 ++in_use;
3292 }
3293 if (!pri->pvts[idx]->inalarm) {
3294 /* There is a channel that is not in alarm. */
3295 in_alarm = 0;
3296 }
3297 }
3298 }
3299
3300 /* Update the span congestion device state and report any change. */
3301 if (in_alarm) {
3302 new_state = AST_DEVICE_UNAVAILABLE;
3303 } else {
3304 new_state = num_b_chans == in_use ? AST_DEVICE_BUSY : AST_DEVICE_NOT_INUSE;
3305 }
3306 if (pri->congestion_devstate != new_state) {
3307 pri->congestion_devstate = new_state;
3309 }
3310#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
3311 /* Update the span threshold device state and report any change. */
3312 if (in_alarm) {
3313 new_state = AST_DEVICE_UNAVAILABLE;
3314 } else if (!in_use) {
3315 new_state = AST_DEVICE_NOT_INUSE;
3316 } else if (!pri->user_busy_threshold) {
3317 new_state = in_use < num_b_chans ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
3318 } else {
3319 new_state = in_use < pri->user_busy_threshold ? AST_DEVICE_INUSE
3321 }
3322 if (pri->threshold_devstate != new_state) {
3323 pri->threshold_devstate = new_state;
3325 }
3326#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
3327}
3328#endif /* defined(HAVE_PRI) */
3329
3330#if defined(HAVE_PRI)
3331/*!
3332 * \internal
3333 * \brief Reference this module.
3334 * \since 1.8
3335 */
3336static void my_module_ref(void)
3337{
3339}
3340#endif /* defined(HAVE_PRI) */
3341
3342#if defined(HAVE_PRI)
3343/*!
3344 * \internal
3345 * \brief Unreference this module.
3346 * \since 1.8
3347 */
3348static void my_module_unref(void)
3349{
3351}
3352#endif /* defined(HAVE_PRI) */
3353
3354#if defined(HAVE_PRI)
3355#if defined(HAVE_PRI_CALL_WAITING)
3356static void my_pri_init_config(void *priv, struct sig_pri_span *pri);
3357#endif /* defined(HAVE_PRI_CALL_WAITING) */
3358static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri);
3359
3361{
3362 .handle_dchan_exception = my_handle_dchan_exception,
3363 .play_tone = my_pri_play_tone,
3364 .set_echocanceller = my_set_echocanceller,
3365 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3366 .lock_private = my_lock_private,
3367 .unlock_private = my_unlock_private,
3368 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3369 .new_ast_channel = my_new_pri_ast_channel,
3370 .fixup_chans = my_pri_fixup_chans,
3371 .set_alarm = my_set_alarm,
3372 .set_dialing = my_set_dialing,
3373 .set_outgoing = my_set_outgoing,
3374 .set_digital = my_set_digital,
3375 .set_callerid = my_set_callerid,
3376 .set_dnid = my_set_dnid,
3377 .set_rdnis = my_set_rdnis,
3378 .new_nobch_intf = dahdi_new_pri_nobch_channel,
3379#if defined(HAVE_PRI_CALL_WAITING)
3380 .init_config = my_pri_init_config,
3381#endif /* defined(HAVE_PRI_CALL_WAITING) */
3382 .get_orig_dialstring = my_get_orig_dialstring,
3383 .make_cc_dialstring = my_pri_make_cc_dialstring,
3384 .update_span_devstate = dahdi_pri_update_span_devstate,
3385 .module_ref = my_module_ref,
3386 .module_unref = my_module_unref,
3387 .dial_digits = my_pri_dial_digits,
3388 .open_media = my_pri_ss7_open_media,
3389 .ami_channel_event = my_ami_channel_event,
3390 .destroy_later = pri_queue_for_destruction,
3391};
3392#endif /* defined(HAVE_PRI) */
3393
3394#if defined(HAVE_SS7)
3395/*!
3396 * \internal
3397 * \brief Handle the SS7 link exception.
3398 * \since 1.8
3399 *
3400 * \param linkset Controlling linkset for the channel.
3401 * \param which Link index of the signaling channel.
3402 */
3403static void my_handle_link_exception(struct sig_ss7_linkset *linkset, int which)
3404{
3405 int event;
3406
3407 if (ioctl(linkset->fds[which], DAHDI_GETEVENT, &event)) {
3408 ast_log(LOG_ERROR, "SS7: Error in exception retrieval on span %d/%d!\n",
3409 linkset->span, which);
3410 return;
3411 }
3412 switch (event) {
3413 case DAHDI_EVENT_NONE:
3414 break;
3415 case DAHDI_EVENT_ALARM:
3416 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3417 event2str(event), event, linkset->span, which);
3418 sig_ss7_link_alarm(linkset, which);
3419 break;
3420 case DAHDI_EVENT_NOALARM:
3421 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3422 event2str(event), event, linkset->span, which);
3423 sig_ss7_link_noalarm(linkset, which);
3424 break;
3425 default:
3426 ast_log(LOG_NOTICE, "SS7 got event: %s(%d) on span %d/%d\n",
3427 event2str(event), event, linkset->span, which);
3428 break;
3429 }
3430}
3431#endif /* defined(HAVE_SS7) */
3432
3433#if defined(HAVE_SS7)
3434static void my_ss7_set_loopback(void *pvt, int enable)
3435{
3436 struct dahdi_pvt *p = pvt;
3437
3438 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
3439 ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel,
3440 strerror(errno));
3441 }
3442}
3443#endif /* defined(HAVE_SS7) */
3444
3445#if defined(HAVE_SS7)
3446/*!
3447 * \internal
3448 * \brief Find the linkset to which SS7 belongs.
3449 * \since 11.0
3450 *
3451 * \param ss7 structure to match on.
3452 *
3453 * \retval linkset if found.
3454 * \retval NULL if not found.
3455 */
3456static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
3457{
3458 int idx;
3459
3460 if (!ss7) {
3461 return NULL;
3462 }
3463
3464 for (idx = 0; idx < NUM_SPANS; ++idx) {
3465 if (linksets[idx].ss7.ss7 == ss7) {
3466 return &linksets[idx].ss7;
3467 }
3468 }
3469 return NULL;
3470}
3471#endif /* defined(HAVE_SS7) */
3472
3473#if defined(HAVE_SS7)
3474/*!
3475 * \internal
3476 * \brief Create a new asterisk channel structure for SS7.
3477 * \since 1.8
3478 *
3479 * \param pvt Private channel structure.
3480 * \param state Initial state of new channel.
3481 * \param law Companding law to use.
3482 * \param exten Dialplan extension for incoming call.
3483 * \param requestor Channel requesting this new channel.
3484 * \param assignedids
3485 *
3486 * \retval ast_channel on success.
3487 * \retval NULL on error.
3488 */
3489static 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)
3490{
3491 struct dahdi_pvt *p = pvt;
3492 int audio;
3493 int newlaw;
3494 ast_callid callid = 0;
3495 int callid_created = ast_callid_threadstorage_auto(&callid);
3496
3497 /* Set to audio mode at this point */
3498 audio = 1;
3499 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1)
3500 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
3501 p->channel, audio, strerror(errno));
3502
3503 if (law != SIG_SS7_DEFLAW) {
3504 dahdi_setlaw(p->subs[SUB_REAL].dfd,
3505 (law == SIG_SS7_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
3506 }
3507
3508 ast_copy_string(p->exten, exten, sizeof(p->exten));
3509
3510 newlaw = -1;
3511 switch (law) {
3512 case SIG_SS7_DEFLAW:
3513 newlaw = 0;
3514 break;
3515 case SIG_SS7_ALAW:
3516 newlaw = DAHDI_LAW_ALAW;
3517 break;
3518 case SIG_SS7_ULAW:
3519 newlaw = DAHDI_LAW_MULAW;
3520 break;
3521 }
3522 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
3523}
3524#endif /* defined(HAVE_SS7) */
3525
3526#if defined(HAVE_SS7)
3527static int sig_ss7_tone_to_dahditone(enum sig_ss7_tone tone)
3528{
3529 switch (tone) {
3531 return DAHDI_TONE_RINGTONE;
3533 return DAHDI_TONE_STUTTER;
3535 return DAHDI_TONE_CONGESTION;
3537 return DAHDI_TONE_DIALTONE;
3539 return DAHDI_TONE_DIALRECALL;
3540 case SIG_SS7_TONE_INFO:
3541 return DAHDI_TONE_INFO;
3542 case SIG_SS7_TONE_BUSY:
3543 return DAHDI_TONE_BUSY;
3544 default:
3545 return -1;
3546 }
3547}
3548#endif /* defined(HAVE_SS7) */
3549
3550#if defined(HAVE_SS7)
3551static int my_ss7_play_tone(void *pvt, enum sig_ss7_tone tone)
3552{
3553 struct dahdi_pvt *p = pvt;
3554
3555 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_ss7_tone_to_dahditone(tone));
3556}
3557#endif /* defined(HAVE_SS7) */
3558
3559#if defined(HAVE_SS7)
3561{
3563 .unlock_private = my_unlock_private,
3564 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3565
3566 .set_echocanceller = my_set_echocanceller,
3567 .set_loopback = my_ss7_set_loopback,
3568
3569 .new_ast_channel = my_new_ss7_ast_channel,
3570 .play_tone = my_ss7_play_tone,
3571
3572 .handle_link_exception = my_handle_link_exception,
3573 .set_alarm = my_set_alarm,
3574 .set_dialing = my_set_dialing,
3575 .set_outgoing = my_set_outgoing,
3576 .set_digital = my_set_digital,
3577 .set_inservice = my_set_inservice,
3578 .set_locallyblocked = my_set_locallyblocked,
3579 .set_remotelyblocked = my_set_remotelyblocked,
3580 .set_callerid = my_set_callerid,
3581 .set_dnid = my_set_dnid,
3582 .open_media = my_pri_ss7_open_media,
3583 .find_linkset = my_ss7_find_linkset,
3584};
3585#endif /* defined(HAVE_SS7) */
3586
3587/*!
3588 * \brief Send MWI state change
3589 *
3590 * \param mailbox This is the mailbox associated with the FXO line that the
3591 * MWI state has changed on.
3592 * \param thereornot This argument should simply be set to 1 or 0, to indicate
3593 * whether there are messages waiting or not.
3594 *
3595 * This function does two things:
3596 *
3597 * 1) It generates an internal Asterisk event notifying any other module that
3598 * cares about MWI that the state of a mailbox has changed.
3599 *
3600 * 2) It runs the script specified by the mwimonitornotify option to allow
3601 * some custom handling of the state change.
3602 */
3603static void notify_message(char *mailbox, int thereornot)
3604{
3605 char s[sizeof(mwimonitornotify) + 164];
3606
3607 if (ast_strlen_zero(mailbox)) {
3608 return;
3609 }
3610
3611 ast_publish_mwi_state(mailbox, NULL, thereornot, thereornot);
3613 snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
3614 ast_safe_system(s);
3615 }
3616}
3617
3618static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
3619{
3620 struct dahdi_pvt *p = pvt;
3621
3622 if (neon_mwievent > -1 && !p->mwimonitor_neon)
3623 return;
3624
3625 if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
3626 ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
3627 notify_message(p->mailbox, 1);
3628 } else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
3629 ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
3630 notify_message(p->mailbox, 0);
3631 }
3632 /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
3633 /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
3634 if (neon_mwievent == -1 && p->mwimonitor_rpas) {
3635 ast_hangup(chan);
3636 return;
3637 }
3638}
3639
3640static int my_have_progressdetect(void *pvt)
3641{
3642 struct dahdi_pvt *p = pvt;
3643
3645 && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
3646 return 1;
3647 } else {
3648 /* Don't have progress detection. */
3649 return 0;
3650 }
3651}
3652
3653#define gen_pvt_field_callback(type, field) \
3654 static type my_get_##field(void *pvt) \
3655 { \
3656 struct dahdi_pvt *p = pvt; \
3657 return p->field; \
3658 }
3659
3663
3664#undef gen_pvt_field_callback
3665
3667{
3669 .get_event = my_get_event,
3670 .wait_event = my_wait_event,
3671 .is_off_hook = my_is_off_hook,
3672 .set_echocanceller = my_set_echocanceller,
3673 .ring = my_ring,
3674 .flash = my_flash,
3675 .off_hook = my_off_hook,
3676 .dial_digits = my_dial_digits,
3677 .train_echocanceller = my_train_echocanceller,
3678 .on_hook = my_on_hook,
3679 .is_dialing = my_is_dialing,
3680 .allocate_sub = my_allocate_sub,
3681 .unallocate_sub = my_unallocate_sub,
3682 .swap_subs = my_swap_subchannels,
3683 .has_voicemail = my_has_voicemail,
3684 .check_for_conference = my_check_for_conference,
3685 .conf_add = my_conf_add,
3686 .conf_del = my_conf_del,
3687 .complete_conference_update = my_complete_conference_update,
3688 .start = my_start,
3689 .all_subchannels_hungup = my_all_subchannels_hungup,
3690 .lock_private = my_lock_private,
3691 .unlock_private = my_unlock_private,
3692 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3693 .handle_dtmf = my_handle_dtmf,
3694 .wink = my_wink,
3695 .new_ast_channel = my_new_analog_ast_channel,
3696 .dsp_set_digitmode = my_dsp_set_digitmode,
3697 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3698 .send_callerid = my_send_callerid,
3699 .callwait = my_callwait,
3700 .stop_callwait = my_stop_callwait,
3701 .get_callerid = my_get_callerid,
3702 .start_cid_detect = my_start_cid_detect,
3703 .stop_cid_detect = my_stop_cid_detect,
3704 .handle_notify_message = my_handle_notify_message,
3705 .increase_ss_count = my_increase_ss_count,
3706 .decrease_ss_count = my_decrease_ss_count,
3707 .distinctive_ring = my_distinctive_ring,
3708 .set_linear_mode = my_set_linear_mode,
3709 .set_inthreeway = my_set_inthreeway,
3710 .get_and_handle_alarms = my_get_and_handle_alarms,
3711 .get_sigpvt_bridged_channel = my_get_sigpvt_bridged_channel,
3712 .get_sub_fd = my_get_sub_fd,
3713 .set_cadence = my_set_cadence,
3714 .set_alarm = my_set_alarm,
3715 .set_dialing = my_set_dialing,
3716 .set_outgoing = my_set_outgoing,
3717 .set_ringtimeout = my_set_ringtimeout,
3718 .set_waitingfordt = my_set_waitingfordt,
3719 .check_waitingfordt = my_check_waitingfordt,
3720 .set_confirmanswer = my_set_confirmanswer,
3721 .check_confirmanswer = my_check_confirmanswer,
3722 .set_callwaiting = my_set_callwaiting,
3723 .cancel_cidspill = my_cancel_cidspill,
3724 .confmute = my_confmute,
3725 .set_pulsedial = my_set_pulsedial,
3726 .set_new_owner = my_set_new_owner,
3727 .get_orig_dialstring = my_get_orig_dialstring,
3728 .set_needringing = my_set_needringing,
3729 .set_polarity = my_set_polarity,
3730 .start_polarityswitch = my_start_polarityswitch,
3731 .answer_polarityswitch = my_answer_polarityswitch,
3732 .hangup_polarityswitch = my_hangup_polarityswitch,
3733 .have_progressdetect = my_have_progressdetect,
3734 .get_firstdigit_timeout = my_get_firstdigit_timeout,
3735 .get_matchdigit_timeout = my_get_matchdigit_timeout,
3736 .get_interdigit_timeout = my_get_interdigit_timeout,
3737};
3738
3739/*! Round robin search locations. */
3740static struct dahdi_pvt *round_robin[64]; /* groups can range from 0-63 */
3741
3742int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
3743{
3744 int res;
3745 if (p->subs[SUB_REAL].owner == ast)
3746 res = 0;
3747 else if (p->subs[SUB_CALLWAIT].owner == ast)
3748 res = 1;
3749 else if (p->subs[SUB_THREEWAY].owner == ast)
3750 res = 2;
3751 else {
3752 res = -1;
3753 if (!nullok)
3755 "Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
3756 ast ? ast_channel_name(ast) : "", p->channel, fname, line);
3757 }
3758 return res;
3759}
3760
3761/*!
3762 * \internal
3763 * \brief Obtain the specified subchannel owner lock if the owner exists.
3764 *
3765 * \param pvt Channel private struct.
3766 * \param sub_idx Subchannel owner to lock.
3767 *
3768 * \note Assumes the pvt->lock is already obtained.
3769 *
3770 * \note
3771 * Because deadlock avoidance may have been necessary, you need to confirm
3772 * the state of things before continuing.
3773 */
3774static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
3775{
3776 for (;;) {
3777 if (!pvt->subs[sub_idx].owner) {
3778 /* No subchannel owner pointer */
3779 break;
3780 }
3781 if (!ast_channel_trylock(pvt->subs[sub_idx].owner)) {
3782 /* Got subchannel owner lock */
3783 break;
3784 }
3785 /* We must unlock the private to avoid the possibility of a deadlock */
3786 DEADLOCK_AVOIDANCE(&pvt->lock);
3787 }
3788}
3789
3790static void wakeup_sub(struct dahdi_pvt *p, int a)
3791{
3793 if (p->subs[a].owner) {
3796 }
3797}
3798
3799static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
3800{
3801 for (;;) {
3802 if (p->owner) {
3803 if (ast_channel_trylock(p->owner)) {
3805 } else {
3806 ast_queue_frame(p->owner, f);
3808 break;
3809 }
3810 } else
3811 break;
3812 }
3813}
3814
3816{
3817 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3818 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
3819 if (!dahdi_chan) {
3820 return;
3821 }
3822
3823 ast_str_set(&dahdi_chan, 0, "%d", channel);
3824 ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
3825 body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
3826 if (!body) {
3827 return;
3828 }
3829
3830 ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
3831}
3832
3834{
3835 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3836
3837 ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
3838 body = ast_json_pack("{s: i}", "Span", span);
3839 if (!body) {
3840 return;
3841 }
3842
3843 ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
3844}
3845
3846static void handle_clear_alarms(struct dahdi_pvt *p)
3847{
3848#if defined(HAVE_PRI)
3850 return;
3851 }
3852#endif /* defined(HAVE_PRI) */
3853
3856 }
3859 }
3860}
3861
3862#ifdef HAVE_OPENR2
3863static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
3864{
3865 const struct dahdi_mfcr2 *r2link = p->mfcr2;
3866 struct r2link_entry *cur;
3867 AST_LIST_LOCK(&r2links);
3868 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
3869 if (r2link == &cur->mfcr2) {
3870 ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
3871 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
3872 break;
3873 }
3874 }
3876 AST_LIST_UNLOCK(&r2links);
3877}
3878
3879static int dahdi_r2_answer(struct dahdi_pvt *p)
3880{
3881 int res = 0;
3882 /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
3883 * and does not has support for openr2_chan_answer_call_with_mode
3884 * */
3885#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
3886 const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
3887 int wants_double_answer = ast_true(double_answer) ? 1 : 0;
3888 if (!double_answer) {
3889 /* this still can result in double answer if the channel context
3890 * was configured that way */
3891 res = openr2_chan_answer_call(p->r2chan);
3892 } else if (wants_double_answer) {
3893 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
3894 } else {
3895 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
3896 }
3897#else
3898 res = openr2_chan_answer_call(p->r2chan);
3899#endif
3900 return res;
3901}
3902
3903
3904
3905/* should be called with the ast_channel locked */
3906static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
3907{
3908 openr2_calling_party_category_t cat;
3909 const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
3910 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
3911 if (ast_strlen_zero(catstr)) {
3912 ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
3913 ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3914 return p->mfcr2_category;
3915 }
3916 if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
3917 ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
3918 catstr, ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3919 return p->mfcr2_category;
3920 }
3921 ast_debug(1, "Using category %s\n", catstr);
3922 return cat;
3923}
3924
3925static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
3926{
3927 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3928 ast_mutex_lock(&p->lock);
3929 if (p->mfcr2call) {
3931 /* TODO: This can happen when some other thread just finished dahdi_request requesting this very same
3932 interface but has not yet seized the line (dahdi_call), and the far end wins and seize the line,
3933 can we avoid this somehow?, at this point when dahdi_call send the seize, it is likely that since
3934 the other end will see our seize as a forced release and drop the call, we will see an invalid
3935 pattern that will be seen and treated as protocol error. */
3936 ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
3937 return;
3938 }
3939 p->mfcr2call = 1;
3940 /* better safe than sorry ... */
3941 p->cid_name[0] = '\0';
3942 p->cid_num[0] = '\0';
3943 p->cid_subaddr[0] = '\0';
3944 p->rdnis[0] = '\0';
3945 p->exten[0] = '\0';
3946 p->mfcr2_ani_index = '\0';
3947 p->mfcr2_dnis_index = '\0';
3948 p->mfcr2_dnis_matched = 0;
3949 p->mfcr2_answer_pending = 0;
3950 p->mfcr2_call_accepted = 0;
3952 ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
3953}
3954
3955static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
3956{
3957 int res;
3958 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3959 ast_mutex_lock(&p->lock);
3960 p->inalarm = alarm ? 1 : 0;
3961 if (p->inalarm) {
3962 res = get_alarms(p);
3963 if (res == DAHDI_ALARM_NOTOPEN) {
3964 mfcr2_queue_for_destruction(p);
3965 }
3966 handle_alarms(p, res);
3967 } else {
3969 }
3971}
3972
3973static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
3974{
3975 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3976
3977 ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
3978 ast_mutex_lock(&p->lock);
3979 /* Disconnected? */
3980 if (errorcode == ENODEV) {
3981 struct dahdi_mfcr2 *r2link = p->mfcr2;
3982 p->mfcr2call = 0;
3983 if (r2link) {
3984 r2link->nodev = 1;
3985 }
3986 }
3988}
3989
3990static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
3991{
3992 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3993 ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
3994 if (p->owner) {
3997 }
3998 ast_mutex_lock(&p->lock);
3999 p->mfcr2call = 0;
4001}
4002
4003static void dahdi_r2_disconnect_call(struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
4004{
4005 if (openr2_chan_disconnect_call(p->r2chan, cause)) {
4006 ast_log(LOG_NOTICE, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
4007 p->channel, openr2_proto_get_disconnect_string(cause));
4008 /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
4009 openr2_chan_set_idle(p->r2chan);
4010 ast_mutex_lock(&p->lock);
4011 p->mfcr2call = 0;
4013 }
4014}
4015
4016static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
4017{
4018 struct dahdi_pvt *p;
4019 struct ast_channel *c;
4020 ast_callid callid = 0;
4021 int callid_created = ast_callid_threadstorage_auto(&callid);
4022 ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
4023 openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
4024 openr2_proto_get_category_string(category));
4025 p = openr2_chan_get_client_data(r2chan);
4026 /* if collect calls are not allowed and this is a collect call, reject it! */
4027 if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
4028 ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call\n");
4029 dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
4030 goto dahdi_r2_on_call_offered_cleanup;
4031 }
4032 ast_mutex_lock(&p->lock);
4033 p->mfcr2_recvd_category = category;
4034 /* if we're not supposed to use CID, clear whatever we have */
4035 if (!p->use_callerid) {
4036 ast_debug(1, "No CID allowed in configuration, CID is being cleared!\n");
4037 p->cid_num[0] = 0;
4038 p->cid_name[0] = 0;
4039 }
4040 /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
4041 if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
4042 ast_debug(1, "Setting exten => s because of immediate or 0 DNIS configured\n");
4043 p->exten[0] = 's';
4044 p->exten[1] = 0;
4045 }
4047 if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
4048 ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
4049 p->channel, p->exten, p->context);
4050 dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
4051 goto dahdi_r2_on_call_offered_cleanup;
4052 }
4053 if (!p->mfcr2_accept_on_offer) {
4054 /* The user wants us to start the PBX thread right away without accepting the call first */
4055 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4056 if (c) {
4057 /* Done here, don't disable reading now since we still need to generate MF tones to accept
4058 the call or reject it and detect the tone off condition of the other end, all of this
4059 will be done in the PBX thread now */
4060 goto dahdi_r2_on_call_offered_cleanup;
4061 }
4062 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4063 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4064 } else if (p->mfcr2_charge_calls) {
4065 ast_debug(1, "Accepting MFC/R2 call with charge on chan %d\n", p->channel);
4066 openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
4067 } else {
4068 ast_debug(1, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
4069 openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
4070 }
4071
4072dahdi_r2_on_call_offered_cleanup:
4074}
4075
4076static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
4077{
4078 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4079 ast_verbose("MFC/R2 call end on channel %d\n", p->channel);
4080 ast_mutex_lock(&p->lock);
4081 p->mfcr2call = 0;
4083}
4084
4085static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
4086{
4087 struct dahdi_pvt *p = NULL;
4088 struct ast_channel *c = NULL;
4089 ast_callid callid = 0;
4090 int callid_created = ast_callid_threadstorage_auto(&callid);
4091 p = openr2_chan_get_client_data(r2chan);
4092 dahdi_ec_enable(p);
4093 p->mfcr2_call_accepted = 1;
4094 /* if it's an incoming call ... */
4095 if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
4096 ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
4097 /* If accept on offer is not set, it means at this point the PBX thread is already
4098 launched (was launched in the 'on call offered' handler) and therefore this callback
4099 is being executed already in the PBX thread rather than the monitor thread, don't launch
4100 any other thread, just disable the openr2 reading and answer the call if needed */
4101 if (!p->mfcr2_accept_on_offer) {
4102 openr2_chan_disable_read(r2chan);
4103 if (p->mfcr2_answer_pending) {
4104 ast_debug(1, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
4105 dahdi_r2_answer(p);
4106 }
4107 goto dahdi_r2_on_call_accepted_cleanup;
4108 }
4109 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4110 if (c) {
4111 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
4112 library to forget about it */
4113 openr2_chan_disable_read(r2chan);
4114 goto dahdi_r2_on_call_accepted_cleanup;
4115 }
4116 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4117 /* failed to create the channel, bail out and report it as an out of order line */
4118 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4119 goto dahdi_r2_on_call_accepted_cleanup;
4120 }
4121 /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
4122 ast_verbose("MFC/R2 call has been accepted on forward channel %d\n", p->channel);
4123 p->subs[SUB_REAL].needringing = 1;
4124 p->dialing = 0;
4125 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the library to forget about it */
4126 openr2_chan_disable_read(r2chan);
4127
4128dahdi_r2_on_call_accepted_cleanup:
4130}
4131
4132static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
4133{
4134 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4135 ast_verbose("MFC/R2 call has been answered on channel %d\n", openr2_chan_get_number(r2chan));
4136 p->subs[SUB_REAL].needanswer = 1;
4137}
4138
4139static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
4140{
4141 /*ast_debug(1, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
4142}
4143
4144static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
4145{
4146 switch (cause) {
4147 case OR2_CAUSE_BUSY_NUMBER:
4148 return AST_CAUSE_BUSY;
4149 case OR2_CAUSE_NETWORK_CONGESTION:
4150 return AST_CAUSE_CONGESTION;
4151 case OR2_CAUSE_OUT_OF_ORDER:
4153 case OR2_CAUSE_UNALLOCATED_NUMBER:
4155 case OR2_CAUSE_NO_ANSWER:
4156 return AST_CAUSE_NO_ANSWER;
4157 case OR2_CAUSE_NORMAL_CLEARING:
4159 case OR2_CAUSE_UNSPECIFIED:
4160 default:
4161 return AST_CAUSE_NOTDEFINED;
4162 }
4163}
4164
4165static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
4166{
4167 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4168 char cause_str[50];
4169 struct ast_control_pvt_cause_code *cause_code;
4170 int datalen = sizeof(*cause_code);
4171
4172 ast_verbose("MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan));
4173 ast_mutex_lock(&p->lock);
4174 if (!p->owner) {
4176 /* no owner, therefore we can't use dahdi_hangup to disconnect, do it right now */
4177 dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
4178 return;
4179 }
4180
4181 snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
4182 datalen += strlen(cause_str);
4183 cause_code = ast_alloca(datalen);
4184 memset(cause_code, 0, datalen);
4185 cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
4187 ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
4189 ast_channel_hangupcause_hash_set(p->owner, cause_code, datalen);
4191
4192 /* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
4193 be done in dahdi_hangup */
4197 } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
4198 /* being the forward side we must report what happened to the call to whoever requested it */
4199 switch (cause) {
4200 case OR2_CAUSE_BUSY_NUMBER:
4201 p->subs[SUB_REAL].needbusy = 1;
4202 break;
4203 case OR2_CAUSE_NETWORK_CONGESTION:
4204 case OR2_CAUSE_OUT_OF_ORDER:
4205 case OR2_CAUSE_UNALLOCATED_NUMBER:
4206 case OR2_CAUSE_NO_ANSWER:
4207 case OR2_CAUSE_UNSPECIFIED:
4208 case OR2_CAUSE_NORMAL_CLEARING:
4210 break;
4211 default:
4213 }
4215 } else {
4217 /* being the backward side and not UP yet, we only need to request hangup */
4218 /* TODO: what about doing this same thing when were AST_STATE_UP? */
4219 ast_queue_hangup_with_cause(p->owner, dahdi_r2_cause_to_ast_cause(cause));
4220 }
4221}
4222
4223static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
4224{
4225 switch (level) {
4226 case OR2_LOG_NOTICE:
4227 ast_verbose("%s", logmessage);
4228 break;
4229 case OR2_LOG_WARNING:
4230 ast_log(LOG_WARNING, "%s", logmessage);
4231 break;
4232 case OR2_LOG_ERROR:
4233 ast_log(LOG_ERROR, "%s", logmessage);
4234 break;
4235 case OR2_LOG_STACK_TRACE:
4236 case OR2_LOG_MF_TRACE:
4237 case OR2_LOG_CAS_TRACE:
4238 case OR2_LOG_DEBUG:
4239 case OR2_LOG_EX_DEBUG:
4240 ast_debug(1, "%s", logmessage);
4241 break;
4242 default:
4243 ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
4244 ast_debug(1, "%s", logmessage);
4245 break;
4246 }
4247}
4248
4249static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
4250{
4251 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4252 ast_mutex_lock(&p->lock);
4253 p->remotelyblocked = 1;
4255 ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
4256}
4257
4258static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
4259{
4260 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4261 ast_mutex_lock(&p->lock);
4262 p->remotelyblocked = 0;
4264 ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
4265}
4266
4267static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4268 __attribute__((format (printf, 3, 0)));
4269static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4270{
4271#define CONTEXT_TAG "Context - "
4272 char logmsg[256];
4273 char completemsg[sizeof(logmsg) * 2];
4274 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4275 snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
4276 dahdi_r2_write_log(level, completemsg);
4277#undef CONTEXT_TAG
4278}
4279
4280static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4281 __attribute__((format (printf, 3, 0)));
4282static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4283{
4284#define CHAN_TAG "Chan "
4285 char logmsg[256];
4286 char completemsg[sizeof(logmsg) * 2];
4287 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4288 snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
4289 dahdi_r2_write_log(level, completemsg);
4290#undef CHAN_TAG
4291}
4292
4293static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
4294{
4295 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4296 /* if 'immediate' is set, let's stop requesting DNIS */
4297 if (p->immediate) {
4298 return 0;
4299 }
4300 p->exten[p->mfcr2_dnis_index] = digit;
4301 p->rdnis[p->mfcr2_dnis_index] = digit;
4302 p->mfcr2_dnis_index++;
4303 p->exten[p->mfcr2_dnis_index] = 0;
4304 p->rdnis[p->mfcr2_dnis_index] = 0;
4305 /* if the DNIS is a match and cannot match more, stop requesting DNIS */
4306 if ((p->mfcr2_dnis_matched ||
4307 (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
4309 return 0;
4310 }
4311 /* otherwise keep going */
4312 return 1;
4313}
4314
4315static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
4316{
4317 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4318 p->cid_num[p->mfcr2_ani_index] = digit;
4319 p->cid_name[p->mfcr2_ani_index] = digit;
4320 p->mfcr2_ani_index++;
4321 p->cid_num[p->mfcr2_ani_index] = 0;
4322 p->cid_name[p->mfcr2_ani_index] = 0;
4323}
4324
4325static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
4326{
4327 ast_verbose("MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
4328}
4329
4330static openr2_event_interface_t dahdi_r2_event_iface = {
4331 .on_call_init = dahdi_r2_on_call_init,
4332 .on_call_offered = dahdi_r2_on_call_offered,
4333 .on_call_accepted = dahdi_r2_on_call_accepted,
4334 .on_call_answered = dahdi_r2_on_call_answered,
4335 .on_call_disconnect = dahdi_r2_on_call_disconnect,
4336 .on_call_end = dahdi_r2_on_call_end,
4337 .on_call_read = dahdi_r2_on_call_read,
4338 .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
4339 .on_os_error = dahdi_r2_on_os_error,
4340 .on_protocol_error = dahdi_r2_on_protocol_error,
4341 .on_line_blocked = dahdi_r2_on_line_blocked,
4342 .on_line_idle = dahdi_r2_on_line_idle,
4343 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
4344 .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
4345 .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
4346 .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
4347 /* so far we do nothing with billing pulses */
4348 .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
4349};
4350
4351static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
4352{
4353 return AST_ALAW(sample);
4354}
4355
4356static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
4357{
4358 return AST_LIN2A(sample);
4359}
4360
4361static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
4362 dahdi_r2_alaw_to_linear,
4363 dahdi_r2_linear_to_alaw
4364};
4365
4366#endif /* HAVE_OPENR2 */
4367
4368static void swap_subs(struct dahdi_pvt *p, int a, int b)
4369{
4370 int tchan;
4371 int tinthreeway;
4372 struct ast_channel *towner;
4373
4374 ast_debug(1, "Swapping %d and %d\n", a, b);
4375
4376 tchan = p->subs[a].chan;
4377 towner = p->subs[a].owner;
4378 tinthreeway = p->subs[a].inthreeway;
4379
4380 p->subs[a].chan = p->subs[b].chan;
4381 p->subs[a].owner = p->subs[b].owner;
4382 p->subs[a].inthreeway = p->subs[b].inthreeway;
4383
4384 p->subs[b].chan = tchan;
4385 p->subs[b].owner = towner;
4386 p->subs[b].inthreeway = tinthreeway;
4387
4388 if (p->subs[a].owner)
4389 ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
4390 if (p->subs[b].owner)
4391 ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
4392 wakeup_sub(p, a);
4393 wakeup_sub(p, b);
4394}
4395
4396static int dahdi_open(char *fn)
4397{
4398 int fd;
4399 int isnum;
4400 int chan = 0;
4401 int bs;
4402 int x;
4403 isnum = 1;
4404 for (x = 0; x < strlen(fn); x++) {
4405 if (!isdigit(fn[x])) {
4406 isnum = 0;
4407 break;
4408 }
4409 }
4410 if (isnum) {
4411 chan = atoi(fn);
4412 if (chan < 1) {
4413 ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
4414 return -1;
4415 }
4416 fn = "/dev/dahdi/channel";
4417 }
4418 fd = open(fn, O_RDWR | O_NONBLOCK);
4419 if (fd < 0) {
4420 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
4421 return -1;
4422 }
4423 if (chan) {
4424 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
4425 x = errno;
4426 close(fd);
4427 errno = x;
4428 ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
4429 return -1;
4430 }
4431 }
4432 bs = READ_SIZE;
4433 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
4434 ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs, strerror(errno));
4435 x = errno;
4436 close(fd);
4437 errno = x;
4438 return -1;
4439 }
4440 return fd;
4441}
4442
4443static void dahdi_close(int fd)
4444{
4445 if (fd > 0)
4446 close(fd);
4447}
4448
4449static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
4450{
4451 dahdi_close(chan_pvt->subs[sub_num].dfd);
4452 chan_pvt->subs[sub_num].dfd = -1;
4453}
4454
4455#if defined(HAVE_PRI)
4456static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
4457{
4458 dahdi_close(pri->pri.fds[fd_num]);
4459 pri->pri.fds[fd_num] = -1;
4460}
4461#endif /* defined(HAVE_PRI) */
4462
4463#if defined(HAVE_SS7)
4464static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
4465{
4466 dahdi_close(ss7->ss7.fds[fd_num]);
4467 ss7->ss7.fds[fd_num] = -1;
4468}
4469#endif /* defined(HAVE_SS7) */
4470
4471static int dahdi_setlinear(int dfd, int linear)
4472{
4473 return ioctl(dfd, DAHDI_SETLINEAR, &linear);
4474}
4475
4476
4477static int alloc_sub(struct dahdi_pvt *p, int x)
4478{
4479 struct dahdi_bufferinfo bi;
4480 int res;
4481 if (p->subs[x].dfd >= 0) {
4482 ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
4483 return -1;
4484 }
4485
4486 p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
4487 if (p->subs[x].dfd <= -1) {
4488 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
4489 return -1;
4490 }
4491
4492 res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
4493 if (!res) {
4494 bi.txbufpolicy = p->buf_policy;
4495 bi.rxbufpolicy = p->buf_policy;
4496 bi.numbufs = p->buf_no;
4497 res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
4498 if (res < 0) {
4499 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
4500 }
4501 } else
4502 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
4503
4504 if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
4505 ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
4506 dahdi_close_sub(p, x);
4507 p->subs[x].dfd = -1;
4508 return -1;
4509 }
4510 ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
4511 return 0;
4512}
4513
4514static int unalloc_sub(struct dahdi_pvt *p, int x)
4515{
4516 if (!x) {
4517 ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
4518 return -1;
4519 }
4520 ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
4521 dahdi_close_sub(p, x);
4522 p->subs[x].linear = 0;
4523 p->subs[x].chan = 0;
4524 p->subs[x].owner = NULL;
4525 p->subs[x].inthreeway = 0;
4527 memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
4528 return 0;
4529}
4530
4532{
4533 if (isdigit(digit))
4534 return DAHDI_TONE_DTMF_BASE + (digit - '0');
4535 else if (digit >= 'A' && digit <= 'D')
4536 return DAHDI_TONE_DTMF_A + (digit - 'A');
4537 else if (digit >= 'a' && digit <= 'd')
4538 return DAHDI_TONE_DTMF_A + (digit - 'a');
4539 else if (digit == '*')
4540 return DAHDI_TONE_DTMF_s;
4541 else if (digit == '#')
4542 return DAHDI_TONE_DTMF_p;
4543 else
4544 return -1;
4545}
4546
4547static int dahdi_digit_begin(struct ast_channel *chan, char digit)
4548{
4549 struct dahdi_pvt *pvt;
4550 int idx;
4551 int dtmf;
4552 int res;
4553
4554 pvt = ast_channel_tech_pvt(chan);
4555
4556 ast_mutex_lock(&pvt->lock);
4557
4558 idx = dahdi_get_index(chan, pvt, 0);
4559
4560 if ((idx != SUB_REAL) || !pvt->owner)
4561 goto out;
4562
4563#ifdef HAVE_PRI
4564 switch (pvt->sig) {
4566 res = sig_pri_digit_begin(pvt->sig_pvt, chan, digit);
4567 if (!res)
4568 goto out;
4569 break;
4570 default:
4571 break;
4572 }
4573#endif
4574 dtmf = digit_to_dtmfindex(digit);
4575 if (dtmf == -1) {
4576 /* Not a valid DTMF digit */
4577 goto out;
4578 }
4579
4580 if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
4581 char dial_str[] = { 'T', digit, '\0' };
4582
4583 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
4584 if (!res) {
4585 pvt->dialing = 1;
4586 }
4587 } else {
4588 pvt->dialing = 1;
4589 pvt->begindigit = digit;
4590
4591 /* Flush the write buffer in DAHDI to start sending the digit immediately. */
4592 dtmf = DAHDI_FLUSH_WRITE;
4593 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &dtmf);
4594 if (res) {
4595 ast_log(LOG_WARNING, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
4596 pvt->channel, strerror(errno));
4597 }
4598
4599 ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
4600 ast_channel_name(chan), digit);
4601 }
4602
4603out:
4604 ast_mutex_unlock(&pvt->lock);
4605
4606 return 0;
4607}
4608
4609static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
4610{
4611 struct dahdi_pvt *pvt;
4612 int res = 0;
4613 int idx;
4614 int x;
4615
4616 pvt = ast_channel_tech_pvt(chan);
4617
4618 ast_mutex_lock(&pvt->lock);
4619
4620 idx = dahdi_get_index(chan, pvt, 0);
4621
4622 if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
4623 goto out;
4624
4625#ifdef HAVE_PRI
4626 /* This means that the digit was already sent via PRI signalling */
4627 if (dahdi_sig_pri_lib_handles(pvt->sig) && !pvt->begindigit) {
4628 goto out;
4629 }
4630#endif
4631
4632 if (pvt->begindigit) {
4633 x = -1;
4634 ast_debug(1, "Channel %s ending VLDTMF digit '%c'\n",
4635 ast_channel_name(chan), digit);
4636 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
4637 pvt->dialing = 0;
4638 pvt->begindigit = 0;
4639 }
4640
4641out:
4642 ast_mutex_unlock(&pvt->lock);
4643
4644 return res;
4645}
4646
4647static const char * const events[] = {
4648 "No event",
4649 "On hook",
4650 "Ring/Answered",
4651 "Wink/Flash",
4652 "Alarm",
4653 "No more alarm",
4654 "HDLC Abort",
4655 "HDLC Overrun",
4656 "HDLC Bad FCS",
4657 "Dial Complete",
4658 "Ringer On",
4659 "Ringer Off",
4660 "Hook Transition Complete",
4661 "Bits Changed",
4662 "Pulse Start",
4663 "Timer Expired",
4664 "Timer Ping",
4665 "Polarity Reversal",
4666 "Ring Begin",
4667};
4668
4669static struct {
4671 char *name;
4672} alarms[] = {
4673 { DAHDI_ALARM_RED, "Red Alarm" },
4674 { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
4675 { DAHDI_ALARM_BLUE, "Blue Alarm" },
4676 { DAHDI_ALARM_RECOVER, "Recovering" },
4677 { DAHDI_ALARM_LOOPBACK, "Loopback" },
4678 { DAHDI_ALARM_NOTOPEN, "Not Open" },
4679 { DAHDI_ALARM_NONE, "None" },
4681
4682static char *alarm2str(int alm)
4683{
4684 int x;
4685 for (x = 0; x < ARRAY_LEN(alarms); x++) {
4686 if (alarms[x].alarm & alm)
4687 return alarms[x].name;
4688 }
4689 return alm ? "Unknown Alarm" : "No Alarm";
4690}
4691
4692static const char *event2str(int event)
4693{
4694 static char buf[256];
4695 if ((event > -1) && (event < (ARRAY_LEN(events))) )
4696 return events[event];
4697 sprintf(buf, "Event %d", event); /* safe */
4698 return buf;
4699}
4700
4701static char *dahdi_sig2str(int sig)
4702{
4703 static char buf[256];
4704 switch (sig) {
4705 case SIG_EM:
4706 return "E & M Immediate";
4707 case SIG_EMWINK:
4708 return "E & M Wink";
4709 case SIG_EM_E1:
4710 return "E & M E1";
4711 case SIG_FEATD:
4712 return "Feature Group D (DTMF)";
4713 case SIG_FEATDMF:
4714 return "Feature Group D (MF)";
4715 case SIG_FEATDMF_TA:
4716 return "Feature Group D (MF) Tandem Access";
4717 case SIG_FEATB:
4718 return "Feature Group B (MF)";
4719 case SIG_E911:
4720 return "E911 (MF)";
4721 case SIG_FGC_CAMA:
4722 return "FGC/CAMA (Dialpulse)";
4723 case SIG_FGC_CAMAMF:
4724 return "FGC/CAMA (MF)";
4725 case SIG_FXSLS:
4726 return "FXS Loopstart";
4727 case SIG_FXSGS:
4728 return "FXS Groundstart";
4729 case SIG_FXSKS:
4730 return "FXS Kewlstart";
4731 case SIG_FXOLS:
4732 return "FXO Loopstart";
4733 case SIG_FXOGS:
4734 return "FXO Groundstart";
4735 case SIG_FXOKS:
4736 return "FXO Kewlstart";
4737 case SIG_PRI:
4738 return "ISDN PRI";
4739 case SIG_BRI:
4740 return "ISDN BRI Point to Point";
4741 case SIG_BRI_PTMP:
4742 return "ISDN BRI Point to MultiPoint";
4743 case SIG_SS7:
4744 return "SS7";
4745 case SIG_MFCR2:
4746 return "MFC/R2";
4747 case SIG_SF:
4748 return "SF (Tone) Immediate";
4749 case SIG_SFWINK:
4750 return "SF (Tone) Wink";
4751 case SIG_SF_FEATD:
4752 return "SF (Tone) with Feature Group D (DTMF)";
4753 case SIG_SF_FEATDMF:
4754 return "SF (Tone) with Feature Group D (MF)";
4755 case SIG_SF_FEATB:
4756 return "SF (Tone) with Feature Group B (MF)";
4757 case 0:
4758 return "Pseudo";
4759 default:
4760 snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
4761 return buf;
4762 }
4763}
4764
4765#define sig2str dahdi_sig2str
4766
4767static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
4768{
4769 /* If the conference already exists, and we're already in it
4770 don't bother doing anything */
4771 struct dahdi_confinfo zi;
4772
4773 memset(&zi, 0, sizeof(zi));
4774 zi.chan = 0;
4775
4776 if (slavechannel > 0) {
4777 /* If we have only one slave, do a digital mon */
4778 zi.confmode = DAHDI_CONF_DIGITALMON;
4779 zi.confno = slavechannel;
4780 } else {
4781 if (!idx) {
4782 /* Real-side and pseudo-side both participate in conference */
4783 zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
4784 DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4785 } else
4786 zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
4787 zi.confno = p->confno;
4788 }
4789 if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
4790 return 0;
4791 if (c->dfd < 0)
4792 return 0;
4793 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4794 ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
4795 return -1;
4796 }
4797 if (slavechannel < 1) {
4798 p->confno = zi.confno;
4799 }
4800 c->curconf = zi;
4801 ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4802 return 0;
4803}
4804
4805static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
4806{
4807 /* If they're listening to our channel, they're ours */
4808 if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
4809 return 1;
4810 /* If they're a talker on our (allocated) conference, they're ours */
4811 if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
4812 return 1;
4813 return 0;
4814}
4815
4816static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
4817{
4818 struct dahdi_confinfo zi;
4819 if (/* Can't delete if there's no dfd */
4820 (c->dfd < 0) ||
4821 /* Don't delete from the conference if it's not our conference */
4822 !isourconf(p, c)
4823 /* Don't delete if we don't think it's conferenced at all (implied) */
4824 ) return 0;
4825 memset(&zi, 0, sizeof(zi));
4826 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4827 ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
4828 return -1;
4829 }
4830 ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4831 memcpy(&c->curconf, &zi, sizeof(c->curconf));
4832 return 0;
4833}
4834
4835static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
4836{
4837 int x;
4838 int useslavenative;
4839 struct dahdi_pvt *slave = NULL;
4840 /* Start out optimistic */
4841 useslavenative = 1;
4842 /* Update conference state in a stateless fashion */
4843 for (x = 0; x < 3; x++) {
4844 /* Any three-way calling makes slave native mode *definitely* out
4845 of the question */
4846 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
4847 useslavenative = 0;
4848 }
4849 /* If we don't have any 3-way calls, check to see if we have
4850 precisely one slave */
4851 if (useslavenative) {
4852 for (x = 0; x < MAX_SLAVES; x++) {
4853 if (p->slaves[x]) {
4854 if (slave) {
4855 /* Whoops already have a slave! No
4856 slave native and stop right away */
4857 slave = NULL;
4858 useslavenative = 0;
4859 break;
4860 } else {
4861 /* We have one slave so far */
4862 slave = p->slaves[x];
4863 }
4864 }
4865 }
4866 }
4867 /* If no slave, slave native definitely out */
4868 if (!slave)
4869 useslavenative = 0;
4870 else if (slave->law != p->law) {
4871 useslavenative = 0;
4872 slave = NULL;
4873 }
4874 if (out)
4875 *out = slave;
4876 return useslavenative;
4877}
4878
4879static int reset_conf(struct dahdi_pvt *p)
4880{
4881 p->confno = -1;
4882 memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
4883 if (p->subs[SUB_REAL].dfd > -1) {
4884 struct dahdi_confinfo zi;
4885
4886 memset(&zi, 0, sizeof(zi));
4887 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
4888 ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
4889 }
4890 return 0;
4891}
4892
4894{
4895 int needconf = 0;
4896 int x;
4897 int useslavenative;
4898 struct dahdi_pvt *slave = NULL;
4899
4900 useslavenative = isslavenative(p, &slave);
4901 /* Start with the obvious, general stuff */
4902 for (x = 0; x < 3; x++) {
4903 /* Look for three way calls */
4904 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
4905 conf_add(p, &p->subs[x], x, 0);
4906 needconf++;
4907 } else {
4908 conf_del(p, &p->subs[x], x);
4909 }
4910 }
4911 /* If we have a slave, add him to our conference now. or DAX
4912 if this is slave native */
4913 for (x = 0; x < MAX_SLAVES; x++) {
4914 if (p->slaves[x]) {
4915 if (useslavenative)
4916 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
4917 else {
4918 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
4919 needconf++;
4920 }
4921 }
4922 }
4923 /* If we're supposed to be in there, do so now */
4924 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
4925 if (useslavenative)
4926 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
4927 else {
4928 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
4929 needconf++;
4930 }
4931 }
4932 /* If we have a master, add ourselves to his conference */
4933 if (p->master) {
4934 if (isslavenative(p->master, NULL)) {
4936 } else {
4937 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
4938 }
4939 }
4940 if (!needconf) {
4941 /* Nobody is left (or should be left) in our conference.
4942 Kill it. */
4943 p->confno = -1;
4944 }
4945 ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
4946}
4947
4949{
4950 int res;
4951 if (!p)
4952 return;
4953 if (p->echocanon) {
4954 ast_debug(1, "Echo cancellation already on\n");
4955 return;
4956 }
4957 if (p->digital) {
4958 ast_debug(1, "Echo cancellation isn't required on digital connection\n");
4959 return;
4960 }
4961 if (p->echocancel.head.tap_length) {
4962#if defined(HAVE_PRI) || defined(HAVE_SS7)
4963 switch (p->sig) {
4964#if defined(HAVE_PRI)
4966 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
4967 /*
4968 * PRI nobch pseudo channel. Does not need ec anyway.
4969 * Does not handle ioctl(DAHDI_AUDIOMODE)
4970 */
4971 return;
4972 }
4973 /* Fall through */
4974#endif /* defined(HAVE_PRI) */
4975#if defined(HAVE_SS7)
4976 case SIG_SS7:
4977#endif /* defined(HAVE_SS7) */
4978 {
4979 int x = 1;
4980
4981 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
4982 if (res)
4984 "Unable to enable audio mode on channel %d (%s)\n",
4985 p->channel, strerror(errno));
4986 }
4987 break;
4988 default:
4989 break;
4990 }
4991#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
4992 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
4993 if (res) {
4994 ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
4995 } else {
4996 p->echocanon = 1;
4997 ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
4998 }
4999 } else
5000 ast_debug(1, "No echo cancellation requested\n");
5001}
5002
5003static void dahdi_train_ec(struct dahdi_pvt *p)
5004{
5005 int x;
5006 int res;
5007
5008 if (p && p->echocanon && p->echotraining) {
5009 x = p->echotraining;
5010 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
5011 if (res)
5012 ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
5013 else
5014 ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
5015 } else {
5016 ast_debug(1, "No echo training requested\n");
5017 }
5018}
5019
5021{
5022 int res;
5023
5024 if (p->echocanon) {
5025 struct dahdi_echocanparams ecp = { .tap_length = 0 };
5026
5027 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
5028
5029 if (res)
5030 ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
5031 else
5032 ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
5033 }
5034
5035 p->echocanon = 0;
5036}
5037
5038static int set_hwgain(int fd, float gain, int tx_direction)
5039{
5040 struct dahdi_hwgain hwgain;
5041
5042 hwgain.newgain = gain * 10.0;
5043 hwgain.tx = tx_direction;
5044 return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
5045}
5046
5047/* perform a dynamic range compression transform on the given sample */
5048static int drc_sample(int sample, float drc)
5049{
5050 float neg;
5051 float shallow, steep;
5052 float max = SHRT_MAX;
5053
5054 neg = (sample < 0 ? -1 : 1);
5055 steep = drc*sample;
5056 shallow = neg*(max-max/drc)+(float)sample/drc;
5057 if (fabsf(steep) < fabsf(shallow)) {
5058 sample = steep;
5059 }
5060 else {
5061 sample = shallow;
5062 }
5063
5064 return sample;
5065}
5066
5067
5068static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
5069{
5070 int j;
5071 int k;
5072
5073 float linear_gain = pow(10.0, gain / 20.0);
5074
5075 switch (law) {
5076 case DAHDI_LAW_ALAW:
5077 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5078 if (gain || drc) {
5079 k = AST_ALAW(j);
5080 if (drc) {
5081 k = drc_sample(k, drc);
5082 }
5083 k = (float)k * linear_gain;
5084 if (k > 32767) {
5085 k = 32767;
5086 } else if (k < -32768) {
5087 k = -32768;
5088 }
5089 g->txgain[j] = AST_LIN2A(k);
5090 } else {
5091 g->txgain[j] = j;
5092 }
5093 }
5094 break;
5095 case DAHDI_LAW_MULAW:
5096 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5097 if (gain || drc) {
5098 k = AST_MULAW(j);
5099 if (drc) {
5100 k = drc_sample(k, drc);
5101 }
5102 k = (float)k * linear_gain;
5103 if (k > 32767) {
5104 k = 32767;
5105 } else if (k < -32768) {
5106 k = -32768;
5107 }
5108 g->txgain[j] = AST_LIN2MU(k);
5109
5110 } else {
5111 g->txgain[j] = j;
5112 }
5113 }
5114 break;
5115 }
5116}
5117
5118static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
5119{
5120 int j;
5121 int k;
5122 float linear_gain = pow(10.0, gain / 20.0);
5123
5124 switch (law) {
5125 case DAHDI_LAW_ALAW:
5126 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5127 if (gain || drc) {
5128 k = AST_ALAW(j);
5129 if (drc) {
5130 k = drc_sample(k, drc);
5131 }
5132 k = (float)k * linear_gain;
5133 if (k > 32767) {
5134 k = 32767;
5135 } else if (k < -32768) {
5136 k = -32768;
5137 }
5138 g->rxgain[j] = AST_LIN2A(k);
5139 } else {
5140 g->rxgain[j] = j;
5141 }
5142 }
5143 break;
5144 case DAHDI_LAW_MULAW:
5145 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5146 if (gain || drc) {
5147 k = AST_MULAW(j);
5148 if (drc) {
5149 k = drc_sample(k, drc);
5150 }
5151 k = (float)k * linear_gain;
5152 if (k > 32767) {
5153 k = 32767;
5154 } else if (k < -32768) {
5155 k = -32768;
5156 }
5157 g->rxgain[j] = AST_LIN2MU(k);
5158 } else {
5159 g->rxgain[j] = j;
5160 }
5161 }
5162 break;
5163 }
5164}
5165
5166static int set_actual_txgain(int fd, float gain, float drc, int law)
5167{
5168 struct dahdi_gains g;
5169 int res;
5170
5171 memset(&g, 0, sizeof(g));
5172 res = ioctl(fd, DAHDI_GETGAINS, &g);
5173 if (res) {
5174 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5175 return res;
5176 }
5177
5178 fill_txgain(&g, gain, drc, law);
5179
5180 return ioctl(fd, DAHDI_SETGAINS, &g);
5181}
5182
5183static int set_actual_rxgain(int fd, float gain, float drc, int law)
5184{
5185 struct dahdi_gains g;
5186 int res;
5187
5188 memset(&g, 0, sizeof(g));
5189 res = ioctl(fd, DAHDI_GETGAINS, &g);
5190 if (res) {
5191 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5192 return res;
5193 }
5194
5195 fill_rxgain(&g, gain, drc, law);
5196
5197 return ioctl(fd, DAHDI_SETGAINS, &g);
5198}
5199
5200static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
5201{
5202 return set_actual_txgain(fd, txgain, txdrc, law) | set_actual_rxgain(fd, rxgain, rxdrc, law);
5203}
5204
5205static int bump_gains(struct dahdi_pvt *p)
5206{
5207 int res;
5208
5209 /* Bump receive gain by value stored in cid_rxgain */
5210 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain + p->cid_rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5211 if (res) {
5212 ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
5213 return -1;
5214 }
5215
5216 return 0;
5217}
5218
5219static int restore_gains(struct dahdi_pvt *p)
5220{
5221 int res;
5222
5223 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5224 if (res) {
5225 ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
5226 return -1;
5227 }
5228
5229 return 0;
5230}
5231
5232static inline int dahdi_set_hook(int fd, int hs)
5233{
5234 int x, res;
5235
5236 x = hs;
5237 res = ioctl(fd, DAHDI_HOOK, &x);
5238
5239 if (res < 0) {
5240 if (errno == EINPROGRESS)
5241 return 0;
5242 ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
5243 /* will expectedly fail if phone is off hook during operation, such as during a restart */
5244 }
5245
5246 return res;
5247}
5248
5249static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
5250{
5251 int x, res;
5252
5253 x = muted;
5254#if defined(HAVE_PRI) || defined(HAVE_SS7)
5255 switch (p->sig) {
5256#if defined(HAVE_PRI)
5258 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
5259 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
5260 break;
5261 }
5262 /* Fall through */
5263#endif /* defined(HAVE_PRI) */
5264#if defined(HAVE_SS7)
5265 case SIG_SS7:
5266#endif /* defined(HAVE_SS7) */
5267 {
5268 int y = 1;
5269
5270 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
5271 if (res)
5272 ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n",
5273 p->channel, strerror(errno));
5274 }
5275 break;
5276 default:
5277 break;
5278 }
5279#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5280 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
5281 if (res < 0)
5282 ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
5283 return res;
5284}
5285
5286static int save_conference(struct dahdi_pvt *p)
5287{
5288 struct dahdi_confinfo c;
5289 int res;
5290 if (p->saveconf.confmode) {
5291 ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
5292 return -1;
5293 }
5294 p->saveconf.chan = 0;
5295 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
5296 if (res) {
5297 ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
5298 p->saveconf.confmode = 0;
5299 return -1;
5300 }
5301 memset(&c, 0, sizeof(c));
5302 c.confmode = DAHDI_CONF_NORMAL;
5303 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
5304 if (res) {
5305 ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
5306 return -1;
5307 }
5308 ast_debug(1, "Disabled conferencing\n");
5309 return 0;
5310}
5311
5312static int restore_conference(struct dahdi_pvt *p)
5313{
5314 int res;
5315 if (p->saveconf.confmode) {
5316 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
5317 p->saveconf.confmode = 0;
5318 if (res) {
5319 ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
5320 return -1;
5321 }
5322 ast_debug(1, "Restored conferencing\n");
5323 }
5324 return 0;
5325}
5326
5327static int send_cwcidspill(struct dahdi_pvt *p)
5328{
5329 p->callwaitcas = 0;
5330 p->cidcwexpire = 0;
5331 p->cid_suppress_expire = 0;
5333 return -1;
5335 /* Make sure we account for the end */
5336 p->cidlen += READ_SIZE * 4;
5337 p->cidpos = 0;
5338 send_callerid(p);
5339 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
5340 return 0;
5341}
5342
5343static int has_voicemail(struct dahdi_pvt *p)
5344{
5345 int new_msgs;
5346 RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
5347
5348 /* A manual MWI disposition has been requested, use that instead
5349 * if this is for sending the new MWI indication. */
5350 if (p->mwioverride_active) {
5351 /* We don't clear p->mwioverride_active automatically,
5352 * because otherwise do_monitor would just change it back to the way it was.
5353 * We need to keep the override active until explicitly disabled by the user,
5354 * so that we can keep returning the correct answer in subsequent calls to do_monitor. */
5355 ast_debug(6, "MWI manual override active on channel %d: pretending that it should be %s\n",
5356 p->channel, p->mwioverride_disposition ? "active" : "inactive");
5357 return p->mwioverride_disposition;
5358 }
5359
5361 if (mwi_message) {
5362 struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
5363 new_msgs = mwi_state->new_msgs;
5364 } else {
5366 }
5367
5368 return new_msgs;
5369}
5370
5371
5372
5373static int send_callerid(struct dahdi_pvt *p)
5374{
5375 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
5376 int res;
5377 /* Take out of linear mode if necessary */
5378 if (p->subs[SUB_REAL].linear) {
5379 p->subs[SUB_REAL].linear = 0;
5381 }
5382 while (p->cidpos < p->cidlen) {
5383 res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
5384 ast_debug(4, "writing callerid at pos %d of %d, res = %d\n", p->cidpos, p->cidlen, res);
5385 if (res < 0) {
5386 if (errno == EAGAIN)
5387 return 0;
5388 else {
5389 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
5390 return -1;
5391 }
5392 }
5393 if (!res)
5394 return 0;
5395 p->cidpos += res;
5396 }
5398 ast_free(p->cidspill);
5399 p->cidspill = NULL;
5400 if (p->callwaitcas) {
5401 /* Wait for CID/CW to expire */
5404 } else
5406 return 0;
5407}
5408
5409static int dahdi_callwait(struct ast_channel *ast)
5410{
5411 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5412
5414 if (p->cidspill) {
5415 ast_log(LOG_WARNING, "Spill already exists?!?\n");
5416 ast_free(p->cidspill);
5417 }
5418
5419 /*
5420 * SAS: Subscriber Alert Signal, 440Hz for 300ms
5421 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
5422 */
5423 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
5424 return -1;
5425 save_conference(p);
5426 /* Silence */
5427 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
5428 if (!p->callwaitrings && p->callwaitingcallerid) {
5429 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
5430 p->callwaitcas = 1;
5431 p->cidlen = 2400 + 680 + READ_SIZE * 4;
5432 } else {
5433 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
5434 p->callwaitcas = 0;
5435 p->cidlen = 2400 + READ_SIZE * 4;
5436 }
5437 p->cidpos = 0;
5438 send_callerid(p);
5439
5440 return 0;
5441}
5442
5443static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
5444{
5445 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5446 int x, res, mysig;
5447 char *dest;
5449 AST_APP_ARG(group); /* channel/group token */
5450 AST_APP_ARG(ext); /* extension token */
5451 //AST_APP_ARG(opts); /* options token */
5452 AST_APP_ARG(other); /* Any remaining unused arguments */
5453 );
5454
5455 ast_mutex_lock(&p->lock);
5456 ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
5457
5458 /* Split the dialstring */
5459 dest = ast_strdupa(rdest);
5460 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
5461 if (!args.ext) {
5462 args.ext = "";
5463 }
5464
5465#if defined(HAVE_PRI)
5467 char *subaddr;
5468
5469 sig_pri_extract_called_num_subaddr(p->sig_pvt, rdest, p->exten, sizeof(p->exten));
5470
5471 /* Remove any subaddress for uniformity with incoming calls. */
5472 subaddr = strchr(p->exten, ':');
5473 if (subaddr) {
5474 *subaddr = '\0';
5475 }
5476 } else
5477#endif /* defined(HAVE_PRI) */
5478 {
5479 ast_copy_string(p->exten, args.ext, sizeof(p->exten));
5480 }
5481
5482 if ((ast_channel_state(ast) == AST_STATE_BUSY)) {
5483 p->subs[SUB_REAL].needbusy = 1;
5485 return 0;
5486 }
5488 ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
5490 return -1;
5491 }
5492 p->waitingfordt.tv_sec = 0;
5493 p->dialednone = 0;
5494 if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
5495 {
5496 /* Special pseudo -- automatically up */
5499 return 0;
5500 }
5501 x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
5502 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
5503 if (res)
5504 ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
5505 p->outgoing = 1;
5506
5508 set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
5509 } else {
5510 set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5511 }
5512
5513#ifdef HAVE_PRI
5515 res = sig_pri_call(p->sig_pvt, ast, rdest, timeout,
5516 (p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW);
5518 return res;
5519 }
5520#endif
5521
5522#if defined(HAVE_SS7)
5523 if (p->sig == SIG_SS7) {
5524 res = sig_ss7_call(p->sig_pvt, ast, rdest);
5526 return res;
5527 }
5528#endif /* defined(HAVE_SS7) */
5529
5530 /* If this is analog signalling we can exit here */
5531 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
5532 p->callwaitrings = 0;
5533 res = analog_call(p->sig_pvt, ast, rdest, timeout);
5535 return res;
5536 }
5537
5538 mysig = p->outsigmod > -1 ? p->outsigmod : p->sig;
5539 switch (mysig) {
5540 case 0:
5541 /* Special pseudo -- automatically up*/
5543 break;
5544 case SIG_MFCR2:
5545 break;
5546 default:
5547 ast_debug(1, "not yet implemented\n");
5549 return -1;
5550 }
5551
5552#ifdef HAVE_OPENR2
5553 if (p->mfcr2) {
5554 openr2_calling_party_category_t chancat;
5555 int callres = 0;
5556 char *c, *l;
5557
5558 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
5559 p->dialdest[0] = '\0';
5560
5561 c = args.ext;
5562 if (!p->hidecallerid) {
5564 } else {
5565 l = NULL;
5566 }
5567 if (strlen(c) < p->stripmsd) {
5568 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
5570 return -1;
5571 }
5572 p->dialing = 1;
5573 chancat = dahdi_r2_get_channel_category(ast);
5574 callres = openr2_chan_make_call(p->r2chan, l, (c + p->stripmsd), chancat);
5575 if (-1 == callres) {
5577 ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
5578 return -1;
5579 }
5580 p->mfcr2_call_accepted = 0;
5581 p->mfcr2_progress_sent = 0;
5583 }
5584#endif /* HAVE_OPENR2 */
5586 return 0;
5587}
5588
5589/*!
5590 * \internal
5591 * \brief Insert the given chan_dahdi interface structure into the interface list.
5592 * \since 1.8
5593 *
5594 * \param pvt chan_dahdi private interface structure to insert.
5595 *
5596 * \details
5597 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5598 * Any duplicates are inserted after the existing entries.
5599 *
5600 * \note The new interface must not already be in the list.
5601 */
5602static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
5603{
5604 struct dahdi_pvt *cur;
5605
5607
5608 /* Find place in middle of list for the new interface. */
5609 for (cur = iflist; cur; cur = cur->next) {
5610 if (pvt->channel < cur->channel) {
5611 /* New interface goes before the current interface. */
5612 pvt->prev = cur->prev;
5613 pvt->next = cur;
5614 if (cur->prev) {
5615 /* Insert into the middle of the list. */
5616 cur->prev->next = pvt;
5617 } else {
5618 /* Insert at head of list. */
5619 iflist = pvt;
5620 }
5621 cur->prev = pvt;
5622 return;
5623 }
5624 }
5625
5626 /* New interface goes onto the end of the list */
5627 pvt->prev = ifend;
5628 pvt->next = NULL;
5629 if (ifend) {
5630 ifend->next = pvt;
5631 }
5632 ifend = pvt;
5633 if (!iflist) {
5634 /* List was empty */
5635 iflist = pvt;
5636 }
5637}
5638
5639/*!
5640 * \internal
5641 * \brief Extract the given chan_dahdi interface structure from the interface list.
5642 * \since 1.8
5643 *
5644 * \param pvt chan_dahdi private interface structure to extract.
5645 *
5646 * \note
5647 * The given interface structure can be either in the interface list or a stand alone
5648 * structure that has not been put in the list if the next and prev pointers are NULL.
5649 */
5650static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
5651{
5652 /* Extract from the forward chain. */
5653 if (pvt->prev) {
5654 pvt->prev->next = pvt->next;
5655 } else if (iflist == pvt) {
5656 /* Node is at the head of the list. */
5657 iflist = pvt->next;
5658 }
5659
5660 /* Extract from the reverse chain. */
5661 if (pvt->next) {
5662 pvt->next->prev = pvt->prev;
5663 } else if (ifend == pvt) {
5664 /* Node is at the end of the list. */
5665 ifend = pvt->prev;
5666 }
5667
5668 /* Node is no longer in the list. */
5670 pvt->prev = NULL;
5671 pvt->next = NULL;
5672}
5673
5674#if defined(HAVE_PRI)
5675/*!
5676 * \internal
5677 * \brief Insert the given chan_dahdi interface structure into the no B channel list.
5678 * \since 1.8
5679 *
5680 * \param pri sig_pri span control structure holding no B channel list.
5681 * \param pvt chan_dahdi private interface structure to insert.
5682 *
5683 * \details
5684 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5685 * Any duplicates are inserted after the existing entries.
5686 *
5687 * \note The new interface must not already be in the list.
5688 */
5689static void dahdi_nobch_insert(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5690{
5691 struct dahdi_pvt *cur;
5692
5693 pvt->which_iflist = DAHDI_IFLIST_NO_B_CHAN;
5694
5695 /* Find place in middle of list for the new interface. */
5696 for (cur = pri->no_b_chan_iflist; cur; cur = cur->next) {
5697 if (pvt->channel < cur->channel) {
5698 /* New interface goes before the current interface. */
5699 pvt->prev = cur->prev;
5700 pvt->next = cur;
5701 if (cur->prev) {
5702 /* Insert into the middle of the list. */
5703 cur->prev->next = pvt;
5704 } else {
5705 /* Insert at head of list. */
5706 pri->no_b_chan_iflist = pvt;
5707 }
5708 cur->prev = pvt;
5709 return;
5710 }
5711 }
5712
5713 /* New interface goes onto the end of the list */
5714 pvt->prev = pri->no_b_chan_end;
5715 pvt->next = NULL;
5716 if (pri->no_b_chan_end) {
5717 ((struct dahdi_pvt *) pri->no_b_chan_end)->next = pvt;
5718 }
5719 pri->no_b_chan_end = pvt;
5720 if (!pri->no_b_chan_iflist) {
5721 /* List was empty */
5722 pri->no_b_chan_iflist = pvt;
5723 }
5724}
5725#endif /* defined(HAVE_PRI) */
5726
5727#if defined(HAVE_PRI)
5728/*!
5729 * \internal
5730 * \brief Extract the given chan_dahdi interface structure from the no B channel list.
5731 * \since 1.8
5732 *
5733 * \param pri sig_pri span control structure holding no B channel list.
5734 * \param pvt chan_dahdi private interface structure to extract.
5735 *
5736 * \note
5737 * The given interface structure can be either in the interface list or a stand alone
5738 * structure that has not been put in the list if the next and prev pointers are NULL.
5739 */
5740static void dahdi_nobch_extract(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5741{
5742 /* Extract from the forward chain. */
5743 if (pvt->prev) {
5744 pvt->prev->next = pvt->next;
5745 } else if (pri->no_b_chan_iflist == pvt) {
5746 /* Node is at the head of the list. */
5747 pri->no_b_chan_iflist = pvt->next;
5748 }
5749
5750 /* Extract from the reverse chain. */
5751 if (pvt->next) {
5752 pvt->next->prev = pvt->prev;
5753 } else if (pri->no_b_chan_end == pvt) {
5754 /* Node is at the end of the list. */
5755 pri->no_b_chan_end = pvt->prev;
5756 }
5757
5758 /* Node is no longer in the list. */
5760 pvt->prev = NULL;
5761 pvt->next = NULL;
5762}
5763#endif /* defined(HAVE_PRI) */
5764
5765#if defined(HAVE_PRI)
5766/*!
5767 * \internal
5768 * \brief Unlink the channel interface from the PRI private pointer array.
5769 * \since 1.8
5770 *
5771 * \param pvt chan_dahdi private interface structure to unlink.
5772 */
5773static void dahdi_unlink_pri_pvt(struct dahdi_pvt *pvt)
5774{
5775 unsigned idx;
5776 struct sig_pri_span *pri;
5777
5778 pri = pvt->pri;
5779 if (!pri) {
5780 /* Not PRI signaling so cannot be in a PRI private pointer array. */
5781 return;
5782 }
5783 ast_mutex_lock(&pri->lock);
5784 for (idx = 0; idx < pri->numchans; ++idx) {
5785 if (pri->pvts[idx] == pvt->sig_pvt) {
5786 pri->pvts[idx] = NULL;
5787 ast_mutex_unlock(&pri->lock);
5788 return;
5789 }
5790 }
5791 ast_mutex_unlock(&pri->lock);
5792}
5793#endif /* defined(HAVE_PRI) */
5794
5795#if defined(HAVE_SS7)
5796/*!
5797 * \internal
5798 * \brief Unlink the channel interface from the SS7 private pointer array.
5799 * \since 1.8
5800 *
5801 * \param pvt chan_dahdi private interface structure to unlink.
5802 */
5803static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
5804{
5805 unsigned idx;
5806 struct sig_ss7_linkset *ss7;
5807
5808 ss7 = pvt->ss7;
5809 if (!ss7) {
5810 /* Not SS7 signaling so cannot be in a SS7 private pointer array. */
5811 return;
5812 }
5813 ast_mutex_lock(&ss7->lock);
5814 for (idx = 0; idx < ss7->numchans; ++idx) {
5815 if (ss7->pvts[idx] == pvt->sig_pvt) {
5816 ss7->pvts[idx] = NULL;
5817 ast_mutex_unlock(&ss7->lock);
5818 return;
5819 }
5820 }
5821 ast_mutex_unlock(&ss7->lock);
5822}
5823#endif /* defined(HAVE_SS7) */
5824
5825#if defined(HAVE_OPENR2)
5826/*!
5827 * \internal
5828 * \brief Unlink the channel interface from the MFC/R2 private pointer array.
5829 *
5830 * \param pvt chan_dahdi private interface structure to unlink.
5831 */
5832static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
5833{
5834 unsigned idx;
5835 struct dahdi_mfcr2 *mfcr2;
5836 int should_destroy_link = 0;
5837
5838 ast_mutex_lock(&pvt->lock);
5839 if (pvt->r2chan) {
5840 ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
5841 openr2_chan_disable_read(pvt->r2chan);
5842 }
5843 mfcr2 = pvt->mfcr2;
5844 if (mfcr2) {
5845 for (idx = 0; idx < mfcr2->numchans; ++idx) {
5846 if (mfcr2->pvts[idx] == pvt) {
5847 ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
5848 mfcr2->pvts[idx] = NULL;
5849 mfcr2->live_chans--;
5850 break;
5851 }
5852 }
5853 if (!mfcr2->live_chans) {
5854 ast_debug(1, "MFC/R2 link is now empty\n");
5855 should_destroy_link = 1;
5856 }
5857 }
5858 ast_mutex_unlock(&pvt->lock);
5859 if (should_destroy_link) {
5860 ast_debug(1, "MFC/R2 link is now empty\n");
5861 mfcr2_queue_for_destruction(pvt);
5862 }
5863}
5864#endif /* defined(HAVE_OPENR2) */
5865
5867{
5868 if (cur->next && cur->next->span == cur->span) {
5869 return cur->next;
5870 } else if (cur->prev && cur->prev->span == cur->span) {
5871 return cur->prev;
5872 }
5873
5874 return NULL;
5875}
5876
5877static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
5878{
5879 struct dahdi_pvt *p = pvt;
5880
5881 if (p->manages_span_alarms) {
5883 if (next) {
5885 }
5886 }
5887
5888 /* Remove channel from the list */
5889#if defined(HAVE_PRI)
5890 dahdi_unlink_pri_pvt(p);
5891#endif /* defined(HAVE_PRI) */
5892#if defined(HAVE_SS7)
5893 dahdi_unlink_ss7_pvt(p);
5894#endif /* defined(HAVE_SS7) */
5895#if defined(HAVE_OPENR2)
5896 dahdi_unlink_mfcr2_pvt(p);
5897#endif /* defined(HAVE_SS7) */
5898 switch (pvt->which_iflist) {
5899 case DAHDI_IFLIST_NONE:
5900 break;
5901 case DAHDI_IFLIST_MAIN:
5903 break;
5904#if defined(HAVE_PRI)
5905 case DAHDI_IFLIST_NO_B_CHAN:
5906 if (p->pri) {
5907 dahdi_nobch_extract(p->pri, p);
5908 }
5909 break;
5910#endif /* defined(HAVE_PRI) */
5911 }
5912
5913 if (p->sig_pvt) {
5914 if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
5916 }
5917 switch (p->sig) {
5918#if defined(HAVE_PRI)
5921 break;
5922#endif /* defined(HAVE_PRI) */
5923#if defined(HAVE_SS7)
5924 case SIG_SS7:
5926 break;
5927#endif /* defined(HAVE_SS7) */
5928 default:
5929 break;
5930 }
5931 }
5932 ast_free(p->cidspill);
5933 if (p->use_smdi) {
5935 }
5936 if (p->mwi_event_sub) {
5938 }
5939 if (p->vars) {
5941 }
5942 if (p->cc_params) {
5944 }
5945
5948
5951 if (p->owner) {
5953 }
5954 ast_free(p);
5955}
5956
5957static void destroy_channel(struct dahdi_pvt *cur, int now)
5958{
5959 int i;
5960
5961 if (!now) {
5962 /* Do not destroy the channel now if it is owned by someone. */
5963 if (cur->owner) {
5964 return;
5965 }
5966 for (i = 0; i < 3; i++) {
5967 if (cur->subs[i].owner) {
5968 return;
5969 }
5970 }
5971 }
5972 destroy_dahdi_pvt(cur);
5973}
5974
5975static void destroy_all_channels(void)
5976{
5977 int chan;
5978#if defined(HAVE_PRI)
5979 unsigned span;
5980 struct sig_pri_span *pri;
5981#endif /* defined(HAVE_PRI) */
5982 struct dahdi_pvt *p;
5983
5984 while (num_restart_pending) {
5985 usleep(1);
5986 }
5987
5989 /* Destroy all the interfaces and free their memory */
5990 while (iflist) {
5991 p = iflist;
5992
5993 chan = p->channel;
5994#if defined(HAVE_PRI_SERVICE_MESSAGES)
5995 {
5996 char db_chan_name[20];
5997 char db_answer[5];
5998 char state;
5999 int why = -1;
6000
6001 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, p->span, chan);
6002 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
6003 sscanf(db_answer, "%1c:%30d", &state, &why);
6004 }
6005 if (!why) {
6006 /* SRVST persistence is not required */
6007 ast_db_del(db_chan_name, SRVST_DBKEY);
6008 }
6009 }
6010#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
6011 /* Free associated memory */
6013 ast_verb(3, "Unregistered channel %d\n", chan);
6014 }
6015 ifcount = 0;
6017
6018#if defined(HAVE_PRI)
6019 /* Destroy all of the no B channel interface lists */
6020 for (span = 0; span < NUM_SPANS; ++span) {
6021 if (!pris[span].dchannels[0]) {
6022 break;
6023 }
6024 pri = &pris[span].pri;
6025 ast_mutex_lock(&pri->lock);
6026 while (pri->no_b_chan_iflist) {
6027 p = pri->no_b_chan_iflist;
6028
6029 /* Free associated memory */
6031 }
6032 ast_mutex_unlock(&pri->lock);
6033 }
6034#endif /* defined(HAVE_PRI) */
6035}
6036
6037#if defined(HAVE_PRI)
6038static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
6039
6040static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, const char *digits)
6041{
6042 /* Data will be our digit string */
6043 struct dahdi_pvt *p;
6044
6045 if (ast_strlen_zero(digits)) {
6046 ast_debug(1, "No digit string sent to application!\n");
6047 return -1;
6048 }
6049
6050 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6051
6052 if (!p) {
6053 ast_debug(1, "Unable to find technology private\n");
6054 return -1;
6055 }
6056
6058
6059 return 0;
6060}
6061#endif /* defined(HAVE_PRI) */
6062
6063#if defined(HAVE_PRI)
6064#if defined(HAVE_PRI_PROG_W_CAUSE)
6065static char *dahdi_send_callrerouting_facility_app = "DAHDISendCallreroutingFacility";
6066
6067static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, const char *data)
6068{
6069 /* Data will be our digit string */
6070 struct dahdi_pvt *pvt;
6071 char *parse;
6072 int res;
6074 AST_APP_ARG(destination);
6075 AST_APP_ARG(original);
6076 AST_APP_ARG(reason);
6077 );
6078
6079 if (ast_strlen_zero(data)) {
6080 ast_debug(1, "No data sent to application!\n");
6081 return -1;
6082 }
6083 if (ast_channel_tech(chan) != &dahdi_tech) {
6084 ast_debug(1, "Only DAHDI technology accepted!\n");
6085 return -1;
6086 }
6087 pvt = (struct dahdi_pvt *) ast_channel_tech_pvt(chan);
6088 if (!pvt) {
6089 ast_debug(1, "Unable to find technology private\n");
6090 return -1;
6091 }
6092 switch (pvt->sig) {
6094 break;
6095 default:
6096 ast_debug(1, "callrerouting attempted on non-ISDN channel %s\n",
6097 ast_channel_name(chan));
6098 return -1;
6099 }
6100
6101 parse = ast_strdupa(data);
6103
6104 if (ast_strlen_zero(args.destination)) {
6105 ast_log(LOG_WARNING, "callrerouting facility requires at least destination number argument\n");
6106 return -1;
6107 }
6108
6109 if (ast_strlen_zero(args.original)) {
6110 ast_log(LOG_WARNING, "Callrerouting Facility without original called number argument\n");
6111 args.original = NULL;
6112 }
6113
6114 if (ast_strlen_zero(args.reason)) {
6115 ast_log(LOG_NOTICE, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n");
6116 args.reason = NULL;
6117 }
6118
6120 args.destination, args.original, args.reason);
6121 if (!res) {
6122 /*
6123 * Wait up to 5 seconds for a reply before hanging up this call
6124 * leg if the peer does not disconnect first.
6125 */
6126 ast_safe_sleep(chan, 5000);
6127 }
6128
6129 return -1;
6130}
6131#endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
6132#endif /* defined(HAVE_PRI) */
6133
6134#if defined(HAVE_OPENR2)
6135static const char * const dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
6136
6137static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
6138{
6139 /* data is whether to accept with charge or no charge */
6140 openr2_call_mode_t accept_mode;
6141 int res, timeout, maxloops;
6142 struct ast_frame *f;
6143 struct dahdi_pvt *p;
6144 char *parse;
6146 AST_APP_ARG(charge);
6147 );
6148
6149 if (ast_strlen_zero(data)) {
6150 ast_debug(1, "No data sent to application!\n");
6151 return -1;
6152 }
6153
6154 if (ast_channel_tech(chan) != &dahdi_tech) {
6155 ast_debug(1, "Only DAHDI technology accepted!\n");
6156 return -1;
6157 }
6158
6159 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6160 if (!p) {
6161 ast_debug(1, "Unable to find technology private!\n");
6162 return -1;
6163 }
6164
6165 parse = ast_strdupa(data);
6167
6168 if (ast_strlen_zero(args.charge)) {
6169 ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
6170 return -1;
6171 }
6172
6173 ast_mutex_lock(&p->lock);
6174 if (!p->mfcr2 || !p->mfcr2call) {
6176 ast_debug(1, "Channel %s does not seems to be an R2 active channel!\n", ast_channel_name(chan));
6177 return -1;
6178 }
6179
6180 if (p->mfcr2_call_accepted) {
6182 ast_debug(1, "MFC/R2 call already accepted on channel %s!\n", ast_channel_name(chan));
6183 return 0;
6184 }
6185 accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
6186 if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
6188 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6189 return -1;
6190 }
6192
6193 res = 0;
6194 timeout = 100;
6195 maxloops = 50; /* wait up to 5 seconds */
6196 /* we need to read() until the call is accepted */
6197 while (maxloops > 0) {
6198 maxloops--;
6199 if (ast_check_hangup(chan)) {
6200 break;
6201 }
6202 res = ast_waitfor(chan, timeout);
6203 if (res < 0) {
6204 ast_debug(1, "ast_waitfor failed on channel %s, going out ...\n", ast_channel_name(chan));
6205 res = -1;
6206 break;
6207 }
6208 if (res == 0) {
6209 continue;
6210 }
6211 res = 0;
6212 f = ast_read(chan);
6213 if (!f) {
6214 ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
6215 res = -1;
6216 break;
6217 }
6219 ast_debug(1, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
6220 ast_frfree(f);
6221 res = -1;
6222 break;
6223 }
6224 ast_frfree(f);
6225 ast_mutex_lock(&p->lock);
6226 if (p->mfcr2_call_accepted) {
6228 ast_debug(1, "Accepted MFC/R2 call!\n");
6229 break;
6230 }
6232 }
6233 if (res == -1) {
6234 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6235 }
6236 return res;
6237}
6238
6239static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
6240{
6241 openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
6242 switch (cause) {
6245 case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
6246 r2cause = OR2_CAUSE_BUSY_NUMBER;
6247 break;
6248
6251 r2cause = OR2_CAUSE_NETWORK_CONGESTION;
6252 break;
6253
6255 r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
6256 break;
6257
6260 r2cause = OR2_CAUSE_OUT_OF_ORDER;
6261 break;
6262
6265 r2cause = OR2_CAUSE_NO_ANSWER;
6266 break;
6267
6268 default:
6269 r2cause = OR2_CAUSE_NORMAL_CLEARING;
6270 break;
6271 }
6272 ast_debug(1, "ast cause %d resulted in openr2 cause %d/%s\n",
6273 cause, r2cause, openr2_proto_get_disconnect_string(r2cause));
6274 return r2cause;
6275}
6276#endif
6277
6278static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
6279{
6280 if (p->bufferoverrideinuse) {
6281 /* faxbuffers are in use, revert them */
6282 struct dahdi_bufferinfo bi = {
6283 .txbufpolicy = p->buf_policy,
6284 .rxbufpolicy = p->buf_policy,
6285 .bufsize = p->bufsize,
6286 .numbufs = p->buf_no
6287 };
6288 int bpres;
6289
6290 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
6291 ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast_channel_name(ast), strerror(errno));
6292 }
6293 p->bufferoverrideinuse = 0;
6294 return bpres;
6295 }
6296
6297 return -1;
6298}
6299
6300static int dahdi_hangup(struct ast_channel *ast)
6301{
6302 int res = 0;
6303 int idx,x;
6304 int law;
6305 /*static int restore_gains(struct dahdi_pvt *p);*/
6306 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6307 struct dahdi_params par;
6308
6309 ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast));
6310 if (!ast_channel_tech_pvt(ast)) {
6311 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
6312 return 0;
6313 }
6314
6315 ast_mutex_lock(&p->lock);
6316 p->exten[0] = '\0';
6317 /* Always use sig_analog hangup handling for operator mode */
6318 if (dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6319 p->oprmode = 0;
6320 dahdi_confmute(p, 0);
6321 restore_gains(p);
6322 p->ignoredtmf = 0;
6323 p->waitingfordt.tv_sec = 0;
6324
6325 res = analog_hangup(p->sig_pvt, ast);
6326 revert_fax_buffers(p, ast);
6327
6328 goto hangup_out;
6329 } else {
6330 p->cid_num[0] = '\0';
6331 p->cid_name[0] = '\0';
6332 p->cid_subaddr[0] = '\0';
6333 }
6334
6335#if defined(HAVE_PRI)
6337 x = 1;
6338 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6339
6340 dahdi_confmute(p, 0);
6341 p->muting = 0;
6342 restore_gains(p);
6343 if (p->dsp) {
6344 ast_dsp_free(p->dsp);
6345 p->dsp = NULL;
6346 }
6347 p->ignoredtmf = 0;
6348
6349 /* Real channel, do some fixup */
6350 p->subs[SUB_REAL].owner = NULL;
6351 p->subs[SUB_REAL].needbusy = 0;
6353
6354 p->owner = NULL;
6355 p->cid_tag[0] = '\0';
6356 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6357 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6358 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6359 p->outgoing = 0;
6360 p->digital = 0;
6361 p->faxhandled = 0;
6362 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6363
6364 revert_fax_buffers(p, ast);
6365
6366 p->law = p->law_default;
6367 law = p->law_default;
6368 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6369 if (res < 0) {
6370 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6371 p->channel, strerror(errno));
6372 }
6373
6374 sig_pri_hangup(p->sig_pvt, ast);
6375
6376 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6378
6379 x = 0;
6380 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6381 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6382
6383 p->rdnis[0] = '\0';
6385 reset_conf(p);
6386
6387 /* Restore data mode */
6388 x = 0;
6389 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6390
6391 if (num_restart_pending == 0) {
6393 }
6394 goto hangup_out;
6395 }
6396#endif /* defined(HAVE_PRI) */
6397
6398#if defined(HAVE_SS7)
6399 if (p->sig == SIG_SS7) {
6400 x = 1;
6401 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6402
6403 dahdi_confmute(p, 0);
6404 p->muting = 0;
6405 restore_gains(p);
6406 if (p->dsp) {
6407 ast_dsp_free(p->dsp);
6408 p->dsp = NULL;
6409 }
6410 p->ignoredtmf = 0;
6411
6412 /* Real channel, do some fixup */
6413 p->subs[SUB_REAL].owner = NULL;
6414 p->subs[SUB_REAL].needbusy = 0;
6416
6417 p->owner = NULL;
6418 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6419 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6420 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6421 p->outgoing = 0;
6422 p->digital = 0;
6423 p->faxhandled = 0;
6424 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6425
6426 revert_fax_buffers(p, ast);
6427
6428 p->law = p->law_default;
6429 law = p->law_default;
6430 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6431 if (res < 0) {
6432 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6433 p->channel, strerror(errno));
6434 }
6435
6436 sig_ss7_hangup(p->sig_pvt, ast);
6437
6438 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6440
6441 x = 0;
6442 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6443 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6444
6446 reset_conf(p);
6447
6448 /* Restore data mode */
6449 x = 0;
6450 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6451
6452 if (num_restart_pending == 0) {
6454 }
6455 goto hangup_out;
6456 }
6457#endif /* defined(HAVE_SS7) */
6458
6459 idx = dahdi_get_index(ast, p, 1);
6460
6461 dahdi_confmute(p, 0);
6462 p->muting = 0;
6463 restore_gains(p);
6464 if (p->origcid_num) {
6465 ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
6467 p->origcid_num = NULL;
6468 }
6469 if (p->origcid_name) {
6470 ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
6472 p->origcid_name = NULL;
6473 }
6474 if (p->dsp)
6476
6477 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
6478 p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
6479 p->ignoredtmf = 0;
6480
6481 if (idx > -1) {
6482 /* Real channel, do some fixup */
6483 p->subs[idx].owner = NULL;
6484 p->subs[idx].needanswer = 0;
6485 p->subs[idx].needflash = 0;
6486 p->subs[idx].needringing = 0;
6487 p->subs[idx].needbusy = 0;
6488 p->subs[idx].needcongestion = 0;
6489 p->subs[idx].linear = 0;
6491 dahdi_setlinear(p->subs[idx].dfd, 0);
6492 if (idx == SUB_REAL) {
6493 if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
6494 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
6495 if (p->subs[SUB_CALLWAIT].inthreeway) {
6496 /* We had flipped over to answer a callwait and now it's gone */
6497 ast_debug(1, "We were flipped over to the callwait, moving back and not owning.\n");
6498 /* Move to the call-wait, but un-own us until they flip back. */
6501 p->owner = NULL;
6502 } else {
6503 /* The three way hung up, but we still have a call wait */
6504 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
6507 if (p->subs[SUB_REAL].inthreeway) {
6508 /* This was part of a three way call. Immediately make way for
6509 another call */
6510 ast_debug(1, "Call was complete, setting owner to former third call\n");
6511 p->owner = p->subs[SUB_REAL].owner;
6512 } else {
6513 /* This call hasn't been completed yet... Set owner to NULL */
6514 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6515 p->owner = NULL;
6516 }
6517 p->subs[SUB_REAL].inthreeway = 0;
6518 }
6519 } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
6520 /* Move to the call-wait and switch back to them. */
6523 p->owner = p->subs[SUB_REAL].owner;
6525 p->subs[SUB_REAL].needanswer = 1;
6527 } else if (p->subs[SUB_THREEWAY].dfd > -1) {
6530 if (p->subs[SUB_REAL].inthreeway) {
6531 /* This was part of a three way call. Immediately make way for
6532 another call */
6533 ast_debug(1, "Call was complete, setting owner to former third call\n");
6534 p->owner = p->subs[SUB_REAL].owner;
6535 } else {
6536 /* This call hasn't been completed yet... Set owner to NULL */
6537 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6538 p->owner = NULL;
6539 }
6540 p->subs[SUB_REAL].inthreeway = 0;
6541 }
6542 } else if (idx == SUB_CALLWAIT) {
6543 /* Ditch the holding callwait call, and immediately make it available */
6544 if (p->subs[SUB_CALLWAIT].inthreeway) {
6545 /* This is actually part of a three way, placed on hold. Place the third part
6546 on music on hold now */
6547 if (p->subs[SUB_THREEWAY].owner) {
6549 }
6551 /* Make it the call wait now */
6554 } else
6556 } else if (idx == SUB_THREEWAY) {
6557 if (p->subs[SUB_CALLWAIT].inthreeway) {
6558 /* The other party of the three way call is currently in a call-wait state.
6559 Start music on hold for them, and take the main guy out of the third call */
6560 if (p->subs[SUB_CALLWAIT].owner) {
6562 }
6564 }
6565 p->subs[SUB_REAL].inthreeway = 0;
6566 /* If this was part of a three way call index, let us make
6567 another three way call */
6569 } else {
6570 /* This wasn't any sort of call, but how are we an index? */
6571 ast_log(LOG_WARNING, "Index found but not any type of call?\n");
6572 }
6573 }
6574
6575 if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
6576 p->owner = NULL;
6577 p->ringt = 0;
6578 p->distinctivering = 0;
6579 p->confirmanswer = 0;
6580 p->outgoing = 0;
6581 p->digital = 0;
6582 p->faxhandled = 0;
6583 p->pulsedial = 0;
6584 if (p->dsp) {
6585 ast_dsp_free(p->dsp);
6586 p->dsp = NULL;
6587 }
6588
6589 revert_fax_buffers(p, ast);
6590
6591 p->law = p->law_default;
6592 law = p->law_default;
6593 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6594 if (res < 0)
6595 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
6596 /* Perform low level hangup if no owner left */
6597#ifdef HAVE_OPENR2
6598 if (p->mfcr2 && p->mfcr2call && openr2_chan_get_direction(p->r2chan) != OR2_DIR_STOPPED) {
6599 ast_debug(1, "disconnecting MFC/R2 call on chan %d\n", p->channel);
6600 /* If it's an incoming call, check the mfcr2_forced_release setting */
6601 if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
6602 dahdi_r2_disconnect_call(p, OR2_CAUSE_FORCED_RELEASE);
6603 } else {
6604 const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
6605 int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
6606 openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
6607 : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast));
6608 dahdi_r2_disconnect_call(p, r2cause);
6609 }
6610 } else if (p->mfcr2call) {
6611 ast_debug(1, "Clearing call request on channel %d\n", p->channel);
6612 /* since ast_request() was called but not ast_call() we have not yet dialed
6613 and the openr2 stack will not call on_call_end callback, we need to unset
6614 the mfcr2call flag and bump the monitor count so the monitor thread can take
6615 care of this channel events from now on */
6616 p->mfcr2call = 0;
6617 }
6618#endif
6619 switch (p->sig) {
6620 case SIG_SS7:
6621 case SIG_MFCR2:
6623 case 0:
6624 break;
6625 default:
6626 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
6627 break;
6628 }
6629 if (res < 0) {
6630 ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast_channel_name(ast));
6631 }
6632 switch (p->sig) {
6633 case SIG_FXOGS:
6634 case SIG_FXOLS:
6635 case SIG_FXOKS:
6636 memset(&par, 0, sizeof(par));
6637 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
6638 if (!res) {
6639 struct analog_pvt *analog_p = p->sig_pvt;
6640#if 0
6641 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
6642#endif
6643 /* If they're off hook, try playing congestion */
6644 if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
6645 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
6646 else
6647 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6648 analog_p->fxsoffhookstate = par.rxisoffhook;
6649 }
6650 break;
6651 case SIG_FXSGS:
6652 case SIG_FXSLS:
6653 case SIG_FXSKS:
6654 /* Make sure we're not made available for at least two seconds assuming
6655 we were actually used for an inbound or outbound call. */
6657 time(&p->guardtime);
6658 p->guardtime += 2;
6659 }
6660 break;
6661 default:
6662 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6663 break;
6664 }
6665 if (p->sig)
6667 x = 0;
6668 ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
6669 ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
6670 p->didtdd = 0;
6671 p->callwaitcas = 0;
6674 if (dahdi_analog_lib_handles(p->sig, p->radio, 0) && !p->owner) {
6675 /* The code in sig_analog handles resetting to permdialmode on originations;
6676 * this addresses the edge case of multiple calls that do not involve
6677 * origination inbetween, i.e. multiple incoming calls. */
6678 struct analog_pvt *analog_p = p->sig_pvt;
6679 /* If no calls remain, reset dialmode.
6680 * This way, if the next call is an incoming call,
6681 * it's already been reset. */
6682 analog_p->dialmode = analog_p->permdialmode;
6683 }
6684 p->waitingfordt.tv_sec = 0;
6685 p->dialing = 0;
6686 p->rdnis[0] = '\0';
6688 reset_conf(p);
6689 /* Restore data mode */
6690 switch (p->sig) {
6692 case SIG_SS7:
6693 x = 0;
6694 ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
6695 break;
6696 default:
6697 break;
6698 }
6699 if (num_restart_pending == 0)
6701 }
6702
6703 p->callwaitingrepeat = 0;
6704 p->cidcwexpire = 0;
6705 p->cid_suppress_expire = 0;
6706 p->oprmode = 0;
6707hangup_out:
6709 ast_free(p->cidspill);
6710 p->cidspill = NULL;
6711
6712 if (p->reoriginate && p->sig == SIG_FXOKS && dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6713 /* Automatic reorigination: if all calls towards a user have hung up,
6714 * give dial tone again, so user doesn't need to cycle the hook state manually. */
6715 if (my_is_off_hook(p) && !p->owner) {
6716 /* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
6717 ast_debug(1, "Queuing reorigination for channel %d\n", p->channel);
6718 my_play_tone(p, SUB_REAL, -1); /* Stop any congestion tone that may be present. */
6719 /* Must wait for the loop disconnect to end.
6720 * Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
6721 * Calling usleep on an active DAHDI channel is a no-no, but this is okay.
6722 */
6723 usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
6724 /* If the line is still off-hook and ownerless, actually queue the reorigination.
6725 * do_monitor will actually go ahead and do it. */
6726 if (!p->owner && my_is_off_hook(p)) {
6727 p->doreoriginate = 1; /* Tell do_monitor to reoriginate this channel */
6728 /* Note, my_off_hook will fail if called before the loop disconnect has finished
6729 * (important for FXOKS signaled channels). This is because DAHDI will reject
6730 * DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
6731 * so we have to wait for that to finish (see comment above).
6732 * do_monitor itself cannot block, so make the blocking usleep call
6733 * here in the channel thread instead.
6734 */
6735 my_off_hook(p); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
6736 } else {
6737 ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p->channel);
6738 }
6739 }
6740 }
6741
6743 ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
6744
6746 if (p->restartpending) {
6748 }
6749
6750 if (p->destroy) {
6751 destroy_channel(p, 0);
6752 }
6754
6756 return 0;
6757}
6758
6759static int dahdi_answer(struct ast_channel *ast)
6760{
6761 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6762 int res = 0;
6763 int idx;
6764 ast_setstate(ast, AST_STATE_UP);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
6765 ast_mutex_lock(&p->lock);
6766 idx = dahdi_get_index(ast, p, 0);
6767 if (idx < 0)
6768 idx = SUB_REAL;
6769 /* nothing to do if a radio channel */
6770 if ((p->radio || (p->oprmode < 0))) {
6772 return 0;
6773 }
6774
6775 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
6776 res = analog_answer(p->sig_pvt, ast);
6778 return res;
6779 }
6780
6781 switch (p->sig) {
6782#if defined(HAVE_PRI)
6784 res = sig_pri_answer(p->sig_pvt, ast);
6785 break;
6786#endif /* defined(HAVE_PRI) */
6787#if defined(HAVE_SS7)
6788 case SIG_SS7:
6789 res = sig_ss7_answer(p->sig_pvt, ast);
6790 break;
6791#endif /* defined(HAVE_SS7) */
6792#ifdef HAVE_OPENR2
6793 case SIG_MFCR2:
6794 if (!p->mfcr2_call_accepted) {
6795 /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
6796 openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
6797 p->mfcr2_answer_pending = 1;
6798 if (p->mfcr2_charge_calls) {
6799 ast_debug(1, "Accepting MFC/R2 call with charge before answering on chan %d\n", p->channel);
6800 openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
6801 } else {
6802 ast_debug(1, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p->channel);
6803 openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
6804 }
6805 } else {
6806 ast_debug(1, "Answering MFC/R2 call on chan %d\n", p->channel);
6807 dahdi_r2_answer(p);
6808 }
6809 break;
6810#endif
6811 case 0:
6813 return 0;
6814 default:
6815 ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
6816 res = -1;
6817 break;
6818 }
6820 return res;
6821}
6822
6824{
6825 int val = 0;
6826
6827 p->ignoredtmf = 1;
6828
6829 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6830
6831 if (!p->hardwaredtmf && p->dsp) {
6832 p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
6834 }
6835}
6836
6838{
6839 int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
6840
6841 if (p->channel == CHAN_PSEUDO)
6842 return;
6843
6844 p->ignoredtmf = 0;
6845
6846 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6847
6848 if (!p->hardwaredtmf && p->dsp) {
6851 }
6852}
6853
6854static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
6855{
6856 char *cp;
6857 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
6858
6859 /* all supported options require data */
6860 if (!p || !data || (*datalen < 1)) {
6861 errno = EINVAL;
6862 return -1;
6863 }
6864
6865 switch (option) {
6866 case AST_OPTION_TDD:
6867 cp = (char *) data;
6868 if (p->mate) {
6869 *cp = 2;
6870 } else {
6871 *cp = p->tdd ? 1 : 0;
6872 }
6873 break;
6875 cp = (char *) data;
6876 *cp = p->ignoredtmf ? 0 : 1;
6877 ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6878 break;
6880 cp = (char *) data;
6881 *cp = (p->dsp_features & DSP_FEATURE_FAX_DETECT) ? 0 : 1;
6882 ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6883 break;
6885#if defined(HAVE_PRI)
6886#if defined(HAVE_PRI_CCSS)
6888 ast_copy_string((char *) data, dahdi_pri_cc_type, *datalen);
6889 break;
6890 }
6891#endif /* defined(HAVE_PRI_CCSS) */
6892#endif /* defined(HAVE_PRI) */
6893 return -1;
6894 default:
6895 return -1;
6896 }
6897
6898 errno = 0;
6899
6900 return 0;
6901}
6902
6903static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
6904{
6905 char *cp;
6906 signed char *scp;
6907 int x;
6908 int idx;
6909 struct dahdi_pvt *p = ast_channel_tech_pvt(chan), *pp;
6910 struct oprmode *oprmode;
6911
6912
6913 /* all supported options require data */
6914 if (!p || !data || (datalen < 1)) {
6915 errno = EINVAL;
6916 return -1;
6917 }
6918
6919 switch (option) {
6920 case AST_OPTION_TXGAIN:
6921 scp = (signed char *) data;
6922 idx = dahdi_get_index(chan, p, 0);
6923 if (idx < 0) {
6924 ast_log(LOG_WARNING, "No index in TXGAIN?\n");
6925 return -1;
6926 }
6927 ast_debug(1, "Setting actual tx gain on %s to %f\n", ast_channel_name(chan), p->txgain + (float) *scp);
6928 return set_actual_txgain(p->subs[idx].dfd, p->txgain + (float) *scp, p->txdrc, p->law);
6929 case AST_OPTION_RXGAIN:
6930 scp = (signed char *) data;
6931 idx = dahdi_get_index(chan, p, 0);
6932 if (idx < 0) {
6933 ast_log(LOG_WARNING, "No index in RXGAIN?\n");
6934 return -1;
6935 }
6936 ast_debug(1, "Setting actual rx gain on %s to %f\n", ast_channel_name(chan), p->rxgain + (float) *scp);
6937 return set_actual_rxgain(p->subs[idx].dfd, p->rxgain + (float) *scp, p->rxdrc, p->law);
6939 if (!p->dsp)
6940 break;
6941 cp = (char *) data;
6942 switch (*cp) {
6943 case 1:
6944 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",ast_channel_name(chan));
6945 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */
6946 break;
6947 case 2:
6948 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",ast_channel_name(chan));
6949 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */
6950 break;
6951 default:
6952 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",ast_channel_name(chan));
6953 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */
6954 break;
6955 }
6956 break;
6957 case AST_OPTION_TDD:
6958 /* turn on or off TDD */
6959 cp = (char *) data;
6960 p->mate = 0;
6961 if (!*cp) { /* turn it off */
6962 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",ast_channel_name(chan));
6963 if (p->tdd)
6964 tdd_free(p->tdd);
6965 p->tdd = 0;
6966 break;
6967 }
6968 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
6969 (*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
6971 /* otherwise, turn it on */
6972 if (!p->didtdd) { /* if haven't done it yet */
6973 unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
6974 unsigned char *buf;
6975 int size, res, fd, len;
6976 struct pollfd fds[1];
6977
6978 buf = mybuf;
6979 memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
6980 ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */
6981 len = 40000;
6982 idx = dahdi_get_index(chan, p, 0);
6983 if (idx < 0) {
6984 ast_log(LOG_WARNING, "No index in TDD?\n");
6985 return -1;
6986 }
6987 fd = p->subs[idx].dfd;
6988 while (len) {
6989 if (ast_check_hangup(chan))
6990 return -1;
6991 size = len;
6992 if (size > READ_SIZE)
6993 size = READ_SIZE;
6994 fds[0].fd = fd;
6995 fds[0].events = POLLPRI | POLLOUT;
6996 fds[0].revents = 0;
6997 res = poll(fds, 1, -1);
6998 if (!res) {
6999 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
7000 continue;
7001 }
7002 /* if got exception */
7003 if (fds[0].revents & POLLPRI)
7004 return -1;
7005 if (!(fds[0].revents & POLLOUT)) {
7006 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
7007 continue;
7008 }
7009 res = write(fd, buf, size);
7010 if (res != size) {
7011 if (res == -1) return -1;
7012 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
7013 break;
7014 }
7015 len -= size;
7016 buf += size;
7017 }
7018 p->didtdd = 1; /* set to have done it now */
7019 }
7020 if (*cp == 2) { /* Mate mode */
7021 if (p->tdd)
7022 tdd_free(p->tdd);
7023 p->tdd = 0;
7024 p->mate = 1;
7025 break;
7026 }
7027 if (!p->tdd) { /* if we don't have one yet */
7028 p->tdd = tdd_new(); /* allocate one */
7029 }
7030 break;
7031 case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */
7032 if (!p->dsp)
7033 break;
7034 cp = (char *) data;
7035 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
7036 *cp ? "ON" : "OFF", (int) *cp, ast_channel_name(chan));
7038 break;
7039 case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */
7040#if defined(HAVE_PRI)
7042 && ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
7043 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
7044 break;
7045 }
7046#endif /* defined(HAVE_PRI) */
7047
7048 cp = (char *) data;
7049 if (!*cp) {
7050 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
7051 x = 0;
7053 } else {
7054 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
7055 x = 1;
7056 }
7057 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
7058 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
7059 break;
7060 case AST_OPTION_OPRMODE: /* Operator services mode */
7061 oprmode = (struct oprmode *) data;
7062 /* We don't support operator mode across technologies */
7063 if (strcasecmp(ast_channel_tech(chan)->type, ast_channel_tech(oprmode->peer)->type)) {
7064 ast_log(LOG_NOTICE, "Operator mode not supported on %s to %s calls.\n",
7066 errno = EINVAL;
7067 return -1;
7068 }
7070 p->oprmode = pp->oprmode = 0;
7071 /* setup peers */
7072 p->oprpeer = pp;
7073 pp->oprpeer = p;
7074 /* setup modes, if any */
7075 if (oprmode->mode)
7076 {
7077 pp->oprmode = oprmode->mode;
7078 p->oprmode = -oprmode->mode;
7079 }
7080 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
7082 break;
7083 case AST_OPTION_ECHOCAN:
7084 cp = (char *) data;
7085 if (*cp) {
7086 ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
7087 dahdi_ec_enable(p);
7088 } else {
7089 ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
7091 }
7092 break;
7094 cp = (char *) data;
7095 ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7096 if (*cp) {
7098 } else {
7100 }
7101 break;
7103 cp = (char *) data;
7104 if (p->dsp) {
7105 ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7106 if (*cp) {
7108 } else {
7109 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7110 }
7112 }
7113 break;
7114 default:
7115 return -1;
7116 }
7117 errno = 0;
7118
7119 return 0;
7120}
7121
7122static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
7123{
7124 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7125 int res = 0;
7126
7127 if (!p) {
7128 /* No private structure! */
7129 *buf = '\0';
7130 return -1;
7131 }
7132
7133 if (!strcasecmp(data, "rxgain")) {
7134 ast_mutex_lock(&p->lock);
7135 snprintf(buf, len, "%f", p->rxgain);
7137 } else if (!strcasecmp(data, "txgain")) {
7138 ast_mutex_lock(&p->lock);
7139 snprintf(buf, len, "%f", p->txgain);
7141 } else if (!strcasecmp(data, "dahdi_channel")) {
7142 ast_mutex_lock(&p->lock);
7143 snprintf(buf, len, "%d", p->channel);
7145 } else if (!strcasecmp(data, "dahdi_span")) {
7146 ast_mutex_lock(&p->lock);
7147 snprintf(buf, len, "%d", p->span);
7149 } else if (!strcasecmp(data, "dahdi_group")) {
7150 ast_mutex_lock(&p->lock);
7151 snprintf(buf, len, "%llu", p->group);
7153 } else if (!strcasecmp(data, "dahdi_type")) {
7154 ast_mutex_lock(&p->lock);
7155 switch (p->sig) {
7156#if defined(HAVE_OPENR2)
7157 case SIG_MFCR2:
7158 ast_copy_string(buf, "mfc/r2", len);
7159 break;
7160#endif /* defined(HAVE_OPENR2) */
7161#if defined(HAVE_PRI)
7163 ast_copy_string(buf, "pri", len);
7164 break;
7165#endif /* defined(HAVE_PRI) */
7166 case 0:
7167 ast_copy_string(buf, "pseudo", len);
7168 break;
7169#if defined(HAVE_SS7)
7170 case SIG_SS7:
7171 ast_copy_string(buf, "ss7", len);
7172 break;
7173#endif /* defined(HAVE_SS7) */
7174 default:
7175 /* The only thing left is analog ports. */
7176 ast_copy_string(buf, "analog", len);
7177 break;
7178 }
7180#if defined(HAVE_PRI)
7181#if defined(HAVE_PRI_REVERSE_CHARGE)
7182 } else if (!strcasecmp(data, "reversecharge")) {
7183 ast_mutex_lock(&p->lock);
7184 switch (p->sig) {
7186 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->reverse_charging_indication);
7187 break;
7188 default:
7189 *buf = '\0';
7190 res = -1;
7191 break;
7192 }
7194#endif
7195#if defined(HAVE_PRI_SETUP_KEYPAD)
7196 } else if (!strcasecmp(data, "keypad_digits")) {
7197 ast_mutex_lock(&p->lock);
7198 switch (p->sig) {
7200 ast_copy_string(buf, ((struct sig_pri_chan *) p->sig_pvt)->keypad_digits,
7201 len);
7202 break;
7203 default:
7204 *buf = '\0';
7205 res = -1;
7206 break;
7207 }
7209#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
7210 } else if (!strcasecmp(data, "no_media_path")) {
7211 ast_mutex_lock(&p->lock);
7212 switch (p->sig) {
7214 /*
7215 * TRUE if the call is on hold or is call waiting because
7216 * there is no media path available.
7217 */
7218 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel);
7219 break;
7220 default:
7221 *buf = '\0';
7222 res = -1;
7223 break;
7224 }
7226#endif /* defined(HAVE_PRI) */
7227 } else if (!strcasecmp(data, "dialmode")) {
7228 struct analog_pvt *analog_p;
7229 ast_mutex_lock(&p->lock);
7230 analog_p = p->sig_pvt;
7231 /* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
7232 if (dahdi_analog_lib_handles(p->sig, 0, 0) && analog_p) {
7233 switch (analog_p->dialmode) {
7235 ast_copy_string(buf, "both", len);
7236 break;
7238 ast_copy_string(buf, "pulse", len);
7239 break;
7241 ast_copy_string(buf, "dtmf", len);
7242 break;
7244 ast_copy_string(buf, "none", len);
7245 break;
7246 }
7247 } else {
7248 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7249 *buf = '\0';
7250 res = -1;
7251 }
7253 } else {
7254 *buf = '\0';
7255 res = -1;
7256 }
7257
7258 return res;
7259}
7260
7261
7262static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
7263{
7264 int res;
7265 char policy_str[21] = "";
7266
7267 if ((res = sscanf(parse, "%30d,%20s", num_buffers, policy_str)) != 2) {
7268 ast_log(LOG_WARNING, "Parsing buffer string '%s' failed.\n", parse);
7269 return 1;
7270 }
7271 if (*num_buffers < 0) {
7272 ast_log(LOG_WARNING, "Invalid buffer count given '%d'.\n", *num_buffers);
7273 return -1;
7274 }
7275 if (!strcasecmp(policy_str, "full")) {
7276 *policy = DAHDI_POLICY_WHEN_FULL;
7277 } else if (!strcasecmp(policy_str, "immediate")) {
7278 *policy = DAHDI_POLICY_IMMEDIATE;
7279#if defined(HAVE_DAHDI_HALF_FULL)
7280 } else if (!strcasecmp(policy_str, "half")) {
7281 *policy = DAHDI_POLICY_HALF_FULL;
7282#endif
7283 } else {
7284 ast_log(LOG_WARNING, "Invalid policy name given '%s'.\n", policy_str);
7285 return -1;
7286 }
7287
7288 return 0;
7289}
7290
7291static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
7292{
7293 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7294 int res = 0;
7295
7296 if (!p) {
7297 /* No private structure! */
7298 return -1;
7299 }
7300
7301 if (!strcasecmp(data, "buffers")) {
7302 int num_bufs, policy;
7303
7304 if (!(parse_buffers_policy(value, &num_bufs, &policy))) {
7305 struct dahdi_bufferinfo bi = {
7306 .txbufpolicy = policy,
7307 .rxbufpolicy = policy,
7308 .bufsize = p->bufsize,
7309 .numbufs = num_bufs,
7310 };
7311 int bpres;
7312
7313 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7314 ast_log(LOG_WARNING, "Channel '%d' unable to override buffer policy: %s\n", p->channel, strerror(errno));
7315 } else {
7316 p->bufferoverrideinuse = 1;
7317 }
7318 } else {
7319 res = -1;
7320 }
7321 } else if (!strcasecmp(data, "echocan_mode")) {
7322 if (!strcasecmp(value, "on")) {
7323 ast_mutex_lock(&p->lock);
7324 dahdi_ec_enable(p);
7326 } else if (!strcasecmp(value, "off")) {
7327 ast_mutex_lock(&p->lock);
7330#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7331 } else if (!strcasecmp(value, "fax")) {
7332 int blah = 1;
7333
7334 ast_mutex_lock(&p->lock);
7335 if (!p->echocanon) {
7336 dahdi_ec_enable(p);
7337 }
7338 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7339 ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
7340 }
7342 } else if (!strcasecmp(value, "voice")) {
7343 int blah = 0;
7344
7345 ast_mutex_lock(&p->lock);
7346 if (!p->echocanon) {
7347 dahdi_ec_enable(p);
7348 }
7349 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7350 ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
7351 }
7353#endif
7354 } else {
7355 ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
7356 res = -1;
7357 }
7358 } else if (!strcasecmp(data, "dialmode")) {
7359 struct analog_pvt *analog_p;
7360
7361 ast_mutex_lock(&p->lock);
7362 analog_p = p->sig_pvt;
7363 if (!dahdi_analog_lib_handles(p->sig, 0, 0) || !analog_p) {
7364 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7366 return -1;
7367 }
7368 /* analog pvt is used for pulse dialing, so update both */
7369 if (!strcasecmp(value, "pulse")) {
7370 analog_p->dialmode = ANALOG_DIALMODE_PULSE;
7371 } else if (!strcasecmp(value, "dtmf") || !strcasecmp(value, "tone")) {
7372 analog_p->dialmode = ANALOG_DIALMODE_DTMF;
7373 } else if (!strcasecmp(value, "none")) {
7374 analog_p->dialmode = ANALOG_DIALMODE_NONE;
7375 } else if (!strcasecmp(value, "both")) {
7376 analog_p->dialmode = ANALOG_DIALMODE_BOTH;
7377 } else {
7378 ast_log(LOG_WARNING, "'%s' is an invalid setting for %s\n", value, data);
7379 res = -1;
7380 }
7382 } else if (!strcasecmp(data, "waitfordialtone")) {
7383 if (ast_strlen_zero(value)) {
7384 ast_log(LOG_WARNING, "waitfordialtone requires a duration in ms\n");
7385 return -1;
7386 }
7387
7388 ast_mutex_lock(&p->lock);
7389 if (!CANPROGRESSDETECT(p)) {
7390 ast_log(LOG_WARNING, "%s only supported on analog trunks\n", data);
7392 return -1;
7393 }
7394 /* Only set the temp waitfordialtone setting, not the permanent one. */
7395 p->waitfordialtonetemp = atoi(value);
7397 } else {
7398 res = -1;
7399 }
7400
7401 return res;
7402}
7403
7404void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
7405{
7406 /* Unlink a specific slave or all slaves/masters from a given master */
7407 int x;
7408 int hasslaves;
7409 if (!master)
7410 return;
7411 if (needlock) {
7412 ast_mutex_lock(&master->lock);
7413 if (slave) {
7414 while (ast_mutex_trylock(&slave->lock)) {
7415 DEADLOCK_AVOIDANCE(&master->lock);
7416 }
7417 }
7418 }
7419 hasslaves = 0;
7420 for (x = 0; x < MAX_SLAVES; x++) {
7421 if (master->slaves[x]) {
7422 if (!slave || (master->slaves[x] == slave)) {
7423 /* Take slave out of the conference */
7424 ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
7425 conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
7426 conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
7427 master->slaves[x]->master = NULL;
7428 master->slaves[x] = NULL;
7429 } else
7430 hasslaves = 1;
7431 }
7432 if (!hasslaves)
7433 master->inconference = 0;
7434 }
7435 if (!slave) {
7436 if (master->master) {
7437 /* Take master out of the conference */
7438 conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
7439 conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
7440 hasslaves = 0;
7441 for (x = 0; x < MAX_SLAVES; x++) {
7442 if (master->master->slaves[x] == master)
7443 master->master->slaves[x] = NULL;
7444 else if (master->master->slaves[x])
7445 hasslaves = 1;
7446 }
7447 if (!hasslaves)
7448 master->master->inconference = 0;
7449 }
7450 master->master = NULL;
7451 }
7452 dahdi_conf_update(master);
7453 if (needlock) {
7454 if (slave)
7455 ast_mutex_unlock(&slave->lock);
7456 ast_mutex_unlock(&master->lock);
7457 }
7458}
7459
7460void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
7461{
7462 int x;
7463 if (!slave || !master) {
7464 ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
7465 return;
7466 }
7467 for (x = 0; x < MAX_SLAVES; x++) {
7468 if (!master->slaves[x]) {
7469 master->slaves[x] = slave;
7470 break;
7471 }
7472 }
7473 if (x >= MAX_SLAVES) {
7474 ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
7475 master->slaves[MAX_SLAVES - 1] = slave;
7476 }
7477 if (slave->master)
7478 ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
7479 slave->master = master;
7480
7481 ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
7482}
7483
7484static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
7485{
7486 struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
7487 int x;
7488
7489 ast_mutex_lock(&p->lock);
7490
7491 ast_debug(1, "New owner for channel %d is %s\n", p->channel, ast_channel_name(newchan));
7492 if (p->owner == oldchan) {
7493 p->owner = newchan;
7494 }
7495 for (x = 0; x < 3; x++) {
7496 if (p->subs[x].owner == oldchan) {
7497 if (!x) {
7499 }
7500 p->subs[x].owner = newchan;
7501 }
7502 }
7503 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
7504 analog_fixup(oldchan, newchan, p->sig_pvt);
7505#if defined(HAVE_PRI)
7506 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
7507 sig_pri_fixup(oldchan, newchan, p->sig_pvt);
7508#endif /* defined(HAVE_PRI) */
7509#if defined(HAVE_SS7)
7510 } else if (p->sig == SIG_SS7) {
7511 sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
7512#endif /* defined(HAVE_SS7) */
7513 }
7515
7517
7518 if (ast_channel_state(newchan) == AST_STATE_RINGING) {
7520 }
7521 return 0;
7522}
7523
7524static int dahdi_ring_phone(struct dahdi_pvt *p)
7525{
7526 int x;
7527 int res;
7528 /* Make sure our transmit state is on hook */
7529 x = 0;
7530 x = DAHDI_ONHOOK;
7531 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7532 do {
7533 x = DAHDI_RING;
7534 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7535 if (res) {
7536 switch (errno) {
7537 case EBUSY:
7538 case EINTR:
7539 /* Wait just in case */
7540 usleep(10000);
7541 continue;
7542 case EINPROGRESS:
7543 res = 0;
7544 break;
7545 default:
7546 ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
7547 res = 0;
7548 }
7549 }
7550 } while (res);
7551 return res;
7552}
7553
7554static void *analog_ss_thread(void *data);
7555
7556/*!
7557 * \internal
7558 * \brief Attempt to transfer 3-way call.
7559 *
7560 * \param p DAHDI private structure.
7561 *
7562 * \note On entry these locks are held: real-call, private, 3-way call.
7563 * \note On exit these locks are held: real-call, private.
7564 *
7565 * \retval 0 on success.
7566 * \retval -1 on error.
7567 */
7568static int attempt_transfer(struct dahdi_pvt *p)
7569{
7570 struct ast_channel *owner_real;
7571 struct ast_channel *owner_3way;
7572 enum ast_transfer_result xfer_res;
7573 int res = 0;
7574
7575 owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
7576 owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
7577
7578 ast_verb(3, "TRANSFERRING %s to %s\n",
7579 ast_channel_name(owner_3way), ast_channel_name(owner_real));
7580
7581 ast_channel_unlock(owner_real);
7582 ast_channel_unlock(owner_3way);
7584
7585 xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
7586 if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
7588 res = -1;
7589 }
7590
7591 /* Must leave with these locked. */
7592 ast_channel_lock(owner_real);
7593 ast_mutex_lock(&p->lock);
7594
7595 ast_channel_unref(owner_real);
7596 ast_channel_unref(owner_3way);
7597
7598 return res;
7599}
7600
7601static int check_for_conference(struct dahdi_pvt *p)
7602{
7603 struct dahdi_confinfo ci;
7604 /* Fine if we already have a master, etc */
7605 if (p->master || (p->confno > -1))
7606 return 0;
7607 memset(&ci, 0, sizeof(ci));
7608 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
7609 ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
7610 return 0;
7611 }
7612 /* If we have no master and don't have a confno, then
7613 if we're in a conference, it's probably a MeetMe room or
7614 some such, so don't let us 3-way out! */
7615 if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
7616 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
7617 return 1;
7618 }
7619 return 0;
7620}
7621
7622/*! Checks channel for alarms
7623 * \param p a channel to check for alarms.
7624 * \returns the alarms on the span to which the channel belongs, or alarms on
7625 * the channel if no span alarms.
7626 */
7627static int get_alarms(struct dahdi_pvt *p)
7628{
7629 int res;
7630 struct dahdi_spaninfo zi;
7631 struct dahdi_params params;
7632
7633 memset(&zi, 0, sizeof(zi));
7634 zi.spanno = p->span;
7635
7636 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
7637 if (zi.alarms != DAHDI_ALARM_NONE)
7638 return zi.alarms;
7639 } else {
7640 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
7641 return 0;
7642 }
7643
7644 /* No alarms on the span. Check for channel alarms. */
7645 memset(&params, 0, sizeof(params));
7646 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
7647 return params.chan_alarms;
7648
7649 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
7650
7651 return DAHDI_ALARM_NONE;
7652}
7653
7654static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
7655{
7656 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7657 struct ast_frame *f = *dest;
7658
7659 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
7660 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
7661 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
7662
7663 if (p->confirmanswer) {
7664 if (f->frametype == AST_FRAME_DTMF_END) {
7665 ast_debug(1, "Confirm answer on %s!\n", ast_channel_name(ast));
7666 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
7667 of a DTMF digit */
7670 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
7671 p->confirmanswer = 0;
7672 } else {
7673 p->subs[idx].f.frametype = AST_FRAME_NULL;
7674 p->subs[idx].f.subclass.integer = 0;
7675 }
7676 *dest = &p->subs[idx].f;
7677 } else if (p->callwaitcas) {
7678 if (f->frametype == AST_FRAME_DTMF_END) {
7679 if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
7680 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
7681 ast_free(p->cidspill);
7682 p->cidspill = NULL;
7683 send_cwcidspill(p);
7684 }
7685 p->callwaitcas = 0;
7686 }
7687 p->subs[idx].f.frametype = AST_FRAME_NULL;
7688 p->subs[idx].f.subclass.integer = 0;
7689 *dest = &p->subs[idx].f;
7690 } else if (f->subclass.integer == 'f') {
7691 if (f->frametype == AST_FRAME_DTMF_END) {
7692 /* Fax tone -- Handle and return NULL */
7693 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
7694 /* If faxbuffers are configured, use them for the fax transmission */
7695 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
7696 struct dahdi_bufferinfo bi = {
7697 .txbufpolicy = p->faxbuf_policy,
7698 .bufsize = p->bufsize,
7699 .numbufs = p->faxbuf_no
7700 };
7701 int res;
7702
7703 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7704 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
7705 } else {
7706 p->bufferoverrideinuse = 1;
7707 }
7708 }
7709 p->faxhandled = 1;
7710 if (p->dsp) {
7711 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7713 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
7714 }
7715 if (strcmp(ast_channel_exten(ast), "fax")) {
7716 const char *target_context = ast_channel_context(ast);
7717
7718 /*
7719 * We need to unlock 'ast' here because ast_exists_extension has the
7720 * potential to start autoservice on the channel. Such action is prone
7721 * to deadlock if the channel is locked.
7722 *
7723 * ast_async_goto() has its own restriction on not holding the
7724 * channel lock.
7725 */
7727 ast_channel_unlock(ast);
7728 if (ast_exists_extension(ast, target_context, "fax", 1,
7729 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
7730 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
7731 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
7732 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
7733 if (ast_async_goto(ast, target_context, "fax", 1))
7734 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
7735 } else {
7736 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
7737 }
7738 ast_channel_lock(ast);
7739 ast_mutex_lock(&p->lock);
7740 } else {
7741 ast_debug(1, "Already in a fax extension, not redirecting\n");
7742 }
7743 } else {
7744 ast_debug(1, "Fax already handled\n");
7745 }
7746 dahdi_confmute(p, 0);
7747 }
7748 p->subs[idx].f.frametype = AST_FRAME_NULL;
7749 p->subs[idx].f.subclass.integer = 0;
7750 *dest = &p->subs[idx].f;
7751 }
7752}
7753
7754static void publish_span_alarm(int span, const char *alarm_txt)
7755{
7756 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7757
7758 body = ast_json_pack("{s: i, s: s}",
7759 "Span", span,
7760 "Alarm", alarm_txt);
7761 if (!body) {
7762 return;
7763 }
7764
7765 ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
7766}
7767
7768static void publish_channel_alarm(int channel, const char *alarm_txt)
7769{
7770 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7771 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
7772 if (!dahdi_chan) {
7773 return;
7774 }
7775
7776 ast_str_set(&dahdi_chan, 0, "%d", channel);
7777 body = ast_json_pack("{s: s, s: s}",
7778 "DAHDIChannel", ast_str_buffer(dahdi_chan),
7779 "Alarm", alarm_txt);
7780 if (!body) {
7781 return;
7782 }
7783
7785}
7786
7787static void handle_alarms(struct dahdi_pvt *p, int alms)
7788{
7789 const char *alarm_str;
7790
7791#if defined(HAVE_PRI)
7793 return;
7794 }
7795#endif /* defined(HAVE_PRI) */
7796
7797 alarm_str = alarm2str(alms);
7799 ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
7800 publish_channel_alarm(p->channel, alarm_str);
7801 }
7802
7804 ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
7805 publish_span_alarm(p->span, alarm_str);
7806 }
7807}
7808
7809static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
7810{
7811 int res, x;
7812 int idx, mysig;
7813 char *c;
7814 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7815 pthread_t threadid;
7816 struct ast_channel *chan;
7817 struct ast_frame *f;
7818
7819 idx = dahdi_get_index(ast, p, 0);
7820 if (idx < 0) {
7821 return &ast_null_frame;
7822 }
7823 mysig = p->sig;
7824 if (p->outsigmod > -1)
7825 mysig = p->outsigmod;
7826 p->subs[idx].f.frametype = AST_FRAME_NULL;
7827 p->subs[idx].f.subclass.integer = 0;
7828 p->subs[idx].f.datalen = 0;
7829 p->subs[idx].f.samples = 0;
7830 p->subs[idx].f.mallocd = 0;
7831 p->subs[idx].f.offset = 0;
7832 p->subs[idx].f.src = "dahdi_handle_event";
7833 p->subs[idx].f.data.ptr = NULL;
7834 f = &p->subs[idx].f;
7835
7836 if (p->fake_event) {
7837 res = p->fake_event;
7838 p->fake_event = 0;
7839 } else
7840 res = dahdi_get_event(p->subs[idx].dfd);
7841
7842 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
7843
7844 if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
7845 p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
7846 ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
7847#if defined(HAVE_PRI)
7849 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7850 && p->pri
7851 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7852 /* absorb event */
7853 } else
7854#endif /* defined(HAVE_PRI) */
7855 {
7856 /* Unmute conference */
7857 dahdi_confmute(p, 0);
7859 p->subs[idx].f.subclass.integer = res & 0xff;
7860 dahdi_handle_dtmf(ast, idx, &f);
7861 }
7862 return f;
7863 }
7864
7865 if (res & DAHDI_EVENT_DTMFDOWN) {
7866 ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
7867#if defined(HAVE_PRI)
7869 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7870 && p->pri
7871 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7872 /* absorb event */
7873 } else
7874#endif /* defined(HAVE_PRI) */
7875 {
7876 /* Mute conference */
7877 dahdi_confmute(p, 1);
7879 p->subs[idx].f.subclass.integer = res & 0xff;
7880 dahdi_handle_dtmf(ast, idx, &f);
7881 }
7882 return &p->subs[idx].f;
7883 }
7884
7885 switch (res) {
7886 case DAHDI_EVENT_EC_DISABLED:
7887 ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
7888 p->echocanon = 0;
7889 break;
7890#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7891 case DAHDI_EVENT_TX_CED_DETECTED:
7892 ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
7893 break;
7894 case DAHDI_EVENT_RX_CED_DETECTED:
7895 ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
7896 break;
7897 case DAHDI_EVENT_EC_NLP_DISABLED:
7898 ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
7899 break;
7900 case DAHDI_EVENT_EC_NLP_ENABLED:
7901 ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
7902 break;
7903#endif
7904 case DAHDI_EVENT_BITSCHANGED:
7905#ifdef HAVE_OPENR2
7906 if (p->sig != SIG_MFCR2) {
7907 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7908 } else {
7909 ast_debug(1, "bits changed in chan %d\n", p->channel);
7910 openr2_chan_handle_cas(p->r2chan);
7911 }
7912#else
7913 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7914#endif
7915 break;
7916 case DAHDI_EVENT_PULSE_START:
7917 /* Stop tone if there's a pulse start and the PBX isn't started */
7918 if (!ast_channel_pbx(ast))
7919 tone_zone_play_tone(p->subs[idx].dfd, -1);
7920 break;
7921 case DAHDI_EVENT_DIALCOMPLETE:
7922 /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
7923#if defined(HAVE_PRI)
7925 if (p->inalarm) {
7926 break;
7927 }
7928 if (ioctl(p->subs[idx].dfd, DAHDI_DIALING, &x) == -1) {
7929 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
7930 ast_channel_name(ast), strerror(errno));
7931 return NULL;
7932 }
7933 if (x) {
7934 /* Still dialing in DAHDI driver */
7935 break;
7936 }
7937 /*
7938 * The ast channel is locked and the private may be locked more
7939 * than once.
7940 */
7942 break;
7943 }
7944#endif /* defined(HAVE_PRI) */
7945#ifdef HAVE_OPENR2
7946 if ((p->sig & SIG_MFCR2) && p->r2chan && ast_channel_state(ast) != AST_STATE_UP) {
7947 /* we don't need to do anything for this event for R2 signaling
7948 if the call is being setup */
7949 break;
7950 }
7951#endif
7952 if (p->inalarm) break;
7953 if ((p->radio || (p->oprmode < 0))) break;
7954 if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
7955 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",ast_channel_name(ast), strerror(errno));
7956 return NULL;
7957 }
7958 if (!x) { /* if not still dialing in driver */
7959 dahdi_ec_enable(p);
7960 if (p->echobreak) {
7961 dahdi_train_ec(p);
7962 ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
7963 p->dop.op = DAHDI_DIAL_OP_REPLACE;
7964 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
7965 p->echobreak = 0;
7966 } else {
7967 p->dialing = 0;
7968 if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
7969 /* if thru with dialing after offhook */
7974 break;
7975 } else { /* if to state wait for offhook to dial rest */
7976 /* we now wait for off hook */
7978 }
7979 }
7981 if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
7982 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
7983 } else if (p->confirmanswer || (!p->dialednone
7984 && ((mysig == SIG_EM) || (mysig == SIG_EM_E1)
7985 || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD)
7986 || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF)
7987 || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA)
7988 || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB)
7989 || (mysig == SIG_SF) || (mysig == SIG_SFWINK)
7990 || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF)
7991 || (mysig == SIG_SF_FEATB)))) {
7993 } else if (!p->answeronpolarityswitch) {
7997 /* If aops=0 and hops=1, this is necessary */
7999 } else {
8000 /* Start clean, so we can catch the change to REV polarity when party answers */
8002 }
8003 }
8004 }
8005 }
8006 break;
8007 case DAHDI_EVENT_ALARM:
8008 switch (p->sig) {
8009#if defined(HAVE_PRI)
8012 break;
8013#endif /* defined(HAVE_PRI) */
8014#if defined(HAVE_SS7)
8015 case SIG_SS7:
8017 break;
8018#endif /* defined(HAVE_SS7) */
8019 default:
8020 p->inalarm = 1;
8021 break;
8022 }
8023 res = get_alarms(p);
8024 handle_alarms(p, res);
8025#ifdef HAVE_PRI
8026 if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
8027 /* fall through intentionally */
8028 } else {
8029 break;
8030 }
8031#endif
8032#if defined(HAVE_SS7)
8033 if (p->sig == SIG_SS7)
8034 break;
8035#endif /* defined(HAVE_SS7) */
8036#ifdef HAVE_OPENR2
8037 if (p->sig == SIG_MFCR2)
8038 break;
8039#endif
8040 case DAHDI_EVENT_ONHOOK:
8041 if (p->radio) {
8044 break;
8045 }
8046 if (p->oprmode < 0)
8047 {
8048 if (p->oprmode != -1) { /* Operator flash recall */
8049 ast_verb(4, "Operator mode enabled on channel %d, holding line for channel %d\n", p->channel, p->oprpeer->channel);
8050 break;
8051 }
8052 /* Otherwise, immediate recall */
8053 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
8054 {
8055 /* Make sure it starts ringing */
8056 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8057 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
8059 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8060 ast_verb(4, "Operator recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8061 }
8062 break;
8063 }
8064 switch (p->sig) {
8065 case SIG_FXOLS:
8066 case SIG_FXOGS:
8067 case SIG_FXOKS:
8068 /* Check for some special conditions regarding call waiting */
8069 if (idx == SUB_REAL) {
8070 /* The normal line was hung up */
8071 if (p->subs[SUB_CALLWAIT].owner) {
8072 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
8074 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
8076#if 0
8077 p->subs[idx].needanswer = 0;
8078 p->subs[idx].needringing = 0;
8079#endif
8080 p->callwaitingrepeat = 0;
8081 p->cidcwexpire = 0;
8082 p->cid_suppress_expire = 0;
8083 p->owner = NULL;
8084 /* Don't start streaming audio yet if the incoming call isn't up yet */
8086 p->dialing = 1;
8088 } else if (p->subs[SUB_THREEWAY].owner) {
8089 unsigned int mssinceflash;
8090 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
8091 the private structure -- not especially easy or clean */
8093 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
8094 DLA_UNLOCK(&p->lock);
8096 /* We can grab ast and p in that order, without worry. We should make sure
8097 nothing seriously bad has happened though like some sort of bizarre double
8098 masquerade! */
8099 DLA_LOCK(&p->lock);
8100 if (p->owner != ast) {
8101 ast_log(LOG_WARNING, "This isn't good...\n");
8102 return NULL;
8103 }
8104 }
8105 if (!p->subs[SUB_THREEWAY].owner) {
8106 ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
8107 return NULL;
8108 }
8109 mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
8110 ast_debug(1, "Last flash was %u ms ago\n", mssinceflash);
8111 if (mssinceflash < MIN_MS_SINCE_FLASH) {
8112 /* It hasn't been long enough since the last flashook. This is probably a bounce on
8113 hanging up. Hangup both channels now */
8114 if (p->subs[SUB_THREEWAY].owner)
8117 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
8119 } else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
8120 if (p->transfer) {
8121 /* In any case this isn't a threeway call anymore */
8122 p->subs[SUB_REAL].inthreeway = 0;
8124 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
8125 if (!p->transfertobusy && ast_channel_state(ast) == AST_STATE_BUSY) {
8127 /* Swap subs and dis-own channel */
8129 p->owner = NULL;
8130 /* Ring the phone */
8132 } else if (!attempt_transfer(p)) {
8133 /*
8134 * Transfer successful. Don't actually hang up at this point.
8135 * Let our channel legs of the calls die off as the transfer
8136 * percolates through the core.
8137 */
8138 break;
8139 }
8140 } else {
8142 if (p->subs[SUB_THREEWAY].owner)
8144 }
8145 } else {
8147 /* Swap subs and dis-own channel */
8149 p->owner = NULL;
8150 /* Ring the phone */
8152 }
8153 }
8154 } else {
8155 ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
8156 }
8157 /* Fall through */
8158 default:
8160 return NULL;
8161 }
8162 break;
8163 case DAHDI_EVENT_RINGOFFHOOK:
8164 if (p->inalarm) break;
8165 if (p->oprmode < 0)
8166 {
8167 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
8168 {
8169 /* Make sure it stops ringing */
8170 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8171 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
8173 ast_debug(1, "Operator recall by channel %d for channel %d complete\n", p->oprpeer->channel, p->channel);
8174 }
8175 break;
8176 }
8177 if (p->radio)
8178 {
8181 break;
8182 }
8183 /* for E911, its supposed to wait for offhook then dial
8184 the second half of the dial string */
8185 if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast_channel_state(ast) == AST_STATE_DIALING_OFFHOOK)) {
8186 c = strchr(p->dialdest, '/');
8187 if (c)
8188 c++;
8189 else
8190 c = p->dialdest;
8191
8192 if (*c) {
8193 int numchars = snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
8194 if (numchars >= sizeof(p->dop.dialstr)) {
8195 ast_log(LOG_WARNING, "Dial string '%s' truncated\n", c);
8196 }
8197 } else {
8198 ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
8199 }
8200
8201 if (strlen(p->dop.dialstr) > 4) {
8202 memset(p->echorest, 'w', sizeof(p->echorest) - 1);
8203 strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
8204 p->echorest[sizeof(p->echorest) - 1] = '\0';
8205 p->echobreak = 1;
8206 p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
8207 } else
8208 p->echobreak = 0;
8209 if (dahdi_dial_str(p, p->dop.op, p->dop.dialstr)) {
8210 x = DAHDI_ONHOOK;
8211 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
8212 return NULL;
8213 }
8214 p->dialing = 1;
8215 return &p->subs[idx].f;
8216 }
8217 switch (p->sig) {
8218 case SIG_FXOLS:
8219 case SIG_FXOGS:
8220 case SIG_FXOKS:
8221 switch (ast_channel_state(ast)) {
8222 case AST_STATE_RINGING:
8223 dahdi_ec_enable(p);
8224 dahdi_train_ec(p);
8227 /* Make sure it stops ringing */
8228 p->subs[SUB_REAL].needringing = 0;
8229 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8230 ast_debug(1, "channel %d answered\n", p->channel);
8231
8232 /* Cancel any running CallerID spill */
8233 ast_free(p->cidspill);
8234 p->cidspill = NULL;
8236
8237 p->dialing = 0;
8238 p->callwaitcas = 0;
8239 if (p->confirmanswer) {
8240 /* Ignore answer if "confirm answer" is enabled */
8241 p->subs[idx].f.frametype = AST_FRAME_NULL;
8242 p->subs[idx].f.subclass.integer = 0;
8243 } else if (!ast_strlen_zero(p->dop.dialstr)) {
8244 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
8245 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8246 if (res) {
8247 p->dop.dialstr[0] = '\0';
8248 return NULL;
8249 } else {
8250 ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
8251 p->subs[idx].f.frametype = AST_FRAME_NULL;
8252 p->subs[idx].f.subclass.integer = 0;
8253 p->dialing = 1;
8254 }
8255 p->dop.dialstr[0] = '\0';
8257 } else
8259 return &p->subs[idx].f;
8260 case AST_STATE_DOWN:
8262 ast_channel_rings_set(ast, 1);
8265 ast_debug(1, "channel %d picked up\n", p->channel);
8266 return &p->subs[idx].f;
8267 case AST_STATE_UP:
8268 /* Make sure it stops ringing */
8269 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8270 /* Okay -- probably call waiting*/
8272 p->subs[idx].needunhold = 1;
8273 break;
8274 case AST_STATE_RESERVED:
8275 /* Start up dialtone */
8276 if (has_voicemail(p))
8277 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
8278 else
8279 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
8280 break;
8281 default:
8282 ast_log(LOG_WARNING, "FXO phone off hook in weird state %u??\n", ast_channel_state(ast));
8283 }
8284 break;
8285 case SIG_FXSLS:
8286 case SIG_FXSGS:
8287 case SIG_FXSKS:
8288 if (ast_channel_state(ast) == AST_STATE_RING) {
8289 p->ringt = p->ringt_base;
8290 }
8291
8292 /* If we get a ring then we cannot be in
8293 * reversed polarity. So we reset to idle */
8294 ast_debug(1, "Setting IDLE polarity due "
8295 "to ring. Old polarity was %d\n",
8296 p->polarity);
8298
8299 /* Fall through */
8300 case SIG_EM:
8301 case SIG_EM_E1:
8302 case SIG_EMWINK:
8303 case SIG_FEATD:
8304 case SIG_FEATDMF:
8305 case SIG_FEATDMF_TA:
8306 case SIG_E911:
8307 case SIG_FGC_CAMA:
8308 case SIG_FGC_CAMAMF:
8309 case SIG_FEATB:
8310 case SIG_SF:
8311 case SIG_SFWINK:
8312 case SIG_SF_FEATD:
8313 case SIG_SF_FEATDMF:
8314 case SIG_SF_FEATB:
8318 ast_debug(1, "Ring detected\n");
8321 } else if (p->outgoing && ((ast_channel_state(ast) == AST_STATE_RINGING) || (ast_channel_state(ast) == AST_STATE_DIALING))) {
8322 ast_debug(1, "Line answered\n");
8323 if (p->confirmanswer) {
8324 p->subs[idx].f.frametype = AST_FRAME_NULL;
8325 p->subs[idx].f.subclass.integer = 0;
8326 } else {
8330 }
8331 } else if (ast_channel_state(ast) != AST_STATE_RING)
8332 ast_log(LOG_WARNING, "Ring/Off-hook in strange state %u on channel %d\n", ast_channel_state(ast), p->channel);
8333 break;
8334 default:
8335 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8336 }
8337 break;
8338 case DAHDI_EVENT_RINGBEGIN:
8339 switch (p->sig) {
8340 case SIG_FXSLS:
8341 case SIG_FXSGS:
8342 case SIG_FXSKS:
8343 if (ast_channel_state(ast) == AST_STATE_RING) {
8344 p->ringt = p->ringt_base;
8345 }
8346 break;
8347 }
8348 break;
8349 case DAHDI_EVENT_RINGERON:
8350 break;
8351 case DAHDI_EVENT_NOALARM:
8352 switch (p->sig) {
8353#if defined(HAVE_PRI)
8356 break;
8357#endif /* defined(HAVE_PRI) */
8358#if defined(HAVE_SS7)
8359 case SIG_SS7:
8361 break;
8362#endif /* defined(HAVE_SS7) */
8363 default:
8364 p->inalarm = 0;
8365 break;
8366 }
8368 break;
8369 case DAHDI_EVENT_WINKFLASH:
8370 if (p->inalarm) break;
8371 if (p->radio) break;
8372 if (p->oprmode < 0) break;
8373 if (p->oprmode > 1)
8374 {
8375 struct dahdi_params par;
8376
8377 memset(&par, 0, sizeof(par));
8378 if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
8379 {
8380 if (!par.rxisoffhook)
8381 {
8382 /* Make sure it stops ringing */
8383 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8384 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
8385 save_conference(p);
8386 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8387 ast_verb(4, "Operator flash recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8388 }
8389 }
8390 break;
8391 }
8392 /* Remember last time we got a flash-hook */
8393 p->flashtime = ast_tvnow();
8394 switch (mysig) {
8395 case SIG_FXOLS:
8396 case SIG_FXOGS:
8397 case SIG_FXOKS:
8398 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
8400
8401 /* Cancel any running CallerID spill */
8402 ast_free(p->cidspill);
8403 p->cidspill = NULL;
8405 p->callwaitcas = 0;
8406
8407 if (idx != SUB_REAL) {
8408 ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
8409 goto winkflashdone;
8410 }
8411
8412 if (p->subs[SUB_CALLWAIT].owner) {
8413 /* Swap to call-wait */
8415 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
8416 p->owner = p->subs[SUB_REAL].owner;
8417 ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));
8420 p->subs[SUB_REAL].needanswer = 1;
8421 }
8422 p->callwaitingrepeat = 0;
8423 p->cidcwexpire = 0;
8424 p->cid_suppress_expire = 0;
8425 /* Start music on hold if appropriate */
8426 if (!p->subs[SUB_CALLWAIT].inthreeway) {
8428 }
8429 p->subs[SUB_CALLWAIT].needhold = 1;
8431 p->subs[SUB_REAL].needunhold = 1;
8432 } else if (!p->subs[SUB_THREEWAY].owner) {
8433 if (!p->threewaycalling) {
8434 /* Just send a flash if no 3-way calling */
8435 p->subs[SUB_REAL].needflash = 1;
8436 goto winkflashdone;
8437 } else if (!check_for_conference(p)) {
8438 ast_callid callid = 0;
8439 int callid_created;
8440 char cid_num[256];
8441 char cid_name[256];
8442
8443 cid_num[0] = 0;
8444 cid_name[0] = 0;
8445 if (p->dahditrcallerid && p->owner) {
8449 sizeof(cid_num));
8450 }
8454 sizeof(cid_name));
8455 }
8456 }
8457 /* XXX This section needs much more error checking!!! XXX */
8458 /* Start a 3-way call if feasible */
8459 if (!((ast_channel_pbx(ast)) ||
8460 (ast_channel_state(ast) == AST_STATE_UP) ||
8461 (ast_channel_state(ast) == AST_STATE_RING))) {
8462 ast_debug(1, "Flash when call not up or ringing\n");
8463 goto winkflashdone;
8464 }
8465 if (alloc_sub(p, SUB_THREEWAY)) {
8466 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
8467 goto winkflashdone;
8468 }
8469 callid_created = ast_callid_threadstorage_auto(&callid);
8470 /*
8471 * Make new channel
8472 *
8473 * We cannot hold the p or ast locks while creating a new
8474 * channel.
8475 */
8477 ast_channel_unlock(ast);
8478 chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, NULL, callid);
8479 ast_channel_lock(ast);
8480 ast_mutex_lock(&p->lock);
8481 if (p->dahditrcallerid) {
8482 if (!p->origcid_num)
8484 if (!p->origcid_name)
8486 ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
8487 ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
8488 }
8489 /* Swap things around between the three-way and real call */
8491 /* Disable echo canceller for better dialing */
8493 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
8494 if (res)
8495 ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
8496 p->owner = chan;
8497 if (!chan) {
8498 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
8499 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
8500 ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
8501 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
8502 dahdi_ec_enable(p);
8503 ast_hangup(chan);
8504 } else {
8505 ast_verb(3, "Started three way call on channel %d\n", p->channel);
8506
8507 /* Start music on hold */
8509 p->subs[SUB_THREEWAY].needhold = 1;
8510 }
8511 ast_callid_threadstorage_auto_clean(callid, callid_created);
8512 }
8513 } else {
8514 /* Already have a 3 way call */
8515 if (p->subs[SUB_THREEWAY].inthreeway) {
8516 /* Call is already up, drop the last person */
8517 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
8518 /* If the primary call isn't answered yet, use it */
8520 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
8522 p->owner = p->subs[SUB_REAL].owner;
8523 }
8524 /* Drop the last call and stop the conference */
8525 ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8527 p->subs[SUB_REAL].inthreeway = 0;
8529 } else {
8530 /* Lets see what we're up to */
8531 if (((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) &&
8533 int otherindex = SUB_THREEWAY;
8534
8535 ast_verb(3, "Building conference call with %s and %s\n",
8538 /* Put them in the threeway, and flip */
8540 p->subs[SUB_REAL].inthreeway = 1;
8541 if (ast_channel_state(ast) == AST_STATE_UP) {
8543 otherindex = SUB_REAL;
8544 }
8545 if (p->subs[otherindex].owner) {
8546 ast_queue_unhold(p->subs[otherindex].owner);
8547 }
8548 p->subs[otherindex].needunhold = 1;
8549 p->owner = p->subs[SUB_REAL].owner;
8550 } else {
8551 ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8554 p->owner = p->subs[SUB_REAL].owner;
8555 if (p->subs[SUB_REAL].owner) {
8557 }
8558 p->subs[SUB_REAL].needunhold = 1;
8559 dahdi_ec_enable(p);
8560 }
8561 }
8562 }
8563winkflashdone:
8565 break;
8566 case SIG_EM:
8567 case SIG_EM_E1:
8568 case SIG_FEATD:
8569 case SIG_SF:
8570 case SIG_SFWINK:
8571 case SIG_SF_FEATD:
8572 case SIG_FXSLS:
8573 case SIG_FXSGS:
8574 if (p->dialing)
8575 ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
8576 else
8577 ast_debug(1, "Got wink in weird state %u on channel %d\n", ast_channel_state(ast), p->channel);
8578 break;
8579 case SIG_FEATDMF_TA:
8580 switch (p->whichwink) {
8581 case 0:
8582 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p->owner)->ani2,
8585 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#",
8589 break;
8590 case 1:
8591 ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
8592 break;
8593 case 2:
8594 ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
8595 return NULL;
8596 }
8597 p->whichwink++;
8598 /* Fall through */
8599 case SIG_FEATDMF:
8600 case SIG_E911:
8601 case SIG_FGC_CAMAMF:
8602 case SIG_FGC_CAMA:
8603 case SIG_FEATB:
8604 case SIG_SF_FEATDMF:
8605 case SIG_SF_FEATB:
8606 case SIG_EMWINK:
8607 /* FGD MF and EMWINK *Must* wait for wink */
8608 if (!ast_strlen_zero(p->dop.dialstr)) {
8609 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8610 if (res) {
8611 p->dop.dialstr[0] = '\0';
8612 return NULL;
8613 } else
8614 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8615 }
8616 p->dop.dialstr[0] = '\0';
8617 break;
8618 default:
8619 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8620 }
8621 break;
8622 case DAHDI_EVENT_HOOKCOMPLETE:
8623 if (p->inalarm) break;
8624 if ((p->radio || (p->oprmode < 0))) break;
8625 if (p->waitingfordt.tv_sec) break;
8626 switch (mysig) {
8627 case SIG_FXSLS: /* only interesting for FXS */
8628 case SIG_FXSGS:
8629 case SIG_FXSKS:
8630 case SIG_EM:
8631 case SIG_EM_E1:
8632 case SIG_EMWINK:
8633 case SIG_FEATD:
8634 case SIG_SF:
8635 case SIG_SFWINK:
8636 case SIG_SF_FEATD:
8637 if (!ast_strlen_zero(p->dop.dialstr)) {
8638 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8639 if (res) {
8640 p->dop.dialstr[0] = '\0';
8641 return NULL;
8642 } else
8643 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8644 }
8645 p->dop.dialstr[0] = '\0';
8646 p->dop.op = DAHDI_DIAL_OP_REPLACE;
8647 break;
8648 case SIG_FEATDMF:
8649 case SIG_FEATDMF_TA:
8650 case SIG_E911:
8651 case SIG_FGC_CAMA:
8652 case SIG_FGC_CAMAMF:
8653 case SIG_FEATB:
8654 case SIG_SF_FEATDMF:
8655 case SIG_SF_FEATB:
8656 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
8657 break;
8658 default:
8659 break;
8660 }
8661 break;
8662 case DAHDI_EVENT_POLARITY:
8663 /*
8664 * If we get a Polarity Switch event, check to see
8665 * if we should change the polarity state and
8666 * mark the channel as UP or if this is an indication
8667 * of remote end disconnect.
8668 */
8669 if (p->polarity == POLARITY_IDLE) {
8671 if (p->answeronpolarityswitch &&
8674 ast_debug(1, "Answering on polarity switch!\n");
8676 if (p->hanguponpolarityswitch) {
8678 }
8679 } else
8680 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8681 }
8682 /* Removed else statement from here as it was preventing hangups from ever happening*/
8683 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
8684 if (p->hanguponpolarityswitch &&
8685 (p->polarityonanswerdelay > 0) &&
8686 (p->polarity == POLARITY_REV) &&
8688 /* Added log_debug information below to provide a better indication of what is going on */
8689 ast_debug(1, "Polarity Reversal event occurred - 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) );
8690
8692 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
8695 } else
8696 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));
8697
8698 } else {
8700 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8701 }
8702 /* Added more log_debug information below to provide a better indication of what is going on */
8703 ast_debug(1, "Polarity Reversal event occurred - 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) );
8704 break;
8705 default:
8706 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
8707 }
8708 return &p->subs[idx].f;
8709}
8710
8711static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
8712{
8713 int res;
8714 int idx;
8715 struct ast_frame *f;
8716 int usedindex = -1;
8717 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8718
8719 if ((idx = dahdi_get_index(ast, p, 0)) < 0) {
8720 idx = SUB_REAL;
8721 }
8722
8723 p->subs[idx].f.frametype = AST_FRAME_NULL;
8724 p->subs[idx].f.datalen = 0;
8725 p->subs[idx].f.samples = 0;
8726 p->subs[idx].f.mallocd = 0;
8727 p->subs[idx].f.offset = 0;
8728 p->subs[idx].f.subclass.integer = 0;
8729 p->subs[idx].f.delivery = ast_tv(0,0);
8730 p->subs[idx].f.src = "dahdi_exception";
8731 p->subs[idx].f.data.ptr = NULL;
8732
8733
8734 if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
8735 /* If nobody owns us, absorb the event appropriately, otherwise
8736 we loop indefinitely. This occurs when, during call waiting, the
8737 other end hangs up our channel so that it no longer exists, but we
8738 have neither FLASH'd nor ONHOOK'd to signify our desire to
8739 change to the other channel. */
8740 if (p->fake_event) {
8741 res = p->fake_event;
8742 p->fake_event = 0;
8743 } else
8744 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
8745 /* Switch to real if there is one and this isn't something really silly... */
8746 if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
8747 (res != DAHDI_EVENT_HOOKCOMPLETE)) {
8748 ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
8749 p->owner = p->subs[SUB_REAL].owner;
8750 if (p->owner) {
8752 }
8753 p->subs[SUB_REAL].needunhold = 1;
8754 }
8755 switch (res) {
8756 case DAHDI_EVENT_ONHOOK:
8758 if (p->owner) {
8759 ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
8761 p->callwaitingrepeat = 0;
8762 p->cidcwexpire = 0;
8763 p->cid_suppress_expire = 0;
8764 } else
8765 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8767 break;
8768 case DAHDI_EVENT_RINGOFFHOOK:
8769 dahdi_ec_enable(p);
8770 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
8771 if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
8772 p->subs[SUB_REAL].needanswer = 1;
8773 p->dialing = 0;
8774 }
8775 break;
8776 case DAHDI_EVENT_HOOKCOMPLETE:
8777 case DAHDI_EVENT_RINGERON:
8778 case DAHDI_EVENT_RINGEROFF:
8779 /* Do nothing */
8780 break;
8781 case DAHDI_EVENT_WINKFLASH:
8782 p->flashtime = ast_tvnow();
8783 if (p->owner) {
8784 ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, ast_channel_name(p->owner));
8786 /* Answer if necessary */
8787 usedindex = dahdi_get_index(p->owner, p, 0);
8788 if (usedindex > -1) {
8789 p->subs[usedindex].needanswer = 1;
8790 }
8792 }
8793 p->callwaitingrepeat = 0;
8794 p->cidcwexpire = 0;
8795 p->cid_suppress_expire = 0;
8797 p->subs[SUB_REAL].needunhold = 1;
8798 } else
8799 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8801 break;
8802 default:
8803 ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
8804 }
8805 f = &p->subs[idx].f;
8806 return f;
8807 }
8808 if (!(p->radio || (p->oprmode < 0)))
8809 ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast, 0), p->channel);
8810 /* If it's not us, return NULL immediately */
8811 if (ast != p->owner) {
8812 if (p->owner) {
8813 ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
8814 }
8815 f = &p->subs[idx].f;
8816 return f;
8817 }
8818
8819 f = dahdi_handle_event(ast);
8820 if (!f) {
8821 const char *name = ast_strdupa(ast_channel_name(ast));
8822
8823 /* Tell the CDR this DAHDI device hung up */
8825 ast_channel_unlock(ast);
8826 ast_set_hangupsource(ast, name, 0);
8827 ast_channel_lock(ast);
8828 ast_mutex_lock(&p->lock);
8829 }
8830 return f;
8831}
8832
8833static struct ast_frame *dahdi_exception(struct ast_channel *ast)
8834{
8835 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8836 struct ast_frame *f;
8837 ast_mutex_lock(&p->lock);
8838 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
8839 struct analog_pvt *analog_p = p->sig_pvt;
8840 f = analog_exception(analog_p, ast);
8841 } else {
8842 f = __dahdi_exception(ast);
8843 }
8845 return f;
8846}
8847
8848static struct ast_frame *dahdi_read(struct ast_channel *ast)
8849{
8850 struct dahdi_pvt *p;
8851 int res;
8852 int idx;
8853 void *readbuf;
8854 struct ast_frame *f;
8855
8856 /*
8857 * For analog channels, we must do deadlock avoidance because
8858 * analog ports can have more than one Asterisk channel using
8859 * the same private structure.
8860 */
8861 p = ast_channel_tech_pvt(ast);
8862 while (ast_mutex_trylock(&p->lock)) {
8864
8865 /*
8866 * Check to see if the channel is still associated with the same
8867 * private structure. While the Asterisk channel was unlocked
8868 * the following events may have occurred:
8869 *
8870 * 1) A masquerade may have associated the channel with another
8871 * technology or private structure.
8872 *
8873 * 2) For PRI calls, call signaling could change the channel
8874 * association to another B channel (private structure).
8875 */
8876 if (ast_channel_tech_pvt(ast) != p) {
8877 /* The channel is no longer associated. Quit gracefully. */
8878 return &ast_null_frame;
8879 }
8880 }
8881
8882 idx = dahdi_get_index(ast, p, 0);
8883
8884 /* Hang up if we don't really exist */
8885 if (idx < 0) {
8886 ast_log(LOG_WARNING, "We don't exist?\n");
8888 return NULL;
8889 }
8890
8891 if ((p->radio || (p->oprmode < 0)) && p->inalarm) {
8893 return NULL;
8894 }
8895
8896 p->subs[idx].f.frametype = AST_FRAME_NULL;
8897 p->subs[idx].f.datalen = 0;
8898 p->subs[idx].f.samples = 0;
8899 p->subs[idx].f.mallocd = 0;
8900 p->subs[idx].f.offset = 0;
8901 p->subs[idx].f.subclass.integer = 0;
8902 p->subs[idx].f.delivery = ast_tv(0,0);
8903 p->subs[idx].f.src = "dahdi_read";
8904 p->subs[idx].f.data.ptr = NULL;
8905
8906 /* make sure it sends initial key state as first frame */
8907 if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
8908 {
8909 struct dahdi_params ps;
8910
8911 memset(&ps, 0, sizeof(ps));
8912 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
8914 return NULL;
8915 }
8916 p->firstradio = 1;
8918 if (ps.rxisoffhook)
8919 {
8921 }
8922 else
8923 {
8925 }
8927 return &p->subs[idx].f;
8928 }
8929 if (p->ringt > 0) {
8930 if (!(--p->ringt)) {
8932 return NULL;
8933 }
8934 }
8935
8936#ifdef HAVE_OPENR2
8937 if (p->mfcr2) {
8938 openr2_chan_process_event(p->r2chan);
8939 if (OR2_DIR_FORWARD == openr2_chan_get_direction(p->r2chan)) {
8941 /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
8942 * now enqueue a progress frame to bridge the media up */
8943 if (p->mfcr2_call_accepted &&
8944 !p->mfcr2_progress_sent &&
8946 ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
8947 ast_queue_frame(p->owner, &fr);
8948 p->mfcr2_progress_sent = 1;
8949 }
8950 }
8951 }
8952#endif
8953
8954 if (p->subs[idx].needringing) {
8955 /* Send ringing frame if requested */
8956 p->subs[idx].needringing = 0;
8961 return &p->subs[idx].f;
8962 }
8963
8964 if (p->subs[idx].needbusy) {
8965 /* Send busy frame if requested */
8966 p->subs[idx].needbusy = 0;
8970 return &p->subs[idx].f;
8971 }
8972
8973 if (p->subs[idx].needcongestion) {
8974 /* Send congestion frame if requested */
8975 p->subs[idx].needcongestion = 0;
8979 return &p->subs[idx].f;
8980 }
8981
8982 if (p->subs[idx].needanswer) {
8983 /* Send answer frame if requested */
8984 p->subs[idx].needanswer = 0;
8988 return &p->subs[idx].f;
8989 }
8990#ifdef HAVE_OPENR2
8991 if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
8992 /* openr2 took care of reading and handling any event
8993 (needanswer, needbusy etc), if we continue we will read()
8994 twice, lets just return a null frame. This should only
8995 happen when openr2 is dialing out */
8997 return &ast_null_frame;
8998 }
8999#endif
9000
9001 if (p->subs[idx].needflash) {
9002 /* Send answer frame if requested */
9003 p->subs[idx].needflash = 0;
9007 return &p->subs[idx].f;
9008 }
9009
9010 if (p->subs[idx].needhold) {
9011 /* Send answer frame if requested */
9012 p->subs[idx].needhold = 0;
9016 ast_debug(1, "Sending hold on '%s'\n", ast_channel_name(ast));
9017 return &p->subs[idx].f;
9018 }
9019
9020 if (p->subs[idx].needunhold) {
9021 /* Send answer frame if requested */
9022 p->subs[idx].needunhold = 0;
9026 ast_debug(1, "Sending unhold on '%s'\n", ast_channel_name(ast));
9027 return &p->subs[idx].f;
9028 }
9029
9030 /*
9031 * If we have a fake_event, fake an exception to handle it only
9032 * if this channel owns the private.
9033 */
9034 if (p->fake_event && p->owner == ast) {
9035 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9036 struct analog_pvt *analog_p = p->sig_pvt;
9037
9038 f = analog_exception(analog_p, ast);
9039 } else {
9040 f = __dahdi_exception(ast);
9041 }
9043 return f;
9044 }
9045
9047 if (!p->subs[idx].linear) {
9048 p->subs[idx].linear = 1;
9049 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9050 if (res)
9051 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
9052 }
9053 } else {
9054 if (p->subs[idx].linear) {
9055 p->subs[idx].linear = 0;
9056 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9057 if (res)
9058 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
9059 }
9060 }
9061 readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
9062 CHECK_BLOCKING(ast);
9063 res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9065 /* Check for hangup */
9066 if (res < 0) {
9067 f = NULL;
9068 if (res == -1) {
9069 if (errno == EAGAIN) {
9070 /* Return "NULL" frame if there is nobody there */
9072 return &p->subs[idx].f;
9073 } else if (errno == ELAST) {
9074 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9075 struct analog_pvt *analog_p = p->sig_pvt;
9076 f = analog_exception(analog_p, ast);
9077 } else {
9078 f = __dahdi_exception(ast);
9079 }
9080 } else
9081 ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
9082 }
9084 return f;
9085 }
9086 if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
9087 ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9088 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9089 struct analog_pvt *analog_p = p->sig_pvt;
9090 f = analog_exception(analog_p, ast);
9091 } else {
9092 f = __dahdi_exception(ast);
9093 }
9095 return f;
9096 }
9097 if (p->tdd) { /* if in TDD mode, see if we receive that */
9098 int c;
9099
9100 c = tdd_feed(p->tdd,readbuf,READ_SIZE);
9101 if (c < 0) {
9102 ast_debug(1,"tdd_feed failed\n");
9104 return NULL;
9105 }
9106 if (c) { /* if a char to return */
9107 p->subs[idx].f.subclass.integer = 0;
9108 p->subs[idx].f.frametype = AST_FRAME_TEXT;
9109 p->subs[idx].f.mallocd = 0;
9110 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9111 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
9112 p->subs[idx].f.datalen = 1;
9113 *((char *) p->subs[idx].f.data.ptr) = c;
9115 return &p->subs[idx].f;
9116 }
9117 }
9118 if (idx == SUB_REAL) {
9119 /* Ensure the CW timers decrement only on a single subchannel */
9120 if (p->cidcwexpire) {
9121 if (!--p->cidcwexpire) {
9122 /* Expired CID/CW */
9123 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
9125 }
9126 }
9127 if (p->cid_suppress_expire) {
9129 }
9130 if (p->callwaitingrepeat) {
9131 if (!--p->callwaitingrepeat) {
9132 /* Expired, Repeat callwaiting tone */
9133 ++p->callwaitrings;
9134 dahdi_callwait(ast);
9135 }
9136 }
9137 }
9138 if (p->subs[idx].linear) {
9139 p->subs[idx].f.datalen = READ_SIZE * 2;
9140 } else
9141 p->subs[idx].f.datalen = READ_SIZE;
9142
9143 /* Handle CallerID Transmission */
9144 if ((p->owner == ast) && p->cidspill) {
9145 send_callerid(p);
9146 }
9147
9148 p->subs[idx].f.frametype = AST_FRAME_VOICE;
9150 p->subs[idx].f.samples = READ_SIZE;
9151 p->subs[idx].f.mallocd = 0;
9152 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9153 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
9154#if 0
9155 ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
9156#endif
9157 if ((p->dialing && !p->waitingfordt.tv_sec) || p->radio || /* Transmitting something */
9158 (idx && (ast_channel_state(ast) != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
9159 ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
9160 ) {
9161 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
9162 don't send anything */
9163 p->subs[idx].f.frametype = AST_FRAME_NULL;
9164 p->subs[idx].f.subclass.integer = 0;
9165 p->subs[idx].f.samples = 0;
9166 p->subs[idx].f.mallocd = 0;
9167 p->subs[idx].f.offset = 0;
9168 p->subs[idx].f.data.ptr = NULL;
9169 p->subs[idx].f.datalen= 0;
9170 }
9171 if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec || p->dialtone_detect) && !idx) {
9172 /* Perform busy detection etc on the dahdi line */
9173 int mute;
9174
9176 && p->faxdetect_timeout
9178 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
9180 ast_debug(1, "Channel driver fax CNG detection timeout on %s\n",
9181 ast_channel_name(ast));
9182 }
9183
9184 f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
9185
9186 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
9187 mute = ast_dsp_was_muted(p->dsp);
9188 if (p->muting != mute) {
9189 p->muting = mute;
9190 dahdi_confmute(p, mute);
9191 }
9192
9193 if (f) {
9195 && !p->outgoing && ast_channel_state(ast) == AST_STATE_UP) {
9197 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9199 }
9200 }
9202 if ((ast_channel_state(ast) == AST_STATE_UP) && !p->outgoing) {
9203 /*
9204 * Treat this as a "hangup" instead of a "busy" on the
9205 * assumption that a busy means the incoming call went away.
9206 */
9207 ast_frfree(f);
9208 f = NULL;
9209 }
9210 } else if (p->dialtone_detect && !p->outgoing && f->frametype == AST_FRAME_VOICE) {
9212 /* Dialtone detected on inbound call; hangup the channel */
9213 ast_frfree(f);
9214 f = NULL;
9215 }
9216 } else if (f->frametype == AST_FRAME_DTMF_BEGIN
9217 || f->frametype == AST_FRAME_DTMF_END) {
9218#ifdef HAVE_PRI
9220 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
9221 && p->pri
9222 && ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING))
9223 || (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
9224 /* Don't accept in-band DTMF when in overlap dial mode */
9225 ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n",
9226 f->frametype == AST_FRAME_DTMF_BEGIN ? "begin" : "end",
9227 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
9228
9230 f->subclass.integer = 0;
9231 }
9232#endif
9233 /* DSP clears us of being pulse */
9234 p->pulsedial = 0;
9235 } else if (p->waitingfordt.tv_sec) {
9237 p->waitingfordt.tv_sec = 0;
9238 ast_log(LOG_NOTICE, "Never saw dialtone on channel %d\n", p->channel);
9239 ast_frfree(f);
9240 f = NULL;
9241 } else if (f->frametype == AST_FRAME_VOICE) {
9243 f->subclass.integer = 0;
9245 p->waitingfordt.tv_sec = 0;
9246 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9248 ast_debug(1, "Got 10 samples of dialtone!\n");
9249 if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */
9250 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
9251 if (res) {
9252 p->dop.dialstr[0] = '\0';
9254 ast_frfree(f);
9255 return NULL;
9256 } else {
9257 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
9258 p->dialing = 1;
9259 p->dop.dialstr[0] = '\0';
9260 p->dop.op = DAHDI_DIAL_OP_REPLACE;
9262 }
9263 }
9264 }
9265 }
9266 }
9267 }
9268 } else
9269 f = &p->subs[idx].f;
9270
9271 if (f) {
9272 struct analog_pvt *analog_p = p->sig_pvt;
9273 switch (f->frametype) {
9275 case AST_FRAME_DTMF_END:
9276 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9277 analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
9278 } else {
9279 dahdi_handle_dtmf(ast, idx, &f);
9280 }
9281 if (!(analog_p->dialmode == ANALOG_DIALMODE_BOTH || analog_p->dialmode == ANALOG_DIALMODE_DTMF)) {
9282 if (f->frametype == AST_FRAME_DTMF_END) { /* only show this message when the key is let go of */
9283 ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f->subclass.integer);
9284 }
9286 f->subclass.integer = 0;
9287 }
9288 break;
9289 case AST_FRAME_VOICE:
9290 if (p->cidspill || p->cid_suppress_expire) {
9291 /* We are/were sending a caller id spill. Suppress any echo. */
9292 p->subs[idx].f.frametype = AST_FRAME_NULL;
9293 p->subs[idx].f.subclass.integer = 0;
9294 p->subs[idx].f.samples = 0;
9295 p->subs[idx].f.mallocd = 0;
9296 p->subs[idx].f.offset = 0;
9297 p->subs[idx].f.data.ptr = NULL;
9298 p->subs[idx].f.datalen= 0;
9299 }
9300 break;
9301 default:
9302 break;
9303 }
9304 }
9305
9307 return f;
9308}
9309
9310static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
9311{
9312 int sent=0;
9313 int size;
9314 int res;
9315 int fd;
9316 fd = p->subs[idx].dfd;
9317 while (len) {
9318 size = len;
9319 if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
9320 size = (linear ? READ_SIZE * 2 : READ_SIZE);
9321 res = write(fd, buf, size);
9322 if (res != size) {
9323 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
9324 return sent;
9325 }
9326 len -= size;
9327 buf += size;
9328 }
9329 return sent;
9330}
9331
9332static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
9333{
9334 struct dahdi_pvt *p;
9335 int res;
9336 int idx;
9337
9338 /* Write a frame of (presumably voice) data */
9339 if (frame->frametype != AST_FRAME_VOICE) {
9340 if (frame->frametype != AST_FRAME_IMAGE) {
9341 ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n",
9342 frame->frametype);
9343 }
9344 return 0;
9345 }
9346
9347 /* Return if it's not valid data */
9348 if (!frame->data.ptr || !frame->datalen) {
9349 return 0;
9350 }
9351
9352 p = ast_channel_tech_pvt(ast);
9353 ast_mutex_lock(&p->lock);
9354
9355 idx = dahdi_get_index(ast, p, 0);
9356 if (idx < 0) {
9358 ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast_channel_name(ast));
9359 return -1;
9360 }
9361
9362 if (p->sig == SIG_FXOLS || p->sig == SIG_FXOKS || p->sig == SIG_FXOGS) {
9363 struct analog_pvt *analog_p = p->sig_pvt;
9364 if (analog_p->callwaitingdeluxepending) {
9365 unsigned int mssinceflash = ast_tvdiff_ms(ast_tvnow(), analog_p->flashtime);
9366 if (mssinceflash >= 1000) {
9367 /* Timer expired: the user hasn't yet selected an option. Take the default action and get on with it. */
9368 /* Note: If in the future Advanced Call Waiting Deluxe (*76) is supported, then as part of the
9369 * dialing code, we'll need to automatically invoke the preselected behavior about 2-3 seconds after
9370 * the call waiting begins (this allows for the SAS, CAS, and CWCID spill to be sent first).
9371 */
9372 analog_p->callwaitingdeluxepending = 0;
9373 analog_callwaiting_deluxe(analog_p, 0);
9374 }
9376 /* The user shouldn't hear anything after hook flashing, until a decision is made, by the user or when the timer expires. */
9377 ast_debug(5, "Dropping frame since Call Waiting Deluxe pending on %s\n", ast_channel_name(ast));
9378 return 0;
9379 }
9380 }
9381
9382 if (p->dialing) {
9384 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9385 ast_channel_name(ast));
9386 return 0;
9387 }
9388 if (!p->owner) {
9390 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9391 ast_channel_name(ast));
9392 return 0;
9393 }
9394 if (p->cidspill) {
9396 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9397 ast_channel_name(ast));
9398 return 0;
9399 }
9400
9402 if (!p->subs[idx].linear) {
9403 p->subs[idx].linear = 1;
9404 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9405 if (res)
9406 ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
9407 }
9408 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
9411 /* x-law already */
9412 if (p->subs[idx].linear) {
9413 p->subs[idx].linear = 0;
9414 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9415 if (res)
9416 ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
9417 }
9418 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
9419 } else {
9421 ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
9423 return -1;
9424 }
9426 if (res < 0) {
9427 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
9428 return -1;
9429 }
9430 return 0;
9431}
9432
9433static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
9434{
9435 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9436 int res=-1;
9437 int idx;
9438 int func = DAHDI_FLASH;
9439
9440 ast_mutex_lock(&p->lock);
9441 ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
9442 switch (p->sig) {
9443#if defined(HAVE_PRI)
9445 res = sig_pri_indicate(p->sig_pvt, chan, condition, data, datalen);
9447 return res;
9448#endif /* defined(HAVE_PRI) */
9449#if defined(HAVE_SS7)
9450 case SIG_SS7:
9451 res = sig_ss7_indicate(p->sig_pvt, chan, condition, data, datalen);
9453 return res;
9454#endif /* defined(HAVE_SS7) */
9455 default:
9456 break;
9457 }
9458#ifdef HAVE_OPENR2
9459 if (p->mfcr2 && !p->mfcr2_call_accepted) {
9461 /* if this is an R2 call and the call is not yet accepted, we don't want the
9462 tone indications to mess up with the MF tones */
9463 return 0;
9464 }
9465#endif
9466 idx = dahdi_get_index(chan, p, 0);
9467 if (idx == SUB_REAL) {
9468 switch (condition) {
9469 case AST_CONTROL_BUSY:
9470 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
9471 break;
9473 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
9474
9475 if (ast_channel_state(chan) != AST_STATE_UP) {
9476 if ((ast_channel_state(chan) != AST_STATE_RING) ||
9477 ((p->sig != SIG_FXSKS) &&
9478 (p->sig != SIG_FXSLS) &&
9479 (p->sig != SIG_FXSGS))) {
9480 /* We're playing audible ringback tone on the channel,
9481 * so set state to AST_STATE_RING, not AST_STATE_RINGING. */
9483 }
9484 }
9485 break;
9487 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan));
9488 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9489 res = 0;
9490 break;
9492 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan));
9493 /* don't continue in ast_indicate */
9494 res = 0;
9495 break;
9497 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan));
9498 /* don't continue in ast_indicate */
9499 res = 0;
9500 break;
9502 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9503 switch (ast_channel_hangupcause(chan)) {
9506 case 0:/* Cause has not been set. */
9507 /* Supply a more appropriate cause. */
9509 break;
9510 default:
9511 break;
9512 }
9513 break;
9514 case AST_CONTROL_HOLD:
9515 ast_moh_start(chan, data, p->mohinterpret);
9516 break;
9517 case AST_CONTROL_UNHOLD:
9518 ast_moh_stop(chan);
9519 break;
9521 if (p->radio)
9522 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
9523 res = 0;
9524 break;
9526 if (p->radio)
9527 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
9528 res = 0;
9529 break;
9530 case AST_CONTROL_FLASH:
9531 /* flash hookswitch */
9532 if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
9533 /* Clear out the dial buffer */
9534 p->dop.dialstr[0] = '\0';
9535 if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
9536 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
9537 ast_channel_name(chan), strerror(errno));
9538 } else
9539 res = 0;
9540 } else
9541 res = 0;
9542 break;
9544 res = 0;
9545 break;
9546 case -1:
9547 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
9548 break;
9549 }
9550 } else {
9551 res = 0;
9552 }
9554 return res;
9555}
9556
9557#if defined(HAVE_PRI)
9558static struct ast_str *create_channel_name(struct dahdi_pvt *i, int is_outgoing, char *address)
9559#else
9560static struct ast_str *create_channel_name(struct dahdi_pvt *i)
9561#endif /* defined(HAVE_PRI) */
9562{
9563 struct ast_str *chan_name;
9564 int x, y;
9565
9566 /* Create the new channel name tail. */
9567 if (!(chan_name = ast_str_create(32))) {
9568 return NULL;
9569 }
9570 if (i->channel == CHAN_PSEUDO) {
9571 ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
9572#if defined(HAVE_PRI)
9573 } else if (i->pri) {
9574 ast_mutex_lock(&i->pri->lock);
9575 y = ++i->pri->new_chan_seq;
9576 if (is_outgoing) {
9577 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, address, (unsigned)y);
9578 address[0] = '\0';
9579 } else if (ast_strlen_zero(i->cid_subaddr)) {
9580 /* Put in caller-id number only since there is no subaddress. */
9581 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, i->cid_num, (unsigned)y);
9582 } else {
9583 /* Put in caller-id number and subaddress. */
9584 ast_str_set(&chan_name, 0, "i%d/%s:%s-%x", i->pri->span, i->cid_num,
9585 i->cid_subaddr, (unsigned)y);
9586 }
9587 ast_mutex_unlock(&i->pri->lock);
9588#endif /* defined(HAVE_PRI) */
9589 } else {
9590 y = 1;
9591 do {
9592 ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
9593 for (x = 0; x < 3; ++x) {
9594 if (i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name),
9595 ast_channel_name(i->subs[x].owner) + 6)) {
9596 break;
9597 }
9598 }
9599 ++y;
9600 } while (x < 3);
9601 }
9602 return chan_name;
9603}
9604
9605static 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)
9606{
9607 struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, assignedids, requestor, callid);
9608
9610
9611 return new_channel;
9612}
9613
9614static 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)
9615{
9616 struct ast_channel *tmp;
9617 struct ast_format_cap *caps;
9618 struct ast_format *deflaw;
9619 int x;
9620 int features;
9621 struct ast_str *chan_name;
9622 struct ast_variable *v;
9623 char *dashptr;
9624 char device_name[AST_CHANNEL_NAME];
9625
9626 if (i->subs[idx].owner) {
9627 ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
9628 return NULL;
9629 }
9630
9631#if defined(HAVE_PRI)
9632 /*
9633 * The dnid has been stuffed with the called-number[:subaddress]
9634 * by dahdi_request() for outgoing calls.
9635 */
9636 chan_name = create_channel_name(i, i->outgoing, i->dnid);
9637#else
9638 chan_name = create_channel_name(i);
9639#endif /* defined(HAVE_PRI) */
9640 if (!chan_name) {
9641 return NULL;
9642 }
9643
9645 if (!caps) {
9646 ast_free(chan_name);
9647 return NULL;
9648 }
9649
9650 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));
9651 ast_free(chan_name);
9652 if (!tmp) {
9653 ao2_ref(caps, -1);
9654 return NULL;
9655 }
9656
9658
9659 if (callid) {
9660 ast_channel_callid_set(tmp, callid);
9661 }
9662
9664#if defined(HAVE_PRI)
9665 if (i->pri) {
9667 }
9668#endif /* defined(HAVE_PRI) */
9670 if (law) {
9671 i->law = law;
9672 if (law == DAHDI_LAW_ALAW) {
9673 deflaw = ast_format_alaw;
9674 } else {
9675 deflaw = ast_format_ulaw;
9676 }
9677 } else {
9678 switch (i->sig) {
9680 /* Make sure companding law is known. */
9681 i->law = (i->law_default == DAHDI_LAW_ALAW)
9682 ? DAHDI_LAW_ALAW : DAHDI_LAW_MULAW;
9683 break;
9684 default:
9685 i->law = i->law_default;
9686 break;
9687 }
9688 if (i->law_default == DAHDI_LAW_ALAW) {
9689 deflaw = ast_format_alaw;
9690 } else {
9691 deflaw = ast_format_ulaw;
9692 }
9693 }
9694 ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
9695 ast_format_cap_append(caps, deflaw, 0);
9697 ao2_ref(caps, -1);
9698 /* Start out assuming ulaw since it's smaller :) */
9699 ast_channel_set_rawreadformat(tmp, deflaw);
9700 ast_channel_set_readformat(tmp, deflaw);
9701 ast_channel_set_rawwriteformat(tmp, deflaw);
9702 ast_channel_set_writeformat(tmp, deflaw);
9703 i->subs[idx].linear = 0;
9704 dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
9705 features = 0;
9706 if (idx == SUB_REAL) {
9707 if (i->busydetect && CANBUSYDETECT(i))
9708 features |= DSP_FEATURE_BUSY_DETECT;
9710 features |= DSP_FEATURE_CALL_PROGRESS;
9712 features |= DSP_FEATURE_WAITDIALTONE;
9713 if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
9715 features |= DSP_FEATURE_FAX_DETECT;
9716 }
9717 x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
9718 if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
9719 i->hardwaredtmf = 0;
9720 features |= DSP_FEATURE_DIGIT_DETECT;
9721 } else if (NEED_MFDETECT(i)) {
9722 i->hardwaredtmf = 1;
9723 features |= DSP_FEATURE_DIGIT_DETECT;
9724 }
9725 }
9726 if (features) {
9727 if (i->dsp) {
9728 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp));
9729 } else {
9730 if (i->channel != CHAN_PSEUDO)
9731 i->dsp = ast_dsp_new();
9732 else
9733 i->dsp = NULL;
9734 if (i->dsp) {
9735 i->dsp_features = features;
9736#if defined(HAVE_PRI) || defined(HAVE_SS7)
9737 /* We cannot do progress detection until receive PROGRESS message */
9738 if (i->outgoing && (dahdi_sig_pri_lib_handles(i->sig) || (i->sig == SIG_SS7))) {
9739 /* Remember requested DSP features, don't treat
9740 talking as ANSWER */
9741 i->dsp_features = features & ~DSP_PROGRESS_TALK;
9742 features = 0;
9743 }
9744#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9745 ast_dsp_set_features(i->dsp, features);
9749 if (i->busydetect && CANBUSYDETECT(i)) {
9752 }
9753 }
9754 }
9755 }
9756
9758
9759 if (state == AST_STATE_RING)
9760 ast_channel_rings_set(tmp, 1);
9762 if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
9763 /* Only FXO signalled stuff can be picked up */
9768 }
9769 if (!ast_strlen_zero(i->parkinglot))
9770 ast_channel_parkinglot_set(tmp, i->parkinglot);
9771 if (!ast_strlen_zero(i->language))
9772 ast_channel_language_set(tmp, i->language);
9773 if (!i->owner)
9774 i->owner = tmp;
9776 ast_channel_accountcode_set(tmp, i->accountcode);
9777 if (i->amaflags)
9779 i->subs[idx].owner = tmp;
9781 if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
9782 ast_channel_call_forward_set(tmp, i->call_forward);
9783 }
9784 /* If we've been told "no ADSI" then enforce it */
9785 if (!i->adsi)
9787 if (!ast_strlen_zero(i->exten))
9789 if (!ast_strlen_zero(i->rdnis)) {
9792 }
9793 if (!ast_strlen_zero(i->dnid)) {
9795 }
9796
9797 /* Don't use ast_set_callerid() here because it will
9798 * generate a needless NewCallerID event */
9799#if defined(HAVE_PRI) || defined(HAVE_SS7)
9800 if (!ast_strlen_zero(i->cid_ani)) {
9802 ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_ani);
9803 } else if (!ast_strlen_zero(i->cid_num)) {
9806 }
9807#else
9808 if (!ast_strlen_zero(i->cid_num)) {
9811 }
9812#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9816 ast_channel_caller(tmp)->ani2 = i->cid_ani2;
9818 /* clear the fake event in case we posted one before we had ast_channel */
9819 i->fake_event = 0;
9820 /* Assure there is no confmute on this channel */
9821 dahdi_confmute(i, 0);
9822 i->muting = 0;
9823 /* Configure the new channel jb */
9825
9826 /* Set initial device state */
9827 ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name));
9828 dashptr = strrchr(device_name, '-');
9829 if (dashptr) {
9830 *dashptr = '\0';
9831 }
9834
9835 for (v = i->vars ; v ; v = v->next)
9837
9839
9840 ast_channel_unlock(tmp);
9841
9843
9845 if (startpbx) {
9846#ifdef HAVE_OPENR2
9847 if (i->mfcr2call) {
9848 pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
9849 }
9850#endif
9851 if (ast_pbx_start(tmp)) {
9852 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
9853 ast_hangup(tmp);
9854 return NULL;
9855 }
9856 }
9857 return tmp;
9858}
9859
9860
9861static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
9862{
9863 char c;
9864
9865 *str = 0; /* start with empty output buffer */
9866 for (;;)
9867 {
9868 /* Wait for the first digit (up to specified ms). */
9869 c = ast_waitfordigit(chan, ms);
9870 /* if timeout, hangup or error, return as such */
9871 if (c < 1)
9872 return c;
9873 *str++ = c;
9874 *str = 0;
9875 if (strchr(term, c))
9876 return 1;
9877 }
9878}
9879
9880static int dahdi_wink(struct dahdi_pvt *p, int idx)
9881{
9882 int j;
9883 dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
9884 for (;;)
9885 {
9886 /* set bits of interest */
9887 j = DAHDI_IOMUX_SIGEVENT;
9888 /* wait for some happening */
9889 if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
9890 /* exit loop if we have it */
9891 if (j & DAHDI_IOMUX_SIGEVENT) break;
9892 }
9893 /* get the event info */
9894 if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
9895 return 0;
9896}
9897
9898static void publish_dnd_state(int channel, const char *status)
9899{
9900 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
9901 RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
9902 if (!dahdichan) {
9903 return;
9904 }
9905
9906 ast_str_set(&dahdichan, 0, "%d", channel);
9907
9908 body = ast_json_pack("{s: s, s: s}",
9909 "DAHDIChannel", ast_str_buffer(dahdichan),
9910 "Status", status);
9911 if (!body) {
9912 return;
9913 }
9914
9916}
9917
9918/*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9919 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9920 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9921 *
9922 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9923 * DAHDI channel). Use this to enable or disable it.
9924 *
9925 * \bug the use of the word "channel" for those dahdichans is really confusing.
9926 */
9927static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
9928{
9929 if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
9930 return analog_dnd(dahdichan->sig_pvt, flag);
9931 }
9932
9933 if (flag == -1) {
9934 return dahdichan->dnd;
9935 }
9936
9937 /* Do not disturb */
9938 dahdichan->dnd = flag;
9939 ast_verb(3, "%s DND on channel %d\n",
9940 flag? "Enabled" : "Disabled",
9941 dahdichan->channel);
9942 publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
9943 return 0;
9944}
9945
9946static int canmatch_featurecode(const char *pickupexten, const char *exten)
9947{
9948 int extlen = strlen(exten);
9949
9950 if (!extlen) {
9951 return 1;
9952 }
9953
9954 if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
9955 return 1;
9956 }
9957 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9958 if (exten[0] == '*' && extlen < 3) {
9959 if (extlen == 1) {
9960 return 1;
9961 }
9962 /* "*0" should be processed before it gets here */
9963 switch (exten[1]) {
9964 case '6':
9965 case '7':
9966 case '8':
9967 return 1;
9968 }
9969 }
9970 return 0;
9971}
9972
9973static void *analog_ss_thread(void *data)
9974{
9975 struct ast_channel *chan = data;
9976 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9977 char exten[AST_MAX_EXTENSION] = "";
9978 char exten2[AST_MAX_EXTENSION] = "";
9979 unsigned char buf[256];
9980 char dtmfcid[300];
9981 char dtmfbuf[300];
9982 struct callerid_state *cs = NULL;
9983 char *name = NULL, *number = NULL;
9984 int distMatches;
9985 int curRingData[3];
9986 int receivedRingT;
9987 int counter1;
9988 int counter;
9989 int samples = 0;
9990 struct ast_smdi_md_message *smdi_msg = NULL;
9991 int flags = 0;
9992 int i;
9993 int timeout;
9994 int getforward = 0;
9995 char *s1, *s2;
9996 int len = 0;
9997 int res;
9998 int idx;
9999 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
10000 const char *pickupexten;
10001
10005 /* in the bizarre case where the channel has become a zombie before we
10006 even get started here, abort safely
10007 */
10008 if (!p) {
10009 ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
10010 ast_hangup(chan);
10011 goto quit;
10012 }
10013 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
10014 idx = dahdi_get_index(chan, p, 1);
10015 if (idx < 0) {
10016 ast_log(LOG_WARNING, "Huh?\n");
10017 ast_hangup(chan);
10018 goto quit;
10019 }
10020
10021 ast_channel_lock(chan);
10022 pickup_cfg = ast_get_chan_features_pickup_config(chan);
10023 if (!pickup_cfg) {
10024 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
10025 pickupexten = "";
10026 } else {
10027 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
10028 }
10029 ast_channel_unlock(chan);
10030
10031 if (p->dsp)
10033 switch (p->sig) {
10034 case SIG_FEATD:
10035 case SIG_FEATDMF:
10036 case SIG_FEATDMF_TA:
10037 case SIG_E911:
10038 case SIG_FGC_CAMAMF:
10039 case SIG_FEATB:
10040 case SIG_EMWINK:
10041 case SIG_SF_FEATD:
10042 case SIG_SF_FEATDMF:
10043 case SIG_SF_FEATB:
10044 case SIG_SFWINK:
10045 if (dahdi_wink(p, idx))
10046 goto quit;
10047 /* Fall through */
10048 case SIG_EM:
10049 case SIG_EM_E1:
10050 case SIG_SF:
10051 case SIG_FGC_CAMA:
10052 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10053 if (p->dsp)
10055 /* set digit mode appropriately */
10056 if (p->dsp) {
10057 if (NEED_MFDETECT(p))
10059 else
10061 }
10062 memset(dtmfbuf, 0, sizeof(dtmfbuf));
10063 /* Wait for the first digit only if immediate=no */
10064 if (!p->immediate)
10065 /* Wait for the first digit (up to 5 seconds). */
10066 res = ast_waitfordigit(chan, 5000);
10067 else
10068 res = 0;
10069 if (res > 0) {
10070 /* save first char */
10071 dtmfbuf[0] = res;
10072 switch (p->sig) {
10073 case SIG_FEATD:
10074 case SIG_SF_FEATD:
10075 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10076 if (res > 0)
10077 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10078 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10079 break;
10080 case SIG_FEATDMF_TA:
10081 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10082 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10083 if (dahdi_wink(p, idx)) goto quit;
10084 dtmfbuf[0] = 0;
10085 /* Wait for the first digit (up to 5 seconds). */
10086 res = ast_waitfordigit(chan, 5000);
10087 if (res <= 0) break;
10088 dtmfbuf[0] = res;
10089 /* fall through intentionally */
10090 case SIG_FEATDMF:
10091 case SIG_E911:
10092 case SIG_FGC_CAMAMF:
10093 case SIG_SF_FEATDMF:
10094 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10095 /* if international caca, do it again to get real ANO */
10096 if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
10097 {
10098 if (dahdi_wink(p, idx)) goto quit;
10099 dtmfbuf[0] = 0;
10100 /* Wait for the first digit (up to 5 seconds). */
10101 res = ast_waitfordigit(chan, 5000);
10102 if (res <= 0) break;
10103 dtmfbuf[0] = res;
10104 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10105 }
10106 if (res > 0) {
10107 /* if E911, take off hook */
10108 if (p->sig == SIG_E911)
10109 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10110 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
10111 }
10112 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10113 break;
10114 case SIG_FEATB:
10115 case SIG_SF_FEATB:
10116 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10117 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10118 break;
10119 case SIG_EMWINK:
10120 /* if we received a '*', we are actually receiving Feature Group D
10121 dial syntax, so use that mode; otherwise, fall through to normal
10122 mode
10123 */
10124 if (res == '*') {
10125 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10126 if (res > 0)
10127 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10128 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10129 break;
10130 }
10131 default:
10132 /* If we got the first digit, get the rest */
10133 len = 1;
10134 dtmfbuf[len] = '\0';
10135 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10136 if (ast_exists_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10137 timeout = p->matchdigit_timeout;
10138 } else {
10139 timeout = p->interdigit_timeout;
10140 }
10141 res = ast_waitfordigit(chan, timeout);
10142 if (res < 0) {
10143 ast_debug(1, "waitfordigit returned < 0...\n");
10144 ast_hangup(chan);
10145 goto quit;
10146 } else if (res) {
10147 dtmfbuf[len++] = res;
10148 dtmfbuf[len] = '\0';
10149 } else {
10150 break;
10151 }
10152 }
10153 break;
10154 }
10155 }
10156 if (res == -1) {
10157 ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
10158 ast_hangup(chan);
10159 goto quit;
10160 } else if (res < 0) {
10161 ast_debug(1, "Got hung up before digits finished\n");
10162 ast_hangup(chan);
10163 goto quit;
10164 }
10165
10166 if (p->sig == SIG_FGC_CAMA) {
10167 char anibuf[100];
10168
10169 if (ast_safe_sleep(chan,1000) == -1) {
10170 ast_hangup(chan);
10171 goto quit;
10172 }
10173 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10175 res = my_getsigstr(chan, anibuf, "#", 10000);
10176 if ((res > 0) && (strlen(anibuf) > 2)) {
10177 if (anibuf[strlen(anibuf) - 1] == '#')
10178 anibuf[strlen(anibuf) - 1] = 0;
10179 ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
10180 }
10182 }
10183
10184 ast_copy_string(exten, dtmfbuf, sizeof(exten));
10185 if (ast_strlen_zero(exten))
10186 ast_copy_string(exten, "s", sizeof(exten));
10187 if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
10188 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10189 if (exten[0] == '*') {
10190 char *stringp=NULL;
10191 ast_copy_string(exten2, exten, sizeof(exten2));
10192 /* Parse out extension and callerid */
10193 stringp=exten2 +1;
10194 s1 = strsep(&stringp, "*");
10195 s2 = strsep(&stringp, "*");
10196 if (s2) {
10197 if (!ast_strlen_zero(p->cid_num))
10198 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10199 else
10200 ast_set_callerid(chan, s1, NULL, s1);
10201 ast_copy_string(exten, s2, sizeof(exten));
10202 } else
10203 ast_copy_string(exten, s1, sizeof(exten));
10204 } else if (p->sig == SIG_FEATD)
10205 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10206 }
10207 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10208 if (exten[0] == '*') {
10209 char *stringp=NULL;
10210 ast_copy_string(exten2, exten, sizeof(exten2));
10211 /* Parse out extension and callerid */
10212 stringp=exten2 +1;
10213 s1 = strsep(&stringp, "#");
10214 s2 = strsep(&stringp, "#");
10215 if (s2) {
10216 if (!ast_strlen_zero(p->cid_num))
10217 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10218 else
10219 if (*(s1 + 2))
10220 ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
10221 ast_copy_string(exten, s2 + 1, sizeof(exten));
10222 } else
10223 ast_copy_string(exten, s1 + 2, sizeof(exten));
10224 } else
10225 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10226 }
10227 if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
10228 if (exten[0] == '*') {
10229 char *stringp=NULL;
10230 ast_copy_string(exten2, exten, sizeof(exten2));
10231 /* Parse out extension and callerid */
10232 stringp=exten2 +1;
10233 s1 = strsep(&stringp, "#");
10234 s2 = strsep(&stringp, "#");
10235 if (s2 && (*(s2 + 1) == '0')) {
10236 if (*(s2 + 2))
10237 ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
10238 }
10239 if (s1) ast_copy_string(exten, s1, sizeof(exten));
10240 else ast_copy_string(exten, "911", sizeof(exten));
10241 } else
10242 ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
10243 }
10244 if (p->sig == SIG_FEATB) {
10245 if (exten[0] == '*') {
10246 char *stringp=NULL;
10247 ast_copy_string(exten2, exten, sizeof(exten2));
10248 /* Parse out extension and callerid */
10249 stringp=exten2 +1;
10250 s1 = strsep(&stringp, "#");
10251 ast_copy_string(exten, exten2 + 1, sizeof(exten));
10252 } else
10253 ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
10254 }
10255 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10256 dahdi_wink(p, idx);
10257 /* some switches require a minimum guard time between
10258 the last FGD wink and something that answers
10259 immediately. This ensures it */
10260 if (ast_safe_sleep(chan, 100)) {
10261 ast_hangup(chan);
10262 goto quit;
10263 }
10264 }
10265 dahdi_ec_enable(p);
10266 if (NEED_MFDETECT(p)) {
10267 if (p->dsp) {
10268 if (!p->hardwaredtmf)
10270 else {
10271 ast_dsp_free(p->dsp);
10272 p->dsp = NULL;
10273 }
10274 }
10275 }
10276
10277 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1,
10278 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10279 ast_channel_exten_set(chan, exten);
10280 if (p->dsp) ast_dsp_digitreset(p->dsp);
10281 res = ast_pbx_run(chan);
10282 if (res) {
10283 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10284 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10285 }
10286 goto quit;
10287 } else {
10288 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, ast_channel_context(chan));
10289 sleep(2);
10290 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
10291 if (res < 0)
10292 ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
10293 else
10294 sleep(1);
10295 res = ast_streamfile(chan, "ss-noservice", ast_channel_language(chan));
10296 if (res >= 0)
10297 ast_waitstream(chan, "");
10298 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10299 ast_hangup(chan);
10300 goto quit;
10301 }
10302 break;
10303 case SIG_FXOLS:
10304 case SIG_FXOGS:
10305 case SIG_FXOKS:
10306 /* Read the first digit */
10307 timeout = p->firstdigit_timeout;
10308 /* If starting a threeway call, never timeout on the first digit so someone
10309 can use flash-hook as a "hold" feature */
10310 if (p->subs[SUB_THREEWAY].owner)
10311 timeout = INT_MAX;
10312 while (len < AST_MAX_EXTENSION-1) {
10313 int is_exten_parking = 0;
10314
10315 /* Read digit unless it's supposed to be immediate, in which case the
10316 only answer is 's' */
10317 if (p->immediate)
10318 res = 's';
10319 else
10320 res = ast_waitfordigit(chan, timeout);
10321 timeout = 0;
10322 if (res < 0) {
10323 ast_debug(1, "waitfordigit returned < 0...\n");
10324 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10325 ast_hangup(chan);
10326 goto quit;
10327 } else if (res) {
10328 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
10329 exten[len++]=res;
10330 exten[len] = '\0';
10331 }
10332 if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
10333 tone_zone_play_tone(p->subs[idx].dfd, -1);
10334 } else {
10335 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10336 }
10338 is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
10339 }
10340 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
10341 if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
10342 if (getforward) {
10343 /* Record this as the forwarding extension */
10344 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
10345 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
10346 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10347 if (res)
10348 break;
10349 usleep(500000);
10350 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10351 sleep(1);
10352 memset(exten, 0, sizeof(exten));
10353 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10354 len = 0;
10355 getforward = 0;
10356 } else {
10357 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10358 ast_channel_lock(chan);
10359 ast_channel_exten_set(chan, exten);
10360 if (!ast_strlen_zero(p->cid_num)) {
10361 if (!p->hidecallerid)
10362 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10363 else
10364 ast_set_callerid(chan, NULL, NULL, p->cid_num);
10365 }
10366 if (!ast_strlen_zero(p->cid_name)) {
10367 if (!p->hidecallerid)
10368 ast_set_callerid(chan, NULL, p->cid_name, NULL);
10369 }
10371 ast_channel_unlock(chan);
10372 dahdi_ec_enable(p);
10373 res = ast_pbx_run(chan);
10374 if (res) {
10375 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10376 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10377 }
10378 goto quit;
10379 }
10380 } else {
10381 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10382 so just set the timeout to matchdigit_timeout and wait some more */
10383 timeout = p->matchdigit_timeout;
10384 }
10385 } else if (res == 0) {
10386 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10387 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10388 dahdi_wait_event(p->subs[idx].dfd);
10389 ast_hangup(chan);
10390 goto quit;
10391 } else if (p->callwaiting && !strcmp(exten, "*70")) {
10392 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
10393 /* Disable call waiting if enabled */
10394 p->callwaiting = 0;
10395 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10396 if (res) {
10397 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10398 ast_channel_name(chan), strerror(errno));
10399 }
10400 len = 0;
10401 ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
10402 memset(exten, 0, sizeof(exten));
10403 timeout = p->firstdigit_timeout;
10404
10405 } else if (!strcmp(exten, pickupexten)) {
10406 /* Scan all channels and see if there are any
10407 * ringing channels that have call groups
10408 * that equal this channels pickup group
10409 */
10410 if (idx == SUB_REAL) {
10411 /* Switch us from Third call to Call Wait */
10412 if (p->subs[SUB_THREEWAY].owner) {
10413 /* If you make a threeway call and the *8# a call, it should actually
10414 look like a callwait */
10418 }
10419 dahdi_ec_enable(p);
10420 if (ast_pickup_call(chan)) {
10421 ast_debug(1, "No call pickup possible...\n");
10422 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10423 dahdi_wait_event(p->subs[idx].dfd);
10424 }
10425 ast_hangup(chan);
10426 goto quit;
10427 } else {
10428 ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
10429 ast_hangup(chan);
10430 goto quit;
10431 }
10432
10433 } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
10434 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
10435 /* Disable Caller*ID if enabled */
10436 p->hidecallerid = 1;
10441 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10442 if (res) {
10443 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10444 ast_channel_name(chan), strerror(errno));
10445 }
10446 len = 0;
10447 memset(exten, 0, sizeof(exten));
10448 timeout = p->firstdigit_timeout;
10449 } else if (p->callreturn && !strcmp(exten, "*69")) {
10450 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10451 break;
10452 } else if (!strcmp(exten, "*78")) {
10453 dahdi_dnd(p, 1);
10454 /* Do not disturb */
10455 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10456 getforward = 0;
10457 memset(exten, 0, sizeof(exten));
10458 len = 0;
10459 } else if (!strcmp(exten, "*79")) {
10460 dahdi_dnd(p, 0);
10461 /* Do not disturb */
10462 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10463 getforward = 0;
10464 memset(exten, 0, sizeof(exten));
10465 len = 0;
10466 } else if (p->cancallforward && !strcmp(exten, "*72")) {
10467 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10468 getforward = 1;
10469 memset(exten, 0, sizeof(exten));
10470 len = 0;
10471 } else if (p->cancallforward && !strcmp(exten, "*73")) {
10472 ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
10473 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10474 memset(p->call_forward, 0, sizeof(p->call_forward));
10475 getforward = 0;
10476 memset(exten, 0, sizeof(exten));
10477 len = 0;
10478 } else if ((p->transfer || p->canpark) && is_exten_parking
10479 && p->subs[SUB_THREEWAY].owner) {
10480 struct ast_bridge_channel *bridge_channel;
10481
10482 /*
10483 * This is a three way call, the main call being a real channel,
10484 * and we're parking the first call.
10485 */
10489 if (bridge_channel) {
10490 if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
10491 /*
10492 * Swap things around between the three-way and real call so we
10493 * can hear where the channel got parked.
10494 */
10495 ast_mutex_lock(&p->lock);
10496 p->owner = p->subs[SUB_THREEWAY].owner;
10499
10500 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
10502 ao2_ref(bridge_channel, -1);
10503 goto quit;
10504 }
10505 ao2_ref(bridge_channel, -1);
10506 }
10507 break;
10508 } else if (p->hidecallerid && !strcmp(exten, "*82")) {
10509 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
10510 /* Enable Caller*ID if enabled */
10511 p->hidecallerid = 0;
10513 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10514 if (res) {
10515 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10516 ast_channel_name(chan), strerror(errno));
10517 }
10518 len = 0;
10519 memset(exten, 0, sizeof(exten));
10520 timeout = p->firstdigit_timeout;
10521 } else if (!strcmp(exten, "*0")) {
10522 struct ast_channel *nbridge =
10524 struct dahdi_pvt *pbridge = NULL;
10525 RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
10526
10527 /* set up the private struct of the bridged one, if any */
10528 if (nbridge && bridged) {
10529 pbridge = ast_channel_tech_pvt(bridged);
10530 }
10531 if (nbridge && pbridge &&
10532 (ast_channel_tech(nbridge) == &dahdi_tech) &&
10533 (ast_channel_tech(bridged) == &dahdi_tech) &&
10534 ISTRUNK(pbridge)) {
10535 int func = DAHDI_FLASH;
10536 /* Clear out the dial buffer */
10537 p->dop.dialstr[0] = '\0';
10538 /* flash hookswitch */
10539 if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
10540 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
10541 ast_channel_name(nbridge), strerror(errno));
10542 }
10545 p->owner = p->subs[SUB_REAL].owner;
10547 ast_hangup(chan);
10548 goto quit;
10549 } else {
10550 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10551 dahdi_wait_event(p->subs[idx].dfd);
10552 tone_zone_play_tone(p->subs[idx].dfd, -1);
10555 p->owner = p->subs[SUB_REAL].owner;
10556 ast_hangup(chan);
10557 goto quit;
10558 }
10559 } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
10560 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
10561 && !canmatch_featurecode(pickupexten, exten)) {
10562 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
10563 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
10564 ast_channel_context(chan));
10565 break;
10566 }
10567 if (!timeout)
10568 timeout = p->interdigit_timeout;
10570 tone_zone_play_tone(p->subs[idx].dfd, -1);
10571 }
10572 break;
10573 case SIG_FXSLS:
10574 case SIG_FXSGS:
10575 case SIG_FXSKS:
10576 /* check for SMDI messages */
10577 if (p->use_smdi && p->smdi_iface) {
10579
10580 if (smdi_msg != NULL) {
10581 ast_channel_exten_set(chan, smdi_msg->fwd_st);
10582
10583 if (smdi_msg->type == 'B')
10584 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
10585 else if (smdi_msg->type == 'N')
10586 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
10587
10588 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan));
10589 } else {
10590 ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
10591 }
10592 }
10593
10594 if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
10595 number = smdi_msg->calling_st;
10596
10597 /* If we want caller id, we're in a prering state due to a polarity reversal
10598 * and we're set to use a polarity reversal to trigger the start of caller id,
10599 * grab the caller id and wait for ringing to start... */
10600 } else if (p->use_callerid && (ast_channel_state(chan) == AST_STATE_PRERING &&
10602 /* If set to use DTMF CID signalling, listen for DTMF */
10603 if (p->cid_signalling == CID_SIG_DTMF) {
10604 int k = 0;
10605 int off_ms;
10606 struct timeval start = ast_tvnow();
10607 int ms;
10608 cs = NULL;
10609 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
10610 dahdi_setlinear(p->subs[idx].dfd, 0);
10611 /*
10612 * We are the only party interested in the Rx stream since
10613 * we have not answered yet. We don't need or even want DTMF
10614 * emulation. The DTMF digits can come so fast that emulation
10615 * can drop some of them.
10616 */
10617 ast_channel_lock(chan);
10619 ast_channel_unlock(chan);
10620 off_ms = 4000;/* This is a typical OFF time between rings. */
10621 for (;;) {
10622 struct ast_frame *f;
10623
10624 ms = ast_remaining_ms(start, off_ms);
10625 res = ast_waitfor(chan, ms);
10626 if (res <= 0) {
10627 /*
10628 * We do not need to restore the dahdi_setlinear()
10629 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10630 * are hanging up the channel.
10631 */
10632 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10633 "Exiting simple switch\n");
10634 ast_hangup(chan);
10635 goto quit;
10636 }
10637 f = ast_read(chan);
10638 if (!f)
10639 break;
10640 if (f->frametype == AST_FRAME_DTMF) {
10641 if (k < ARRAY_LEN(dtmfbuf) - 1) {
10642 dtmfbuf[k++] = f->subclass.integer;
10643 }
10644 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10645 start = ast_tvnow();
10646 }
10647 ast_frfree(f);
10648 if (ast_channel_state(chan) == AST_STATE_RING ||
10650 break; /* Got ring */
10651 }
10652 ast_channel_lock(chan);
10654 ast_channel_unlock(chan);
10655 dtmfbuf[k] = '\0';
10656 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10657 /* Got cid and ring. */
10658 ast_debug(1, "CID got string '%s'\n", dtmfbuf);
10659 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10660 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid, flags);
10661 /* If first byte is NULL, we have no cid */
10662 if (!ast_strlen_zero(dtmfcid))
10663 number = dtmfcid;
10664 else
10665 number = NULL;
10666 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10667 } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
10669 if (cs) {
10670 int off_ms;
10671 struct timeval start;
10672 int ms;
10673 samples = 0;
10674#if 1
10675 bump_gains(p);
10676#endif
10677 /* Take out of linear mode for Caller*ID processing */
10678 dahdi_setlinear(p->subs[idx].dfd, 0);
10679
10680 /* First we wait and listen for the Caller*ID */
10681 for (;;) {
10682 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10683 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10684 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10685 callerid_free(cs);
10686 ast_hangup(chan);
10687 goto quit;
10688 }
10689 if (i & DAHDI_IOMUX_SIGEVENT) {
10690 res = dahdi_get_event(p->subs[idx].dfd);
10691 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10692 if (res == DAHDI_EVENT_NOALARM) {
10693 p->inalarm = 0;
10694 }
10695
10696 if (p->cid_signalling == CID_SIG_V23_JP) {
10697 if (res == DAHDI_EVENT_RINGBEGIN) {
10698 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10699 usleep(1);
10700 }
10701 } else {
10702 res = 0;
10703 break;
10704 }
10705 } else if (i & DAHDI_IOMUX_READ) {
10706 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10707 if (res < 0) {
10708 if (errno != ELAST) {
10709 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10710 callerid_free(cs);
10711 ast_hangup(chan);
10712 goto quit;
10713 }
10714 break;
10715 }
10716 samples += res;
10717
10718 if (p->cid_signalling == CID_SIG_V23_JP) {
10719 res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
10720 } else {
10721 res = callerid_feed(cs, buf, res, AST_LAW(p));
10722 }
10723 if (res < 0) {
10724 /*
10725 * The previous diagnostic message output likely
10726 * explains why it failed.
10727 */
10729 "Failed to decode CallerID on channel '%s'\n",
10730 ast_channel_name(chan));
10731 break;
10732 } else if (res)
10733 break;
10734 else if (samples > (8000 * 10))
10735 break;
10736 }
10737 }
10738 if (res == 1) {
10739 callerid_get(cs, &name, &number, &flags);
10740 ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
10741 }
10742
10743 if (p->cid_signalling == CID_SIG_V23_JP) {
10744 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
10745 usleep(1);
10746 }
10747
10748 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10749 start = ast_tvnow();
10750 off_ms = 4000;/* This is a typical OFF time between rings. */
10751 for (;;) {
10752 struct ast_frame *f;
10753
10754 ms = ast_remaining_ms(start, off_ms);
10755 res = ast_waitfor(chan, ms);
10756 if (res <= 0) {
10757 ast_log(LOG_WARNING, "CID timed out waiting for ring. "
10758 "Exiting simple switch\n");
10759 ast_hangup(chan);
10760 goto quit;
10761 }
10762 if (!(f = ast_read(chan))) {
10763 ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
10764 ast_hangup(chan);
10765 goto quit;
10766 }
10767 ast_frfree(f);
10768 if (ast_channel_state(chan) == AST_STATE_RING ||
10770 break; /* Got ring */
10771 }
10772
10773 /* We must have a ring by now, so, if configured, lets try to listen for
10774 * distinctive ringing */
10776 len = 0;
10777 distMatches = 0;
10778 /* Clear the current ring data array so we don't have old data in it. */
10779 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10780 curRingData[receivedRingT] = 0;
10781 receivedRingT = 0;
10782 counter = 0;
10783 counter1 = 0;
10784 /* Check to see if context is what it should be, if not set to be. */
10785 if (strcmp(p->context,p->defcontext) != 0) {
10786 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10788 }
10789
10790 for (;;) {
10791 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10792 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10793 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10794 callerid_free(cs);
10795 ast_hangup(chan);
10796 goto quit;
10797 }
10798 if (i & DAHDI_IOMUX_SIGEVENT) {
10799 res = dahdi_get_event(p->subs[idx].dfd);
10800 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10801 if (res == DAHDI_EVENT_NOALARM) {
10802 p->inalarm = 0;
10803 }
10804 res = 0;
10805 /* Let us detect distinctive ring */
10806
10807 curRingData[receivedRingT] = p->ringt;
10808
10809 if (p->ringt < p->ringt_base/2)
10810 break;
10811 /* Increment the ringT counter so we can match it against
10812 values in chan_dahdi.conf for distinctive ring */
10813 if (++receivedRingT == ARRAY_LEN(curRingData))
10814 break;
10815 } else if (i & DAHDI_IOMUX_READ) {
10816 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10817 if (res < 0) {
10818 if (errno != ELAST) {
10819 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10820 callerid_free(cs);
10821 ast_hangup(chan);
10822 goto quit;
10823 }
10824 break;
10825 }
10826 if (p->ringt > 0) {
10827 if (!(--p->ringt)) {
10828 res = -1;
10829 break;
10830 }
10831 }
10832 }
10833 }
10834 /* this only shows up if you have n of the dring patterns filled in */
10835 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
10836 for (counter = 0; counter < 3; counter++) {
10837 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10838 channel */
10839 distMatches = 0;
10840 for (counter1 = 0; counter1 < 3; counter1++) {
10841 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
10842 if (p->drings.ringnum[counter].ring[counter1] == -1) {
10843 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10844 curRingData[counter1]);
10845 distMatches++;
10846 } else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
10847 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
10848 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10849 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
10850 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
10851 distMatches++;
10852 }
10853 }
10854
10855 if (distMatches == 3) {
10856 /* The ring matches, set the context to whatever is for distinctive ring.. */
10857 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
10859 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
10860 break;
10861 }
10862 }
10863 }
10864 /* Restore linear mode (if appropriate) for Caller*ID processing */
10865 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10866#if 1
10867 restore_gains(p);
10868#endif
10869 } else
10870 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
10871 } else {
10872 ast_log(LOG_WARNING, "Channel %s in prering "
10873 "state, but I have nothing to do. "
10874 "Terminating simple switch, should be "
10875 "restarted by the actual ring.\n",
10876 ast_channel_name(chan));
10877 ast_hangup(chan);
10878 goto quit;
10879 }
10880 } else if (p->use_callerid && p->cid_start == CID_START_RING) {
10881 if (p->cid_signalling == CID_SIG_DTMF) {
10882 int k = 0;
10883 int off_ms;
10884 struct timeval start;
10885 int ms;
10886 cs = NULL;
10887 dahdi_setlinear(p->subs[idx].dfd, 0);
10888 off_ms = 2000;
10889 start = ast_tvnow();
10890 for (;;) {
10891 struct ast_frame *f;
10892
10893 ms = ast_remaining_ms(start, off_ms);
10894 res = ast_waitfor(chan, ms);
10895 if (res <= 0) {
10896 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10897 "Exiting simple switch\n");
10898 ast_hangup(chan);
10899 goto quit;
10900 }
10901 f = ast_read(chan);
10902 if (!f) {
10903 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10904 ast_hangup(chan);
10905 goto quit;
10906 }
10907 if (f->frametype == AST_FRAME_DTMF) {
10908 dtmfbuf[k++] = f->subclass.integer;
10909 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10910 start = ast_tvnow();
10911 }
10912 ast_frfree(f);
10913
10914 if (p->ringt_base == p->ringt)
10915 break;
10916 }
10917 dtmfbuf[k] = '\0';
10918 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10919 /* Got cid and ring. */
10920 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10921 ast_debug(1, "CID is '%s', flags %d\n",
10922 dtmfcid, flags);
10923 /* If first byte is NULL, we have no cid */
10924 if (!ast_strlen_zero(dtmfcid))
10925 number = dtmfcid;
10926 else
10927 number = NULL;
10928 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10929 } else {
10930 /* FSK Bell202 callerID */
10932 if (cs) {
10933#if 1
10934 bump_gains(p);
10935#endif
10936 samples = 0;
10937 len = 0;
10938 distMatches = 0;
10939 /* Clear the current ring data array so we don't have old data in it. */
10940 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10941 curRingData[receivedRingT] = 0;
10942 receivedRingT = 0;
10943 counter = 0;
10944 counter1 = 0;
10945 /* Check to see if context is what it should be, if not set to be. */
10946 if (strcmp(p->context,p->defcontext) != 0) {
10947 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10949 }
10950
10951 /* Take out of linear mode for Caller*ID processing */
10952 dahdi_setlinear(p->subs[idx].dfd, 0);
10953 for (;;) {
10954 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10955 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10956 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10957 callerid_free(cs);
10958 ast_hangup(chan);
10959 goto quit;
10960 }
10961 if (i & DAHDI_IOMUX_SIGEVENT) {
10962 res = dahdi_get_event(p->subs[idx].dfd);
10963 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10964 if (res == DAHDI_EVENT_NOALARM) {
10965 p->inalarm = 0;
10966 }
10967 /* If we get a PR event, they hung up while processing calerid */
10968 if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
10969 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
10971 callerid_free(cs);
10972 ast_hangup(chan);
10973 goto quit;
10974 }
10975 res = 0;
10976 /* Let us detect callerid when the telco uses distinctive ring */
10977
10978 curRingData[receivedRingT] = p->ringt;
10979
10980 if (p->ringt < p->ringt_base/2)
10981 break;
10982 /* Increment the ringT counter so we can match it against
10983 values in chan_dahdi.conf for distinctive ring */
10984 if (++receivedRingT == ARRAY_LEN(curRingData))
10985 break;
10986 } else if (i & DAHDI_IOMUX_READ) {
10987 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10988 if (res < 0) {
10989 if (errno != ELAST) {
10990 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10991 callerid_free(cs);
10992 ast_hangup(chan);
10993 goto quit;
10994 }
10995 break;
10996 }
10997 if (p->ringt > 0) {
10998 if (!(--p->ringt)) {
10999 res = -1;
11000 break;
11001 }
11002 }
11003 samples += res;
11004 res = callerid_feed(cs, buf, res, AST_LAW(p));
11005 if (res < 0) {
11006 /*
11007 * The previous diagnostic message output likely
11008 * explains why it failed.
11009 */
11011 "Failed to decode CallerID on channel '%s'\n",
11012 ast_channel_name(chan));
11013 break;
11014 } else if (res)
11015 break;
11016 else if (samples > (8000 * 10))
11017 break;
11018 }
11019 }
11020 if (res == 1) {
11021 callerid_get(cs, &name, &number, &flags);
11022 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
11023 }
11024 if (distinctiveringaftercid == 1) {
11025 /* Clear the current ring data array so we don't have old data in it. */
11026 for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
11027 curRingData[receivedRingT] = 0;
11028 }
11029 receivedRingT = 0;
11030 ast_verb(3, "Detecting post-CID distinctive ring\n");
11031 for (;;) {
11032 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11033 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
11034 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11035 callerid_free(cs);
11036 ast_hangup(chan);
11037 goto quit;
11038 }
11039 if (i & DAHDI_IOMUX_SIGEVENT) {
11040 res = dahdi_get_event(p->subs[idx].dfd);
11041 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
11042 if (res == DAHDI_EVENT_NOALARM) {
11043 p->inalarm = 0;
11044 }
11045 res = 0;
11046 /* Let us detect callerid when the telco uses distinctive ring */
11047
11048 curRingData[receivedRingT] = p->ringt;
11049
11050 if (p->ringt < p->ringt_base/2)
11051 break;
11052 /* Increment the ringT counter so we can match it against
11053 values in chan_dahdi.conf for distinctive ring */
11054 if (++receivedRingT == ARRAY_LEN(curRingData))
11055 break;
11056 } else if (i & DAHDI_IOMUX_READ) {
11057 res = read(p->subs[idx].dfd, buf, sizeof(buf));
11058 if (res < 0) {
11059 if (errno != ELAST) {
11060 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11061 callerid_free(cs);
11062 ast_hangup(chan);
11063 goto quit;
11064 }
11065 break;
11066 }
11067 if (p->ringt > 0) {
11068 if (!(--p->ringt)) {
11069 res = -1;
11070 break;
11071 }
11072 }
11073 }
11074 }
11075 }
11077 /* this only shows up if you have n of the dring patterns filled in */
11078 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
11079
11080 for (counter = 0; counter < 3; counter++) {
11081 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
11082 channel */
11083 /* this only shows up if you have n of the dring patterns filled in */
11084 ast_verb(3, "Checking %d,%d,%d\n",
11085 p->drings.ringnum[counter].ring[0],
11086 p->drings.ringnum[counter].ring[1],
11087 p->drings.ringnum[counter].ring[2]);
11088 distMatches = 0;
11089 for (counter1 = 0; counter1 < 3; counter1++) {
11090 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
11091 if (p->drings.ringnum[counter].ring[counter1] == -1) {
11092 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
11093 curRingData[counter1]);
11094 distMatches++;
11095 }
11096 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
11097 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
11098 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
11099 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
11100 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
11101 distMatches++;
11102 }
11103 }
11104 if (distMatches == 3) {
11105 /* The ring matches, set the context to whatever is for distinctive ring.. */
11106 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
11108 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
11109 break;
11110 }
11111 }
11112 }
11113 /* Restore linear mode (if appropriate) for Caller*ID processing */
11114 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
11115#if 1
11116 restore_gains(p);
11117#endif
11118 if (res < 0) {
11119 ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
11120 }
11121 } else
11122 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
11123 }
11124 } else
11125 cs = NULL;
11126
11127 if (number)
11130
11131 ao2_cleanup(smdi_msg);
11132
11133 if (cs)
11134 callerid_free(cs);
11135
11136 my_handle_notify_message(chan, p, flags, -1);
11137
11138 ast_channel_lock(chan);
11140 ast_channel_rings_set(chan, 1);
11141 ast_channel_unlock(chan);
11142 p->ringt = p->ringt_base;
11143 res = ast_pbx_run(chan);
11144 if (res) {
11145 ast_hangup(chan);
11146 ast_log(LOG_WARNING, "PBX exited non-zero\n");
11147 }
11148 goto quit;
11149 default:
11150 ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
11151 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11152 if (res < 0)
11153 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11154 }
11155 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11156 if (res < 0)
11157 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11158 ast_hangup(chan);
11159quit:
11164 return NULL;
11165}
11166
11169 unsigned char buf[READ_SIZE];
11170 size_t len;
11171};
11172
11173static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
11174{
11175 int x;
11176 int sum = 0;
11177
11178 if (!len)
11179 return 0;
11180
11181 for (x = 0; x < len; x++)
11182 sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
11183
11184 return sum / len;
11185}
11186
11187static void *mwi_thread(void *data)
11188{
11189 struct mwi_thread_data *mtd = data;
11190 struct callerid_state *cs;
11191 pthread_t threadid;
11192 int samples = 0;
11193 char *name, *number;
11194 int flags;
11195 int i, res;
11196 unsigned int spill_done = 0;
11197 int spill_result = -1;
11198
11199 if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
11200 goto quit_no_clean;
11201 }
11202
11203 callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
11204
11205 bump_gains(mtd->pvt);
11206
11207 for (;;) {
11208 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11209 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
11210 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11211 goto quit;
11212 }
11213
11214 if (i & DAHDI_IOMUX_SIGEVENT) {
11215 struct ast_channel *chan;
11216 ast_callid callid = 0;
11217 int callid_created;
11218
11219 /* If we get an event, screen out events that we do not act on.
11220 * Otherwise, cancel and go to the simple switch to let it deal with it.
11221 */
11222 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
11223
11224 switch (res) {
11225 case DAHDI_EVENT_NEONMWI_ACTIVE:
11226 case DAHDI_EVENT_NEONMWI_INACTIVE:
11227 case DAHDI_EVENT_NONE:
11228 case DAHDI_EVENT_BITSCHANGED:
11229 break;
11230 case DAHDI_EVENT_NOALARM:
11231 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11232 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11233
11234 analog_p->inalarm = 0;
11235 }
11236 mtd->pvt->inalarm = 0;
11238 break;
11239 case DAHDI_EVENT_ALARM:
11240 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11241 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11242
11243 analog_p->inalarm = 1;
11244 }
11245 mtd->pvt->inalarm = 1;
11246 res = get_alarms(mtd->pvt);
11247 handle_alarms(mtd->pvt, res);
11248 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11249 default:
11250 callid_created = ast_callid_threadstorage_auto(&callid);
11251 ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to analog_ss_thread\n", res, event2str(res));
11252 callerid_free(cs);
11253
11254 restore_gains(mtd->pvt);
11255 mtd->pvt->ringt = mtd->pvt->ringt_base;
11256
11257 if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid))) {
11258 int result;
11259
11260 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11262 } else {
11264 }
11265 if (result) {
11266 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
11267 res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11268 if (res < 0)
11269 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
11270 ast_hangup(chan);
11271 }
11272 } else {
11273 ast_log(LOG_WARNING, "Could not create channel to handle call\n");
11274 }
11275
11276 ast_callid_threadstorage_auto_clean(callid, callid_created);
11277 goto quit_no_clean;
11278 }
11279 } else if (i & DAHDI_IOMUX_READ) {
11280 if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
11281 if (errno != ELAST) {
11282 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11283 goto quit;
11284 }
11285 break;
11286 }
11287 samples += res;
11288 if (!spill_done) {
11289 if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
11290 /*
11291 * The previous diagnostic message output likely
11292 * explains why it failed.
11293 */
11294 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
11295 break;
11296 } else if (spill_result) {
11297 spill_done = 1;
11298 }
11299 } else {
11300 /* keep reading data until the energy level drops below the threshold
11301 so we don't get another 'trigger' on the remaining carrier signal
11302 */
11303 if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
11304 break;
11305 }
11306 if (samples > (8000 * 4)) /*Termination case - time to give up*/
11307 break;
11308 }
11309 }
11310
11311 if (spill_result == 1) {
11312 callerid_get(cs, &name, &number, &flags);
11313 if (flags & CID_MSGWAITING) {
11314 ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
11315 notify_message(mtd->pvt->mailbox, 1);
11316 } else if (flags & CID_NOMSGWAITING) {
11317 ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
11318 notify_message(mtd->pvt->mailbox, 0);
11319 } else {
11320 ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
11321 }
11322 }
11323
11324
11325quit:
11326 callerid_free(cs);
11327
11328 restore_gains(mtd->pvt);
11329
11330quit_no_clean:
11331 mtd->pvt->mwimonitoractive = 0;
11332 ast_free(mtd);
11333
11334 return NULL;
11335}
11336
11337/*
11338* The following three functions (mwi_send_init, mwi_send_process_buffer,
11339* mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11340* that are sent out via FXS port on voicemail state change. The execution of
11341* the mwi send is state driven and can either generate a ring pulse prior to
11342* sending the fsk spill or simply send an fsk spill.
11343*/
11344static int mwi_send_init(struct dahdi_pvt * pvt)
11345{
11346 int x;
11347
11348#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11349 /* Determine how this spill is to be sent */
11350 if (pvt->mwisend_rpas) {
11352 pvt->mwisendactive = 1;
11353 } else if (pvt->mwisend_fsk) {
11355 pvt->mwisendactive = 1;
11356 } else {
11357 pvt->mwisendactive = 0;
11358 return 0;
11359 }
11360#else
11361 if (mwisend_rpas) {
11363 } else {
11365 }
11366 pvt->mwisendactive = 1;
11367#endif
11368
11369 if (pvt->cidspill) {
11370 ast_log(LOG_WARNING, "cidspill already exists when trying to send FSK MWI\n");
11371 ast_free(pvt->cidspill);
11372 pvt->cidspill = NULL;
11373 pvt->cidpos = 0;
11374 pvt->cidlen = 0;
11375 }
11377 if (!pvt->cidspill) {
11378 pvt->mwisendactive = 0;
11379 return -1;
11380 }
11381 x = DAHDI_FLUSH_BOTH;
11382 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
11383 x = 3000;
11384 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
11385#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11386 if (pvt->mwisend_fsk) {
11387#endif
11389 CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
11390 pvt->cidpos = 0;
11391#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11392 }
11393#endif
11394 return 0;
11395}
11396
11397static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
11398{
11399 struct timeval now;
11400 int res;
11401
11402 /* sanity check to catch if this had been interrupted previously
11403 * i.e. state says there is more to do but there is no spill allocated
11404 */
11405 if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) {
11407 } else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
11408 /* Normal processing -- Perform mwi send action */
11409 switch ( pvt->mwisend_data.mwisend_current) {
11410 case MWI_SEND_SA:
11411 /* Send the Ring Pulse Signal Alert */
11412 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
11413 if (res) {
11414 ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
11415 goto quit;
11416 }
11417 res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING);
11419 break;
11420 case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */
11421 break;
11422 case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/
11423#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11424 if (pvt->mwisend_fsk) {
11425#endif
11426 gettimeofday(&now, NULL);
11427 if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) {
11429 }
11430#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11431 } else { /* support for mwisendtype=nofsk */
11433 }
11434#endif
11435 break;
11436 case MWI_SEND_SPILL:
11437 /* We read some number of bytes. Write an equal amount of data */
11438 if (0 < num_read) {
11439 if (num_read > pvt->cidlen - pvt->cidpos) {
11440 num_read = pvt->cidlen - pvt->cidpos;
11441 }
11442 res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
11443 if (res > 0) {
11444 pvt->cidpos += res;
11445 if (pvt->cidpos >= pvt->cidlen) {
11447 }
11448 } else {
11449 ast_log(LOG_WARNING, "MWI FSK Send Write failed: %s\n", strerror(errno));
11450 goto quit;
11451 }
11452 }
11453 break;
11454 case MWI_SEND_CLEANUP:
11455 /* For now, do nothing */
11457 break;
11458 default:
11459 /* Should not get here, punt*/
11460 goto quit;
11461 }
11462 }
11463
11465 if (pvt->cidspill) {
11466 ast_free(pvt->cidspill);
11467 pvt->cidspill = NULL;
11468 pvt->cidpos = 0;
11469 pvt->cidlen = 0;
11470 }
11471 pvt->mwisendactive = 0;
11472 }
11473 return 0;
11474quit:
11475 if (pvt->cidspill) {
11476 ast_free(pvt->cidspill);
11477 pvt->cidspill = NULL;
11478 pvt->cidpos = 0;
11479 pvt->cidlen = 0;
11480 }
11481 pvt->mwisendactive = 0;
11482 return -1;
11483}
11484
11485static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
11486{
11487 int handled = 0;
11488
11490 switch (event) {
11491 case DAHDI_EVENT_RINGEROFF:
11493 handled = 1;
11494
11495 if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
11496 ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
11497 ast_free(pvt->cidspill);
11498 pvt->cidspill = NULL;
11500 pvt->mwisendactive = 0;
11501 } else {
11503 gettimeofday(&pvt->mwisend_data.pause, NULL);
11504 }
11505 }
11506 break;
11507 /* Going off hook, I need to punt this spill */
11508 case DAHDI_EVENT_RINGOFFHOOK:
11509 if (pvt->cidspill) {
11510 ast_free(pvt->cidspill);
11511 pvt->cidspill = NULL;
11512 pvt->cidpos = 0;
11513 pvt->cidlen = 0;
11514 }
11516 pvt->mwisendactive = 0;
11517 break;
11518 case DAHDI_EVENT_RINGERON:
11519 case DAHDI_EVENT_HOOKCOMPLETE:
11520 break;
11521 default:
11522 break;
11523 }
11524 }
11525 return handled;
11526}
11527
11528/* destroy a range DAHDI channels, identified by their number */
11529static void dahdi_destroy_channel_range(int start, int end)
11530{
11531 struct dahdi_pvt *cur;
11532 struct dahdi_pvt *next;
11533 int destroyed_first = 0;
11534 int destroyed_last = 0;
11535
11537 ast_debug(1, "range: %d-%d\n", start, end);
11538 for (cur = iflist; cur; cur = next) {
11539 next = cur->next;
11540 if (cur->channel >= start && cur->channel <= end) {
11541 int x = DAHDI_FLASH;
11542
11543 if (cur->channel > destroyed_last) {
11544 destroyed_last = cur->channel;
11545 }
11546 if (destroyed_first < 1 || cur->channel < destroyed_first) {
11547 destroyed_first = cur->channel;
11548 }
11549 ast_debug(3, "Destroying %d\n", cur->channel);
11550 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11551 ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11552
11553 destroy_channel(cur, 1);
11555 }
11556 }
11558 if (destroyed_first > start || destroyed_last < end) {
11559 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11560 start, end, destroyed_first, destroyed_last);
11561 }
11562}
11563
11564#ifdef HAVE_OPENR2
11565static void dahdi_r2_destroy_nodev(void)
11566{
11567 struct r2link_entry *cur;
11568 AST_LIST_LOCK(&nodev_r2links);
11569 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
11570 int i;
11571 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
11572 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
11573 for (i = 0; i < r2->numchans; i++) {
11574 int channel;
11575 struct dahdi_pvt *pvt = r2->pvts[i];
11576 if (!pvt) {
11577 continue;
11578 }
11579 channel = pvt->channel;
11580 ast_debug(3, "About to destroy B-channel %d.\n", channel);
11582 }
11583 ast_debug(3, "Destroying R2 link\n");
11584 AST_LIST_REMOVE(&nodev_r2links, cur, list);
11585 if (r2->r2master != AST_PTHREADT_NULL) {
11586 pthread_cancel(r2->r2master);
11587 pthread_join(r2->r2master, NULL);
11588 r2->r2master = AST_PTHREADT_NULL;
11589 openr2_context_delete(r2->protocol_context);
11590 }
11591 ast_free(cur);
11592 }
11594 AST_LIST_UNLOCK(&nodev_r2links);
11595}
11596#endif
11597
11598static int setup_dahdi(int reload);
11599static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
11600
11601/*!
11602 * \internal
11603 * \brief create a range of new DAHDI channels
11604 *
11605 * \param start first channel in the range
11606 * \param end last channel in the range
11607 *
11608 * \retval RESULT_SUCCESS on success.
11609 * \retval RESULT_FAILURE on error.
11610 */
11611static int dahdi_create_channel_range(int start, int end)
11612{
11613 struct dahdi_pvt *cur;
11614 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
11615 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
11617 int ret = RESULT_FAILURE; /* be pessimistic */
11618
11619 ast_debug(1, "channel range caps: %d - %d\n", start, end);
11621 for (cur = iflist; cur; cur = cur->next) {
11622 if (cur->channel >= start && cur->channel <= end) {
11624 "channel range %d-%d is occupied\n",
11625 start, end);
11626 goto out;
11627 }
11628 }
11629#ifdef HAVE_PRI
11630 {
11631 int i, x;
11632 for (x = 0; x < NUM_SPANS; x++) {
11633 struct dahdi_pri *pri = pris + x;
11634
11635 if (!pris[x].pri.pvts[0]) {
11636 break;
11637 }
11638 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
11639 int channo = pri->dchannels[i];
11640
11641 if (!channo) {
11642 break;
11643 }
11644 if (!pri->pri.fds[i]) {
11645 break;
11646 }
11647 if (channo >= start && channo <= end) {
11649 "channel range %d-%d is occupied by span %d\n",
11650 start, end, x + 1);
11651 goto out;
11652 }
11653 }
11654 }
11655 }
11656#endif
11657 if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
11658 !conf.chan.cc_params) {
11659 goto out;
11660 }
11661 default_conf.wanted_channels_start = start;
11662 base_conf.wanted_channels_start = start;
11663 conf.wanted_channels_start = start;
11664 default_conf.wanted_channels_end = end;
11665 base_conf.wanted_channels_end = end;
11666 conf.wanted_channels_end = end;
11667 if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
11668 ret = RESULT_SUCCESS;
11669 }
11670out:
11673 ast_cc_config_params_destroy(conf.chan.cc_params);
11675 return ret;
11676}
11677
11678
11679static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
11680{
11681 int res;
11682 pthread_t threadid;
11683 struct ast_channel *chan;
11684 ast_callid callid = 0;
11685 int callid_created;
11686
11687 /* Handle an event on a given channel for the monitor thread. */
11688
11689 switch (event) {
11690 case DAHDI_EVENT_NONE:
11691 case DAHDI_EVENT_BITSCHANGED:
11692 break;
11693 case DAHDI_EVENT_WINKFLASH:
11694 case DAHDI_EVENT_RINGOFFHOOK:
11695 if (i->inalarm) break;
11696 if (i->radio) break;
11697 /* Got a ring/answer. What kind of channel are we? */
11698 switch (i->sig) {
11699 case SIG_FXOLS:
11700 case SIG_FXOGS:
11701 case SIG_FXOKS:
11702 res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11703 if (res && (errno == EBUSY)) {
11704 break;
11705 }
11706
11707 callid_created = ast_callid_threadstorage_auto(&callid);
11708
11709 /* Cancel VMWI spill */
11710 ast_free(i->cidspill);
11711 i->cidspill = NULL;
11713
11714 if (i->immediate) {
11715 dahdi_ec_enable(i);
11716 /* The channel is immediately up. Start right away */
11717 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
11718 chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, NULL, callid);
11719 if (!chan) {
11720 ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
11721 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11722 if (res < 0)
11723 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11724 }
11725 } else {
11726 /* Check for callerid, digits, etc */
11727 chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, NULL, callid);
11728 if (chan) {
11729 if (has_voicemail(i))
11730 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
11731 else
11732 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
11733 if (res < 0)
11734 ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
11735 if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11736 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11737 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11738 if (res < 0)
11739 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11740 ast_hangup(chan);
11741 }
11742 } else
11743 ast_log(LOG_WARNING, "Unable to create channel\n");
11744 }
11745
11747 break;
11748 case SIG_FXSLS:
11749 case SIG_FXSGS:
11750 case SIG_FXSKS:
11751 i->ringt = i->ringt_base;
11752 /* Fall through */
11753 case SIG_EMWINK:
11754 case SIG_FEATD:
11755 case SIG_FEATDMF:
11756 case SIG_FEATDMF_TA:
11757 case SIG_E911:
11758 case SIG_FGC_CAMA:
11759 case SIG_FGC_CAMAMF:
11760 case SIG_FEATB:
11761 case SIG_EM:
11762 case SIG_EM_E1:
11763 case SIG_SFWINK:
11764 case SIG_SF_FEATD:
11765 case SIG_SF_FEATDMF:
11766 case SIG_SF_FEATB:
11767 case SIG_SF:
11768 /* Check for callerid, digits, etc */
11769 callid_created = ast_callid_threadstorage_auto(&callid);
11770 if (i->cid_start == CID_START_POLARITY_IN) {
11771 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11772 } else {
11773 chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid);
11774 }
11775
11776 if (!chan) {
11777 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11778 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11779 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11780 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11781 if (res < 0) {
11782 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11783 }
11784 ast_hangup(chan);
11785 }
11786
11788 break;
11789 default:
11790 ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11791 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11792 if (res < 0)
11793 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11794 return NULL;
11795 }
11796 break;
11797 case DAHDI_EVENT_NOALARM:
11798 switch (i->sig) {
11799#if defined(HAVE_PRI)
11801 ast_mutex_lock(&i->lock);
11804 break;
11805#endif /* defined(HAVE_PRI) */
11806#if defined(HAVE_SS7)
11807 case SIG_SS7:
11809 break;
11810#endif /* defined(HAVE_SS7) */
11811 default:
11812 i->inalarm = 0;
11813 break;
11814 }
11816 break;
11817 case DAHDI_EVENT_ALARM:
11818 switch (i->sig) {
11819#if defined(HAVE_PRI)
11821 ast_mutex_lock(&i->lock);
11824 break;
11825#endif /* defined(HAVE_PRI) */
11826#if defined(HAVE_SS7)
11827 case SIG_SS7:
11829 break;
11830#endif /* defined(HAVE_SS7) */
11831 default:
11832 i->inalarm = 1;
11833 break;
11834 }
11835 res = get_alarms(i);
11836 handle_alarms(i, res);
11837 /* fall thru intentionally */
11838 case DAHDI_EVENT_ONHOOK:
11839 if (i->radio)
11840 break;
11841 /* Back on hook. Hang up. */
11842 switch (i->sig) {
11843 case SIG_FXOLS:
11844 case SIG_FXOGS:
11845 case SIG_FEATD:
11846 case SIG_FEATDMF:
11847 case SIG_FEATDMF_TA:
11848 case SIG_E911:
11849 case SIG_FGC_CAMA:
11850 case SIG_FGC_CAMAMF:
11851 case SIG_FEATB:
11852 case SIG_EM:
11853 case SIG_EM_E1:
11854 case SIG_EMWINK:
11855 case SIG_SF_FEATD:
11856 case SIG_SF_FEATDMF:
11857 case SIG_SF_FEATB:
11858 case SIG_SF:
11859 case SIG_SFWINK:
11860 case SIG_FXSLS:
11861 case SIG_FXSGS:
11862 case SIG_FXSKS:
11863 case SIG_FXOKS:
11865 /* Diddle the battery for the zhone */
11866#ifdef ZHONE_HACK
11867 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11868 usleep(1);
11869#endif
11870 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11871 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
11872 break;
11873 case SIG_SS7:
11876 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11877 break;
11878 default:
11879 ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11880 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11881 return NULL;
11882 }
11883 break;
11884 case DAHDI_EVENT_POLARITY:
11885 switch (i->sig) {
11886 case SIG_FXSLS:
11887 case SIG_FXSKS:
11888 case SIG_FXSGS:
11889 /* We have already got a PR before the channel was
11890 created, but it wasn't handled. We need polarity
11891 to be REV for remote hangup detection to work.
11892 At least in Spain */
11893 callid_created = ast_callid_threadstorage_auto(&callid);
11898 ast_verb(2, "Starting post polarity "
11899 "CID detection on channel %d\n",
11900 i->channel);
11901 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11902 if (!chan) {
11903 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11904 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11905 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11906 ast_hangup(chan);
11907 }
11908 }
11910 break;
11911 default:
11912 ast_log(LOG_WARNING, "handle_init_event detected "
11913 "polarity reversal on non-FXO (SIG_FXS) "
11914 "interface %d\n", i->channel);
11915 }
11916 break;
11917 case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
11919 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11920 i->channel);
11921 return i;
11922 case DAHDI_EVENT_NEONMWI_ACTIVE:
11923 if (i->mwimonitor_neon) {
11924 notify_message(i->mailbox, 1);
11925 ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
11926 }
11927 break;
11928 case DAHDI_EVENT_NEONMWI_INACTIVE:
11929 if (i->mwimonitor_neon) {
11930 notify_message(i->mailbox, 0);
11931 ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
11932 }
11933 break;
11934 }
11935 return NULL;
11936}
11937
11938static void monitor_pfds_clean(void *arg) {
11939 struct pollfd **pfds = arg;
11940 ast_free(*pfds);
11941}
11942
11943static void *do_monitor(void *data)
11944{
11945 int count, res, res2, spoint, pollres=0;
11946 struct dahdi_pvt *i;
11947 struct dahdi_pvt *last = NULL;
11948 struct dahdi_pvt *doomed;
11949 time_t thispass = 0, lastpass = 0;
11950 int found;
11951 char buf[1024];
11952 struct pollfd *pfds=NULL;
11953 int lastalloc = -1;
11954 /* This thread monitors all the frame relay interfaces which are not yet in use
11955 (and thus do not have a separate thread) indefinitely */
11956 /* From here on out, we die whenever asked */
11957#if 0
11958 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
11959 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
11960 return NULL;
11961 }
11962 ast_debug(1, "Monitor starting...\n");
11963#endif
11964 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11965
11966 pthread_cleanup_push(monitor_pfds_clean, &pfds);
11967 for (;;) {
11968 /* Lock the interface list */
11970 if (!pfds || (lastalloc != ifcount)) {
11971 if (pfds) {
11972 ast_free(pfds);
11973 pfds = NULL;
11974 }
11975 if (ifcount) {
11976 if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
11978 return NULL;
11979 }
11980 }
11981 lastalloc = ifcount;
11982 }
11983 /* Build the stuff we're going to poll on, that is the socket of every
11984 dahdi_pvt that does not have an associated owner channel */
11985 count = 0;
11986 for (i = iflist; i; i = i->next) {
11987 ast_mutex_lock(&i->lock);
11988 if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
11989 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
11990 struct analog_pvt *p = i->sig_pvt;
11991
11992 if (!p) {
11993 ast_log(LOG_ERROR, "No sig_pvt?\n");
11994 } else if (!p->owner && !p->subs[SUB_REAL].owner) {
11995 /* This needs to be watched, as it lacks an owner */
11996 pfds[count].fd = i->subs[SUB_REAL].dfd;
11997 pfds[count].events = POLLPRI;
11998 pfds[count].revents = 0;
11999 /* Message waiting or r2 channels also get watched for reading */
12000 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12001 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12002 pfds[count].events |= POLLIN;
12003 }
12004 count++;
12005 }
12006 } else {
12007 if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
12008 /* This needs to be watched, as it lacks an owner */
12009 pfds[count].fd = i->subs[SUB_REAL].dfd;
12010 pfds[count].events = POLLPRI;
12011 pfds[count].revents = 0;
12012 /* If we are monitoring for VMWI or sending CID, we need to
12013 read from the channel as well */
12014 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12015 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12016 pfds[count].events |= POLLIN;
12017 }
12018 count++;
12019 }
12020 }
12021 }
12023 }
12024 /* Okay, now that we know what to do, release the interface lock */
12026
12027 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
12028 pthread_testcancel();
12029 /* Wait at least a second for something to happen */
12030 res = poll(pfds, count, 1000);
12031 pthread_testcancel();
12032 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
12033
12034 /* Okay, poll has finished. Let's see what happened. */
12035 if (res < 0) {
12036 if ((errno != EAGAIN) && (errno != EINTR))
12037 ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
12038 continue;
12039 }
12040 /* Alright, lock the interface list again, and let's look and see what has
12041 happened */
12043 found = 0;
12044 spoint = 0;
12045 lastpass = thispass;
12046 thispass = time(NULL);
12047 doomed = NULL;
12048 for (i = iflist;; i = i->next) {
12049 if (doomed) {
12051 doomed = NULL;
12052 }
12053 if (!i) {
12054 break;
12055 }
12056
12057 if (thispass != lastpass) {
12058 if (!found && ((i == last) || ((i == iflist) && !last))) {
12059 last = i;
12060 if (last) {
12061 struct analog_pvt *analog_p = last->sig_pvt;
12062 /* Only allow MWI to be initiated on a quiescent fxs port */
12063 if (analog_p
12064 && !last->mwisendactive
12065 && (last->sig & __DAHDI_SIG_FXO)
12066 && !analog_p->fxsoffhookstate
12067 && !last->owner
12068 && (!ast_strlen_zero(last->mailbox) || last->mwioverride_active)
12069 && !analog_p->subs[SUB_REAL].owner /* could be a recall ring from a flash hook hold */
12070 && (thispass - analog_p->onhooktime > 3)
12071 /* In some cases, all of the above checks will pass even if the line is really off-hook.
12072 * This last check will give the right answer 100% of the time, but is relatively
12073 * "expensive" (it requires an ioctl), so it is last to avoid unnecessary system calls. */
12074 && !my_is_off_hook(last)) {
12075 res = has_voicemail(last);
12076 if (analog_p->msgstate != res) {
12077 /* Set driver resources for signalling VMWI */
12078 res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
12079 if (res2) {
12080 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
12081 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
12082 }
12083 /* If enabled for FSK spill then initiate it */
12084 ast_debug(5, "Initiating MWI FSK spill on channel %d\n", last->channel);
12085 if (mwi_send_init(last)) {
12086 ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
12087 }
12088 analog_p->msgstate = res;
12089 found ++;
12090 }
12091 }
12092 last = last->next;
12093 }
12094 }
12095 }
12096 if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
12097 if (i->radio && !i->owner)
12098 {
12099 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12100 if (res)
12101 {
12102 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
12103 /* Don't hold iflock while handling init events */
12105 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12107 else
12108 doomed = handle_init_event(i, res);
12110 }
12111 continue;
12112 }
12113 pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
12114 if (pollres & POLLIN) {
12115 if (i->owner || i->subs[SUB_REAL].owner) {
12116#ifdef HAVE_PRI
12117 if (!i->pri)
12118#endif
12119 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
12120 continue;
12121 }
12123 ast_log(LOG_WARNING, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
12124 continue;
12125 }
12126 res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
12127 if (res > 0) {
12128 if (i->mwimonitor_fsk) {
12129 if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
12130 pthread_attr_t attr;
12131 pthread_t threadid;
12132 struct mwi_thread_data *mtd;
12133
12134 pthread_attr_init(&attr);
12135 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
12136
12137 ast_debug(1, "Maybe some MWI on port %d!\n", i->channel);
12138 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
12139 mtd->pvt = i;
12140 memcpy(mtd->buf, buf, res);
12141 mtd->len = res;
12142 i->mwimonitoractive = 1;
12143 if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
12144 ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
12145 i->mwimonitoractive = 0;
12146 ast_free(mtd);
12147 }
12148 }
12149 }
12150 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
12151 } else if (i->cid_start == CID_START_DTMF_NOALERT) {
12152 int energy;
12153 struct timeval now;
12154 /* State machine dtmfcid_holdoff_state allows for the line to settle
12155 * before checking again for dtmf energy. Presently waits for 500 mS before checking again
12156 */
12157 if (1 == i->dtmfcid_holdoff_state) {
12158 gettimeofday(&i->dtmfcid_delay, NULL);
12159 i->dtmfcid_holdoff_state = 2;
12160 } else if (2 == i->dtmfcid_holdoff_state) {
12161 gettimeofday(&now, NULL);
12162 if ((int)(now.tv_sec - i->dtmfcid_delay.tv_sec) * 1000000 + (int)now.tv_usec - (int)i->dtmfcid_delay.tv_usec > 500000) {
12163 i->dtmfcid_holdoff_state = 0;
12164 }
12165 } else {
12166 energy = calc_energy((unsigned char *) buf, res, AST_LAW(i));
12167 if (!i->mwisendactive && energy > dtmfcid_level) {
12168 pthread_t threadid;
12169 struct ast_channel *chan;
12171 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12172 /* just in case this event changes or somehow destroys a channel, set doomed here too */
12174 i->dtmfcid_holdoff_state = 1;
12175 } else {
12176 ast_callid callid = 0;
12177 int callid_created = ast_callid_threadstorage_auto(&callid);
12178 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
12179 if (!chan) {
12180 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
12181 } else {
12182 res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
12183 if (res) {
12184 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
12185 ast_hangup(chan);
12186 } else {
12187 i->dtmfcid_holdoff_state = 1;
12188 }
12189 }
12191 }
12193 }
12194 }
12195 }
12196 if (i->mwisendactive) {
12198 }
12199 } else {
12200 ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
12201 }
12202 }
12203 if (pollres & POLLPRI) {
12204 if (i->owner || i->subs[SUB_REAL].owner) {
12205#ifdef HAVE_PRI
12206 if (!i->pri)
12207#endif
12208 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
12209 continue;
12210 }
12211 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12212 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
12213 /* Don't hold iflock while handling init events */
12215 if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
12216 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12218 else
12219 doomed = handle_init_event(i, res);
12220 }
12221 if (i->doreoriginate && res == DAHDI_EVENT_HOOKCOMPLETE) {
12222 /* Actually automatically reoriginate this FXS line, if directed to.
12223 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12224 * doing its thing (one reason why this is for FXOKS only: FXOLS
12225 * hangups don't give us any DAHDI events to piggyback off of)*/
12226 i->doreoriginate = 0;
12227 /* Double check the channel is still off-hook. There's only about a millisecond
12228 * between when doreoriginate is set high and we see that here, but just to be safe. */
12229 if (!my_is_off_hook(i)) {
12230 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i->channel);
12231 } else {
12232 ast_verb(3, "Automatic reorigination on channel %d\n", i->channel);
12233 res = DAHDI_EVENT_RINGOFFHOOK; /* Pretend that the physical channel just went off hook */
12234 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12236 } else {
12237 doomed = handle_init_event(i, res);
12238 }
12239 }
12240 }
12242 }
12243 }
12244 }
12247#ifdef HAVE_OPENR2
12248 dahdi_r2_destroy_nodev();
12249#endif
12250 }
12251 /* Never reached */
12252 pthread_cleanup_pop(1);
12253 return NULL;
12254
12255}
12256
12257static int restart_monitor(void)
12258{
12259 /* If we're supposed to be stopped -- stay stopped */
12261 return 0;
12263 if (monitor_thread == pthread_self()) {
12265 ast_log(LOG_WARNING, "Cannot kill myself\n");
12266 return -1;
12267 }
12269 /* Wake up the thread */
12270 pthread_kill(monitor_thread, SIGURG);
12271 } else {
12272 /* Start a new monitor */
12275 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
12276 return -1;
12277 }
12278 }
12280 return 0;
12281}
12282
12283#if defined(HAVE_PRI)
12284static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
12285{
12286 int x;
12287 int trunkgroup;
12288 /* Get appropriate trunk group if there is one */
12289 trunkgroup = pris[*span].mastertrunkgroup;
12290 if (trunkgroup) {
12291 /* Select a specific trunk group */
12292 for (x = 0; x < NUM_SPANS; x++) {
12293 if (pris[x].pri.trunkgroup == trunkgroup) {
12294 *span = x;
12295 return 0;
12296 }
12297 }
12298 ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
12299 *span = -1;
12300 } else {
12301 if (pris[*span].pri.trunkgroup) {
12302 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);
12303 *span = -1;
12304 } else if (pris[*span].mastertrunkgroup) {
12305 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
12306 *span = -1;
12307 } else {
12308 if (si->totalchans == 31) {
12309 /* E1 */
12310 pris[*span].dchannels[0] = 16 + offset;
12311 } else if (si->totalchans == 24) {
12312 /* T1 or J1 */
12313 pris[*span].dchannels[0] = 24 + offset;
12314 } else if (si->totalchans == 3) {
12315 /* BRI */
12316 pris[*span].dchannels[0] = 3 + offset;
12317 } else {
12318 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);
12319 *span = -1;
12320 return 0;
12321 }
12322 pris[*span].pri.span = *span + 1;
12323 }
12324 }
12325 return 0;
12326}
12327#endif /* defined(HAVE_PRI) */
12328
12329#if defined(HAVE_PRI)
12330static int pri_create_trunkgroup(int trunkgroup, int *channels)
12331{
12332 struct dahdi_spaninfo si;
12333 struct dahdi_params p;
12334 int fd;
12335 int span;
12336 int ospan=0;
12337 int x,y;
12338 for (x = 0; x < NUM_SPANS; x++) {
12339 if (pris[x].pri.trunkgroup == trunkgroup) {
12340 ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
12341 return -1;
12342 }
12343 }
12344 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12345 if (!channels[y])
12346 break;
12347 memset(&si, 0, sizeof(si));
12348 memset(&p, 0, sizeof(p));
12349 fd = open("/dev/dahdi/channel", O_RDWR);
12350 if (fd < 0) {
12351 ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
12352 return -1;
12353 }
12354 x = channels[y];
12355 if (ioctl(fd, DAHDI_SPECIFY, &x)) {
12356 ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
12357 close(fd);
12358 return -1;
12359 }
12360 if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
12361 ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
12362 close(fd);
12363 return -1;
12364 }
12365 if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
12366 ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
12367 close(fd);
12368 return -1;
12369 }
12370 span = p.spanno - 1;
12371 if (pris[span].pri.trunkgroup) {
12372 ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].pri.trunkgroup);
12373 close(fd);
12374 return -1;
12375 }
12376 if (pris[span].pri.pvts[0]) {
12377 ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
12378 close(fd);
12379 return -1;
12380 }
12381 if (!y) {
12382 pris[span].pri.trunkgroup = trunkgroup;
12383 ospan = span;
12384 }
12385 pris[ospan].dchannels[y] = channels[y];
12386 pris[span].pri.span = span + 1;
12387 close(fd);
12388 }
12389 return 0;
12390}
12391#endif /* defined(HAVE_PRI) */
12392
12393#if defined(HAVE_PRI)
12394static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
12395{
12396 if (pris[span].mastertrunkgroup) {
12397 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);
12398 return -1;
12399 }
12400 pris[span].mastertrunkgroup = trunkgroup;
12401 pris[span].prilogicalspan = logicalspan;
12402 return 0;
12403}
12404#endif /* defined(HAVE_PRI) */
12405
12406#if defined(HAVE_SS7)
12407static unsigned int parse_pointcode(const char *pcstring)
12408{
12409 unsigned int code1, code2, code3;
12410 int numvals;
12411
12412 numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
12413 if (numvals == 1)
12414 return code1;
12415 if (numvals == 3)
12416 return (code1 << 16) | (code2 << 8) | code3;
12417
12418 return 0;
12419}
12420#endif /* defined(HAVE_SS7) */
12421
12422#if defined(HAVE_SS7)
12423static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
12424{
12425 if ((linkset < 0) || (linkset >= NUM_SPANS))
12426 return NULL;
12427 else
12428 return &linksets[linkset - 1];
12429}
12430#endif /* defined(HAVE_SS7) */
12431
12432#ifdef HAVE_OPENR2
12433static void dahdi_r2_destroy_links(void)
12434{
12435 struct r2link_entry *cur;
12436
12437 /* Queue everything for removal */
12438 AST_LIST_LOCK(&r2links);
12439 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
12440 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
12441 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
12442 }
12444 AST_LIST_UNLOCK(&r2links);
12445 /* Now destroy properly */
12446 dahdi_r2_destroy_nodev();
12447}
12448
12449/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12450#define R2_LINK_CAPACITY 30
12451static struct r2link_entry *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
12452{
12453 struct r2link_entry *cur = NULL;
12454 /* Only create a new R2 link if
12455 1. This is the first link requested
12456 2. Configuration changed
12457 3. We got more channels than supported per link */
12458 AST_LIST_LOCK(&r2links);
12459 if (! AST_LIST_EMPTY(&r2links)) {
12460 cur = AST_LIST_LAST(&r2links);
12461 if (memcmp(&conf->mfcr2, &cur->mfcr2.conf, sizeof(conf->mfcr2))) {
12462 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12463 cur = NULL;
12464 } else if (cur->mfcr2.numchans == R2_LINK_CAPACITY) {
12465 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY);
12466 cur = NULL;
12467 }
12468 }
12469 if (!cur) {
12470 struct r2link_entry *tmp = NULL;
12471 int new_idx = r2links_count + 1;
12472 int i;
12473 for (i = 1; i <= r2links_count; i++) {
12474 int i_unused = 1;
12475 AST_LIST_TRAVERSE(&r2links, tmp, list) {
12476 if (i == tmp->mfcr2.index) {
12477 i_unused = 0;
12478 break;
12479 }
12480 }
12481 if (i_unused) {
12482 new_idx = i;
12483 break;
12484 }
12485 }
12486 cur = ast_calloc(1, sizeof(*cur));
12487 if (!cur) {
12488 ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
12489 return NULL;
12490 }
12491 cur->mfcr2.index = new_idx;
12492 cur->mfcr2.r2master = AST_PTHREADT_NULL;
12493 r2links_count++;
12494 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx, r2links_count);
12495 AST_LIST_INSERT_TAIL(&r2links, cur, list);
12496 }
12497 AST_LIST_UNLOCK(&r2links);
12498 return cur;
12499}
12500
12501static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_chan_conf *conf)
12502{
12503 char tmplogdir[] = "/tmp";
12504 char logdir[OR2_MAX_PATH];
12505 int threshold = 0;
12506 int snres = 0;
12507 r2_link->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
12508 &dahdi_r2_transcode_iface, conf->mfcr2.variant, conf->mfcr2.max_ani,
12509 conf->mfcr2.max_dnis);
12510 if (!r2_link->protocol_context) {
12511 return -1;
12512 }
12513 openr2_context_set_log_level(r2_link->protocol_context, conf->mfcr2.loglevel);
12514 openr2_context_set_ani_first(r2_link->protocol_context, conf->mfcr2.get_ani_first);
12515#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12516 openr2_context_set_skip_category_request(r2_link->protocol_context, conf->mfcr2.skip_category_request);
12517#endif
12518 openr2_context_set_mf_threshold(r2_link->protocol_context, threshold);
12519 openr2_context_set_mf_back_timeout(r2_link->protocol_context, conf->mfcr2.mfback_timeout);
12520 openr2_context_set_metering_pulse_timeout(r2_link->protocol_context, conf->mfcr2.metering_pulse_timeout);
12521 openr2_context_set_double_answer(r2_link->protocol_context, conf->mfcr2.double_answer);
12522 openr2_context_set_immediate_accept(r2_link->protocol_context, conf->mfcr2.immediate_accept);
12523#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12524 openr2_context_set_dtmf_dialing(r2_link->protocol_context, conf->mfcr2.dtmf_dialing, conf->mfcr2.dtmf_time_on, conf->mfcr2.dtmf_time_off);
12525 openr2_context_set_dtmf_detection(r2_link->protocol_context, conf->mfcr2.dtmf_detection);
12526#endif
12527#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12528 openr2_context_set_dtmf_detection_end_timeout(r2_link->protocol_context, conf->mfcr2.dtmf_end_timeout);
12529#endif
12530 if (ast_strlen_zero(conf->mfcr2.logdir)) {
12531 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12532 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12533 }
12534 } else {
12535 snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", conf->mfcr2.logdir);
12536 if (snres >= sizeof(logdir)) {
12537 ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
12538 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12539 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12540 }
12541 } else {
12542 if (openr2_context_set_log_directory(r2_link->protocol_context, logdir)) {
12543 ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
12544 }
12545 }
12546 }
12547 if (!ast_strlen_zero(conf->mfcr2.r2proto_file)) {
12548 if (openr2_context_configure_from_advanced_file(r2_link->protocol_context, conf->mfcr2.r2proto_file)) {
12549 ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", conf->mfcr2.r2proto_file);
12550 }
12551 }
12552 /* Save the configuration used to setup this link */
12553 memcpy(&r2_link->conf, &conf->mfcr2, sizeof(r2_link->conf));
12554 return 0;
12555}
12556#endif
12557
12558/* converts a DAHDI sigtype to signalling as can be configured from
12559 * chan_dahdi.conf.
12560 * While both have basically the same values, this will later be the
12561 * place to add filters and sanity checks
12562 */
12564{
12565 return sigtype;
12566}
12567
12568/*!
12569 * \internal
12570 * \brief Initialize/create a channel interface.
12571 *
12572 * \param channel Channel interface number to initialize/create.
12573 * \param conf Configuration parameters to initialize interface with.
12574 * \param reloading What we are doing now:
12575 * 0 - initial module load,
12576 * 1 - module reload,
12577 * 2 - module restart
12578 *
12579 * \retval Interface-pointer initialized/created
12580 * \retval NULL if error
12581 */
12582static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
12583{
12584 /* Make a dahdi_pvt structure for this interface */
12585 struct dahdi_pvt *tmp;/*!< Current channel structure initializing */
12586 char fn[80];
12587 struct dahdi_bufferinfo bi;
12588
12589 int res;
12590#if defined(HAVE_PRI)
12591 int span = 0;
12592#endif /* defined(HAVE_PRI) */
12593 int here = 0;/*!< TRUE if the channel interface already exists. */
12594 int x;
12595 struct analog_pvt *analog_p = NULL;
12596 struct dahdi_params p;
12597#if defined(HAVE_PRI)
12598 struct dahdi_spaninfo si;
12599 struct sig_pri_chan *pri_chan = NULL;
12600#endif /* defined(HAVE_PRI) */
12601#if defined(HAVE_SS7)
12602 struct sig_ss7_chan *ss7_chan = NULL;
12603#endif /* defined(HAVE_SS7) */
12604
12605 /* Search channel interface list to see if it already exists. */
12606 for (tmp = iflist; tmp; tmp = tmp->next) {
12607 if (!tmp->destroy) {
12608 if (tmp->channel == channel) {
12609 /* The channel interface already exists. */
12610 here = 1;
12611 break;
12612 }
12613 if (tmp->channel > channel) {
12614 /* No way it can be in the sorted list. */
12615 tmp = NULL;
12616 break;
12617 }
12618 }
12619 }
12620
12621 if (!here && reloading != 1) {
12622 tmp = ast_calloc(1, sizeof(*tmp));
12623 if (!tmp) {
12624 return NULL;
12625 }
12627 if (!tmp->cc_params) {
12628 ast_free(tmp);
12629 return NULL;
12630 }
12631 ast_mutex_init(&tmp->lock);
12632 ifcount++;
12633 for (x = 0; x < 3; x++)
12634 tmp->subs[x].dfd = -1;
12635 tmp->channel = channel;
12636 tmp->priindication_oob = conf->chan.priindication_oob;
12637 }
12638
12639 if (tmp) {
12640 int chan_sig = conf->chan.sig;
12641
12642 /* If there are variables in tmp before it is updated to match the new config, clear them */
12643 if (reloading && tmp->vars) {
12645 tmp->vars = NULL;
12646 }
12647
12648 if (!here) {
12649 /* Can only get here if this is a new channel interface being created. */
12650 if ((channel != CHAN_PSEUDO)) {
12651 int count = 0;
12652
12653 snprintf(fn, sizeof(fn), "%d", channel);
12654 /* Open non-blocking */
12655 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12656 /* Retry open on restarts, but don't keep retrying if the channel doesn't exist (e.g. not configured) */
12657 while (tmp->subs[SUB_REAL].dfd < 0 && reloading == 2 && count < 1000 && errno != ENXIO) { /* the kernel may not call dahdi_release fast enough for the open flagbit to be cleared in time */
12658 usleep(1);
12659 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12660 count++;
12661 }
12662 /* Allocate a DAHDI structure */
12663 if (tmp->subs[SUB_REAL].dfd < 0) {
12664 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);
12665 destroy_dahdi_pvt(tmp);
12666 return NULL;
12667 }
12668 memset(&p, 0, sizeof(p));
12669 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
12670 if (res < 0) {
12671 ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
12672 destroy_dahdi_pvt(tmp);
12673 return NULL;
12674 }
12675 if (conf->is_sig_auto)
12676 chan_sig = sigtype_to_signalling(p.sigtype);
12677 if (p.sigtype != (chan_sig & 0x3ffff)) {
12678 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));
12679 destroy_dahdi_pvt(tmp);
12680 return NULL;
12681 }
12682 tmp->law_default = p.curlaw;
12683 tmp->law = p.curlaw;
12684 tmp->span = p.spanno;
12685#if defined(HAVE_PRI)
12686 span = p.spanno - 1;
12687#endif /* defined(HAVE_PRI) */
12688 } else {
12689 chan_sig = 0;
12690 }
12691 tmp->sig = chan_sig;
12692 tmp->outsigmod = conf->chan.outsigmod;
12693
12694 if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
12695 analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
12696 if (!analog_p) {
12697 destroy_dahdi_pvt(tmp);
12698 return NULL;
12699 }
12700 tmp->sig_pvt = analog_p;
12701 }
12702#if defined(HAVE_SS7)
12703 if (chan_sig == SIG_SS7) {
12704 struct dahdi_ss7 *ss7;
12705 int clear = 0;
12706
12707 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
12708 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12709 destroy_dahdi_pvt(tmp);
12710 return NULL;
12711 }
12712
12713 ss7 = ss7_resolve_linkset(cur_linkset);
12714 if (!ss7) {
12715 ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
12716 destroy_dahdi_pvt(tmp);
12717 return NULL;
12718 }
12719 ss7->ss7.span = cur_linkset;
12720 if (cur_cicbeginswith < 0) {
12721 ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
12722 destroy_dahdi_pvt(tmp);
12723 return NULL;
12724 }
12725 ss7_chan = sig_ss7_chan_new(tmp, &ss7->ss7);
12726 if (!ss7_chan) {
12727 destroy_dahdi_pvt(tmp);
12728 return NULL;
12729 }
12730 tmp->sig_pvt = ss7_chan;
12731 tmp->ss7 = &ss7->ss7;
12732
12733 ss7_chan->channel = tmp->channel;
12734 ss7_chan->cic = cur_cicbeginswith++;
12735
12736 /* DB: Add CIC's DPC information */
12737 ss7_chan->dpc = cur_defaultdpc;
12738
12739 ss7->ss7.pvts[ss7->ss7.numchans++] = ss7_chan;
12740
12741 ast_copy_string(ss7->ss7.internationalprefix, conf->ss7.ss7.internationalprefix, sizeof(ss7->ss7.internationalprefix));
12742 ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
12743 ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
12744 ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
12745 ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
12746
12747 ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
12748 ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
12749 }
12750#endif /* defined(HAVE_SS7) */
12751#ifdef HAVE_OPENR2
12752 if (chan_sig == SIG_MFCR2) {
12753 struct dahdi_mfcr2 *r2_link;
12754 struct r2link_entry *r2_le = dahdi_r2_get_link(conf);
12755 r2_link = &r2_le->mfcr2;
12756 if (!r2_link) {
12757 ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
12758 destroy_dahdi_pvt(tmp);
12759 return NULL;
12760 }
12761 if (!r2_link->protocol_context && dahdi_r2_set_context(r2_link, conf)) {
12762 ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
12763 destroy_dahdi_pvt(tmp);
12764 return NULL;
12765 }
12766 if (r2_link->numchans == ARRAY_LEN(r2_link->pvts)) {
12767 ast_log(LOG_ERROR, "Cannot add more channels to this link!\n");
12768 destroy_dahdi_pvt(tmp);
12769 return NULL;
12770 }
12771 r2_link->pvts[r2_link->numchans++] = tmp;
12772 tmp->r2chan = openr2_chan_new_from_fd(r2_link->protocol_context,
12773 tmp->subs[SUB_REAL].dfd,
12774 NULL, NULL);
12775 if (!tmp->r2chan) {
12776 openr2_liberr_t err = openr2_context_get_last_error(r2_link->protocol_context);
12777 ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
12778 destroy_dahdi_pvt(tmp);
12779 return NULL;
12780 }
12781 r2_link->live_chans++;
12782 tmp->mfcr2 = r2_link;
12783 if (conf->mfcr2.call_files) {
12784 openr2_chan_enable_call_files(tmp->r2chan);
12785 }
12786 openr2_chan_set_client_data(tmp->r2chan, tmp);
12787 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12788 openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
12789 openr2_chan_set_log_level(tmp->r2chan, conf->mfcr2.loglevel);
12790 tmp->mfcr2_category = conf->mfcr2.category;
12791 tmp->mfcr2_charge_calls = conf->mfcr2.charge_calls;
12792 tmp->mfcr2_allow_collect_calls = conf->mfcr2.allow_collect_calls;
12793 tmp->mfcr2_forced_release = conf->mfcr2.forced_release;
12794 tmp->mfcr2_accept_on_offer = conf->mfcr2.accept_on_offer;
12795 tmp->mfcr2call = 0;
12796 tmp->mfcr2_dnis_index = 0;
12797 tmp->mfcr2_ani_index = 0;
12798 }
12799#endif
12800#ifdef HAVE_PRI
12801 if (dahdi_sig_pri_lib_handles(chan_sig)) {
12802 int offset;
12803 int matchesdchan;
12804 int x,y;
12805 int myswitchtype = 0;
12806
12807 offset = 0;
12808 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
12809 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12810 destroy_dahdi_pvt(tmp);
12811 return NULL;
12812 }
12813 if (span >= NUM_SPANS) {
12814 ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
12815 destroy_dahdi_pvt(tmp);
12816 return NULL;
12817 } else {
12818 si.spanno = 0;
12819 if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
12820 ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
12821 destroy_dahdi_pvt(tmp);
12822 return NULL;
12823 }
12824 /* Store the logical span first based upon the real span */
12825 tmp->logicalspan = pris[span].prilogicalspan;
12826 pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
12827 if (span < 0) {
12828 ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
12829 destroy_dahdi_pvt(tmp);
12830 return NULL;
12831 }
12832 myswitchtype = conf->pri.pri.switchtype;
12833 /* Make sure this isn't a d-channel */
12834 matchesdchan=0;
12835 for (x = 0; x < NUM_SPANS; x++) {
12836 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12837 if (pris[x].dchannels[y] == tmp->channel) {
12838 matchesdchan = 1;
12839 break;
12840 }
12841 }
12842 }
12843 if (!matchesdchan) {
12844 if (pris[span].pri.nodetype && (pris[span].pri.nodetype != conf->pri.pri.nodetype)) {
12845 ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].pri.nodetype));
12846 destroy_dahdi_pvt(tmp);
12847 return NULL;
12848 }
12849 if (pris[span].pri.switchtype && (pris[span].pri.switchtype != myswitchtype)) {
12850 ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].pri.switchtype));
12851 destroy_dahdi_pvt(tmp);
12852 return NULL;
12853 }
12854 if ((pris[span].pri.dialplan) && (pris[span].pri.dialplan != conf->pri.pri.dialplan)) {
12855 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));
12856 destroy_dahdi_pvt(tmp);
12857 return NULL;
12858 }
12859 if (!ast_strlen_zero(pris[span].pri.idledial) && strcmp(pris[span].pri.idledial, conf->pri.pri.idledial)) {
12860 ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.pri.idledial);
12861 destroy_dahdi_pvt(tmp);
12862 return NULL;
12863 }
12864 if (!ast_strlen_zero(pris[span].pri.idleext) && strcmp(pris[span].pri.idleext, conf->pri.pri.idleext)) {
12865 ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.pri.idleext);
12866 destroy_dahdi_pvt(tmp);
12867 return NULL;
12868 }
12869 if (pris[span].pri.minunused && (pris[span].pri.minunused != conf->pri.pri.minunused)) {
12870 ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.pri.minunused);
12871 destroy_dahdi_pvt(tmp);
12872 return NULL;
12873 }
12874 if (pris[span].pri.minidle && (pris[span].pri.minidle != conf->pri.pri.minidle)) {
12875 ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.pri.minidle);
12876 destroy_dahdi_pvt(tmp);
12877 return NULL;
12878 }
12879 if (pris[span].pri.numchans >= ARRAY_LEN(pris[span].pri.pvts)) {
12880 ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
12881 pris[span].pri.trunkgroup);
12882 destroy_dahdi_pvt(tmp);
12883 return NULL;
12884 }
12885
12886 pri_chan = sig_pri_chan_new(tmp, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
12887 if (!pri_chan) {
12888 destroy_dahdi_pvt(tmp);
12889 return NULL;
12890 }
12891 tmp->sig_pvt = pri_chan;
12892 tmp->pri = &pris[span].pri;
12893
12894 tmp->priexclusive = conf->chan.priexclusive;
12895
12896 if (!tmp->pri->cc_params) {
12898 if (!tmp->pri->cc_params) {
12899 destroy_dahdi_pvt(tmp);
12900 return NULL;
12901 }
12902 }
12904 conf->chan.cc_params);
12905
12906 pris[span].pri.sig = chan_sig;
12907 pris[span].pri.nodetype = conf->pri.pri.nodetype;
12908 pris[span].pri.switchtype = myswitchtype;
12909 pris[span].pri.nsf = conf->pri.pri.nsf;
12910 pris[span].pri.dialplan = conf->pri.pri.dialplan;
12911 pris[span].pri.localdialplan = conf->pri.pri.localdialplan;
12912 pris[span].pri.cpndialplan = conf->pri.pri.cpndialplan;
12913 pris[span].pri.pvts[pris[span].pri.numchans++] = tmp->sig_pvt;
12914 pris[span].pri.minunused = conf->pri.pri.minunused;
12915 pris[span].pri.minidle = conf->pri.pri.minidle;
12916 pris[span].pri.overlapdial = conf->pri.pri.overlapdial;
12917 pris[span].pri.qsigchannelmapping = conf->pri.pri.qsigchannelmapping;
12918 pris[span].pri.discardremoteholdretrieval = conf->pri.pri.discardremoteholdretrieval;
12919#if defined(HAVE_PRI_SERVICE_MESSAGES)
12920 pris[span].pri.enable_service_message_support = conf->pri.pri.enable_service_message_support;
12921#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12922#ifdef HAVE_PRI_INBANDDISCONNECT
12923 pris[span].pri.inbanddisconnect = conf->pri.pri.inbanddisconnect;
12924#endif
12925#if defined(HAVE_PRI_CALL_HOLD)
12926 pris[span].pri.hold_disconnect_transfer =
12927 conf->pri.pri.hold_disconnect_transfer;
12928#endif /* defined(HAVE_PRI_CALL_HOLD) */
12929#if defined(HAVE_PRI_CCSS)
12930 pris[span].pri.cc_ptmp_recall_mode =
12931 conf->pri.pri.cc_ptmp_recall_mode;
12932 pris[span].pri.cc_qsig_signaling_link_req =
12933 conf->pri.pri.cc_qsig_signaling_link_req;
12934 pris[span].pri.cc_qsig_signaling_link_rsp =
12935 conf->pri.pri.cc_qsig_signaling_link_rsp;
12936#endif /* defined(HAVE_PRI_CCSS) */
12937#if defined(HAVE_PRI_CALL_WAITING)
12938 pris[span].pri.max_call_waiting_calls =
12939 conf->pri.pri.max_call_waiting_calls;
12940 pris[span].pri.allow_call_waiting_calls =
12941 conf->pri.pri.allow_call_waiting_calls;
12942#endif /* defined(HAVE_PRI_CALL_WAITING) */
12943 pris[span].pri.transfer = conf->chan.transfer;
12944 pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
12945#if defined(HAVE_PRI_L2_PERSISTENCE)
12946 pris[span].pri.l2_persistence = conf->pri.pri.l2_persistence;
12947#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12948 pris[span].pri.colp_send = conf->pri.pri.colp_send;
12949#if defined(HAVE_PRI_AOC_EVENTS)
12950 pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
12951 pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
12952#endif /* defined(HAVE_PRI_AOC_EVENTS) */
12953 if (chan_sig == SIG_BRI_PTMP) {
12954 pris[span].pri.layer1_ignored = conf->pri.pri.layer1_ignored;
12955 } else {
12956 /* Option does not apply to this line type. */
12957 pris[span].pri.layer1_ignored = 0;
12958 }
12959 pris[span].pri.append_msn_to_user_tag = conf->pri.pri.append_msn_to_user_tag;
12960 pris[span].pri.inband_on_setup_ack = conf->pri.pri.inband_on_setup_ack;
12961 pris[span].pri.inband_on_proceeding = conf->pri.pri.inband_on_proceeding;
12962 ast_copy_string(pris[span].pri.initial_user_tag, conf->chan.cid_tag, sizeof(pris[span].pri.initial_user_tag));
12963 ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
12964#if defined(HAVE_PRI_MWI)
12965 ast_copy_string(pris[span].pri.mwi_mailboxes,
12966 conf->pri.pri.mwi_mailboxes,
12967 sizeof(pris[span].pri.mwi_mailboxes));
12968 ast_copy_string(pris[span].pri.mwi_vm_boxes,
12969 conf->pri.pri.mwi_vm_boxes,
12970 sizeof(pris[span].pri.mwi_vm_boxes));
12971 ast_copy_string(pris[span].pri.mwi_vm_numbers,
12972 conf->pri.pri.mwi_vm_numbers,
12973 sizeof(pris[span].pri.mwi_vm_numbers));
12974#endif /* defined(HAVE_PRI_MWI) */
12975 ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
12976 ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
12977 ast_copy_string(pris[span].pri.internationalprefix, conf->pri.pri.internationalprefix, sizeof(pris[span].pri.internationalprefix));
12978 ast_copy_string(pris[span].pri.nationalprefix, conf->pri.pri.nationalprefix, sizeof(pris[span].pri.nationalprefix));
12979 ast_copy_string(pris[span].pri.localprefix, conf->pri.pri.localprefix, sizeof(pris[span].pri.localprefix));
12980 ast_copy_string(pris[span].pri.privateprefix, conf->pri.pri.privateprefix, sizeof(pris[span].pri.privateprefix));
12981 ast_copy_string(pris[span].pri.unknownprefix, conf->pri.pri.unknownprefix, sizeof(pris[span].pri.unknownprefix));
12982 pris[span].pri.moh_signaling = conf->pri.pri.moh_signaling;
12983 pris[span].pri.resetinterval = conf->pri.pri.resetinterval;
12984#if defined(HAVE_PRI_DISPLAY_TEXT)
12985 pris[span].pri.display_flags_send = conf->pri.pri.display_flags_send;
12986 pris[span].pri.display_flags_receive = conf->pri.pri.display_flags_receive;
12987#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
12988#if defined(HAVE_PRI_MCID)
12989 pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
12990#endif /* defined(HAVE_PRI_MCID) */
12991 pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
12992#if defined(HAVE_PRI_DATETIME_SEND)
12993 pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
12994#endif /* defined(HAVE_PRI_DATETIME_SEND) */
12995
12996 for (x = 0; x < PRI_MAX_TIMERS; x++) {
12997 pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
12998 }
12999
13000#if defined(HAVE_PRI_CALL_WAITING)
13001 /* Channel initial config parameters. */
13002 pris[span].pri.ch_cfg.stripmsd = conf->chan.stripmsd;
13003 pris[span].pri.ch_cfg.hidecallerid = conf->chan.hidecallerid;
13004 pris[span].pri.ch_cfg.hidecalleridname = conf->chan.hidecalleridname;
13005 pris[span].pri.ch_cfg.immediate = conf->chan.immediate;
13006 pris[span].pri.ch_cfg.priexclusive = conf->chan.priexclusive;
13007 pris[span].pri.ch_cfg.priindication_oob = conf->chan.priindication_oob;
13008 pris[span].pri.ch_cfg.use_callerid = conf->chan.use_callerid;
13009 pris[span].pri.ch_cfg.use_callingpres = conf->chan.use_callingpres;
13010 ast_copy_string(pris[span].pri.ch_cfg.context, conf->chan.context, sizeof(pris[span].pri.ch_cfg.context));
13011 ast_copy_string(pris[span].pri.ch_cfg.mohinterpret, conf->chan.mohinterpret, sizeof(pris[span].pri.ch_cfg.mohinterpret));
13012#endif /* defined(HAVE_PRI_CALL_WAITING) */
13013 } else {
13014 ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", p.chanpos);
13015 destroy_dahdi_pvt(tmp);
13016 return NULL;
13017 }
13018 }
13019 }
13020#endif
13021 } else {
13022 /* already exists in interface list */
13023 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));
13024 chan_sig = tmp->sig;
13025 if (tmp->subs[SUB_REAL].dfd > -1) {
13026 memset(&p, 0, sizeof(p));
13027 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13028 }
13029 }
13030 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
13031 switch (chan_sig) {
13032 case SIG_FXSKS:
13033 case SIG_FXSLS:
13034 case SIG_EM:
13035 case SIG_EM_E1:
13036 case SIG_EMWINK:
13037 case SIG_FEATD:
13038 case SIG_FEATDMF:
13039 case SIG_FEATDMF_TA:
13040 case SIG_FEATB:
13041 case SIG_E911:
13042 case SIG_SF:
13043 case SIG_SFWINK:
13044 case SIG_FGC_CAMA:
13045 case SIG_FGC_CAMAMF:
13046 case SIG_SF_FEATD:
13047 case SIG_SF_FEATDMF:
13048 case SIG_SF_FEATB:
13049 p.starttime = 250;
13050 break;
13051 }
13052
13053 if (tmp->radio) {
13054 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
13055 p.channo = channel;
13056 p.rxwinktime = 1;
13057 p.rxflashtime = 1;
13058 p.starttime = 1;
13059 p.debouncetime = 5;
13060 } else {
13061 p.channo = channel;
13062 /* Override timing settings based on config file */
13063 if (conf->timing.prewinktime >= 0)
13064 p.prewinktime = conf->timing.prewinktime;
13065 if (conf->timing.preflashtime >= 0)
13066 p.preflashtime = conf->timing.preflashtime;
13067 if (conf->timing.winktime >= 0)
13068 p.winktime = conf->timing.winktime;
13069 if (conf->timing.flashtime >= 0)
13070 p.flashtime = conf->timing.flashtime;
13071 if (conf->timing.starttime >= 0)
13072 p.starttime = conf->timing.starttime;
13073 if (conf->timing.rxwinktime >= 0)
13074 p.rxwinktime = conf->timing.rxwinktime;
13075 if (conf->timing.rxflashtime >= 0)
13076 p.rxflashtime = conf->timing.rxflashtime;
13077 if (conf->timing.debouncetime >= 0)
13078 p.debouncetime = conf->timing.debouncetime;
13079 }
13080
13081 /* don't set parms on a pseudo-channel */
13082 if (tmp->subs[SUB_REAL].dfd >= 0)
13083 {
13084 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
13085 if (res < 0) {
13086 ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
13087 destroy_dahdi_pvt(tmp);
13088 return NULL;
13089 }
13090 }
13091#if 1
13092 if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
13093 memset(&bi, 0, sizeof(bi));
13094 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13095 if (!res) {
13096 bi.txbufpolicy = conf->chan.buf_policy;
13097 bi.rxbufpolicy = conf->chan.buf_policy;
13098 bi.numbufs = conf->chan.buf_no;
13099 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13100 if (res < 0) {
13101 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
13102 }
13103 } else {
13104 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
13105 }
13106 tmp->buf_policy = conf->chan.buf_policy;
13107 tmp->buf_no = conf->chan.buf_no;
13108 tmp->usefaxbuffers = conf->chan.usefaxbuffers;
13109 tmp->faxbuf_policy = conf->chan.faxbuf_policy;
13110 tmp->faxbuf_no = conf->chan.faxbuf_no;
13111 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
13112 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
13113 * The reason the ioctl call above failed should to be determined before worrying about the
13114 * faxbuffer-related ioctl calls */
13115 tmp->bufsize = bi.bufsize;
13116 }
13117#endif
13118 tmp->immediate = conf->chan.immediate;
13119 tmp->immediatering = conf->chan.immediatering;
13120 tmp->transfertobusy = conf->chan.transfertobusy;
13121 tmp->permdialmode = conf->chan.permdialmode;
13122 if (chan_sig & __DAHDI_SIG_FXS) {
13123 tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
13124 tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
13125 tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
13126 }
13127 tmp->ringt_base = ringt_base;
13128 tmp->firstradio = 0;
13129 if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
13130 tmp->permcallwaiting = conf->chan.callwaiting;
13131 else
13132 tmp->permcallwaiting = 0;
13133 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
13134 tmp->destroy = 0;
13135 tmp->drings = conf->chan.drings;
13136
13137 /* 10 is a nice default. */
13138 if (tmp->drings.ringnum[0].range == 0)
13139 tmp->drings.ringnum[0].range = 10;
13140 if (tmp->drings.ringnum[1].range == 0)
13141 tmp->drings.ringnum[1].range = 10;
13142 if (tmp->drings.ringnum[2].range == 0)
13143 tmp->drings.ringnum[2].range = 10;
13144
13146 tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
13147 tmp->callwaitingdeluxe = conf->chan.callwaitingdeluxe; /* Not used in DAHDI pvt, only analog pvt */
13148 tmp->threewaycalling = conf->chan.threewaycalling;
13149 tmp->threewaysilenthold = conf->chan.threewaysilenthold;
13150 tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
13151 tmp->adsi = conf->chan.adsi;
13152 tmp->use_smdi = conf->chan.use_smdi;
13153 tmp->permhidecallerid = conf->chan.hidecallerid;
13154 tmp->hidecalleridname = conf->chan.hidecalleridname;
13155 tmp->callreturn = conf->chan.callreturn;
13156 tmp->lastnumredial = conf->chan.lastnumredial; /* Not used in DAHDI pvt, only analog pvt */
13157 tmp->echocancel = conf->chan.echocancel;
13158 tmp->echotraining = conf->chan.echotraining;
13159 tmp->pulse = conf->chan.pulse;
13160 if (tmp->echocancel.head.tap_length) {
13161 tmp->echocanbridged = conf->chan.echocanbridged;
13162 } else {
13163 if (conf->chan.echocanbridged)
13164 ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
13165 tmp->echocanbridged = 0;
13166 }
13167 tmp->busydetect = conf->chan.busydetect;
13168 tmp->busycount = conf->chan.busycount;
13169 tmp->busy_cadence = conf->chan.busy_cadence;
13170 tmp->callprogress = conf->chan.callprogress;
13171 tmp->waitfordialtone = conf->chan.waitfordialtone;
13172 tmp->dialtone_detect = conf->chan.dialtone_detect;
13173 tmp->faxdetect_timeout = conf->chan.faxdetect_timeout;
13174 tmp->firstdigit_timeout = conf->chan.firstdigit_timeout;
13175 tmp->interdigit_timeout = conf->chan.interdigit_timeout;
13176 tmp->matchdigit_timeout = conf->chan.matchdigit_timeout;
13177 tmp->cancallforward = conf->chan.cancallforward;
13178 tmp->dtmfrelax = conf->chan.dtmfrelax;
13179 tmp->callwaiting = tmp->permcallwaiting;
13180 tmp->hidecallerid = tmp->permhidecallerid;
13181 tmp->channel = channel;
13182 tmp->stripmsd = conf->chan.stripmsd;
13183 tmp->use_callerid = conf->chan.use_callerid;
13184 tmp->cid_signalling = conf->chan.cid_signalling;
13185 tmp->cid_start = conf->chan.cid_start;
13186 tmp->dahditrcallerid = conf->chan.dahditrcallerid;
13187 tmp->restrictcid = conf->chan.restrictcid;
13188 tmp->use_callingpres = conf->chan.use_callingpres;
13189 if (tmp->usedistinctiveringdetection) {
13190 if (!tmp->use_callerid) {
13191 ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
13192 tmp->use_callerid = 1;
13193 }
13194 }
13195
13196 if (tmp->cid_signalling == CID_SIG_SMDI) {
13197 if (!tmp->use_smdi) {
13198 ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13199 tmp->use_smdi = 1;
13200 }
13201 }
13202 if (tmp->use_smdi) {
13203 tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
13204 if (!(tmp->smdi_iface)) {
13205 ast_log(LOG_ERROR, "Invalid SMDI port specified, disabling SMDI support\n");
13206 tmp->use_smdi = 0;
13207 }
13208 }
13209
13210 ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
13211 tmp->amaflags = conf->chan.amaflags;
13212 if (!here) {
13213 tmp->confno = -1;
13214 tmp->propconfno = -1;
13215 }
13216 tmp->canpark = conf->chan.canpark;
13217 tmp->transfer = conf->chan.transfer;
13218 ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
13219 ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
13220 ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
13221 ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
13222 ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
13223 ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
13224 ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
13225 tmp->cid_ton = 0;
13226 if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
13227 ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
13228 ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
13229 } else {
13230 tmp->cid_num[0] = '\0';
13231 tmp->cid_name[0] = '\0';
13232 }
13233#if defined(HAVE_PRI)
13234 if (dahdi_sig_pri_lib_handles(tmp->sig)) {
13235 tmp->cid_tag[0] = '\0';
13236 } else
13237#endif /* defined(HAVE_PRI) */
13238 {
13239 ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
13240 }
13241 tmp->cid_subaddr[0] = '\0';
13242 ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
13243 if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
13244 /* This module does not handle MWI in an event-based manner. However, it
13245 * subscribes to MWI for each mailbox that is configured so that the core
13246 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13247 * event cache instead of checking the mailbox directly. */
13249 }
13250#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13251 tmp->mwisend_setting = conf->chan.mwisend_setting;
13252 tmp->mwisend_fsk = conf->chan.mwisend_fsk;
13253 tmp->mwisend_rpas = conf->chan.mwisend_rpas;
13254#endif
13255
13256 tmp->group = conf->chan.group;
13257 tmp->callgroup = conf->chan.callgroup;
13258 tmp->pickupgroup= conf->chan.pickupgroup;
13260 tmp->named_callgroups = ast_ref_namedgroups(conf->chan.named_callgroups);
13262 tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
13263 if (conf->chan.vars) {
13264 struct ast_variable *v, *tmpvar;
13265 for (v = conf->chan.vars ; v ; v = v->next) {
13266 if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
13267 if (ast_variable_list_replace(&tmp->vars, tmpvar)) {
13268 tmpvar->next = tmp->vars;
13269 tmp->vars = tmpvar;
13270 }
13271 }
13272 }
13273 }
13274 tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
13275 tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
13276 tmp->hwrxgain = conf->chan.hwrxgain;
13277 tmp->hwtxgain = conf->chan.hwtxgain;
13278 tmp->cid_rxgain = conf->chan.cid_rxgain;
13279 tmp->rxgain = conf->chan.rxgain;
13280 tmp->txgain = conf->chan.txgain;
13281 tmp->txdrc = conf->chan.txdrc;
13282 tmp->rxdrc = conf->chan.rxdrc;
13283 tmp->tonezone = conf->chan.tonezone;
13284 if (tmp->subs[SUB_REAL].dfd > -1) {
13285 if (tmp->hwrxgain_enabled) {
13286 tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
13287 }
13288 if (tmp->hwtxgain_enabled) {
13289 tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
13290 }
13291 set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
13292 if (tmp->dsp)
13294 dahdi_conf_update(tmp);
13295 if (!here) {
13296 switch (chan_sig) {
13298 case SIG_SS7:
13299 case SIG_MFCR2:
13300 break;
13301 default:
13302 /* Hang it up to be sure it's good */
13303 dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
13304 break;
13305 }
13306 }
13307 ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
13308 if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
13309 /* the dchannel is down so put the channel in alarm */
13310 switch (tmp->sig) {
13311#ifdef HAVE_PRI
13313 sig_pri_set_alarm(tmp->sig_pvt, 1);
13314 break;
13315#endif
13316#if defined(HAVE_SS7)
13317 case SIG_SS7:
13318 sig_ss7_set_alarm(tmp->sig_pvt, 1);
13319 break;
13320#endif /* defined(HAVE_SS7) */
13321 default:
13322 /* The only sig submodule left should be sig_analog. */
13323 analog_p = tmp->sig_pvt;
13324 if (analog_p) {
13325 analog_p->inalarm = 1;
13326 }
13327 tmp->inalarm = 1;
13328 break;
13329 }
13330 handle_alarms(tmp, res);
13331 }
13332 }
13333
13334 tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13335 tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13336 tmp->ani_info_digits = conf->chan.ani_info_digits;
13337 tmp->ani_wink_time = conf->chan.ani_wink_time;
13338 tmp->ani_timeout = conf->chan.ani_timeout;
13339 tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13340 tmp->reoriginate = conf->chan.reoriginate;
13341 tmp->sendcalleridafter = conf->chan.sendcalleridafter;
13342 ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
13343
13344 if (!here) {
13345 tmp->locallyblocked = 0;
13346 tmp->remotelyblocked = 0;
13347 switch (tmp->sig) {
13348#if defined(HAVE_PRI)
13350 tmp->inservice = 1;/* Inservice until actually implemented. */
13351#if defined(HAVE_PRI_SERVICE_MESSAGES)
13352 ((struct sig_pri_chan *) tmp->sig_pvt)->service_status = 0;
13353 if (chan_sig == SIG_PRI) {
13354 char db_chan_name[20];
13355 char db_answer[5];
13356
13357 /*
13358 * Initialize the active out-of-service status
13359 * and delete any record if the feature is not enabled.
13360 */
13361 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, tmp->channel);
13362 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
13363 unsigned *why;
13364
13365 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
13366 if (tmp->pri->enable_service_message_support) {
13367 char state;
13368
13369 sscanf(db_answer, "%1c:%30u", &state, why);
13370
13371 /* Ensure that only the implemented bits could be set.*/
13372 *why &= (SRVST_NEAREND | SRVST_FAREND);
13373 }
13374 if (!*why) {
13375 ast_db_del(db_chan_name, SRVST_DBKEY);
13376 }
13377 }
13378 }
13379#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13380 break;
13381#endif /* defined(HAVE_PRI) */
13382#if defined(HAVE_SS7)
13383 case SIG_SS7:
13384 tmp->inservice = 0;
13385 if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
13387 }
13388 break;
13389#endif /* defined(HAVE_SS7) */
13390 default:
13391 /* We default to in service on protocols that don't have a reset */
13392 tmp->inservice = 1;
13393 break;
13394 }
13395 }
13396
13397 switch (tmp->sig) {
13398#if defined(HAVE_PRI)
13400 if (pri_chan) {
13401 pri_chan->channel = tmp->channel;
13402 pri_chan->hidecallerid = tmp->hidecallerid;
13403 pri_chan->hidecalleridname = tmp->hidecalleridname;
13404 pri_chan->immediate = tmp->immediate;
13405 pri_chan->inalarm = tmp->inalarm;
13406 pri_chan->priexclusive = tmp->priexclusive;
13407 pri_chan->priindication_oob = tmp->priindication_oob;
13408 pri_chan->use_callerid = tmp->use_callerid;
13409 pri_chan->use_callingpres = tmp->use_callingpres;
13410 ast_copy_string(pri_chan->context, tmp->context,
13411 sizeof(pri_chan->context));
13413 sizeof(pri_chan->mohinterpret));
13414 pri_chan->stripmsd = tmp->stripmsd;
13415 }
13416 break;
13417#endif /* defined(HAVE_PRI) */
13418#if defined(HAVE_SS7)
13419 case SIG_SS7:
13420 if (ss7_chan) {
13421 ss7_chan->inalarm = tmp->inalarm;
13422 ss7_chan->inservice = tmp->inservice;
13423
13424 ss7_chan->stripmsd = tmp->stripmsd;
13425 ss7_chan->hidecallerid = tmp->hidecallerid;
13426 ss7_chan->use_callerid = tmp->use_callerid;
13427 ss7_chan->use_callingpres = tmp->use_callingpres;
13428 ss7_chan->immediate = tmp->immediate;
13429 ss7_chan->locallyblocked = tmp->locallyblocked;
13430 ss7_chan->remotelyblocked = tmp->remotelyblocked;
13431 ast_copy_string(ss7_chan->context, tmp->context,
13432 sizeof(ss7_chan->context));
13434 sizeof(ss7_chan->mohinterpret));
13435 }
13436 break;
13437#endif /* defined(HAVE_SS7) */
13438 default:
13439 /* The only sig submodule left should be sig_analog. */
13440 analog_p = tmp->sig_pvt;
13441 if (analog_p) {
13442 analog_p->channel = tmp->channel;
13443 analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13444 analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13445 analog_p->ani_info_digits = conf->chan.ani_info_digits;
13446 analog_p->ani_timeout = conf->chan.ani_timeout;
13447 analog_p->ani_wink_time = conf->chan.ani_wink_time;
13448 analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13449 analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
13450 analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
13451 analog_p->callreturn = conf->chan.callreturn;
13452 analog_p->lastnumredial = conf->chan.lastnumredial; /* Only actually used in analog pvt, not DAHDI pvt */
13453 analog_p->cancallforward = conf->chan.cancallforward;
13454 analog_p->canpark = conf->chan.canpark;
13455 analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
13456 analog_p->immediate = conf->chan.immediate;
13457 analog_p->immediatering = conf->chan.immediatering;
13458 analog_p->permhidecallerid = conf->chan.hidecallerid; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13459 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13460 analog_p->pulse = conf->chan.pulse;
13461 analog_p->threewaycalling = conf->chan.threewaycalling;
13462 analog_p->transfer = conf->chan.transfer;
13463 analog_p->transfertobusy = conf->chan.transfertobusy;
13464 analog_p->permdialmode = conf->chan.permdialmode;
13465 analog_p->use_callerid = tmp->use_callerid;
13467 analog_p->use_smdi = tmp->use_smdi;
13468 analog_p->smdi_iface = tmp->smdi_iface;
13469 analog_p->outsigmod = ANALOG_SIG_NONE;
13470 analog_p->echotraining = conf->chan.echotraining;
13471 analog_p->cid_signalling = conf->chan.cid_signalling;
13472 analog_p->stripmsd = conf->chan.stripmsd;
13473 switch (conf->chan.cid_start) {
13474 case CID_START_POLARITY:
13476 break;
13479 break;
13482 break;
13483 default:
13484 analog_p->cid_start = ANALOG_CID_START_RING;
13485 break;
13486 }
13487 analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;
13488 analog_p->callwaitingdeluxe = conf->chan.callwaitingdeluxe;
13489 analog_p->ringt = conf->chan.ringt;
13490 analog_p->ringt_base = ringt_base;
13491 analog_p->onhooktime = time(NULL);
13492 if (chan_sig & __DAHDI_SIG_FXO) {
13493 memset(&p, 0, sizeof(p));
13494 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13495 if (!res) {
13496 analog_p->fxsoffhookstate = p.rxisoffhook;
13497 }
13498#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13499 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
13500#endif
13501 }
13502 analog_p->msgstate = -1;
13503
13504 ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
13505 ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
13506 ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
13507
13508 analog_config_complete(analog_p);
13509 }
13510 break;
13511 }
13512#if defined(HAVE_PRI)
13513 if (tmp->channel == CHAN_PSEUDO) {
13514 /*
13515 * Save off pseudo channel buffer policy values for dynamic creation of
13516 * no B channel interfaces.
13517 */
13518 dahdi_pseudo_parms.buf_no = tmp->buf_no;
13519 dahdi_pseudo_parms.buf_policy = tmp->buf_policy;
13520 dahdi_pseudo_parms.faxbuf_no = tmp->faxbuf_no;
13521 dahdi_pseudo_parms.faxbuf_policy = tmp->faxbuf_policy;
13522 }
13523#endif /* defined(HAVE_PRI) */
13524 }
13525 if (tmp && !here) {
13526 /* Add the new channel interface to the sorted channel interface list. */
13528 }
13529 return tmp;
13530}
13531
13532static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
13533{
13534#if defined(HAVE_PRI)
13535 if (0 < span) {
13536 /* The channel must be on the specified PRI span. */
13537 if (!p->pri || p->pri->span != span) {
13538 return 0;
13539 }
13540 if (!groupmatch && channelmatch == -1) {
13541 /* Match any group since it only needs to be on the PRI span. */
13542 *groupmatched = 1;
13543 return 1;
13544 }
13545 }
13546#endif /* defined(HAVE_PRI) */
13547 /* check group matching */
13548 if (groupmatch) {
13549 if ((p->group & groupmatch) != groupmatch)
13550 /* Doesn't match the specified group, try the next one */
13551 return 0;
13552 *groupmatched = 1;
13553 }
13554 /* Check to see if we have a channel match */
13555 if (channelmatch != -1) {
13556 if (p->channel != channelmatch)
13557 /* Doesn't match the specified channel, try the next one */
13558 return 0;
13559 *channelmatched = 1;
13560 }
13561
13562 return 1;
13563}
13564
13565static int available(struct dahdi_pvt **pvt, int is_specific_channel)
13566{
13567 struct dahdi_pvt *p = *pvt;
13568
13569 if (p->inalarm)
13570 return 0;
13571
13572 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
13573 return analog_available(p->sig_pvt);
13574
13575 switch (p->sig) {
13576#if defined(HAVE_PRI)
13578 {
13579 struct sig_pri_chan *pvt_chan;
13580 int res;
13581
13582 pvt_chan = p->sig_pvt;
13583 res = sig_pri_available(&pvt_chan, is_specific_channel);
13584 *pvt = pvt_chan->chan_pvt;
13585 return res;
13586 }
13587#endif /* defined(HAVE_PRI) */
13588#if defined(HAVE_SS7)
13589 case SIG_SS7:
13590 return sig_ss7_available(p->sig_pvt);
13591#endif /* defined(HAVE_SS7) */
13592 default:
13593 break;
13594 }
13595
13596 if (p->locallyblocked || p->remotelyblocked) {
13597 return 0;
13598 }
13599
13600 /* If no owner definitely available */
13601 if (!p->owner) {
13602#ifdef HAVE_OPENR2
13603 /* Trust MFC/R2 */
13604 if (p->mfcr2) {
13605 if (p->mfcr2call) {
13606 return 0;
13607 } else {
13608 return 1;
13609 }
13610 }
13611#endif
13612 return 1;
13613 }
13614
13615 return 0;
13616}
13617
13618#if defined(HAVE_PRI)
13619#if defined(HAVE_PRI_CALL_WAITING)
13620/*!
13621 * \internal
13622 * \brief Init the private channel configuration using the span controller.
13623 * \since 1.8
13624 *
13625 * \param priv Channel to init the configuration.
13626 * \param pri sig_pri PRI control structure.
13627 *
13628 * \note Assumes the pri->lock is already obtained.
13629 */
13630static void my_pri_init_config(void *priv, struct sig_pri_span *pri)
13631{
13632 struct dahdi_pvt *pvt = priv;
13633
13634 pvt->stripmsd = pri->ch_cfg.stripmsd;
13635 pvt->hidecallerid = pri->ch_cfg.hidecallerid;
13636 pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
13637 pvt->immediate = pri->ch_cfg.immediate;
13638 pvt->priexclusive = pri->ch_cfg.priexclusive;
13639 pvt->priindication_oob = pri->ch_cfg.priindication_oob;
13640 pvt->use_callerid = pri->ch_cfg.use_callerid;
13641 pvt->use_callingpres = pri->ch_cfg.use_callingpres;
13642 ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
13643 ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
13644}
13645#endif /* defined(HAVE_PRI_CALL_WAITING) */
13646#endif /* defined(HAVE_PRI) */
13647
13648#if defined(HAVE_PRI)
13649/*!
13650 * \internal
13651 * \brief Create a no B channel interface.
13652 * \since 1.8
13653 *
13654 * \param pri sig_pri span controller to add interface.
13655 *
13656 * \note Assumes the pri->lock is already obtained.
13657 *
13658 * \retval array-index into private pointer array on success.
13659 * \retval -1 on error.
13660 */
13661static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri)
13662{
13663 int pvt_idx;
13664 int res;
13665 unsigned idx;
13666 struct dahdi_pvt *pvt;
13667 struct sig_pri_chan *chan;
13668 struct dahdi_bufferinfo bi;
13669
13670 static int nobch_channel = CHAN_PSEUDO;
13671
13672 /* Find spot in the private pointer array for new interface. */
13673 for (pvt_idx = 0; pvt_idx < pri->numchans; ++pvt_idx) {
13674 if (!pri->pvts[pvt_idx]) {
13675 break;
13676 }
13677 }
13678 if (pri->numchans == pvt_idx) {
13679 if (ARRAY_LEN(pri->pvts) <= pvt_idx) {
13680 ast_log(LOG_ERROR, "Unable to add a no-B-channel interface!\n");
13681 return -1;
13682 }
13683
13684 /* Add new spot to the private pointer array. */
13685 pri->pvts[pvt_idx] = NULL;
13686 ++pri->numchans;
13687 }
13688
13689 pvt = ast_calloc(1, sizeof(*pvt));
13690 if (!pvt) {
13691 return -1;
13692 }
13694 if (!pvt->cc_params) {
13695 ast_free(pvt);
13696 return -1;
13697 }
13698 ast_mutex_init(&pvt->lock);
13699 for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
13700 pvt->subs[idx].dfd = -1;
13701 }
13702 pvt->buf_no = dahdi_pseudo_parms.buf_no;
13703 pvt->buf_policy = dahdi_pseudo_parms.buf_policy;
13704 pvt->faxbuf_no = dahdi_pseudo_parms.faxbuf_no;
13705 pvt->faxbuf_policy = dahdi_pseudo_parms.faxbuf_policy;
13706
13707 chan = sig_pri_chan_new(pvt, pri, 0, 0, 0);
13708 if (!chan) {
13709 destroy_dahdi_pvt(pvt);
13710 return -1;
13711 }
13712 chan->no_b_channel = 1;
13713
13714 /*
13715 * Pseudo channel companding law.
13716 * Needed for outgoing call waiting calls.
13717 * XXX May need to make this determined by switchtype or user option.
13718 */
13719 pvt->law_default = DAHDI_LAW_ALAW;
13720
13721 pvt->sig = pri->sig;
13722 pvt->outsigmod = -1;
13723 pvt->pri = pri;
13724 pvt->sig_pvt = chan;
13725 pri->pvts[pvt_idx] = chan;
13726
13727 pvt->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13728 if (pvt->subs[SUB_REAL].dfd < 0) {
13729 ast_log(LOG_ERROR, "Unable to open no B channel interface pseudo channel: %s\n",
13730 strerror(errno));
13731 destroy_dahdi_pvt(pvt);
13732 return -1;
13733 }
13734 memset(&bi, 0, sizeof(bi));
13735 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13736 if (!res) {
13737 pvt->bufsize = bi.bufsize;
13738 bi.txbufpolicy = pvt->buf_policy;
13739 bi.rxbufpolicy = pvt->buf_policy;
13740 bi.numbufs = pvt->buf_no;
13741 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13742 if (res < 0) {
13744 "Unable to set buffer policy on no B channel interface: %s\n",
13745 strerror(errno));
13746 }
13747 } else
13749 "Unable to check buffer policy on no B channel interface: %s\n",
13750 strerror(errno));
13751
13752 --nobch_channel;
13753 if (CHAN_PSEUDO < nobch_channel) {
13754 nobch_channel = CHAN_PSEUDO - 1;
13755 }
13756 pvt->channel = nobch_channel;
13757 pvt->span = pri->span;
13758 chan->channel = pvt->channel;
13759
13760 dahdi_nobch_insert(pri, pvt);
13761
13762 return pvt_idx;
13763}
13764#endif /* defined(HAVE_PRI) */
13765
13766/* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13767 structures; it makes no attempt to safely copy regular channel private
13768 structures that might contain reference-counted object pointers and other
13769 scary bits
13770*/
13771static struct dahdi_pvt *duplicate_pseudo(struct dahdi_pvt *src)
13772{
13773 struct dahdi_pvt *p;
13774 struct dahdi_bufferinfo bi;
13775 int res;
13776
13777 p = ast_malloc(sizeof(*p));
13778 if (!p) {
13779 return NULL;
13780 }
13781 *p = *src;
13782
13783 /* Must deep copy the cc_params. */
13785 if (!p->cc_params) {
13786 ast_free(p);
13787 return NULL;
13788 }
13790
13792 p->next = NULL;
13793 p->prev = NULL;
13794 ast_mutex_init(&p->lock);
13795 p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13796 if (p->subs[SUB_REAL].dfd < 0) {
13797 ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
13799 return NULL;
13800 }
13801 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13802 if (!res) {
13803 bi.txbufpolicy = src->buf_policy;
13804 bi.rxbufpolicy = src->buf_policy;
13805 bi.numbufs = src->buf_no;
13806 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13807 if (res < 0) {
13808 ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
13809 }
13810 } else
13811 ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
13812 p->destroy = 1;
13814 return p;
13815}
13816
13818 /*! Group matching mask. Zero if not specified. */
13820 /*! DAHDI channel to match with. -1 if not specified. */
13822 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13824 /*! ISDN span where channels can be picked (Zero if not specified) */
13825 int span;
13826 /*! Analog channel distinctive ring cadence index. */
13828 /*! Dialing option. c/r/d if present and valid. */
13829 char opt;
13830 /*! TRUE if to search the channel list backwards. */
13832 /*! TRUE if search is done with round robin sequence. */
13834};
13835static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi_starting_point *param)
13836{
13837 char *dest;
13838 char *s;
13839 int x;
13840 int res = 0;
13841 struct dahdi_pvt *p;
13842 char *subdir = NULL;
13844 AST_APP_ARG(group); /* channel/group token */
13845 //AST_APP_ARG(ext); /* extension token */
13846 //AST_APP_ARG(opts); /* options token */
13847 AST_APP_ARG(other); /* Any remaining unused arguments */
13848 );
13849
13850 /*
13851 * data is ---v
13852 * Dial(DAHDI/pseudo[/extension[/options]])
13853 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13854 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13855 * Dial(DAHDI/i<span>[/extension[/options]])
13856 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13857 *
13858 * i - ISDN span channel restriction.
13859 * Used by CC to ensure that the CC recall goes out the same span.
13860 * Also to make ISDN channel names dialable when the sequence number
13861 * is stripped off. (Used by DTMF attended transfer feature.)
13862 *
13863 * g - channel group allocation search forward
13864 * G - channel group allocation search backward
13865 * r - channel group allocation round robin search forward
13866 * R - channel group allocation round robin search backward
13867 *
13868 * c - Wait for DTMF digit to confirm answer
13869 * r<cadence#> - Set distinctive ring cadence number
13870 * d - Force bearer capability for ISDN/SS7 call to digital.
13871 */
13872
13873 if (data) {
13874 dest = ast_strdupa(data);
13875 } else {
13876 ast_log(LOG_WARNING, "Channel requested with no data\n");
13877 return NULL;
13878 }
13879 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
13880 if (!args.argc || ast_strlen_zero(args.group)) {
13881 ast_log(LOG_WARNING, "No channel/group specified\n");
13882 return NULL;
13883 }
13884
13885 /* Initialize the output parameters */
13886 memset(param, 0, sizeof(*param));
13887 param->channelmatch = -1;
13888
13889 if (strchr(args.group, '!') != NULL) {
13890 char *prev = args.group;
13891 while ((s = strchr(prev, '!')) != NULL) {
13892 *s++ = '/';
13893 prev = s;
13894 }
13895 *(prev - 1) = '\0';
13896 subdir = args.group;
13897 args.group = prev;
13898 } else if (args.group[0] == 'i') {
13899 /* Extract the ISDN span channel restriction specifier. */
13900 res = sscanf(args.group + 1, "%30d", &x);
13901 if (res < 1) {
13902 ast_log(LOG_WARNING, "Unable to determine ISDN span for data %s\n", data);
13903 return NULL;
13904 }
13905 param->span = x;
13906
13907 /* Remove the ISDN span channel restriction specifier. */
13908 s = strchr(args.group, '-');
13909 if (!s) {
13910 /* Search all groups since we are ISDN span restricted. */
13911 return iflist;
13912 }
13913 args.group = s + 1;
13914 res = 0;
13915 }
13916 if (toupper(args.group[0]) == 'G' || toupper(args.group[0])=='R') {
13917 /* Retrieve the group number */
13918 s = args.group + 1;
13919 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13920 if (res < 1) {
13921 ast_log(LOG_WARNING, "Unable to determine group for data %s\n", data);
13922 return NULL;
13923 }
13924 param->groupmatch = ((ast_group_t) 1 << x);
13925
13926 if (toupper(args.group[0]) == 'G') {
13927 if (args.group[0] == 'G') {
13928 param->backwards = 1;
13929 p = ifend;
13930 } else
13931 p = iflist;
13932 } else {
13933 if (ARRAY_LEN(round_robin) <= x) {
13934 ast_log(LOG_WARNING, "Round robin index %d out of range for data %s\n",
13935 x, data);
13936 return NULL;
13937 }
13938 if (args.group[0] == 'R') {
13939 param->backwards = 1;
13940 p = round_robin[x] ? round_robin[x]->prev : ifend;
13941 if (!p)
13942 p = ifend;
13943 } else {
13944 p = round_robin[x] ? round_robin[x]->next : iflist;
13945 if (!p)
13946 p = iflist;
13947 }
13948 param->roundrobin = 1;
13949 param->rr_starting_point = x;
13950 }
13951 } else {
13952 s = args.group;
13953 if (!strcasecmp(s, "pseudo")) {
13954 /* Special case for pseudo */
13955 x = CHAN_PSEUDO;
13956 param->channelmatch = x;
13957 } else {
13958 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13959 if (res < 1) {
13960 ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", data);
13961 return NULL;
13962 } else {
13963 param->channelmatch = x;
13964 }
13965 }
13966 if (subdir) {
13967 char path[PATH_MAX];
13968 struct stat stbuf;
13969
13970 snprintf(path, sizeof(path), "/dev/dahdi/%s/%d",
13971 subdir, param->channelmatch);
13972 if (stat(path, &stbuf) < 0) {
13973 ast_log(LOG_WARNING, "stat(%s) failed: %s\n",
13974 path, strerror(errno));
13975 return NULL;
13976 }
13977 if (!S_ISCHR(stbuf.st_mode)) {
13978 ast_log(LOG_ERROR, "%s: Not a character device file\n",
13979 path);
13980 return NULL;
13981 }
13982 param->channelmatch = minor(stbuf.st_rdev);
13983 }
13984
13985 p = iflist;
13986 }
13987
13988 if (param->opt == 'r' && res < 3) {
13989 ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", data);
13990 param->opt = '\0';
13991 }
13992
13993 return p;
13994}
13995
13996static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
13997 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
13998 const char *data, int *cause)
13999{
14000 int callwait = 0;
14001 struct dahdi_pvt *p;
14002 struct ast_channel *tmp = NULL;
14003 struct dahdi_pvt *exitpvt;
14004 int channelmatched = 0;
14005 int foundowner = 0;
14006 int groupmatched = 0;
14007#if defined(HAVE_PRI) || defined(HAVE_SS7)
14008 int transcapdigital = 0;
14009#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14010 struct dahdi_starting_point start;
14011 ast_callid callid = 0;
14012 int callid_created = ast_callid_threadstorage_auto(&callid);
14013
14015 p = determine_starting_point(data, &start);
14016 if (!p) {
14017 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
14019 ast_callid_threadstorage_auto_clean(callid, callid_created);
14020 return NULL;
14021 }
14022
14023 /* Search for an unowned channel */
14024 exitpvt = p;
14025 while (p && !tmp) {
14026 if (start.roundrobin)
14027 round_robin[start.rr_starting_point] = p;
14028
14029 if (p->owner) {
14030 foundowner++;
14031 }
14032
14033 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
14034 && available(&p, channelmatched)) {
14035 ast_debug(1, "Using channel %d\n", p->channel);
14036
14037 callwait = (p->owner != NULL);
14038#ifdef HAVE_OPENR2
14039 if (p->mfcr2) {
14040 ast_mutex_lock(&p->lock);
14041 if (p->mfcr2call) {
14043 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
14044 goto next;
14045 }
14046 p->mfcr2call = 1;
14048 }
14049#endif
14050 if (p->channel == CHAN_PSEUDO) {
14051 p = duplicate_pseudo(p);
14052 if (!p) {
14053 break;
14054 }
14055 }
14056
14057 p->distinctivering = 0;
14058 /* Make special notes */
14059 switch (start.opt) {
14060 case '\0':
14061 /* No option present. */
14062 break;
14063 case 'c':
14064 /* Confirm answer */
14065 p->confirmanswer = 1;
14066 break;
14067 case 'r':
14068 /* Distinctive ring */
14069 p->distinctivering = start.cadence;
14070 break;
14071 case 'd':
14072#if defined(HAVE_PRI) || defined(HAVE_SS7)
14073 /* If this is an ISDN call, make it digital */
14074 transcapdigital = AST_TRANS_CAP_DIGITAL;
14075#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14076 break;
14077 default:
14078 ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", start.opt, data);
14079 break;
14080 }
14081
14082 p->outgoing = 1;
14083 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
14084 tmp = analog_request(p->sig_pvt, &callwait, requestor);
14085#ifdef HAVE_PRI
14086 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
14087 /*
14088 * We already have the B channel reserved for this call. We
14089 * just need to make sure that dahdi_hangup() has completed
14090 * cleaning up before continuing.
14091 */
14092 ast_mutex_lock(&p->lock);
14094
14096 sizeof(p->dnid));
14097 tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, assignedids, requestor, transcapdigital);
14098#endif
14099#if defined(HAVE_SS7)
14100 } else if (p->sig == SIG_SS7) {
14101 tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, assignedids, requestor, transcapdigital);
14102#endif /* defined(HAVE_SS7) */
14103 } else {
14104 tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, assignedids, requestor, callid);
14105 }
14106 if (!tmp) {
14107 p->outgoing = 0;
14108#if defined(HAVE_PRI)
14109 switch (p->sig) {
14111#if defined(HAVE_PRI_CALL_WAITING)
14112 if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
14113 ((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
14114 ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
14115 }
14116#endif /* defined(HAVE_PRI_CALL_WAITING) */
14117 /*
14118 * This should be the last thing to clear when we are done with
14119 * the channel.
14120 */
14121 ((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
14122 break;
14123 default:
14124 break;
14125 }
14126#endif /* defined(HAVE_PRI) */
14127 } else {
14128 snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", data);
14129 }
14130 break;
14131 }
14132#ifdef HAVE_OPENR2
14133next:
14134#endif
14135 if (start.backwards) {
14136 p = p->prev;
14137 if (!p)
14138 p = ifend;
14139 } else {
14140 p = p->next;
14141 if (!p)
14142 p = iflist;
14143 }
14144 /* stop when you roll to the one that we started from */
14145 if (p == exitpvt)
14146 break;
14147 }
14150 if (cause && !tmp) {
14151 if (callwait || (channelmatched && foundowner)) {
14152 *cause = AST_CAUSE_BUSY;
14153 } else if (groupmatched) {
14154 *cause = AST_CAUSE_CONGESTION;
14155 } else {
14156 /*
14157 * We did not match any channel requested.
14158 * Dialplan error requesting non-existant channel?
14159 */
14160 }
14161 }
14162
14163 ast_callid_threadstorage_auto_clean(callid, callid_created);
14164 return tmp;
14165}
14166
14167/*!
14168 * \internal
14169 * \brief Determine the device state for a given DAHDI device if we can.
14170 * \since 1.8
14171 *
14172 * \param data DAHDI device name after "DAHDI/".
14173 *
14174 * \retval device_state enum ast_device_state value.
14175 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
14176 */
14177static int dahdi_devicestate(const char *data)
14178{
14179#if defined(HAVE_PRI)
14180 const char *device;
14181 unsigned span;
14182 int res;
14183
14184 device = data;
14185
14186 if (*device != 'I') {
14187 /* The request is not for an ISDN span device. */
14188 return AST_DEVICE_UNKNOWN;
14189 }
14190 res = sscanf(device, "I%30u", &span);
14191 if (res != 1 || !span || NUM_SPANS < span) {
14192 /* Bad format for ISDN span device name. */
14193 return AST_DEVICE_UNKNOWN;
14194 }
14195 device = strchr(device, '/');
14196 if (!device) {
14197 /* Bad format for ISDN span device name. */
14198 return AST_DEVICE_UNKNOWN;
14199 }
14200
14201 /*
14202 * Since there are currently no other span devstate's defined,
14203 * it must be congestion.
14204 */
14205#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14206 ++device;
14207 if (!strcmp(device, "congestion"))
14208#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14209 {
14210 return pris[span - 1].pri.congestion_devstate;
14211 }
14212#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14213 else if (!strcmp(device, "threshold")) {
14214 return pris[span - 1].pri.threshold_devstate;
14215 }
14216 return AST_DEVICE_UNKNOWN;
14217#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14218#else
14219 return AST_DEVICE_UNKNOWN;
14220#endif /* defined(HAVE_PRI) */
14221}
14222
14223/*!
14224 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14225 * \since 1.8
14226 *
14227 * \param inbound Incoming asterisk channel.
14228 * \param dest Same dial string passed to dahdi_request().
14229 * \param callback Callback into CC core to announce a busy channel available for CC.
14230 *
14231 * \details
14232 * This callback acts like a forked dial with all prongs of the fork busy.
14233 * Essentially, for each channel that could have taken the call, indicate that
14234 * it is busy.
14235 *
14236 * \retval 0 on success.
14237 * \retval -1 on error.
14238 */
14239static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
14240{
14241 struct dahdi_pvt *p;
14242 struct dahdi_pvt *exitpvt;
14243 struct dahdi_starting_point start;
14244 int groupmatched = 0;
14245 int channelmatched = 0;
14246
14248 p = determine_starting_point(dest, &start);
14249 if (!p) {
14251 return -1;
14252 }
14253 exitpvt = p;
14254 for (;;) {
14255 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)) {
14256 /* We found a potential match. call the callback */
14257 struct ast_str *device_name;
14258 char *dash;
14259 const char *monitor_type;
14260 char dialstring[AST_CHANNEL_NAME];
14261 char full_device_name[AST_CHANNEL_NAME];
14262
14265 break;
14269#if defined(HAVE_PRI)
14271 /*
14272 * ISDN is in a trunk busy condition so we need to monitor
14273 * the span congestion device state.
14274 */
14275 snprintf(full_device_name, sizeof(full_device_name),
14276 "DAHDI/I%d/congestion", p->pri->span);
14277 } else
14278#endif /* defined(HAVE_PRI) */
14279 {
14280#if defined(HAVE_PRI)
14281 device_name = create_channel_name(p, 1, "");
14282#else
14283 device_name = create_channel_name(p);
14284#endif /* defined(HAVE_PRI) */
14285 snprintf(full_device_name, sizeof(full_device_name), "DAHDI/%s",
14286 device_name ? ast_str_buffer(device_name) : "");
14287 ast_free(device_name);
14288 /*
14289 * The portion after the '-' in the channel name is either a random
14290 * number, a sequence number, or a subchannel number. None are
14291 * necessary so strip them off.
14292 */
14293 dash = strrchr(full_device_name, '-');
14294 if (dash) {
14295 *dash = '\0';
14296 }
14297 }
14298 snprintf(dialstring, sizeof(dialstring), "DAHDI/%s", dest);
14299
14300 /*
14301 * Analog can only do generic monitoring.
14302 * ISDN is in a trunk busy condition and any "device" is going
14303 * to be busy until a B channel becomes available. The generic
14304 * monitor can do this task.
14305 */
14306 monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
14307 callback(inbound,
14308#if defined(HAVE_PRI)
14309 p->pri ? p->pri->cc_params : p->cc_params,
14310#else
14311 p->cc_params,
14312#endif /* defined(HAVE_PRI) */
14313 monitor_type, full_device_name, dialstring, NULL);
14314 break;
14315 }
14316 }
14317 p = start.backwards ? p->prev : p->next;
14318 if (!p) {
14319 p = start.backwards ? ifend : iflist;
14320 }
14321 if (p == exitpvt) {
14322 break;
14323 }
14324 }
14326 return 0;
14327}
14328
14329#if defined(HAVE_SS7)
14330static void dahdi_ss7_message(struct ss7 *ss7, char *s)
14331{
14332 int i;
14333
14334 if (ss7) {
14335 for (i = 0; i < NUM_SPANS; i++) {
14336 if (linksets[i].ss7.ss7 == ss7) {
14337 ast_verbose_callid(0, "[%d] %s", i + 1, s);
14338 return;
14339 }
14340 }
14341 }
14342 ast_verbose_callid(0, "%s", s);
14343}
14344#endif /* defined(HAVE_SS7) */
14345
14346#if defined(HAVE_SS7)
14347static void dahdi_ss7_error(struct ss7 *ss7, char *s)
14348{
14349 int i;
14350
14351 if (ss7) {
14352 for (i = 0; i < NUM_SPANS; i++) {
14353 if (linksets[i].ss7.ss7 == ss7) {
14354 ast_log_callid(LOG_ERROR, 0, "[%d] %s", i + 1, s);
14355 return;
14356 }
14357 }
14358 }
14359 ast_log_callid(LOG_ERROR, 0, "%s", s);
14360}
14361#endif /* defined(HAVE_SS7) */
14362
14363#if defined(HAVE_OPENR2)
14364static void *mfcr2_monitor(void *data)
14365{
14366 struct dahdi_mfcr2 *mfcr2 = data;
14367 struct dahdi_pvt *pvt;
14368
14369 /* we should be using pthread_key_create
14370 and allocate pollers dynamically.
14371 I think do_monitor() could be leaking, since it
14372 could be cancelled at any time and is not
14373 using thread keys, why?, */
14374 struct pollfd pollers[ARRAY_LEN(mfcr2->pvts)];
14375 int res = 0;
14376 int i = 0;
14377 int oldstate = 0;
14378 int quit_loop = 0;
14379 int maxsleep = 20;
14380 int was_idle = 0;
14381 int pollsize = 0;
14382 /* now that we're ready to get calls, unblock our side and
14383 get current line state */
14384 for (i = 0; i < mfcr2->numchans; i++) {
14385 pvt = mfcr2->pvts[i];
14386 if (!pvt) {
14387 continue;
14388 }
14389 openr2_chan_set_idle(pvt->r2chan);
14390 openr2_chan_handle_cas(pvt->r2chan);
14391 }
14392 while (1) {
14393 /* we trust here that the mfcr2 channel list will not ever change once
14394 the module is loaded */
14395 pollsize = 0;
14396 for (i = 0; i < mfcr2->numchans; i++) {
14397 pollers[i].revents = 0;
14398 pollers[i].events = 0;
14399 pvt = mfcr2->pvts[i];
14400 if (!pvt) {
14401 continue;
14402 }
14403 if (pvt->owner) {
14404 continue;
14405 }
14406 if (mfcr2->nodev) {
14407 continue;
14408 }
14409 if (!pvt->r2chan) {
14410 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
14411 quit_loop = 1;
14412 break;
14413 }
14414 openr2_chan_enable_read(pvt->r2chan);
14415 pollers[i].events = POLLIN | POLLPRI;
14416 pollers[i].fd = pvt->subs[SUB_REAL].dfd;
14417 pollsize++;
14418 }
14419 if (quit_loop) {
14420 break;
14421 }
14422 if (pollsize == 0) {
14423 if (!was_idle) {
14424 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14425 was_idle = 1;
14426 }
14427 poll(NULL, 0, maxsleep);
14428 continue;
14429 }
14430 was_idle = 0;
14431 /* probably poll() is a valid cancel point, lets just be on the safe side
14432 by calling pthread_testcancel */
14433 pthread_testcancel();
14434 res = poll(pollers, mfcr2->numchans, maxsleep);
14435 pthread_testcancel();
14436 if ((res < 0) && (errno != EINTR)) {
14437 ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
14438 break;
14439 }
14440 /* do we want to allow to cancel while processing events? */
14441 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
14442 for (i = 0; i < mfcr2->numchans; i++) {
14443 pvt = mfcr2->pvts[i];
14444 if (!pvt) {
14445 continue;
14446 }
14447 if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
14448 openr2_chan_process_event(pvt->r2chan);
14449 }
14450 }
14451 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
14452 }
14453 ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
14454 return 0;
14455}
14456#endif /* HAVE_OPENR2 */
14457
14458#if defined(HAVE_PRI)
14459static void dahdi_pri_message(struct pri *pri, char *s)
14460{
14461 int x;
14462 int y;
14463 int dchan = -1;
14464 int span = -1;
14465 int dchancount = 0;
14466
14467 if (pri) {
14468 for (x = 0; x < NUM_SPANS; x++) {
14469 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14470 if (pris[x].pri.dchans[y]) {
14471 dchancount++;
14472 }
14473
14474 if (pris[x].pri.dchans[y] == pri) {
14475 dchan = y;
14476 }
14477 }
14478 if (dchan >= 0) {
14479 span = x;
14480 break;
14481 }
14482 dchancount = 0;
14483 }
14484 if (-1 < span) {
14485 if (1 < dchancount) {
14486 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14487 } else {
14488 ast_verbose_callid(0, "PRI Span: %d %s", span + 1, s);
14489 }
14490 } else {
14491 ast_verbose_callid(0, "PRI Span: ? %s", s);
14492 }
14493 } else {
14494 ast_verbose_callid(0, "PRI Span: ? %s", s);
14495 }
14496
14497 ast_mutex_lock(&pridebugfdlock);
14498
14499 if (pridebugfd >= 0) {
14500 if (write(pridebugfd, s, strlen(s)) < 0) {
14501 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14502 }
14503 }
14504
14505 ast_mutex_unlock(&pridebugfdlock);
14506}
14507#endif /* defined(HAVE_PRI) */
14508
14509#if defined(HAVE_PRI)
14510static void dahdi_pri_error(struct pri *pri, char *s)
14511{
14512 int x;
14513 int y;
14514 int dchan = -1;
14515 int span = -1;
14516 int dchancount = 0;
14517
14518 if (pri) {
14519 for (x = 0; x < NUM_SPANS; x++) {
14520 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14521 if (pris[x].pri.dchans[y]) {
14522 dchancount++;
14523 }
14524
14525 if (pris[x].pri.dchans[y] == pri) {
14526 dchan = y;
14527 }
14528 }
14529 if (dchan >= 0) {
14530 span = x;
14531 break;
14532 }
14533 dchancount = 0;
14534 }
14535 if (-1 < span) {
14536 if (1 < dchancount) {
14537 ast_log_callid(LOG_ERROR, 0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14538 } else {
14539 ast_log_callid(LOG_ERROR, 0, "PRI Span: %d %s", span + 1, s);
14540 }
14541 } else {
14542 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14543 }
14544 } else {
14545 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14546 }
14547
14548 ast_mutex_lock(&pridebugfdlock);
14549
14550 if (pridebugfd >= 0) {
14551 if (write(pridebugfd, s, strlen(s)) < 0) {
14552 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14553 }
14554 }
14555
14556 ast_mutex_unlock(&pridebugfdlock);
14557}
14558#endif /* defined(HAVE_PRI) */
14559
14560#if defined(HAVE_PRI)
14561static int prepare_pri(struct dahdi_pri *pri)
14562{
14563 int i, res, x;
14564 struct dahdi_params p;
14565 struct dahdi_bufferinfo bi;
14566 struct dahdi_spaninfo si;
14567
14568 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
14569 if (!pri->dchannels[i])
14570 break;
14571 if (pri->pri.fds[i] >= 0) {
14572 /* A partial range addition. Not a complete setup. */
14573 break;
14574 }
14575 pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
14576 if ((pri->pri.fds[i] < 0)) {
14577 ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
14578 pri->pri.fds[i], strerror(errno));
14579 return -1;
14580 }
14581 x = pri->dchannels[i];
14582 res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
14583 if (res) {
14584 dahdi_close_pri_fd(pri, i);
14585 ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
14586 return -1;
14587 }
14588 memset(&p, 0, sizeof(p));
14589 res = ioctl(pri->pri.fds[i], DAHDI_GET_PARAMS, &p);
14590 if (res) {
14591 dahdi_close_pri_fd(pri, i);
14592 ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
14593 return -1;
14594 }
14595 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
14596 dahdi_close_pri_fd(pri, i);
14597 ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
14598 return -1;
14599 }
14600 memset(&si, 0, sizeof(si));
14601 res = ioctl(pri->pri.fds[i], DAHDI_SPANSTAT, &si);
14602 if (res) {
14603 dahdi_close_pri_fd(pri, i);
14604 ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
14605 }
14606 if (!si.alarms) {
14607 pri_event_noalarm(&pri->pri, i, 1);
14608 } else {
14609 pri_event_alarm(&pri->pri, i, 1);
14610 }
14611 memset(&bi, 0, sizeof(bi));
14612 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
14613 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
14614 bi.numbufs = 32;
14615 bi.bufsize = 1024;
14616 if (ioctl(pri->pri.fds[i], DAHDI_SET_BUFINFO, &bi)) {
14617 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
14618 dahdi_close_pri_fd(pri, i);
14619 return -1;
14620 }
14621 pri->pri.dchan_logical_span[i] = pris[p.spanno - 1].prilogicalspan;
14622 }
14623 return 0;
14624}
14625#endif /* defined(HAVE_PRI) */
14626
14627#if defined(HAVE_PRI)
14628static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
14629{
14630 int which, span;
14631 char *ret = NULL;
14632
14633 if (pos != rpos)
14634 return ret;
14635
14636 for (which = span = 0; span < NUM_SPANS; span++) {
14637 if (pris[span].pri.pri && ++which > state) {
14638 if (ast_asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
14639 ret = NULL;
14640 }
14641 break;
14642 }
14643 }
14644 return ret;
14645}
14646#endif /* defined(HAVE_PRI) */
14647
14648#if defined(HAVE_PRI)
14649static char *complete_span_4(const char *line, const char *word, int pos, int state)
14650{
14651 return complete_span_helper(line,word,pos,state,3);
14652}
14653#endif /* defined(HAVE_PRI) */
14654
14655#if defined(HAVE_PRI)
14656static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14657{
14658 int myfd;
14659 switch (cmd) {
14660 case CLI_INIT:
14661 e->command = "pri set debug file";
14662 e->usage = "Usage: pri set debug file [output-file]\n"
14663 " Sends PRI debug output to the specified output file\n";
14664 return NULL;
14665 case CLI_GENERATE:
14666 return NULL;
14667 }
14668 if (a->argc < 5)
14669 return CLI_SHOWUSAGE;
14670
14671 if (ast_strlen_zero(a->argv[4]))
14672 return CLI_SHOWUSAGE;
14673
14674 myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
14675 if (myfd < 0) {
14676 ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
14677 return CLI_SUCCESS;
14678 }
14679
14680 ast_mutex_lock(&pridebugfdlock);
14681
14682 if (pridebugfd >= 0)
14683 close(pridebugfd);
14684
14685 pridebugfd = myfd;
14686 ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
14687 ast_mutex_unlock(&pridebugfdlock);
14688 ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
14689 return CLI_SUCCESS;
14690}
14691#endif /* defined(HAVE_PRI) */
14692
14693#if defined(HAVE_PRI)
14694static int action_pri_debug_file_set(struct mansession *s, const struct message *m)
14695{
14696 const char *output_file = astman_get_header(m, "File");
14697 int myfd;
14698
14699 if (ast_strlen_zero(output_file)) {
14700 astman_send_error(s, m, "Action must define a 'File'");
14701 }
14702
14703 myfd = open(output_file, O_CREAT|O_WRONLY, AST_FILE_MODE);
14704 if (myfd < 0) {
14705 astman_send_error(s, m, "Unable to open requested file for writing");
14706 return 0;
14707 }
14708
14709 ast_mutex_lock(&pridebugfdlock);
14710
14711 if (pridebugfd >= 0) {
14712 close(pridebugfd);
14713 }
14714
14715 pridebugfd = myfd;
14716 ast_copy_string(pridebugfilename, output_file, sizeof(pridebugfilename));
14717 ast_mutex_unlock(&pridebugfdlock);
14718 astman_send_ack(s, m, "PRI debug output will now be sent to requested file.");
14719
14720 return 0;
14721}
14722#endif /* defined(HAVE_PRI) */
14723
14724#if defined(HAVE_PRI)
14725static int action_pri_debug_file_unset(struct mansession *s, const struct message *m)
14726{
14727 ast_mutex_lock(&pridebugfdlock);
14728
14729 if (pridebugfd >= 0) {
14730 close(pridebugfd);
14731 }
14732
14733 pridebugfd = -1;
14734
14735 ast_mutex_unlock(&pridebugfdlock);
14736
14737 astman_send_ack(s, m, "PRI Debug output to file disabled");
14738 return 0;
14739}
14740#endif /* defined(HAVE_PRI) */
14741
14742#if defined(HAVE_PRI)
14743static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14744{
14745 int span;
14746 int x;
14747 int debugmask = 0;
14748 int level = 0;
14749 switch (cmd) {
14750 case CLI_INIT:
14751 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";
14752 e->usage =
14753 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14754 " Enables debugging on a given PRI span\n"
14755 " Level is a bitmap of the following values:\n"
14756 " 1 General debugging incl. state changes\n"
14757 " 2 Decoded Q.931 messages\n"
14758 " 4 Decoded Q.921 messages\n"
14759 " 8 Raw hex dumps of Q.921 frames\n"
14760 " on - equivalent to 3\n"
14761 " hex - equivalent to 8\n"
14762 " intense - equivalent to 15\n";
14763 return NULL;
14764 case CLI_GENERATE:
14765 return complete_span_4(a->line, a->word, a->pos, a->n);
14766 }
14767 if (a->argc < 6) {
14768 return CLI_SHOWUSAGE;
14769 }
14770
14771 if (!strcasecmp(a->argv[3], "on")) {
14772 level = 3;
14773 } else if (!strcasecmp(a->argv[3], "off")) {
14774 level = 0;
14775 } else if (!strcasecmp(a->argv[3], "intense")) {
14776 level = 15;
14777 } else if (!strcasecmp(a->argv[3], "hex")) {
14778 level = 8;
14779 } else {
14780 level = atoi(a->argv[3]);
14781 }
14782 span = atoi(a->argv[5]);
14783 if ((span < 1) || (span > NUM_SPANS)) {
14784 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[5], 1, NUM_SPANS);
14785 return CLI_SUCCESS;
14786 }
14787 if (!pris[span-1].pri.pri) {
14788 ast_cli(a->fd, "No PRI running on span %d\n", span);
14789 return CLI_SUCCESS;
14790 }
14791
14792 if (level & 1) debugmask |= SIG_PRI_DEBUG_NORMAL;
14793 if (level & 2) debugmask |= PRI_DEBUG_Q931_DUMP;
14794 if (level & 4) debugmask |= PRI_DEBUG_Q921_DUMP;
14795 if (level & 8) debugmask |= PRI_DEBUG_Q921_RAW;
14796
14797 /* Set debug level in libpri */
14798 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14799 if (pris[span - 1].pri.dchans[x]) {
14800 pri_set_debug(pris[span - 1].pri.dchans[x], debugmask);
14801 }
14802 }
14803 if (level == 0) {
14804 /* Close the debugging file if it's set */
14805 ast_mutex_lock(&pridebugfdlock);
14806 if (0 <= pridebugfd) {
14807 close(pridebugfd);
14808 pridebugfd = -1;
14809 ast_cli(a->fd, "Disabled PRI debug output to file '%s'\n",
14810 pridebugfilename);
14811 }
14812 ast_mutex_unlock(&pridebugfdlock);
14813 }
14814 pris[span - 1].pri.debug = (level) ? 1 : 0;
14815 ast_cli(a->fd, "%s debugging on span %d\n", (level) ? "Enabled" : "Disabled", span);
14816 return CLI_SUCCESS;
14817}
14818#endif /* defined(HAVE_PRI) */
14819
14820#if defined(HAVE_PRI)
14821static int action_pri_debug_set(struct mansession *s, const struct message *m)
14822{
14823 const char *level = astman_get_header(m, "Level");
14824 const char *span = astman_get_header(m, "Span");
14825 int level_val;
14826 int span_val;
14827 int x;
14828 int debugmask = 0;
14829
14830 if (ast_strlen_zero(level)) {
14831 astman_send_error(s, m, "'Level' was not specified");
14832 return 0;
14833 }
14834
14835 if (ast_strlen_zero(span)) {
14836 astman_send_error(s, m, "'Span' was not specified");
14837 return 0;
14838 }
14839
14840 if (!strcasecmp(level, "on")) {
14841 level_val = 3;
14842 } else if (!strcasecmp(level, "off")) {
14843 level_val = 0;
14844 } else if (!strcasecmp(level, "intense")) {
14845 level_val = 15;
14846 } else if (!strcasecmp(level, "hex")) {
14847 level_val = 8;
14848 } else {
14849 if (sscanf(level, "%30d", &level_val) != 1) {
14850 astman_send_error(s, m, "Invalid value for 'Level'");
14851 return 0;
14852 }
14853 }
14854
14855 if (sscanf(span, "%30d", &span_val) != 1) {
14856 astman_send_error(s, m, "Invalid value for 'Span'");
14857 }
14858
14859 if ((span_val < 1) || (span_val > NUM_SPANS)) {
14860 const char *id = astman_get_header(m, "ActionID");
14861 char id_text[256] = "";
14862
14863 if (!ast_strlen_zero(id)) {
14864 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
14865 }
14866
14867 astman_append(s, "Response: Error\r\n"
14868 "%s" /* id_text */
14869 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14870 "\r\n",
14871 id_text,
14872 span, NUM_SPANS);
14873
14874 return 0;
14875 }
14876
14877 if (!pris[span_val-1].pri.pri) {
14878 astman_send_error(s, m, "No PRI running on requested span");
14879 return 0;
14880 }
14881
14882 if (level_val & 1) {
14883 debugmask |= SIG_PRI_DEBUG_NORMAL;
14884 }
14885 if (level_val & 2) {
14886 debugmask |= PRI_DEBUG_Q931_DUMP;
14887 }
14888 if (level_val & 4) {
14889 debugmask |= PRI_DEBUG_Q921_DUMP;
14890 }
14891 if (level_val & 8) {
14892 debugmask |= PRI_DEBUG_Q921_RAW;
14893 }
14894
14895 /* Set debug level in libpri */
14896 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14897 if (pris[span_val - 1].pri.dchans[x]) {
14898 pri_set_debug(pris[span_val - 1].pri.dchans[x], debugmask);
14899 }
14900 }
14901
14902 pris[span_val - 1].pri.debug = (level_val) ? 1 : 0;
14903 astman_send_ack(s, m, "Debug level set for requested span");
14904
14905 return 0;
14906}
14907#endif /* defined(HAVE_PRI) */
14908
14909#if defined(HAVE_PRI)
14910#if defined(HAVE_PRI_SERVICE_MESSAGES)
14911static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
14912{
14913 unsigned *why;
14914 int channel;
14915 int trunkgroup;
14916 int x, y, fd = a->fd;
14917 int interfaceid = 0;
14918 char db_chan_name[20], db_answer[15];
14919 struct dahdi_pvt *tmp;
14920 struct dahdi_pri *pri;
14921
14922 if (a->argc < 5 || a->argc > 6)
14923 return CLI_SHOWUSAGE;
14924 if (strchr(a->argv[4], ':')) {
14925 if (sscanf(a->argv[4], "%30d:%30d", &trunkgroup, &channel) != 2)
14926 return CLI_SHOWUSAGE;
14927 if ((trunkgroup < 1) || (channel < 1))
14928 return CLI_SHOWUSAGE;
14929 pri = NULL;
14930 for (x=0;x<NUM_SPANS;x++) {
14931 if (pris[x].pri.trunkgroup == trunkgroup) {
14932 pri = pris + x;
14933 break;
14934 }
14935 }
14936 if (!pri) {
14937 ast_cli(fd, "No such trunk group %d\n", trunkgroup);
14938 return CLI_FAILURE;
14939 }
14940 } else
14941 channel = atoi(a->argv[4]);
14942
14943 if (a->argc == 6)
14944 interfaceid = atoi(a->argv[5]);
14945
14946 /* either servicing a D-Channel */
14947 for (x = 0; x < NUM_SPANS; x++) {
14948 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14949 if (pris[x].dchannels[y] == channel) {
14950 pri = pris + x;
14951 if (pri->pri.enable_service_message_support) {
14952 ast_mutex_lock(&pri->pri.lock);
14953 pri_maintenance_service(pri->pri.pri, interfaceid, -1, changestatus);
14954 ast_mutex_unlock(&pri->pri.lock);
14955 } else {
14956 ast_cli(fd,
14957 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14958 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14959 }
14960 return CLI_SUCCESS;
14961 }
14962 }
14963 }
14964
14965 /* or servicing a B-Channel */
14967 for (tmp = iflist; tmp; tmp = tmp->next) {
14968 if (tmp->pri && tmp->channel == channel) {
14970 ast_mutex_lock(&tmp->pri->lock);
14971 if (!tmp->pri->enable_service_message_support) {
14972 ast_mutex_unlock(&tmp->pri->lock);
14973 ast_cli(fd,
14974 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14975 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14976 return CLI_SUCCESS;
14977 }
14978 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, channel);
14979 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
14980 switch(changestatus) {
14981 case 0: /* enable */
14982 /* Near end wants to be in service now. */
14983 ast_db_del(db_chan_name, SRVST_DBKEY);
14984 *why &= ~SRVST_NEAREND;
14985 if (*why) {
14986 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
14987 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
14988 } else {
14989 dahdi_pri_update_span_devstate(tmp->pri);
14990 }
14991 break;
14992 /* case 1: -- loop */
14993 case 2: /* disable */
14994 /* Near end wants to be out-of-service now. */
14995 ast_db_del(db_chan_name, SRVST_DBKEY);
14996 *why |= SRVST_NEAREND;
14997 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
14998 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
14999 dahdi_pri_update_span_devstate(tmp->pri);
15000 break;
15001 /* case 3: -- continuity */
15002 /* case 4: -- shutdown */
15003 default:
15004 ast_log(LOG_WARNING, "Unsupported changestatus: '%d'\n", changestatus);
15005 break;
15006 }
15007 pri_maintenance_bservice(tmp->pri->pri, tmp->sig_pvt, changestatus);
15008 ast_mutex_unlock(&tmp->pri->lock);
15009 return CLI_SUCCESS;
15010 }
15011 }
15013
15014 ast_cli(fd, "Unable to find given channel %d, possibly not a PRI\n", channel);
15015 return CLI_FAILURE;
15016}
15017
15018static char *handle_pri_service_enable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15019{
15020 switch (cmd) {
15021 case CLI_INIT:
15022 e->command = "pri service enable channel";
15023 e->usage =
15024 "Usage: pri service enable channel <channel> [<interface id>]\n"
15025 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15026 " to restore a channel to service, with optional interface id\n"
15027 " as agreed upon with remote switch operator\n";
15028 return NULL;
15029 case CLI_GENERATE:
15030 return NULL;
15031 }
15032 return handle_pri_service_generic(e, cmd, a, 0);
15033}
15034
15035static char *handle_pri_service_disable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15036{
15037 switch (cmd) {
15038 case CLI_INIT:
15039 e->command = "pri service disable channel";
15040 e->usage =
15041 "Usage: pri service disable channel <chan num> [<interface id>]\n"
15042 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15043 " to remove a channel from service, with optional interface id\n"
15044 " as agreed upon with remote switch operator\n";
15045 return NULL;
15046 case CLI_GENERATE:
15047 return NULL;
15048 }
15049 return handle_pri_service_generic(e, cmd, a, 2);
15050}
15051#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15052#endif /* defined(HAVE_PRI) */
15053
15054#if defined(HAVE_PRI)
15055static char *handle_pri_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15056{
15057 int span;
15058
15059 switch (cmd) {
15060 case CLI_INIT:
15061 e->command = "pri show channels";
15062 e->usage =
15063 "Usage: pri show channels\n"
15064 " Displays PRI channel information such as the current mapping\n"
15065 " of DAHDI B channels to Asterisk channel names and which calls\n"
15066 " are on hold or call-waiting. Calls on hold or call-waiting\n"
15067 " are not associated with any B channel.\n";
15068 return NULL;
15069 case CLI_GENERATE:
15070 return NULL;
15071 }
15072
15073 if (a->argc != 3)
15074 return CLI_SHOWUSAGE;
15075
15077 for (span = 0; span < NUM_SPANS; ++span) {
15078 if (pris[span].pri.pri) {
15079 sig_pri_cli_show_channels(a->fd, &pris[span].pri);
15080 }
15081 }
15082 return CLI_SUCCESS;
15083}
15084#endif /* defined(HAVE_PRI) */
15085
15086#if defined(HAVE_PRI)
15087static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15088{
15089 int span;
15090
15091 switch (cmd) {
15092 case CLI_INIT:
15093 e->command = "pri show spans";
15094 e->usage =
15095 "Usage: pri show spans\n"
15096 " Displays PRI span information\n";
15097 return NULL;
15098 case CLI_GENERATE:
15099 return NULL;
15100 }
15101
15102 if (a->argc != 3)
15103 return CLI_SHOWUSAGE;
15104
15105 for (span = 0; span < NUM_SPANS; span++) {
15106 if (pris[span].pri.pri) {
15107 sig_pri_cli_show_spans(a->fd, span + 1, &pris[span].pri);
15108 }
15109 }
15110 return CLI_SUCCESS;
15111}
15112#endif /* defined(HAVE_PRI) */
15113
15114#if defined(HAVE_PRI)
15115#define container_of(ptr, type, member) \
15116 ((type *)((char *)(ptr) - offsetof(type, member)))
15117/*!
15118 * \internal
15119 * \brief Destroy a D-Channel of a PRI span
15120 * \since 12
15121 *
15122 * \param pri the pri span
15123 *
15124 * Shuts down a span and destroys its D-Channel. Further destruction
15125 * of the B-channels using dahdi_destroy_channel() would probably be required
15126 * for the B-Channels.
15127 */
15128static void pri_destroy_span(struct sig_pri_span *pri)
15129{
15130 int i;
15131 int res;
15132 int cancel_code;
15133 struct dahdi_pri* dahdi_pri;
15134 pthread_t master = pri->master;
15135
15136 if (!master || (master == AST_PTHREADT_NULL)) {
15137 return;
15138 }
15139 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
15140 for (i = 0; i < pri->numchans; i++) {
15141 int channel;
15142 struct sig_pri_chan *pvt = pri->pvts[i];
15143
15144 if (!pvt) {
15145 continue;
15146 }
15147 channel = pvt->channel;
15148 ast_debug(2, "About to destroy B-channel %d.\n", channel);
15150 }
15151
15152 cancel_code = pthread_cancel(master);
15153 pthread_kill(master, SIGURG);
15154 ast_debug(4,
15155 "Waiting to join thread of span %d "
15156 "with pid=%p cancel_code=%d\n",
15157 pri->span, (void *)master, cancel_code);
15158 res = pthread_join(master, NULL);
15159 if (res != 0) {
15160 ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
15161 }
15163
15164 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
15165 dahdi_pri = container_of(pri, struct dahdi_pri, pri);
15166 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
15167 ast_debug(4, "closing pri_fd %d\n", i);
15168 dahdi_close_pri_fd(dahdi_pri, i);
15169 dahdi_pri->dchannels[i] = 0;
15170 }
15172 ast_debug(1, "PRI span %d destroyed\n", pri->span);
15173}
15174
15175static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
15176 struct ast_cli_args *a)
15177{
15178 int span;
15179 int res;
15180 struct sig_pri_span *pri;
15181
15182 switch (cmd) {
15183 case CLI_INIT:
15184 e->command = "pri destroy span";
15185 e->usage =
15186 "Usage: pri destroy span <span>\n"
15187 " Destroys D-channel of span and its B-channels.\n"
15188 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15189 return NULL;
15190 case CLI_GENERATE:
15191 return complete_span_4(a->line, a->word, a->pos, a->n);
15192 }
15193
15194 if (a->argc < 4) {
15195 return CLI_SHOWUSAGE;
15196 }
15197 res = sscanf(a->argv[3], "%30d", &span);
15198 if ((res != 1) || span < 1 || span > NUM_SPANS) {
15199 ast_cli(a->fd,
15200 "Invalid span '%s'. Should be a number from %d to %d\n",
15201 a->argv[3], 1, NUM_SPANS);
15202 return CLI_SUCCESS;
15203 }
15204 pri = &pris[span - 1].pri;
15205 if (!pri->pri) {
15206 ast_cli(a->fd, "No PRI running on span %d\n", span);
15207 return CLI_SUCCESS;
15208 }
15209
15210 pri_destroy_span(pri);
15211 return CLI_SUCCESS;
15212}
15213
15214#endif /* defined(HAVE_PRI) */
15215
15216#if defined(HAVE_PRI)
15217static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15218{
15219 int span;
15220
15221 switch (cmd) {
15222 case CLI_INIT:
15223 e->command = "pri show span";
15224 e->usage =
15225 "Usage: pri show span <span>\n"
15226 " Displays PRI Information on a given PRI span\n";
15227 return NULL;
15228 case CLI_GENERATE:
15229 return complete_span_4(a->line, a->word, a->pos, a->n);
15230 }
15231
15232 if (a->argc < 4)
15233 return CLI_SHOWUSAGE;
15234 span = atoi(a->argv[3]);
15235 if ((span < 1) || (span > NUM_SPANS)) {
15236 ast_cli(a->fd, "Invalid span '%s'. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
15237 return CLI_SUCCESS;
15238 }
15239 if (!pris[span-1].pri.pri) {
15240 ast_cli(a->fd, "No PRI running on span %d\n", span);
15241 return CLI_SUCCESS;
15242 }
15243
15244 sig_pri_cli_show_span(a->fd, pris[span-1].dchannels, &pris[span-1].pri);
15245
15246 return CLI_SUCCESS;
15247}
15248#endif /* defined(HAVE_PRI) */
15249
15250#if defined(HAVE_PRI)
15251static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15252{
15253 int x;
15254 int span;
15255 int count=0;
15256 int debug;
15257
15258 switch (cmd) {
15259 case CLI_INIT:
15260 e->command = "pri show debug";
15261 e->usage =
15262 "Usage: pri show debug\n"
15263 " Show the debug state of pri spans\n";
15264 return NULL;
15265 case CLI_GENERATE:
15266 return NULL;
15267 }
15268
15269 for (span = 0; span < NUM_SPANS; span++) {
15270 if (pris[span].pri.pri) {
15271 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
15272 if (pris[span].pri.dchans[x]) {
15273 debug = pri_get_debug(pris[span].pri.dchans[x]);
15274 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" );
15275 count++;
15276 }
15277 }
15278 }
15279
15280 }
15281 ast_mutex_lock(&pridebugfdlock);
15282 if (pridebugfd >= 0)
15283 ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
15284 ast_mutex_unlock(&pridebugfdlock);
15285
15286 if (!count)
15287 ast_cli(a->fd, "No PRI running\n");
15288 return CLI_SUCCESS;
15289}
15290#endif /* defined(HAVE_PRI) */
15291
15292#if defined(HAVE_PRI)
15293static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15294{
15295 switch (cmd) {
15296 case CLI_INIT:
15297 e->command = "pri show version";
15298 e->usage =
15299 "Usage: pri show version\n"
15300 "Show libpri version information\n";
15301 return NULL;
15302 case CLI_GENERATE:
15303 return NULL;
15304 }
15305
15306 ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
15307
15308 return CLI_SUCCESS;
15309}
15310#endif /* defined(HAVE_PRI) */
15311
15312#if defined(HAVE_PRI)
15313static struct ast_cli_entry dahdi_pri_cli[] = {
15314 AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
15315#if defined(HAVE_PRI_SERVICE_MESSAGES)
15316 AST_CLI_DEFINE(handle_pri_service_enable_channel, "Return a channel to service"),
15317 AST_CLI_DEFINE(handle_pri_service_disable_channel, "Remove a channel from service"),
15318#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15319 AST_CLI_DEFINE(handle_pri_show_channels, "Displays PRI channel information"),
15320 AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI span information"),
15321 AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI span information"),
15322 AST_CLI_DEFINE(handle_pri_destroy_span, "Destroy a PRI span"),
15323 AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
15324 AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
15325 AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
15326};
15327#endif /* defined(HAVE_PRI) */
15328
15329#ifdef HAVE_OPENR2
15330
15331static char *handle_mfcr2_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15332{
15333 switch (cmd) {
15334 case CLI_INIT:
15335 e->command = "mfcr2 show version";
15336 e->usage =
15337 "Usage: mfcr2 show version\n"
15338 " Shows the version of the OpenR2 library being used.\n";
15339 return NULL;
15340 case CLI_GENERATE:
15341 return NULL;
15342 }
15343 ast_cli(a->fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15344 return CLI_SUCCESS;
15345}
15346
15347static char *handle_mfcr2_show_variants(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15348{
15349#define FORMAT "%4s %40s\n"
15350 int i = 0;
15351 int numvariants = 0;
15352 const openr2_variant_entry_t *variants;
15353 switch (cmd) {
15354 case CLI_INIT:
15355 e->command = "mfcr2 show variants";
15356 e->usage =
15357 "Usage: mfcr2 show variants\n"
15358 " Shows the list of MFC/R2 variants supported.\n";
15359 return NULL;
15360 case CLI_GENERATE:
15361 return NULL;
15362 }
15363 if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
15364 ast_cli(a->fd, "Failed to get list of variants.\n");
15365 return CLI_FAILURE;
15366 }
15367 ast_cli(a->fd, FORMAT, "Variant Code", "Country");
15368 for (i = 0; i < numvariants; i++) {
15369 ast_cli(a->fd, FORMAT, variants[i].name, variants[i].country);
15370 }
15371 return CLI_SUCCESS;
15372#undef FORMAT
15373}
15374
15375static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15376{
15377#define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15378 int filtertype = 0;
15379 int targetnum = 0;
15380 char channo[5];
15381 char linkno[5];
15382 char anino[5];
15383 char dnisno[5];
15384 struct dahdi_pvt *p;
15385 openr2_context_t *r2context;
15386 openr2_variant_t r2variant;
15387 switch (cmd) {
15388 case CLI_INIT:
15389 e->command = "mfcr2 show channels [group|context]";
15390 e->usage =
15391 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15392 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15393 return NULL;
15394 case CLI_GENERATE:
15395 return NULL;
15396 }
15397 if (!((a->argc == 3) || (a->argc == 5))) {
15398 return CLI_SHOWUSAGE;
15399 }
15400 if (a->argc == 5) {
15401 if (!strcasecmp(a->argv[3], "group")) {
15402 targetnum = atoi(a->argv[4]);
15403 if ((targetnum < 0) || (targetnum > 63))
15404 return CLI_SHOWUSAGE;
15405 targetnum = 1 << targetnum;
15406 filtertype = 1;
15407 } else if (!strcasecmp(a->argv[3], "context")) {
15408 filtertype = 2;
15409 } else {
15410 return CLI_SHOWUSAGE;
15411 }
15412 }
15413 ast_cli(a->fd, FORMAT, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15415 for (p = iflist; p; p = p->next) {
15416 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15417 continue;
15418 }
15419 if (filtertype) {
15420 switch(filtertype) {
15421 case 1: /* mfcr2 show channels group <group> */
15422 if (p->group != targetnum) {
15423 continue;
15424 }
15425 break;
15426 case 2: /* mfcr2 show channels context <context> */
15427 if (strcasecmp(p->context, a->argv[4])) {
15428 continue;
15429 }
15430 break;
15431 default:
15432 ;
15433 }
15434 }
15435 r2context = openr2_chan_get_context(p->r2chan);
15436 r2variant = openr2_context_get_variant(r2context);
15437 snprintf(channo, sizeof(channo), "%d", p->channel);
15438 snprintf(linkno, sizeof(linkno), "%d", p->mfcr2->index);
15439 snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
15440 snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
15441 ast_cli(a->fd, FORMAT, channo, linkno, openr2_proto_get_variant_string(r2variant),
15442 anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
15443 openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
15444 openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
15445 }
15447 return CLI_SUCCESS;
15448#undef FORMAT
15449}
15450
15451static char *handle_mfcr2_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15452{
15453 struct dahdi_pvt *p = NULL;
15454 int channo = 0;
15455 char *toklevel = NULL;
15456 char *saveptr = NULL;
15457 char *logval = NULL;
15458 openr2_log_level_t loglevel = OR2_LOG_NOTHING;
15459 openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
15460 switch (cmd) {
15461 case CLI_INIT:
15462 e->command = "mfcr2 set debug";
15463 e->usage =
15464 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15465 " Set a new logging level for the specified channel.\n"
15466 " If no channel is specified the logging level will be applied to all channels.\n";
15467 return NULL;
15468 case CLI_GENERATE:
15469 return NULL;
15470 }
15471 if (a->argc < 4) {
15472 return CLI_SHOWUSAGE;
15473 }
15474 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15475 logval = ast_strdupa(a->argv[3]);
15476 toklevel = strtok_r(logval, ",", &saveptr);
15477 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15478 ast_cli(a->fd, "Invalid MFC/R2 logging level '%s'.\n", a->argv[3]);
15479 return CLI_FAILURE;
15480 } else if (OR2_LOG_NOTHING == tmplevel) {
15481 loglevel = tmplevel;
15482 } else {
15483 loglevel |= tmplevel;
15484 while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
15485 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15486 ast_cli(a->fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
15487 continue;
15488 }
15489 loglevel |= tmplevel;
15490 }
15491 }
15493 for (p = iflist; p; p = p->next) {
15494 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15495 continue;
15496 }
15497 if ((channo != -1) && (p->channel != channo )) {
15498 continue;
15499 }
15500 openr2_chan_set_log_level(p->r2chan, loglevel);
15501 if (channo != -1) {
15502 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for channel %d.\n", a->argv[3], p->channel);
15503 break;
15504 }
15505 }
15506 if ((channo != -1) && !p) {
15507 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15508 }
15509 if (channo == -1) {
15510 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for all channels.\n", a->argv[3]);
15511 }
15513 return CLI_SUCCESS;
15514}
15515
15516static char *handle_mfcr2_call_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15517{
15518 struct dahdi_pvt *p = NULL;
15519 int channo = 0;
15520 switch (cmd) {
15521 case CLI_INIT:
15522 e->command = "mfcr2 call files [on|off]";
15523 e->usage =
15524 "Usage: mfcr2 call files [on|off] <channel>\n"
15525 " Enable call files creation on the specified channel.\n"
15526 " If no channel is specified call files creation policy will be applied to all channels.\n";
15527 return NULL;
15528 case CLI_GENERATE:
15529 return NULL;
15530 }
15531 if (a->argc < 4) {
15532 return CLI_SHOWUSAGE;
15533 }
15534 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15536 for (p = iflist; p; p = p->next) {
15537 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15538 continue;
15539 }
15540 if ((channo != -1) && (p->channel != channo )) {
15541 continue;
15542 }
15543 if (ast_true(a->argv[3])) {
15544 openr2_chan_enable_call_files(p->r2chan);
15545 } else {
15546 openr2_chan_disable_call_files(p->r2chan);
15547 }
15548 if (channo != -1) {
15549 if (ast_true(a->argv[3])) {
15550 ast_cli(a->fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
15551 } else {
15552 ast_cli(a->fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
15553 }
15554 break;
15555 }
15556 }
15557 if ((channo != -1) && !p) {
15558 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15559 }
15560 if (channo == -1) {
15561 if (ast_true(a->argv[3])) {
15562 ast_cli(a->fd, "MFC/R2 Call files enabled for all channels.\n");
15563 } else {
15564 ast_cli(a->fd, "MFC/R2 Call files disabled for all channels.\n");
15565 }
15566 }
15568 return CLI_SUCCESS;
15569}
15570
15571static char *handle_mfcr2_set_idle(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15572{
15573 struct dahdi_pvt *p = NULL;
15574 int channo = 0;
15575 switch (cmd) {
15576 case CLI_INIT:
15577 e->command = "mfcr2 set idle";
15578 e->usage =
15579 "Usage: mfcr2 set idle <channel>\n"
15580 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15581 " Force the given channel into IDLE state.\n"
15582 " If no channel is specified, all channels will be set to IDLE.\n";
15583 return NULL;
15584 case CLI_GENERATE:
15585 return NULL;
15586 }
15587 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15589 for (p = iflist; p; p = p->next) {
15590 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15591 continue;
15592 }
15593 if ((channo != -1) && (p->channel != channo )) {
15594 continue;
15595 }
15596 openr2_chan_set_idle(p->r2chan);
15597 ast_mutex_lock(&p->lock);
15598 p->locallyblocked = 0;
15599 p->mfcr2call = 0;
15601 if (channo != -1) {
15602 break;
15603 }
15604 }
15605 if ((channo != -1) && !p) {
15606 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15607 }
15609 return CLI_SUCCESS;
15610}
15611
15612static char *handle_mfcr2_set_blocked(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15613{
15614 struct dahdi_pvt *p = NULL;
15615 int channo = 0;
15616 switch (cmd) {
15617 case CLI_INIT:
15618 e->command = "mfcr2 set blocked";
15619 e->usage =
15620 "Usage: mfcr2 set blocked <channel>\n"
15621 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15622 " Force the given channel into BLOCKED state.\n"
15623 " If no channel is specified, all channels will be set to BLOCKED.\n";
15624 return NULL;
15625 case CLI_GENERATE:
15626 return NULL;
15627 }
15628 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15630 for (p = iflist; p; p = p->next) {
15631 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15632 continue;
15633 }
15634 if ((channo != -1) && (p->channel != channo )) {
15635 continue;
15636 }
15637 openr2_chan_set_blocked(p->r2chan);
15638 ast_mutex_lock(&p->lock);
15639 p->locallyblocked = 1;
15641 if (channo != -1) {
15642 break;
15643 }
15644 }
15645 if ((channo != -1) && !p) {
15646 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15647 }
15649 return CLI_SUCCESS;
15650}
15651
15652static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_head, const char *title)
15653{
15654#define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15655 AST_LIST_LOCK(list_head);
15656 if (! AST_LIST_EMPTY(list_head)) {
15657 int x = 0;
15658 char index[5];
15659 char live_chans_str[5];
15660 char channel_list[R2_LINK_CAPACITY * 4];
15661 struct r2link_entry *cur;
15662 ast_cli(a->fd, "%s\n", title);
15663 ast_cli(a->fd, FORMAT, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15664 AST_LIST_TRAVERSE(list_head, cur, list) {
15665 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15666 const char *thread_status = NULL;
15667 int i;
15668 int len;
15669 int inside_range;
15670 int channo;
15671 int prev_channo;
15672 x++;
15673 if (mfcr2->r2master == 0L) {
15674 thread_status = "zero";
15675 } else if (mfcr2->r2master == AST_PTHREADT_NULL) {
15676 thread_status = "none";
15677 } else {
15678 thread_status = "created";
15679 }
15680 snprintf(index, sizeof(index), "%d", mfcr2->index);
15681 snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
15682 channo = 0;
15683 prev_channo = 0;
15684 inside_range = 0;
15685 len = 0;
15686 /* Prepare nice string in channel_list[] */
15687 for (i = 0; i < mfcr2->numchans && len < sizeof(channel_list) - 1; i++) {
15688 struct dahdi_pvt *p = mfcr2->pvts[i];
15689 if (!p) {
15690 continue;
15691 }
15692 channo = p->channel;
15693 /* Don't show a range until we know the last channel number */
15694 if (prev_channo && prev_channo == channo - 1) {
15695 prev_channo = channo;
15696 inside_range = 1;
15697 continue;
15698 }
15699 if (inside_range) {
15700 /* Close range */
15701 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d,%d", prev_channo, channo);
15702 inside_range = 0;
15703 } else if (prev_channo) {
15704 /* Non-sequential channel numbers */
15705 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15706 } else {
15707 /* First channel number */
15708 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "%d", channo);
15709 }
15710 prev_channo = channo;
15711 }
15712 /* Handle leftover channels */
15713 if (inside_range) {
15714 /* Close range */
15715 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d", channo);
15716 inside_range = 0;
15717 } else if (prev_channo) {
15718 /* Non-sequential channel numbers */
15719 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15720 }
15721 // channel_list[len] = '\0';
15722 ast_cli(a->fd, FORMAT,
15723 index,
15724 thread_status,
15725 (mfcr2->nodev) ? "MISSING" : "OK",
15726 live_chans_str,
15727 channel_list);
15728 }
15729 }
15730 AST_LIST_UNLOCK(list_head);
15731#undef FORMAT
15732}
15733
15734static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15735{
15736 switch (cmd) {
15737 case CLI_INIT:
15738 e->command = "mfcr2 show links";
15739 e->usage =
15740 "Usage: mfcr2 show links\n"
15741 " Shows the DAHDI MFC/R2 links.\n";
15742 return NULL;
15743 case CLI_GENERATE:
15744 return NULL;
15745 }
15746 if (a->argc != 3) {
15747 return CLI_SHOWUSAGE;
15748 }
15749 mfcr2_show_links_of(a, &r2links, "Live links\n");
15750 mfcr2_show_links_of(a, &nodev_r2links, "Links to be removed (device missing)\n");
15751 return CLI_SUCCESS;
15752}
15753
15754static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15755{
15756 int res;
15757 int wanted_link_index;
15758 int found_link = 0;
15759 struct r2link_entry *cur = NULL;
15760
15761 switch (cmd) {
15762 case CLI_INIT:
15763 e->command = "mfcr2 destroy link";
15764 e->usage =
15765 "Usage: mfcr2 destroy link <index-number>\n"
15766 " Destroys D-channel of link and its B-channels.\n"
15767 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15768 return NULL;
15769 case CLI_GENERATE:
15770 return NULL;
15771 }
15772 if (a->argc < 4) {
15773 return CLI_SHOWUSAGE;
15774 }
15775 res = sscanf(a->argv[3], "%30d", &wanted_link_index);
15776 if ((res != 1) || wanted_link_index < 1) {
15777 ast_cli(a->fd,
15778 "Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
15779 return CLI_SUCCESS;
15780 }
15781 AST_LIST_LOCK(&r2links);
15782 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
15783 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15784 if (wanted_link_index == mfcr2->index) {
15785 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
15786 r2links_count--;
15787 break;
15788 }
15789 }
15791 AST_LIST_UNLOCK(&r2links);
15792 if (! found_link) {
15793 ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
15794 return CLI_FAILURE;
15795 }
15796 return CLI_SUCCESS;
15797}
15798
15799static struct ast_cli_entry dahdi_mfcr2_cli[] = {
15800 AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
15801 AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
15802 AST_CLI_DEFINE(handle_mfcr2_show_channels, "Show MFC/R2 channels"),
15803 AST_CLI_DEFINE(handle_mfcr2_show_links, "Show MFC/R2 links"),
15804 AST_CLI_DEFINE(handle_mfcr2_set_debug, "Set MFC/R2 channel logging level"),
15805 AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
15806 AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
15807 AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
15808 AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
15809};
15810
15811#endif /* HAVE_OPENR2 */
15812
15813static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15814{
15815 int start;
15816 int end;
15817 switch (cmd) {
15818 case CLI_INIT:
15819 e->command = "dahdi destroy channels";
15820 e->usage =
15821 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15822 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15823 return NULL;
15824 case CLI_GENERATE:
15825 return NULL;
15826 }
15827 if ((a->argc < 4) || a->argc > 5) {
15828 return CLI_SHOWUSAGE;
15829 }
15830 start = atoi(a->argv[3]);
15831 if (start < 1) {
15832 ast_cli(a->fd, "Invalid starting channel number %s.\n",
15833 a->argv[4]);
15834 return CLI_FAILURE;
15835 }
15836 if (a->argc == 5) {
15837 end = atoi(a->argv[4]);
15838 if (end < 1) {
15839 ast_cli(a->fd, "Invalid ending channel number %s.\n",
15840 a->argv[4]);
15841 return CLI_FAILURE;
15842 }
15843 } else {
15844 end = start;
15845 }
15846
15847 if (end < start) {
15848 ast_cli(a->fd,
15849 "range end (%d) is smaller than range start (%d)\n",
15850 end, start);
15851 return CLI_FAILURE;
15852 }
15854 return CLI_SUCCESS;
15855}
15856
15857static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15858{
15859 int start;
15860 int end;
15861 int ret;
15862
15863 switch (cmd) {
15864 case CLI_INIT:
15865 e->command = "dahdi create channels";
15866 e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15867 " dahdi create channels new - add channels not yet created\n"
15868 "For ISDN and SS7 the range should include complete spans.\n";
15869 return NULL;
15870 case CLI_GENERATE:
15871 return NULL;
15872 }
15873 if ((a->argc < 4) || a->argc > 5) {
15874 return CLI_SHOWUSAGE;
15875 }
15876 if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
15877 ret = dahdi_create_channel_range(0, 0);
15878 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15879 }
15880 start = atoi(a->argv[3]);
15881 if (start <= 0) {
15882 ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
15883 a->argv[3]);
15884 return CLI_FAILURE;
15885 }
15886 if (a->argc == 5) {
15887 end = atoi(a->argv[4]);
15888 if (end <= 0) {
15889 ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
15890 a->argv[4]);
15891 return CLI_FAILURE;
15892 }
15893 } else {
15894 end = start;
15895 }
15896 if (end < start) {
15897 ast_cli(a->fd,
15898 "range end (%d) is smaller than range start (%d)\n",
15899 end, start);
15900 return CLI_FAILURE;
15901 }
15902 ret = dahdi_create_channel_range(start, end);
15903 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15904}
15905
15906static void dahdi_softhangup_all(void)
15907{
15908 struct dahdi_pvt *p;
15909retry:
15911 for (p = iflist; p; p = p->next) {
15912 ast_mutex_lock(&p->lock);
15913 if (p->owner && !p->restartpending) {
15914 if (ast_channel_trylock(p->owner)) {
15915 if (DEBUG_ATLEAST(3))
15916 ast_verbose("Avoiding deadlock\n");
15917 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15920 goto retry;
15921 }
15922 if (DEBUG_ATLEAST(3))
15923 ast_verbose("Softhanging up on %s\n", ast_channel_name(p->owner));
15925 p->restartpending = 1;
15928 }
15930 }
15932}
15933
15934static int dahdi_restart(void)
15935{
15936#if defined(HAVE_PRI) || defined(HAVE_SS7)
15937 int i, j;
15938#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15939 int cancel_code;
15940 struct dahdi_pvt *p;
15941
15943 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15945 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15946#ifdef HAVE_OPENR2
15947 dahdi_r2_destroy_links();
15948#endif
15949
15950#if defined(HAVE_PRI)
15951 for (i = 0; i < NUM_SPANS; i++) {
15952 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
15953 cancel_code = pthread_cancel(pris[i].pri.master);
15954 pthread_kill(pris[i].pri.master, SIGURG);
15955 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);
15956 pthread_join(pris[i].pri.master, NULL);
15957 ast_debug(4, "Joined thread of span %d\n", i);
15958 }
15959 }
15960#endif
15961
15962#if defined(HAVE_SS7)
15963 for (i = 0; i < NUM_SPANS; i++) {
15964 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
15965 cancel_code = pthread_cancel(linksets[i].ss7.master);
15966 pthread_kill(linksets[i].ss7.master, SIGURG);
15967 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);
15968 pthread_join(linksets[i].ss7.master, NULL);
15969 ast_debug(4, "Joined thread of span %d\n", i);
15970 }
15971 }
15972#endif /* defined(HAVE_SS7) */
15973
15976 cancel_code = pthread_cancel(monitor_thread);
15977 pthread_kill(monitor_thread, SIGURG);
15978 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
15979 pthread_join(monitor_thread, NULL);
15980 ast_debug(4, "Joined monitor thread\n");
15981 }
15982 monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
15983
15985 while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
15986 int x = DAHDI_FLASH;
15987 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count);
15988
15990 for (p = iflist; p; p = p->next) {
15991 if (p->owner) {
15992 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
15993 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
15994 }
15995 }
15998 }
15999
16000 /* ensure any created channels before monitor threads were stopped are hungup */
16002 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
16004 memset(round_robin, 0, sizeof(round_robin));
16005 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
16006
16008
16009#ifdef HAVE_PRI
16010 for (i = 0; i < NUM_SPANS; i++) {
16011 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++)
16012 dahdi_close_pri_fd(&(pris[i]), j);
16013 }
16014
16015 memset(pris, 0, sizeof(pris));
16016 for (i = 0; i < NUM_SPANS; i++) {
16017 sig_pri_init_pri(&pris[i].pri);
16018 }
16019 pri_set_error(dahdi_pri_error);
16020 pri_set_message(dahdi_pri_message);
16021#endif
16022#if defined(HAVE_SS7)
16023 for (i = 0; i < NUM_SPANS; i++) {
16024 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++)
16025 dahdi_close_ss7_fd(&(linksets[i]), j);
16026 }
16027
16028 memset(linksets, 0, sizeof(linksets));
16029 for (i = 0; i < NUM_SPANS; i++) {
16030 sig_ss7_init_linkset(&linksets[i].ss7);
16031 }
16032 ss7_set_error(dahdi_ss7_error);
16033 ss7_set_message(dahdi_ss7_message);
16034 ss7_set_hangup(sig_ss7_cb_hangup);
16035 ss7_set_notinservice(sig_ss7_cb_notinservice);
16036 ss7_set_call_null(sig_ss7_cb_call_null);
16037#endif /* defined(HAVE_SS7) */
16038
16039 if (setup_dahdi(2) != 0) {
16040 ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
16042 return 1;
16043 }
16046 return 0;
16047}
16048
16049static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16050{
16051 switch (cmd) {
16052 case CLI_INIT:
16053 e->command = "dahdi restart";
16054 e->usage =
16055 "Usage: dahdi restart\n"
16056 " Restarts the DAHDI channels: destroys them all and then\n"
16057 " re-reads them from chan_dahdi.conf.\n"
16058 " Note that this will STOP any running CALL on DAHDI channels.\n"
16059 "";
16060 return NULL;
16061 case CLI_GENERATE:
16062 return NULL;
16063 }
16064 if (a->argc != 2)
16065 return CLI_SHOWUSAGE;
16066
16067 if (dahdi_restart() != 0)
16068 return CLI_FAILURE;
16069 return CLI_SUCCESS;
16070}
16071
16072static int action_dahdirestart(struct mansession *s, const struct message *m)
16073{
16074 if (dahdi_restart() != 0) {
16075 astman_send_error(s, m, "Failed rereading DAHDI configuration");
16076 return 1;
16077 }
16078 astman_send_ack(s, m, "DAHDIRestart: Success");
16079 return 0;
16080}
16081
16082static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16083{
16084#define FORMAT "%7s %4d %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16085#define FORMAT2 "%7s %4s %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16086 ast_group_t targetnum = 0;
16087 int filtertype = 0;
16088 struct dahdi_pvt *tmp = NULL;
16089 char tmps[20];
16090 char blockstr[20];
16091
16092 switch (cmd) {
16093 case CLI_INIT:
16094 e->command = "dahdi show channels [group|context]";
16095 e->usage =
16096 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
16097 " Shows a list of available channels with optional filtering\n"
16098 " <group> must be a number between 0 and 63\n";
16099 return NULL;
16100 case CLI_GENERATE:
16101 return NULL;
16102 }
16103
16104 /* syntax: dahdi show channels [ group <group> | context <context> ] */
16105
16106 if (!((a->argc == 3) || (a->argc == 5))) {
16107 return CLI_SHOWUSAGE;
16108 }
16109
16110 if (a->argc == 5) {
16111 if (!strcasecmp(a->argv[3], "group")) {
16112 targetnum = atoi(a->argv[4]);
16113 if (63 < targetnum) {
16114 return CLI_SHOWUSAGE;
16115 }
16116 targetnum = ((ast_group_t) 1) << targetnum;
16117 filtertype = 1;
16118 } else if (!strcasecmp(a->argv[3], "context")) {
16119 filtertype = 2;
16120 }
16121 }
16122
16123 ast_cli(a->fd, FORMAT2, "Chan", "Span", "Signalling", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Alarms", "Description");
16125 for (tmp = iflist; tmp; tmp = tmp->next) {
16126 int alm = 0;
16127 if (filtertype) {
16128 switch(filtertype) {
16129 case 1: /* dahdi show channels group <group> */
16130 if (!(tmp->group & targetnum)) {
16131 continue;
16132 }
16133 break;
16134 case 2: /* dahdi show channels context <context> */
16135 if (strcasecmp(tmp->context, a->argv[4])) {
16136 continue;
16137 }
16138 break;
16139 default:
16140 break;
16141 }
16142 }
16143 if (tmp->channel > 0) {
16144 snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
16145 alm = get_alarms(tmp);
16146 } else {
16147 ast_copy_string(tmps, "pseudo", sizeof(tmps));
16148 }
16149
16150 blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
16151 blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
16152 blockstr[2] = '\0';
16153
16154 ast_cli(a->fd, FORMAT, tmps, tmp->span, sig2str(tmp->sig), tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No",
16155 alarm2str(alm), tmp->description);
16156 }
16158 return CLI_SUCCESS;
16159#undef FORMAT
16160#undef FORMAT2
16161}
16162
16163static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16164{
16165 int channel;
16166 struct dahdi_pvt *tmp = NULL;
16167 struct dahdi_confinfo ci;
16168 struct dahdi_params ps;
16169 int x;
16170 char hwrxgain[15];
16171 char hwtxgain[15];
16172
16173 switch (cmd) {
16174 case CLI_INIT:
16175 e->command = "dahdi show channel";
16176 e->usage =
16177 "Usage: dahdi show channel <chan num>\n"
16178 " Detailed information about a given channel\n";
16179 return NULL;
16180 case CLI_GENERATE:
16181 return NULL;
16182 }
16183
16184 if (a->argc != 4)
16185 return CLI_SHOWUSAGE;
16186
16187 channel = atoi(a->argv[3]);
16188
16190 for (tmp = iflist; tmp; tmp = tmp->next) {
16191 if (tmp->channel == channel) {
16192 ast_cli(a->fd, "Channel: %d\n", tmp->channel);
16193 ast_cli(a->fd, "Description: %s\n", tmp->description);
16194 ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
16195 ast_cli(a->fd, "Span: %d\n", tmp->span);
16196 ast_cli(a->fd, "Extension: %s\n", tmp->exten);
16197 ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
16198 ast_cli(a->fd, "Context: %s\n", tmp->context);
16199 ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
16200 ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
16201#if defined(HAVE_PRI)
16202#if defined(HAVE_PRI_SUBADDR)
16203 ast_cli(a->fd, "Caller ID subaddress: %s\n", tmp->cid_subaddr);
16204#endif /* defined(HAVE_PRI_SUBADDR) */
16205#endif /* defined(HAVE_PRI) */
16206 ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
16207 ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
16208 if (tmp->vars) {
16209 struct ast_variable *v;
16210 ast_cli(a->fd, "Variables:\n");
16211 for (v = tmp->vars ; v ; v = v->next)
16212 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
16213 }
16214 ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
16215 ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
16216 ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
16217 ast_cli(a->fd, "Radio: %d\n", tmp->radio);
16218 ast_cli(a->fd, "Owner: %s\n", tmp->owner ? ast_channel_name(tmp->owner) : "<None>");
16219 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)" : "");
16220 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)" : "");
16221 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)" : "");
16222 ast_cli(a->fd, "Confno: %d\n", tmp->confno);
16223 ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
16224 ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
16225 ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
16226 ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
16227 if (tmp->busydetect) {
16228#if defined(BUSYDETECT_TONEONLY)
16229 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16230#elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16231 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16232#endif
16233#ifdef BUSYDETECT_DEBUG
16234 ast_cli(a->fd, " Busy Detector Debug: Enabled\n");
16235#endif
16236 ast_cli(a->fd, " Busy Count: %d\n", tmp->busycount);
16237 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);
16238 }
16239 ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
16240 ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
16241 ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
16242 ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
16243 ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
16244 ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
16245 if (tmp->hwrxgain_enabled) {
16246 snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
16247 } else {
16248 ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
16249 }
16250 if (tmp->hwtxgain_enabled) {
16251 snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
16252 } else {
16253 ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
16254 }
16255 ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
16256 ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
16257 ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
16258 ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
16259 ast_cli(a->fd, "Echo Cancellation:\n");
16260
16261 if (tmp->echocancel.head.tap_length) {
16262 ast_cli(a->fd, "\t%u taps\n", tmp->echocancel.head.tap_length);
16263 for (x = 0; x < tmp->echocancel.head.param_count; x++) {
16264 ast_cli(a->fd, "\t\t%s: %dd\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
16265 }
16266 ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
16267 } else {
16268 ast_cli(a->fd, "\tnone\n");
16269 }
16270 ast_cli(a->fd, "Wait for dialtone: %dms\n", tmp->waitfordialtone);
16271 if (tmp->master)
16272 ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
16273 for (x = 0; x < MAX_SLAVES; x++) {
16274 if (tmp->slaves[x])
16275 ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
16276 }
16277#ifdef HAVE_OPENR2
16278 if (tmp->mfcr2) {
16279 char calldir[OR2_MAX_PATH];
16280 openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
16281 openr2_variant_t r2variant = openr2_context_get_variant(r2context);
16282 ast_cli(a->fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
16283 ast_cli(a->fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
16284 ast_cli(a->fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
16285 ast_cli(a->fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
16286 ast_cli(a->fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
16287 ast_cli(a->fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
16288 ast_cli(a->fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
16289 ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
16290#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16291 ast_cli(a->fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
16292 ast_cli(a->fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
16293#endif
16294 ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
16295#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16296 ast_cli(a->fd, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
16297#endif
16298 ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
16299 ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
16300 ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
16301 ast_cli(a->fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
16302 ast_cli(a->fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
16303 ast_cli(a->fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
16304 ast_cli(a->fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
16305 ast_cli(a->fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
16306 ast_cli(a->fd, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
16307 ast_cli(a->fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
16308 ast_cli(a->fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
16309 ast_cli(a->fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
16310 }
16311#endif
16312#if defined(HAVE_SS7)
16313 if (tmp->ss7) {
16314 struct sig_ss7_chan *chan = tmp->sig_pvt;
16315
16316 ast_cli(a->fd, "CIC: %d\n", chan->cic);
16317 }
16318#endif /* defined(HAVE_SS7) */
16319#ifdef HAVE_PRI
16320 if (tmp->pri) {
16321 struct sig_pri_chan *chan = tmp->sig_pvt;
16322
16323 ast_cli(a->fd, "PRI Flags: ");
16324 if (chan->resetting != SIG_PRI_RESET_IDLE) {
16325 ast_cli(a->fd, "Resetting=%u ", chan->resetting);
16326 }
16327 if (chan->call)
16328 ast_cli(a->fd, "Call ");
16329 if (chan->allocated) {
16330 ast_cli(a->fd, "Allocated ");
16331 }
16332 ast_cli(a->fd, "\n");
16333 if (tmp->logicalspan)
16334 ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
16335 else
16336 ast_cli(a->fd, "PRI Logical Span: Implicit\n");
16337 }
16338#endif
16339 memset(&ci, 0, sizeof(ci));
16340 ps.channo = tmp->channel;
16341 if (tmp->subs[SUB_REAL].dfd > -1) {
16342 memset(&ci, 0, sizeof(ci));
16343 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
16344 ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, (unsigned)ci.confmode);
16345 }
16346 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
16347 ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
16348 }
16349 memset(&ps, 0, sizeof(ps));
16350 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
16351 ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
16352 } else {
16353 ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
16354 }
16355 }
16357 return CLI_SUCCESS;
16358 }
16359 }
16361
16362 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16363 return CLI_FAILURE;
16364}
16365
16366static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16367{
16368 int i, j;
16369 switch (cmd) {
16370 case CLI_INIT:
16371 e->command = "dahdi show cadences";
16372 e->usage =
16373 "Usage: dahdi show cadences\n"
16374 " Shows all cadences currently defined\n";
16375 return NULL;
16376 case CLI_GENERATE:
16377 return NULL;
16378 }
16379 for (i = 0; i < num_cadence; i++) {
16380 char output[1024];
16381 char tmp[16], tmp2[64];
16382 snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
16383 term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
16384
16385 for (j = 0; j < 16; j++) {
16386 if (cadences[i].ringcadence[j] == 0)
16387 break;
16388 snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
16389 if (cidrings[i] * 2 - 1 == j)
16390 term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
16391 else
16392 term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
16393 if (j != 0)
16394 strncat(output, ",", sizeof(output) - strlen(output) - 1);
16395 strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
16396 }
16397 ast_cli(a->fd,"%s\n",output);
16398 }
16399 return CLI_SUCCESS;
16400}
16401
16402static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
16403{
16404 alarmstr[0] = '\0';
16405 if (spaninfo->alarms > 0) {
16406 if (spaninfo->alarms & DAHDI_ALARM_BLUE) {
16407 strcat(alarmstr, "BLU/");
16408 }
16409 if (spaninfo->alarms & DAHDI_ALARM_YELLOW) {
16410 strcat(alarmstr, "YEL/");
16411 }
16412 if (spaninfo->alarms & DAHDI_ALARM_RED) {
16413 strcat(alarmstr, "RED/");
16414 }
16415 if (spaninfo->alarms & DAHDI_ALARM_LOOPBACK) {
16416 strcat(alarmstr, "LB/");
16417 }
16418 if (spaninfo->alarms & DAHDI_ALARM_RECOVER) {
16419 strcat(alarmstr, "REC/");
16420 }
16421 if (spaninfo->alarms & DAHDI_ALARM_NOTOPEN) {
16422 strcat(alarmstr, "NOP/");
16423 }
16424 if (!strlen(alarmstr)) {
16425 strcat(alarmstr, "UUU/");
16426 }
16427 if (strlen(alarmstr)) {
16428 /* Strip trailing / */
16429 alarmstr[strlen(alarmstr) - 1] = '\0';
16430 }
16431 } else {
16432 if (spaninfo->numchans) {
16433 strcpy(alarmstr, "OK");
16434 } else {
16435 strcpy(alarmstr, "UNCONFIGURED");
16436 }
16437 }
16438}
16439
16440/* Based on irqmiss.c */
16441static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16442{
16443 #define FORMAT "%4d %-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16444 #define FORMAT2 "%4s %-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16445 int span;
16446 int res;
16447 char alarmstr[50];
16448
16449 int ctl;
16450 struct dahdi_spaninfo s;
16451
16452 switch (cmd) {
16453 case CLI_INIT:
16454 e->command = "dahdi show status";
16455 e->usage =
16456 "Usage: dahdi show status\n"
16457 " Shows a list of DAHDI cards with status\n";
16458 return NULL;
16459 case CLI_GENERATE:
16460 return NULL;
16461 }
16462 ctl = open("/dev/dahdi/ctl", O_RDWR);
16463 if (ctl < 0) {
16464 ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
16465 return CLI_FAILURE;
16466 }
16467 ast_cli(a->fd, FORMAT2, "Span", "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16468
16469 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
16470 s.spanno = span;
16471 res = ioctl(ctl, DAHDI_SPANSTAT, &s);
16472 if (res) {
16473 continue;
16474 }
16475 build_alarm_info(alarmstr, &s);
16476 ast_cli(a->fd, FORMAT, span, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count,
16477 s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
16478 s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
16479 s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
16480 "CAS",
16481 s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
16482 s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
16483 s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
16484 "Unknown",
16485 s.lineconfig & DAHDI_CONFIG_CRC4 ?
16486 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
16487 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
16488 lbostr[s.lbo]
16489 );
16490 }
16491 close(ctl);
16492
16493 return CLI_SUCCESS;
16494#undef FORMAT
16495#undef FORMAT2
16496}
16497
16498static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16499{
16500 int pseudo_fd = -1;
16501 struct dahdi_versioninfo vi;
16502
16503 switch (cmd) {
16504 case CLI_INIT:
16505 e->command = "dahdi show version";
16506 e->usage =
16507 "Usage: dahdi show version\n"
16508 " Shows the DAHDI version in use\n";
16509 return NULL;
16510 case CLI_GENERATE:
16511 return NULL;
16512 }
16513 if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
16514 ast_cli(a->fd, "Failed to open control file to get version.\n");
16515 return CLI_SUCCESS;
16516 }
16517
16518 strcpy(vi.version, "Unknown");
16519 strcpy(vi.echo_canceller, "Unknown");
16520
16521 if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
16522 ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
16523 else
16524 ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
16525
16526 close(pseudo_fd);
16527
16528 return CLI_SUCCESS;
16529}
16530
16531static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16532{
16533 int channel;
16534 float gain;
16535 int tx;
16536 struct dahdi_pvt *tmp = NULL;
16537
16538 switch (cmd) {
16539 case CLI_INIT:
16540 e->command = "dahdi set hwgain {rx|tx}";
16541 e->usage =
16542 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16543 " Sets the hardware gain on a given channel and overrides the\n"
16544 " value provided at module loadtime. Changes take effect\n"
16545 " immediately whether the channel is in use or not.\n"
16546 "\n"
16547 " <rx|tx> which direction do you want to change (relative to our module)\n"
16548 " <chan num> is the channel number relative to the device\n"
16549 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16550 "\n"
16551 " Please note:\n"
16552 " * hwgain is only supportable by hardware with analog ports because\n"
16553 " hwgain works on the analog side of an analog-digital conversion.\n";
16554 return NULL;
16555 case CLI_GENERATE:
16556 return NULL;
16557 }
16558
16559 if (a->argc != 6)
16560 return CLI_SHOWUSAGE;
16561
16562 if (!strcasecmp("rx", a->argv[3]))
16563 tx = 0; /* rx */
16564 else if (!strcasecmp("tx", a->argv[3]))
16565 tx = 1; /* tx */
16566 else
16567 return CLI_SHOWUSAGE;
16568
16569 channel = atoi(a->argv[4]);
16570 gain = atof(a->argv[5]);
16571
16573
16574 for (tmp = iflist; tmp; tmp = tmp->next) {
16575
16576 if (tmp->channel != channel)
16577 continue;
16578
16579 if (tmp->subs[SUB_REAL].dfd == -1)
16580 break;
16581
16582 if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
16583 ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
16585 return CLI_FAILURE;
16586 }
16587 ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
16588 tx ? "tx" : "rx", gain, channel);
16589
16590 if (tx) {
16591 tmp->hwtxgain_enabled = 1;
16592 tmp->hwtxgain = gain;
16593 } else {
16594 tmp->hwrxgain_enabled = 1;
16595 tmp->hwrxgain = gain;
16596 }
16597 break;
16598 }
16599
16601
16602 if (tmp)
16603 return CLI_SUCCESS;
16604
16605 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16606 return CLI_FAILURE;
16607
16608}
16609
16610static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16611{
16612 int channel;
16613 float gain;
16614 int tx;
16615 int res;
16616 struct dahdi_pvt *tmp = NULL;
16617
16618 switch (cmd) {
16619 case CLI_INIT:
16620 e->command = "dahdi set swgain {rx|tx}";
16621 e->usage =
16622 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16623 " Sets the software gain on a given channel and overrides the\n"
16624 " value provided at module loadtime. Changes take effect\n"
16625 " immediately whether the channel is in use or not.\n"
16626 "\n"
16627 " <rx|tx> which direction do you want to change (relative to our module)\n"
16628 " <chan num> is the channel number relative to the device\n"
16629 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16630 return NULL;
16631 case CLI_GENERATE:
16632 return NULL;
16633 }
16634
16635 if (a->argc != 6)
16636 return CLI_SHOWUSAGE;
16637
16638 if (!strcasecmp("rx", a->argv[3]))
16639 tx = 0; /* rx */
16640 else if (!strcasecmp("tx", a->argv[3]))
16641 tx = 1; /* tx */
16642 else
16643 return CLI_SHOWUSAGE;
16644
16645 channel = atoi(a->argv[4]);
16646 gain = atof(a->argv[5]);
16647
16649 for (tmp = iflist; tmp; tmp = tmp->next) {
16650
16651 if (tmp->channel != channel)
16652 continue;
16653
16654 if (tmp->subs[SUB_REAL].dfd == -1)
16655 break;
16656
16657 if (tx)
16658 res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, gain, tmp->txdrc, tmp->law);
16659 else
16660 res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, gain, tmp->rxdrc, tmp->law);
16661
16662 if (res) {
16663 ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
16665 return CLI_FAILURE;
16666 }
16667
16668 ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
16669 tx ? "tx" : "rx", gain, channel);
16670
16671 if (tx) {
16672 tmp->txgain = gain;
16673 } else {
16674 tmp->rxgain = gain;
16675 }
16676 break;
16677 }
16679
16680 if (tmp)
16681 return CLI_SUCCESS;
16682
16683 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16684 return CLI_FAILURE;
16685
16686}
16687
16688static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16689{
16690 int channel;
16691 int on;
16692 struct dahdi_pvt *dahdi_chan = NULL;
16693
16694 switch (cmd) {
16695 case CLI_INIT:
16696 e->command = "dahdi set dnd";
16697 e->usage =
16698 "Usage: dahdi set dnd <chan#> <on|off>\n"
16699 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16700 " Changes take effect immediately.\n"
16701 " <chan num> is the channel number\n"
16702 " <on|off> Enable or disable DND mode?\n"
16703 ;
16704 return NULL;
16705 case CLI_GENERATE:
16706 return NULL;
16707 }
16708
16709 if (a->argc != 5)
16710 return CLI_SHOWUSAGE;
16711
16712 if ((channel = atoi(a->argv[3])) <= 0) {
16713 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16714 return CLI_SHOWUSAGE;
16715 }
16716
16717 if (ast_true(a->argv[4]))
16718 on = 1;
16719 else if (ast_false(a->argv[4]))
16720 on = 0;
16721 else {
16722 ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
16723 return CLI_SHOWUSAGE;
16724 }
16725
16727 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16728 if (dahdi_chan->channel != channel)
16729 continue;
16730
16731 /* Found the channel. Actually set it */
16732 dahdi_dnd(dahdi_chan, on);
16733 break;
16734 }
16736
16737 if (!dahdi_chan) {
16738 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16739 return CLI_FAILURE;
16740 }
16741
16742 return CLI_SUCCESS;
16743}
16744
16745static char *dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16746{
16747 int channel;
16748 int on;
16749 int override = 1;
16750 struct dahdi_pvt *dahdi_chan = NULL;
16751
16752 switch (cmd) {
16753 case CLI_INIT:
16754 e->command = "dahdi set mwi";
16755 e->usage =
16756 "Usage: dahdi set mwi <chan#> <on|off|reset>\n"
16757 " Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
16758 " This may be used regardless of whether the channel is assigned any mailboxes.\n"
16759 " When active, this setting will override the voicemail status to set MWI.\n"
16760 " Once cleared, the voicemail status will resume control of MWI.\n"
16761 " Changes are queued for when the channel is idle and persist until cleared.\n"
16762 " <chan num> is the channel number\n"
16763 " <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
16764 ;
16765 return NULL;
16766 case CLI_GENERATE:
16767 return NULL;
16768 }
16769
16770 if (a->argc != 5)
16771 return CLI_SHOWUSAGE;
16772
16773 if ((channel = atoi(a->argv[3])) <= 0) {
16774 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16775 return CLI_SHOWUSAGE;
16776 }
16777
16778 if (ast_true(a->argv[4])) {
16779 on = 1;
16780 } else if (ast_false(a->argv[4])) {
16781 on = 0;
16782 } else if (!strcmp(a->argv[4], "reset")) {
16783 override = 0;
16784 } else {
16785 ast_cli(a->fd, "Expected 'on' or 'off' or 'reset', got '%s'\n", a->argv[4]);
16786 return CLI_SHOWUSAGE;
16787 }
16788
16790 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16791 if (dahdi_chan->channel != channel)
16792 continue;
16793
16794 /* Found the channel. Actually set it */
16795 if (override) {
16796 dahdi_chan->mwioverride_disposition = on;
16797 ast_cli(a->fd, "MWI '%s' queued for channel %d\n", on ? "enable" : "disable", channel);
16798 }
16799 dahdi_chan->mwioverride_active = override;
16800 /* The do_monitor thread will take care of actually sending the MWI
16801 * at an appropriate time for the channel. */
16802 break;
16803 }
16805
16806 if (!dahdi_chan) {
16807 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16808 return CLI_FAILURE;
16809 }
16810
16811 return CLI_SUCCESS;
16812}
16813
16814static struct ast_cli_entry dahdi_cli[] = {
16816 AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
16817 AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
16818 AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
16819 AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
16820 AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
16821 AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
16822 AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
16823 AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
16824 AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
16825 AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16826 AST_CLI_DEFINE(dahdi_set_mwi, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
16827};
16828
16829#define TRANSFER 0
16830#define HANGUP 1
16831
16832static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
16833{
16834 if (p) {
16835 switch (mode) {
16836 case TRANSFER:
16837 p->fake_event = DAHDI_EVENT_WINKFLASH;
16838 break;
16839 case HANGUP:
16840 p->fake_event = DAHDI_EVENT_ONHOOK;
16841 break;
16842 default:
16843 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));
16844 }
16845 }
16846 return 0;
16847}
16848static struct dahdi_pvt *find_channel(int channel)
16849{
16850 struct dahdi_pvt *p;
16851
16853 for (p = iflist; p; p = p->next) {
16854 if (p->channel == channel) {
16855 break;
16856 }
16857 }
16859 return p;
16860}
16861
16862/*!
16863 * \internal
16864 * \brief Get private struct using given numeric channel string.
16865 *
16866 * \param channel Numeric channel number string get private struct.
16867 *
16868 * \retval pvt on success.
16869 * \retval NULL on error.
16870 */
16871static struct dahdi_pvt *find_channel_from_str(const char *channel)
16872{
16873 int chan_num;
16874
16875 if (sscanf(channel, "%30d", &chan_num) != 1) {
16876 /* Not numeric string. */
16877 return NULL;
16878 }
16879
16880 return find_channel(chan_num);
16881}
16882
16883static int print_subchannel(struct dahdi_pvt *p, int subchan, char *buffer, size_t len)
16884{
16885 if (!p->subs[subchan].owner) {
16886 return -1;
16887 }
16888 ast_channel_lock(p->subs[subchan].owner);
16889 snprintf(buffer, len, "%s", ast_channel_name(p->subs[subchan].owner));
16890 ast_channel_unlock(p->subs[subchan].owner);
16891 return 0;
16892}
16893
16894#define REQUIRE_FXO_SIG() \
16895 if (!(dahdip->sigtype & __DAHDI_SIG_FXO)) { \
16896 ast_log(LOG_WARNING, "DAHDI channel %d is not FXO signalled\n", p->channel); \
16897 return -1; \
16898 }
16899
16900static int dahdichan_read_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, char *buffer, size_t len)
16901{
16902 struct analog_pvt *analog_p = p->sig_pvt;
16903
16904 /* R/O properties */
16905 if (!strcasecmp(property, "owner")) {
16906 return print_subchannel(p, SUB_REAL, buffer, len);
16907 } else if (!strcasecmp(property, "callwait")) {
16908 return print_subchannel(p, SUB_CALLWAIT, buffer, len);
16909 } else if (!strcasecmp(property, "threeway")) {
16910 return print_subchannel(p, SUB_THREEWAY, buffer, len);
16911 /* R/W properties */
16912 } else if (!strcasecmp(property, "polarity")) {
16914 snprintf(buffer, len, "%d", p->polarity);
16915 } else if (!strcasecmp(property, "dnd")) {
16917 snprintf(buffer, len, "%d", analog_p->dnd);
16918 } else if (!strcasecmp(property, "callforward")) {
16920 snprintf(buffer, len, "%s", analog_p->call_forward);
16921 } else if (!strcasecmp(property, "lastexten")) {
16923 snprintf(buffer, len, "%s", analog_p->lastexten);
16924 } else {
16925 ast_log(LOG_ERROR, "Unknown DAHDI_CHANNEL property '%s'\n", property);
16926 return -1;
16927 }
16928 return 0;
16929}
16930
16931static int dahdichan_write_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, const char *value)
16932{
16933 struct analog_pvt *analog_p = p->sig_pvt;
16934
16935 /* We don't need to check ast_strlen_zero(value) because it's obviously not NULL.
16936 * It may even be okay for it to be an empty string, but that's a per-setting thing. */
16937
16938 /* R/O properties */
16939 if (!strcasecmp(property, "owner") || !strcasecmp(property, "callwait") || !strcasecmp(property, "threeway")) {
16940 ast_log(LOG_ERROR, "DAHDI subchannel names are R/O\n");
16941 return -1;
16942 /* R/W properties */
16943 } else if (!strcasecmp(property, "polarity")) {
16944 int polarity = atoi(value);
16947 ast_log(LOG_ERROR, "Invalid polarity: '%s'\n", value);
16948 return -1;
16949 }
16951 } else if (!strcasecmp(property, "dnd")) {
16952 int dnd = atoi(value);
16954 analog_dnd(analog_p, dnd ? 1 : 0);
16955 } else if (!strcasecmp(property, "callforward")) {
16957 if (strlen(value) >= sizeof(analog_p->call_forward) - 1) {
16958 ast_log(LOG_ERROR, "Provided call forwarding target '%s' is too long\n", value);
16959 }
16960 ast_copy_string(analog_p->call_forward, value, sizeof(analog_p->call_forward)); /* Could be empty to clear value */
16961 } else if (!strcasecmp(property, "lastexten")) {
16963 if (strlen(value) >= sizeof(analog_p->lastexten) - 1) {
16964 ast_log(LOG_ERROR, "Provided lastexten target '%s' is too long\n", value);
16965 }
16966 ast_copy_string(analog_p->lastexten, value, sizeof(analog_p->lastexten)); /* Could be empty to clear value */
16967 } else {
16968 ast_log(LOG_ERROR, "Unknown DAHDI_CHANNEL property '%s'\n", property);
16969 return -1;
16970 }
16971 return 0;
16972}
16973#undef REQUIRE_FXO_SIG
16974
16975static int dahdichan_helper(struct ast_channel *chan, char *data, const char *value, char *buffer, size_t buflen)
16976{
16977 char *parse;
16978 struct dahdi_pvt *pvt;
16979 struct dahdi_params dahdip;
16980 int res;
16982 AST_APP_ARG(property);
16983 AST_APP_ARG(dahdichan);
16984 );
16985
16986 parse = ast_strdupa(data);
16988
16989 if (buflen > 0) {
16990 *buffer = '\0';
16991 }
16992
16993 if (!ast_strlen_zero(args.dahdichan)) {
16994 /* DAHDI channel number explicitly provided, find it. */
16995 int channo = atoi(args.dahdichan);
16996 pvt = find_channel(channo);
16997 if (!pvt) {
16998 ast_log(LOG_ERROR, "DAHDI channel %d does not exist\n", channo);
16999 return -1;
17000 }
17001 } else {
17002 /* No channel specified explicitly, so implicitly use the current channel, in which case it must be a DAHDI channel. */
17003 if (!chan || !ast_channel_tech(chan) || strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
17004 ast_log(LOG_WARNING, "%s is not a DAHDI channel, and no DAHDI channel specified\n", ast_channel_name(chan));
17005 return -1;
17006 }
17007 pvt = ast_channel_tech_pvt(chan);
17008 }
17009
17010 memset(&dahdip, 0, sizeof(dahdip));
17011 if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
17012 ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->channel, strerror(errno));
17013 return -1;
17014 }
17015
17016 /* We have the channel private to use. */
17017 ast_mutex_lock(&pvt->lock);
17018 if (value) {
17019 res = dahdichan_write_property(pvt, &dahdip, args.property, value);
17020 } else {
17021 res = dahdichan_read_property(pvt, &dahdip, args.property, buffer, buflen);
17022 }
17023 ast_mutex_unlock(&pvt->lock);
17024 return res;
17025}
17026
17027static int dahdichan_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
17028{
17029 return dahdichan_helper(chan, data, NULL, buffer, buflen);
17030}
17031
17032static int dahdichan_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
17033{
17034 return dahdichan_helper(chan, data, value, NULL, 0);
17035}
17036
17038 .name = "DAHDI_CHANNEL",
17039 .write = dahdichan_write,
17040 .read = dahdichan_read,
17041};
17042
17043/*! \todo The standalone POLARITY function can and should be deprecated/removed, since its functionality is now part of DAHDI_CHANNEL. */
17044
17045static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
17046{
17047 struct dahdi_params dahdip;
17048 struct dahdi_pvt *pvt = ast_channel_tech_pvt(chan);
17049 if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
17050 ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
17051 return -1;
17052 }
17053 memset(&dahdip, 0, sizeof(dahdip));
17054 if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
17055 ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->subs[SUB_REAL].dfd, strerror(errno));
17056 return -1;
17057 }
17058 return dahdichan_read_property(ast_channel_tech_pvt(chan), &dahdip, "polarity", buffer, buflen);
17059}
17060
17061static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
17062{
17063 struct dahdi_params dahdip;
17064 struct dahdi_pvt *pvt = ast_channel_tech_pvt(chan);
17065 if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
17066 ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
17067 return -1;
17068 }
17069 memset(&dahdip, 0, sizeof(dahdip));
17070 if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
17071 ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->subs[SUB_REAL].dfd, strerror(errno));
17072 return -1;
17073 }
17074 return dahdichan_write_property(ast_channel_tech_pvt(chan), &dahdip, "polarity", value);
17075}
17076
17078 .name = "POLARITY",
17079 .write = polarity_write,
17080 .read = polarity_read,
17081};
17082
17083static int action_dahdidndon(struct mansession *s, const struct message *m)
17084{
17085 struct dahdi_pvt *p;
17086 const char *channel = astman_get_header(m, "DAHDIChannel");
17087
17088 if (ast_strlen_zero(channel)) {
17089 astman_send_error(s, m, "No channel specified");
17090 return 0;
17091 }
17093 if (!p) {
17094 astman_send_error(s, m, "No such channel");
17095 return 0;
17096 }
17097 dahdi_dnd(p, 1);
17098 astman_send_ack(s, m, "DND Enabled");
17099 return 0;
17100}
17101
17102static int action_dahdidndoff(struct mansession *s, const struct message *m)
17103{
17104 struct dahdi_pvt *p;
17105 const char *channel = astman_get_header(m, "DAHDIChannel");
17106
17107 if (ast_strlen_zero(channel)) {
17108 astman_send_error(s, m, "No channel specified");
17109 return 0;
17110 }
17112 if (!p) {
17113 astman_send_error(s, m, "No such channel");
17114 return 0;
17115 }
17116 dahdi_dnd(p, 0);
17117 astman_send_ack(s, m, "DND Disabled");
17118 return 0;
17119}
17120
17121static int action_transfer(struct mansession *s, const struct message *m)
17122{
17123 struct dahdi_pvt *p;
17124 const char *channel = astman_get_header(m, "DAHDIChannel");
17125
17126 if (ast_strlen_zero(channel)) {
17127 astman_send_error(s, m, "No channel specified");
17128 return 0;
17129 }
17131 if (!p) {
17132 astman_send_error(s, m, "No such channel");
17133 return 0;
17134 }
17135 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
17136 astman_send_error(s, m, "Channel signaling is not analog");
17137 return 0;
17138 }
17140 astman_send_ack(s, m, "DAHDITransfer");
17141 return 0;
17142}
17143
17144static int action_transferhangup(struct mansession *s, const struct message *m)
17145{
17146 struct dahdi_pvt *p;
17147 const char *channel = astman_get_header(m, "DAHDIChannel");
17148
17149 if (ast_strlen_zero(channel)) {
17150 astman_send_error(s, m, "No channel specified");
17151 return 0;
17152 }
17154 if (!p) {
17155 astman_send_error(s, m, "No such channel");
17156 return 0;
17157 }
17158 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
17159 astman_send_error(s, m, "Channel signaling is not analog");
17160 return 0;
17161 }
17163 astman_send_ack(s, m, "DAHDIHangup");
17164 return 0;
17165}
17166
17167static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
17168{
17169 struct dahdi_pvt *p;
17170 const char *channel = astman_get_header(m, "DAHDIChannel");
17171 const char *number = astman_get_header(m, "Number");
17172 int i;
17173
17174 if (ast_strlen_zero(channel)) {
17175 astman_send_error(s, m, "No channel specified");
17176 return 0;
17177 }
17178 if (ast_strlen_zero(number)) {
17179 astman_send_error(s, m, "No number specified");
17180 return 0;
17181 }
17183 if (!p) {
17184 astman_send_error(s, m, "No such channel");
17185 return 0;
17186 }
17187 if (!p->owner) {
17188 astman_send_error(s, m, "Channel does not have it's owner");
17189 return 0;
17190 }
17191 for (i = 0; i < strlen(number); i++) {
17192 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = number[i] };
17193 dahdi_queue_frame(p, &f);
17194 }
17195 astman_send_ack(s, m, "DAHDIDialOffhook");
17196 return 0;
17197}
17198
17199static int action_dahdishowchannels(struct mansession *s, const struct message *m)
17200{
17201 struct dahdi_pvt *tmp = NULL;
17202 const char *id = astman_get_header(m, "ActionID");
17203 const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
17204 char idText[256];
17205 int channels = 0;
17206 int dahdichanquery;
17207
17208 if (!dahdichannel || sscanf(dahdichannel, "%30d", &dahdichanquery) != 1) {
17209 /* Not numeric string. */
17210 dahdichanquery = -1;
17211 }
17212
17213 idText[0] = '\0';
17214 if (!ast_strlen_zero(id)) {
17215 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17216 }
17217
17218 astman_send_listack(s, m, "DAHDI channel status will follow", "start");
17219
17221
17222 for (tmp = iflist; tmp; tmp = tmp->next) {
17223 if (tmp->channel > 0) {
17224 int alm;
17225
17226 /* If a specific channel is queried for, only deliver status for that channel */
17227 if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
17228 continue;
17229
17230 alm = get_alarms(tmp);
17231 channels++;
17232 if (tmp->owner) {
17233 /* Add data if we have a current call */
17234 astman_append(s,
17235 "Event: DAHDIShowChannels\r\n"
17236 "DAHDIChannel: %d\r\n"
17237 "Channel: %s\r\n"
17238 "Uniqueid: %s\r\n"
17239 "AccountCode: %s\r\n"
17240 "Signalling: %s\r\n"
17241 "SignallingCode: %d\r\n"
17242 "Context: %s\r\n"
17243 "DND: %s\r\n"
17244 "Alarm: %s\r\n"
17245 "Description: %s\r\n"
17246 "%s"
17247 "\r\n",
17248 tmp->channel,
17249 ast_channel_name(tmp->owner),
17252 sig2str(tmp->sig),
17253 tmp->sig,
17254 tmp->context,
17255 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17256 alarm2str(alm),
17257 tmp->description, idText);
17258 } else {
17259 astman_append(s,
17260 "Event: DAHDIShowChannels\r\n"
17261 "DAHDIChannel: %d\r\n"
17262 "Signalling: %s\r\n"
17263 "SignallingCode: %d\r\n"
17264 "Context: %s\r\n"
17265 "DND: %s\r\n"
17266 "Alarm: %s\r\n"
17267 "Description: %s\r\n"
17268 "%s"
17269 "\r\n",
17270 tmp->channel, sig2str(tmp->sig), tmp->sig,
17271 tmp->context,
17272 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17273 alarm2str(alm),
17274 tmp->description, idText);
17275 }
17276 }
17277 }
17278
17280
17281 astman_send_list_complete_start(s, m, "DAHDIShowChannelsComplete", channels);
17282 astman_append(s, "Items: %d\r\n", channels);
17284 return 0;
17285}
17286
17287static int action_dahdishowstatus(struct mansession *s, const struct message *m)
17288{
17289 const char *id = astman_get_header(m, "ActionID");
17290 int span;
17291 int res;
17292 char alarmstr[50];
17293 int ctl;
17294 char idText[256];
17295 int numspans = 0;
17296 struct dahdi_spaninfo spaninfo;
17297
17298 ctl = open("/dev/dahdi/ctl", O_RDWR);
17299 if (ctl < 0) {
17300 astman_send_error(s, m, "No DAHDI detected");
17301 return 0;
17302 }
17303
17304 idText[0] = '\0';
17305 if (!ast_strlen_zero(id)) {
17306 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17307 }
17308 astman_send_listack(s, m, "DAHDI span statuses will follow", "start");
17309
17310 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
17311 spaninfo.spanno = span;
17312 res = ioctl(ctl, DAHDI_SPANSTAT, &spaninfo);
17313 if (res) {
17314 continue;
17315 }
17316 numspans++;
17317 build_alarm_info(alarmstr, &spaninfo);
17318 astman_append(s,
17319 "Event: DAHDIShowStatus\r\n"
17320 "Span: %d\r\n"
17321 "Description: %s\r\n"
17322 "Alarms: %s\r\n"
17323 "IRQ: %d\r\n"
17324 "bpviol: %d\r\n"
17325 "CRC: %d\r\n"
17326 "Framing: %s\r\n"
17327 "Coding: %s\r\n"
17328 "Options: %s\r\n"
17329 "LBO: %s\r\n"
17330 "%s"
17331 "\r\n",
17332 span, spaninfo.desc, alarmstr, spaninfo.irqmisses, spaninfo.bpvcount, spaninfo.crc4count,
17333 spaninfo.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
17334 spaninfo.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
17335 spaninfo.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
17336 "CAS",
17337 spaninfo.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
17338 spaninfo.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
17339 spaninfo.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
17340 "Unk",
17341 spaninfo.lineconfig & DAHDI_CONFIG_CRC4 ?
17342 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
17343 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
17344 lbostr[spaninfo.lbo],
17345 idText);
17346 }
17347 close(ctl);
17348
17349 astman_send_list_complete_start(s, m, "DAHDIShowStatusComplete", numspans);
17350 astman_append(s, "Items: %d\r\n", numspans);
17352 return 0;
17353}
17354
17355#if defined(HAVE_PRI)
17356static int action_prishowspans(struct mansession *s, const struct message *m)
17357{
17358 int count;
17359 int idx;
17360 int span_query;
17361 struct dahdi_pri *dspan;
17362 const char *id = astman_get_header(m, "ActionID");
17363 const char *span_str = astman_get_header(m, "Span");
17364 char action_id[256];
17365 const char *show_cmd = "PRIShowSpans";
17366
17367 /* NOTE: Asking for span 0 gets all spans. */
17368 if (!ast_strlen_zero(span_str)) {
17369 span_query = atoi(span_str);
17370 } else {
17371 span_query = 0;
17372 }
17373
17374 if (!ast_strlen_zero(id)) {
17375 snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
17376 } else {
17377 action_id[0] = '\0';
17378 }
17379
17380 astman_send_listack(s, m, "Span status will follow", "start");
17381
17382 count = 0;
17383 for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
17384 dspan = &pris[idx];
17385
17386 /* If a specific span is asked for, only deliver status for that span. */
17387 if (0 < span_query && dspan->pri.span != span_query) {
17388 continue;
17389 }
17390
17391 if (dspan->pri.pri) {
17392 count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
17393 action_id);
17394 }
17395 }
17396
17397 astman_send_list_complete_start(s, m, "PRIShowSpansComplete", count);
17398 astman_append(s, "Items: %d\r\n", count);
17400 return 0;
17401}
17402#endif /* defined(HAVE_PRI) */
17403
17404#if defined(HAVE_SS7)
17405static int linkset_addsigchan(int sigchan)
17406{
17407 struct dahdi_ss7 *link;
17408 int res;
17409 int curfd;
17410 struct dahdi_params params;
17411 struct dahdi_bufferinfo bi;
17412 struct dahdi_spaninfo si;
17413
17414 if (sigchan < 0) {
17415 ast_log(LOG_ERROR, "Invalid sigchan!\n");
17416 return -1;
17417 }
17418 if (cur_ss7type < 0) {
17419 ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
17420 return -1;
17421 }
17422 if (cur_pointcode < 0) {
17423 ast_log(LOG_ERROR, "Unspecified pointcode!\n");
17424 return -1;
17425 }
17426 if (cur_adjpointcode < 0) {
17427 ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
17428 return -1;
17429 }
17430 if (cur_defaultdpc < 0) {
17431 ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
17432 return -1;
17433 }
17434 if (cur_networkindicator < 0) {
17435 ast_log(LOG_ERROR, "Invalid networkindicator!\n");
17436 return -1;
17437 }
17438 link = ss7_resolve_linkset(cur_linkset);
17439 if (!link) {
17440 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
17441 return -1;
17442 }
17443 if (link->ss7.numsigchans >= SIG_SS7_NUM_DCHANS) {
17444 ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
17445 return -1;
17446 }
17447
17448 curfd = link->ss7.numsigchans;
17449
17450 /* Open signaling channel */
17451 link->ss7.fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
17452 if (link->ss7.fds[curfd] < 0) {
17453 ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan,
17454 strerror(errno));
17455 return -1;
17456 }
17457 if (ioctl(link->ss7.fds[curfd], DAHDI_SPECIFY, &sigchan) == -1) {
17458 dahdi_close_ss7_fd(link, curfd);
17459 ast_log(LOG_ERROR, "Unable to specify SS7 sigchan %d (%s)\n", sigchan,
17460 strerror(errno));
17461 return -1;
17462 }
17463
17464 /* Get signaling channel parameters */
17465 memset(&params, 0, sizeof(params));
17466 res = ioctl(link->ss7.fds[curfd], DAHDI_GET_PARAMS, &params);
17467 if (res) {
17468 dahdi_close_ss7_fd(link, curfd);
17469 ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan,
17470 strerror(errno));
17471 return -1;
17472 }
17473 if (params.sigtype != DAHDI_SIG_HDLCFCS
17474 && params.sigtype != DAHDI_SIG_HARDHDLC
17475 && params.sigtype != DAHDI_SIG_MTP2) {
17476 dahdi_close_ss7_fd(link, curfd);
17477 ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
17478 return -1;
17479 }
17480
17481 /* Set signaling channel buffer policy. */
17482 memset(&bi, 0, sizeof(bi));
17483 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
17484 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
17485 bi.numbufs = 32;
17486 bi.bufsize = 512;
17487 if (ioctl(link->ss7.fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
17488 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n",
17489 sigchan, strerror(errno));
17490 dahdi_close_ss7_fd(link, curfd);
17491 return -1;
17492 }
17493
17494 /* Get current signaling channel alarm status. */
17495 memset(&si, 0, sizeof(si));
17496 res = ioctl(link->ss7.fds[curfd], DAHDI_SPANSTAT, &si);
17497 if (res) {
17498 dahdi_close_ss7_fd(link, curfd);
17499 ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan,
17500 strerror(errno));
17501 }
17502
17503 res = sig_ss7_add_sigchan(&link->ss7, curfd, cur_ss7type,
17504 (params.sigtype == DAHDI_SIG_MTP2)
17505 ? SS7_TRANSPORT_DAHDIMTP2
17506 : SS7_TRANSPORT_DAHDIDCHAN,
17507 si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
17508 if (res) {
17509 dahdi_close_ss7_fd(link, curfd);
17510 return -1;
17511 }
17512
17513 ++link->ss7.numsigchans;
17514
17515 return 0;
17516}
17517#endif /* defined(HAVE_SS7) */
17518
17519#if defined(HAVE_SS7)
17520static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17521{
17522 int span;
17523 switch (cmd) {
17524 case CLI_INIT:
17525 e->command = "ss7 set debug {on|off} linkset";
17526 e->usage =
17527 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
17528 " Enables debugging on a given SS7 linkset\n";
17529 return NULL;
17530 case CLI_GENERATE:
17531 return NULL;
17532 }
17533
17534 if (a->argc < 6) {
17535 return CLI_SHOWUSAGE;
17536 }
17537
17538 span = atoi(a->argv[5]);
17539 if ((span < 1) || (span > NUM_SPANS)) {
17540 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
17541 return CLI_SUCCESS;
17542 }
17543 if (!linksets[span-1].ss7.ss7) {
17544 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
17545 } else {
17546 if (!strcasecmp(a->argv[3], "on")) {
17547 linksets[span - 1].ss7.debug = 1;
17548 ss7_set_debug(linksets[span-1].ss7.ss7, SIG_SS7_DEBUG);
17549 ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
17550 } else {
17551 linksets[span - 1].ss7.debug = 0;
17552 ss7_set_debug(linksets[span-1].ss7.ss7, 0);
17553 ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
17554 }
17555 }
17556
17557 return CLI_SUCCESS;
17558}
17559#endif /* defined(HAVE_SS7) */
17560
17561#if defined(HAVE_SS7)
17562static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17563{
17564 int linkset, cic;
17565 int blocked, i;
17566 int do_block = 0;
17567 unsigned int dpc;
17568
17569 switch (cmd) {
17570 case CLI_INIT:
17571 e->command = "ss7 {block|unblock} cic";
17572 e->usage =
17573 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17574 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17575 return NULL;
17576 case CLI_GENERATE:
17577 return NULL;
17578 }
17579
17580 if (a->argc == 6) {
17581 linkset = atoi(a->argv[3]);
17582 } else {
17583 return CLI_SHOWUSAGE;
17584 }
17585
17586 if (!strcasecmp(a->argv[1], "block")) {
17587 do_block = 1;
17588 } else if (strcasecmp(a->argv[1], "unblock")) {
17589 return CLI_SHOWUSAGE;
17590 }
17591
17592 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17593 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17594 return CLI_SUCCESS;
17595 }
17596
17597 if (!linksets[linkset-1].ss7.ss7) {
17598 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17599 return CLI_SUCCESS;
17600 }
17601
17602 cic = atoi(a->argv[5]);
17603 if (cic < 1) {
17604 ast_cli(a->fd, "Invalid CIC specified!\n");
17605 return CLI_SUCCESS;
17606 }
17607
17608 dpc = atoi(a->argv[4]);
17609 if (dpc < 1) {
17610 ast_cli(a->fd, "Invalid DPC specified!\n");
17611 return CLI_SUCCESS;
17612 }
17613
17614 for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
17615 if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
17616 blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
17617 if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
17618 if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
17619 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17620 } else {
17621 ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
17622 }
17623 } else if (!do_block && blocked) {
17624 ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
17625 } else {
17626 ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
17627 }
17628 return CLI_SUCCESS;
17629 }
17630 }
17631
17632 ast_cli(a->fd, "Invalid CIC specified!\n");
17633 return CLI_SUCCESS;
17634}
17635#endif /* defined(HAVE_SS7) */
17636
17637#if defined(HAVE_SS7)
17638static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17639{
17640 int linkset, i;
17641 enum {
17642 DO_BLOCK,
17643 DO_UNBLOCK,
17644 DO_RESET,
17645 } do_what;
17646
17647 switch (cmd) {
17648 case CLI_INIT:
17649 e->command = "ss7 {reset|block|unblock} linkset";
17650 e->usage =
17651 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17652 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17653 return NULL;
17654 case CLI_GENERATE:
17655 return NULL;
17656 }
17657
17658 if (a->argc == 4) {
17659 linkset = atoi(a->argv[3]);
17660 } else {
17661 return CLI_SHOWUSAGE;
17662 }
17663
17664 if (!strcasecmp(a->argv[1], "block")) {
17665 do_what = DO_BLOCK;
17666 } else if (!strcasecmp(a->argv[1], "unblock")) {
17667 do_what = DO_UNBLOCK;
17668 } else if (!strcasecmp(a->argv[1], "reset")) {
17669 do_what = DO_RESET;
17670 } else {
17671 return CLI_SHOWUSAGE;
17672 }
17673
17674 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17675 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17676 return CLI_SUCCESS;
17677 }
17678
17679 if (!linksets[linkset - 1].ss7.ss7) {
17680 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17681 return CLI_SUCCESS;
17682 }
17683
17684 for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
17685 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17686 if (linksets[linkset - 1].ss7.pvts[i]) {
17687 switch (do_what) {
17688 case DO_BLOCK:
17689 case DO_UNBLOCK:
17690 if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
17691 ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
17692 (do_what == DO_BLOCK) ? "blocking" : "unblocking",
17693 linksets[linkset - 1].ss7.pvts[i]->cic);
17694 }
17695 break;
17696 case DO_RESET:
17697 if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
17698 linksets[linkset - 1].ss7.pvts[i]->cic,
17699 linksets[linkset - 1].ss7.pvts[i]->dpc)) {
17700 ast_cli(a->fd, "Sent reset request on CIC %d\n",
17701 linksets[linkset - 1].ss7.pvts[i]->cic);
17702 }
17703 break;
17704 }
17705 }
17706 }
17707
17708 return CLI_SUCCESS;
17709}
17710#endif /* defined(HAVE_SS7) */
17711
17712#if defined(HAVE_SS7)
17713static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17714{
17715 int linkset, cic, range, chanpos;
17716 int i, dpc, orient = 0;
17717 int do_block = 0;
17718 unsigned char state[255];
17719
17720 switch (cmd) {
17721 case CLI_INIT:
17722 e->command = "ss7 {block|unblock} group";
17723 e->usage =
17724 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17725 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17726 return NULL;
17727 case CLI_GENERATE:
17728 return NULL;
17729 }
17730
17731 if (a->argc == 7 || a->argc == 8) {
17732 linkset = atoi(a->argv[3]);
17733 } else {
17734 return CLI_SHOWUSAGE;
17735 }
17736
17737 if (!strcasecmp(a->argv[1], "block")) {
17738 do_block = 1;
17739 } else if (strcasecmp(a->argv[1], "unblock")) {
17740 return CLI_SHOWUSAGE;
17741 }
17742
17743 if (a->argc == 8) {
17744 if (!strcasecmp(a->argv[7], "H")) {
17745 orient = 1;
17746 } else {
17747 return CLI_SHOWUSAGE;
17748 }
17749 }
17750
17751 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17752 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17753 return CLI_SUCCESS;
17754 }
17755
17756 if (!linksets[linkset-1].ss7.ss7) {
17757 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17758 return CLI_SUCCESS;
17759 }
17760
17761 cic = atoi(a->argv[5]);
17762 if (cic < 1) {
17763 ast_cli(a->fd, "Invalid CIC specified!\n");
17764 return CLI_SUCCESS;
17765 }
17766
17767 range = atoi(a->argv[6]);
17768 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17769 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17770 ast_cli(a->fd, "Invalid range specified!\n");
17771 return CLI_SUCCESS;
17772 }
17773
17774 dpc = atoi(a->argv[4]);
17775 if (dpc < 1) {
17776 ast_cli(a->fd, "Invalid DPC specified!\n");
17777 return CLI_SUCCESS;
17778 }
17779
17780 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17781 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17782 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17783 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17784 return CLI_SHOWUSAGE;
17785 }
17786
17787 memset(state, 0, sizeof(state));
17788 for (i = 0; i <= range; ++i) {
17789 state[i] = 1;
17790 }
17791
17792 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17793 chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
17794 if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
17795 ast_cli(a->fd, "Unable allocate new ss7call\n");
17796 } else {
17797 ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17798 orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
17799 }
17800
17801 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17802
17803 /* Break poll on the linkset so it sends our messages */
17804 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17805 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17806 }
17807 return CLI_SUCCESS;
17808}
17809#endif /* defined(HAVE_SS7) */
17810
17811#if defined(HAVE_SS7)
17812static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17813{
17814 int linkset, cic, range;
17815 unsigned int dpc;
17816
17817 switch (cmd) {
17818 case CLI_INIT:
17819 e->command = "ss7 reset group";
17820 e->usage =
17821 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17822 " Send a GRS for the given CIC range on the specified linkset\n";
17823 return NULL;
17824 case CLI_GENERATE:
17825 return NULL;
17826 }
17827
17828 if (a->argc == 7) {
17829 linkset = atoi(a->argv[3]);
17830 } else {
17831 return CLI_SHOWUSAGE;
17832 }
17833
17834 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17835 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17836 return CLI_SUCCESS;
17837 }
17838
17839 if (!linksets[linkset-1].ss7.ss7) {
17840 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17841 return CLI_SUCCESS;
17842 }
17843
17844 cic = atoi(a->argv[5]);
17845
17846 if (cic < 1) {
17847 ast_cli(a->fd, "Invalid CIC specified!\n");
17848 return CLI_SUCCESS;
17849 }
17850
17851 range = atoi(a->argv[6]);
17852 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17853 ast_cli(a->fd, "Invalid range specified!\n");
17854 return CLI_SUCCESS;
17855 }
17856
17857 dpc = atoi(a->argv[4]);
17858 if (dpc < 1) {
17859 ast_cli(a->fd, "Invalid DPC specified!\n");
17860 return CLI_SUCCESS;
17861 }
17862
17863 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17864 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17865 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17866 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17867 return CLI_SHOWUSAGE;
17868 }
17869
17870 if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
17871 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17872 } else {
17873 ast_cli(a->fd, "GRS sent ... \n");
17874 }
17875
17876 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17877
17878 /* Break poll on the linkset so it sends our messages */
17879 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17880 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17881 }
17882 return CLI_SUCCESS;
17883}
17884#endif /* defined(HAVE_SS7) */
17885
17886#if defined(HAVE_SS7)
17887static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17888{
17889 int linkset;
17890
17891 switch (cmd) {
17892 case CLI_INIT:
17893 e->command = "ss7 show calls";
17894 e->usage =
17895 "Usage: ss7 show calls <linkset>\n"
17896 " Show SS7 calls on the specified linkset\n";
17897 return NULL;
17898 case CLI_GENERATE:
17899 return NULL;
17900 }
17901
17902 if (a->argc == 4) {
17903 linkset = atoi(a->argv[3]);
17904 } else {
17905 return CLI_SHOWUSAGE;
17906 }
17907
17908 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17909 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17910 return CLI_SUCCESS;
17911 }
17912
17913 if (!linksets[linkset-1].ss7.ss7) {
17914 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17915 return CLI_SUCCESS;
17916 }
17917
17918 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17919 isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
17920 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17921
17922 return CLI_SUCCESS;
17923}
17924#endif /* defined(HAVE_SS7) */
17925
17926#if defined(HAVE_SS7)
17927static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17928{
17929 int linkset, cic, res;
17930 unsigned int dpc;
17931
17932 switch (cmd) {
17933 case CLI_INIT:
17934 e->command = "ss7 reset cic";
17935 e->usage =
17936 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17937 " Send a RSC for the given CIC on the specified linkset\n";
17938 return NULL;
17939 case CLI_GENERATE:
17940 return NULL;
17941 }
17942
17943 if (a->argc == 6) {
17944 linkset = atoi(a->argv[3]);
17945 } else {
17946 return CLI_SHOWUSAGE;
17947 }
17948
17949 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17950 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17951 return CLI_SUCCESS;
17952 }
17953
17954 if (!linksets[linkset-1].ss7.ss7) {
17955 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17956 return CLI_SUCCESS;
17957 }
17958
17959 cic = atoi(a->argv[5]);
17960
17961 if (cic < 1) {
17962 ast_cli(a->fd, "Invalid CIC specified!\n");
17963 return CLI_SUCCESS;
17964 }
17965
17966 dpc = atoi(a->argv[4]);
17967 if (dpc < 1) {
17968 ast_cli(a->fd, "Invalid DPC specified!\n");
17969 return CLI_SUCCESS;
17970 }
17971
17972 res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
17973
17974 ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
17975
17976 return CLI_SUCCESS;
17977}
17978#endif /* defined(HAVE_SS7) */
17979
17980#if defined(HAVE_SS7)
17981static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17982{
17983 int linkset;
17984 unsigned int slc;
17985 unsigned int arg = 0;
17986 const char *res;
17987
17988 switch (cmd) {
17989 case CLI_INIT:
17990 e->command = "ss7 mtp3";
17991 e->usage =
17992 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
17993 " Send a NET MNG message\n"
17994 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
17995 return NULL;
17996 case CLI_GENERATE:
17997 return NULL;
17998 }
17999
18000 if (a->argc < 5) {
18001 return CLI_SHOWUSAGE;
18002 }
18003
18004 linkset = atoi(a->argv[2]);
18005 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18006 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
18007 return CLI_SUCCESS;
18008 }
18009 if (!linksets[linkset-1].ss7.ss7) {
18010 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18011 return CLI_SUCCESS;
18012 }
18013
18014 slc = atoi(a->argv[3]);
18015
18016 if (a->argc == 6) {
18017 arg = atoi(a->argv[5]);
18018 }
18019
18020 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
18021 res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
18022 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
18023
18024 /* Break poll on the linkset so it sends our messages */
18025 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
18026 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
18027 }
18028
18029 ast_cli(a->fd, "%s", res);
18030
18031 return CLI_SUCCESS;
18032}
18033#endif /* defined(HAVE_SS7) */
18034
18035#if defined(HAVE_SS7)
18036static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18037{
18038 int linkset;
18039 unsigned int slc = 0;
18040
18041 switch (cmd) {
18042 case CLI_INIT:
18043 e->command = "ss7 restart mtp3";
18044 e->usage =
18045 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
18046 " Restart link\n";
18047 return NULL;
18048 case CLI_GENERATE:
18049 return NULL;
18050 }
18051
18052 if (a->argc < 5) {
18053 return CLI_SHOWUSAGE;
18054 }
18055
18056 linkset = atoi(a->argv[3]);
18057 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18058 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
18059 return CLI_SUCCESS;
18060 }
18061 if (!linksets[linkset-1].ss7.ss7) {
18062 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18063 return CLI_SUCCESS;
18064 }
18065
18066 slc = atoi(a->argv[4]);
18067
18068 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
18069 mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
18070 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
18071
18072 /* Break poll on the linkset so it sends our messages */
18073 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
18074 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
18075 }
18076
18077 return CLI_SUCCESS;
18078}
18079#endif /* defined(HAVE_SS7) */
18080
18081#if defined(HAVE_SS7)
18082static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18083{
18084 int linkset;
18085 struct sig_ss7_linkset *ss7;
18086 switch (cmd) {
18087 case CLI_INIT:
18088 e->command = "ss7 show linkset";
18089 e->usage =
18090 "Usage: ss7 show linkset <span>\n"
18091 " Shows the status of an SS7 linkset.\n";
18092 return NULL;
18093 case CLI_GENERATE:
18094 return NULL;
18095 }
18096
18097 if (a->argc < 4) {
18098 return CLI_SHOWUSAGE;
18099 }
18100
18101 linkset = atoi(a->argv[3]);
18102 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18103 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
18104 return CLI_SUCCESS;
18105 }
18106 ss7 = &linksets[linkset - 1].ss7;
18107 if (!ss7->ss7) {
18108 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18109 return CLI_SUCCESS;
18110 }
18111
18112 ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
18113 ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
18114 ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
18115 ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
18116 ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
18117 ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
18118 ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
18119 ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
18120 ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
18121 ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
18122
18123 return CLI_SUCCESS;
18124}
18125#endif /* defined(HAVE_SS7) */
18126
18127#if defined(HAVE_SS7)
18128static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18129{
18130 int linkset;
18131
18132 switch (cmd) {
18133 case CLI_INIT:
18134 e->command = "ss7 show channels";
18135 e->usage =
18136 "Usage: ss7 show channels\n"
18137 " Displays SS7 channel information at a glance.\n";
18138 return NULL;
18139 case CLI_GENERATE:
18140 return NULL;
18141 }
18142
18143 if (a->argc != 3) {
18144 return CLI_SHOWUSAGE;
18145 }
18146
18148 for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
18149 if (linksets[linkset].ss7.ss7) {
18150 sig_ss7_cli_show_channels(a->fd, &linksets[linkset].ss7);
18151 }
18152 }
18153 return CLI_SUCCESS;
18154}
18155#endif /* defined(HAVE_SS7) */
18156
18157#if defined(HAVE_SS7)
18158static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18159{
18160#define FORMAT "%5s %5s %6s %12s %-12s\n"
18161#define FORMAT2 "%5i %5i %6i %12s %-12s\n"
18162 int i, linkset, dpc = 0;
18163 struct sig_ss7_linkset *ss7;
18164 char *state;
18165 char blocking[12];
18166
18167 switch (cmd) {
18168 case CLI_INIT:
18169 e->command = "ss7 show cics";
18170 e->usage =
18171 "Usage: ss7 show cics <linkset> [dpc]\n"
18172 " Shows the cics of an SS7 linkset.\n";
18173 return NULL;
18174 case CLI_GENERATE:
18175 return NULL;
18176 }
18177
18178 if (a->argc < 4 || a->argc > 5) {
18179 return CLI_SHOWUSAGE;
18180 }
18181
18182 linkset = atoi(a->argv[3]);
18183
18184 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18185 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
18186 return CLI_SUCCESS;
18187 }
18188
18189 if (!linksets[linkset-1].ss7.ss7) {
18190 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18191 return CLI_SUCCESS;
18192 }
18193 ss7 = &linksets[linkset-1].ss7;
18194
18195 if (a->argc == 5) {
18196 dpc = atoi(a->argv[4]);
18197 if (dpc < 1) {
18198 ast_cli(a->fd, "Invalid DPC specified!\n");
18199 return CLI_SUCCESS;
18200 }
18201 }
18202
18203 ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
18204
18205 for (i = 0; i < ss7->numchans; i++) {
18206 if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
18207 struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
18208
18209 if (ss7->pvts[i]->owner) {
18210 state = "Used";
18211 } else if (ss7->pvts[i]->ss7call) {
18212 state = "Pending";
18213 } else if (!p->inservice) {
18214 state = "NotInServ";
18215 } else {
18216 state = "Idle";
18217 }
18218
18219 if (p->locallyblocked) {
18220 strcpy(blocking, "L:");
18222 strcat(blocking, "M");
18223 } else {
18224 strcat(blocking, " ");
18225 }
18226
18228 strcat(blocking, "H");
18229 } else {
18230 strcat(blocking, " ");
18231 }
18232 } else {
18233 strcpy(blocking, " ");
18234 }
18235
18236 if (p->remotelyblocked) {
18237 strcat(blocking, " R:");
18239 strcat(blocking, "M");
18240 } else {
18241 strcat(blocking, " ");
18242 }
18243
18245 strcat(blocking, "H");
18246 } else {
18247 strcat(blocking, " ");
18248 }
18249 }
18250
18251 ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
18252 }
18253 }
18254
18255 return CLI_SUCCESS;
18256#undef FORMAT
18257#undef FORMAT2
18258}
18259#endif /* defined(HAVE_SS7) */
18260
18261#if defined(HAVE_SS7)
18262static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18263{
18264 switch (cmd) {
18265 case CLI_INIT:
18266 e->command = "ss7 show version";
18267 e->usage =
18268 "Usage: ss7 show version\n"
18269 " Show the libss7 version\n";
18270 return NULL;
18271 case CLI_GENERATE:
18272 return NULL;
18273 }
18274
18275 ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
18276
18277 return CLI_SUCCESS;
18278}
18279#endif /* defined(HAVE_SS7) */
18280
18281#if defined(HAVE_SS7)
18282static struct ast_cli_entry dahdi_ss7_cli[] = {
18283 AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
18284 AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
18285 AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
18286 AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
18287 AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
18288 AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
18289 AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
18290 AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
18291 AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
18292 AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
18293 AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
18294 AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
18295 AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
18296};
18297#endif /* defined(HAVE_SS7) */
18298
18299#if defined(HAVE_PRI)
18300#if defined(HAVE_PRI_CCSS)
18301/*!
18302 * \internal
18303 * \brief CC agent initialization.
18304 * \since 1.8
18305 *
18306 * \param agent CC core agent control.
18307 * \param chan Original channel the agent will attempt to recall.
18308 *
18309 * \details
18310 * This callback is called when the CC core is initialized. Agents should allocate
18311 * any private data necessary for the call and assign it to the private_data
18312 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
18313 * specific agent type, they should be set in this function as well.
18314 *
18315 * \retval 0 on success.
18316 * \retval -1 on error.
18317 */
18318static int dahdi_pri_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
18319{
18320 struct dahdi_pvt *pvt;
18321 struct sig_pri_chan *pvt_chan;
18322 int res;
18323
18324 ast_assert(!strcmp(ast_channel_tech(chan)->type, "DAHDI"));
18325
18326 pvt = ast_channel_tech_pvt(chan);
18327 if (dahdi_sig_pri_lib_handles(pvt->sig)) {
18328 pvt_chan = pvt->sig_pvt;
18329 } else {
18330 pvt_chan = NULL;
18331 }
18332 if (!pvt_chan) {
18333 return -1;
18334 }
18335
18337
18338 res = sig_pri_cc_agent_init(agent, pvt_chan);
18339 if (res) {
18341 }
18342 return res;
18343}
18344#endif /* defined(HAVE_PRI_CCSS) */
18345#endif /* defined(HAVE_PRI) */
18346
18347#if defined(HAVE_PRI)
18348#if defined(HAVE_PRI_CCSS)
18349/*!
18350 * \internal
18351 * \brief Destroy private data on the agent.
18352 * \since 1.8
18353 *
18354 * \param agent CC core agent control.
18355 *
18356 * \details
18357 * The core will call this function upon completion
18358 * or failure of CC.
18359 */
18360static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent *agent)
18361{
18363
18365}
18366#endif /* defined(HAVE_PRI_CCSS) */
18367#endif /* defined(HAVE_PRI) */
18368
18369#if defined(HAVE_PRI)
18370#if defined(HAVE_PRI_CCSS)
18371static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = {
18372 .type = dahdi_pri_cc_type,
18373 .init = dahdi_pri_cc_agent_init,
18374 .start_offer_timer = sig_pri_cc_agent_start_offer_timer,
18375 .stop_offer_timer = sig_pri_cc_agent_stop_offer_timer,
18376 .respond = sig_pri_cc_agent_req_rsp,
18377 .status_request = sig_pri_cc_agent_status_req,
18378 .stop_ringing = sig_pri_cc_agent_stop_ringing,
18379 .party_b_free = sig_pri_cc_agent_party_b_free,
18380 .start_monitoring = sig_pri_cc_agent_start_monitoring,
18381 .callee_available = sig_pri_cc_agent_callee_available,
18382 .destructor = dahdi_pri_cc_agent_destructor,
18383};
18384#endif /* defined(HAVE_PRI_CCSS) */
18385#endif /* defined(HAVE_PRI) */
18386
18387#if defined(HAVE_PRI)
18388#if defined(HAVE_PRI_CCSS)
18389static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks = {
18390 .type = dahdi_pri_cc_type,
18391 .request_cc = sig_pri_cc_monitor_req_cc,
18392 .suspend = sig_pri_cc_monitor_suspend,
18393 .unsuspend = sig_pri_cc_monitor_unsuspend,
18394 .status_response = sig_pri_cc_monitor_status_rsp,
18395 .cancel_available_timer = sig_pri_cc_monitor_cancel_available_timer,
18396 .destructor = sig_pri_cc_monitor_destructor,
18397};
18398#endif /* defined(HAVE_PRI_CCSS) */
18399#endif /* defined(HAVE_PRI) */
18400
18401static int __unload_module(void)
18402{
18403 struct dahdi_pvt *p;
18404#if defined(HAVE_PRI) || defined(HAVE_SS7)
18405 int i, j;
18406#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18407
18408#ifdef HAVE_PRI
18409 for (i = 0; i < NUM_SPANS; i++) {
18410 if (pris[i].pri.master != AST_PTHREADT_NULL) {
18411 pthread_cancel(pris[i].pri.master);
18412 pthread_kill(pris[i].pri.master, SIGURG);
18413 }
18414 }
18415 ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
18416 ast_unregister_application(dahdi_send_keypad_facility_app);
18417#ifdef HAVE_PRI_PROG_W_CAUSE
18418 ast_unregister_application(dahdi_send_callrerouting_facility_app);
18419#endif
18420#endif
18421#if defined(HAVE_SS7)
18422 for (i = 0; i < NUM_SPANS; i++) {
18423 if (linksets[i].ss7.master != AST_PTHREADT_NULL) {
18424 pthread_cancel(linksets[i].ss7.master);
18425 pthread_kill(linksets[i].ss7.master, SIGURG);
18426 }
18427 }
18428 ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
18429#endif /* defined(HAVE_SS7) */
18430#if defined(HAVE_OPENR2)
18431 dahdi_r2_destroy_links();
18432 ast_cli_unregister_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
18433 ast_unregister_application(dahdi_accept_r2_call_app);
18434#endif
18435
18438
18440 ast_manager_unregister("DAHDIDialOffhook");
18441 ast_manager_unregister("DAHDIHangup");
18442 ast_manager_unregister("DAHDITransfer");
18443 ast_manager_unregister("DAHDIDNDoff");
18444 ast_manager_unregister("DAHDIDNDon");
18445 ast_manager_unregister("DAHDIShowChannels");
18446 ast_manager_unregister("DAHDIShowStatus");
18447 ast_manager_unregister("DAHDIRestart");
18448#if defined(HAVE_PRI)
18449 ast_manager_unregister("PRIShowSpans");
18450 ast_manager_unregister("PRIDebugSet");
18451 ast_manager_unregister("PRIDebugFileSet");
18452 ast_manager_unregister("PRIDebugFileUnset");
18453#endif /* defined(HAVE_PRI) */
18455
18456 /* Hangup all interfaces if they have an owner */
18458 for (p = iflist; p; p = p->next) {
18459 if (p->owner)
18461 }
18463
18466 pthread_cancel(monitor_thread);
18467 pthread_kill(monitor_thread, SIGURG);
18468 pthread_join(monitor_thread, NULL);
18469 }
18472
18474
18475#if defined(HAVE_PRI)
18476 for (i = 0; i < NUM_SPANS; i++) {
18477 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
18478 pthread_join(pris[i].pri.master, NULL);
18479 }
18480 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) {
18481 dahdi_close_pri_fd(&(pris[i]), j);
18482 }
18483 sig_pri_stop_pri(&pris[i].pri);
18484 }
18485#if defined(HAVE_PRI_CCSS)
18486 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks);
18487 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks);
18488#endif /* defined(HAVE_PRI_CCSS) */
18490#endif
18491
18492#if defined(HAVE_SS7)
18493 for (i = 0; i < NUM_SPANS; i++) {
18494 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
18495 pthread_join(linksets[i].ss7.master, NULL);
18496 }
18497 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
18498 dahdi_close_ss7_fd(&(linksets[i]), j);
18499 }
18500 if (linksets[i].ss7.ss7) {
18501 ss7_destroy(linksets[i].ss7.ss7);
18502 linksets[i].ss7.ss7 = NULL;
18503 }
18504 }
18505#endif /* defined(HAVE_SS7) */
18507
18509
18512 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
18513 return 0;
18514}
18515
18516static int unload_module(void)
18517{
18518#if defined(HAVE_PRI) || defined(HAVE_SS7)
18519 int y;
18520#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18521#ifdef HAVE_PRI
18522 for (y = 0; y < NUM_SPANS; y++)
18523 ast_mutex_destroy(&pris[y].pri.lock);
18524#endif
18525#if defined(HAVE_SS7)
18526 for (y = 0; y < NUM_SPANS; y++)
18527 ast_mutex_destroy(&linksets[y].ss7.lock);
18528#endif /* defined(HAVE_SS7) */
18529 return __unload_module();
18530}
18531
18532static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
18533{
18534 char *c, *chan;
18535 int x, start, finish;
18536 struct dahdi_pvt *tmp;
18537
18538 if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
18539 ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
18540 return -1;
18541 }
18542
18543 c = ast_strdupa(value);
18544
18545 while ((chan = strsep(&c, ","))) {
18546 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
18547 /* Range */
18548 } else if (sscanf(chan, "%30d", &start)) {
18549 /* Just one */
18550 finish = start;
18551 } else if (!strcasecmp(chan, "pseudo")) {
18552 finish = start = CHAN_PSEUDO;
18553 } else {
18554 ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
18555 return -1;
18556 }
18557 if (finish < start) {
18558 ast_log(LOG_WARNING, "Silliness: %d < %d\n", start, finish);
18559 x = finish;
18560 finish = start;
18561 start = x;
18562 }
18563
18564 for (x = start; x <= finish; x++) {
18565 if (conf->wanted_channels_start &&
18566 (x < conf->wanted_channels_start ||
18567 x > conf->wanted_channels_end)
18568 ) {
18569 continue;
18570 }
18571 tmp = mkintf(x, conf, reload);
18572
18573 if (tmp) {
18574 ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
18575 } else {
18576 ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
18577 (reload == 1) ? "reconfigure" : "register", value);
18578 return -1;
18579 }
18580 if (x == CHAN_PSEUDO) {
18581 has_pseudo = 1;
18582 }
18583 }
18584 }
18585
18586 return 0;
18587}
18588
18589/** The length of the parameters list of 'dahdichan'.
18590 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18591#define MAX_CHANLIST_LEN 80
18592
18593static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
18594{
18595 char *parse = ast_strdupa(data);
18596 char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
18597 unsigned int param_count;
18598 unsigned int x;
18599
18600 if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
18601 return;
18602
18603 memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
18604
18605 /* first parameter is tap length, process it here */
18606
18607 x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
18608
18609 if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
18610 confp->chan.echocancel.head.tap_length = x;
18611 else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
18612 confp->chan.echocancel.head.tap_length = 128;
18613
18614 /* now process any remaining parameters */
18615
18616 for (x = 1; x < param_count; x++) {
18617 struct {
18618 char *name;
18619 char *value;
18620 } param;
18621
18622 if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
18623 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, params[x]);
18624 continue;
18625 }
18626
18627 if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
18628 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, param.name);
18629 continue;
18630 }
18631
18632 strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
18633
18634 if (param.value) {
18635 if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
18636 ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line, param.value);
18637 continue;
18638 }
18639 }
18640 confp->chan.echocancel.head.param_count++;
18641 }
18642}
18643
18644#if defined(HAVE_PRI)
18645#if defined(HAVE_PRI_DISPLAY_TEXT)
18646/*!
18647 * \internal
18648 * \brief Determine the configured display text options.
18649 * \since 10.0
18650 *
18651 * \param value Configuration value string.
18652 *
18653 * \return Configured display text option flags.
18654 */
18655static unsigned long dahdi_display_text_option(const char *value)
18656{
18657 char *val_str;
18658 char *opt_str;
18659 unsigned long options;
18660
18661 options = 0;
18662 val_str = ast_strdupa(value);
18663
18664 for (;;) {
18665 opt_str = strsep(&val_str, ",");
18666 if (!opt_str) {
18667 break;
18668 }
18669 opt_str = ast_strip(opt_str);
18670 if (!*opt_str) {
18671 continue;
18672 }
18673
18674 if (!strcasecmp(opt_str, "block")) {
18675 options |= PRI_DISPLAY_OPTION_BLOCK;
18676 } else if (!strcasecmp(opt_str, "name_initial")) {
18677 options |= PRI_DISPLAY_OPTION_NAME_INITIAL;
18678 } else if (!strcasecmp(opt_str, "name_update")) {
18679 options |= PRI_DISPLAY_OPTION_NAME_UPDATE;
18680 } else if (!strcasecmp(opt_str, "name")) {
18681 options |= (PRI_DISPLAY_OPTION_NAME_INITIAL | PRI_DISPLAY_OPTION_NAME_UPDATE);
18682 } else if (!strcasecmp(opt_str, "text")) {
18683 options |= PRI_DISPLAY_OPTION_TEXT;
18684 }
18685 }
18686 return options;
18687}
18688#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18689#endif /* defined(HAVE_PRI) */
18690
18691#if defined(HAVE_PRI)
18692#if defined(HAVE_PRI_DATETIME_SEND)
18693/*!
18694 * \internal
18695 * \brief Determine the configured date/time send policy option.
18696 * \since 10.0
18697 *
18698 * \param value Configuration value string.
18699 *
18700 * \return Configured date/time send policy option.
18701 */
18702static int dahdi_datetime_send_option(const char *value)
18703{
18704 int option;
18705
18706 option = PRI_DATE_TIME_SEND_DEFAULT;
18707
18708 if (ast_false(value)) {
18709 option = PRI_DATE_TIME_SEND_NO;
18710 } else if (!strcasecmp(value, "date")) {
18711 option = PRI_DATE_TIME_SEND_DATE;
18712 } else if (!strcasecmp(value, "date_hh")) {
18713 option = PRI_DATE_TIME_SEND_DATE_HH;
18714 } else if (!strcasecmp(value, "date_hhmm")) {
18715 option = PRI_DATE_TIME_SEND_DATE_HHMM;
18716 } else if (!strcasecmp(value, "date_hhmmss")) {
18717 option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
18718 }
18719
18720 return option;
18721}
18722#endif /* defined(HAVE_PRI_DATETIME_SEND) */
18723#endif /* defined(HAVE_PRI) */
18724
18725/*! process_dahdi() - ignore keyword 'channel' and similar */
18726#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18727/*! process_dahdi() - No warnings on non-existing configuration keywords */
18728#define PROC_DAHDI_OPT_NOWARN (1 << 1)
18729
18730static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
18731{
18732 int count_pattern = 0;
18733 int norval = 0;
18734 char *temp = NULL;
18735
18736 for (; ;) {
18737 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18738 if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
18739 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18740 break;
18741 }
18742
18743 busy_cadence->pattern[count_pattern] = norval;
18744
18745 count_pattern++;
18746 if (count_pattern == 4) {
18747 break;
18748 }
18749
18750 temp = strchr(v->value, ',');
18751 if (temp == NULL) {
18752 break;
18753 }
18754 v->value = temp + 1;
18755 }
18756 busy_cadence->length = count_pattern;
18757
18758 if (count_pattern % 2 != 0) {
18759 /* The pattern length must be divisible by two */
18760 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18761 }
18762
18763}
18764
18765static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
18766{
18767 struct dahdi_pvt *tmp;
18768 int y;
18769 struct ast_variable *dahdichan = NULL;
18770
18771 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18773
18774 for (; v; v = v->next) {
18776 continue;
18777
18778 /* Create the interface list */
18779 if (!strcasecmp(v->name, "channel") || !strcasecmp(v->name, "channels")) {
18781 ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
18782 continue;
18783 }
18784 if (build_channels(confp, v->value, reload, v->lineno)) {
18785 if (confp->ignore_failed_channels) {
18786 ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
18787 continue;
18788 } else {
18789 return -1;
18790 }
18791 }
18792 ast_debug(1, "Channel '%s' configured.\n", v->value);
18793 } else if (!strcasecmp(v->name, "ignore_failed_channels")) {
18795 } else if (!strcasecmp(v->name, "buffers")) {
18796 if (parse_buffers_policy(v->value, &confp->chan.buf_no, &confp->chan.buf_policy)) {
18797 ast_log(LOG_WARNING, "Using default buffer policy.\n");
18798 confp->chan.buf_no = numbufs;
18799 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
18800 }
18801 } else if (!strcasecmp(v->name, "faxbuffers")) {
18802 if (!parse_buffers_policy(v->value, &confp->chan.faxbuf_no, &confp->chan.faxbuf_policy)) {
18803 confp->chan.usefaxbuffers = 1;
18804 }
18805 } else if (!strcasecmp(v->name, "dahdichan")) {
18806 /* Only process the last dahdichan value. */
18807 dahdichan = v;
18808 } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
18810 } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
18812 } else if (!strcasecmp(v->name, "dring1context")) {
18814 } else if (!strcasecmp(v->name, "dring2context")) {
18816 } else if (!strcasecmp(v->name, "dring3context")) {
18818 } else if (!strcasecmp(v->name, "dring1range")) {
18819 confp->chan.drings.ringnum[0].range = atoi(v->value);
18820 } else if (!strcasecmp(v->name, "dring2range")) {
18821 confp->chan.drings.ringnum[1].range = atoi(v->value);
18822 } else if (!strcasecmp(v->name, "dring3range")) {
18823 confp->chan.drings.ringnum[2].range = atoi(v->value);
18824 } else if (!strcasecmp(v->name, "dring1")) {
18825 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]);
18826 } else if (!strcasecmp(v->name, "dring2")) {
18827 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]);
18828 } else if (!strcasecmp(v->name, "dring3")) {
18829 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]);
18830 } else if (!strcasecmp(v->name, "usecallerid")) {
18831 confp->chan.use_callerid = ast_true(v->value);
18832 } else if (!strcasecmp(v->name, "cidsignalling")) {
18833 if (!strcasecmp(v->value, "bell"))
18835 else if (!strcasecmp(v->value, "v23"))
18837 else if (!strcasecmp(v->value, "dtmf"))
18839 else if (!strcasecmp(v->value, "smdi"))
18841 else if (!strcasecmp(v->value, "v23_jp"))
18843 else if (ast_true(v->value))
18845 } else if (!strcasecmp(v->name, "cidstart")) {
18846 if (!strcasecmp(v->value, "ring"))
18847 confp->chan.cid_start = CID_START_RING;
18848 else if (!strcasecmp(v->value, "polarity_in"))
18850 else if (!strcasecmp(v->value, "polarity"))
18852 else if (!strcasecmp(v->value, "dtmf"))
18854 else if (ast_true(v->value))
18855 confp->chan.cid_start = CID_START_RING;
18856 } else if (!strcasecmp(v->name, "threewaycalling")) {
18857 confp->chan.threewaycalling = ast_true(v->value);
18858 } else if (!strcasecmp(v->name, "threewaysilenthold")) {
18860 } else if (!strcasecmp(v->name, "cancallforward")) {
18861 confp->chan.cancallforward = ast_true(v->value);
18862 } else if (!strcasecmp(v->name, "relaxdtmf")) {
18863 if (ast_true(v->value))
18865 else
18866 confp->chan.dtmfrelax = 0;
18867 } else if (!strcasecmp(v->name, "mailbox")) {
18868 ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
18869 } else if (!strcasecmp(v->name, "description")) {
18870 ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
18871 } else if (!strcasecmp(v->name, "adsi")) {
18872 confp->chan.adsi = ast_true(v->value);
18873 } else if (!strcasecmp(v->name, "usesmdi")) {
18874 confp->chan.use_smdi = ast_true(v->value);
18875 } else if (!strcasecmp(v->name, "smdiport")) {
18876 ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
18877 } else if (!strcasecmp(v->name, "transfer")) {
18878 confp->chan.transfer = ast_true(v->value);
18879 } else if (!strcasecmp(v->name, "canpark")) {
18880 confp->chan.canpark = ast_true(v->value);
18881 } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
18882 confp->chan.echocanbridged = ast_true(v->value);
18883 } else if (!strcasecmp(v->name, "busydetect")) {
18884 confp->chan.busydetect = ast_true(v->value);
18885 } else if (!strcasecmp(v->name, "busycount")) {
18886 confp->chan.busycount = atoi(v->value);
18887 } else if (!strcasecmp(v->name, "busypattern")) {
18889 } else if (!strcasecmp(v->name, "calledsubscriberheld")) {
18891 } else if (!strcasecmp(v->name, "lastnumredial")) {
18892 confp->chan.lastnumredial = ast_true(v->value);
18893 } else if (!strcasecmp(v->name, "callprogress")) {
18894 confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
18895 if (ast_true(v->value))
18897 } else if (!strcasecmp(v->name, "waitfordialtone")) {
18898 confp->chan.waitfordialtone = atoi(v->value);
18899 } else if (!strcasecmp(v->name, "dialtone_detect")) {
18900 if (!strcasecmp(v->value, "always")) {
18901 confp->chan.dialtone_detect = -1;
18902 } else if (ast_true(v->value)) {
18904 } else if (ast_false(v->value)) {
18905 confp->chan.dialtone_detect = 0;
18906 } else {
18907 confp->chan.dialtone_detect = ast_strlen_zero(v->value) ? 0 : (8 * atoi(v->value)) / READ_SIZE;
18908 }
18909 } else if (!strcasecmp(v->name, "faxdetect")) {
18910 confp->chan.callprogress &= ~CALLPROGRESS_FAX;
18911 if (!strcasecmp(v->value, "incoming")) {
18913 } else if (!strcasecmp(v->value, "outgoing")) {
18915 } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
18917 } else if (!strcasecmp(v->name, "faxdetect_timeout")) {
18918 if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) {
18919 confp->chan.faxdetect_timeout = 0;
18920 }
18921 } else if (!strcasecmp(v->name, "firstdigit_timeout")) {
18922 if (sscanf(v->value, "%30d", &confp->chan.firstdigit_timeout) != 1
18923 || confp->chan.firstdigit_timeout <= 0) {
18925 }
18926 } else if (!strcasecmp(v->name, "interdigit_timeout")) {
18927 if (sscanf(v->value, "%30d", &confp->chan.interdigit_timeout) != 1
18928 || confp->chan.interdigit_timeout <= 0) {
18930 }
18931 } else if (!strcasecmp(v->name, "matchdigit_timeout")) {
18932 if (sscanf(v->value, "%30d", &confp->chan.matchdigit_timeout) != 1
18933 || confp->chan.matchdigit_timeout <= 0) {
18935 }
18936 } else if (!strcasecmp(v->name, "echocancel")) {
18937 process_echocancel(confp, v->value, v->lineno);
18938 } else if (!strcasecmp(v->name, "echotraining")) {
18939 if (sscanf(v->value, "%30d", &y) == 1) {
18940 if ((y < 10) || (y > 4000)) {
18941 ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);
18942 } else {
18943 confp->chan.echotraining = y;
18944 }
18945 } else if (ast_true(v->value)) {
18946 confp->chan.echotraining = 400;
18947 } else
18948 confp->chan.echotraining = 0;
18949 } else if (!strcasecmp(v->name, "hidecallerid")) {
18950 confp->chan.hidecallerid = ast_true(v->value);
18951 } else if (!strcasecmp(v->name, "hidecalleridname")) {
18952 confp->chan.hidecalleridname = ast_true(v->value);
18953 } else if (!strcasecmp(v->name, "pulsedial")) {
18954 confp->chan.pulse = ast_true(v->value);
18955 } else if (!strcasecmp(v->name, "callreturn")) {
18956 confp->chan.callreturn = ast_true(v->value);
18957 } else if (!strcasecmp(v->name, "callwaiting")) {
18958 confp->chan.callwaiting = ast_true(v->value);
18959 } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
18961 } else if (!strcasecmp(v->name, "callwaitingdeluxe")) {
18962 confp->chan.callwaitingdeluxe = ast_true(v->value);
18963 } else if (!strcasecmp(v->name, "context")) {
18964 ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
18965 } else if (!strcasecmp(v->name, "language")) {
18966 ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
18967 } else if (!strcasecmp(v->name, "progzone")) {
18968 ast_copy_string(progzone, v->value, sizeof(progzone));
18969 } else if (!strcasecmp(v->name, "mohinterpret")
18970 ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
18971 ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
18972 } else if (!strcasecmp(v->name, "mohsuggest")) {
18973 ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
18974 } else if (!strcasecmp(v->name, "parkinglot")) {
18975 ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
18976 } else if (!strcasecmp(v->name, "stripmsd")) {
18977 ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
18978 confp->chan.stripmsd = atoi(v->value);
18979 } else if (!strcasecmp(v->name, "jitterbuffers")) {
18980 numbufs = atoi(v->value);
18981 } else if (!strcasecmp(v->name, "group")) {
18982 confp->chan.group = ast_get_group(v->value);
18983 } else if (!strcasecmp(v->name, "callgroup")) {
18984 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18985 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a call group\n");
18986 }
18987 if (!strcasecmp(v->value, "none"))
18988 confp->chan.callgroup = 0;
18989 else
18990 confp->chan.callgroup = ast_get_group(v->value);
18991 } else if (!strcasecmp(v->name, "pickupgroup")) {
18992 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18993 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a pickup group\n");
18994 }
18995 if (!strcasecmp(v->value, "none"))
18996 confp->chan.pickupgroup = 0;
18997 else
18998 confp->chan.pickupgroup = ast_get_group(v->value);
18999 } else if (!strcasecmp(v->name, "namedcallgroup")) {
19000 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
19001 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named call group\n");
19002 }
19004 } else if (!strcasecmp(v->name, "namedpickupgroup")) {
19005 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
19006 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named pickup group\n");
19007 }
19009 } else if (!strcasecmp(v->name, "setvar")) {
19010 if (v->value) {
19011 char *varval = NULL;
19012 struct ast_variable *tmpvar;
19013 char varname[strlen(v->value) + 1];
19014 strcpy(varname, v->value); /* safe */
19015 if ((varval = strchr(varname, '='))) {
19016 *varval++ = '\0';
19017 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
19018 if (ast_variable_list_replace(&confp->chan.vars, tmpvar)) {
19019 tmpvar->next = confp->chan.vars;
19020 confp->chan.vars = tmpvar;
19021 }
19022 }
19023 }
19024 }
19025 } else if (!strcasecmp(v->name, "immediate")) {
19026 confp->chan.immediate = ast_true(v->value);
19027 } else if (!strcasecmp(v->name, "immediatering")) {
19028 confp->chan.immediatering = ast_true(v->value);
19029 } else if (!strcasecmp(v->name, "transfertobusy")) {
19030 confp->chan.transfertobusy = ast_true(v->value);
19031 } else if (!strcasecmp(v->name, "dialmode")) {
19032 if (!strcasecmp(v->value, "pulse")) {
19034 } else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
19036 } else if (!strcasecmp(v->value, "none")) {
19038 } else {
19040 }
19041 } else if (!strcasecmp(v->name, "mwimonitor")) {
19042 confp->chan.mwimonitor_neon = 0;
19043 confp->chan.mwimonitor_fsk = 0;
19044 confp->chan.mwimonitor_rpas = 0;
19045 if (strcasestr(v->value, "fsk")) {
19046 confp->chan.mwimonitor_fsk = 1;
19047 }
19048 if (strcasestr(v->value, "rpas")) {
19049 confp->chan.mwimonitor_rpas = 1;
19050 }
19051 if (strcasestr(v->value, "neon")) {
19052 confp->chan.mwimonitor_neon = 1;
19053 }
19054 /* If set to true or yes, assume that simple fsk is desired */
19055 if (ast_true(v->value)) {
19056 confp->chan.mwimonitor_fsk = 1;
19057 }
19058 } else if (!strcasecmp(v->name, "hwrxgain")) {
19059 confp->chan.hwrxgain_enabled = 0;
19060 if (strcasecmp(v->value, "disabled")) {
19061 if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
19062 confp->chan.hwrxgain_enabled = 1;
19063 } else {
19064 ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
19065 }
19066 }
19067 } else if (!strcasecmp(v->name, "hwtxgain")) {
19068 confp->chan.hwtxgain_enabled = 0;
19069 if (strcasecmp(v->value, "disabled")) {
19070 if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
19071 confp->chan.hwtxgain_enabled = 1;
19072 } else {
19073 ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
19074 }
19075 }
19076 } else if (!strcasecmp(v->name, "cid_rxgain")) {
19077 if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
19078 ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
19079 }
19080 } else if (!strcasecmp(v->name, "rxgain")) {
19081 if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
19082 ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
19083 }
19084 } else if (!strcasecmp(v->name, "txgain")) {
19085 if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
19086 ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
19087 }
19088 } else if (!strcasecmp(v->name, "txdrc")) {
19089 if (sscanf(v->value, "%f", &confp->chan.txdrc) != 1) {
19090 ast_log(LOG_WARNING, "Invalid txdrc: %s\n", v->value);
19091 }
19092 } else if (!strcasecmp(v->name, "rxdrc")) {
19093 if (sscanf(v->value, "%f", &confp->chan.rxdrc) != 1) {
19094 ast_log(LOG_WARNING, "Invalid rxdrc: %s\n", v->value);
19095 }
19096 } else if (!strcasecmp(v->name, "tonezone")) {
19097 if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
19098 ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
19099 }
19100 } else if (!strcasecmp(v->name, "callerid")) {
19101 if (!strcasecmp(v->value, "asreceived")) {
19102 confp->chan.cid_num[0] = '\0';
19103 confp->chan.cid_name[0] = '\0';
19104 } else {
19105 ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
19106 }
19107 } else if (!strcasecmp(v->name, "fullname")) {
19108 ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
19109 } else if (!strcasecmp(v->name, "cid_number")) {
19110 ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
19111 } else if (!strcasecmp(v->name, "cid_tag")) {
19112 ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
19113 } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
19114 confp->chan.dahditrcallerid = ast_true(v->value);
19115 } else if (!strcasecmp(v->name, "restrictcid")) {
19116 confp->chan.restrictcid = ast_true(v->value);
19117 } else if (!strcasecmp(v->name, "usecallingpres")) {
19118 confp->chan.use_callingpres = ast_true(v->value);
19119 } else if (!strcasecmp(v->name, "accountcode")) {
19120 ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
19121 } else if (!strcasecmp(v->name, "amaflags")) {
19123 if (y < 0)
19124 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
19125 else
19126 confp->chan.amaflags = y;
19127 } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
19128 confp->chan.polarityonanswerdelay = atoi(v->value);
19129 } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
19131 } else if (!strcasecmp(v->name, "ani_info_digits")) {
19132 confp->chan.ani_info_digits = atoi(v->value);
19133 } else if (!strcasecmp(v->name, "ani_wink_time")) {
19134 confp->chan.ani_wink_time = atoi(v->value);
19135 } else if (!strcasecmp(v->name, "ani_timeout")) {
19136 confp->chan.ani_timeout = atoi(v->value);
19137 } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
19139 } else if (!strcasecmp(v->name, "autoreoriginate")) {
19140 confp->chan.reoriginate = ast_true(v->value);
19141 } else if (!strcasecmp(v->name, "sendcalleridafter")) {
19142 confp->chan.sendcalleridafter = atoi(v->value);
19143 } else if (!strcasecmp(v->name, "mwimonitornotify")) {
19145 } else if (ast_cc_is_config_param(v->name)) {
19146 ast_cc_set_param(confp->chan.cc_params, v->name, v->value);
19147 } else if (!strcasecmp(v->name, "mwisendtype")) {
19148#ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
19149 if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
19150 mwisend_rpas = 1;
19151 } else {
19152 mwisend_rpas = 0;
19153 }
19154#else
19155 /* Default is fsk, to turn it off you must specify nofsk */
19156 memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
19157 if (strcasestr(v->value, "nofsk")) { /* NoFSK */
19158 confp->chan.mwisend_fsk = 0;
19159 } else { /* Default FSK */
19160 confp->chan.mwisend_fsk = 1;
19161 }
19162 if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
19163 confp->chan.mwisend_rpas = 1;
19164 } else {
19165 confp->chan.mwisend_rpas = 0;
19166 }
19167 if (strcasestr(v->value, "lrev")) { /* Line Reversal */
19168 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
19169 }
19170 if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
19171 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
19172 }
19173 if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) { /* 90V DC pulses */
19174 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
19175 }
19176#endif
19177 } else if (reload != 1) {
19178 if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
19179 int orig_radio = confp->chan.radio;
19180 int orig_outsigmod = confp->chan.outsigmod;
19181 int orig_auto = confp->is_sig_auto;
19182
19183 confp->chan.radio = 0;
19184 confp->chan.outsigmod = -1;
19185 confp->is_sig_auto = 0;
19186 if (!strcasecmp(v->value, "em")) {
19187 confp->chan.sig = SIG_EM;
19188 } else if (!strcasecmp(v->value, "em_e1")) {
19189 confp->chan.sig = SIG_EM_E1;
19190 } else if (!strcasecmp(v->value, "em_w")) {
19191 confp->chan.sig = SIG_EMWINK;
19192 } else if (!strcasecmp(v->value, "fxs_ls")) {
19193 confp->chan.sig = SIG_FXSLS;
19194 } else if (!strcasecmp(v->value, "fxs_gs")) {
19195 confp->chan.sig = SIG_FXSGS;
19196 } else if (!strcasecmp(v->value, "fxs_ks")) {
19197 confp->chan.sig = SIG_FXSKS;
19198 } else if (!strcasecmp(v->value, "fxo_ls")) {
19199 confp->chan.sig = SIG_FXOLS;
19200 } else if (!strcasecmp(v->value, "fxo_gs")) {
19201 confp->chan.sig = SIG_FXOGS;
19202 } else if (!strcasecmp(v->value, "fxo_ks")) {
19203 confp->chan.sig = SIG_FXOKS;
19204 } else if (!strcasecmp(v->value, "fxs_rx")) {
19205 confp->chan.sig = SIG_FXSKS;
19206 confp->chan.radio = 1;
19207 } else if (!strcasecmp(v->value, "fxo_rx")) {
19208 confp->chan.sig = SIG_FXOLS;
19209 confp->chan.radio = 1;
19210 } else if (!strcasecmp(v->value, "fxs_tx")) {
19211 confp->chan.sig = SIG_FXSLS;
19212 confp->chan.radio = 1;
19213 } else if (!strcasecmp(v->value, "fxo_tx")) {
19214 confp->chan.sig = SIG_FXOGS;
19215 confp->chan.radio = 1;
19216 } else if (!strcasecmp(v->value, "em_rx")) {
19217 confp->chan.sig = SIG_EM;
19218 confp->chan.radio = 1;
19219 } else if (!strcasecmp(v->value, "em_tx")) {
19220 confp->chan.sig = SIG_EM;
19221 confp->chan.radio = 1;
19222 } else if (!strcasecmp(v->value, "em_rxtx")) {
19223 confp->chan.sig = SIG_EM;
19224 confp->chan.radio = 2;
19225 } else if (!strcasecmp(v->value, "em_txrx")) {
19226 confp->chan.sig = SIG_EM;
19227 confp->chan.radio = 2;
19228 } else if (!strcasecmp(v->value, "sf")) {
19229 confp->chan.sig = SIG_SF;
19230 } else if (!strcasecmp(v->value, "sf_w")) {
19231 confp->chan.sig = SIG_SFWINK;
19232 } else if (!strcasecmp(v->value, "sf_featd")) {
19233 confp->chan.sig = SIG_FEATD;
19234 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19235 confp->chan.sig = SIG_FEATDMF;
19236 } else if (!strcasecmp(v->value, "sf_featb")) {
19237 confp->chan.sig = SIG_SF_FEATB;
19238 } else if (!strcasecmp(v->value, "sf")) {
19239 confp->chan.sig = SIG_SF;
19240 } else if (!strcasecmp(v->value, "sf_rx")) {
19241 confp->chan.sig = SIG_SF;
19242 confp->chan.radio = 1;
19243 } else if (!strcasecmp(v->value, "sf_tx")) {
19244 confp->chan.sig = SIG_SF;
19245 confp->chan.radio = 1;
19246 } else if (!strcasecmp(v->value, "sf_rxtx")) {
19247 confp->chan.sig = SIG_SF;
19248 confp->chan.radio = 2;
19249 } else if (!strcasecmp(v->value, "sf_txrx")) {
19250 confp->chan.sig = SIG_SF;
19251 confp->chan.radio = 2;
19252 } else if (!strcasecmp(v->value, "featd")) {
19253 confp->chan.sig = SIG_FEATD;
19254 } else if (!strcasecmp(v->value, "featdmf")) {
19255 confp->chan.sig = SIG_FEATDMF;
19256 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19257 confp->chan.sig = SIG_FEATDMF_TA;
19258 } else if (!strcasecmp(v->value, "e911")) {
19259 confp->chan.sig = SIG_E911;
19260 } else if (!strcasecmp(v->value, "fgccama")) {
19261 confp->chan.sig = SIG_FGC_CAMA;
19262 } else if (!strcasecmp(v->value, "fgccamamf")) {
19263 confp->chan.sig = SIG_FGC_CAMAMF;
19264 } else if (!strcasecmp(v->value, "featb")) {
19265 confp->chan.sig = SIG_FEATB;
19266#ifdef HAVE_PRI
19267 } else if (!strcasecmp(v->value, "pri_net")) {
19268 confp->chan.sig = SIG_PRI;
19269 confp->pri.pri.nodetype = PRI_NETWORK;
19270 } else if (!strcasecmp(v->value, "pri_cpe")) {
19271 confp->chan.sig = SIG_PRI;
19272 confp->pri.pri.nodetype = PRI_CPE;
19273 } else if (!strcasecmp(v->value, "bri_cpe")) {
19274 confp->chan.sig = SIG_BRI;
19275 confp->pri.pri.nodetype = PRI_CPE;
19276 } else if (!strcasecmp(v->value, "bri_net")) {
19277 confp->chan.sig = SIG_BRI;
19278 confp->pri.pri.nodetype = PRI_NETWORK;
19279 } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
19280 confp->chan.sig = SIG_BRI_PTMP;
19281 confp->pri.pri.nodetype = PRI_CPE;
19282 } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
19283#if defined(HAVE_PRI_CALL_HOLD)
19284 confp->chan.sig = SIG_BRI_PTMP;
19285 confp->pri.pri.nodetype = PRI_NETWORK;
19286#else
19287 ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v->lineno);
19288#endif /* !defined(HAVE_PRI_CALL_HOLD) */
19289#endif
19290#if defined(HAVE_SS7)
19291 } else if (!strcasecmp(v->value, "ss7")) {
19292 confp->chan.sig = SIG_SS7;
19293#endif /* defined(HAVE_SS7) */
19294#ifdef HAVE_OPENR2
19295 } else if (!strcasecmp(v->value, "mfcr2")) {
19296 confp->chan.sig = SIG_MFCR2;
19297#endif
19298 } else if (!strcasecmp(v->value, "auto")) {
19299 confp->is_sig_auto = 1;
19300 } else {
19301 confp->chan.outsigmod = orig_outsigmod;
19302 confp->chan.radio = orig_radio;
19303 confp->is_sig_auto = orig_auto;
19304 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19305 }
19306 } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
19307 if (!strcasecmp(v->value, "em")) {
19308 confp->chan.outsigmod = SIG_EM;
19309 } else if (!strcasecmp(v->value, "em_e1")) {
19310 confp->chan.outsigmod = SIG_EM_E1;
19311 } else if (!strcasecmp(v->value, "em_w")) {
19312 confp->chan.outsigmod = SIG_EMWINK;
19313 } else if (!strcasecmp(v->value, "sf")) {
19314 confp->chan.outsigmod = SIG_SF;
19315 } else if (!strcasecmp(v->value, "sf_w")) {
19316 confp->chan.outsigmod = SIG_SFWINK;
19317 } else if (!strcasecmp(v->value, "sf_featd")) {
19318 confp->chan.outsigmod = SIG_FEATD;
19319 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19320 confp->chan.outsigmod = SIG_FEATDMF;
19321 } else if (!strcasecmp(v->value, "sf_featb")) {
19322 confp->chan.outsigmod = SIG_SF_FEATB;
19323 } else if (!strcasecmp(v->value, "sf")) {
19324 confp->chan.outsigmod = SIG_SF;
19325 } else if (!strcasecmp(v->value, "featd")) {
19326 confp->chan.outsigmod = SIG_FEATD;
19327 } else if (!strcasecmp(v->value, "featdmf")) {
19328 confp->chan.outsigmod = SIG_FEATDMF;
19329 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19330 confp->chan.outsigmod = SIG_FEATDMF_TA;
19331 } else if (!strcasecmp(v->value, "e911")) {
19332 confp->chan.outsigmod = SIG_E911;
19333 } else if (!strcasecmp(v->value, "fgccama")) {
19334 confp->chan.outsigmod = SIG_FGC_CAMA;
19335 } else if (!strcasecmp(v->value, "fgccamamf")) {
19336 confp->chan.outsigmod = SIG_FGC_CAMAMF;
19337 } else if (!strcasecmp(v->value, "featb")) {
19338 confp->chan.outsigmod = SIG_FEATB;
19339 } else {
19340 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19341 }
19342#ifdef HAVE_PRI
19343 } else if (!strcasecmp(v->name, "pridialplan")) {
19344 if (!strcasecmp(v->value, "national")) {
19345 confp->pri.pri.dialplan = PRI_NATIONAL_ISDN + 1;
19346 } else if (!strcasecmp(v->value, "unknown")) {
19347 confp->pri.pri.dialplan = PRI_UNKNOWN + 1;
19348 } else if (!strcasecmp(v->value, "private")) {
19349 confp->pri.pri.dialplan = PRI_PRIVATE + 1;
19350 } else if (!strcasecmp(v->value, "international")) {
19351 confp->pri.pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
19352 } else if (!strcasecmp(v->value, "local")) {
19353 confp->pri.pri.dialplan = PRI_LOCAL_ISDN + 1;
19354 } else if (!strcasecmp(v->value, "dynamic")) {
19355 confp->pri.pri.dialplan = -1;
19356 } else if (!strcasecmp(v->value, "redundant")) {
19357 confp->pri.pri.dialplan = -2;
19358 } else {
19359 ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
19360 }
19361 } else if (!strcasecmp(v->name, "prilocaldialplan")) {
19362 if (!strcasecmp(v->value, "national")) {
19363 confp->pri.pri.localdialplan = PRI_NATIONAL_ISDN + 1;
19364 } else if (!strcasecmp(v->value, "unknown")) {
19365 confp->pri.pri.localdialplan = PRI_UNKNOWN + 1;
19366 } else if (!strcasecmp(v->value, "private")) {
19367 confp->pri.pri.localdialplan = PRI_PRIVATE + 1;
19368 } else if (!strcasecmp(v->value, "international")) {
19369 confp->pri.pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
19370 } else if (!strcasecmp(v->value, "local")) {
19371 confp->pri.pri.localdialplan = PRI_LOCAL_ISDN + 1;
19372 } else if (!strcasecmp(v->value, "from_channel")) {
19373 confp->pri.pri.localdialplan = 0;
19374 } else if (!strcasecmp(v->value, "dynamic")) {
19375 confp->pri.pri.localdialplan = -1;
19376 } else if (!strcasecmp(v->value, "redundant")) {
19377 confp->pri.pri.localdialplan = -2;
19378 } else {
19379 ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
19380 }
19381 } else if (!strcasecmp(v->name, "pricpndialplan")) {
19382 if (!strcasecmp(v->value, "national")) {
19383 confp->pri.pri.cpndialplan = PRI_NATIONAL_ISDN + 1;
19384 } else if (!strcasecmp(v->value, "unknown")) {
19385 confp->pri.pri.cpndialplan = PRI_UNKNOWN + 1;
19386 } else if (!strcasecmp(v->value, "private")) {
19387 confp->pri.pri.cpndialplan = PRI_PRIVATE + 1;
19388 } else if (!strcasecmp(v->value, "international")) {
19389 confp->pri.pri.cpndialplan = PRI_INTERNATIONAL_ISDN + 1;
19390 } else if (!strcasecmp(v->value, "local")) {
19391 confp->pri.pri.cpndialplan = PRI_LOCAL_ISDN + 1;
19392 } else if (!strcasecmp(v->value, "from_channel")) {
19393 confp->pri.pri.cpndialplan = 0;
19394 } else if (!strcasecmp(v->value, "dynamic")) {
19395 confp->pri.pri.cpndialplan = -1;
19396 } else if (!strcasecmp(v->value, "redundant")) {
19397 confp->pri.pri.cpndialplan = -2;
19398 } else {
19399 ast_log(LOG_WARNING, "Unknown PRI cpndialplan '%s' at line %d.\n", v->value, v->lineno);
19400 }
19401 } else if (!strcasecmp(v->name, "switchtype")) {
19402 if (!strcasecmp(v->value, "national"))
19403 confp->pri.pri.switchtype = PRI_SWITCH_NI2;
19404 else if (!strcasecmp(v->value, "ni1"))
19405 confp->pri.pri.switchtype = PRI_SWITCH_NI1;
19406 else if (!strcasecmp(v->value, "dms100"))
19407 confp->pri.pri.switchtype = PRI_SWITCH_DMS100;
19408 else if (!strcasecmp(v->value, "4ess"))
19409 confp->pri.pri.switchtype = PRI_SWITCH_ATT4ESS;
19410 else if (!strcasecmp(v->value, "5ess"))
19411 confp->pri.pri.switchtype = PRI_SWITCH_LUCENT5E;
19412 else if (!strcasecmp(v->value, "euroisdn"))
19413 confp->pri.pri.switchtype = PRI_SWITCH_EUROISDN_E1;
19414 else if (!strcasecmp(v->value, "qsig"))
19415 confp->pri.pri.switchtype = PRI_SWITCH_QSIG;
19416 else {
19417 ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
19418 return -1;
19419 }
19420 } else if (!strcasecmp(v->name, "msn")) {
19421 ast_copy_string(confp->pri.pri.msn_list, v->value,
19422 sizeof(confp->pri.pri.msn_list));
19423 } else if (!strcasecmp(v->name, "nsf")) {
19424 if (!strcasecmp(v->value, "sdn"))
19425 confp->pri.pri.nsf = PRI_NSF_SDN;
19426 else if (!strcasecmp(v->value, "megacom"))
19427 confp->pri.pri.nsf = PRI_NSF_MEGACOM;
19428 else if (!strcasecmp(v->value, "tollfreemegacom"))
19429 confp->pri.pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
19430 else if (!strcasecmp(v->value, "accunet"))
19431 confp->pri.pri.nsf = PRI_NSF_ACCUNET;
19432 else if (!strcasecmp(v->value, "none"))
19433 confp->pri.pri.nsf = PRI_NSF_NONE;
19434 else {
19435 ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
19436 confp->pri.pri.nsf = PRI_NSF_NONE;
19437 }
19438 } else if (!strcasecmp(v->name, "priindication")) {
19439 if (!strcasecmp(v->value, "outofband"))
19440 confp->chan.priindication_oob = 1;
19441 else if (!strcasecmp(v->value, "inband"))
19442 confp->chan.priindication_oob = 0;
19443 else
19444 ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
19445 v->value, v->lineno);
19446 } else if (!strcasecmp(v->name, "priexclusive")) {
19447 confp->chan.priexclusive = ast_true(v->value);
19448 } else if (!strcasecmp(v->name, "internationalprefix")) {
19449 ast_copy_string(confp->pri.pri.internationalprefix, v->value, sizeof(confp->pri.pri.internationalprefix));
19450 } else if (!strcasecmp(v->name, "nationalprefix")) {
19451 ast_copy_string(confp->pri.pri.nationalprefix, v->value, sizeof(confp->pri.pri.nationalprefix));
19452 } else if (!strcasecmp(v->name, "localprefix")) {
19453 ast_copy_string(confp->pri.pri.localprefix, v->value, sizeof(confp->pri.pri.localprefix));
19454 } else if (!strcasecmp(v->name, "privateprefix")) {
19455 ast_copy_string(confp->pri.pri.privateprefix, v->value, sizeof(confp->pri.pri.privateprefix));
19456 } else if (!strcasecmp(v->name, "unknownprefix")) {
19457 ast_copy_string(confp->pri.pri.unknownprefix, v->value, sizeof(confp->pri.pri.unknownprefix));
19458 } else if (!strcasecmp(v->name, "resetinterval")) {
19459 if (!strcasecmp(v->value, "never"))
19460 confp->pri.pri.resetinterval = -1;
19461 else if (atoi(v->value) >= 60)
19462 confp->pri.pri.resetinterval = atoi(v->value);
19463 else
19464 ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
19465 v->value, v->lineno);
19466 } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
19467 confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
19468 } else if (!strcasecmp(v->name, "minunused")) {
19469 confp->pri.pri.minunused = atoi(v->value);
19470 } else if (!strcasecmp(v->name, "minidle")) {
19471 confp->pri.pri.minidle = atoi(v->value);
19472 } else if (!strcasecmp(v->name, "idleext")) {
19473 ast_copy_string(confp->pri.pri.idleext, v->value, sizeof(confp->pri.pri.idleext));
19474 } else if (!strcasecmp(v->name, "idledial")) {
19475 ast_copy_string(confp->pri.pri.idledial, v->value, sizeof(confp->pri.pri.idledial));
19476 } else if (!strcasecmp(v->name, "overlapdial")) {
19477 if (ast_true(v->value)) {
19478 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19479 } else if (!strcasecmp(v->value, "incoming")) {
19480 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
19481 } else if (!strcasecmp(v->value, "outgoing")) {
19482 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
19483 } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
19484 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19485 } else {
19486 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
19487 }
19488#ifdef HAVE_PRI_PROG_W_CAUSE
19489 } else if (!strcasecmp(v->name, "qsigchannelmapping")) {
19490 if (!strcasecmp(v->value, "logical")) {
19491 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_LOGICAL;
19492 } else if (!strcasecmp(v->value, "physical")) {
19493 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19494 } else {
19495 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19496 }
19497#endif
19498 } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) {
19499 confp->pri.pri.discardremoteholdretrieval = ast_true(v->value);
19500#if defined(HAVE_PRI_SERVICE_MESSAGES)
19501 } else if (!strcasecmp(v->name, "service_message_support")) {
19502 /* assuming switchtype for this channel group has been configured already */
19503 if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
19504 || confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
19505 || confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
19506 confp->pri.pri.enable_service_message_support = 1;
19507 } else {
19508 confp->pri.pri.enable_service_message_support = 0;
19509 }
19510#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
19511#ifdef HAVE_PRI_INBANDDISCONNECT
19512 } else if (!strcasecmp(v->name, "inbanddisconnect")) {
19513 confp->pri.pri.inbanddisconnect = ast_true(v->value);
19514#endif
19515 } else if (!strcasecmp(v->name, "pritimer")) {
19516#ifdef PRI_GETSET_TIMERS
19517 char tmp[20];
19518 char *timerc;
19519 char *c;
19520 int timer;
19521 int timeridx;
19522
19523 ast_copy_string(tmp, v->value, sizeof(tmp));
19524 c = tmp;
19525 timerc = strsep(&c, ",");
19526 if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
19527 timeridx = pri_timer2idx(timerc);
19528 timer = atoi(c);
19529 if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
19531 "'%s' is not a valid ISDN timer at line %d.\n", timerc,
19532 v->lineno);
19533 } else if (!timer) {
19535 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19536 c, timerc, v->lineno);
19537 } else {
19538 confp->pri.pri.pritimers[timeridx] = timer;
19539 }
19540 } else {
19542 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19543 v->value, v->lineno);
19544 }
19545#endif /* PRI_GETSET_TIMERS */
19546 } else if (!strcasecmp(v->name, "facilityenable")) {
19547 confp->pri.pri.facilityenable = ast_true(v->value);
19548#if defined(HAVE_PRI_AOC_EVENTS)
19549 } else if (!strcasecmp(v->name, "aoc_enable")) {
19550 confp->pri.pri.aoc_passthrough_flag = 0;
19551 if (strchr(v->value, 's') || strchr(v->value, 'S')) {
19552 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_S;
19553 }
19554 if (strchr(v->value, 'd') || strchr(v->value, 'D')) {
19555 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_D;
19556 }
19557 if (strchr(v->value, 'e') || strchr(v->value, 'E')) {
19558 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_E;
19559 }
19560 } else if (!strcasecmp(v->name, "aoce_delayhangup")) {
19561 confp->pri.pri.aoce_delayhangup = ast_true(v->value);
19562#endif /* defined(HAVE_PRI_AOC_EVENTS) */
19563#if defined(HAVE_PRI_CALL_HOLD)
19564 } else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
19565 confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
19566#endif /* defined(HAVE_PRI_CALL_HOLD) */
19567 } else if (!strcasecmp(v->name, "moh_signaling")
19568 || !strcasecmp(v->name, "moh_signalling")) {
19569 if (!strcasecmp(v->value, "moh")) {
19570 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19571 } else if (!strcasecmp(v->value, "notify")) {
19572 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_NOTIFY;
19573#if defined(HAVE_PRI_CALL_HOLD)
19574 } else if (!strcasecmp(v->value, "hold")) {
19575 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_HOLD;
19576#endif /* defined(HAVE_PRI_CALL_HOLD) */
19577 } else {
19578 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19579 }
19580#if defined(HAVE_PRI_CCSS)
19581 } else if (!strcasecmp(v->name, "cc_ptmp_recall_mode")) {
19582 if (!strcasecmp(v->value, "global")) {
19583 confp->pri.pri.cc_ptmp_recall_mode = 0;/* globalRecall */
19584 } else if (!strcasecmp(v->value, "specific")) {
19585 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19586 } else {
19587 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19588 }
19589 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_req")) {
19590 if (!strcasecmp(v->value, "release")) {
19591 confp->pri.pri.cc_qsig_signaling_link_req = 0;/* release */
19592 } else if (!strcasecmp(v->value, "retain")) {
19593 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19594 } else if (!strcasecmp(v->value, "do_not_care")) {
19595 confp->pri.pri.cc_qsig_signaling_link_req = 2;/* do-not-care */
19596 } else {
19597 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19598 }
19599 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_rsp")) {
19600 if (!strcasecmp(v->value, "release")) {
19601 confp->pri.pri.cc_qsig_signaling_link_rsp = 0;/* release */
19602 } else if (!strcasecmp(v->value, "retain")) {
19603 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19604 } else {
19605 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19606 }
19607#endif /* defined(HAVE_PRI_CCSS) */
19608#if defined(HAVE_PRI_CALL_WAITING)
19609 } else if (!strcasecmp(v->name, "max_call_waiting_calls")) {
19610 confp->pri.pri.max_call_waiting_calls = atoi(v->value);
19611 if (confp->pri.pri.max_call_waiting_calls < 0) {
19612 /* Negative values are not allowed. */
19613 confp->pri.pri.max_call_waiting_calls = 0;
19614 }
19615 } else if (!strcasecmp(v->name, "allow_call_waiting_calls")) {
19616 confp->pri.pri.allow_call_waiting_calls = ast_true(v->value);
19617#endif /* defined(HAVE_PRI_CALL_WAITING) */
19618#if defined(HAVE_PRI_MWI)
19619 } else if (!strcasecmp(v->name, "mwi_mailboxes")) {
19620 ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
19621 sizeof(confp->pri.pri.mwi_mailboxes));
19622 } else if (!strcasecmp(v->name, "mwi_vm_boxes")) {
19623 ast_copy_string(confp->pri.pri.mwi_vm_boxes, v->value,
19624 sizeof(confp->pri.pri.mwi_vm_boxes));
19625 } else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
19626 ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
19627 sizeof(confp->pri.pri.mwi_vm_numbers));
19628#endif /* defined(HAVE_PRI_MWI) */
19629 } else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
19630 confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
19631 } else if (!strcasecmp(v->name, "inband_on_setup_ack")) {
19632 confp->pri.pri.inband_on_setup_ack = ast_true(v->value);
19633 } else if (!strcasecmp(v->name, "inband_on_proceeding")) {
19634 confp->pri.pri.inband_on_proceeding = ast_true(v->value);
19635#if defined(HAVE_PRI_DISPLAY_TEXT)
19636 } else if (!strcasecmp(v->name, "display_send")) {
19637 confp->pri.pri.display_flags_send = dahdi_display_text_option(v->value);
19638 } else if (!strcasecmp(v->name, "display_receive")) {
19639 confp->pri.pri.display_flags_receive = dahdi_display_text_option(v->value);
19640#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19641#if defined(HAVE_PRI_MCID)
19642 } else if (!strcasecmp(v->name, "mcid_send")) {
19643 confp->pri.pri.mcid_send = ast_true(v->value);
19644#endif /* defined(HAVE_PRI_MCID) */
19645#if defined(HAVE_PRI_DATETIME_SEND)
19646 } else if (!strcasecmp(v->name, "datetime_send")) {
19647 confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
19648#endif /* defined(HAVE_PRI_DATETIME_SEND) */
19649 } else if (!strcasecmp(v->name, "layer1_presence")) {
19650 if (!strcasecmp(v->value, "required")) {
19651 confp->pri.pri.layer1_ignored = 0;
19652 } else if (!strcasecmp(v->value, "ignore")) {
19653 confp->pri.pri.layer1_ignored = 1;
19654 } else {
19655 /* Default */
19656 confp->pri.pri.layer1_ignored = 0;
19657 }
19658#if defined(HAVE_PRI_L2_PERSISTENCE)
19659 } else if (!strcasecmp(v->name, "layer2_persistence")) {
19660 if (!strcasecmp(v->value, "keep_up")) {
19661 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_KEEP_UP;
19662 } else if (!strcasecmp(v->value, "leave_down")) {
19663 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_LEAVE_DOWN;
19664 } else {
19665 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_DEFAULT;
19666 }
19667#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19668 } else if (!strcasecmp(v->name, "colp_send")) {
19669 if (!strcasecmp(v->value, "block")) {
19670 confp->pri.pri.colp_send = SIG_PRI_COLP_BLOCK;
19671 } else if (!strcasecmp(v->value, "connect")) {
19672 confp->pri.pri.colp_send = SIG_PRI_COLP_CONNECT;
19673 } else if (!strcasecmp(v->value, "update")) {
19674 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19675 } else {
19676 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19677 }
19678#endif /* HAVE_PRI */
19679#if defined(HAVE_SS7)
19680 } else if (!strcasecmp(v->name, "ss7type")) {
19681 if (!strcasecmp(v->value, "itu")) {
19682 cur_ss7type = SS7_ITU;
19683 } else if (!strcasecmp(v->value, "ansi")) {
19684 cur_ss7type = SS7_ANSI;
19685 } else {
19686 ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
19687 }
19688 } else if (!strcasecmp(v->name, "slc")) {
19689 cur_slc = atoi(v->value);
19690 } else if (!strcasecmp(v->name, "linkset")) {
19691 cur_linkset = atoi(v->value);
19692 } else if (!strcasecmp(v->name, "pointcode")) {
19693 cur_pointcode = parse_pointcode(v->value);
19694 } else if (!strcasecmp(v->name, "adjpointcode")) {
19695 cur_adjpointcode = parse_pointcode(v->value);
19696 } else if (!strcasecmp(v->name, "defaultdpc")) {
19697 cur_defaultdpc = parse_pointcode(v->value);
19698 } else if (!strcasecmp(v->name, "cicbeginswith")) {
19699 cur_cicbeginswith = atoi(v->value);
19700 } else if (!strcasecmp(v->name, "networkindicator")) {
19701 if (!strcasecmp(v->value, "national")) {
19702 cur_networkindicator = SS7_NI_NAT;
19703 } else if (!strcasecmp(v->value, "national_spare")) {
19704 cur_networkindicator = SS7_NI_NAT_SPARE;
19705 } else if (!strcasecmp(v->value, "international")) {
19706 cur_networkindicator = SS7_NI_INT;
19707 } else if (!strcasecmp(v->value, "international_spare")) {
19708 cur_networkindicator = SS7_NI_INT_SPARE;
19709 } else {
19710 cur_networkindicator = -1;
19711 }
19712 } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
19713 ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
19714 } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
19715 ast_copy_string(confp->ss7.ss7.nationalprefix, v->value, sizeof(confp->ss7.ss7.nationalprefix));
19716 } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
19717 ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
19718 } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
19719 ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
19720 } else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
19721 ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
19722 } else if (!strcasecmp(v->name, "ss7_called_nai")) {
19723 if (!strcasecmp(v->value, "national")) {
19724 confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
19725 } else if (!strcasecmp(v->value, "international")) {
19726 confp->ss7.ss7.called_nai = SS7_NAI_INTERNATIONAL;
19727 } else if (!strcasecmp(v->value, "subscriber")) {
19728 confp->ss7.ss7.called_nai = SS7_NAI_SUBSCRIBER;
19729 } else if (!strcasecmp(v->value, "unknown")) {
19730 confp->ss7.ss7.called_nai = SS7_NAI_UNKNOWN;
19731 } else if (!strcasecmp(v->value, "dynamic")) {
19732 confp->ss7.ss7.called_nai = SS7_NAI_DYNAMIC;
19733 } else {
19734 ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
19735 }
19736 } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
19737 if (!strcasecmp(v->value, "national")) {
19738 confp->ss7.ss7.calling_nai = SS7_NAI_NATIONAL;
19739 } else if (!strcasecmp(v->value, "international")) {
19740 confp->ss7.ss7.calling_nai = SS7_NAI_INTERNATIONAL;
19741 } else if (!strcasecmp(v->value, "subscriber")) {
19742 confp->ss7.ss7.calling_nai = SS7_NAI_SUBSCRIBER;
19743 } else if (!strcasecmp(v->value, "unknown")) {
19744 confp->ss7.ss7.calling_nai = SS7_NAI_UNKNOWN;
19745 } else if (!strcasecmp(v->value, "dynamic")) {
19746 confp->ss7.ss7.calling_nai = SS7_NAI_DYNAMIC;
19747 } else {
19748 ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
19749 }
19750 } else if (!strcasecmp(v->name, "sigchan")) {
19751 int sigchan, res;
19752 sigchan = atoi(v->value);
19753 res = linkset_addsigchan(sigchan);
19754 if (res < 0) {
19755 return -1;
19756 }
19757 } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
19758 struct dahdi_ss7 *link;
19759 link = ss7_resolve_linkset(cur_linkset);
19760 if (!link) {
19761 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19762 return -1;
19763 }
19764 if (ast_true(v->value)) {
19765 link->ss7.flags |= LINKSET_FLAG_EXPLICITACM;
19766 } else {
19767 link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
19768 }
19769 } else if (!strcasecmp(v->name, "ss7_autoacm")) {
19770 struct dahdi_ss7 *link;
19771 link = ss7_resolve_linkset(cur_linkset);
19772 if (!link) {
19773 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19774 return -1;
19775 }
19776 if (ast_true(v->value)) {
19777 link->ss7.flags |= LINKSET_FLAG_AUTOACM;
19778 } else {
19779 link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
19780 }
19781 } else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
19782 struct dahdi_ss7 *link;
19783 link = ss7_resolve_linkset(cur_linkset);
19784 if (!link) {
19785 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19786 return -1;
19787 }
19788 if (ast_true(v->value)) {
19789 link->ss7.flags |= LINKSET_FLAG_INITIALHWBLO;
19790 } else {
19791 link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
19792 }
19793 } else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
19794 struct dahdi_ss7 *link;
19795 link = ss7_resolve_linkset(cur_linkset);
19796 if (!link) {
19797 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19798 return -1;
19799 }
19800 if (ast_true(v->value)) {
19801 link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
19802 } else {
19803 link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
19804 }
19805 } else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
19806 struct dahdi_ss7 *link;
19807 link = ss7_resolve_linkset(cur_linkset);
19808 if (!link) {
19809 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19810 return -1;
19811 }
19812 if (ast_true(v->value)) {
19813 link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
19814 } else {
19815 link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
19816 }
19817 } else if (!strncasecmp(v->name, "isup_timer.", 11)) {
19818 struct dahdi_ss7 *link;
19819 link = ss7_resolve_linkset(cur_linkset);
19820 if (!link) {
19821 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19822 return -1;
19823 }
19824 if (!link->ss7.ss7) {
19825 ast_log(LOG_ERROR, "Please specify isup timers after sigchan!\n");
19826 } else if (!ss7_set_isup_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19827 ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
19828 }
19829 } else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
19830 struct dahdi_ss7 *link;
19831 link = ss7_resolve_linkset(cur_linkset);
19832 if (!link) {
19833 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19834 return -1;
19835 }
19836 if (!link->ss7.ss7) {
19837 ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
19838 } else if (!ss7_set_mtp3_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19839 ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
19840 }
19841 } else if (!strcasecmp(v->name, "inr_if_no_calling")) {
19842 struct dahdi_ss7 *link;
19843 link = ss7_resolve_linkset(cur_linkset);
19844 if (!link) {
19845 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19846 return -1;
19847 }
19848 if (!link->ss7.ss7) {
19849 ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
19850 } else if (ast_true(v->value)) {
19851 ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19852 } else {
19853 ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19854 }
19855 } else if (!strcasecmp(v->name, "non_isdn_access")) {
19856 struct dahdi_ss7 *link;
19857 link = ss7_resolve_linkset(cur_linkset);
19858 if (!link) {
19859 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19860 return -1;
19861 }
19862 if (!link->ss7.ss7) {
19863 ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
19864 } else if (ast_true(v->value)) {
19865 ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19866 } else {
19867 ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19868 }
19869 } else if (!strcasecmp(v->name, "sls_shift")) {
19870 struct dahdi_ss7 *link;
19871 int sls_shift = atoi(v->value);
19872
19873 if (sls_shift < 0 || sls_shift > 7) {
19874 ast_log(LOG_ERROR, "Invalid sls_shift value. Must be between 0 and 7\n");
19875 return -1;
19876 }
19877
19878 link = ss7_resolve_linkset(cur_linkset);
19879 if (!link) {
19880 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19881 return -1;
19882 }
19883 if (!link->ss7.ss7) {
19884 ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
19885 } else {
19886 ss7_set_sls_shift(link->ss7.ss7, sls_shift);
19887 }
19888 } else if (!strcasecmp(v->name, "cause_location")) {
19889 struct dahdi_ss7 *link;
19890 int cause_location = atoi(v->value);
19891
19892 if (cause_location < 0 || cause_location > 15) {
19893 ast_log(LOG_ERROR, "Invalid cause_location value. Must be between 0 and 15\n");
19894 return -1;
19895 }
19896 link = ss7_resolve_linkset(cur_linkset);
19897 if (!link) {
19898 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19899 return -1;
19900 }
19901 if (!link->ss7.ss7) {
19902 ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
19903 } else {
19904 ss7_set_cause_location(link->ss7.ss7, cause_location);
19905 }
19906#endif /* defined(HAVE_SS7) */
19907#ifdef HAVE_OPENR2
19908 } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
19909 ast_copy_string(confp->mfcr2.r2proto_file, v->value, sizeof(confp->mfcr2.r2proto_file));
19910 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);
19911 } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
19912 ast_copy_string(confp->mfcr2.logdir, v->value, sizeof(confp->mfcr2.logdir));
19913 } else if (!strcasecmp(v->name, "mfcr2_variant")) {
19914 confp->mfcr2.variant = openr2_proto_get_variant(v->value);
19915 if (OR2_VAR_UNKNOWN == confp->mfcr2.variant) {
19916 ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v->value, v->lineno);
19917 confp->mfcr2.variant = OR2_VAR_ITU;
19918 }
19919 } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
19920 confp->mfcr2.mfback_timeout = atoi(v->value);
19921 if (!confp->mfcr2.mfback_timeout) {
19922 ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19923 confp->mfcr2.mfback_timeout = -1;
19924 } else if (confp->mfcr2.mfback_timeout > 0 && confp->mfcr2.mfback_timeout < 500) {
19925 ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19926 }
19927 } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
19928 confp->mfcr2.metering_pulse_timeout = atoi(v->value);
19929 if (confp->mfcr2.metering_pulse_timeout > 500) {
19930 ast_log(LOG_WARNING, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19931 }
19932#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19933 } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
19934 confp->mfcr2.dtmf_detection = ast_true(v->value) ? 1 : 0;
19935 } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
19936 confp->mfcr2.dtmf_dialing = ast_true(v->value) ? 1 : 0;
19937 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
19938 confp->mfcr2.dtmf_time_on = atoi(v->value);
19939 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
19940 confp->mfcr2.dtmf_time_off = atoi(v->value);
19941#endif
19942#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19943 } else if (!strcasecmp(v->name, "mfcr2_dtmf_end_timeout")) {
19944 confp->mfcr2.dtmf_end_timeout = atoi(v->value);
19945#endif
19946 } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
19947 confp->mfcr2.get_ani_first = ast_true(v->value) ? 1 : 0;
19948 } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
19949 confp->mfcr2.double_answer = ast_true(v->value) ? 1 : 0;
19950 } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
19951 confp->mfcr2.charge_calls = ast_true(v->value) ? 1 : 0;
19952 } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
19953 confp->mfcr2.accept_on_offer = ast_true(v->value) ? 1 : 0;
19954 } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
19955 confp->mfcr2.allow_collect_calls = ast_true(v->value) ? 1 : 0;
19956 } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
19957 confp->mfcr2.forced_release = ast_true(v->value) ? 1 : 0;
19958 } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
19959 confp->mfcr2.immediate_accept = ast_true(v->value) ? 1 : 0;
19960#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19961 } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
19962 confp->mfcr2.skip_category_request = ast_true(v->value) ? 1 : 0;
19963#endif
19964 } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
19965 confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
19966 } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
19967 confp->mfcr2.max_ani = atoi(v->value);
19968 if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
19969 confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
19970 }
19971 } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
19972 confp->mfcr2.max_dnis = atoi(v->value);
19973 if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
19974 confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
19975 }
19976 } else if (!strcasecmp(v->name, "mfcr2_category")) {
19977 confp->mfcr2.category = openr2_proto_get_category(v->value);
19978 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == confp->mfcr2.category) {
19979 confp->mfcr2.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
19980 ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19981 v->value, v->lineno);
19982 }
19983 } else if (!strcasecmp(v->name, "mfcr2_logging")) {
19984 openr2_log_level_t tmplevel;
19985 char *clevel;
19986 char *logval;
19987 char copy[strlen(v->value) + 1];
19988 strcpy(copy, v->value); /* safe */
19989 logval = copy;
19990 while (logval) {
19991 clevel = strsep(&logval,",");
19992 if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
19993 ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", clevel, v->lineno);
19994 continue;
19995 }
19996 confp->mfcr2.loglevel |= tmplevel;
19997 }
19998#endif /* HAVE_OPENR2 */
19999 } else if (!strcasecmp(v->name, "cadence")) {
20000 /* setup to scan our argument */
20001 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
20002 int i;
20003 struct dahdi_ring_cadence new_cadence;
20004 int cid_location = -1;
20005 int firstcadencepos = 0;
20006 char original_args[80];
20007 int cadence_is_ok = 1;
20008
20009 ast_copy_string(original_args, v->value, sizeof(original_args));
20010 /* 16 cadences allowed (8 pairs) */
20011 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]);
20012
20013 /* Cadence must be even (on/off) */
20014 if (element_count % 2 == 1) {
20015 ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
20016 cadence_is_ok = 0;
20017 }
20018
20019 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
20020 if (element_count > ARRAY_LEN(c)) {
20021 element_count = ARRAY_LEN(c);
20022 }
20023
20024 /* Ring cadences cannot be negative */
20025 for (i = 0; i < element_count; i++) {
20026 if (c[i] == 0) {
20027 ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
20028 cadence_is_ok = 0;
20029 break;
20030 } else if (c[i] < 0) {
20031 if (i % 2 == 1) {
20032 /* Silence duration, negative possibly okay */
20033 if (cid_location == -1) {
20034 cid_location = i;
20035 c[i] *= -1;
20036 } else {
20037 ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
20038 cadence_is_ok = 0;
20039 break;
20040 }
20041 } else {
20042 if (firstcadencepos == 0) {
20043 firstcadencepos = i; /* only recorded to avoid duplicate specification */
20044 /* duration will be passed negative to the DAHDI driver */
20045 } else {
20046 ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
20047 cadence_is_ok = 0;
20048 break;
20049 }
20050 }
20051 }
20052 }
20053
20054 /* Substitute our scanned cadence */
20055 for (i = 0; i < 16; i++) {
20056 new_cadence.ringcadence[i] = c[i];
20057 }
20058
20059 if (cadence_is_ok) {
20060 /* ---we scanned it without getting annoyed; now some sanity checks--- */
20061 if (element_count < 2) {
20062 ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
20063 } else {
20064 if (cid_location == -1) {
20065 /* user didn't say; default to first pause */
20066 cid_location = 1;
20067 } else {
20068 /* convert element_index to cidrings value */
20069 cid_location = (cid_location + 1) / 2;
20070 }
20071 /* ---we like their cadence; try to install it--- */
20073 /* this is the first user-defined cadence; clear the default user cadences */
20074 num_cadence = 0;
20075 if ((num_cadence+1) >= NUM_CADENCE_MAX)
20076 ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
20077 else {
20078 cadences[num_cadence] = new_cadence;
20079 cidrings[num_cadence++] = cid_location;
20080 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
20081 }
20082 }
20083 }
20084 } else if (!strcasecmp(v->name, "ringtimeout")) {
20085 ringt_base = (atoi(v->value) * 8) / READ_SIZE;
20086 } else if (!strcasecmp(v->name, "prewink")) {
20087 confp->timing.prewinktime = atoi(v->value);
20088 } else if (!strcasecmp(v->name, "preflash")) {
20089 confp->timing.preflashtime = atoi(v->value);
20090 } else if (!strcasecmp(v->name, "wink")) {
20091 confp->timing.winktime = atoi(v->value);
20092 } else if (!strcasecmp(v->name, "flash")) {
20093 confp->timing.flashtime = atoi(v->value);
20094 } else if (!strcasecmp(v->name, "start")) {
20095 confp->timing.starttime = atoi(v->value);
20096 } else if (!strcasecmp(v->name, "rxwink")) {
20097 confp->timing.rxwinktime = atoi(v->value);
20098 } else if (!strcasecmp(v->name, "rxflash")) {
20099 confp->timing.rxflashtime = atoi(v->value);
20100 } else if (!strcasecmp(v->name, "debounce")) {
20101 confp->timing.debouncetime = atoi(v->value);
20102 } else if (!strcasecmp(v->name, "toneduration")) {
20103 int toneduration;
20104 int ctlfd;
20105 int res;
20106 struct dahdi_dialparams dps;
20107
20108 ctlfd = open("/dev/dahdi/ctl", O_RDWR);
20109 if (ctlfd == -1) {
20110 ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
20111 return -1;
20112 }
20113
20114 toneduration = atoi(v->value);
20115 if (toneduration > -1) {
20116 memset(&dps, 0, sizeof(dps));
20117
20118 dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
20119 res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
20120 if (res < 0) {
20121 ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
20122 close(ctlfd);
20123 return -1;
20124 }
20125 }
20126 close(ctlfd);
20127 } else if (!strcasecmp(v->name, "defaultcic")) {
20129 } else if (!strcasecmp(v->name, "defaultozz")) {
20131 } else if (!strcasecmp(v->name, "mwilevel")) {
20132 mwilevel = atoi(v->value);
20133 } else if (!strcasecmp(v->name, "dtmfcidlevel")) {
20134 dtmfcid_level = atoi(v->value);
20135 } else if (!strcasecmp(v->name, "reportalarms")) {
20136 if (!strcasecmp(v->value, "all"))
20138 if (!strcasecmp(v->value, "none"))
20139 report_alarms = 0;
20140 else if (!strcasecmp(v->value, "channels"))
20142 else if (!strcasecmp(v->value, "spans"))
20144 }
20145 } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
20146 ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
20147 }
20148
20149 if (dahdichan) {
20150 /* Process the deferred dahdichan value. */
20151 if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
20152 if (confp->ignore_failed_channels) {
20154 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
20155 dahdichan->value);
20156 } else {
20157 return -1;
20158 }
20159 }
20160 }
20161
20162 /*
20163 * Since confp has already filled individual dahdi_pvt objects with channels
20164 * at this point, clear the variables in confp's pvt.
20165 */
20166 if (confp->chan.vars) {
20168 confp->chan.vars = NULL;
20169 }
20170
20171 /* mark the first channels of each DAHDI span to watch for their span alarms */
20172 for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
20173 if (!tmp->destroy && tmp->span != y) {
20174 tmp->manages_span_alarms = 1;
20175 y = tmp->span;
20176 } else {
20177 tmp->manages_span_alarms = 0;
20178 }
20179 }
20180
20181 /*< \todo why check for the pseudo in the per-channel section.
20182 * Any actual use for manual setup of the pseudo channel? */
20183 if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
20184 /* use the default configuration for a channel, so
20185 that any settings from real configured channels
20186 don't "leak" into the pseudo channel config
20187 */
20189
20190 if (conf.chan.cc_params) {
20191 tmp = mkintf(CHAN_PSEUDO, &conf, reload);
20192 } else {
20193 tmp = NULL;
20194 }
20195 if (tmp) {
20196 ast_verb(3, "Automatically generated pseudo channel\n");
20197 has_pseudo = 1;
20198 } else {
20199 ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
20200 }
20201 ast_cc_config_params_destroy(conf.chan.cc_params);
20202 }
20203
20204 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
20207
20208 return 0;
20209}
20210
20211/*!
20212 * \internal
20213 * \brief Deep copy struct dahdi_chan_conf.
20214 * \since 1.8
20215 *
20216 * \param dest Destination.
20217 * \param src Source.
20218 */
20219static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
20220{
20221 struct ast_cc_config_params *cc_params;
20222
20223 cc_params = dest->chan.cc_params;
20224 *dest = *src;
20225 dest->chan.cc_params = cc_params;
20227}
20228
20229/*!
20230 * \internal
20231 * \brief Setup DAHDI channel driver.
20232 *
20233 * \param reload enum: load_module(0), reload(1), restart(2).
20234 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
20235 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
20236 * \param conf Local config parameters. So cc_params can be properly destroyed.
20237 *
20238 * \retval 0 on success.
20239 * \retval -1 on error.
20240 */
20241static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
20242{
20243 struct ast_config *cfg;
20244 struct ast_config;
20245 struct ast_variable *v;
20246 struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
20247 const char *chans;
20248 const char *cat;
20249 int res;
20250
20251#ifdef HAVE_PRI
20252 char *c;
20253 int spanno;
20254 int i;
20255 int logicalspan;
20256 int trunkgroup;
20257 int dchannels[SIG_PRI_NUM_DCHANS];
20258#endif
20259 int have_cfg_now;
20260 static int had_cfg_before = 1;/* So initial load will complain if we don't have cfg. */
20261
20262 cfg = ast_config_load(config, config_flags);
20263 have_cfg_now = !!cfg;
20264 if (!cfg) {
20265 /* Error if we have no config file */
20266 if (had_cfg_before) {
20267 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
20269 }
20270 cfg = ast_config_new();/* Dummy config */
20271 if (!cfg) {
20272 return 0;
20273 }
20274 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
20276 cfg = ast_config_load(config, config_flags);
20277 have_cfg_now = !!cfg;
20278 if (!cfg) {
20279 if (had_cfg_before) {
20280 /* We should have been able to load the config. */
20281 ast_log(LOG_ERROR, "Bad. Unable to load config %s\n", config);
20282 return 0;
20283 }
20284 cfg = ast_config_new();/* Dummy config */
20285 if (!cfg) {
20286 return 0;
20287 }
20288 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20289 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20290 return 0;
20291 }
20292 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20293 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20294 return 0;
20295 } else {
20297 }
20298 had_cfg_before = have_cfg_now;
20299
20300 /* It's a little silly to lock it, but we might as well just to be sure */
20302#ifdef HAVE_PRI
20303 if (reload != 1) {
20304 /* Process trunkgroups first */
20305 v = ast_variable_browse(cfg, "trunkgroups");
20306 while (v) {
20307 if (!strcasecmp(v->name, "trunkgroup")) {
20308 trunkgroup = atoi(v->value);
20309 if (trunkgroup > 0) {
20310 if ((c = strchr(v->value, ','))) {
20311 i = 0;
20312 memset(dchannels, 0, sizeof(dchannels));
20313 while (c && (i < SIG_PRI_NUM_DCHANS)) {
20314 dchannels[i] = atoi(c + 1);
20315 if (dchannels[i] < 0) {
20316 ast_log(LOG_WARNING, "D-channel for trunk group %d must be a positive number at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20317 } else
20318 i++;
20319 c = strchr(c + 1, ',');
20320 }
20321 if (i) {
20322 if (pri_create_trunkgroup(trunkgroup, dchannels)) {
20323 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);
20324 } else
20325 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");
20326 } else
20327 ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20328 } else
20329 ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20330 } else
20331 ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20332 } else if (!strcasecmp(v->name, "spanmap")) {
20333 spanno = atoi(v->value);
20334 if (spanno > 0) {
20335 if ((c = strchr(v->value, ','))) {
20336 trunkgroup = atoi(c + 1);
20337 if (trunkgroup > 0) {
20338 if ((c = strchr(c + 1, ',')))
20339 logicalspan = atoi(c + 1);
20340 else
20341 logicalspan = 0;
20342 if (logicalspan >= 0) {
20343 if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
20344 ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20345 } else
20346 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20347 } else
20348 ast_log(LOG_WARNING, "Logical span must be a positive number, or '0' (for unspecified) at line %d of chan_dahdi.conf\n", v->lineno);
20349 } else
20350 ast_log(LOG_WARNING, "Trunk group must be a positive number at line %d of chan_dahdi.conf\n", v->lineno);
20351 } else
20352 ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
20353 } else
20354 ast_log(LOG_WARNING, "Span number must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20355 } else {
20356 ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
20357 }
20358 v = v->next;
20359 }
20360 }
20361#endif
20362
20363 /* Copy the default jb config over global_jbconf */
20364 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
20365
20366 mwimonitornotify[0] = '\0';
20367
20368 v = ast_variable_browse(cfg, "channels");
20369 if ((res = process_dahdi(base_conf,
20370 "" /* Must be empty for the channels category. Silly voicemail mailbox. */,
20371 v, reload, 0))) {
20373 ast_config_destroy(cfg);
20374 return res;
20375 }
20376
20377 /* Now get configuration from all normal sections in chan_dahdi.conf: */
20378 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
20379 /* [channels] and [trunkgroups] are used. Let's also reserve
20380 * [globals] and [general] for future use
20381 */
20382 if (!strcasecmp(cat, "general") ||
20383 !strcasecmp(cat, "trunkgroups") ||
20384 !strcasecmp(cat, "globals") ||
20385 !strcasecmp(cat, "channels")) {
20386 continue;
20387 }
20388
20389 chans = ast_variable_retrieve(cfg, cat, "dahdichan");
20390 if (ast_strlen_zero(chans)) {
20391 /* Section is useless without a dahdichan value present. */
20392 continue;
20393 }
20394
20395 /* Copy base_conf to conf. */
20396 deep_copy_dahdi_chan_conf(conf, base_conf);
20397
20398 if ((res = process_dahdi(conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
20400 ast_config_destroy(cfg);
20401 return res;
20402 }
20403 }
20404
20405 ast_config_destroy(cfg);
20407
20408#ifdef HAVE_PRI
20409 if (reload != 1) {
20410 int x;
20411 for (x = 0; x < NUM_SPANS; x++) {
20412 if (pris[x].pri.pvts[0] &&
20413 pris[x].pri.master == AST_PTHREADT_NULL) {
20414 prepare_pri(pris + x);
20415 if (sig_pri_start_pri(&pris[x].pri)) {
20416 ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
20417 return -1;
20418 } else
20419 ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
20420 }
20421 }
20422 }
20423#endif
20424#if defined(HAVE_SS7)
20425 if (reload != 1) {
20426 int x;
20427 for (x = 0; x < NUM_SPANS; x++) {
20428 if (linksets[x].ss7.ss7) {
20429 if (ast_pthread_create(&linksets[x].ss7.master, NULL, ss7_linkset, &linksets[x].ss7)) {
20430 ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
20431 return -1;
20432 } else
20433 ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
20434 }
20435 }
20436 }
20437#endif /* defined(HAVE_SS7) */
20438#ifdef HAVE_OPENR2
20439 if (reload != 1) {
20440 struct r2link_entry *cur;
20441 int x = 0;
20442 AST_LIST_LOCK(&r2links);
20443 AST_LIST_TRAVERSE(&r2links, cur, list) {
20444 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
20445 if (r2->r2master == AST_PTHREADT_NULL) {
20446 if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
20447 ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
20448 return -1;
20449 } else {
20450 ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
20451 }
20452 x++;
20453 }
20454 }
20455 AST_LIST_UNLOCK(&r2links);
20456 }
20457#endif
20458 /* And start the monitor for the first time */
20460 return 0;
20461}
20462
20463/*!
20464 * \internal
20465 * \brief Setup DAHDI channel driver.
20466 *
20467 * \param reload enum: load_module(0), reload(1), restart(2).
20468 *
20469 * \retval 0 on success.
20470 * \retval -1 on error.
20471 */
20472static int setup_dahdi(int reload)
20473{
20474 int res;
20475 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
20476 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
20478
20479 if (default_conf.chan.cc_params && base_conf.chan.cc_params && conf.chan.cc_params) {
20480 res = setup_dahdi_int(reload, &default_conf, &base_conf, &conf);
20481 } else {
20482 res = -1;
20483 }
20486 ast_cc_config_params_destroy(conf.chan.cc_params);
20487
20488 return res;
20489}
20490
20491/*!
20492 * \brief Load the module
20493 *
20494 * Module loading including tests for configuration or dependencies.
20495 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20496 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20497 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20498 * configuration file or other non-critical problem return
20499 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20500 */
20501static int load_module(void)
20502{
20503 int res;
20504#if defined(HAVE_PRI) || defined(HAVE_SS7)
20505 int y;
20506#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20507
20508 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
20510 }
20511
20514 }
20518
20522 }
20523
20524#ifdef HAVE_PRI
20525 memset(pris, 0, sizeof(pris));
20526 for (y = 0; y < NUM_SPANS; y++) {
20527 sig_pri_init_pri(&pris[y].pri);
20528 }
20529 pri_set_error(dahdi_pri_error);
20530 pri_set_message(dahdi_pri_message);
20531 ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec);
20532#ifdef HAVE_PRI_PROG_W_CAUSE
20533 ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
20534#endif
20535#if defined(HAVE_PRI_CCSS)
20536 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks)
20537 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) {
20540 }
20541#endif /* defined(HAVE_PRI_CCSS) */
20542 if (sig_pri_load(
20543#if defined(HAVE_PRI_CCSS)
20544 dahdi_pri_cc_type
20545#else
20546 NULL
20547#endif /* defined(HAVE_PRI_CCSS) */
20548 )) {
20551 }
20552#endif
20553#if defined(HAVE_SS7)
20554 memset(linksets, 0, sizeof(linksets));
20555 for (y = 0; y < NUM_SPANS; y++) {
20556 sig_ss7_init_linkset(&linksets[y].ss7);
20557 }
20558 ss7_set_error(dahdi_ss7_error);
20559 ss7_set_message(dahdi_ss7_message);
20560 ss7_set_hangup(sig_ss7_cb_hangup);
20561 ss7_set_notinservice(sig_ss7_cb_notinservice);
20562 ss7_set_call_null(sig_ss7_cb_call_null);
20563#endif /* defined(HAVE_SS7) */
20564 res = setup_dahdi(0);
20565 /* Make sure we can register our DAHDI channel type */
20566 if (res) {
20569 }
20571 ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
20574 }
20575#ifdef HAVE_PRI
20576 ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
20577#endif
20578#if defined(HAVE_SS7)
20579 ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
20580#endif /* defined(HAVE_SS7) */
20581#ifdef HAVE_OPENR2
20582 ast_cli_register_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
20583 ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
20584#endif
20585
20588
20590 memset(round_robin, 0, sizeof(round_robin));
20591 ast_manager_register_xml("DAHDITransfer", 0, action_transfer);
20593 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook);
20596 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
20597 ast_manager_register_xml("DAHDIShowStatus", 0, action_dahdishowstatus);
20599#if defined(HAVE_PRI)
20600 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
20601 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
20602 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM, action_pri_debug_file_set);
20603 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset);
20604#endif /* defined(HAVE_PRI) */
20605
20607
20608 return res;
20609}
20610
20611static int dahdi_sendtext(struct ast_channel *c, const char *text)
20612{
20613#define END_SILENCE_LEN 400
20614#define HEADER_MS 50
20615#define TRAILER_MS 5
20616#define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20617#define ASCII_BYTES_PER_CHAR 80
20618
20619 unsigned char *buf,*mybuf;
20620 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
20621 struct pollfd fds[1];
20622 int size,res,fd,len,x;
20623 int bytes=0;
20624 int idx;
20625
20626 /*
20627 * Initial carrier (imaginary)
20628 *
20629 * Note: The following float variables are used by the
20630 * PUT_CLID_MARKMS and PUT_CLID() macros.
20631 */
20632 float cr = 1.0;
20633 float ci = 0.0;
20634 float scont = 0.0;
20635
20636 if (!text[0]) {
20637 return(0); /* if nothing to send, don't */
20638 }
20639 idx = dahdi_get_index(c, p, 0);
20640 if (idx < 0) {
20641 ast_log(LOG_WARNING, "Huh? I don't exist?\n");
20642 return -1;
20643 }
20644 if ((!p->tdd) && (!p->mate)) {
20645#if defined(HAVE_PRI)
20646#if defined(HAVE_PRI_DISPLAY_TEXT)
20647 ast_mutex_lock(&p->lock);
20649 sig_pri_sendtext(p->sig_pvt, text);
20650 }
20652#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20653#endif /* defined(HAVE_PRI) */
20654 return(0); /* if not in TDD mode, just return */
20655 }
20656 if (p->mate)
20658 else
20659 buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
20660 if (!buf)
20661 return -1;
20662 mybuf = buf;
20663 if (p->mate) {
20664 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20665 struct ast_format *codec = AST_LAW(p);
20666
20667 for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
20669 }
20670 /* Put actual message */
20671 for (x = 0; text[x]; x++) {
20672 PUT_CLID(text[x]);
20673 }
20674 for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
20676 }
20677 len = bytes;
20678 buf = mybuf;
20679 } else {
20680 len = tdd_generate(p->tdd, buf, text);
20681 if (len < 1) {
20682 ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
20683 ast_free(mybuf);
20684 return -1;
20685 }
20686 }
20687 memset(buf + len, 0x7f, END_SILENCE_LEN);
20689 fd = p->subs[idx].dfd;
20690 while (len) {
20691 if (ast_check_hangup(c)) {
20692 ast_free(mybuf);
20693 return -1;
20694 }
20695 size = len;
20696 if (size > READ_SIZE)
20697 size = READ_SIZE;
20698 fds[0].fd = fd;
20699 fds[0].events = POLLOUT | POLLPRI;
20700 fds[0].revents = 0;
20701 res = poll(fds, 1, -1);
20702 if (!res) {
20703 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
20704 continue;
20705 }
20706 /* if got exception */
20707 if (fds[0].revents & POLLPRI) {
20708 ast_free(mybuf);
20709 return -1;
20710 }
20711 if (!(fds[0].revents & POLLOUT)) {
20712 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
20713 continue;
20714 }
20715 res = write(fd, buf, size);
20716 if (res != size) {
20717 if (res == -1) {
20718 ast_free(mybuf);
20719 return -1;
20720 }
20721 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
20722 break;
20723 }
20724 len -= size;
20725 buf += size;
20726 }
20727 ast_free(mybuf);
20728 return(0);
20729}
20730
20731
20732static int reload(void)
20733{
20734 int res = 0;
20735
20736 res = setup_dahdi(1);
20737 if (res) {
20738 ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
20739 return -1;
20740 }
20741 return 0;
20742}
20743
20744/* This is a workaround so that menuselect displays a proper description
20745 * AST_MODULE_INFO(, , "DAHDI Telephony"
20746 */
20747
20749 .support_level = AST_MODULE_SUPPORT_CORE,
20750 .load = load_module,
20751 .unload = unload_module,
20752 .reload = reload,
20753 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
20754 .requires = "ccss",
20755 .optional_modules = "res_smdi",
Common implementation-independent jitterbuffer stuff.
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
ADSI Support (built upon Caller*ID)
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
A-Law to Signed linear conversion.
#define AST_LIN2A(a)
Definition alaw.h:50
#define AST_ALAW(a)
Definition alaw.h:84
char digit
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
char * text
Definition app_queue.c:1772
struct sla_ringing_trunk * last
Definition app_sla.c:338
static int copy(char *infile, char *outfile)
Utility function to copy a file.
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition db.c:335
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition db.c:421
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition db.c:472
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
#define AST_FILE_MODE
Definition asterisk.h:32
#define PATH_MAX
Definition asterisk.h:40
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
Bridging API.
ast_transfer_result
Definition bridge.h:1102
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1104
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition bridge.c:4756
void dahdi_native_unload(void)
int dahdi_native_load(const struct ast_channel_tech *tech)
Native DAHDI bridging support.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define PUT_CLID(byte)
Definition callerid.h:412
#define CID_SIG_V23_JP
Definition callerid.h:63
int ast_callerid_callwaiting_full_generate(unsigned char *buf, const char *name, const char *number, const char *ddn, int redirecting, int pres, int qualifier, struct ast_format *codec)
Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
Definition callerid.c:1253
#define CID_TYPE_MDMF
Definition callerid.h:75
#define CID_UNKNOWN_NUMBER
Definition callerid.h:55
int ast_gen_cas(unsigned char *outbuf, int sas, int len, struct ast_format *codec)
Generate a CAS (CPE Alert Signal) tone for 'n' samples.
Definition callerid.c:271
#define CID_SIG_SMDI
Definition callerid.h:64
int ast_callerid_full_generate(unsigned char *buf, const char *name, const char *number, const char *ddn, int redirecting, int pres, int qualifier, int format, struct ast_format *codec)
Generate Caller-ID spill from the "callerid" field of asterisk (in e-mail address like format)
Definition callerid.c:1247
int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int samples, struct ast_format *codec)
Read samples into the state machine.
Definition callerid.c:316
#define AST_PRES_USER_NUMBER_UNSCREENED
Definition callerid.h:426
#define AST_PRES_UNAVAILABLE
Definition callerid.h:434
int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct ast_format *codec, const char *name, const char *number, int flags)
Generate message waiting indicator.
Definition callerid.c:952
#define AST_PRES_RESTRICTED
Definition callerid.h:433
void callerid_free(struct callerid_state *cid)
This function frees callerid_state cid.
Definition callerid.c:833
void callerid_get_with_redirecting(struct callerid_state *cid, char **name, char **number, int *flags, int *redirecting)
Extract info out of callerID state machine. Flags are listed above.
Definition callerid.c:189
#define MAX_CALLERID_SIZE
Definition callerid.h:50
const char * ast_redirecting_reason_name(const struct ast_party_redirecting_reason *data)
Convert redirecting reason value to text code.
Definition callerid.c:1449
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition callerid.c:1101
int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec)
Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
Definition callerid.c:1242
#define PUT_CLID_MARKMS
Definition callerid.h:397
#define CID_NOMSGWAITING
Definition callerid.h:57
#define CID_SIG_DTMF
Definition callerid.h:62
#define CID_PRIVATE_NUMBER
Definition callerid.h:53
struct callerid_state * callerid_new(int cid_signalling)
Create a callerID state machine.
Definition callerid.c:130
#define CID_MSGWAITING
Definition callerid.h:56
#define CID_SIG_V23
Definition callerid.h:61
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples, struct ast_format *codec)
Read samples into the state machine.
Definition callerid.c:570
#define CID_MWI_TYPE_MDMF_FULL
Definition callerid.h:83
void callerid_get_dtmf(char *cidstring, char *number, int *flags)
Get and parse DTMF-based callerid.
Definition callerid.c:211
#define CID_START_RING
Definition callerid.h:66
#define CID_START_POLARITY
Definition callerid.h:67
#define CID_SIG_BELL
Definition callerid.h:60
#define CID_QUALIFIER
Definition callerid.h:58
void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags)
Extract info out of callerID state machine. Flags are listed above.
Definition callerid.c:205
#define CID_START_POLARITY_IN
Definition callerid.h:68
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition callerid.c:1292
#define CID_START_DTMF_NOALERT
Definition callerid.h:69
Internal Asterisk hangup causes.
#define AST_CAUSE_SWITCH_CONGESTION
Definition causes.h:123
#define AST_CAUSE_CONGESTION
Definition causes.h:153
#define AST_CAUSE_UNALLOCATED
Definition causes.h:98
#define AST_CAUSE_INTERWORKING
Definition causes.h:146
#define AST_CAUSE_PROTOCOL_ERROR
Definition causes.h:145
#define AST_CAUSE_DESTINATION_OUT_OF_ORDER
Definition causes.h:115
#define AST_CAUSE_NO_USER_RESPONSE
Definition causes.h:108
#define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION
Definition causes.h:120
#define AST_CAUSE_NOTDEFINED
Definition causes.h:155
#define AST_CAUSE_CALL_REJECTED
Definition causes.h:111
#define AST_CAUSE_NETWORK_OUT_OF_ORDER
Definition causes.h:121
#define AST_CAUSE_UNREGISTERED
Definition causes.h:154
#define AST_CAUSE_BUSY
Definition causes.h:149
#define AST_CAUSE_NO_ANSWER
Definition causes.h:109
#define AST_CAUSE_NORMAL_CLEARING
Definition causes.h:106
#define AST_CAUSE_USER_BUSY
Definition causes.h:107
Call Completion Supplementary Services API.
#define ast_cc_config_params_init()
Allocate and initialize an ast_cc_config_params structure.
Definition ccss.h:135
#define AST_CC_GENERIC_MONITOR_TYPE
Definition ccss.h:455
int ast_cc_monitor_register(const struct ast_cc_monitor_callbacks *callbacks)
Register a set of monitor callbacks with the core.
Definition ccss.c:1168
void ast_cc_config_params_destroy(struct ast_cc_config_params *params)
Free memory from CCSS configuration params.
Definition ccss.c:698
void(* ast_cc_callback_fn)(struct ast_channel *chan, struct ast_cc_config_params *cc_params, const char *monitor_type, const char *const device_name, const char *const dialstring, void *private_data)
Callback made from ast_cc_callback for certain channel types.
Definition ccss.h:1562
int ast_cc_agent_register(const struct ast_cc_agent_callbacks *callbacks)
Register a set of agent callbacks with the core.
Definition ccss.c:1223
void ast_cc_copy_config_params(struct ast_cc_config_params *dest, const struct ast_cc_config_params *src)
copy CCSS configuration parameters from one structure to another
Definition ccss.c:860
@ AST_CC_MONITOR_NEVER
Definition ccss.h:76
@ AST_CC_MONITOR_ALWAYS
Definition ccss.h:87
@ AST_CC_MONITOR_NATIVE
Definition ccss.h:78
@ AST_CC_MONITOR_GENERIC
Definition ccss.h:83
void ast_cc_monitor_unregister(const struct ast_cc_monitor_callbacks *callbacks)
Unregister a set of monitor callbacks with the core.
Definition ccss.c:1201
enum ast_cc_monitor_policies ast_get_cc_monitor_policy(struct ast_cc_config_params *config)
Get the cc_monitor_policy.
Definition ccss.c:882
void ast_cc_agent_unregister(const struct ast_cc_agent_callbacks *callbacks)
Unregister a set of agent callbacks with the core.
Definition ccss.c:1238
int ast_cc_is_config_param(const char *const name)
Is this a CCSS configuration parameter?
Definition ccss.c:846
int ast_cc_set_param(struct ast_cc_config_params *params, const char *const name, const char *value)
set a CCSS configuration parameter, given its name
Definition ccss.c:807
static sqlite3 * db
static PGresult * result
Definition cel_pgsql.c:84
static struct ao2_container * pvts
#define CALLPROGRESS_FAX_INCOMING
Definition chan_dahdi.c:811
static int dahdi_create_channel_range(int start, int end)
static int dahdi_confmute(struct dahdi_pvt *p, int muted)
static ast_mutex_t ss_thread_lock
Definition chan_dahdi.c:893
static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
#define CALLWAITING_SUPPRESS_SAMPLES
Definition chan_dahdi.c:931
static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
static void release_doomed_pris(void)
static struct dahdi_pvt * round_robin[64]
#define HANGUP
static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
static int restore_gains(struct dahdi_pvt *p)
static void publish_channel_alarm_clear(int channel)
static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index)
static char * dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void my_set_confirmanswer(void *pvt, int flag)
#define CIDCW_EXPIRE_SAMPLES
Definition chan_dahdi.c:932
static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
static int my_callwait(void *pvt)
static int restore_conference(struct dahdi_pvt *p)
static void publish_span_alarm_clear(int span)
static ast_mutex_t iflock
Protect the interface list (of dahdi_pvt's)
Definition chan_dahdi.c:876
static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
static void notify_message(char *mailbox, int thereornot)
Send MWI state change.
static struct dahdi_pvt * mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel)
static int unalloc_sub(struct dahdi_pvt *p, int x)
static int my_check_confirmanswer(void *pvt)
static const char *const events[]
static int reset_conf(struct dahdi_pvt *p)
static int my_is_dialing(void *pvt, enum analog_sub sub)
static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
static struct ast_manager_event_blob * dahdichannel_to_ami(struct stasis_message *msg)
static void my_cancel_cidspill(void *pvt)
static int numbufs
Definition chan_dahdi.c:861
static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
static int my_set_echocanceller(void *pvt, int enable)
static int dahdi_wink(struct dahdi_pvt *p, int index)
static char mwimonitornotify[PATH_MAX]
Definition chan_dahdi.c:851
static char * alarm2str(int alm)
static void my_hangup_polarityswitch(void *pvt)
static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
static int dahdi_ring_phone(struct dahdi_pvt *p)
static char * dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define CALLWAITING_REPEAT_SAMPLES
Definition chan_dahdi.c:930
static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
#define DEFAULT_RINGT
Definition chan_dahdi.c:934
#define CALLPROGRESS_FAX_OUTGOING
Definition chan_dahdi.c:810
static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
static int my_stop_cid_detect(void *pvt)
static int my_get_sub_fd(void *pvt, enum analog_sub sub)
static void my_set_needringing(void *pvt, int value)
static char * dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_jb_conf default_jbconf
Definition chan_dahdi.c:748
static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
Callback made when dial failed to get a channel out of dahdi_request().
static struct dahdi_pvt * find_channel_from_str(const char *channel)
static int __unload_module(void)
static void dahdi_softhangup_all(void)
static void dahdi_train_ec(struct dahdi_pvt *p)
static struct @120 alarms[]
static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
static enum analog_event dahdievent_to_analogevent(int event)
static int dahdi_digit_begin(struct ast_channel *ast, char digit)
static void my_unlock_private(void *pvt)
static int dahdichan_helper(struct ast_channel *chan, char *data, const char *value, char *buffer, size_t buflen)
#define HEADER_MS
#define TRANSFER
static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
static void my_set_dialing(void *pvt, int is_dialing)
static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
static int mwisend_rpas
Definition chan_dahdi.c:853
static void publish_dnd_state(int channel, const char *status)
static int my_on_hook(void *pvt)
static int attempt_transfer(struct dahdi_pvt *p)
static int cidrings[NUM_CADENCE_MAX]
cidrings says in which pause to transmit the cid information, where the first pause is 1,...
Definition chan_dahdi.c:831
static void my_set_pulsedial(void *pvt, int flag)
static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
static char * dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dahdi_wait_event(int fd)
Avoid the silly dahdi_waitevent which ignores a bunch of events.
Definition chan_dahdi.c:912
static void publish_channel_alarm(int channel, const char *alarm_txt)
static int canmatch_featurecode(const char *pickupexten, const char *exten)
static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
struct analog_callback analog_callbacks
static void dahdi_destroy_channel_range(int start, int end)
static char * dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
static void my_set_alarm(void *pvt, int in_alarm)
static int num_restart_pending
Definition chan_dahdi.c:896
static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
static int my_get_event(void *pvt)
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
static int dahdi_devicestate(const char *data)
static int user_has_defined_cadences
Definition chan_dahdi.c:816
static int dahdi_callwait(struct ast_channel *ast)
static void wakeup_sub(struct dahdi_pvt *p, int a)
static void my_set_callwaiting(void *pvt, int callwaiting_enable)
static int distinctiveringaftercid
Definition chan_dahdi.c:859
static int my_is_off_hook(void *pvt)
char * name
#define END_SILENCE_LEN
static int mwi_send_init(struct dahdi_pvt *pvt)
static int dahdi_open(char *fn)
static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages.
static int my_check_waitingfordt(void *pvt)
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
static void publish_span_alarm(int span, const char *alarm_txt)
static int dahdichan_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static void my_set_outgoing(void *pvt, int is_outgoing)
static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
static int dahdi_hangup(struct ast_channel *ast)
static void * analog_ss_thread(void *data)
static int dahdi_sendtext(struct ast_channel *c, const char *text)
static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
static int dahdichan_read_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, char *buffer, size_t len)
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)
#define PROC_DAHDI_OPT_NOCHAN
static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
static int analogsub_to_dahdisub(enum analog_sub analogsub)
static void my_get_and_handle_alarms(void *pvt)
static void my_lock_private(void *pvt)
static int dahdi_answer(struct ast_channel *ast)
static const char tdesc[]
Definition chan_dahdi.c:778
static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
static int dahdi_restart(void)
static int action_transfer(struct mansession *s, const struct message *m)
static int bump_gains(struct dahdi_pvt *p)
static void * do_monitor(void *data)
static int save_conference(struct dahdi_pvt *p)
static char * dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_clear_alarms(struct dahdi_pvt *p)
static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
static char * dahdi_sig2str(int sig)
static int dahdi_set_hook(int fd, int hs)
static int my_stop_callwait(void *pvt)
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)
static int check_for_conference(struct dahdi_pvt *p)
static struct dahdi_ring_cadence AS_RP_cadence
Definition chan_dahdi.c:839
static int dahdichan_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
#define NUM_SPANS
Definition chan_dahdi.c:804
void dahdi_ec_enable(struct dahdi_pvt *p)
#define AST_LAW(p)
Definition chan_dahdi.c:772
static int dahdi_setlinear(int dfd, int linear)
static int restart_monitor(void)
static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
static int my_confmute(void *pvt, int mute)
#define READ_SIZE
Definition chan_dahdi.c:924
static void * mwi_thread(void *data)
#define CALLPROGRESS_FAX
Definition chan_dahdi.c:812
static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
static int sigtype_to_signalling(int sigtype)
static void my_decrease_ss_count(void)
static char * handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int has_voicemail(struct dahdi_pvt *p)
static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
void dahdi_conf_update(struct dahdi_pvt *p)
static int alloc_sub(struct dahdi_pvt *p, int x)
static void my_start_polarityswitch(void *pvt)
static int digit_to_dtmfindex(char digit)
static int setup_dahdi(int reload)
static char * dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int action_dahdidndon(struct mansession *s, const struct message *m)
static int report_alarms
Definition chan_dahdi.c:868
#define GET_CHANNEL(p)
static int mwilevel
Definition chan_dahdi.c:863
static struct dahdi_pvt * iflist
#define NEED_MFDETECT(p)
Signaling types that need to use MF detection should be placed in this macro.
Definition chan_dahdi.c:776
static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
static int set_actual_txgain(int fd, float gain, float drc, int law)
static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
static int my_wait_event(void *pvt)
static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
static struct ast_channel * my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
static int analog_tone_to_dahditone(enum analog_tone tone)
static struct ast_str * create_channel_name(struct dahdi_pvt *i)
static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
#define TRAILER_MS
static int set_actual_rxgain(int fd, float gain, float drc, int law)
static int my_start(void *pvt)
static ast_mutex_t restart_lock
Definition chan_dahdi.c:894
static struct ast_frame * dahdi_handle_event(struct ast_channel *ast)
static char defaultcic[64]
Definition chan_dahdi.c:847
int alarm
static const char config[]
Definition chan_dahdi.c:799
static int action_dahdishowchannels(struct mansession *s, const struct message *m)
void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
static struct dahdi_pvt * find_next_iface_in_span(struct dahdi_pvt *cur)
static ast_cond_t ss_thread_complete
Definition chan_dahdi.c:892
static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
static struct ast_frame * dahdi_exception(struct ast_channel *ast)
static void my_answer_polarityswitch(void *pvt)
static struct ast_channel * dahdi_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
#define SMDI_MD_WAIT_TIMEOUT
Definition chan_dahdi.c:733
static int my_have_progressdetect(void *pvt)
static char * dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
#define CANPROGRESSDETECT(p)
Definition chan_dahdi.c:845
static char * dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
static int my_train_echocanceller(void *pvt)
static const char * event2str(int event)
#define CALLPROGRESS_PROGRESS
Definition chan_dahdi.c:809
static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
static void my_set_polarity(void *pvt, int value)
void dahdi_ec_disable(struct dahdi_pvt *p)
static struct ast_frame * __dahdi_exception(struct ast_channel *ast)
static void handle_alarms(struct dahdi_pvt *p, int alms)
static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
static struct dahdi_chan_conf dahdi_chan_conf_default(void)
static struct dahdi_pvt * duplicate_pseudo(struct dahdi_pvt *src)
static void swap_subs(struct dahdi_pvt *p, int a, int b)
#define ISTRUNK(p)
Definition chan_dahdi.c:841
static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
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)
static int drc_sample(int sample, float drc)
static int dahdi_get_event(int fd)
Avoid the silly dahdi_getevent which ignores a bunch of events.
Definition chan_dahdi.c:903
static int ringt_base
Configured ring timeout base.
Definition chan_dahdi.c:941
void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
static ast_mutex_t monlock
Protect the monitoring thread, so only one process can kill or start it, and not when it's doing some...
Definition chan_dahdi.c:887
#define ASCII_BYTES_PER_CHAR
static void my_all_subchannels_hungup(void *pvt)
static int my_ring(void *pvt)
static int my_start_cid_detect(void *pvt, int cid_signalling)
static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
static struct dahdi_pvt * ifend
static char * dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int my_complete_conference_update(void *pvt, int needconference)
#define DEFAULT_DIALTONE_DETECT_TIMEOUT
Definition chan_dahdi.c:935
static int mwi_send_process_buffer(struct dahdi_pvt *pvt, int num_read)
#define HEADER_LEN
static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
static void my_increase_ss_count(void)
#define REPORT_CHANNEL_ALARMS
Definition chan_dahdi.c:866
static int has_pseudo
Definition chan_dahdi.c:818
static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
static int my_wink(void *pvt, enum analog_sub sub)
static struct ast_channel_tech dahdi_tech
static struct ast_jb_conf global_jbconf
Definition chan_dahdi.c:756
#define REQUIRE_FXO_SIG()
static int my_conf_add(void *pvt, enum analog_sub sub)
static int my_dsp_reset_and_flush_digits(void *pvt)
void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
#define PROC_DAHDI_OPT_NOWARN
#define MIN_MS_SINCE_FLASH
Definition chan_dahdi.c:933
static int my_has_voicemail(void *pvt)
static char progzone[10]
Definition chan_dahdi.c:856
static int load_module(void)
Load the module.
#define sig2str
static struct ast_custom_function dahdichan_function
static struct ast_frame * dahdi_read(struct ast_channel *ast)
#define FORMAT
static const char * my_get_orig_dialstring(void *pvt)
static int action_dahdirestart(struct mansession *s, const struct message *m)
static struct ast_custom_function polarity_function
static int get_alarms(struct dahdi_pvt *p)
static struct dahdi_pvt * determine_starting_point(const char *data, struct dahdi_starting_point *param)
#define gen_pvt_field_callback(type, field)
static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
static int send_cwcidspill(struct dahdi_pvt *p)
static int my_conf_del(void *pvt, enum analog_sub sub)
#define FORMAT2
static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX]
Definition chan_dahdi.c:820
static int action_dahdidndoff(struct mansession *s, const struct message *m)
static int unload_module(void)
static int reload(void)
static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
static struct ast_cli_entry dahdi_cli[]
#define POLARITY_IDLE
#define DEFAULT_CIDRINGS
Typically, how many rings before we should send Caller*ID.
Definition chan_dahdi.c:770
static int num_cadence
Definition chan_dahdi.c:815
static int dahdichan_write_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, const char *value)
static enum analog_sigtype dahdisig_to_analogsig(int sig)
static void dahdi_close(int fd)
static char defaultozz[64]
Definition chan_dahdi.c:848
void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
static int dtmfcid_level
Definition chan_dahdi.c:864
#define CHAN_PSEUDO
Definition chan_dahdi.c:807
static int my_off_hook(void *pvt)
const char *const subnames[]
static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
static int usedistinctiveringdetection
Definition chan_dahdi.c:858
static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int print_subchannel(struct dahdi_pvt *p, int subchan, char *buffer, size_t len)
static char * dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct dahdi_pvt * find_channel(int channel)
static void * my_get_sigpvt_bridged_channel(struct ast_channel *chan)
static int send_callerid(struct dahdi_pvt *p)
static int set_hwgain(int fd, float gain, int tx_direction)
static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
static int my_check_for_conference(void *pvt)
static int mwi_send_process_event(struct dahdi_pvt *pvt, int event)
static int my_flash(void *pvt)
#define POLARITY_REV
static int ss_thread_count
Definition chan_dahdi.c:895
static const char *const lbostr[]
Definition chan_dahdi.c:735
int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
#define REPORT_SPAN_ALARMS
Definition chan_dahdi.c:867
static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
static void my_deadlock_avoidance_private(void *pvt)
static struct dahdi_pvt * handle_init_event(struct dahdi_pvt *i, int event)
static void destroy_channel(struct dahdi_pvt *cur, int now)
static void my_set_ringtimeout(void *pvt, int ringt)
static void monitor_pfds_clean(void *arg)
static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
static int ifcount
Definition chan_dahdi.c:879
#define NUM_CADENCE_MAX
Definition chan_dahdi.c:814
static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
static pthread_t monitor_thread
This is the thread for the monitor which checks for input on the channels which are not currently in ...
Definition chan_dahdi.c:891
static int action_transferhangup(struct mansession *s, const struct message *m)
#define CANBUSYDETECT(p)
Definition chan_dahdi.c:844
static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
static void destroy_all_channels(void)
static int action_dahdishowstatus(struct mansession *s, const struct message *m)
DAHDI internal API definitions.
#define SIG_FEATB
Definition chan_dahdi.h:787
#define SIG_FGC_CAMA
Definition chan_dahdi.h:790
#define SIG_SFWINK
Definition chan_dahdi.h:799
#define SIG_EMWINK
Definition chan_dahdi.h:784
#define SIG_MFCR2
Definition chan_dahdi.h:814
#define SIG_FXSLS
Definition chan_dahdi.h:792
#define MAX_SLAVES
Definition chan_dahdi.h:95
static int dahdi_sig_pri_lib_handles(int signaling)
Definition chan_dahdi.h:831
#define SIG_SF_FEATB
Definition chan_dahdi.h:802
#define SIG_FXSKS
Definition chan_dahdi.h:794
#define SIG_FXOGS
Definition chan_dahdi.h:796
#define SUB_REAL
Definition chan_dahdi.h:57
#define SIG_SF_FEATDMF
Definition chan_dahdi.h:801
static int dahdi_analog_lib_handles(int signalling, int radio, int oprmode)
Definition chan_dahdi.h:847
#define SUB_THREEWAY
Definition chan_dahdi.h:59
#define SUB_CALLWAIT
Definition chan_dahdi.h:58
#define SIG_PRI_LIB_HANDLE_CASES
Definition chan_dahdi.h:817
#define SIG_FXOKS
Definition chan_dahdi.h:797
#define SIG_FGC_CAMAMF
Definition chan_dahdi.h:791
#define SIG_FXSGS
Definition chan_dahdi.h:793
#define SIG_FEATDMF
Definition chan_dahdi.h:786
#define SIG_EM_E1
Definition chan_dahdi.h:803
#define SIG_SF_FEATD
Definition chan_dahdi.h:800
#define SIG_SS7
Definition chan_dahdi.h:811
#define SIG_BRI
Definition chan_dahdi.h:807
@ DAHDI_IFLIST_NONE
Definition chan_dahdi.h:117
@ DAHDI_IFLIST_MAIN
Definition chan_dahdi.h:118
#define SIG_FEATD
Definition chan_dahdi.h:785
#define SIG_BRI_PTMP
Definition chan_dahdi.h:808
#define SIG_FEATDMF_TA
Definition chan_dahdi.h:789
@ MWI_SEND_SA
Definition chan_dahdi.h:102
@ MWI_SEND_PAUSE
Definition chan_dahdi.h:104
@ MWI_SEND_SA_WAIT
Definition chan_dahdi.h:103
@ MWI_SEND_DONE
Definition chan_dahdi.h:107
@ MWI_SEND_SPILL
Definition chan_dahdi.h:105
@ MWI_SEND_CLEANUP
Definition chan_dahdi.h:106
#define SIG_FXOLS
Definition chan_dahdi.h:795
#define SIG_E911
Definition chan_dahdi.h:788
#define SIG_PRI
Definition chan_dahdi.h:806
#define SIG_EM
Definition chan_dahdi.h:783
#define SIG_SF
Definition chan_dahdi.h:798
#define dahdi_get_index(ast, p, nullok)
Definition chan_dahdi.h:888
static struct ast_timer * timer
Definition chan_iax2.c:388
static const char type[]
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3172
const char * ast_channel_name(const struct ast_channel *chan)
static int ast_fdisset(struct pollfd *pfds, int fd, int maximum, int *start)
Helper function for migrating select to poll.
Definition channel.h:2887
void ast_channel_rings_set(struct ast_channel *chan, int value)
void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
void ast_party_name_init(struct ast_party_name *init)
Initialize the given name structure.
Definition channel.c:1577
void * ast_channel_tech_pvt(const struct ast_channel *chan)
struct ast_format * ast_channel_rawreadformat(struct ast_channel *chan)
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition channel.c:1630
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2538
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition channel.h:1299
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition channel.c:10608
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition channel.c:1807
#define CHECK_BLOCKING(c)
Set the blocking indication on the channel.
Definition channel.h:2931
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition channel.h:2982
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition channel.c:570
unsigned short ast_channel_transfercapability(const struct ast_channel *chan)
struct ast_namedgroups * ast_ref_namedgroups(struct ast_namedgroups *groups)
Definition channel.c:7750
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3159
int ast_channel_cc_params_init(struct ast_channel *chan, const struct ast_cc_config_params *base_params)
Set up datastore with CCSS parameters for a channel.
Definition channel.c:10495
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
unsigned long long ast_group_t
Definition channel.h:215
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3007
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition channel.c:1170
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_accountcode(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
void ast_party_caller_set(struct ast_party_caller *dest, const struct ast_party_caller *src, const struct ast_set_party_caller *update)
Set the caller information based on another caller source.
Definition channel.c:1993
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4250
#define ast_channel_trylock(chan)
Definition channel.h:2984
int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame with payload.
Definition channel.c:1295
@ AST_ADSI_UNAVAILABLE
Definition channel.h:891
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition channel.c:1985
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition channel.c:1624
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition channel.c:7346
int ast_channel_fd(const struct ast_channel *chan, int which)
void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value)
int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
Queue a hangup frame with hangupcause set.
Definition channel.c:1212
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
void ast_party_caller_free(struct ast_party_caller *doomed)
Destroy the caller party contents.
Definition channel.c:2001
int ast_active_channels(void)
returns number of active/allocated channels
Definition channel.c:499
struct ast_namedgroups * ast_get_namedgroups(const char *s)
Create an ast_namedgroups set with group names from comma separated string.
Definition channel.c:7687
void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:445
int ast_channel_hangupcause(const struct ast_channel *chan)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Definition channel.c:2496
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2461
void ast_channel_named_callgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen)
Sets the HANGUPCAUSE hash and optionally the SIP_CAUSE hash on the given channel.
Definition channel.c:4340
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition channel.c:1273
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition channel.c:1248
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define AST_CHANNEL_NAME
Definition channel.h:173
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition channel.c:539
void ast_channel_softhangup_internal_flag_add(struct ast_channel *chan, int value)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition channel.c:1677
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition channel.c:2843
void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
const char * ast_channel_language(const struct ast_channel *chan)
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel's bridge pointer.
Definition channel.c:10626
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition channel.c:2416
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition channel.c:2448
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition channel.c:4354
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
struct ast_namedgroups * ast_unref_namedgroups(struct ast_namedgroups *groups)
Definition channel.c:7744
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition channel.c:7434
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_FLAG_DISABLE_DEVSTATE_CACHE
Definition channel.h:1049
@ AST_FLAG_END_DTMF_ONLY
Definition channel.h:1027
@ AST_FLAG_BLOCKING
Definition channel.h:1005
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3029
void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
ast_group_t ast_get_group(const char *s)
Definition channel.c:7630
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition channel.c:1560
const char * ast_channel_exten(const struct ast_channel *chan)
@ AST_SOFTHANGUP_EXPLICIT
Definition channel.h:1168
@ AST_SOFTHANGUP_DEV
Definition channel.h:1141
@ AST_SOFTHANGUP_APPUNLOAD
Definition channel.h:1163
#define ast_channel_unlock(chan)
Definition channel.h:2983
#define AST_MAX_EXTENSION
Definition channel.h:134
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
ast_channel_state
ast_channel states
@ AST_STATE_RING
@ AST_STATE_DIALING_OFFHOOK
@ AST_STATE_RINGING
@ AST_STATE_PRERING
@ AST_STATE_DOWN
@ AST_STATE_OFFHOOK
@ AST_STATE_BUSY
@ AST_STATE_DIALING
@ AST_STATE_UP
@ AST_STATE_RESERVED
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition channel.c:7398
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
#define RESULT_SUCCESS
Definition cli.h:40
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define RESULT_FAILURE
Definition cli.h:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
static struct channel_usage channels
#define container_of(ptr, type, member)
short word
Device state management.
@ AST_DEVSTATE_NOT_CACHABLE
Definition devicestate.h:69
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
Tells Asterisk the State for Device is changed.
ast_device_state
Device States.
Definition devicestate.h:52
@ AST_DEVICE_INUSE
Definition devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition devicestate.h:53
@ AST_DEVICE_BUSY
Definition devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition devicestate.h:54
@ AST_DEVICE_UNAVAILABLE
Definition devicestate.h:58
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1787
int ast_dsp_get_tcount(struct ast_dsp *dsp)
Get tcount (Threshold counter)
Definition dsp.c:1920
threshold
Definition dsp.h:71
#define DSP_FEATURE_WAITDIALTONE
Definition dsp.h:44
#define DSP_FEATURE_BUSY_DETECT
Definition dsp.h:27
#define DSP_TONE_STATE_DIALTONE
Definition dsp.h:54
void ast_dsp_digitreset(struct ast_dsp *dsp)
Reset DTMF detector.
Definition dsp.c:1814
#define DSP_DIGITMODE_MF
Definition dsp.h:32
#define DSP_DIGITMODE_MUTEMAX
Definition dsp.h:36
void ast_dsp_set_busy_pattern(struct ast_dsp *dsp, const struct ast_dsp_busy_pattern *cadence)
Set expected lengths of the busy tone.
Definition dsp.c:1808
struct ast_frame * ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *inf)
Return AST_FRAME_NULL frames when there is silence, AST_FRAME_BUSY on busies, and call progress,...
Definition dsp.c:1503
#define DSP_FEATURE_DIGIT_DETECT
Definition dsp.h:28
#define DSP_FEATURE_FAX_DETECT
Definition dsp.h:29
#define DSP_FEATURE_CALL_PROGRESS
Definition dsp.h:43
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition dsp.c:1861
#define DSP_DIGITMODE_MUTECONF
Definition dsp.h:35
int ast_dsp_get_tstate(struct ast_dsp *dsp)
Get tstate (Tone State)
Definition dsp.c:1915
int ast_dsp_was_muted(struct ast_dsp *dsp)
Returns true if DSP code was muting any fragment of the last processed frame. Muting (squelching) hap...
Definition dsp.c:1910
#define DSP_TONE_STATE_RINGING
Definition dsp.h:53
void ast_dsp_set_busy_count(struct ast_dsp *dsp, int cadences)
Set number of required cadences for busy.
Definition dsp.c:1797
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition dsp.c:1772
#define DSP_DIGITMODE_DTMF
Definition dsp.h:31
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1762
#define DSP_DIGITMODE_RELAXDTMF
Definition dsp.h:37
int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone)
Set zone for doing progress detection.
Definition dsp.c:1896
char * bs
Definition eagi_proxy.c:73
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
char * address
Definition f2c.h:59
#define abs(x)
Definition f2c.h:195
long int flag
Definition f2c.h:83
#define max(a, b)
Definition f2c.h:198
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition file.c:1312
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition file.c:1874
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition format.h:36
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
Media Format Cache API.
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
struct ast_format * ast_format_alaw
Built-in cached alaw format.
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
static const char name[]
Definition format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:2024
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1982
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition manager.c:634
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:2060
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1643
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2068
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1903
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7698
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
const char * ext
Definition http.c:150
#define AST_APP_ARG(name)
Define an application argument.
#define ast_app_separate_args(a, b, c, d)
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX"....
Definition main/app.c:582
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition extconf.c:3272
#define ast_variable_new(name, value, filename)
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
@ CONFIG_FLAG_FILEUNCHANGED
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
struct ast_features_pickup_config * ast_get_chan_features_pickup_config(struct ast_channel *chan)
Get the pickup configuration options for a channel.
#define AST_FRAME_DTMF
#define AST_OPTION_RELAXDTMF
#define AST_OPTION_TONE_VERIFY
#define AST_OPTION_RXGAIN
#define AST_OPTION_DIGIT_DETECT
#define AST_OPTION_OPRMODE
#define ast_frfree(fr)
#define AST_OPTION_CC_AGENT_TYPE
#define AST_OPTION_TDD
#define AST_OPTION_FAX_DETECT
#define AST_OPTION_TXGAIN
#define AST_OPTION_ECHOCAN
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_CONTROL
@ AST_CONTROL_SRCUPDATE
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_RADIO_UNKEY
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HANGUP
@ AST_CONTROL_RADIO_KEY
@ AST_CONTROL_FLASH
@ AST_CONTROL_INCOMPLETE
@ AST_CONTROL_PVT_CAUSE_CODE
#define AST_OPTION_AUDIO_MODE
struct ast_frame ast_null_frame
Definition main/frame.c:79
void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created)
Use in conjunction with ast_callid_threadstorage_auto. Cleans up the references and if the callid was...
Definition logger.c:2348
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int ast_callid
int ast_callid_threadstorage_auto(ast_callid *callid)
Checks thread storage for a callid and stores a reference if it exists. If not, then a new one will b...
Definition logger.c:2326
void ast_log_callid(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt,...)
Used for sending a log message with a known call_id This is a modified logger function which is funct...
Definition logger.c:2471
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
#define ast_verbose_callid(callid,...)
#define ast_verbose(...)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition json.c:332
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition json.h:87
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_MOVE_CURRENT(newhead, field)
Move the current list entry to another list.
#define AST_LIST_LOCK(head)
Locks a list.
Definition linkedlists.h:40
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Asterisk locking-related definitions:
#define DLA_LOCK(lock)
Definition lock.h:499
#define DLA_UNLOCK(lock)
Definition lock.h:497
#define ast_cond_destroy(cond)
Definition lock.h:209
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
#define AST_PTHREADT_NULL
Definition lock.h:73
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition lock.h:481
#define DEADLOCK_AVOIDANCE(lock)
Definition lock.h:486
#define AST_PTHREADT_STOP
Definition lock.h:74
#define ast_mutex_unlock(a)
Definition lock.h:197
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
#define ast_mutex_trylock(a)
Definition lock.h:198
pthread_cond_t ast_cond_t
Definition lock.h:185
#define ast_mutex_destroy(a)
Definition lock.h:195
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define ast_cond_signal(cond)
Definition lock.h:210
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:192
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition manager.c:10144
#define EVENT_FLAG_CALL
Definition manager.h:76
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
#define ast_module_ref(mod)
Hold a reference to the module.
Definition module.h:457
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_CHANNEL_DRIVER
Definition module.h:341
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
Music on hold handling.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition channel.c:7778
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition channel.c:7788
Asterisk MWI API.
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
void * ast_mwi_unsubscribe(struct ast_mwi_subscriber *sub)
Unsubscribe from the stasis topic and MWI.
Definition mwi.c:254
struct stasis_cache * ast_mwi_state_cache(void)
Backend cache for ast_mwi_topic_cached().
Definition mwi.c:94
struct ast_mwi_subscriber * ast_mwi_subscribe_pool(const char *mailbox, stasis_subscription_cb callback, void *data)
Add an MWI state subscriber, and stasis subscription to the mailbox.
Definition mwi.c:235
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
Definition mwi.h:378
Call Parking API.
int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data)
Perform a blind transfer to a parking extension.
Definition parking.c:143
int ast_parking_is_exten_park(const char *context, const char *exten)
Determine if the context/exten is a "parking" extension.
Definition parking.c:179
int ast_parking_provider_registered(void)
Check whether a parking provider is registered.
Definition parking.c:241
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_LOG_DIR
Definition options.c:160
Core PBX routines and definitions.
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition pbx.c:4776
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition pbx.c:4196
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1562
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition pbx.c:4211
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition pbx.c:4729
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition pbx.c:6900
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks to see if adding anything to this extension might match something. (exists ^ canmatch)
Definition pbx.c:4216
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
Definition pbx.c:6994
Call Pickup API.
int ast_pickup_call(struct ast_channel *chan)
Pickup a call.
Definition pickup.c:202
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
static struct @519 args
static int debug
Global debug status.
Definition res_xmpp.c:570
#define NULL
Definition resample.c:96
Say numbers and dates (maybe words one day too)
int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
int analog_available(struct analog_pvt *p)
Definition sig_analog.c:799
struct ast_frame * analog_exception(struct analog_pvt *p, struct ast_channel *ast)
int analog_dnd(struct analog_pvt *p, int flag)
int analog_callwaiting_deluxe(struct analog_pvt *p, int option)
int analog_config_complete(struct analog_pvt *p)
void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest, int timeout)
void analog_delete(struct analog_pvt *doomed)
Delete the analog private structure.
struct analog_pvt * analog_new(enum analog_sigtype signallingtype, void *private_data)
int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
enum analog_sigtype sigtype
Definition sig_analog.c:69
struct ast_channel * analog_request(struct analog_pvt *p, int *callwait, const struct ast_channel *requestor)
Definition sig_analog.c:776
void * analog_handle_init_event(struct analog_pvt *i, int event)
int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
Interface header for analog signaling module.
#define ANALOG_MAX_CID
Definition sig_analog.h:33
analog_dsp_digitmode
Definition sig_analog.h:114
@ ANALOG_DIGITMODE_DTMF
Definition sig_analog.h:115
@ ANALOG_DIGITMODE_MF
Definition sig_analog.h:116
#define ANALOG_INTER_DIGIT_TIMEOUT
Default time (ms) to detect following digits.
Definition sig_analog.h:40
#define ANALOG_MATCH_DIGIT_TIMEOUT
Default time (ms) to wait, in case of ambiguous match.
Definition sig_analog.h:42
@ ANALOG_DIALMODE_DTMF
Definition sig_analog.h:122
@ ANALOG_DIALMODE_PULSE
Definition sig_analog.h:121
@ ANALOG_DIALMODE_NONE
Definition sig_analog.h:123
@ ANALOG_DIALMODE_BOTH
Definition sig_analog.h:120
#define RING_PATTERNS
Definition sig_analog.h:35
analog_event
Definition sig_analog.h:79
@ ANALOG_EVENT_NONE
Definition sig_analog.h:80
@ ANALOG_EVENT_HOOKCOMPLETE
Definition sig_analog.h:89
@ ANALOG_EVENT_DTMFDOWN
Definition sig_analog.h:104
@ ANALOG_EVENT_RINGEROFF
Definition sig_analog.h:88
@ ANALOG_EVENT_PULSE_START
Definition sig_analog.h:90
@ ANALOG_EVENT_DTMFCID
Definition sig_analog.h:102
@ ANALOG_EVENT_TX_CED_DETECTED
Definition sig_analog.h:97
@ ANALOG_EVENT_NEONMWI_ACTIVE
Definition sig_analog.h:95
@ ANALOG_EVENT_RINGBEGIN
Definition sig_analog.h:92
@ ANALOG_EVENT_ONHOOK
Definition sig_analog.h:81
@ ANALOG_EVENT_EC_DISABLED
Definition sig_analog.h:93
@ ANALOG_EVENT_WINKFLASH
Definition sig_analog.h:83
@ ANALOG_EVENT_ERROR
Definition sig_analog.h:101
@ ANALOG_EVENT_PULSEDIGIT
Definition sig_analog.h:103
@ ANALOG_EVENT_RINGERON
Definition sig_analog.h:87
@ ANALOG_EVENT_RX_CED_DETECTED
Definition sig_analog.h:98
@ ANALOG_EVENT_ALARM
Definition sig_analog.h:84
@ ANALOG_EVENT_DIALCOMPLETE
Definition sig_analog.h:86
@ ANALOG_EVENT_EC_NLP_ENABLED
Definition sig_analog.h:100
@ ANALOG_EVENT_POLARITY
Definition sig_analog.h:91
@ ANALOG_EVENT_NEONMWI_INACTIVE
Definition sig_analog.h:96
@ ANALOG_EVENT_DTMFUP
Definition sig_analog.h:105
@ ANALOG_EVENT_EC_NLP_DISABLED
Definition sig_analog.h:99
@ ANALOG_EVENT_RINGOFFHOOK
Definition sig_analog.h:82
@ ANALOG_EVENT_REMOVED
Definition sig_analog.h:94
@ ANALOG_EVENT_NOALARM
Definition sig_analog.h:85
@ ANALOG_DIAL_OP_REPLACE
Definition sig_analog.h:134
analog_sub
Definition sig_analog.h:108
@ ANALOG_SUB_THREEWAY
Definition sig_analog.h:111
@ ANALOG_SUB_REAL
Definition sig_analog.h:109
@ ANALOG_SUB_CALLWAIT
Definition sig_analog.h:110
#define ANALOG_FIRST_DIGIT_TIMEOUT
Default time (ms) to detect first digit.
Definition sig_analog.h:38
analog_sigtype
Definition sig_analog.h:45
@ ANALOG_SIG_FEATD
Definition sig_analog.h:56
@ ANALOG_SIG_FEATDMF_TA
Definition sig_analog.h:66
@ ANALOG_SIG_FGC_CAMAMF
Definition sig_analog.h:60
@ ANALOG_SIG_FXOLS
Definition sig_analog.h:47
@ ANALOG_SIG_FEATDMF
Definition sig_analog.h:57
@ ANALOG_SIG_EM_E1
Definition sig_analog.h:55
@ ANALOG_SIG_EMWINK
Definition sig_analog.h:53
@ ANALOG_SIG_FXOKS
Definition sig_analog.h:48
@ ANALOG_SIG_SF
Definition sig_analog.h:63
@ ANALOG_SIG_FGC_CAMA
Definition sig_analog.h:59
@ ANALOG_SIG_FXSLS
Definition sig_analog.h:50
@ ANALOG_SIG_EM
Definition sig_analog.h:54
@ ANALOG_SIG_FXOGS
Definition sig_analog.h:49
@ ANALOG_SIG_NONE
Definition sig_analog.h:46
@ ANALOG_SIG_FXSGS
Definition sig_analog.h:52
@ ANALOG_SIG_SF_FEATDMF
Definition sig_analog.h:65
@ ANALOG_SIG_SFWINK
Definition sig_analog.h:62
@ ANALOG_SIG_FEATB
Definition sig_analog.h:61
@ ANALOG_SIG_SF_FEATD
Definition sig_analog.h:64
@ ANALOG_SIG_FXSKS
Definition sig_analog.h:51
analog_tone
Definition sig_analog.h:70
@ ANALOG_TONE_CONGESTION
Definition sig_analog.h:73
@ ANALOG_TONE_INFO
Definition sig_analog.h:76
@ ANALOG_TONE_DIALTONE
Definition sig_analog.h:74
@ ANALOG_TONE_DIALRECALL
Definition sig_analog.h:75
@ ANALOG_TONE_STUTTER
Definition sig_analog.h:72
@ ANALOG_TONE_RINGTONE
Definition sig_analog.h:71
@ ANALOG_CID_START_RING
Definition sig_analog.h:129
@ ANALOG_CID_START_DTMF_NOALERT
Definition sig_analog.h:130
@ ANALOG_CID_START_POLARITY
Definition sig_analog.h:127
@ ANALOG_CID_START_POLARITY_IN
Definition sig_analog.h:128
Interface header for PRI signaling module.
int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
void sig_pri_unload(void)
sig_pri_law
Definition sig_pri.h:67
@ SIG_PRI_DEFLAW
Definition sig_pri.h:68
@ SIG_PRI_ULAW
Definition sig_pri.h:69
@ SIG_PRI_ALAW
Definition sig_pri.h:70
#define SIG_PRI_DEBUG_NORMAL
Definition sig_pri.h:41
@ SIG_PRI_COLP_UPDATE
Definition sig_pri.h:441
@ SIG_PRI_COLP_CONNECT
Definition sig_pri.h:439
@ SIG_PRI_COLP_BLOCK
Definition sig_pri.h:437
int pri_send_callrerouting_facility_exec(struct sig_pri_chan *p, enum ast_channel_state chanstate, const char *destination, const char *original, const char *reason)
int sig_pri_ami_show_spans(struct mansession *s, const char *show_cmd, struct sig_pri_span *pri, const int *dchannels, const char *action_id)
int sig_pri_cc_agent_status_req(struct ast_cc_agent *agent)
struct sig_pri_callback sig_pri_callbacks
int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen)
void sig_pri_extract_called_num_subaddr(struct sig_pri_chan *p, const char *rdest, char *called, size_t called_buff_size)
#define SIG_PRI_NUM_DCHANS
Definition sig_pri.h:239
int sig_pri_cc_agent_start_offer_timer(struct ast_cc_agent *agent)
int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
int sig_pri_cc_monitor_unsuspend(struct ast_cc_monitor *monitor)
int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel)
int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rdest, int timeout, int layer1)
#define DAHDI_OVERLAPDIAL_OUTGOING
Definition sig_pri.h:252
int sig_pri_is_alarm_ignored(struct sig_pri_span *pri)
int sig_pri_cc_monitor_req_cc(struct ast_cc_monitor *monitor, int *available_timer_id)
int sig_pri_start_pri(struct sig_pri_span *pri)
int sig_pri_cc_monitor_cancel_available_timer(struct ast_cc_monitor *monitor, int *sched_id)
void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri)
void sig_pri_cc_agent_req_rsp(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
int sig_pri_cc_monitor_suspend(struct ast_cc_monitor *monitor)
@ SIG_PRI_RESET_IDLE
The channel is not being RESTARTed.
Definition sig_pri.h:154
#define DAHDI_OVERLAPDIAL_BOTH
Definition sig_pri.h:254
void sig_pri_stop_pri(struct sig_pri_span *pri)
void sig_pri_cc_agent_destructor(struct ast_cc_agent *agent)
void sig_pri_cli_show_spans(int fd, int span, struct sig_pri_span *pri)
void sig_pri_init_pri(struct sig_pri_span *pri)
#define SIG_PRI_AOC_GRANT_D
Definition sig_pri.h:54
#define DAHDI_OVERLAPDIAL_NONE
Definition sig_pri.h:251
int sig_pri_cc_agent_start_monitoring(struct ast_cc_agent *agent)
#define DAHDI_CHAN_MAPPING_LOGICAL
Definition sig_pri.h:248
int sig_pri_cc_agent_init(struct ast_cc_agent *agent, struct sig_pri_chan *pvt_chan)
void sig_pri_chan_alarm_notify(struct sig_pri_chan *p, int noalarm)
int sig_pri_load(const char *cc_type_name)
@ SIG_PRI_CALL_LEVEL_PROCEEDING
Definition sig_pri.h:143
@ SIG_PRI_MOH_SIGNALING_MOH
Definition sig_pri.h:75
@ SIG_PRI_MOH_SIGNALING_NOTIFY
Definition sig_pri.h:77
int sig_pri_cc_agent_callee_available(struct ast_cc_agent *agent)
#define DAHDI_OVERLAPDIAL_INCOMING
Definition sig_pri.h:253
struct ast_channel * sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int transfercapability)
#define SIG_PRI_AOC_GRANT_E
Definition sig_pri.h:55
void sig_pri_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_pri_chan *pchan)
void sig_pri_cc_monitor_destructor(void *monitor_pvt)
void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast)
struct sig_pri_chan * sig_pri_chan_new(void *pvt_data, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup)
void pri_event_noalarm(struct sig_pri_span *pri, int index, int before_start_pri)
void sig_pri_cli_show_span(int fd, int *dchannels, struct sig_pri_span *pri)
void sig_pri_chan_delete(struct sig_pri_chan *doomed)
int sig_pri_answer(struct sig_pri_chan *p, struct ast_channel *ast)
#define SIG_PRI_AOC_GRANT_S
Definition sig_pri.h:53
sig_pri_tone
Definition sig_pri.h:57
@ SIG_PRI_TONE_RINGTONE
Definition sig_pri.h:58
@ SIG_PRI_TONE_INFO
Definition sig_pri.h:63
@ SIG_PRI_TONE_DIALTONE
Definition sig_pri.h:61
@ SIG_PRI_TONE_BUSY
Definition sig_pri.h:64
@ SIG_PRI_TONE_STUTTER
Definition sig_pri.h:59
@ SIG_PRI_TONE_CONGESTION
Definition sig_pri.h:60
@ SIG_PRI_TONE_DIALRECALL
Definition sig_pri.h:62
void pri_event_alarm(struct sig_pri_span *pri, int index, int before_start_pri)
int sig_pri_cc_agent_stop_offer_timer(struct ast_cc_agent *agent)
void sig_pri_cli_show_channels_header(int fd)
void sig_pri_set_alarm(struct sig_pri_chan *p, int in_alarm)
int sig_pri_cc_agent_party_b_free(struct ast_cc_agent *agent)
int sig_pri_cc_monitor_status_rsp(struct ast_cc_monitor *monitor, enum ast_device_state devstate)
#define DAHDI_CHAN_MAPPING_PHYSICAL
Definition sig_pri.h:247
int sig_pri_cc_agent_stop_ringing(struct ast_cc_agent *agent)
int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char digit)
int pri_send_keypad_facility_exec(struct sig_pri_chan *p, const char *digits)
Interface header for SS7 signaling module.
void sig_ss7_cb_call_null(struct ss7 *ss7, struct isup_call *c, int lock)
void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which)
void sig_ss7_cli_show_channels_header(int fd)
struct ast_channel * sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int transfercapability)
void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7)
void sig_ss7_link_alarm(struct sig_ss7_linkset *linkset, int which)
#define LINKSET_FLAG_EXPLICITACM
Definition sig_ss7.h:68
#define LINKSET_FLAG_AUTOACM
Definition sig_ss7.h:72
int sig_ss7_reset_group(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, int range)
int sig_ss7_available(struct sig_ss7_chan *p)
void sig_ss7_cb_notinservice(struct ss7 *ss7, int cic, unsigned int dpc)
int sig_ss7_reset_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rdest)
void * ss7_linkset(void *data)
int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen)
#define SS7_BLOCKED_MAINTENANCE
Definition sig_ss7.h:74
int sig_ss7_group_blocking(struct sig_ss7_linkset *linkset, int do_block, int startcic, int endcic, unsigned char state[], int type)
int sig_ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
#define SIG_SS7_DEBUG
Definition sig_ss7.h:43
struct sig_ss7_callback sig_ss7_callbacks
void sig_ss7_set_alarm(struct sig_ss7_chan *p, int in_alarm)
sig_ss7_tone
Definition sig_ss7.h:78
@ SIG_SS7_TONE_DIALRECALL
Definition sig_ss7.h:83
@ SIG_SS7_TONE_INFO
Definition sig_ss7.h:84
@ SIG_SS7_TONE_STUTTER
Definition sig_ss7.h:80
@ SIG_SS7_TONE_RINGTONE
Definition sig_ss7.h:79
@ SIG_SS7_TONE_CONGESTION
Definition sig_ss7.h:81
@ SIG_SS7_TONE_DIALTONE
Definition sig_ss7.h:82
@ SIG_SS7_TONE_BUSY
Definition sig_ss7.h:85
struct sig_ss7_chan * sig_ss7_chan_new(void *pvt_data, struct sig_ss7_linkset *ss7)
void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset)
int sig_ss7_cic_blocking(struct sig_ss7_linkset *linkset, int do_block, int cic)
#define LINKSET_FLAG_DEFAULTECHOCONTROL
Definition sig_ss7.h:71
sig_ss7_law
Definition sig_ss7.h:88
@ SIG_SS7_DEFLAW
Definition sig_ss7.h:89
@ SIG_SS7_ULAW
Definition sig_ss7.h:90
@ SIG_SS7_ALAW
Definition sig_ss7.h:91
#define LINKSET_FLAG_USEECHOCONTROL
Definition sig_ss7.h:70
void sig_ss7_chan_delete(struct sig_ss7_chan *doomed)
#define LINKSET_FLAG_INITIALHWBLO
Definition sig_ss7.h:69
int sig_ss7_cb_hangup(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup)
#define SS7_NAI_DYNAMIC
Definition sig_ss7.h:66
int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode, int cur_slc)
int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_ss7_chan *pchan)
#define SS7_BLOCKED_HARDWARE
Definition sig_ss7.h:75
#define SIG_SS7_NUM_DCHANS
Definition sig_ss7.h:56
int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
int sig_ss7_find_cic_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
SMDI support for Asterisk.
#define SMDI_MAX_FILENAME_LEN
Definition smdi.h:42
struct ast_smdi_interface *AST_OPTIONAL_API_NAME() ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
Definition res_smdi.c:569
struct ast_smdi_md_message *AST_OPTIONAL_API_NAME() ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
Get the next SMDI message from the queue.
Definition res_smdi.c:545
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1515
#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name,...)
Boiler-plate messaging macro for defining local message types.
Definition stasis.h:1467
void stasis_subscription_cb_noop(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Stasis subscription callback function that does nothing.
Definition stasis.c:876
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_cache_get(struct stasis_cache *cache, struct stasis_message_type *type, const char *id)
Retrieve an item from the cache for the ast_eid_default entity.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2235
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition utils.c:2252
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
int(*const play_tone)(void *pvt, enum analog_sub sub, enum analog_tone tone)
Definition sig_analog.h:182
int(*const start)(void *pvt)
Definition sig_analog.h:161
unsigned int immediate
Definition sig_analog.h:298
unsigned int immediatering
Definition sig_analog.h:299
unsigned int permcallwaiting
Definition sig_analog.h:301
unsigned int callwaitingdeluxepending
TRUE if a Call Waiting Deluxe action is currently pending.
Definition sig_analog.h:356
unsigned int canpark
Definition sig_analog.h:295
unsigned int dnd
Definition sig_analog.h:340
unsigned int dahditrcallerid
Definition sig_analog.h:296
char lastexten[AST_MAX_EXTENSION]
Definition sig_analog.h:364
int polarityonanswerdelay
Definition sig_analog.h:327
char cid_num[AST_MAX_EXTENSION]
Definition sig_analog.h:331
int redirecting_reason
Definition sig_analog.h:366
unsigned int permhidecallerid
Definition sig_analog.h:303
struct timeval flashtime
Definition sig_analog.h:374
unsigned int callwaitingcallerid
Definition sig_analog.h:312
unsigned int ani_wink_time
Definition sig_analog.h:289
enum analog_sigtype outsigmod
Definition sig_analog.h:323
unsigned int usedistinctiveringdetection
Definition sig_analog.h:311
unsigned int answeronpolarityswitch
Definition sig_analog.h:291
unsigned int threewaycalling
Definition sig_analog.h:306
unsigned int pulse
Definition sig_analog.h:305
int echotraining
Definition sig_analog.h:325
int msgstate
-1 = unknown, 0 = no messages, 1 = new messages available
Definition sig_analog.h:284
unsigned int hanguponpolarityswitch
Definition sig_analog.h:297
enum analog_dialmode permdialmode
Definition sig_analog.h:304
unsigned int callwaitingdeluxe
Definition sig_analog.h:302
char call_forward[AST_MAX_EXTENSION]
Definition sig_analog.h:379
enum analog_cid_start cid_start
Definition sig_analog.h:329
unsigned int callreturn
Definition sig_analog.h:293
struct ast_channel * owner
Definition sig_analog.h:277
unsigned int use_smdi
TRUE if SMDI (Simplified Message Desk Interface) is enabled.
Definition sig_analog.h:316
unsigned int call_qualifier
Definition sig_analog.h:358
unsigned int ani_timeout
Definition sig_analog.h:288
unsigned int lastnumredial
Definition sig_analog.h:300
int fxsoffhookstate
Definition sig_analog.h:282
unsigned int ani_info_digits
Definition sig_analog.h:287
enum analog_dialmode dialmode
Definition sig_analog.h:324
unsigned int cancallforward
Definition sig_analog.h:294
struct analog_subchannel subs[3]
Definition sig_analog.h:279
int cid_signalling
Definition sig_analog.h:326
unsigned int transfer
Definition sig_analog.h:308
unsigned int transfertobusy
Definition sig_analog.h:309
unsigned int inalarm
Definition sig_analog.h:344
char cid_name[AST_MAX_EXTENSION]
Definition sig_analog.h:332
unsigned int calledsubscriberheld
Definition sig_analog.h:292
char mohsuggest[MAX_MUSICCLASS]
Definition sig_analog.h:330
unsigned int use_callerid
Definition sig_analog.h:310
struct ast_channel * ss_astchan
Definition sig_analog.h:382
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition sig_analog.h:318
struct ast_party_caller caller
Definition sig_analog.h:365
struct ast_channel * owner
Definition sig_analog.h:264
Structure to pass both assignedid values to channel drivers.
Definition channel.h:606
Structure that contains information regarding a channel in a bridge.
struct ast_channel * chan
const char * type
Type of agent the callbacks belong to.
Definition ccss.h:857
Callbacks defined by CC monitors.
Definition ccss.h:542
const char * type
Type of monitor the callbacks belong to.
Definition ccss.h:549
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
struct ast_format_cap * capabilities
Definition channel.h:652
const char *const type
Definition channel.h:649
Main Channel structure associated with a channel.
ast_callid callid
char exten[AST_MAX_EXTENSION]
const char * data
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
struct ast_flags flags
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * name
Definition pbx.h:119
int pattern[4]
Definition dsp.h:68
Configuration relating to call pickup.
Structure used to handle boolean flags.
Definition utils.h:220
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
struct ast_codec * codec
Pointer to the codec in use for this format.
Definition format.c:47
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
struct timeval delivery
enum ast_frame_type frametype
union ast_frame::@239 data
General jitterbuffer configuration.
Definition abstract_jb.h:70
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition abstract_jb.h:72
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition manager.h:503
struct ast_module * self
Definition module.h:356
The structure that contains MWI state.
Definition mwi.h:455
int new_msgs
Definition mwi.h:459
Caller Party information.
Definition channel.h:420
struct ast_party_id id
Caller party ID.
Definition channel.h:422
int ani2
Automatic Number Identification 2 (Info Digits)
Definition channel.h:435
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition channel.h:429
struct ast_party_id id
Connected party ID.
Definition channel.h:460
char * str
Subscriber phone number (Malloced)
Definition channel.h:388
struct ast_party_dialed::@221 number
Dialed/Called number.
struct ast_party_subaddress subaddress
Subscriber subaddress.
Definition channel.h:346
char * tag
User-set "tag".
Definition channel.h:356
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
int presentation
Q.931 encoded presentation-indicator encoded field.
Definition channel.h:279
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
int presentation
Q.931 presentation-indicator and screening-indicator encoded fields.
Definition channel.h:297
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293
int plan
Q.931 Type-Of-Number and Numbering-Plan encoded fields.
Definition channel.h:295
int code
enum AST_REDIRECTING_REASON value for redirection
Definition channel.h:512
struct ast_party_redirecting_reason reason
Reason for the redirection.
Definition channel.h:544
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition channel.h:529
unsigned char valid
TRUE if the subaddress information is valid/present.
Definition channel.h:330
char * str
Malloced subaddress string.
Definition channel.h:315
An SMDI message desk message.
Definition smdi.h:65
char calling_st[SMDI_MAX_STATION_NUM_LEN+1]
Definition smdi.h:70
char fwd_st[SMDI_MAX_STATION_NUM_LEN+1]
Definition smdi.h:69
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
char number[64]
Definition callerid.c:54
Definition astman.c:88
All configuration options for http media cache.
Channel configuration from chan_dahdi.conf . This struct is used for parsing the [channels] section o...
char smdi_port[SMDI_MAX_FILENAME_LEN]
The serial port to listen for SMDI data on.
struct dahdi_params timing
int wanted_channels_end
Don't create channels above this number (infinity by default)
struct dahdi_pvt chan
int wanted_channels_start
Don't create channels below this number.
struct ringContextData ringContext[3]
Definition chan_dahdi.h:71
struct distRingData ringnum[3]
Definition chan_dahdi.h:70
unsigned int echocanon
TRUE if echo cancellation is turned on.
Definition chan_dahdi.h:272
char dialdest[256]
Delayed dialing for E911. Overlap digits for ISDN.
Definition chan_dahdi.h:719
unsigned int immediate
TRUE if the channel should be answered immediately without attempting to gather any digits.
Definition chan_dahdi.h:316
unsigned int immediatering
TRUE if audible ringback should be provided when immediate = yes.
Definition chan_dahdi.h:322
unsigned int threewaysilenthold
TRUE if a three way dial tone should time out to silence.
Definition chan_dahdi.h:377
enum DAHDI_IFLIST which_iflist
Definition chan_dahdi.h:168
unsigned int permcallwaiting
TRUE if busy extensions will hear the call-waiting tone and can use hook-flash to switch between call...
Definition chan_dahdi.h:334
float cid_rxgain
Amount of gain to increase during caller id.
Definition chan_dahdi.h:158
float txdrc
Definition chan_dahdi.h:164
struct dahdi_distRings drings
Distinctive Ring data.
Definition chan_dahdi.h:491
struct ast_variable * vars
Channel variable list with associated values to set when a channel is created.
Definition chan_dahdi.h:590
char cid_subaddr[AST_MAX_EXTENSION]
Caller ID subaddress from an incoming call.
Definition chan_dahdi.h:543
unsigned int canpark
TRUE if support for call parking is enabled.
Definition chan_dahdi.h:243
unsigned int bufferoverrideinuse
Definition chan_dahdi.h:278
int law
Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition chan_dahdi.h:562
unsigned int hwtxgain_enabled
TRUE if hardware Tx gain set by Asterisk.
Definition chan_dahdi.h:475
unsigned int dnd
TRUE if Do-Not-Disturb is enabled, present only for non sig_analog.
Definition chan_dahdi.h:262
int faxbuf_policy
Definition chan_dahdi.h:142
unsigned int ignoredtmf
TRUE if DTMF detection is disabled.
Definition chan_dahdi.h:310
struct dahdi_dialoperation dop
DAHDI dial operation command struct for ioctl() call.
Definition chan_dahdi.h:702
struct timeval dtmfcid_delay
Definition chan_dahdi.h:597
unsigned int dahditrcallerid
TRUE if we should use the callerid from incoming call on dahdi transfer.
Definition chan_dahdi.h:412
struct dahdi_pvt * next
Definition chan_dahdi.h:169
unsigned int doreoriginate
Internal flag for if we should actually process a reorigination.
Definition chan_dahdi.h:293
unsigned char * cidspill
Analog caller ID waveform sample buffer.
Definition chan_dahdi.h:603
struct tdd_state * tdd
Definition chan_dahdi.h:708
int waitfordialtonetemp
Transient variable. Same as waitfordialtone, but temporarily set for a specific call,...
Definition chan_dahdi.h:666
int cidlen
Length of the cidspill buffer containing samples.
Definition chan_dahdi.h:607
int polarityonanswerdelay
Minimal time period (ms) between the answer polarity switch and hangup polarity switch.
Definition chan_dahdi.h:733
int busycount
Number of times to see "busy" tone before hanging up.
Definition chan_dahdi.h:647
char cid_num[AST_MAX_EXTENSION]
Caller ID number from an incoming call.
Definition chan_dahdi.h:532
struct dahdi_pvt::@121 echocancel
Echo cancel parameters.
int ringt
Ring timeout timer??
Definition chan_dahdi.h:609
struct ast_mwi_subscriber * mwi_event_sub
Opaque event subscription parameters for message waiting indication support.
Definition chan_dahdi.h:717
ast_group_t group
Bitmapped groups this belongs to.
Definition chan_dahdi.h:558
int sendcalleridafter
Send caller ID on FXS after this many rings. Set to 1 for US.
Definition chan_dahdi.h:740
struct dahdi_pvt * oprpeer
Definition chan_dahdi.h:152
unsigned int permhidecallerid
TRUE if the outgoing caller ID is blocked/restricted/hidden.
Definition chan_dahdi.h:343
unsigned int mwisendactive
TRUE if a MWI message sending thread is active.
Definition chan_dahdi.h:437
char * origcid_name
Definition chan_dahdi.h:545
struct mwisend_info mwisend_data
Definition chan_dahdi.h:486
int cid_suppress_expire
Definition chan_dahdi.h:601
struct timeval flashtime
Definition chan_dahdi.h:698
int interdigit_timeout
Time (ms) to detect following digits (in an analog phone)
Definition chan_dahdi.h:691
unsigned int mwimonitor_rpas
TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
Definition chan_dahdi.h:433
struct dahdi_pvt * master
Definition chan_dahdi.h:135
unsigned int confirmanswer
TRUE if to wait for a DTMF digit to confirm answer.
Definition chan_dahdi.h:245
unsigned int restartpending
Definition chan_dahdi.h:361
unsigned int mwimonitoractive
TRUE if an MWI monitor thread is currently active.
Definition chan_dahdi.h:435
unsigned int outgoing
TRUE if we originated the call leg.
Definition chan_dahdi.h:328
unsigned int faxdetect_timeout
The number of seconds into call to disable fax detection. (0 = disabled)
Definition chan_dahdi.h:681
int whichwink
Definition chan_dahdi.h:703
float rxdrc
Definition chan_dahdi.h:165
unsigned int callwaitingcallerid
TRUE if send caller ID for Call Waiting.
Definition chan_dahdi.h:231
char * origcid_num
Definition chan_dahdi.h:544
unsigned int manages_span_alarms
TRUE if the channel alarms will be managed also as Span ones.
Definition chan_dahdi.h:471
unsigned int ani_wink_time
INTEGER, length of time to wait before sending ANI wink in ms.
Definition chan_dahdi.h:200
int waitfordialtone
Number of milliseconds to wait for dialtone.
Definition chan_dahdi.h:662
unsigned int locallyblocked
Bitmask for the channel being locally blocked.
Definition chan_dahdi.h:457
unsigned int adsi
TRUE if ADSI (Analog Display Services Interface) available.
Definition chan_dahdi.h:178
int outsigmod
Definition chan_dahdi.h:150
unsigned int usedistinctiveringdetection
TRUE if distinctive rings are to be detected.
Definition chan_dahdi.h:407
unsigned int answeronpolarityswitch
TRUE if we can use a polarity reversal to mark when an outgoing call is answered by the remote party.
Definition chan_dahdi.h:184
unsigned int threewaycalling
TRUE if three way calling is enabled.
Definition chan_dahdi.h:372
struct dahdi_subchannel subs[3]
Definition chan_dahdi.h:131
int distinctivering
Definition chan_dahdi.h:725
struct dahdi_confinfo saveconf
Definition chan_dahdi.h:132
unsigned int use_callingpres
TRUE if we will use the calling presentation setting from the Asterisk channel for outgoing calls.
Definition chan_dahdi.h:401
int dtmfrelax
Definition chan_dahdi.h:726
unsigned int pulse
TRUE if we will pulse dial.
Definition chan_dahdi.h:358
int dialtone_scanning_time_elapsed
Definition chan_dahdi.h:676
unsigned int priexclusive
TRUE if PRI B channels are always exclusively selected.
Definition chan_dahdi.h:353
char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Voice mailbox location.
Definition chan_dahdi.h:715
float hwrxgain
Hardware Rx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:154
int echotraining
Echo training time. 0 = disabled.
Definition chan_dahdi.h:640
char callwait_num[AST_MAX_EXTENSION]
Call waiting number.
Definition chan_dahdi.h:547
float hwtxgain
Hardware Tx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:156
int waitfordialtoneduration
Transient variable. Stored off waitfordialtone duration at runtime.
Definition chan_dahdi.h:670
int dsp_features
DSP feature flags: DSP_FEATURE_xxx.
Definition chan_dahdi.h:744
unsigned int callwaiting
TRUE if busy extensions will hear the call-waiting tone and can use hook-flash to switch between call...
Definition chan_dahdi.h:226
char exten[AST_MAX_EXTENSION]
Extension to use in the dialplan.
Definition chan_dahdi.h:508
int callprogress
Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
Definition chan_dahdi.h:657
int callwaitcas
TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
Definition chan_dahdi.h:628
time_t guardtime
Definition chan_dahdi.h:593
struct timeval polaritydelaytv
Start delay time if polarityonanswerdelay is nonzero.
Definition chan_dahdi.h:735
unsigned int hanguponpolarityswitch
TRUE if the call will be considered "hung up" on a polarity reversal.
Definition chan_dahdi.h:285
enum analog_dialmode permdialmode
Definition chan_dahdi.h:149
char dnid[AST_MAX_EXTENSION]
Dialed Number Identifier.
Definition chan_dahdi.h:553
char dialstring[AST_CHANNEL_NAME]
Definition chan_dahdi.h:778
unsigned int callwaitingdeluxe
TRUE if Call Waiting Deluxe options should be available.
Definition chan_dahdi.h:338
char call_forward[AST_MAX_EXTENSION]
Accumulated call forwarding number.
Definition chan_dahdi.h:710
char description[32]
A description for the channel configuration.
Definition chan_dahdi.h:502
unsigned int firstradio
TRUE if over a radio and dahdi_read() has been called.
Definition chan_dahdi.h:280
unsigned int remotelyblocked
Bitmask for the channel being remotely blocked. 1 maintenance, 2 blocked in hardware.
Definition chan_dahdi.h:466
unsigned int hidecallerid
TRUE if the outgoing caller ID is blocked/hidden.
Definition chan_dahdi.h:302
unsigned int echobreak
XXX BOOLEAN Purpose???
Definition chan_dahdi.h:264
struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS]
Definition chan_dahdi.h:634
int faxbuf_no
Definition chan_dahdi.h:141
unsigned int callreturn
TRUE if call return is enabled. (*69, if your dialplan doesn't catch this first)
Definition chan_dahdi.h:219
struct ast_namedgroups * named_pickupgroups
Named pickup groups this belongs to.
Definition chan_dahdi.h:585
struct ast_channel * owner
Definition chan_dahdi.h:127
char rdnis[AST_MAX_EXTENSION]
Redirecting Directory Number Information Service (RDNIS) number.
Definition chan_dahdi.h:551
unsigned int faxhandled
TRUE if a fax tone has already been handled.
Definition chan_dahdi.h:274
unsigned int use_smdi
TRUE if SMDI (Simplified Message Desk Interface) is enabled.
Definition chan_dahdi.h:485
struct callerid_state * cs
Definition chan_dahdi.h:126
int cid_ani2
Automatic Number Identification code from PRI.
Definition chan_dahdi.h:530
struct ast_namedgroups * named_callgroups
Named call groups this belongs to.
Definition chan_dahdi.h:580
int callwaitrings
Number of call waiting rings.
Definition chan_dahdi.h:630
unsigned int mwimonitor_neon
TRUE if the FXO port monitors for neon type MWI indications from the other end.
Definition chan_dahdi.h:422
unsigned int dialednone
TRUE if analog type line dialed no digits in Dial()
Definition chan_dahdi.h:253
unsigned int hwrxgain_enabled
TRUE if hardware Rx gain set by Asterisk.
Definition chan_dahdi.h:473
int law_default
Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition chan_dahdi.h:560
int fake_event
Holding place for event injected from outside normal operation.
Definition chan_dahdi.h:728
unsigned int didtdd
Definition chan_dahdi.h:251
char echorest[20]
Filled with 'w'. XXX Purpose??
Definition chan_dahdi.h:642
struct dahdi_pvt * slaves[MAX_SLAVES]
Definition chan_dahdi.h:134
void * sig_pvt
Definition chan_dahdi.h:770
unsigned int ani_timeout
INTEGER, length of ANI failure timeout in ms.
Definition chan_dahdi.h:195
int dtmfcid_holdoff_state
Definition chan_dahdi.h:596
unsigned int lastnumredial
TRUE if last number redial enabled.
Definition chan_dahdi.h:448
unsigned int mwioverride_active
TRUE if a manual MWI override is active for a channel.
Definition chan_dahdi.h:439
unsigned int mwimonitor_fsk
TRUE if the FXO port monitors for fsk type MWI indications from the other end.
Definition chan_dahdi.h:427
int ringt_base
Ring timeout base.
Definition chan_dahdi.h:614
int cid_start
Definition chan_dahdi.h:595
unsigned int destroy
TRUE if the channel is to be destroyed on hangup. (Used by pseudo channels.)
Definition chan_dahdi.h:250
unsigned int restrictcid
TRUE if caller ID is restricted.
Definition chan_dahdi.h:367
char defcontext[AST_MAX_CONTEXT]
Default distinctive ring context.
Definition chan_dahdi.h:506
unsigned int priindication_oob
TRUE if PRI congestion/busy indications are sent out-of-band.
Definition chan_dahdi.h:348
unsigned int ani_info_digits
INTEGER, number of ANI INFO digits on a CAMA trunk. older switches use 1 INFO digit,...
Definition chan_dahdi.h:190
unsigned int busydetect
TRUE if busy detection is enabled. (Listens for the beep-beep busy pattern.)
Definition chan_dahdi.h:206
unsigned int hidecalleridname
TRUE if hide just the name not the number for legacy PBX use.
Definition chan_dahdi.h:308
struct timeval waitingfordt
Definition chan_dahdi.h:697
struct ast_dsp * dsp
Opaque DSP configuration structure.
Definition chan_dahdi.h:700
struct dahdi_pvt * prev
Definition chan_dahdi.h:170
ast_group_t pickupgroup
Bitmapped pickup groups this belongs to.
Definition chan_dahdi.h:575
int callingpres
Definition chan_dahdi.h:598
unsigned int reoriginate
TRUE if FXS (FXO-signalled) channel should reoriginate for user to make a new call.
Definition chan_dahdi.h:289
int buf_policy
Definition chan_dahdi.h:140
int cidpos
Position in the cidspill buffer to send out next.
Definition chan_dahdi.h:605
char context[AST_MAX_CONTEXT]
The configured context for incoming calls.
Definition chan_dahdi.h:497
unsigned int cancallforward
TRUE if support for call forwarding enabled. Dial *72 to enable call forwarding. Dial *73 to disable ...
Definition chan_dahdi.h:238
int radio
Nonzero if the signaling type is sent over a radio.
Definition chan_dahdi.h:148
char parkinglot[AST_MAX_EXTENSION]
Definition chan_dahdi.h:524
int cidcwexpire
Definition chan_dahdi.h:600
unsigned int hardwaredtmf
TRUE if DTMF detection needs to be done by hardware.
Definition chan_dahdi.h:295
int callwaitingrepeat
Definition chan_dahdi.h:599
char begindigit
DTMF digit in progress. 0 when no digit in progress.
Definition chan_dahdi.h:767
struct ast_cc_config_params * cc_params
Definition chan_dahdi.h:771
unsigned int mate
TRUE if TDD in MATE mode.
Definition chan_dahdi.h:326
float txgain
Software Tx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:162
int firstdigit_timeout
Time (ms) to detect first digit (in an analog phone)
Definition chan_dahdi.h:686
struct dahdi_echocanparams head
Definition chan_dahdi.h:633
unsigned int echocanbridged
TRUE if echo cancellation enabled when bridged.
Definition chan_dahdi.h:270
int cid_signalling
Definition chan_dahdi.h:594
char finaldial[64]
Second part of SIG_FEATDMF_TA wink operation.
Definition chan_dahdi.h:705
unsigned int transfer
TRUE if call transfer is enabled.
Definition chan_dahdi.h:386
unsigned int transfertobusy
TRUE if allowed to flash-transfer to busy channels.
Definition chan_dahdi.h:417
unsigned int inalarm
TRUE if in an alarm condition.
Definition chan_dahdi.h:324
char cid_name[AST_MAX_EXTENSION]
Caller ID name from an incoming call.
Definition chan_dahdi.h:541
ast_mutex_t lock
Definition chan_dahdi.h:125
unsigned int inservice
TRUE if channel is out of reset and ready.
Definition chan_dahdi.h:446
char language[MAX_LANGUAGE]
Language configured for calls.
Definition chan_dahdi.h:513
unsigned int digital
TRUE if the transfer capability of the call is digital.
Definition chan_dahdi.h:260
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition chan_dahdi.h:706
unsigned int mwioverride_disposition
Manual MWI disposition (on/off)
Definition chan_dahdi.h:441
struct ast_dsp_busy_pattern busy_cadence
Busy cadence pattern description.
Definition chan_dahdi.h:652
int stripmsd
Number of most significant digits/characters to strip from the dialed number.
Definition chan_dahdi.h:621
unsigned int pulsedial
TRUE if a pulsed digit was detected. (Pulse dial phone detected)
Definition chan_dahdi.h:360
unsigned int calledsubscriberheld
TRUE if Called Subscriber held is enabled. This allows a single incoming call to hold a DAHDI channel...
Definition chan_dahdi.h:213
int muting
TRUE if confrence is muted.
Definition chan_dahdi.h:769
char cid_tag[AST_MAX_EXTENSION]
Caller ID tag from incoming call.
Definition chan_dahdi.h:537
int matchdigit_timeout
Time (ms) to wait, in case of ambiguous match (in an analog phone)
Definition chan_dahdi.h:696
char mohsuggest[MAX_MUSICCLASS]
Suggested music-on-hold class for peer channel to use for calls.
Definition chan_dahdi.h:523
unsigned int use_callerid
TRUE if caller ID is used on this channel.
Definition chan_dahdi.h:394
float rxgain
Software Rx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:160
int polarity
Current line interface polarity. POLARITY_IDLE, POLARITY_REV.
Definition chan_dahdi.h:742
ast_group_t callgroup
Bitmapped call groups this belongs to.
Definition chan_dahdi.h:570
unsigned int dialing
TRUE if in the process of dialing digits or sending something.
Definition chan_dahdi.h:258
unsigned int usefaxbuffers
Definition chan_dahdi.h:276
char callwait_name[AST_MAX_EXTENSION]
Call waiting name.
Definition chan_dahdi.h:549
char mohinterpret[MAX_MUSICCLASS]
The configured music-on-hold class to use for calls.
Definition chan_dahdi.h:518
int dialtone_detect
Number of frames to watch for dialtone in incoming calls.
Definition chan_dahdi.h:675
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition chan_dahdi.h:488
int propconfno
Definition chan_dahdi.h:565
int inconference
Definition chan_dahdi.h:136
int cid_ton
Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise.
Definition chan_dahdi.h:539
unsigned int needanswer
Definition chan_dahdi.h:86
unsigned int needringing
Definition chan_dahdi.h:83
unsigned int linear
Definition chan_dahdi.h:90
unsigned int needhold
Definition chan_dahdi.h:88
unsigned int needunhold
Definition chan_dahdi.h:89
struct ast_frame f
Definition chan_dahdi.h:82
unsigned int inthreeway
Definition chan_dahdi.h:91
struct ast_channel * owner
Definition chan_dahdi.h:79
struct dahdi_confinfo curconf
Definition chan_dahdi.h:92
unsigned int needflash
Definition chan_dahdi.h:87
unsigned int needbusy
Definition chan_dahdi.h:84
short buffer[AST_FRIENDLY_OFFSET/2+READ_SIZE]
Definition chan_dahdi.h:81
unsigned int needcongestion
Definition chan_dahdi.h:85
int ring[3]
Definition chan_dahdi.h:63
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:323
struct dahdi_pvt * pvt
unsigned char buf[READ_SIZE]
mwisend_states mwisend_current
Definition chan_dahdi.h:112
struct timeval pause
Definition chan_dahdi.h:111
Number structure.
struct ast_channel * peer
char contextData[AST_MAX_CONTEXT]
Definition chan_dahdi.h:67
void(*const handle_dchan_exception)(struct sig_pri_span *pri, int index)
Definition sig_pri.h:202
unsigned int immediate
Definition sig_pri.h:282
struct sig_pri_span * pri
Definition sig_pri.h:355
void * chan_pvt
Definition sig_pri.h:374
enum sig_pri_reset_state resetting
Channel reset/restart state.
Definition sig_pri.h:361
unsigned int allocated
TRUE when this channel is allocated.
Definition sig_pri.h:339
unsigned int use_callingpres
Definition sig_pri.h:286
unsigned int priexclusive
Definition sig_pri.h:283
unsigned int hidecallerid
Definition sig_pri.h:280
unsigned int priindication_oob
Definition sig_pri.h:284
unsigned int hidecalleridname
Definition sig_pri.h:281
char context[AST_MAX_CONTEXT]
Definition sig_pri.h:287
unsigned int inalarm
Definition sig_pri.h:324
unsigned int no_b_channel
TRUE if this interface has no B channel. (call hold and call waiting)
Definition sig_pri.h:343
unsigned int use_callerid
Definition sig_pri.h:285
char mohinterpret[MAX_MUSICCLASS]
Definition sig_pri.h:288
q931_call * call
Definition sig_pri.h:356
struct sig_pri_chan * pvts[SIG_PRI_MAX_CHANNELS]
Definition sig_pri.h:614
struct pri * pri
Definition sig_pri.h:602
char idleext[AST_MAX_EXTENSION]
Definition sig_pri.h:550
int switchtype
Definition sig_pri.h:556
int minunused
Definition sig_pri.h:553
int fds[SIG_PRI_NUM_DCHANS]
Definition sig_pri.h:457
int trunkgroup
Definition sig_pri.h:558
pthread_t master
Definition sig_pri.h:615
int congestion_devstate
Congestion device state of the span.
Definition sig_pri.h:627
void * no_b_chan_end
Definition sig_pri.h:612
void * no_b_chan_iflist
Definition sig_pri.h:607
ast_mutex_t lock
Definition sig_pri.h:616
char idledial[AST_MAX_EXTENSION]
Definition sig_pri.h:552
void(*const lock_private)(void *pvt)
Definition sig_ss7.h:157
unsigned int immediate
Definition sig_ss7.h:221
void * chan_pvt
Definition sig_ss7.h:190
unsigned int locallyblocked
Bitmask for the channel being locally blocked.
Definition sig_ss7.h:228
unsigned int dpc
Definition sig_ss7.h:202
unsigned int use_callingpres
TRUE if we will use the calling presentation setting from the Asterisk channel for outgoing calls.
Definition sig_ss7.h:220
struct isup_call * ss7call
Opaque libss7 call control structure.
Definition sig_ss7.h:195
unsigned int remotelyblocked
Bitmask for the channel being remotely blocked.
Definition sig_ss7.h:235
unsigned int hidecallerid
TRUE if the outgoing caller ID is blocked/hidden.
Definition sig_ss7.h:213
struct ast_channel * owner
Definition sig_ss7.h:192
char context[AST_MAX_CONTEXT]
Definition sig_ss7.h:237
unsigned int inalarm
TRUE if channel is associated with a link that is down.
Definition sig_ss7.h:288
unsigned int inservice
TRUE if channel is in service.
Definition sig_ss7.h:290
int stripmsd
Number of most significant digits/characters to strip from the dialed number.
Definition sig_ss7.h:209
unsigned int use_callerid
TRUE if caller ID is used on this channel.
Definition sig_ss7.h:215
char mohinterpret[MAX_MUSICCLASS]
Definition sig_ss7.h:238
int fds[SIG_SS7_NUM_DCHANS]
Definition sig_ss7.h:323
enum sig_ss7_linkset::@152 state
pthread_t master
Definition sig_ss7.h:319
struct ss7 * ss7
Definition sig_ss7.h:321
ast_mutex_t lock
Definition sig_ss7.h:320
struct sig_ss7_chan * pvts[SIG_SS7_MAX_CHANNELS]
Definition sig_ss7.h:322
struct sla_ringing_trunk * next
Definition app_sla.c:314
const char * name
int value
Definition syslog.c:37
TTY/TDD Generation support.
#define TDD_BYTES_PER_CHAR
Definition tdd.h:27
int tdd_generate(struct tdd_state *tdd, unsigned char *buf, const char *string)
Definition tdd.c:296
struct tdd_state * tdd_new(void)
Definition tdd.c:103
void tdd_free(struct tdd_state *tdd)
Definition tdd.c:218
int ast_tdd_gen_ecdisa(unsigned char *outbuf, int len)
Definition tdd.c:148
int tdd_feed(struct tdd_state *tdd, unsigned char *ubuf, int samples)
Definition tdd.c:161
Handy terminal functions for vt* terms.
#define COLOR_MAGENTA
Definition term.h:60
#define COLOR_BLACK
Definition term.h:50
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition term.c:235
#define COLOR_GREEN
Definition term.h:54
static struct test_options options
static struct test_val b
static struct test_val a
static struct test_val c
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2317
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition time.h:235
General Asterisk channel transcoding definitions.
#define IS_DIGITAL(cap)
Definition transcap.h:45
#define AST_TRANS_CAP_DIGITAL
Definition transcap.h:36
u-Law to Signed linear conversion
#define AST_MULAW(a)
Definition ulaw.h:85
#define AST_LIN2MU(a)
Definition ulaw.h:49
FILE * out
Definition utils/frame.c:33
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ast_pthread_create(a, b, c, d)
Definition utils.h:624
#define ast_pthread_create_background(a, b, c, d)
Definition utils.h:632
#define ast_clear_flag(p, flag)
Definition utils.h:78
long int ast_random(void)
Definition utils.c:2348
#define ast_pthread_create_detached(a, b, c, d)
Definition utils.h:628
#define ast_set_flag(p, flag)
Definition utils.h:71
#define ARRAY_LEN(a)
Definition utils.h:706