Asterisk - The Open Source Telephony Project GIT-master-0deac78
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 <info name="CHANNEL" language="en_US" tech="DAHDI">
224 <enumlist>
225 <enum name="dahdi_channel">
226 <para>R/O DAHDI channel related to this channel.</para>
227 </enum>
228 <enum name="dahdi_span">
229 <para>R/O DAHDI span related to this channel.</para>
230 </enum>
231 <enum name="dahdi_group">
232 <para>R/O DAHDI logical group related to this channel.</para>
233 </enum>
234 <enum name="dahdi_type">
235 <para>R/O DAHDI channel type, one of:</para>
236 <enumlist>
237 <enum name="analog" />
238 <enum name="mfc/r2" />
239 <enum name="pri" />
240 <enum name="pseudo" />
241 <enum name="ss7" />
242 </enumlist>
243 </enum>
244 <enum name="keypad_digits">
245 <para>R/O PRI Keypad digits that came in with the SETUP message.</para>
246 </enum>
247 <enum name="reversecharge">
248 <para>R/O PRI Reverse Charging Indication, one of:</para>
249 <enumlist>
250 <enum name="-1"> <para>None</para></enum>
251 <enum name=" 1"> <para>Reverse Charging Requested</para></enum>
252 </enumlist>
253 </enum>
254 <enum name="no_media_path">
255 <para>R/O PRI Nonzero if the channel has no B channel.
256 The channel is either on hold or a call waiting call.</para>
257 </enum>
258 <enum name="buffers">
259 <para>W/O Change the channel's buffer policy (for the current call only)</para>
260 <para>This option takes two arguments:</para>
261 <para> Number of buffers,</para>
262 <para> Buffer policy being one of:</para>
263 <para> <literal>full</literal></para>
264 <para> <literal>immediate</literal></para>
265 <para> <literal>half</literal></para>
266 </enum>
267 <enum name="echocan_mode">
268 <para>W/O Change the configuration of the active echo
269 canceller on the channel (if any), for the current call
270 only.</para>
271 <para>Possible values are:</para>
272 <para> <literal>on</literal> Normal mode (the echo canceller is actually reinitialized)</para>
273 <para> <literal>off</literal> Disabled</para>
274 <para> <literal>fax</literal> FAX/data mode (NLP disabled if possible, otherwise
275 completely disabled)</para>
276 <para> <literal>voice</literal> Voice mode (returns from FAX mode, reverting the changes that were made)</para>
277 </enum>
278 <enum name="dialmode">
279 <para>R/W Pulse and tone dialing mode of the channel.</para>
280 <para>Disabling tone dialing using this option will not automatically disable the DSP used for DTMF detection.
281 To do that, also set the <literal>digitdetect</literal> option. If digit detection is disabled,
282 DTMF will not be detected, regardless of the <literal>dialmode</literal> setting.
283 The <literal>digitdetect</literal> setting has no impact on pulse dialing detection.</para>
284 <para>If set, overrides the setting in <literal>chan_dahdi.conf</literal> for that channel.</para>
285 <para>The <literal>dialmode</literal> setting applies to the DAHDI channel as a whole, but is reset for each call,
286 so modifications made using the <literal>CHANNEL</literal> function apply temporarily per-call.
287 The <literal>digitdetect</literal> setting applies to the entire DAHDI channel,
288 so any changes made to this setting will affect all calls concurrently on the same DAHDI channel.
289 <literal>digitdetect</literal> is reset once all calls on the line have cleared.</para>
290 <enumlist>
291 <enum name="both" />
292 <enum name="pulse" />
293 <enum name="dtmf" />
294 <enum name="tone" />
295 <enum name="none" />
296 </enumlist>
297 </enum>
298 <enum name="waitfordialtone">
299 <para>W/O Duration in ms for which to wait for dial tone on the current call.</para>
300 <para>This setting is will temporarily override the <literal>waitfordialtone</literal>
301 setting in <literal>chan_dahdi.conf</literal> (typically if that setting is disabled).
302 You must call this in a pre-dial handler when making a call on an analog trunk
303 (e.g. FXS-signalled interface).</para>
304 <para>This allows, for example, being able to barge in on an in-use trunk,
305 if dialed specifically, but allows skipping the trunk when routing calls
306 if dial tone is not present on a channel.</para>
307 <para>This setting will only apply to the current (next) call made on the
308 DAHDI channel, and will not persist for future calls.</para>
309 <para>Please keep in mind that due to the way that chan_dahdi implements dial tone detection,
310 DTMF digits on an in-use channel will temporarily relay to any other channels attempting to use the channel for a call.
311 However, voice transmission will not leak.</para>
312 </enum>
313 </enumlist>
314 </info>
315 <info name="Dial_Resource" language="en_US" tech="DAHDI">
316 <para>DAHDI allows several modifiers to be specified as part of the resource.</para>
317 <para>The general syntax is :</para>
318 <para><literal>Dial(DAHDI/pseudo[/extension])</literal></para>
319 <para><literal>Dial(DAHDI/&lt;channel#&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
320 <para><literal>Dial(DAHDI/(g|G|r|R)&lt;group#(0-63)&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
321 <para>The following modifiers may be used before the channel number:</para>
322 <enumlist>
323 <enum name="g">
324 <para>Search forward, dialing on first available channel in group (lowest to highest).</para>
325 </enum>
326 <enum name="G">
327 <para>Search backward, dialing on first available channel in group (highest to lowest).</para>
328 </enum>
329 <enum name="r">
330 <para>Round robin search forward, picking up from where last left off (lowest to highest).</para>
331 </enum>
332 <enum name="R">
333 <para>Round robin search backward, picking up from where last left off (highest to lowest).</para>
334 </enum>
335 </enumlist>
336 <para>The following modifiers may be used after the channel number:</para>
337 <enumlist>
338 <enum name="c">
339 <para>Wait for DTMF digit <literal>#</literal> before providing answer supervision.</para>
340 <para>This can be useful on outbound calls via FXO ports, as otherwise
341 they would indicate answer immediately.</para>
342 </enum>
343 <enum name="d">
344 <para>Force bearer capability for ISDN/SS7 call to digital.</para>
345 </enum>
346 <enum name="i">
347 <para>ISDN span channel restriction.</para>
348 <para>Used by CC to ensure that the CC recall goes out the same span.
349 Also to make ISDN channel names dialable when the sequence number
350 is stripped off. (Used by DTMF attended transfer feature.)</para>
351 </enum>
352 <enum name="r">
353 <para>Specifies the distinctive ring cadence number to use immediately after
354 specifying this option. There are 4 default built-in cadences, and up to 24
355 total cadences may be configured.</para>
356 </enum>
357 </enumlist>
358 <example title="Dial 555-1212 on first available channel in group 1, searching from highest to lowest">
359 same => n,Dial(DAHDI/g1/5551212)
360 </example>
361 <example title="Ringing FXS channel 4 with ring cadence 2">
362 same => n,Dial(DAHDI/4r2)
363 </example>
364 <example title="Dial 555-1212 on channel 3 and require answer confirmation">
365 same => n,Dial(DAHDI/3c/5551212)
366 </example>
367 </info>
368 <manager name="DAHDITransfer" language="en_US">
369 <since>
370 <version>1.4.22</version>
371 </since>
372 <synopsis>
373 Transfer DAHDI Channel.
374 </synopsis>
375 <syntax>
376 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
377 <parameter name="DAHDIChannel" required="true">
378 <para>DAHDI channel number to transfer.</para>
379 </parameter>
380 </syntax>
381 <description>
382 <para>Simulate a flash hook event by the user connected to the channel.</para>
383 <note><para>Valid only for analog channels.</para></note>
384 </description>
385 </manager>
386 <manager name="DAHDIHangup" language="en_US">
387 <since>
388 <version>1.4.22</version>
389 </since>
390 <synopsis>
391 Hangup DAHDI Channel.
392 </synopsis>
393 <syntax>
394 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
395 <parameter name="DAHDIChannel" required="true">
396 <para>DAHDI channel number to hangup.</para>
397 </parameter>
398 </syntax>
399 <description>
400 <para>Simulate an on-hook event by the user connected to the channel.</para>
401 <note><para>Valid only for analog channels.</para></note>
402 </description>
403 </manager>
404 <manager name="DAHDIDialOffhook" language="en_US">
405 <since>
406 <version>1.4.22</version>
407 </since>
408 <synopsis>
409 Dial over DAHDI channel while offhook.
410 </synopsis>
411 <syntax>
412 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
413 <parameter name="DAHDIChannel" required="true">
414 <para>DAHDI channel number to dial digits.</para>
415 </parameter>
416 <parameter name="Number" required="true">
417 <para>Digits to dial.</para>
418 </parameter>
419 </syntax>
420 <description>
421 <para>Generate DTMF control frames to the bridged peer.</para>
422 </description>
423 </manager>
424 <manager name="DAHDIDNDon" language="en_US">
425 <since>
426 <version>1.4.22</version>
427 </since>
428 <synopsis>
429 Toggle DAHDI channel Do Not Disturb status ON.
430 </synopsis>
431 <syntax>
432 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
433 <parameter name="DAHDIChannel" required="true">
434 <para>DAHDI channel number to set DND on.</para>
435 </parameter>
436 </syntax>
437 <description>
438 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> on".</para>
439 <note><para>Feature only supported by analog channels.</para></note>
440 </description>
441 </manager>
442 <manager name="DAHDIDNDoff" language="en_US">
443 <since>
444 <version>1.4.22</version>
445 </since>
446 <synopsis>
447 Toggle DAHDI channel Do Not Disturb status OFF.
448 </synopsis>
449 <syntax>
450 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
451 <parameter name="DAHDIChannel" required="true">
452 <para>DAHDI channel number to set DND off.</para>
453 </parameter>
454 </syntax>
455 <description>
456 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> off".</para>
457 <note><para>Feature only supported by analog channels.</para></note>
458 </description>
459 </manager>
460 <manager name="DAHDIShowChannels" language="en_US">
461 <since>
462 <version>1.4.22</version>
463 </since>
464 <synopsis>
465 Show status of DAHDI channels.
466 </synopsis>
467 <syntax>
468 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
469 <parameter name="DAHDIChannel">
470 <para>Specify the specific channel number to show. Show all channels if zero or not present.</para>
471 </parameter>
472 </syntax>
473 <description>
474 <para>Similar to the CLI command "dahdi show channels".</para>
475 </description>
476 </manager>
477 <manager name="DAHDIShowStatus" language="en_US">
478 <since>
479 <version>21.3.0</version>
480 <version>20.8.0</version>
481 <version>18.23.0</version>
482 </since>
483 <synopsis>
484 Show status of DAHDI spans.
485 </synopsis>
486 <syntax/>
487 <description>
488 <para>Similar to the CLI command "dahdi show status".</para>
489 </description>
490 </manager>
491 <manager name="DAHDIRestart" language="en_US">
492 <since>
493 <version>1.4.22</version>
494 </since>
495 <synopsis>
496 Fully Restart DAHDI channels (terminates calls).
497 </synopsis>
498 <syntax>
499 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
500 </syntax>
501 <description>
502 <para>Equivalent to the CLI command "dahdi restart".</para>
503 </description>
504 </manager>
505 <manager name="PRIShowSpans" language="en_US">
506 <since>
507 <version>10.0.0</version>
508 </since>
509 <synopsis>
510 Show status of PRI spans.
511 </synopsis>
512 <syntax>
513 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
514 <parameter name="Span">
515 <para>Specify the specific span to show. Show all spans if zero or not present.</para>
516 </parameter>
517 </syntax>
518 <description>
519 <para>Similar to the CLI command "pri show spans".</para>
520 </description>
521 </manager>
522 <manager name="PRIDebugSet" language="en_US">
523 <since>
524 <version>13.0.0</version>
525 </since>
526 <synopsis>
527 Set PRI debug levels for a span
528 </synopsis>
529 <syntax>
530 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
531 <parameter name="Span" required="true">
532 <para>Which span to affect.</para>
533 </parameter>
534 <parameter name="Level" required="true">
535 <para>What debug level to set. May be a numerical value or a text value from the list below</para>
536 <enumlist>
537 <enum name="off" />
538 <enum name="on" />
539 <enum name="hex" />
540 <enum name="intense" />
541 </enumlist>
542 </parameter>
543 </syntax>
544 <description>
545 <para>Equivalent to the CLI command "pri set debug &lt;level&gt; span &lt;span&gt;".</para>
546 </description>
547 </manager>
548 <manager name="PRIDebugFileSet" language="en_US">
549 <since>
550 <version>13.0.0</version>
551 </since>
552 <synopsis>
553 Set the file used for PRI debug message output
554 </synopsis>
555 <syntax>
556 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
557 <parameter name="File" required="true">
558 <para>Path of file to write debug output.</para>
559 </parameter>
560 </syntax>
561 <description>
562 <para>Equivalent to the CLI command "pri set debug file &lt;output-file&gt;"</para>
563 </description>
564 </manager>
565 <manager name="PRIDebugFileUnset" language="en_US">
566 <since>
567 <version>13.0.0</version>
568 </since>
569 <synopsis>
570 Disables file output for PRI debug messages
571 </synopsis>
572 <syntax>
573 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
574 </syntax>
575 </manager>
576 <managerEvent language="en_US" name="AlarmClear">
577 <managerEventInstance class="EVENT_FLAG_SYSTEM">
578 <since>
579 <version>12.0.0</version>
580 </since>
581 <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
582 <syntax>
583 <parameter name="DAHDIChannel">
584 <para>The DAHDI channel on which the alarm was cleared.</para>
585 <note><para>This is not an Asterisk channel identifier.</para></note>
586 </parameter>
587 </syntax>
588 </managerEventInstance>
589 </managerEvent>
590 <managerEvent language="en_US" name="SpanAlarmClear">
591 <managerEventInstance class="EVENT_FLAG_SYSTEM">
592 <since>
593 <version>12.0.0</version>
594 </since>
595 <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
596 <syntax>
597 <parameter name="Span">
598 <para>The span on which the alarm was cleared.</para>
599 </parameter>
600 </syntax>
601 </managerEventInstance>
602 </managerEvent>
603 <managerEvent language="en_US" name="DNDState">
604 <managerEventInstance class="EVENT_FLAG_SYSTEM">
605 <since>
606 <version>12.0.0</version>
607 </since>
608 <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
609 <syntax>
610 <parameter name="DAHDIChannel">
611 <para>The DAHDI channel on which DND status changed.</para>
612 <note><para>This is not an Asterisk channel identifier.</para></note>
613 </parameter>
614 <parameter name="Status">
615 <enumlist>
616 <enum name="enabled"/>
617 <enum name="disabled"/>
618 </enumlist>
619 </parameter>
620 </syntax>
621 </managerEventInstance>
622 </managerEvent>
623 <managerEvent language="en_US" name="Alarm">
624 <managerEventInstance class="EVENT_FLAG_SYSTEM">
625 <since>
626 <version>12.0.0</version>
627 </since>
628 <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
629 <syntax>
630 <parameter name="DAHDIChannel">
631 <para>The channel on which the alarm occurred.</para>
632 <note><para>This is not an Asterisk channel identifier.</para></note>
633 </parameter>
634 <parameter name="Alarm">
635 <para>A textual description of the alarm that occurred.</para>
636 </parameter>
637 </syntax>
638 </managerEventInstance>
639 </managerEvent>
640 <managerEvent language="en_US" name="SpanAlarm">
641 <managerEventInstance class="EVENT_FLAG_SYSTEM">
642 <since>
643 <version>12.0.0</version>
644 </since>
645 <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
646 <syntax>
647 <parameter name="Span">
648 <para>The span on which the alarm occurred.</para>
649 </parameter>
650 <parameter name="Alarm">
651 <para>A textual description of the alarm that occurred.</para>
652 </parameter>
653 </syntax>
654 </managerEventInstance>
655 </managerEvent>
656 <managerEvent language="en_US" name="DAHDIChannel">
657 <managerEventInstance class="EVENT_FLAG_CALL">
658 <since>
659 <version>12.0.0</version>
660 </since>
661 <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
662 <syntax>
663 <channel_snapshot/>
664 <parameter name="DAHDIGroup">
665 <para>The DAHDI logical group associated with this channel.</para>
666 </parameter>
667 <parameter name="DAHDISpan">
668 <para>The DAHDI span associated with this channel.</para>
669 </parameter>
670 <parameter name="DAHDIChannel">
671 <para>The DAHDI channel associated with this channel.</para>
672 </parameter>
673 </syntax>
674 </managerEventInstance>
675 </managerEvent>
676 ***/
677
678#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
679
680static const char * const lbostr[] = {
681"0 db (CSU)/0-133 feet (DSX-1)",
682"133-266 feet (DSX-1)",
683"266-399 feet (DSX-1)",
684"399-533 feet (DSX-1)",
685"533-655 feet (DSX-1)",
686"-7.5db (CSU)",
687"-15db (CSU)",
688"-22.5db (CSU)"
689};
690
691/*! Global jitterbuffer configuration - by default, jb is disabled
692 * \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
694{
695 .flags = 0,
696 .max_size = 200,
697 .resync_threshold = 1000,
698 .impl = "fixed",
699 .target_extra = 40,
700};
702
703/*!
704 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
705 * the user hangs up to reset the state machine so ring works properly.
706 * This is used to be able to support kewlstart by putting the zhone in
707 * groundstart mode since their forward disconnect supervision is entirely
708 * broken even though their documentation says it isn't and their support
709 * is entirely unwilling to provide any assistance with their channel banks
710 * even though their web site says they support their products for life.
711 */
712/* #define ZHONE_HACK */
713
714/*! \brief Typically, how many rings before we should send Caller*ID */
715#define DEFAULT_CIDRINGS 1
716
717#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
718
719
720/*! \brief Signaling types that need to use MF detection should be placed in this macro */
721#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))
722
723static const char tdesc[] = "DAHDI Telephony"
724#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
725 " w/"
726 #if defined(HAVE_PRI)
727 "PRI"
728 #endif /* defined(HAVE_PRI) */
729 #if defined(HAVE_SS7)
730 #if defined(HAVE_PRI)
731 " & "
732 #endif /* defined(HAVE_PRI) */
733 "SS7"
734 #endif /* defined(HAVE_SS7) */
735 #if defined(HAVE_OPENR2)
736 #if defined(HAVE_PRI) || defined(HAVE_SS7)
737 " & "
738 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
739 "MFC/R2"
740 #endif /* defined(HAVE_OPENR2) */
741#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2) */
742;
743
744static const char config[] = "chan_dahdi.conf";
745
746#ifdef LOTS_OF_SPANS
747#define NUM_SPANS DAHDI_MAX_SPANS
748#else
749#define NUM_SPANS 32
750#endif
751
752#define CHAN_PSEUDO -2
753
754#define CALLPROGRESS_PROGRESS 1
755#define CALLPROGRESS_FAX_OUTGOING 2
756#define CALLPROGRESS_FAX_INCOMING 4
757#define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
758
759#define NUM_CADENCE_MAX 25
760static int num_cadence = 4;
762
763static int has_pseudo;
764
765static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
766 { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
767 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
768 { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
769 { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
770};
771
772/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
773 * is 1, the second pause is 2 and so on.
774 */
775
777 2, /*!< Right after first long ring */
778 4, /*!< Right after long part */
779 3, /*!< After third chirp */
780 2, /*!< Second spell */
781};
782
783/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
784static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
785
786#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
787 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
788
789#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
790#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
791
792static char defaultcic[64] = "";
793static char defaultozz[64] = "";
794
795/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
796static char mwimonitornotify[PATH_MAX] = "";
797#ifndef HAVE_DAHDI_LINEREVERSE_VMWI
798static int mwisend_rpas = 0;
799#endif
800
801static char progzone[10] = "";
802
805
806static int numbufs = 4;
807
808static int mwilevel = 512;
809static int dtmfcid_level = 256;
810
811#define REPORT_CHANNEL_ALARMS 1
812#define REPORT_SPAN_ALARMS 2
814
815#ifdef HAVE_PRI
816static int pridebugfd = -1;
817static char pridebugfilename[1024] = "";
818#endif
819
820/*! \brief Protect the interface list (of dahdi_pvt's) */
822
823
824static int ifcount = 0;
825
826#ifdef HAVE_PRI
827AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
828#endif
829
830/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
831 when it's doing something critical. */
833
834/*! \brief This is the thread for the monitor which checks for input on the channels
835 which are not currently in use. */
840static int ss_thread_count = 0;
841static int num_restart_pending = 0;
842
843static int restart_monitor(void);
844
845static int dahdi_sendtext(struct ast_channel *c, const char *text);
846
847/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
848static inline int dahdi_get_event(int fd)
849{
850 int j;
851 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
852 return -1;
853 return j;
854}
855
856/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
857static inline int dahdi_wait_event(int fd)
858{
859 int i, j = 0;
860 i = DAHDI_IOMUX_SIGEVENT;
861 if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
862 return -1;
863 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
864 return -1;
865 return j;
866}
867
868/*! Chunk size to read -- we use 20ms chunks to make things happy. */
869#define READ_SIZE 160
870
871#define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
872#define MASK_INUSE (1 << 1) /*!< Channel currently in use */
873
874#define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE) /*!< 300 ms */
875#define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
876#define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE) /*!< 100 ms */
877#define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE) /*!< 500 ms */
878#define MIN_MS_SINCE_FLASH ((2000) ) /*!< 2000 ms */
879#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
880#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
881
882/*!
883 * \brief Configured ring timeout base.
884 * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
885 */
887
888#if defined(HAVE_SS7)
889
890struct dahdi_ss7 {
891 struct sig_ss7_linkset ss7;
892};
893
894static struct dahdi_ss7 linksets[NUM_SPANS];
895
896static int cur_ss7type = -1;
897static int cur_slc = -1;
898static int cur_linkset = -1;
899static int cur_pointcode = -1;
900static int cur_cicbeginswith = -1;
901static int cur_adjpointcode = -1;
902static int cur_networkindicator = -1;
903static int cur_defaultdpc = -1;
904#endif /* defined(HAVE_SS7) */
905
906#ifdef HAVE_OPENR2
907struct dahdi_mfcr2_conf {
908 openr2_variant_t variant;
909 int mfback_timeout;
910 int metering_pulse_timeout;
911 int max_ani;
912 int max_dnis;
913#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
914 int dtmf_time_on;
915 int dtmf_time_off;
916#endif
917#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
918 int dtmf_end_timeout;
919#endif
920 signed int get_ani_first:2;
921#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
922 signed int skip_category_request:2;
923#endif
924 unsigned int call_files:1;
925 unsigned int allow_collect_calls:1;
926 unsigned int charge_calls:1;
927 unsigned int accept_on_offer:1;
928 unsigned int forced_release:1;
929 unsigned int double_answer:1;
930 signed int immediate_accept:2;
931#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
932 signed int dtmf_dialing:2;
933 signed int dtmf_detection:2;
934#endif
935 char logdir[OR2_MAX_PATH];
936 char r2proto_file[OR2_MAX_PATH];
937 openr2_log_level_t loglevel;
938 openr2_calling_party_category_t category;
939};
940
941/* MFC-R2 pseudo-link structure */
942struct dahdi_mfcr2 {
943 int index; /*!< Unique index for CLI */
944 pthread_t r2master; /*!< Thread of master */
945 openr2_context_t *protocol_context; /*!< OpenR2 context handle */
946 struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
947 int numchans; /*!< Number of channels in this R2 block */
948 int live_chans; /*!< Number of unremoved channels in this R2 block */
949 int nodev; /*!< Link disconnected? */
950 struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
951};
952
953struct r2link_entry {
954 struct dahdi_mfcr2 mfcr2;
955 AST_LIST_ENTRY(r2link_entry) list;
956};
957static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
958static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
959
960
961/* how many r2links have been malloc'd */
962static int r2links_count = 0;
963
964#endif /* HAVE_OPENR2 */
965
966#ifdef HAVE_PRI
967
968struct dahdi_pri {
969 int dchannels[SIG_PRI_NUM_DCHANS]; /*!< What channel are the dchannels on */
970 int mastertrunkgroup; /*!< What trunk group is our master */
971 int prilogicalspan; /*!< Logical span number within trunk group */
972 struct sig_pri_span pri;
973};
974
975static struct dahdi_pri pris[NUM_SPANS];
976
977#if defined(HAVE_PRI_CCSS)
978/*! DAHDI PRI CCSS agent and monitor type name. */
979static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
980#endif /* defined(HAVE_PRI_CCSS) */
981
982#else
983/*! Shut up the compiler */
984struct dahdi_pri;
985#endif
986
987/* Polarity states */
988#define POLARITY_IDLE 0
989#define POLARITY_REV 1
990
991const char * const subnames[] = {
992 "Real",
993 "Callwait",
994 "Threeway"
995};
996
997static struct dahdi_pvt *iflist = NULL; /*!< Main interface list start */
998static struct dahdi_pvt *ifend = NULL; /*!< Main interface list end */
999
1000#if defined(HAVE_PRI)
1001struct doomed_pri {
1002 struct sig_pri_span *pri;
1003 AST_LIST_ENTRY(doomed_pri) list;
1004};
1005static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);
1006
1007static void pri_destroy_span(struct sig_pri_span *pri);
1008
1009static struct dahdi_parms_pseudo {
1010 int buf_no; /*!< Number of buffers */
1011 int buf_policy; /*!< Buffer policy */
1012 int faxbuf_no; /*!< Number of Fax buffers */
1013 int faxbuf_policy; /*!< Fax buffer policy */
1014} dahdi_pseudo_parms;
1015#endif /* defined(HAVE_PRI) */
1016
1017/*! \brief Channel configuration from chan_dahdi.conf .
1018 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
1019 * Generally there is a field here for every possible configuration item.
1020 *
1021 * The state of fields is saved along the parsing and whenever a 'channel'
1022 * statement is reached, the current dahdi_chan_conf is used to configure the
1023 * channel (struct dahdi_pvt)
1024 *
1025 * \see dahdi_chan_init for the default values.
1026 */
1029#ifdef HAVE_PRI
1030 struct dahdi_pri pri;
1031#endif
1032
1033#if defined(HAVE_SS7)
1034 struct dahdi_ss7 ss7;
1035#endif /* defined(HAVE_SS7) */
1036
1037#ifdef HAVE_OPENR2
1038 struct dahdi_mfcr2_conf mfcr2;
1039#endif
1040 struct dahdi_params timing;
1041 int is_sig_auto; /*!< Use channel signalling from DAHDI? */
1042 /*! Continue configuration even if a channel is not there. */
1044
1045 /*!
1046 * \brief The serial port to listen for SMDI data on
1047 * \note Set from the "smdiport" string read in from chan_dahdi.conf
1048 */
1050
1051 /*!
1052 * \brief Don't create channels below this number
1053 * \note by default is 0 (no limit)
1054 */
1056
1057 /*!
1058 * \brief Don't create channels above this number (infinity by default)
1059 * \note by default is 0 (special value that means "no limit").
1060 */
1062};
1063
1064/*! returns a new dahdi_chan_conf with default values (by-value) */
1066{
1067 /* recall that if a field is not included here it is initialized
1068 * to 0 or equivalent
1069 */
1070 struct dahdi_chan_conf conf = {
1071#ifdef HAVE_PRI
1072 .pri.pri = {
1073 .nsf = PRI_NSF_NONE,
1074 .switchtype = PRI_SWITCH_NI2,
1075 .dialplan = PRI_UNKNOWN + 1,
1076 .localdialplan = PRI_NATIONAL_ISDN + 1,
1077 .nodetype = PRI_CPE,
1078 .qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
1079
1080#if defined(HAVE_PRI_CCSS)
1081 .cc_ptmp_recall_mode = 1,/* specificRecall */
1082 .cc_qsig_signaling_link_req = 1,/* retain */
1083 .cc_qsig_signaling_link_rsp = 1,/* retain */
1084#endif /* defined(HAVE_PRI_CCSS) */
1085
1086 .minunused = 2,
1087 .idleext = "",
1088 .idledial = "",
1089 .internationalprefix = "",
1090 .nationalprefix = "",
1091 .localprefix = "",
1092 .privateprefix = "",
1093 .unknownprefix = "",
1094 .colp_send = SIG_PRI_COLP_UPDATE,
1095 .resetinterval = -1,
1096 },
1097#endif
1098#if defined(HAVE_SS7)
1099 .ss7.ss7 = {
1100 .called_nai = SS7_NAI_NATIONAL,
1101 .calling_nai = SS7_NAI_NATIONAL,
1102 .internationalprefix = "",
1103 .nationalprefix = "",
1104 .subscriberprefix = "",
1105 .unknownprefix = "",
1106 .networkroutedprefix = ""
1107 },
1108#endif /* defined(HAVE_SS7) */
1109#ifdef HAVE_OPENR2
1110 .mfcr2 = {
1111 .variant = OR2_VAR_ITU,
1112 .mfback_timeout = -1,
1113 .metering_pulse_timeout = -1,
1114 .max_ani = 10,
1115 .max_dnis = 4,
1116 .get_ani_first = -1,
1117#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
1118 .skip_category_request = -1,
1119#endif
1120 .call_files = 0,
1121 .allow_collect_calls = 0,
1122 .charge_calls = 1,
1123 .accept_on_offer = 1,
1124 .forced_release = 0,
1125 .double_answer = 0,
1126 .immediate_accept = -1,
1127#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
1128 .dtmf_dialing = -1,
1129 .dtmf_detection = -1,
1130 .dtmf_time_on = OR2_DEFAULT_DTMF_ON,
1131 .dtmf_time_off = OR2_DEFAULT_DTMF_OFF,
1132#endif
1133#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
1134 .dtmf_end_timeout = -1,
1135#endif
1136 .logdir = "",
1137 .r2proto_file = "",
1138 .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
1139 .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
1140 },
1141#endif
1142 .chan = {
1143 .context = "default",
1144 .immediatering = 1,
1145 .cid_num = "",
1146 .cid_name = "",
1147 .cid_tag = "",
1148 .mohinterpret = "default",
1149 .mohsuggest = "",
1150 .parkinglot = "",
1151 .transfertobusy = 1,
1152 .permdialmode = ANALOG_DIALMODE_BOTH,
1153
1154 .ani_info_digits = 2,
1155 .ani_wink_time = 1000,
1156 .ani_timeout = 10000,
1157
1158 .cid_signalling = CID_SIG_BELL,
1159 .cid_start = CID_START_RING,
1160 .dahditrcallerid = 0,
1161 .use_callerid = 1,
1162 .sig = -1,
1163 .outsigmod = -1,
1164
1165 .cid_rxgain = +5.0,
1166
1167 .tonezone = -1,
1168
1169 .echocancel.head.tap_length = 1,
1170
1171 .busycount = 3,
1172
1173 .accountcode = "",
1174
1175 .mailbox = "",
1176
1177#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
1178 .mwisend_fsk = 1,
1179#endif
1180 .polarityonanswerdelay = 600,
1181
1182 .sendcalleridafter = DEFAULT_CIDRINGS,
1183
1184 .buf_policy = DAHDI_POLICY_IMMEDIATE,
1185 .buf_no = numbufs,
1186 .usefaxbuffers = 0,
1187 .cc_params = ast_cc_config_params_init(),
1188 .firstdigit_timeout = ANALOG_FIRST_DIGIT_TIMEOUT,
1189 .interdigit_timeout = ANALOG_INTER_DIGIT_TIMEOUT,
1190 .matchdigit_timeout = ANALOG_MATCH_DIGIT_TIMEOUT,
1191 },
1192 .timing = {
1193 .prewinktime = -1,
1194 .preflashtime = -1,
1195 .winktime = -1,
1196 .flashtime = -1,
1197 .starttime = -1,
1198 .rxwinktime = -1,
1199 .rxflashtime = -1,
1200 .debouncetime = -1
1201 },
1202 .is_sig_auto = 1,
1203 .ignore_failed_channels = 1,
1204 .smdi_port = "/dev/ttyS0",
1205 };
1206
1207 return conf;
1208}
1209
1210
1211static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
1212 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
1213 const char *data, int *cause);
1214static int dahdi_digit_begin(struct ast_channel *ast, char digit);
1215static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
1216static int dahdi_sendtext(struct ast_channel *c, const char *text);
1217static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout);
1218static int dahdi_hangup(struct ast_channel *ast);
1219static int dahdi_answer(struct ast_channel *ast);
1220static struct ast_frame *dahdi_read(struct ast_channel *ast);
1221static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
1222static struct ast_frame *dahdi_exception(struct ast_channel *ast);
1223static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
1224static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1225static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
1226static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
1227static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
1228static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
1229static int dahdi_devicestate(const char *data);
1230static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
1231
1233 .type = "DAHDI",
1234 .description = tdesc,
1235 .requester = dahdi_request,
1236 .send_digit_begin = dahdi_digit_begin,
1237 .send_digit_end = dahdi_digit_end,
1238 .send_text = dahdi_sendtext,
1239 .call = dahdi_call,
1240 .hangup = dahdi_hangup,
1241 .answer = dahdi_answer,
1242 .read = dahdi_read,
1243 .write = dahdi_write,
1244 .exception = dahdi_exception,
1245 .indicate = dahdi_indicate,
1246 .fixup = dahdi_fixup,
1247 .setoption = dahdi_setoption,
1248 .queryoption = dahdi_queryoption,
1249 .func_channel_read = dahdi_func_read,
1250 .func_channel_write = dahdi_func_write,
1251 .devicestate = dahdi_devicestate,
1252 .cc_callback = dahdi_cc_callback,
1253};
1254
1255#define GET_CHANNEL(p) ((p)->channel)
1256
1258{
1259 switch (sig) {
1260 case SIG_FXOLS:
1261 return ANALOG_SIG_FXOLS;
1262 case SIG_FXOGS:
1263 return ANALOG_SIG_FXOGS;
1264 case SIG_FXOKS:
1265 return ANALOG_SIG_FXOKS;
1266 case SIG_FXSLS:
1267 return ANALOG_SIG_FXSLS;
1268 case SIG_FXSGS:
1269 return ANALOG_SIG_FXSGS;
1270 case SIG_FXSKS:
1271 return ANALOG_SIG_FXSKS;
1272 case SIG_EMWINK:
1273 return ANALOG_SIG_EMWINK;
1274 case SIG_EM:
1275 return ANALOG_SIG_EM;
1276 case SIG_EM_E1:
1277 return ANALOG_SIG_EM_E1;
1278 case SIG_FEATD:
1279 return ANALOG_SIG_FEATD;
1280 case SIG_FEATDMF:
1281 return ANALOG_SIG_FEATDMF;
1282 case SIG_E911:
1283 return SIG_E911;
1284 case SIG_FGC_CAMA:
1285 return ANALOG_SIG_FGC_CAMA;
1286 case SIG_FGC_CAMAMF:
1287 return ANALOG_SIG_FGC_CAMAMF;
1288 case SIG_FEATB:
1289 return ANALOG_SIG_FEATB;
1290 case SIG_SFWINK:
1291 return ANALOG_SIG_SFWINK;
1292 case SIG_SF:
1293 return ANALOG_SIG_SF;
1294 case SIG_SF_FEATD:
1295 return ANALOG_SIG_SF_FEATD;
1296 case SIG_SF_FEATDMF:
1297 return ANALOG_SIG_SF_FEATDMF;
1298 case SIG_FEATDMF_TA:
1299 return ANALOG_SIG_FEATDMF_TA;
1300 case SIG_SF_FEATB:
1301 return ANALOG_SIG_FEATB;
1302 default:
1303 return -1;
1304 }
1305}
1306
1307
1309{
1310 switch (tone) {
1312 return DAHDI_TONE_RINGTONE;
1314 return DAHDI_TONE_STUTTER;
1316 return DAHDI_TONE_CONGESTION;
1318 return DAHDI_TONE_DIALTONE;
1320 return DAHDI_TONE_DIALRECALL;
1321 case ANALOG_TONE_INFO:
1322 return DAHDI_TONE_INFO;
1323 default:
1324 return -1;
1325 }
1326}
1327
1328static int analogsub_to_dahdisub(enum analog_sub analogsub)
1329{
1330 int index;
1331
1332 switch (analogsub) {
1333 case ANALOG_SUB_REAL:
1334 index = SUB_REAL;
1335 break;
1337 index = SUB_CALLWAIT;
1338 break;
1340 index = SUB_THREEWAY;
1341 break;
1342 default:
1343 ast_log(LOG_ERROR, "Unidentified sub!\n");
1344 index = SUB_REAL;
1345 }
1346
1347 return index;
1348}
1349
1350/*!
1351 * \internal
1352 * \brief release all members on the doomed pris list
1353 * \since 13.0
1354 *
1355 * Called periodically by the monitor threads to release spans marked for
1356 * removal.
1357 */
1358static void release_doomed_pris(void)
1359{
1360#ifdef HAVE_PRI
1361 struct doomed_pri *entry;
1362
1363 AST_LIST_LOCK(&doomed_pris);
1364 while ((entry = AST_LIST_REMOVE_HEAD(&doomed_pris, list))) {
1365 /* The span destruction must be done with this lock not held */
1366 AST_LIST_UNLOCK(&doomed_pris);
1367 ast_debug(4, "Destroying span %d from doomed queue.\n",
1368 entry->pri->span);
1369 pri_destroy_span(entry->pri);
1370 ast_free(entry);
1371 AST_LIST_LOCK(&doomed_pris);
1372 }
1373 AST_LIST_UNLOCK(&doomed_pris);
1374#endif
1375}
1376
1377#ifdef HAVE_PRI
1378/*!
1379 * \brief Queue a span for destruction
1380 * \since 13.0
1381 *
1382 * \param pri the span to destroy
1383 *
1384 * Add a span to the list of spans to be destroyed later on
1385 * by the monitor thread. Allows destroying a span while holding its
1386 * lock.
1387 */
1388static void pri_queue_for_destruction(struct sig_pri_span *pri)
1389{
1390 struct doomed_pri *entry;
1391
1392 AST_LIST_LOCK(&doomed_pris);
1393 AST_LIST_TRAVERSE(&doomed_pris, entry, list) {
1394 if (entry->pri == pri) {
1395 AST_LIST_UNLOCK(&doomed_pris);
1396 return;
1397 }
1398 }
1399 entry = ast_calloc(sizeof(struct doomed_pri), 1);
1400 if (!entry) {
1401 /* Nothing useful to do here. Panic? */
1402 ast_log(LOG_WARNING, "Failed allocating memory for a doomed_pri.\n");
1403 AST_LIST_UNLOCK(&doomed_pris);
1404 return;
1405 }
1406 entry->pri = pri;
1407 ast_debug(4, "Queue span %d for destruction.\n", pri->span);
1408 AST_LIST_INSERT_TAIL(&doomed_pris, entry, list);
1409 AST_LIST_UNLOCK(&doomed_pris);
1410}
1411#endif
1412
1413/*!
1414 * \internal
1415 * \brief Send a dial string to DAHDI.
1416 * \since 12.0.0
1417 *
1418 * \param pvt DAHDI private pointer
1419 * \param operation DAHDI dial operation to do to string
1420 * \param dial_str Dial string to send
1421 *
1422 * \retval 0 on success.
1423 * \retval non-zero on error.
1424 */
1425static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
1426{
1427 int res;
1428 int offset;
1429 const char *pos;
1430 struct dahdi_dialoperation zo = {
1431 .op = operation,
1432 };
1433
1434 /* Convert the W's to ww. */
1435 pos = dial_str;
1436 for (offset = 0; offset < sizeof(zo.dialstr) - 1; ++offset) {
1437 if (!*pos) {
1438 break;
1439 }
1440 if (*pos == 'W') {
1441 /* Convert 'W' to "ww" */
1442 ++pos;
1443 if (offset >= sizeof(zo.dialstr) - 3) {
1444 /* No room to expand */
1445 break;
1446 }
1447 zo.dialstr[offset] = 'w';
1448 ++offset;
1449 zo.dialstr[offset] = 'w';
1450 continue;
1451 }
1452 zo.dialstr[offset] = *pos++;
1453 }
1454 /* The zo initialization has already terminated the dialstr. */
1455
1456 ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
1457 pvt->channel, dial_str, zo.dialstr);
1458 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
1459 if (res) {
1460 ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
1461 pvt->channel, dial_str, strerror(errno));
1462 }
1463
1464 return res;
1465}
1466
1468static int bump_gains(struct dahdi_pvt *p);
1469static int dahdi_setlinear(int dfd, int linear);
1470
1471static int my_start_cid_detect(void *pvt, int cid_signalling)
1472{
1473 struct dahdi_pvt *p = pvt;
1474 int index = SUB_REAL;
1476 if (!p->cs) {
1477 ast_log(LOG_ERROR, "Unable to alloc callerid\n");
1478 return -1;
1479 }
1480 bump_gains(p);
1481 dahdi_setlinear(p->subs[index].dfd, 0);
1482
1483 return 0;
1484}
1485
1486static int restore_gains(struct dahdi_pvt *p);
1487
1488static int my_stop_cid_detect(void *pvt)
1489{
1490 struct dahdi_pvt *p = pvt;
1491 int index = SUB_REAL;
1492
1493 if (p->cs) {
1494 callerid_free(p->cs);
1495 }
1496
1497 /* Restore linear mode after Caller*ID processing */
1498 dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
1499 restore_gains(p);
1500
1501 return 0;
1502}
1503
1504static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
1505{
1506 struct dahdi_pvt *p = pvt;
1507 struct analog_pvt *analog_p = p->sig_pvt;
1508 struct pollfd poller;
1509 char *name, *num;
1510 int index = SUB_REAL;
1511 int res;
1512 unsigned char buf[256];
1513 int flags;
1514 int redirecting;
1515
1516 poller.fd = p->subs[SUB_REAL].dfd;
1517 poller.events = POLLPRI | POLLIN;
1518 poller.revents = 0;
1519
1520 res = poll(&poller, 1, timeout);
1521
1522 if (poller.revents & POLLPRI) {
1524 return 1;
1525 }
1526
1527 if (poller.revents & POLLIN) {
1528 /*** NOTES ***/
1529 /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
1530 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
1531 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
1532 * a failure and die, and returning 2 means no event was received. */
1533 res = read(p->subs[index].dfd, buf, sizeof(buf));
1534 if (res < 0) {
1535 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1536 return -1;
1537 }
1538
1539 if (analog_p->ringt > 0) {
1540 if (!(--analog_p->ringt)) {
1541 /* only return if we timeout from a ring event */
1542 return -1;
1543 }
1544 }
1545
1546 if (p->cid_signalling == CID_SIG_V23_JP) {
1547 res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
1548 } else {
1549 res = callerid_feed(p->cs, buf, res, AST_LAW(p));
1550 }
1551 if (res < 0) {
1552 /*
1553 * The previous diagnostic message output likely
1554 * explains why it failed.
1555 */
1556 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
1557 return -1;
1558 }
1559
1560 if (res == 1) {
1561 struct ast_channel *chan = analog_p->ss_astchan;
1563 if (name)
1565 if (num)
1566 ast_copy_string(numbuf, num, ANALOG_MAX_CID);
1567
1569 /* If we got a presentation, we must set it on the channel */
1570 struct ast_party_caller caller;
1571
1573 caller.id.name.presentation = caller.id.number.presentation = (flags & CID_PRIVATE_NUMBER) ?
1576 ast_party_caller_free(&caller);
1577 }
1578 if (redirecting) {
1579 /* There is a redirecting reason available in the Caller*ID received.
1580 * No idea what the redirecting number is, since the Caller*ID protocol
1581 * has no parameter for that, but at least we know WHY it was redirected. */
1582 ast_channel_redirecting(chan)->reason.code = redirecting;
1583 }
1584
1585 if (flags & CID_QUALIFIER) {
1586 /* This is the inverse of how the qualifier is set in sig_analog */
1587 pbx_builtin_setvar_helper(chan, "CALL_QUALIFIER", "1");
1588 }
1589
1590 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));
1591 return 0;
1592 }
1593 }
1594
1595 *ev = ANALOG_EVENT_NONE;
1596 return 2;
1597}
1598
1599static const char *event2str(int event);
1600
1601static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
1602{
1603 unsigned char buf[256];
1604 int distMatches;
1605 int curRingData[RING_PATTERNS];
1606 int receivedRingT;
1607 int counter1;
1608 int counter;
1609 int i;
1610 int res;
1611 int checkaftercid = 0;
1612 const char *matched_context;
1613 struct dahdi_pvt *p = pvt;
1614 struct analog_pvt *analog_p = p->sig_pvt;
1615
1616 if (ringdata == NULL) {
1617 ringdata = curRingData;
1618 } else {
1619 checkaftercid = 1;
1620 }
1621
1622 /* We must have a ring by now so lets try to listen for distinctive ringing */
1623 if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
1624 /* Clear the current ring data array so we don't have old data in it. */
1625 for (receivedRingT = 0; receivedRingT < RING_PATTERNS; receivedRingT++)
1626 ringdata[receivedRingT] = 0;
1627 receivedRingT = 0;
1628
1629 if (checkaftercid && distinctiveringaftercid) {
1630 ast_verb(3, "Detecting post-CID distinctive ring\n");
1631 }
1632
1633 for (;;) {
1634 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
1635 res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i);
1636 if (res) {
1637 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
1638 ast_hangup(chan);
1639 return 1;
1640 }
1641 if (i & DAHDI_IOMUX_SIGEVENT) {
1642 res = dahdi_get_event(p->subs[idx].dfd);
1643 ast_debug(3, "Got event %d (%s)...\n", res, event2str(res));
1644 if (res == DAHDI_EVENT_NOALARM) {
1645 p->inalarm = 0;
1646 analog_p->inalarm = 0;
1647 } else if (res == DAHDI_EVENT_RINGOFFHOOK) {
1648 /* Let us detect distinctive ring */
1649 ringdata[receivedRingT] = analog_p->ringt;
1650
1651 if (analog_p->ringt < analog_p->ringt_base / 2) {
1652 break;
1653 }
1654 /* Increment the ringT counter so we can match it against
1655 values in chan_dahdi.conf for distinctive ring */
1656 if (++receivedRingT == RING_PATTERNS) {
1657 break;
1658 }
1659 }
1660 } else if (i & DAHDI_IOMUX_READ) {
1661 res = read(p->subs[idx].dfd, buf, sizeof(buf));
1662 if (res < 0) {
1663 if (errno != ELAST) {
1664 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1665 ast_hangup(chan);
1666 return 1;
1667 }
1668 break;
1669 }
1670 if (analog_p->ringt > 0) {
1671 if (!(--analog_p->ringt)) {
1672 break;
1673 }
1674 }
1675 }
1676 }
1677 }
1678
1679 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
1680 ast_verb(3, "Detected ring pattern: %d,%d,%d\n", ringdata[0], ringdata[1], ringdata[2]);
1681 matched_context = p->defcontext;
1682 for (counter = 0; counter < 3; counter++) {
1683 int range = p->drings.ringnum[counter].range;
1684
1685 distMatches = 0;
1686 ast_verb(3, "Checking %d,%d,%d with +/- %d range\n",
1687 p->drings.ringnum[counter].ring[0],
1688 p->drings.ringnum[counter].ring[1],
1689 p->drings.ringnum[counter].ring[2],
1690 range);
1691 for (counter1 = 0; counter1 < 3; counter1++) {
1692 int ring = p->drings.ringnum[counter].ring[counter1];
1693
1694 if (ring == -1) {
1695 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
1696 ringdata[counter1]);
1697 distMatches++;
1698 } else if (ring - range <= ringdata[counter1] && ringdata[counter1] <= ring + range) {
1699 ast_verb(3, "Ring pattern %d is in range: %d to %d\n",
1700 ringdata[counter1], ring - range, ring + range);
1701 distMatches++;
1702 } else {
1703 /* The current dring pattern cannot match. */
1704 break;
1705 }
1706 }
1707
1708 if (distMatches == 3) {
1709 /* The ring matches, set the context to whatever is for distinctive ring.. */
1710 matched_context = S_OR(p->drings.ringContext[counter].contextData, p->defcontext);
1711 ast_verb(3, "Matched Distinctive Ring context %s\n", matched_context);
1712 break;
1713 }
1714 }
1715
1716 /* Set selected distinctive ring context if not already set. */
1717 if (strcmp(p->context, matched_context) != 0) {
1718 ast_copy_string(p->context, matched_context, sizeof(p->context));
1719 ast_channel_context_set(chan, matched_context);
1720 }
1721
1722 return 0;
1723}
1724
1725static int my_stop_callwait(void *pvt)
1726{
1727 struct dahdi_pvt *p = pvt;
1728 p->callwaitingrepeat = 0;
1729 p->cidcwexpire = 0;
1730 p->cid_suppress_expire = 0;
1731
1732 return 0;
1733}
1734
1735static int send_callerid(struct dahdi_pvt *p);
1736static int save_conference(struct dahdi_pvt *p);
1737static int restore_conference(struct dahdi_pvt *p);
1738
1739static int my_callwait(void *pvt)
1740{
1741 struct dahdi_pvt *p = pvt;
1742
1744 if (p->cidspill) {
1745 ast_log(LOG_WARNING, "Spill already exists?!?\n");
1746 ast_free(p->cidspill);
1747 }
1748
1749 /*
1750 * SAS: Subscriber Alert Signal, 440Hz for 300ms
1751 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
1752 */
1753 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
1754 return -1;
1755 save_conference(p);
1756 /* Silence */
1757 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
1758 if (!p->callwaitrings && p->callwaitingcallerid) {
1759 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
1760 p->callwaitcas = 1;
1761 p->cidlen = 2400 + 680 + READ_SIZE * 4;
1762 } else {
1763 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
1764 p->callwaitcas = 0;
1765 p->cidlen = 2400 + READ_SIZE * 4;
1766 }
1767 p->cidpos = 0;
1768 send_callerid(p);
1769
1770 return 0;
1771}
1772
1773static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
1774{
1775 struct dahdi_pvt *p = pvt;
1776 struct analog_pvt *analog_p = p->sig_pvt;
1777
1778 ast_debug(2, "Starting cid spill\n");
1779
1780 if (p->cidspill) {
1781 ast_log(LOG_WARNING, "cidspill already exists??\n");
1782 ast_free(p->cidspill);
1783 }
1784
1786 int pres = ast_party_id_presentation(&caller->id);
1787 if (cwcid == 0) {
1788 /* Some CPE support additional parameters for on-hook Caller*ID,
1789 * such as redirecting reason and call qualifier, so send those
1790 * if available.
1791 * I don't know of any CPE that supports this for Call Waiting (unfortunately),
1792 * so don't send those for call waiting as that will just lengthen the CID spill
1793 * for no good reason.
1794 */
1796 caller->id.name.str,
1798 NULL,
1799 analog_p->redirecting_reason,
1800 pres,
1801 analog_p->call_qualifier,
1803 AST_LAW(p));
1804 } else {
1805 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
1807 p->callwaitcas = 0;
1808 p->cidcwexpire = 0;
1810 caller->id.name.str,
1812 NULL,
1813 -1,
1814 pres,
1815 0,
1816 AST_LAW(p));
1817 p->cidlen += READ_SIZE * 4;
1818 }
1819 p->cidpos = 0;
1820 p->cid_suppress_expire = 0;
1821 send_callerid(p);
1822 }
1823 return 0;
1824}
1825
1827{
1828 struct dahdi_pvt *p = pvt;
1829 if (p->dsp)
1831
1832 return 0;
1833}
1834
1835static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
1836{
1837 struct dahdi_pvt *p = pvt;
1838
1839 if (p->channel == CHAN_PSEUDO)
1840 ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
1841
1842 if (mode == ANALOG_DIGITMODE_DTMF) {
1843 /* If we do hardware dtmf, no need for a DSP */
1844 if (p->hardwaredtmf) {
1845 if (p->dsp) {
1846 ast_dsp_free(p->dsp);
1847 p->dsp = NULL;
1848 }
1849 return 0;
1850 }
1851
1852 if (!p->dsp) {
1853 p->dsp = ast_dsp_new();
1854 if (!p->dsp) {
1855 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1856 return -1;
1857 }
1858 }
1859
1861 } else if (mode == ANALOG_DIGITMODE_MF) {
1862 if (!p->dsp) {
1863 p->dsp = ast_dsp_new();
1864 if (!p->dsp) {
1865 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1866 return -1;
1867 }
1868 }
1870 }
1871 return 0;
1872}
1873
1874static int dahdi_wink(struct dahdi_pvt *p, int index);
1875
1876static int my_wink(void *pvt, enum analog_sub sub)
1877{
1878 struct dahdi_pvt *p = pvt;
1879 int index = analogsub_to_dahdisub(sub);
1880 if (index != SUB_REAL) {
1881 ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
1882 }
1883 return dahdi_wink(p, index);
1884}
1885
1886static void wakeup_sub(struct dahdi_pvt *p, int a);
1887
1888static int reset_conf(struct dahdi_pvt *p);
1889
1890static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
1891
1892static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
1893{
1894 struct ast_frame *f = *dest;
1895 struct dahdi_pvt *p = pvt;
1896 int idx = analogsub_to_dahdisub(analog_index);
1897
1898 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
1899 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
1900 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
1901
1902 if (f->subclass.integer == 'f') {
1903 if (f->frametype == AST_FRAME_DTMF_END) {
1904 /* Fax tone -- Handle and return NULL */
1905 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
1906 /* If faxbuffers are configured, use them for the fax transmission */
1907 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
1908 struct dahdi_bufferinfo bi = {
1909 .txbufpolicy = p->faxbuf_policy,
1910 .bufsize = p->bufsize,
1911 .numbufs = p->faxbuf_no
1912 };
1913 int res;
1914
1915 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
1916 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
1917 } else {
1918 p->bufferoverrideinuse = 1;
1919 }
1920 }
1921 p->faxhandled = 1;
1922 if (p->dsp) {
1923 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
1925 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
1926 }
1927 if (strcmp(ast_channel_exten(ast), "fax")) {
1928 const char *target_context = ast_channel_context(ast);
1929
1930 /*
1931 * We need to unlock 'ast' here because ast_exists_extension has the
1932 * potential to start autoservice on the channel. Such action is prone
1933 * to deadlock if the channel is locked.
1934 *
1935 * ast_async_goto() has its own restriction on not holding the
1936 * channel lock.
1937 */
1939 ast_channel_unlock(ast);
1940 if (ast_exists_extension(ast, target_context, "fax", 1,
1941 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
1942 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
1943 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
1944 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
1945 if (ast_async_goto(ast, target_context, "fax", 1))
1946 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
1947 } else {
1948 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
1949 }
1950 ast_channel_lock(ast);
1951 ast_mutex_lock(&p->lock);
1952 } else {
1953 ast_debug(1, "Already in a fax extension, not redirecting\n");
1954 }
1955 } else {
1956 ast_debug(1, "Fax already handled\n");
1957 }
1958 dahdi_confmute(p, 0);
1959 }
1960 p->subs[idx].f.frametype = AST_FRAME_NULL;
1961 p->subs[idx].f.subclass.integer = 0;
1962 *dest = &p->subs[idx].f;
1963 }
1964}
1965
1966static void my_lock_private(void *pvt)
1967{
1968 struct dahdi_pvt *p = pvt;
1969 ast_mutex_lock(&p->lock);
1970}
1971
1972static void my_unlock_private(void *pvt)
1973{
1974 struct dahdi_pvt *p = pvt;
1976}
1977
1978static void my_deadlock_avoidance_private(void *pvt)
1979{
1980 struct dahdi_pvt *p = pvt;
1981
1983}
1984
1986{
1987 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1988 struct ast_channel_blob *obj = stasis_message_data(msg);
1989 struct ast_json *group, *span, *channel;
1990
1991 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1992 if (!channel_string) {
1993 return NULL;
1994 }
1995
1996 group = ast_json_object_get(obj->blob, "group");
1997 span = ast_json_object_get(obj->blob, "span");
1998 channel = ast_json_object_get(obj->blob, "channel");
1999
2000 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
2001 "%s"
2002 "DAHDIGroup: %llu\r\n"
2003 "DAHDISpan: %u\r\n"
2004 "DAHDIChannel: %s\r\n",
2005 ast_str_buffer(channel_string),
2007 (unsigned int)ast_json_integer_get(span),
2008 ast_json_string_get(channel));
2009}
2010
2013 );
2014
2015/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
2016static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
2017{
2018 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
2019
2020 ast_assert(dahdi_channel != NULL);
2021
2022 blob = ast_json_pack("{s: I, s: i, s: s}",
2023 "group", (ast_json_int_t)group,
2024 "span", span,
2025 "channel", dahdi_channel);
2026 if (!blob) {
2027 return;
2028 }
2029
2030 ast_channel_lock(chan);
2031 ast_channel_publish_blob(chan, dahdichannel_type(), blob);
2032 ast_channel_unlock(chan);
2033}
2034
2035/*!
2036 * \internal
2037 * \brief Post an AMI DAHDI channel association event.
2038 * \since 1.8
2039 *
2040 * \param p DAHDI private pointer
2041 * \param chan Channel associated with the private pointer
2042 */
2043static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
2044{
2045 char ch_name[23];
2046
2047 if (p->channel < CHAN_PSEUDO) {
2048 /* No B channel */
2049 snprintf(ch_name, sizeof(ch_name), "no-media (%d)", p->channel);
2050 } else if (p->channel == CHAN_PSEUDO) {
2051 /* Pseudo channel */
2052 strcpy(ch_name, "pseudo");
2053 } else {
2054 /* Real channel */
2055 snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
2056 }
2057 publish_dahdichannel(chan, p->group, p->span, ch_name);
2058}
2059
2060#ifdef HAVE_PRI
2061/*!
2062 * \internal
2063 * \brief Post an AMI DAHDI channel association event.
2064 * \since 1.8
2065 *
2066 * \param pvt DAHDI private pointer
2067 * \param chan Channel associated with the private pointer
2068 */
2069static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
2070{
2071 struct dahdi_pvt *p = pvt;
2072
2073 dahdi_ami_channel_event(p, chan);
2074}
2075#endif
2076
2077/* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
2078* returns the last value of the linear setting
2079*/
2080static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
2081{
2082 struct dahdi_pvt *p = pvt;
2083 int oldval;
2084 int idx = analogsub_to_dahdisub(sub);
2085
2086 dahdi_setlinear(p->subs[idx].dfd, linear_mode);
2087 oldval = p->subs[idx].linear;
2088 p->subs[idx].linear = linear_mode ? 1 : 0;
2089 return oldval;
2090}
2091
2092static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
2093{
2094 struct dahdi_pvt *p = pvt;
2095 int idx = analogsub_to_dahdisub(sub);
2096
2097 p->subs[idx].inthreeway = inthreeway;
2098}
2099
2100static int get_alarms(struct dahdi_pvt *p);
2101static void handle_alarms(struct dahdi_pvt *p, int alms);
2102static void my_get_and_handle_alarms(void *pvt)
2103{
2104 int res;
2105 struct dahdi_pvt *p = pvt;
2106
2107 res = get_alarms(p);
2108 handle_alarms(p, res);
2109}
2110
2112{
2114
2115 if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
2116 struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
2117
2118 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
2119 return p->sig_pvt;
2120 }
2121 }
2122 return NULL;
2123}
2124
2125static int my_get_sub_fd(void *pvt, enum analog_sub sub)
2126{
2127 struct dahdi_pvt *p = pvt;
2128 int dahdi_sub = analogsub_to_dahdisub(sub);
2129 return p->subs[dahdi_sub].dfd;
2130}
2131
2132static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
2133{
2134 struct dahdi_pvt *p = pvt;
2135
2136 /* Choose proper cadence */
2137 if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
2138 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
2139 ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast_channel_name(ast), strerror(errno));
2140 *cid_rings = cidrings[p->distinctivering - 1];
2141 } else {
2142 if (p->distinctivering > 0) {
2143 ast_log(LOG_WARNING, "Cadence %d is not defined, falling back to default ring cadence\n", p->distinctivering);
2144 }
2145 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
2146 ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast), strerror(errno));
2147 *cid_rings = p->sendcalleridafter;
2148 }
2149}
2150
2151static void my_set_alarm(void *pvt, int in_alarm)
2152{
2153 struct dahdi_pvt *p = pvt;
2154
2155 p->inalarm = in_alarm;
2156}
2157
2158static void my_set_dialing(void *pvt, int is_dialing)
2159{
2160 struct dahdi_pvt *p = pvt;
2161
2162 p->dialing = is_dialing;
2163}
2164
2165static void my_set_outgoing(void *pvt, int is_outgoing)
2166{
2167 struct dahdi_pvt *p = pvt;
2168
2169 p->outgoing = is_outgoing;
2170}
2171
2172#if defined(HAVE_PRI) || defined(HAVE_SS7)
2173static void my_set_digital(void *pvt, int is_digital)
2174{
2175 struct dahdi_pvt *p = pvt;
2176
2177 p->digital = is_digital;
2178}
2179#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2180
2181#if defined(HAVE_SS7)
2182static void my_set_inservice(void *pvt, int is_inservice)
2183{
2184 struct dahdi_pvt *p = pvt;
2185
2186 p->inservice = is_inservice;
2187}
2188#endif /* defined(HAVE_SS7) */
2189
2190#if defined(HAVE_SS7)
2191static void my_set_locallyblocked(void *pvt, int is_blocked)
2192{
2193 struct dahdi_pvt *p = pvt;
2194
2195 p->locallyblocked = is_blocked;
2196}
2197#endif /* defined(HAVE_SS7) */
2198
2199#if defined(HAVE_SS7)
2200static void my_set_remotelyblocked(void *pvt, int is_blocked)
2201{
2202 struct dahdi_pvt *p = pvt;
2203
2204 p->remotelyblocked = is_blocked;
2205}
2206#endif /* defined(HAVE_SS7) */
2207
2208static void my_set_ringtimeout(void *pvt, int ringt)
2209{
2210 struct dahdi_pvt *p = pvt;
2211 p->ringt = ringt;
2212}
2213
2214static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
2215{
2216 struct dahdi_pvt *p = pvt;
2217
2218 /* We reset p->waitfordialtonetemp here, to prevent leaking to future calls,
2219 * but we also need to check against this value until we get dialtone
2220 * or the timer expires, since waitingfordt is when the timer started,
2221 * not when it should expire.
2222 *
2223 * Critically, we only set p->waitingfordt here if waitfordialtone or waitfordialtonetemp
2224 * has already been set, as waitingfordt is what is checked at runtime to determine
2225 * if we should be waiting for dial tone. This ensures that if a second call
2226 * is initiated concurrently, the first one "consumes" waitfordialtonetemp and resets it,
2227 * preventing leaking to other calls while remaining available to check on the first one while dialing.
2228 */
2230 p->waitfordialtonetemp = 0;
2231
2233 return;
2234 }
2235
2236 /* Because the DSP is allocated when the channel is created,
2237 * if we requested waitfordialtone later (in a predial handler),
2238 * we need to create it now */
2239 if (!p->dsp) {
2240 p->dsp = ast_dsp_new();
2241 if (!p->dsp) {
2242 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
2243 return;
2244 }
2245 }
2248
2249 ast_debug(1, "Defer dialing for %dms or dialtone\n", p->waitfordialtoneduration);
2250 gettimeofday(&p->waitingfordt, NULL);
2252}
2253
2254static int my_check_waitingfordt(void *pvt)
2255{
2256 struct dahdi_pvt *p = pvt;
2257
2258 if (p->waitingfordt.tv_sec) {
2259 return 1;
2260 }
2261
2262 return 0;
2263}
2264
2265static void my_set_confirmanswer(void *pvt, int flag)
2266{
2267 struct dahdi_pvt *p = pvt;
2268 p->confirmanswer = flag;
2269}
2270
2271static int my_check_confirmanswer(void *pvt)
2272{
2273 struct dahdi_pvt *p = pvt;
2274 if (p->confirmanswer) {
2275 return 1;
2276 }
2277
2278 return 0;
2279}
2280
2281static void my_set_callwaiting(void *pvt, int callwaiting_enable)
2282{
2283 struct dahdi_pvt *p = pvt;
2284
2285 p->callwaiting = callwaiting_enable;
2286}
2287
2288static void my_cancel_cidspill(void *pvt)
2289{
2290 struct dahdi_pvt *p = pvt;
2291
2292 ast_free(p->cidspill);
2293 p->cidspill = NULL;
2295}
2296
2297static int my_confmute(void *pvt, int mute)
2298{
2299 struct dahdi_pvt *p = pvt;
2300 return dahdi_confmute(p, mute);
2301}
2302
2303static void my_set_pulsedial(void *pvt, int flag)
2304{
2305 struct dahdi_pvt *p = pvt;
2306 p->pulsedial = flag;
2307}
2308
2309static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
2310{
2311 struct dahdi_pvt *p = pvt;
2312
2313 p->owner = new_owner;
2314}
2315
2316static const char *my_get_orig_dialstring(void *pvt)
2317{
2318 struct dahdi_pvt *p = pvt;
2319
2320 return p->dialstring;
2321}
2322
2323static void my_increase_ss_count(void)
2324{
2328}
2329
2330static void my_decrease_ss_count(void)
2331{
2336}
2337
2338static void my_all_subchannels_hungup(void *pvt)
2339{
2340 struct dahdi_pvt *p = pvt;
2341 int res, law;
2342
2343 p->faxhandled = 0;
2344 p->didtdd = 0;
2345
2346 if (p->dsp) {
2347 ast_dsp_free(p->dsp);
2348 p->dsp = NULL;
2349 }
2350
2351 p->law = p->law_default;
2352 law = p->law_default;
2353 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
2354 if (res < 0)
2355 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
2356
2358
2359#if 1
2360 {
2361 int i;
2362 p->owner = NULL;
2363 /* Cleanup owners here */
2364 for (i = 0; i < 3; i++) {
2365 p->subs[i].owner = NULL;
2366 }
2367 }
2368#endif
2369
2370 reset_conf(p);
2371 if (num_restart_pending == 0) {
2373 }
2374}
2375
2376static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
2377
2378static int my_conf_del(void *pvt, enum analog_sub sub)
2379{
2380 struct dahdi_pvt *p = pvt;
2381 int x = analogsub_to_dahdisub(sub);
2382
2383 return conf_del(p, &p->subs[x], x);
2384}
2385
2386static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
2387
2388static int my_conf_add(void *pvt, enum analog_sub sub)
2389{
2390 struct dahdi_pvt *p = pvt;
2391 int x = analogsub_to_dahdisub(sub);
2392
2393 return conf_add(p, &p->subs[x], x, 0);
2394}
2395
2396static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
2397
2398static int my_complete_conference_update(void *pvt, int needconference)
2399{
2400 struct dahdi_pvt *p = pvt;
2401 int needconf = needconference;
2402 int x;
2403 int useslavenative;
2404 struct dahdi_pvt *slave = NULL;
2405
2406 useslavenative = isslavenative(p, &slave);
2407
2408 /* If we have a slave, add him to our conference now. or DAX
2409 if this is slave native */
2410 for (x = 0; x < MAX_SLAVES; x++) {
2411 if (p->slaves[x]) {
2412 if (useslavenative)
2413 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
2414 else {
2415 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
2416 needconf++;
2417 }
2418 }
2419 }
2420 /* If we're supposed to be in there, do so now */
2421 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
2422 if (useslavenative)
2423 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
2424 else {
2425 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
2426 needconf++;
2427 }
2428 }
2429 /* If we have a master, add ourselves to his conference */
2430 if (p->master) {
2431 if (isslavenative(p->master, NULL)) {
2433 } else {
2434 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
2435 }
2436 }
2437 if (!needconf) {
2438 /* Nobody is left (or should be left) in our conference.
2439 Kill it. */
2440 p->confno = -1;
2441 }
2442
2443 return 0;
2444}
2445
2446static int check_for_conference(struct dahdi_pvt *p);
2447
2448static int my_check_for_conference(void *pvt)
2449{
2450 struct dahdi_pvt *p = pvt;
2451 return check_for_conference(p);
2452}
2453
2454static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
2455{
2456 struct dahdi_pvt *p = pvt;
2457 int da, db;
2458 int tchan;
2459 int tinthreeway;
2460
2463
2464 tchan = p->subs[da].chan;
2465 p->subs[da].chan = p->subs[db].chan;
2466 p->subs[db].chan = tchan;
2467
2468 tinthreeway = p->subs[da].inthreeway;
2469 p->subs[da].inthreeway = p->subs[db].inthreeway;
2470 p->subs[db].inthreeway = tinthreeway;
2471
2472 p->subs[da].owner = ast_a;
2473 p->subs[db].owner = ast_b;
2474
2475 if (ast_a)
2476 ast_channel_set_fd(ast_a, 0, p->subs[da].dfd);
2477 if (ast_b)
2478 ast_channel_set_fd(ast_b, 0, p->subs[db].dfd);
2479
2480 wakeup_sub(p, a);
2481 wakeup_sub(p, b);
2482
2483 return;
2484}
2485
2486/*!
2487 * \internal
2488 * \brief performs duties of dahdi_new, but also removes and possibly unbinds (if callid_created is 1) before returning
2489 * \note this variant of dahdi should only be used in conjunction with ast_callid_threadstorage_auto()
2490 *
2491 * \param callid_created value returned from ast_callid_threadstorage_auto()
2492 * \param i, state, startpbx, idx, law, assignedids, requestor, callid
2493 */
2494static 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);
2495
2496static 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);
2497
2498static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
2499{
2500 ast_callid callid = 0;
2501 int callid_created = ast_callid_threadstorage_auto(&callid);
2502 struct dahdi_pvt *p = pvt;
2503 int dsub = analogsub_to_dahdisub(sub);
2504
2505 return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, NULL, requestor, callid, callid_created);
2506}
2507
2508#if defined(HAVE_PRI) || defined(HAVE_SS7)
2509static int dahdi_setlaw(int dfd, int law)
2510{
2511 int res;
2512 res = ioctl(dfd, DAHDI_SETLAW, &law);
2513 if (res)
2514 return res;
2515 return 0;
2516}
2517#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2518
2519#if defined(HAVE_PRI)
2520static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state,
2521 enum sig_pri_law law, char *exten, const struct ast_assigned_ids *assignedids,
2522 const struct ast_channel *requestor)
2523{
2524 struct dahdi_pvt *p = pvt;
2525 int audio;
2526 int newlaw = -1;
2527 ast_callid callid = 0;
2528 int callid_created = ast_callid_threadstorage_auto(&callid);
2529
2530 switch (p->sig) {
2532 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
2533 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
2534 break;
2535 }
2536 /* Fall through */
2537 default:
2538 /* Set to audio mode at this point */
2539 audio = 1;
2540 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) {
2541 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
2542 p->channel, audio, strerror(errno));
2543 }
2544 break;
2545 }
2546
2547 if (law != SIG_PRI_DEFLAW) {
2548 dahdi_setlaw(p->subs[SUB_REAL].dfd, (law == SIG_PRI_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
2549 }
2550
2551 ast_copy_string(p->exten, exten, sizeof(p->exten));
2552
2553 switch (law) {
2554 case SIG_PRI_DEFLAW:
2555 newlaw = 0;
2556 break;
2557 case SIG_PRI_ALAW:
2558 newlaw = DAHDI_LAW_ALAW;
2559 break;
2560 case SIG_PRI_ULAW:
2561 newlaw = DAHDI_LAW_MULAW;
2562 break;
2563 }
2564
2565 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
2566}
2567#endif /* defined(HAVE_PRI) */
2568
2569static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law);
2570
2571#if defined(HAVE_PRI) || defined(HAVE_SS7)
2572/*!
2573 * \internal
2574 * \brief Open the PRI/SS7 channel media path.
2575 * \since 1.8
2576 *
2577 * \param p Channel private control structure.
2578 */
2579static void my_pri_ss7_open_media(void *p)
2580{
2581 struct dahdi_pvt *pvt = p;
2582 int res;
2583 int dfd;
2584 int set_val;
2585
2586 dfd = pvt->subs[SUB_REAL].dfd;
2587
2588 /* Open the media path. */
2589 set_val = 1;
2590 res = ioctl(dfd, DAHDI_AUDIOMODE, &set_val);
2591 if (res < 0) {
2592 ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n",
2593 pvt->channel, strerror(errno));
2594 }
2595
2596 /* Set correct companding law for this call. */
2597 res = dahdi_setlaw(dfd, pvt->law);
2598 if (res < 0) {
2599 ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pvt->channel);
2600 }
2601
2602 /* Set correct gain for this call. */
2603 if (pvt->digital) {
2604 res = set_actual_gain(dfd, 0, 0, pvt->rxdrc, pvt->txdrc, pvt->law);
2605 } else {
2606 res = set_actual_gain(dfd, pvt->rxgain, pvt->txgain, pvt->rxdrc, pvt->txdrc,
2607 pvt->law);
2608 }
2609 if (res < 0) {
2610 ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pvt->channel);
2611 }
2612
2613 if (pvt->dsp_features && pvt->dsp) {
2615 }
2616}
2617#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2618
2619#if defined(HAVE_PRI)
2620/*!
2621 * \internal
2622 * \brief Ask DAHDI to dial the given dial string.
2623 * \since 1.8.11
2624 *
2625 * \param p Channel private control structure.
2626 * \param dial_string String to pass to DAHDI to dial.
2627 *
2628 * \note The channel private lock needs to be held when calling.
2629 */
2630static void my_pri_dial_digits(void *p, const char *dial_string)
2631{
2632 char dial_str[DAHDI_MAX_DTMF_BUF];
2633 struct dahdi_pvt *pvt = p;
2634 int res;
2635
2636 snprintf(dial_str, sizeof(dial_str), "T%s", dial_string);
2637 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
2638 if (!res) {
2639 pvt->dialing = 1;
2640 }
2641}
2642#endif /* defined(HAVE_PRI) */
2643
2644static int unalloc_sub(struct dahdi_pvt *p, int x);
2645
2646static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
2647{
2648 struct dahdi_pvt *p = pvt;
2649
2650 return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
2651}
2652
2653static int alloc_sub(struct dahdi_pvt *p, int x);
2654
2655static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
2656{
2657 struct dahdi_pvt *p = pvt;
2658
2659 return alloc_sub(p, analogsub_to_dahdisub(analogsub));
2660}
2661
2662static int has_voicemail(struct dahdi_pvt *p);
2663
2664static int my_has_voicemail(void *pvt)
2665{
2666 struct dahdi_pvt *p = pvt;
2667
2668 return has_voicemail(p);
2669}
2670
2671static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
2672{
2673 struct dahdi_pvt *p = pvt;
2674 int index;
2675
2676 index = analogsub_to_dahdisub(sub);
2677
2678 return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
2679}
2680
2682{
2683 enum analog_event res;
2684
2685 switch (event) {
2686 case DAHDI_EVENT_ONHOOK:
2687 res = ANALOG_EVENT_ONHOOK;
2688 break;
2689 case DAHDI_EVENT_RINGOFFHOOK:
2691 break;
2692 case DAHDI_EVENT_WINKFLASH:
2694 break;
2695 case DAHDI_EVENT_ALARM:
2696 res = ANALOG_EVENT_ALARM;
2697 break;
2698 case DAHDI_EVENT_NOALARM:
2700 break;
2701 case DAHDI_EVENT_DIALCOMPLETE:
2703 break;
2704 case DAHDI_EVENT_RINGERON:
2706 break;
2707 case DAHDI_EVENT_RINGEROFF:
2709 break;
2710 case DAHDI_EVENT_HOOKCOMPLETE:
2712 break;
2713 case DAHDI_EVENT_PULSE_START:
2715 break;
2716 case DAHDI_EVENT_POLARITY:
2718 break;
2719 case DAHDI_EVENT_RINGBEGIN:
2721 break;
2722 case DAHDI_EVENT_EC_DISABLED:
2724 break;
2725 case DAHDI_EVENT_REMOVED:
2727 break;
2728 case DAHDI_EVENT_NEONMWI_ACTIVE:
2730 break;
2731 case DAHDI_EVENT_NEONMWI_INACTIVE:
2733 break;
2734#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
2735 case DAHDI_EVENT_TX_CED_DETECTED:
2737 break;
2738 case DAHDI_EVENT_RX_CED_DETECTED:
2740 break;
2741 case DAHDI_EVENT_EC_NLP_DISABLED:
2743 break;
2744 case DAHDI_EVENT_EC_NLP_ENABLED:
2746 break;
2747#endif
2748 case DAHDI_EVENT_PULSEDIGIT:
2750 break;
2751 case DAHDI_EVENT_DTMFDOWN:
2753 break;
2754 case DAHDI_EVENT_DTMFUP:
2755 res = ANALOG_EVENT_DTMFUP;
2756 break;
2757 default:
2758 switch(event & 0xFFFF0000) {
2759 case DAHDI_EVENT_PULSEDIGIT:
2760 case DAHDI_EVENT_DTMFDOWN:
2761 case DAHDI_EVENT_DTMFUP:
2762 /* The event includes a digit number in the low word.
2763 * Converting it to a 'enum analog_event' would remove
2764 * that information. Thus it is returned as-is.
2765 */
2766 return event;
2767 }
2768
2769 res = ANALOG_EVENT_ERROR;
2770 break;
2771 }
2772
2773 return res;
2774}
2775
2776static inline int dahdi_wait_event(int fd);
2777
2778static int my_wait_event(void *pvt)
2779{
2780 struct dahdi_pvt *p = pvt;
2781
2782 return dahdi_wait_event(p->subs[SUB_REAL].dfd);
2783}
2784
2785static int my_get_event(void *pvt)
2786{
2787 struct dahdi_pvt *p = pvt;
2788 int res;
2789
2790 if (p->fake_event) {
2791 res = p->fake_event;
2792 p->fake_event = 0;
2793 } else
2794 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
2795
2796 return dahdievent_to_analogevent(res);
2797}
2798
2799static int my_is_off_hook(void *pvt)
2800{
2801 struct dahdi_pvt *p = pvt;
2802 int res;
2803 struct dahdi_params par;
2804
2805 memset(&par, 0, sizeof(par));
2806
2807 if (p->subs[SUB_REAL].dfd > -1)
2808 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
2809 else {
2810 /* Assume not off hook on CVRS */
2811 res = 0;
2812 par.rxisoffhook = 0;
2813 }
2814 if (res) {
2815 ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
2816 }
2817
2818 if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
2819 /* When "onhook" that means no battery on the line, and thus
2820 it is out of service..., if it's on a TDM card... If it's a channel
2821 bank, there is no telling... */
2822 return (par.rxbits > -1) || par.rxisoffhook;
2823 }
2824
2825 return par.rxisoffhook;
2826}
2827
2828static int my_set_echocanceller(void *pvt, int enable)
2829{
2830 struct dahdi_pvt *p = pvt;
2831
2832 if (enable)
2833 dahdi_ec_enable(p);
2834 else
2836
2837 return 0;
2838}
2839
2840static int dahdi_ring_phone(struct dahdi_pvt *p);
2841
2842static int my_ring(void *pvt)
2843{
2844 struct dahdi_pvt *p = pvt;
2845
2846 return dahdi_ring_phone(p);
2847}
2848
2849static int my_flash(void *pvt)
2850{
2851 struct dahdi_pvt *p = pvt;
2852 int func = DAHDI_FLASH;
2853 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &func);
2854}
2855
2856static inline int dahdi_set_hook(int fd, int hs);
2857
2858static int my_off_hook(void *pvt)
2859{
2860 struct dahdi_pvt *p = pvt;
2861 return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
2862}
2863
2864static void my_set_needringing(void *pvt, int value)
2865{
2866 struct dahdi_pvt *p = pvt;
2868}
2869
2870static void my_set_polarity(void *pvt, int value)
2871{
2872 struct dahdi_pvt *p = pvt;
2873
2874 if (p->channel == CHAN_PSEUDO) {
2875 return;
2876 }
2877 p->polarity = value;
2878 ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETPOLARITY, &value);
2879}
2880
2881static void my_start_polarityswitch(void *pvt)
2882{
2883 struct dahdi_pvt *p = pvt;
2884
2886 my_set_polarity(pvt, 0);
2887 }
2888}
2889
2890static void my_answer_polarityswitch(void *pvt)
2891{
2892 struct dahdi_pvt *p = pvt;
2893
2894 if (!p->answeronpolarityswitch) {
2895 return;
2896 }
2897
2898 my_set_polarity(pvt, 1);
2899}
2900
2901static void my_hangup_polarityswitch(void *pvt)
2902{
2903 struct dahdi_pvt *p = pvt;
2904
2905 if (!p->hanguponpolarityswitch) {
2906 return;
2907 }
2908
2909 if (p->answeronpolarityswitch) {
2910 my_set_polarity(pvt, 0);
2911 } else {
2912 my_set_polarity(pvt, 1);
2913 }
2914}
2915
2916/*! \brief Return DAHDI pivot if channel is FXO signalled */
2917static struct dahdi_pvt *fxo_pvt(struct ast_channel *chan)
2918{
2919 int res;
2920 struct dahdi_params dahdip;
2921 struct dahdi_pvt *pvt = NULL;
2922
2923 if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
2924 ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
2925 return NULL;
2926 }
2927
2928 memset(&dahdip, 0, sizeof(dahdip));
2929 res = ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip);
2930
2931 if (res) {
2932 ast_log(LOG_WARNING, "Unable to get parameters of %s: %s\n", ast_channel_name(chan), strerror(errno));
2933 return NULL;
2934 }
2935 if (!(dahdip.sigtype & __DAHDI_SIG_FXO)) {
2936 ast_log(LOG_WARNING, "%s is not FXO signalled\n", ast_channel_name(chan));
2937 return NULL;
2938 }
2939
2940 pvt = ast_channel_tech_pvt(chan);
2941 if (!dahdi_analog_lib_handles(pvt->sig, 0, 0)) {
2942 ast_log(LOG_WARNING, "Channel signalling is not analog");
2943 return NULL;
2944 }
2945
2946 return pvt;
2947}
2948
2949static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
2950{
2951 struct dahdi_pvt *pvt;
2952
2953 pvt = fxo_pvt(chan);
2954 if (!pvt) {
2955 return -1;
2956 }
2957
2958 snprintf(buffer, buflen, "%d", pvt->polarity);
2959
2960 return 0;
2961}
2962
2963static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
2964{
2965 struct dahdi_pvt *pvt;
2966 int polarity;
2967
2968 pvt = fxo_pvt(chan);
2969 if (!pvt) {
2970 return -1;
2971 }
2972
2973 if (!strcasecmp(value, "idle")) {
2975 } else if (!strcasecmp(value, "reverse")) {
2977 } else {
2978 polarity = atoi(value);
2979 }
2980
2982 ast_log(LOG_WARNING, "Invalid polarity: '%s'\n", value);
2983 return -1;
2984 }
2985
2987 return 0;
2988}
2989
2991 .name = "POLARITY",
2992 .write = polarity_write,
2993 .read = polarity_read,
2994};
2995
2996static int my_start(void *pvt)
2997{
2998 struct dahdi_pvt *p = pvt;
2999 int x = DAHDI_START;
3000
3001 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
3002}
3003
3004static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
3005{
3006 struct dahdi_pvt *p = pvt;
3007
3008 if (dop->op != ANALOG_DIAL_OP_REPLACE) {
3009 ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
3010 return -1;
3011 }
3012
3013 if (sub != ANALOG_SUB_REAL) {
3014 ast_log(LOG_ERROR, "Trying to dial_digits '%s' on channel %d subchannel %u\n",
3015 dop->dialstr, p->channel, sub);
3016 return -1;
3017 }
3018
3019 return dahdi_dial_str(p, DAHDI_DIAL_OP_REPLACE, dop->dialstr);
3020}
3021
3022static void dahdi_train_ec(struct dahdi_pvt *p);
3023
3024static int my_train_echocanceller(void *pvt)
3025{
3026 struct dahdi_pvt *p = pvt;
3027
3028 dahdi_train_ec(p);
3029
3030 return 0;
3031}
3032
3033static int my_is_dialing(void *pvt, enum analog_sub sub)
3034{
3035 struct dahdi_pvt *p = pvt;
3036 int index;
3037 int x;
3038
3039 index = analogsub_to_dahdisub(sub);
3040
3041 if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
3042 ast_debug(1, "DAHDI_DIALING ioctl failed!\n");
3043 return -1;
3044 }
3045
3046 return x;
3047}
3048
3049static int my_on_hook(void *pvt)
3050{
3051 struct dahdi_pvt *p = pvt;
3052 return dahdi_set_hook(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_ONHOOK);
3053}
3054
3055#if defined(HAVE_PRI)
3056static void my_pri_fixup_chans(void *chan_old, void *chan_new)
3057{
3058 struct dahdi_pvt *old_chan = chan_old;
3059 struct dahdi_pvt *new_chan = chan_new;
3060
3061 new_chan->owner = old_chan->owner;
3062 old_chan->owner = NULL;
3063 if (new_chan->owner) {
3064 ast_channel_tech_pvt_set(new_chan->owner, new_chan);
3065 ast_channel_internal_fd_set(new_chan->owner, 0, new_chan->subs[SUB_REAL].dfd);
3066 new_chan->subs[SUB_REAL].owner = old_chan->subs[SUB_REAL].owner;
3067 old_chan->subs[SUB_REAL].owner = NULL;
3068 }
3069 /* Copy any DSP that may be present */
3070 new_chan->dsp = old_chan->dsp;
3071 new_chan->dsp_features = old_chan->dsp_features;
3072 old_chan->dsp = NULL;
3073 old_chan->dsp_features = 0;
3074
3075 /* Transfer flags from the old channel. */
3076 new_chan->dialing = old_chan->dialing;
3077 new_chan->digital = old_chan->digital;
3078 new_chan->outgoing = old_chan->outgoing;
3079 old_chan->dialing = 0;
3080 old_chan->digital = 0;
3081 old_chan->outgoing = 0;
3082
3083 /* More stuff to transfer to the new channel. */
3084 new_chan->law = old_chan->law;
3085 strcpy(new_chan->dialstring, old_chan->dialstring);
3086}
3087#endif /* defined(HAVE_PRI) */
3088
3089#if defined(HAVE_PRI)
3090static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
3091{
3092 switch (tone) {
3094 return DAHDI_TONE_RINGTONE;
3096 return DAHDI_TONE_STUTTER;
3098 return DAHDI_TONE_CONGESTION;
3100 return DAHDI_TONE_DIALTONE;
3102 return DAHDI_TONE_DIALRECALL;
3103 case SIG_PRI_TONE_INFO:
3104 return DAHDI_TONE_INFO;
3105 case SIG_PRI_TONE_BUSY:
3106 return DAHDI_TONE_BUSY;
3107 default:
3108 return -1;
3109 }
3110}
3111#endif /* defined(HAVE_PRI) */
3112
3113#if defined(HAVE_PRI)
3114static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
3115{
3116 int x;
3117
3118 ioctl(pri->fds[index], DAHDI_GETEVENT, &x);
3119 switch (x) {
3120 case DAHDI_EVENT_NONE:
3121 break;
3122 case DAHDI_EVENT_ALARM:
3123 case DAHDI_EVENT_NOALARM:
3124 if (sig_pri_is_alarm_ignored(pri)) {
3125 break;
3126 }
3127 /* Fall through */
3128 default:
3129 ast_log(LOG_NOTICE, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
3130 event2str(x), x, pri->span);
3131 break;
3132 }
3133 /* Keep track of alarm state */
3134 switch (x) {
3135 case DAHDI_EVENT_ALARM:
3136 pri_event_alarm(pri, index, 0);
3137 break;
3138 case DAHDI_EVENT_NOALARM:
3139 pri_event_noalarm(pri, index, 0);
3140 break;
3141 case DAHDI_EVENT_REMOVED:
3142 pri_queue_for_destruction(pri);
3143 break;
3144 default:
3145 break;
3146 }
3147}
3148#endif /* defined(HAVE_PRI) */
3149
3150#if defined(HAVE_PRI)
3151static int my_pri_play_tone(void *pvt, enum sig_pri_tone tone)
3152{
3153 struct dahdi_pvt *p = pvt;
3154
3155 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_pri_tone_to_dahditone(tone));
3156}
3157#endif /* defined(HAVE_PRI) */
3158
3159#if defined(HAVE_PRI) || defined(HAVE_SS7)
3160/*!
3161 * \internal
3162 * \brief Set the caller id information.
3163 * \since 1.8
3164 *
3165 * \param pvt DAHDI private structure
3166 * \param caller Caller-id information to set.
3167 */
3168static void my_set_callerid(void *pvt, const struct ast_party_caller *caller)
3169{
3170 struct dahdi_pvt *p = pvt;
3171
3173 S_COR(caller->id.number.valid, caller->id.number.str, ""),
3174 sizeof(p->cid_num));
3176 S_COR(caller->id.name.valid, caller->id.name.str, ""),
3177 sizeof(p->cid_name));
3179 S_COR(caller->id.subaddress.valid, caller->id.subaddress.str, ""),
3180 sizeof(p->cid_subaddr));
3181 p->cid_ton = caller->id.number.plan;
3183 if (caller->id.tag) {
3184 ast_copy_string(p->cid_tag, caller->id.tag, sizeof(p->cid_tag));
3185 }
3186 ast_copy_string(p->cid_ani,
3187 S_COR(caller->ani.number.valid, caller->ani.number.str, ""),
3188 sizeof(p->cid_ani));
3189 p->cid_ani2 = caller->ani2;
3190}
3191#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3192
3193#if defined(HAVE_PRI) || defined(HAVE_SS7)
3194/*!
3195 * \internal
3196 * \brief Set the Dialed Number Identifier.
3197 * \since 1.8
3198 *
3199 * \param pvt DAHDI private structure
3200 * \param dnid Dialed Number Identifier string.
3201 */
3202static void my_set_dnid(void *pvt, const char *dnid)
3203{
3204 struct dahdi_pvt *p = pvt;
3205
3206 ast_copy_string(p->dnid, dnid, sizeof(p->dnid));
3207}
3208#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3209
3210#if defined(HAVE_PRI)
3211/*!
3212 * \internal
3213 * \brief Set the Redirecting Directory Number Information Service (RDNIS).
3214 * \since 1.8
3215 *
3216 * \param pvt DAHDI private structure
3217 * \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
3218 */
3219static void my_set_rdnis(void *pvt, const char *rdnis)
3220{
3221 struct dahdi_pvt *p = pvt;
3222
3223 ast_copy_string(p->rdnis, rdnis, sizeof(p->rdnis));
3224}
3225#endif /* defined(HAVE_PRI) */
3226
3227#if defined(HAVE_PRI)
3228/*!
3229 * \internal
3230 * \brief Make a dialstring for native ISDN CC to recall properly.
3231 * \since 1.8
3232 *
3233 * \param priv Channel private control structure.
3234 * \param buf Where to put the modified dialstring.
3235 * \param buf_size Size of modified dialstring buffer.
3236 *
3237 * \details
3238 * original dialstring:
3239 * \verbatim
3240 DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3241 \endverbatim
3242 *
3243 * The modified dialstring will have prefixed the channel-group section
3244 * with the ISDN channel restriction.
3245 *
3246 * buf:
3247 * \verbatim
3248 DAHDI/i<span>-(g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3249 \endverbatim
3250 *
3251 * The routine will check to see if the ISDN channel restriction is already
3252 * in the original dialstring.
3253 */
3254static void my_pri_make_cc_dialstring(void *priv, char *buf, size_t buf_size)
3255{
3256 char *dial;
3257 struct dahdi_pvt *pvt;
3259 AST_APP_ARG(tech); /* channel technology token */
3260 AST_APP_ARG(group); /* channel/group token */
3261 //AST_APP_ARG(ext); /* extension token */
3262 //AST_APP_ARG(opts); /* options token */
3263 //AST_APP_ARG(other); /* Any remaining unused arguments */
3264 );
3265
3266 pvt = priv;
3267 dial = ast_strdupa(pvt->dialstring);
3268 AST_NONSTANDARD_APP_ARGS(args, dial, '/');
3269 if (!args.tech) {
3270 ast_copy_string(buf, pvt->dialstring, buf_size);
3271 return;
3272 }
3273 if (!args.group) {
3274 /* Append the ISDN span channel restriction to the dialstring. */
3275 snprintf(buf, buf_size, "%s/i%d-", args.tech, pvt->pri->span);
3276 return;
3277 }
3278 if (isdigit(args.group[0]) || args.group[0] == 'i' || strchr(args.group, '!')) {
3279 /* The ISDN span channel restriction is not needed or already
3280 * in the dialstring. */
3281 ast_copy_string(buf, pvt->dialstring, buf_size);
3282 return;
3283 }
3284 /* Insert the ISDN span channel restriction into the dialstring. */
3285 snprintf(buf, buf_size, "%s/i%d-%s", args.tech, pvt->pri->span, args.group);
3286}
3287#endif /* defined(HAVE_PRI) */
3288
3289#if defined(HAVE_PRI)
3290/*!
3291 * \internal
3292 * \brief Reevaluate the PRI span device state.
3293 * \since 1.8
3294 *
3295 * \param pri Asterisk D channel control structure.
3296 *
3297 * \note Assumes the pri->lock is already obtained.
3298 */
3299static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
3300{
3301 unsigned idx;
3302 unsigned num_b_chans; /* Number of B channels provisioned on the span. */
3303 unsigned in_use; /* Number of B channels in use on the span. */
3304 unsigned in_alarm; /* TRUE if the span is in alarm condition. */
3305 enum ast_device_state new_state;
3306
3307 /* Count the number of B channels and the number of B channels in use. */
3308 num_b_chans = 0;
3309 in_use = 0;
3310 in_alarm = 1;
3311 for (idx = pri->numchans; idx--;) {
3312 if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
3313 /* This is a B channel interface. */
3314 ++num_b_chans;
3315 if (!sig_pri_is_chan_available(pri->pvts[idx])) {
3316 ++in_use;
3317 }
3318 if (!pri->pvts[idx]->inalarm) {
3319 /* There is a channel that is not in alarm. */
3320 in_alarm = 0;
3321 }
3322 }
3323 }
3324
3325 /* Update the span congestion device state and report any change. */
3326 if (in_alarm) {
3327 new_state = AST_DEVICE_UNAVAILABLE;
3328 } else {
3329 new_state = num_b_chans == in_use ? AST_DEVICE_BUSY : AST_DEVICE_NOT_INUSE;
3330 }
3331 if (pri->congestion_devstate != new_state) {
3332 pri->congestion_devstate = new_state;
3334 }
3335#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
3336 /* Update the span threshold device state and report any change. */
3337 if (in_alarm) {
3338 new_state = AST_DEVICE_UNAVAILABLE;
3339 } else if (!in_use) {
3340 new_state = AST_DEVICE_NOT_INUSE;
3341 } else if (!pri->user_busy_threshold) {
3342 new_state = in_use < num_b_chans ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
3343 } else {
3344 new_state = in_use < pri->user_busy_threshold ? AST_DEVICE_INUSE
3346 }
3347 if (pri->threshold_devstate != new_state) {
3348 pri->threshold_devstate = new_state;
3350 }
3351#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
3352}
3353#endif /* defined(HAVE_PRI) */
3354
3355#if defined(HAVE_PRI)
3356/*!
3357 * \internal
3358 * \brief Reference this module.
3359 * \since 1.8
3360 */
3361static void my_module_ref(void)
3362{
3364}
3365#endif /* defined(HAVE_PRI) */
3366
3367#if defined(HAVE_PRI)
3368/*!
3369 * \internal
3370 * \brief Unreference this module.
3371 * \since 1.8
3372 */
3373static void my_module_unref(void)
3374{
3376}
3377#endif /* defined(HAVE_PRI) */
3378
3379#if defined(HAVE_PRI)
3380#if defined(HAVE_PRI_CALL_WAITING)
3381static void my_pri_init_config(void *priv, struct sig_pri_span *pri);
3382#endif /* defined(HAVE_PRI_CALL_WAITING) */
3383static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri);
3384
3386{
3387 .handle_dchan_exception = my_handle_dchan_exception,
3388 .play_tone = my_pri_play_tone,
3389 .set_echocanceller = my_set_echocanceller,
3390 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3391 .lock_private = my_lock_private,
3392 .unlock_private = my_unlock_private,
3393 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3394 .new_ast_channel = my_new_pri_ast_channel,
3395 .fixup_chans = my_pri_fixup_chans,
3396 .set_alarm = my_set_alarm,
3397 .set_dialing = my_set_dialing,
3398 .set_outgoing = my_set_outgoing,
3399 .set_digital = my_set_digital,
3400 .set_callerid = my_set_callerid,
3401 .set_dnid = my_set_dnid,
3402 .set_rdnis = my_set_rdnis,
3403 .new_nobch_intf = dahdi_new_pri_nobch_channel,
3404#if defined(HAVE_PRI_CALL_WAITING)
3405 .init_config = my_pri_init_config,
3406#endif /* defined(HAVE_PRI_CALL_WAITING) */
3407 .get_orig_dialstring = my_get_orig_dialstring,
3408 .make_cc_dialstring = my_pri_make_cc_dialstring,
3409 .update_span_devstate = dahdi_pri_update_span_devstate,
3410 .module_ref = my_module_ref,
3411 .module_unref = my_module_unref,
3412 .dial_digits = my_pri_dial_digits,
3413 .open_media = my_pri_ss7_open_media,
3414 .ami_channel_event = my_ami_channel_event,
3415 .destroy_later = pri_queue_for_destruction,
3416};
3417#endif /* defined(HAVE_PRI) */
3418
3419#if defined(HAVE_SS7)
3420/*!
3421 * \internal
3422 * \brief Handle the SS7 link exception.
3423 * \since 1.8
3424 *
3425 * \param linkset Controlling linkset for the channel.
3426 * \param which Link index of the signaling channel.
3427 */
3428static void my_handle_link_exception(struct sig_ss7_linkset *linkset, int which)
3429{
3430 int event;
3431
3432 if (ioctl(linkset->fds[which], DAHDI_GETEVENT, &event)) {
3433 ast_log(LOG_ERROR, "SS7: Error in exception retrieval on span %d/%d!\n",
3434 linkset->span, which);
3435 return;
3436 }
3437 switch (event) {
3438 case DAHDI_EVENT_NONE:
3439 break;
3440 case DAHDI_EVENT_ALARM:
3441 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3442 event2str(event), event, linkset->span, which);
3443 sig_ss7_link_alarm(linkset, which);
3444 break;
3445 case DAHDI_EVENT_NOALARM:
3446 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3447 event2str(event), event, linkset->span, which);
3448 sig_ss7_link_noalarm(linkset, which);
3449 break;
3450 default:
3451 ast_log(LOG_NOTICE, "SS7 got event: %s(%d) on span %d/%d\n",
3452 event2str(event), event, linkset->span, which);
3453 break;
3454 }
3455}
3456#endif /* defined(HAVE_SS7) */
3457
3458#if defined(HAVE_SS7)
3459static void my_ss7_set_loopback(void *pvt, int enable)
3460{
3461 struct dahdi_pvt *p = pvt;
3462
3463 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
3464 ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel,
3465 strerror(errno));
3466 }
3467}
3468#endif /* defined(HAVE_SS7) */
3469
3470#if defined(HAVE_SS7)
3471/*!
3472 * \internal
3473 * \brief Find the linkset to which SS7 belongs.
3474 * \since 11.0
3475 *
3476 * \param ss7 structure to match on.
3477 *
3478 * \retval linkset if found.
3479 * \retval NULL if not found.
3480 */
3481static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
3482{
3483 int idx;
3484
3485 if (!ss7) {
3486 return NULL;
3487 }
3488
3489 for (idx = 0; idx < NUM_SPANS; ++idx) {
3490 if (linksets[idx].ss7.ss7 == ss7) {
3491 return &linksets[idx].ss7;
3492 }
3493 }
3494 return NULL;
3495}
3496#endif /* defined(HAVE_SS7) */
3497
3498#if defined(HAVE_SS7)
3499/*!
3500 * \internal
3501 * \brief Create a new asterisk channel structure for SS7.
3502 * \since 1.8
3503 *
3504 * \param pvt Private channel structure.
3505 * \param state Initial state of new channel.
3506 * \param law Companding law to use.
3507 * \param exten Dialplan extension for incoming call.
3508 * \param requestor Channel requesting this new channel.
3509 * \param assignedids
3510 *
3511 * \retval ast_channel on success.
3512 * \retval NULL on error.
3513 */
3514static 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)
3515{
3516 struct dahdi_pvt *p = pvt;
3517 int audio;
3518 int newlaw;
3519 ast_callid callid = 0;
3520 int callid_created = ast_callid_threadstorage_auto(&callid);
3521
3522 /* Set to audio mode at this point */
3523 audio = 1;
3524 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1)
3525 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
3526 p->channel, audio, strerror(errno));
3527
3528 if (law != SIG_SS7_DEFLAW) {
3529 dahdi_setlaw(p->subs[SUB_REAL].dfd,
3530 (law == SIG_SS7_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
3531 }
3532
3533 ast_copy_string(p->exten, exten, sizeof(p->exten));
3534
3535 newlaw = -1;
3536 switch (law) {
3537 case SIG_SS7_DEFLAW:
3538 newlaw = 0;
3539 break;
3540 case SIG_SS7_ALAW:
3541 newlaw = DAHDI_LAW_ALAW;
3542 break;
3543 case SIG_SS7_ULAW:
3544 newlaw = DAHDI_LAW_MULAW;
3545 break;
3546 }
3547 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
3548}
3549#endif /* defined(HAVE_SS7) */
3550
3551#if defined(HAVE_SS7)
3552static int sig_ss7_tone_to_dahditone(enum sig_ss7_tone tone)
3553{
3554 switch (tone) {
3556 return DAHDI_TONE_RINGTONE;
3558 return DAHDI_TONE_STUTTER;
3560 return DAHDI_TONE_CONGESTION;
3562 return DAHDI_TONE_DIALTONE;
3564 return DAHDI_TONE_DIALRECALL;
3565 case SIG_SS7_TONE_INFO:
3566 return DAHDI_TONE_INFO;
3567 case SIG_SS7_TONE_BUSY:
3568 return DAHDI_TONE_BUSY;
3569 default:
3570 return -1;
3571 }
3572}
3573#endif /* defined(HAVE_SS7) */
3574
3575#if defined(HAVE_SS7)
3576static int my_ss7_play_tone(void *pvt, enum sig_ss7_tone tone)
3577{
3578 struct dahdi_pvt *p = pvt;
3579
3580 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_ss7_tone_to_dahditone(tone));
3581}
3582#endif /* defined(HAVE_SS7) */
3583
3584#if defined(HAVE_SS7)
3586{
3588 .unlock_private = my_unlock_private,
3589 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3590
3591 .set_echocanceller = my_set_echocanceller,
3592 .set_loopback = my_ss7_set_loopback,
3593
3594 .new_ast_channel = my_new_ss7_ast_channel,
3595 .play_tone = my_ss7_play_tone,
3596
3597 .handle_link_exception = my_handle_link_exception,
3598 .set_alarm = my_set_alarm,
3599 .set_dialing = my_set_dialing,
3600 .set_outgoing = my_set_outgoing,
3601 .set_digital = my_set_digital,
3602 .set_inservice = my_set_inservice,
3603 .set_locallyblocked = my_set_locallyblocked,
3604 .set_remotelyblocked = my_set_remotelyblocked,
3605 .set_callerid = my_set_callerid,
3606 .set_dnid = my_set_dnid,
3607 .open_media = my_pri_ss7_open_media,
3608 .find_linkset = my_ss7_find_linkset,
3609};
3610#endif /* defined(HAVE_SS7) */
3611
3612/*!
3613 * \brief Send MWI state change
3614 *
3615 * \param mailbox This is the mailbox associated with the FXO line that the
3616 * MWI state has changed on.
3617 * \param thereornot This argument should simply be set to 1 or 0, to indicate
3618 * whether there are messages waiting or not.
3619 *
3620 * This function does two things:
3621 *
3622 * 1) It generates an internal Asterisk event notifying any other module that
3623 * cares about MWI that the state of a mailbox has changed.
3624 *
3625 * 2) It runs the script specified by the mwimonitornotify option to allow
3626 * some custom handling of the state change.
3627 */
3628static void notify_message(char *mailbox, int thereornot)
3629{
3630 char s[sizeof(mwimonitornotify) + 164];
3631
3632 if (ast_strlen_zero(mailbox)) {
3633 return;
3634 }
3635
3636 ast_publish_mwi_state(mailbox, NULL, thereornot, thereornot);
3638 snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
3639 ast_safe_system(s);
3640 }
3641}
3642
3643static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
3644{
3645 struct dahdi_pvt *p = pvt;
3646
3647 if (neon_mwievent > -1 && !p->mwimonitor_neon)
3648 return;
3649
3650 if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
3651 ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
3652 notify_message(p->mailbox, 1);
3653 } else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
3654 ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
3655 notify_message(p->mailbox, 0);
3656 }
3657 /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
3658 /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
3659 if (neon_mwievent == -1 && p->mwimonitor_rpas) {
3660 ast_hangup(chan);
3661 return;
3662 }
3663}
3664
3665static int my_have_progressdetect(void *pvt)
3666{
3667 struct dahdi_pvt *p = pvt;
3668
3670 && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
3671 return 1;
3672 } else {
3673 /* Don't have progress detection. */
3674 return 0;
3675 }
3676}
3677
3678#define gen_pvt_field_callback(type, field) \
3679 static type my_get_##field(void *pvt) \
3680 { \
3681 struct dahdi_pvt *p = pvt; \
3682 return p->field; \
3683 }
3684
3688
3689#undef gen_pvt_field_callback
3690
3692{
3694 .get_event = my_get_event,
3695 .wait_event = my_wait_event,
3696 .is_off_hook = my_is_off_hook,
3697 .set_echocanceller = my_set_echocanceller,
3698 .ring = my_ring,
3699 .flash = my_flash,
3700 .off_hook = my_off_hook,
3701 .dial_digits = my_dial_digits,
3702 .train_echocanceller = my_train_echocanceller,
3703 .on_hook = my_on_hook,
3704 .is_dialing = my_is_dialing,
3705 .allocate_sub = my_allocate_sub,
3706 .unallocate_sub = my_unallocate_sub,
3707 .swap_subs = my_swap_subchannels,
3708 .has_voicemail = my_has_voicemail,
3709 .check_for_conference = my_check_for_conference,
3710 .conf_add = my_conf_add,
3711 .conf_del = my_conf_del,
3712 .complete_conference_update = my_complete_conference_update,
3713 .start = my_start,
3714 .all_subchannels_hungup = my_all_subchannels_hungup,
3715 .lock_private = my_lock_private,
3716 .unlock_private = my_unlock_private,
3717 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3718 .handle_dtmf = my_handle_dtmf,
3719 .wink = my_wink,
3720 .new_ast_channel = my_new_analog_ast_channel,
3721 .dsp_set_digitmode = my_dsp_set_digitmode,
3722 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3723 .send_callerid = my_send_callerid,
3724 .callwait = my_callwait,
3725 .stop_callwait = my_stop_callwait,
3726 .get_callerid = my_get_callerid,
3727 .start_cid_detect = my_start_cid_detect,
3728 .stop_cid_detect = my_stop_cid_detect,
3729 .handle_notify_message = my_handle_notify_message,
3730 .increase_ss_count = my_increase_ss_count,
3731 .decrease_ss_count = my_decrease_ss_count,
3732 .distinctive_ring = my_distinctive_ring,
3733 .set_linear_mode = my_set_linear_mode,
3734 .set_inthreeway = my_set_inthreeway,
3735 .get_and_handle_alarms = my_get_and_handle_alarms,
3736 .get_sigpvt_bridged_channel = my_get_sigpvt_bridged_channel,
3737 .get_sub_fd = my_get_sub_fd,
3738 .set_cadence = my_set_cadence,
3739 .set_alarm = my_set_alarm,
3740 .set_dialing = my_set_dialing,
3741 .set_outgoing = my_set_outgoing,
3742 .set_ringtimeout = my_set_ringtimeout,
3743 .set_waitingfordt = my_set_waitingfordt,
3744 .check_waitingfordt = my_check_waitingfordt,
3745 .set_confirmanswer = my_set_confirmanswer,
3746 .check_confirmanswer = my_check_confirmanswer,
3747 .set_callwaiting = my_set_callwaiting,
3748 .cancel_cidspill = my_cancel_cidspill,
3749 .confmute = my_confmute,
3750 .set_pulsedial = my_set_pulsedial,
3751 .set_new_owner = my_set_new_owner,
3752 .get_orig_dialstring = my_get_orig_dialstring,
3753 .set_needringing = my_set_needringing,
3754 .set_polarity = my_set_polarity,
3755 .start_polarityswitch = my_start_polarityswitch,
3756 .answer_polarityswitch = my_answer_polarityswitch,
3757 .hangup_polarityswitch = my_hangup_polarityswitch,
3758 .have_progressdetect = my_have_progressdetect,
3759 .get_firstdigit_timeout = my_get_firstdigit_timeout,
3760 .get_matchdigit_timeout = my_get_matchdigit_timeout,
3761 .get_interdigit_timeout = my_get_interdigit_timeout,
3762};
3763
3764/*! Round robin search locations. */
3765static struct dahdi_pvt *round_robin[64]; /* groups can range from 0-63 */
3766
3767int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
3768{
3769 int res;
3770 if (p->subs[SUB_REAL].owner == ast)
3771 res = 0;
3772 else if (p->subs[SUB_CALLWAIT].owner == ast)
3773 res = 1;
3774 else if (p->subs[SUB_THREEWAY].owner == ast)
3775 res = 2;
3776 else {
3777 res = -1;
3778 if (!nullok)
3780 "Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
3781 ast ? ast_channel_name(ast) : "", p->channel, fname, line);
3782 }
3783 return res;
3784}
3785
3786/*!
3787 * \internal
3788 * \brief Obtain the specified subchannel owner lock if the owner exists.
3789 *
3790 * \param pvt Channel private struct.
3791 * \param sub_idx Subchannel owner to lock.
3792 *
3793 * \note Assumes the pvt->lock is already obtained.
3794 *
3795 * \note
3796 * Because deadlock avoidance may have been necessary, you need to confirm
3797 * the state of things before continuing.
3798 */
3799static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
3800{
3801 for (;;) {
3802 if (!pvt->subs[sub_idx].owner) {
3803 /* No subchannel owner pointer */
3804 break;
3805 }
3806 if (!ast_channel_trylock(pvt->subs[sub_idx].owner)) {
3807 /* Got subchannel owner lock */
3808 break;
3809 }
3810 /* We must unlock the private to avoid the possibility of a deadlock */
3811 DEADLOCK_AVOIDANCE(&pvt->lock);
3812 }
3813}
3814
3815static void wakeup_sub(struct dahdi_pvt *p, int a)
3816{
3818 if (p->subs[a].owner) {
3821 }
3822}
3823
3824static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
3825{
3826 for (;;) {
3827 if (p->owner) {
3828 if (ast_channel_trylock(p->owner)) {
3830 } else {
3831 ast_queue_frame(p->owner, f);
3833 break;
3834 }
3835 } else
3836 break;
3837 }
3838}
3839
3841{
3842 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3843 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
3844 if (!dahdi_chan) {
3845 return;
3846 }
3847
3848 ast_str_set(&dahdi_chan, 0, "%d", channel);
3849 ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
3850 body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
3851 if (!body) {
3852 return;
3853 }
3854
3855 ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
3856}
3857
3859{
3860 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3861
3862 ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
3863 body = ast_json_pack("{s: i}", "Span", span);
3864 if (!body) {
3865 return;
3866 }
3867
3868 ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
3869}
3870
3871static void handle_clear_alarms(struct dahdi_pvt *p)
3872{
3873#if defined(HAVE_PRI)
3875 return;
3876 }
3877#endif /* defined(HAVE_PRI) */
3878
3881 }
3884 }
3885}
3886
3887#ifdef HAVE_OPENR2
3888static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
3889{
3890 const struct dahdi_mfcr2 *r2link = p->mfcr2;
3891 struct r2link_entry *cur;
3892 AST_LIST_LOCK(&r2links);
3893 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
3894 if (r2link == &cur->mfcr2) {
3895 ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
3896 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
3897 break;
3898 }
3899 }
3901 AST_LIST_UNLOCK(&r2links);
3902}
3903
3904static int dahdi_r2_answer(struct dahdi_pvt *p)
3905{
3906 int res = 0;
3907 /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
3908 * and does not has support for openr2_chan_answer_call_with_mode
3909 * */
3910#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
3911 const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
3912 int wants_double_answer = ast_true(double_answer) ? 1 : 0;
3913 if (!double_answer) {
3914 /* this still can result in double answer if the channel context
3915 * was configured that way */
3916 res = openr2_chan_answer_call(p->r2chan);
3917 } else if (wants_double_answer) {
3918 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
3919 } else {
3920 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
3921 }
3922#else
3923 res = openr2_chan_answer_call(p->r2chan);
3924#endif
3925 return res;
3926}
3927
3928
3929
3930/* should be called with the ast_channel locked */
3931static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
3932{
3933 openr2_calling_party_category_t cat;
3934 const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
3935 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
3936 if (ast_strlen_zero(catstr)) {
3937 ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
3938 ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3939 return p->mfcr2_category;
3940 }
3941 if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
3942 ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
3943 catstr, ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3944 return p->mfcr2_category;
3945 }
3946 ast_debug(1, "Using category %s\n", catstr);
3947 return cat;
3948}
3949
3950static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
3951{
3952 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3953 ast_mutex_lock(&p->lock);
3954 if (p->mfcr2call) {
3956 /* TODO: This can happen when some other thread just finished dahdi_request requesting this very same
3957 interface but has not yet seized the line (dahdi_call), and the far end wins and seize the line,
3958 can we avoid this somehow?, at this point when dahdi_call send the seize, it is likely that since
3959 the other end will see our seize as a forced release and drop the call, we will see an invalid
3960 pattern that will be seen and treated as protocol error. */
3961 ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
3962 return;
3963 }
3964 p->mfcr2call = 1;
3965 /* better safe than sorry ... */
3966 p->cid_name[0] = '\0';
3967 p->cid_num[0] = '\0';
3968 p->cid_subaddr[0] = '\0';
3969 p->rdnis[0] = '\0';
3970 p->exten[0] = '\0';
3971 p->mfcr2_ani_index = '\0';
3972 p->mfcr2_dnis_index = '\0';
3973 p->mfcr2_dnis_matched = 0;
3974 p->mfcr2_answer_pending = 0;
3975 p->mfcr2_call_accepted = 0;
3977 ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
3978}
3979
3980static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
3981{
3982 int res;
3983 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3984 ast_mutex_lock(&p->lock);
3985 p->inalarm = alarm ? 1 : 0;
3986 if (p->inalarm) {
3987 res = get_alarms(p);
3988 if (res == DAHDI_ALARM_NOTOPEN) {
3989 mfcr2_queue_for_destruction(p);
3990 }
3991 handle_alarms(p, res);
3992 } else {
3994 }
3996}
3997
3998static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
3999{
4000 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4001
4002 ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
4003 ast_mutex_lock(&p->lock);
4004 /* Disconnected? */
4005 if (errorcode == ENODEV) {
4006 struct dahdi_mfcr2 *r2link = p->mfcr2;
4007 p->mfcr2call = 0;
4008 if (r2link) {
4009 r2link->nodev = 1;
4010 }
4011 }
4013}
4014
4015static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
4016{
4017 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4018 ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
4019 if (p->owner) {
4022 }
4023 ast_mutex_lock(&p->lock);
4024 p->mfcr2call = 0;
4026}
4027
4028static void dahdi_r2_disconnect_call(struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
4029{
4030 if (openr2_chan_disconnect_call(p->r2chan, cause)) {
4031 ast_log(LOG_NOTICE, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
4032 p->channel, openr2_proto_get_disconnect_string(cause));
4033 /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
4034 openr2_chan_set_idle(p->r2chan);
4035 ast_mutex_lock(&p->lock);
4036 p->mfcr2call = 0;
4038 }
4039}
4040
4041static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
4042{
4043 struct dahdi_pvt *p;
4044 struct ast_channel *c;
4045 ast_callid callid = 0;
4046 int callid_created = ast_callid_threadstorage_auto(&callid);
4047 ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
4048 openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
4049 openr2_proto_get_category_string(category));
4050 p = openr2_chan_get_client_data(r2chan);
4051 /* if collect calls are not allowed and this is a collect call, reject it! */
4052 if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
4053 ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call\n");
4054 dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
4055 goto dahdi_r2_on_call_offered_cleanup;
4056 }
4057 ast_mutex_lock(&p->lock);
4058 p->mfcr2_recvd_category = category;
4059 /* if we're not supposed to use CID, clear whatever we have */
4060 if (!p->use_callerid) {
4061 ast_debug(1, "No CID allowed in configuration, CID is being cleared!\n");
4062 p->cid_num[0] = 0;
4063 p->cid_name[0] = 0;
4064 }
4065 /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
4066 if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
4067 ast_debug(1, "Setting exten => s because of immediate or 0 DNIS configured\n");
4068 p->exten[0] = 's';
4069 p->exten[1] = 0;
4070 }
4072 if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
4073 ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
4074 p->channel, p->exten, p->context);
4075 dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
4076 goto dahdi_r2_on_call_offered_cleanup;
4077 }
4078 if (!p->mfcr2_accept_on_offer) {
4079 /* The user wants us to start the PBX thread right away without accepting the call first */
4080 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4081 if (c) {
4082 /* Done here, don't disable reading now since we still need to generate MF tones to accept
4083 the call or reject it and detect the tone off condition of the other end, all of this
4084 will be done in the PBX thread now */
4085 goto dahdi_r2_on_call_offered_cleanup;
4086 }
4087 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4088 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4089 } else if (p->mfcr2_charge_calls) {
4090 ast_debug(1, "Accepting MFC/R2 call with charge on chan %d\n", p->channel);
4091 openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
4092 } else {
4093 ast_debug(1, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
4094 openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
4095 }
4096
4097dahdi_r2_on_call_offered_cleanup:
4099}
4100
4101static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
4102{
4103 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4104 ast_verbose("MFC/R2 call end on channel %d\n", p->channel);
4105 ast_mutex_lock(&p->lock);
4106 p->mfcr2call = 0;
4108}
4109
4110static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
4111{
4112 struct dahdi_pvt *p = NULL;
4113 struct ast_channel *c = NULL;
4114 ast_callid callid = 0;
4115 int callid_created = ast_callid_threadstorage_auto(&callid);
4116 p = openr2_chan_get_client_data(r2chan);
4117 dahdi_ec_enable(p);
4118 p->mfcr2_call_accepted = 1;
4119 /* if it's an incoming call ... */
4120 if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
4121 ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
4122 /* If accept on offer is not set, it means at this point the PBX thread is already
4123 launched (was launched in the 'on call offered' handler) and therefore this callback
4124 is being executed already in the PBX thread rather than the monitor thread, don't launch
4125 any other thread, just disable the openr2 reading and answer the call if needed */
4126 if (!p->mfcr2_accept_on_offer) {
4127 openr2_chan_disable_read(r2chan);
4128 if (p->mfcr2_answer_pending) {
4129 ast_debug(1, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
4130 dahdi_r2_answer(p);
4131 }
4132 goto dahdi_r2_on_call_accepted_cleanup;
4133 }
4134 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4135 if (c) {
4136 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
4137 library to forget about it */
4138 openr2_chan_disable_read(r2chan);
4139 goto dahdi_r2_on_call_accepted_cleanup;
4140 }
4141 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4142 /* failed to create the channel, bail out and report it as an out of order line */
4143 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4144 goto dahdi_r2_on_call_accepted_cleanup;
4145 }
4146 /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
4147 ast_verbose("MFC/R2 call has been accepted on forward channel %d\n", p->channel);
4148 p->subs[SUB_REAL].needringing = 1;
4149 p->dialing = 0;
4150 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the library to forget about it */
4151 openr2_chan_disable_read(r2chan);
4152
4153dahdi_r2_on_call_accepted_cleanup:
4155}
4156
4157static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
4158{
4159 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4160 ast_verbose("MFC/R2 call has been answered on channel %d\n", openr2_chan_get_number(r2chan));
4161 p->subs[SUB_REAL].needanswer = 1;
4162}
4163
4164static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
4165{
4166 /*ast_debug(1, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
4167}
4168
4169static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
4170{
4171 switch (cause) {
4172 case OR2_CAUSE_BUSY_NUMBER:
4173 return AST_CAUSE_BUSY;
4174 case OR2_CAUSE_NETWORK_CONGESTION:
4175 return AST_CAUSE_CONGESTION;
4176 case OR2_CAUSE_OUT_OF_ORDER:
4178 case OR2_CAUSE_UNALLOCATED_NUMBER:
4180 case OR2_CAUSE_NO_ANSWER:
4181 return AST_CAUSE_NO_ANSWER;
4182 case OR2_CAUSE_NORMAL_CLEARING:
4184 case OR2_CAUSE_UNSPECIFIED:
4185 default:
4186 return AST_CAUSE_NOTDEFINED;
4187 }
4188}
4189
4190static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
4191{
4192 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4193 char cause_str[50];
4194 struct ast_control_pvt_cause_code *cause_code;
4195 int datalen = sizeof(*cause_code);
4196
4197 ast_verbose("MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan));
4198 ast_mutex_lock(&p->lock);
4199 if (!p->owner) {
4201 /* no owner, therefore we can't use dahdi_hangup to disconnect, do it right now */
4202 dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
4203 return;
4204 }
4205
4206 snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
4207 datalen += strlen(cause_str);
4208 cause_code = ast_alloca(datalen);
4209 memset(cause_code, 0, datalen);
4210 cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
4212 ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
4214 ast_channel_hangupcause_hash_set(p->owner, cause_code, datalen);
4216
4217 /* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
4218 be done in dahdi_hangup */
4222 } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
4223 /* being the forward side we must report what happened to the call to whoever requested it */
4224 switch (cause) {
4225 case OR2_CAUSE_BUSY_NUMBER:
4226 p->subs[SUB_REAL].needbusy = 1;
4227 break;
4228 case OR2_CAUSE_NETWORK_CONGESTION:
4229 case OR2_CAUSE_OUT_OF_ORDER:
4230 case OR2_CAUSE_UNALLOCATED_NUMBER:
4231 case OR2_CAUSE_NO_ANSWER:
4232 case OR2_CAUSE_UNSPECIFIED:
4233 case OR2_CAUSE_NORMAL_CLEARING:
4235 break;
4236 default:
4238 }
4240 } else {
4242 /* being the backward side and not UP yet, we only need to request hangup */
4243 /* TODO: what about doing this same thing when were AST_STATE_UP? */
4244 ast_queue_hangup_with_cause(p->owner, dahdi_r2_cause_to_ast_cause(cause));
4245 }
4246}
4247
4248static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
4249{
4250 switch (level) {
4251 case OR2_LOG_NOTICE:
4252 ast_verbose("%s", logmessage);
4253 break;
4254 case OR2_LOG_WARNING:
4255 ast_log(LOG_WARNING, "%s", logmessage);
4256 break;
4257 case OR2_LOG_ERROR:
4258 ast_log(LOG_ERROR, "%s", logmessage);
4259 break;
4260 case OR2_LOG_STACK_TRACE:
4261 case OR2_LOG_MF_TRACE:
4262 case OR2_LOG_CAS_TRACE:
4263 case OR2_LOG_DEBUG:
4264 case OR2_LOG_EX_DEBUG:
4265 ast_debug(1, "%s", logmessage);
4266 break;
4267 default:
4268 ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
4269 ast_debug(1, "%s", logmessage);
4270 break;
4271 }
4272}
4273
4274static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
4275{
4276 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4277 ast_mutex_lock(&p->lock);
4278 p->remotelyblocked = 1;
4280 ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
4281}
4282
4283static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
4284{
4285 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4286 ast_mutex_lock(&p->lock);
4287 p->remotelyblocked = 0;
4289 ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
4290}
4291
4292static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4293 __attribute__((format (printf, 3, 0)));
4294static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4295{
4296#define CONTEXT_TAG "Context - "
4297 char logmsg[256];
4298 char completemsg[sizeof(logmsg) * 2];
4299 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4300 snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
4301 dahdi_r2_write_log(level, completemsg);
4302#undef CONTEXT_TAG
4303}
4304
4305static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4306 __attribute__((format (printf, 3, 0)));
4307static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4308{
4309#define CHAN_TAG "Chan "
4310 char logmsg[256];
4311 char completemsg[sizeof(logmsg) * 2];
4312 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4313 snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
4314 dahdi_r2_write_log(level, completemsg);
4315#undef CHAN_TAG
4316}
4317
4318static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
4319{
4320 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4321 /* if 'immediate' is set, let's stop requesting DNIS */
4322 if (p->immediate) {
4323 return 0;
4324 }
4325 p->exten[p->mfcr2_dnis_index] = digit;
4326 p->rdnis[p->mfcr2_dnis_index] = digit;
4327 p->mfcr2_dnis_index++;
4328 p->exten[p->mfcr2_dnis_index] = 0;
4329 p->rdnis[p->mfcr2_dnis_index] = 0;
4330 /* if the DNIS is a match and cannot match more, stop requesting DNIS */
4331 if ((p->mfcr2_dnis_matched ||
4332 (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
4334 return 0;
4335 }
4336 /* otherwise keep going */
4337 return 1;
4338}
4339
4340static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
4341{
4342 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4343 p->cid_num[p->mfcr2_ani_index] = digit;
4344 p->cid_name[p->mfcr2_ani_index] = digit;
4345 p->mfcr2_ani_index++;
4346 p->cid_num[p->mfcr2_ani_index] = 0;
4347 p->cid_name[p->mfcr2_ani_index] = 0;
4348}
4349
4350static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
4351{
4352 ast_verbose("MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
4353}
4354
4355static openr2_event_interface_t dahdi_r2_event_iface = {
4356 .on_call_init = dahdi_r2_on_call_init,
4357 .on_call_offered = dahdi_r2_on_call_offered,
4358 .on_call_accepted = dahdi_r2_on_call_accepted,
4359 .on_call_answered = dahdi_r2_on_call_answered,
4360 .on_call_disconnect = dahdi_r2_on_call_disconnect,
4361 .on_call_end = dahdi_r2_on_call_end,
4362 .on_call_read = dahdi_r2_on_call_read,
4363 .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
4364 .on_os_error = dahdi_r2_on_os_error,
4365 .on_protocol_error = dahdi_r2_on_protocol_error,
4366 .on_line_blocked = dahdi_r2_on_line_blocked,
4367 .on_line_idle = dahdi_r2_on_line_idle,
4368 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
4369 .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
4370 .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
4371 .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
4372 /* so far we do nothing with billing pulses */
4373 .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
4374};
4375
4376static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
4377{
4378 return AST_ALAW(sample);
4379}
4380
4381static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
4382{
4383 return AST_LIN2A(sample);
4384}
4385
4386static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
4387 dahdi_r2_alaw_to_linear,
4388 dahdi_r2_linear_to_alaw
4389};
4390
4391#endif /* HAVE_OPENR2 */
4392
4393static void swap_subs(struct dahdi_pvt *p, int a, int b)
4394{
4395 int tchan;
4396 int tinthreeway;
4397 struct ast_channel *towner;
4398
4399 ast_debug(1, "Swapping %d and %d\n", a, b);
4400
4401 tchan = p->subs[a].chan;
4402 towner = p->subs[a].owner;
4403 tinthreeway = p->subs[a].inthreeway;
4404
4405 p->subs[a].chan = p->subs[b].chan;
4406 p->subs[a].owner = p->subs[b].owner;
4407 p->subs[a].inthreeway = p->subs[b].inthreeway;
4408
4409 p->subs[b].chan = tchan;
4410 p->subs[b].owner = towner;
4411 p->subs[b].inthreeway = tinthreeway;
4412
4413 if (p->subs[a].owner)
4414 ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
4415 if (p->subs[b].owner)
4416 ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
4417 wakeup_sub(p, a);
4418 wakeup_sub(p, b);
4419}
4420
4421static int dahdi_open(char *fn)
4422{
4423 int fd;
4424 int isnum;
4425 int chan = 0;
4426 int bs;
4427 int x;
4428 isnum = 1;
4429 for (x = 0; x < strlen(fn); x++) {
4430 if (!isdigit(fn[x])) {
4431 isnum = 0;
4432 break;
4433 }
4434 }
4435 if (isnum) {
4436 chan = atoi(fn);
4437 if (chan < 1) {
4438 ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
4439 return -1;
4440 }
4441 fn = "/dev/dahdi/channel";
4442 }
4443 fd = open(fn, O_RDWR | O_NONBLOCK);
4444 if (fd < 0) {
4445 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
4446 return -1;
4447 }
4448 if (chan) {
4449 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
4450 x = errno;
4451 close(fd);
4452 errno = x;
4453 ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
4454 return -1;
4455 }
4456 }
4457 bs = READ_SIZE;
4458 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
4459 ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs, strerror(errno));
4460 x = errno;
4461 close(fd);
4462 errno = x;
4463 return -1;
4464 }
4465 return fd;
4466}
4467
4468static void dahdi_close(int fd)
4469{
4470 if (fd > 0)
4471 close(fd);
4472}
4473
4474static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
4475{
4476 dahdi_close(chan_pvt->subs[sub_num].dfd);
4477 chan_pvt->subs[sub_num].dfd = -1;
4478}
4479
4480#if defined(HAVE_PRI)
4481static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
4482{
4483 dahdi_close(pri->pri.fds[fd_num]);
4484 pri->pri.fds[fd_num] = -1;
4485}
4486#endif /* defined(HAVE_PRI) */
4487
4488#if defined(HAVE_SS7)
4489static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
4490{
4491 dahdi_close(ss7->ss7.fds[fd_num]);
4492 ss7->ss7.fds[fd_num] = -1;
4493}
4494#endif /* defined(HAVE_SS7) */
4495
4496static int dahdi_setlinear(int dfd, int linear)
4497{
4498 return ioctl(dfd, DAHDI_SETLINEAR, &linear);
4499}
4500
4501
4502static int alloc_sub(struct dahdi_pvt *p, int x)
4503{
4504 struct dahdi_bufferinfo bi;
4505 int res;
4506 if (p->subs[x].dfd >= 0) {
4507 ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
4508 return -1;
4509 }
4510
4511 p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
4512 if (p->subs[x].dfd <= -1) {
4513 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
4514 return -1;
4515 }
4516
4517 res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
4518 if (!res) {
4519 bi.txbufpolicy = p->buf_policy;
4520 bi.rxbufpolicy = p->buf_policy;
4521 bi.numbufs = p->buf_no;
4522 res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
4523 if (res < 0) {
4524 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
4525 }
4526 } else
4527 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
4528
4529 if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
4530 ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
4531 dahdi_close_sub(p, x);
4532 p->subs[x].dfd = -1;
4533 return -1;
4534 }
4535 ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
4536 return 0;
4537}
4538
4539static int unalloc_sub(struct dahdi_pvt *p, int x)
4540{
4541 if (!x) {
4542 ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
4543 return -1;
4544 }
4545 ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
4546 dahdi_close_sub(p, x);
4547 p->subs[x].linear = 0;
4548 p->subs[x].chan = 0;
4549 p->subs[x].owner = NULL;
4550 p->subs[x].inthreeway = 0;
4552 memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
4553 return 0;
4554}
4555
4557{
4558 if (isdigit(digit))
4559 return DAHDI_TONE_DTMF_BASE + (digit - '0');
4560 else if (digit >= 'A' && digit <= 'D')
4561 return DAHDI_TONE_DTMF_A + (digit - 'A');
4562 else if (digit >= 'a' && digit <= 'd')
4563 return DAHDI_TONE_DTMF_A + (digit - 'a');
4564 else if (digit == '*')
4565 return DAHDI_TONE_DTMF_s;
4566 else if (digit == '#')
4567 return DAHDI_TONE_DTMF_p;
4568 else
4569 return -1;
4570}
4571
4572static int dahdi_digit_begin(struct ast_channel *chan, char digit)
4573{
4574 struct dahdi_pvt *pvt;
4575 int idx;
4576 int dtmf;
4577 int res;
4578
4579 pvt = ast_channel_tech_pvt(chan);
4580
4581 ast_mutex_lock(&pvt->lock);
4582
4583 idx = dahdi_get_index(chan, pvt, 0);
4584
4585 if ((idx != SUB_REAL) || !pvt->owner)
4586 goto out;
4587
4588#ifdef HAVE_PRI
4589 switch (pvt->sig) {
4591 res = sig_pri_digit_begin(pvt->sig_pvt, chan, digit);
4592 if (!res)
4593 goto out;
4594 break;
4595 default:
4596 break;
4597 }
4598#endif
4599 dtmf = digit_to_dtmfindex(digit);
4600 if (dtmf == -1) {
4601 /* Not a valid DTMF digit */
4602 goto out;
4603 }
4604
4605 if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
4606 char dial_str[] = { 'T', digit, '\0' };
4607
4608 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
4609 if (!res) {
4610 pvt->dialing = 1;
4611 }
4612 } else {
4613 pvt->dialing = 1;
4614 pvt->begindigit = digit;
4615
4616 /* Flush the write buffer in DAHDI to start sending the digit immediately. */
4617 dtmf = DAHDI_FLUSH_WRITE;
4618 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &dtmf);
4619 if (res) {
4620 ast_log(LOG_WARNING, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
4621 pvt->channel, strerror(errno));
4622 }
4623
4624 ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
4625 ast_channel_name(chan), digit);
4626 }
4627
4628out:
4629 ast_mutex_unlock(&pvt->lock);
4630
4631 return 0;
4632}
4633
4634static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
4635{
4636 struct dahdi_pvt *pvt;
4637 int res = 0;
4638 int idx;
4639 int x;
4640
4641 pvt = ast_channel_tech_pvt(chan);
4642
4643 ast_mutex_lock(&pvt->lock);
4644
4645 idx = dahdi_get_index(chan, pvt, 0);
4646
4647 if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
4648 goto out;
4649
4650#ifdef HAVE_PRI
4651 /* This means that the digit was already sent via PRI signalling */
4652 if (dahdi_sig_pri_lib_handles(pvt->sig) && !pvt->begindigit) {
4653 goto out;
4654 }
4655#endif
4656
4657 if (pvt->begindigit) {
4658 x = -1;
4659 ast_debug(1, "Channel %s ending VLDTMF digit '%c'\n",
4660 ast_channel_name(chan), digit);
4661 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
4662 pvt->dialing = 0;
4663 pvt->begindigit = 0;
4664 }
4665
4666out:
4667 ast_mutex_unlock(&pvt->lock);
4668
4669 return res;
4670}
4671
4672static const char * const events[] = {
4673 "No event",
4674 "On hook",
4675 "Ring/Answered",
4676 "Wink/Flash",
4677 "Alarm",
4678 "No more alarm",
4679 "HDLC Abort",
4680 "HDLC Overrun",
4681 "HDLC Bad FCS",
4682 "Dial Complete",
4683 "Ringer On",
4684 "Ringer Off",
4685 "Hook Transition Complete",
4686 "Bits Changed",
4687 "Pulse Start",
4688 "Timer Expired",
4689 "Timer Ping",
4690 "Polarity Reversal",
4691 "Ring Begin",
4692};
4693
4694static struct {
4696 char *name;
4697} alarms[] = {
4698 { DAHDI_ALARM_RED, "Red Alarm" },
4699 { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
4700 { DAHDI_ALARM_BLUE, "Blue Alarm" },
4701 { DAHDI_ALARM_RECOVER, "Recovering" },
4702 { DAHDI_ALARM_LOOPBACK, "Loopback" },
4703 { DAHDI_ALARM_NOTOPEN, "Not Open" },
4704 { DAHDI_ALARM_NONE, "None" },
4706
4707static char *alarm2str(int alm)
4708{
4709 int x;
4710 for (x = 0; x < ARRAY_LEN(alarms); x++) {
4711 if (alarms[x].alarm & alm)
4712 return alarms[x].name;
4713 }
4714 return alm ? "Unknown Alarm" : "No Alarm";
4715}
4716
4717static const char *event2str(int event)
4718{
4719 static char buf[256];
4720 if ((event > -1) && (event < (ARRAY_LEN(events))) )
4721 return events[event];
4722 sprintf(buf, "Event %d", event); /* safe */
4723 return buf;
4724}
4725
4726static char *dahdi_sig2str(int sig)
4727{
4728 static char buf[256];
4729 switch (sig) {
4730 case SIG_EM:
4731 return "E & M Immediate";
4732 case SIG_EMWINK:
4733 return "E & M Wink";
4734 case SIG_EM_E1:
4735 return "E & M E1";
4736 case SIG_FEATD:
4737 return "Feature Group D (DTMF)";
4738 case SIG_FEATDMF:
4739 return "Feature Group D (MF)";
4740 case SIG_FEATDMF_TA:
4741 return "Feature Group D (MF) Tandem Access";
4742 case SIG_FEATB:
4743 return "Feature Group B (MF)";
4744 case SIG_E911:
4745 return "E911 (MF)";
4746 case SIG_FGC_CAMA:
4747 return "FGC/CAMA (Dialpulse)";
4748 case SIG_FGC_CAMAMF:
4749 return "FGC/CAMA (MF)";
4750 case SIG_FXSLS:
4751 return "FXS Loopstart";
4752 case SIG_FXSGS:
4753 return "FXS Groundstart";
4754 case SIG_FXSKS:
4755 return "FXS Kewlstart";
4756 case SIG_FXOLS:
4757 return "FXO Loopstart";
4758 case SIG_FXOGS:
4759 return "FXO Groundstart";
4760 case SIG_FXOKS:
4761 return "FXO Kewlstart";
4762 case SIG_PRI:
4763 return "ISDN PRI";
4764 case SIG_BRI:
4765 return "ISDN BRI Point to Point";
4766 case SIG_BRI_PTMP:
4767 return "ISDN BRI Point to MultiPoint";
4768 case SIG_SS7:
4769 return "SS7";
4770 case SIG_MFCR2:
4771 return "MFC/R2";
4772 case SIG_SF:
4773 return "SF (Tone) Immediate";
4774 case SIG_SFWINK:
4775 return "SF (Tone) Wink";
4776 case SIG_SF_FEATD:
4777 return "SF (Tone) with Feature Group D (DTMF)";
4778 case SIG_SF_FEATDMF:
4779 return "SF (Tone) with Feature Group D (MF)";
4780 case SIG_SF_FEATB:
4781 return "SF (Tone) with Feature Group B (MF)";
4782 case 0:
4783 return "Pseudo";
4784 default:
4785 snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
4786 return buf;
4787 }
4788}
4789
4790#define sig2str dahdi_sig2str
4791
4792static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
4793{
4794 /* If the conference already exists, and we're already in it
4795 don't bother doing anything */
4796 struct dahdi_confinfo zi;
4797
4798 memset(&zi, 0, sizeof(zi));
4799 zi.chan = 0;
4800
4801 if (slavechannel > 0) {
4802 /* If we have only one slave, do a digital mon */
4803 zi.confmode = DAHDI_CONF_DIGITALMON;
4804 zi.confno = slavechannel;
4805 } else {
4806 if (!idx) {
4807 /* Real-side and pseudo-side both participate in conference */
4808 zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
4809 DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4810 } else
4811 zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
4812 zi.confno = p->confno;
4813 }
4814 if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
4815 return 0;
4816 if (c->dfd < 0)
4817 return 0;
4818 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4819 ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
4820 return -1;
4821 }
4822 if (slavechannel < 1) {
4823 p->confno = zi.confno;
4824 }
4825 c->curconf = zi;
4826 ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4827 return 0;
4828}
4829
4830static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
4831{
4832 /* If they're listening to our channel, they're ours */
4833 if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
4834 return 1;
4835 /* If they're a talker on our (allocated) conference, they're ours */
4836 if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
4837 return 1;
4838 return 0;
4839}
4840
4841static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
4842{
4843 struct dahdi_confinfo zi;
4844 if (/* Can't delete if there's no dfd */
4845 (c->dfd < 0) ||
4846 /* Don't delete from the conference if it's not our conference */
4847 !isourconf(p, c)
4848 /* Don't delete if we don't think it's conferenced at all (implied) */
4849 ) return 0;
4850 memset(&zi, 0, sizeof(zi));
4851 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4852 ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
4853 return -1;
4854 }
4855 ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4856 memcpy(&c->curconf, &zi, sizeof(c->curconf));
4857 return 0;
4858}
4859
4860static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
4861{
4862 int x;
4863 int useslavenative;
4864 struct dahdi_pvt *slave = NULL;
4865 /* Start out optimistic */
4866 useslavenative = 1;
4867 /* Update conference state in a stateless fashion */
4868 for (x = 0; x < 3; x++) {
4869 /* Any three-way calling makes slave native mode *definitely* out
4870 of the question */
4871 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
4872 useslavenative = 0;
4873 }
4874 /* If we don't have any 3-way calls, check to see if we have
4875 precisely one slave */
4876 if (useslavenative) {
4877 for (x = 0; x < MAX_SLAVES; x++) {
4878 if (p->slaves[x]) {
4879 if (slave) {
4880 /* Whoops already have a slave! No
4881 slave native and stop right away */
4882 slave = NULL;
4883 useslavenative = 0;
4884 break;
4885 } else {
4886 /* We have one slave so far */
4887 slave = p->slaves[x];
4888 }
4889 }
4890 }
4891 }
4892 /* If no slave, slave native definitely out */
4893 if (!slave)
4894 useslavenative = 0;
4895 else if (slave->law != p->law) {
4896 useslavenative = 0;
4897 slave = NULL;
4898 }
4899 if (out)
4900 *out = slave;
4901 return useslavenative;
4902}
4903
4904static int reset_conf(struct dahdi_pvt *p)
4905{
4906 p->confno = -1;
4907 memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
4908 if (p->subs[SUB_REAL].dfd > -1) {
4909 struct dahdi_confinfo zi;
4910
4911 memset(&zi, 0, sizeof(zi));
4912 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
4913 ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
4914 }
4915 return 0;
4916}
4917
4919{
4920 int needconf = 0;
4921 int x;
4922 int useslavenative;
4923 struct dahdi_pvt *slave = NULL;
4924
4925 useslavenative = isslavenative(p, &slave);
4926 /* Start with the obvious, general stuff */
4927 for (x = 0; x < 3; x++) {
4928 /* Look for three way calls */
4929 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
4930 conf_add(p, &p->subs[x], x, 0);
4931 needconf++;
4932 } else {
4933 conf_del(p, &p->subs[x], x);
4934 }
4935 }
4936 /* If we have a slave, add him to our conference now. or DAX
4937 if this is slave native */
4938 for (x = 0; x < MAX_SLAVES; x++) {
4939 if (p->slaves[x]) {
4940 if (useslavenative)
4941 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
4942 else {
4943 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
4944 needconf++;
4945 }
4946 }
4947 }
4948 /* If we're supposed to be in there, do so now */
4949 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
4950 if (useslavenative)
4951 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
4952 else {
4953 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
4954 needconf++;
4955 }
4956 }
4957 /* If we have a master, add ourselves to his conference */
4958 if (p->master) {
4959 if (isslavenative(p->master, NULL)) {
4961 } else {
4962 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
4963 }
4964 }
4965 if (!needconf) {
4966 /* Nobody is left (or should be left) in our conference.
4967 Kill it. */
4968 p->confno = -1;
4969 }
4970 ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
4971}
4972
4974{
4975 int res;
4976 if (!p)
4977 return;
4978 if (p->echocanon) {
4979 ast_debug(1, "Echo cancellation already on\n");
4980 return;
4981 }
4982 if (p->digital) {
4983 ast_debug(1, "Echo cancellation isn't required on digital connection\n");
4984 return;
4985 }
4986 if (p->echocancel.head.tap_length) {
4987#if defined(HAVE_PRI) || defined(HAVE_SS7)
4988 switch (p->sig) {
4989#if defined(HAVE_PRI)
4991 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
4992 /*
4993 * PRI nobch pseudo channel. Does not need ec anyway.
4994 * Does not handle ioctl(DAHDI_AUDIOMODE)
4995 */
4996 return;
4997 }
4998 /* Fall through */
4999#endif /* defined(HAVE_PRI) */
5000#if defined(HAVE_SS7)
5001 case SIG_SS7:
5002#endif /* defined(HAVE_SS7) */
5003 {
5004 int x = 1;
5005
5006 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
5007 if (res)
5009 "Unable to enable audio mode on channel %d (%s)\n",
5010 p->channel, strerror(errno));
5011 }
5012 break;
5013 default:
5014 break;
5015 }
5016#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5017 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
5018 if (res) {
5019 ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
5020 } else {
5021 p->echocanon = 1;
5022 ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
5023 }
5024 } else
5025 ast_debug(1, "No echo cancellation requested\n");
5026}
5027
5028static void dahdi_train_ec(struct dahdi_pvt *p)
5029{
5030 int x;
5031 int res;
5032
5033 if (p && p->echocanon && p->echotraining) {
5034 x = p->echotraining;
5035 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
5036 if (res)
5037 ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
5038 else
5039 ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
5040 } else {
5041 ast_debug(1, "No echo training requested\n");
5042 }
5043}
5044
5046{
5047 int res;
5048
5049 if (p->echocanon) {
5050 struct dahdi_echocanparams ecp = { .tap_length = 0 };
5051
5052 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
5053
5054 if (res)
5055 ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
5056 else
5057 ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
5058 }
5059
5060 p->echocanon = 0;
5061}
5062
5063static int set_hwgain(int fd, float gain, int tx_direction)
5064{
5065 struct dahdi_hwgain hwgain;
5066
5067 hwgain.newgain = gain * 10.0;
5068 hwgain.tx = tx_direction;
5069 return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
5070}
5071
5072/* perform a dynamic range compression transform on the given sample */
5073static int drc_sample(int sample, float drc)
5074{
5075 float neg;
5076 float shallow, steep;
5077 float max = SHRT_MAX;
5078
5079 neg = (sample < 0 ? -1 : 1);
5080 steep = drc*sample;
5081 shallow = neg*(max-max/drc)+(float)sample/drc;
5082 if (fabsf(steep) < fabsf(shallow)) {
5083 sample = steep;
5084 }
5085 else {
5086 sample = shallow;
5087 }
5088
5089 return sample;
5090}
5091
5092
5093static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
5094{
5095 int j;
5096 int k;
5097
5098 float linear_gain = pow(10.0, gain / 20.0);
5099
5100 switch (law) {
5101 case DAHDI_LAW_ALAW:
5102 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5103 if (gain || drc) {
5104 k = AST_ALAW(j);
5105 if (drc) {
5106 k = drc_sample(k, drc);
5107 }
5108 k = (float)k * linear_gain;
5109 if (k > 32767) {
5110 k = 32767;
5111 } else if (k < -32768) {
5112 k = -32768;
5113 }
5114 g->txgain[j] = AST_LIN2A(k);
5115 } else {
5116 g->txgain[j] = j;
5117 }
5118 }
5119 break;
5120 case DAHDI_LAW_MULAW:
5121 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5122 if (gain || drc) {
5123 k = AST_MULAW(j);
5124 if (drc) {
5125 k = drc_sample(k, drc);
5126 }
5127 k = (float)k * linear_gain;
5128 if (k > 32767) {
5129 k = 32767;
5130 } else if (k < -32768) {
5131 k = -32768;
5132 }
5133 g->txgain[j] = AST_LIN2MU(k);
5134
5135 } else {
5136 g->txgain[j] = j;
5137 }
5138 }
5139 break;
5140 }
5141}
5142
5143static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
5144{
5145 int j;
5146 int k;
5147 float linear_gain = pow(10.0, gain / 20.0);
5148
5149 switch (law) {
5150 case DAHDI_LAW_ALAW:
5151 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5152 if (gain || drc) {
5153 k = AST_ALAW(j);
5154 if (drc) {
5155 k = drc_sample(k, drc);
5156 }
5157 k = (float)k * linear_gain;
5158 if (k > 32767) {
5159 k = 32767;
5160 } else if (k < -32768) {
5161 k = -32768;
5162 }
5163 g->rxgain[j] = AST_LIN2A(k);
5164 } else {
5165 g->rxgain[j] = j;
5166 }
5167 }
5168 break;
5169 case DAHDI_LAW_MULAW:
5170 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5171 if (gain || drc) {
5172 k = AST_MULAW(j);
5173 if (drc) {
5174 k = drc_sample(k, drc);
5175 }
5176 k = (float)k * linear_gain;
5177 if (k > 32767) {
5178 k = 32767;
5179 } else if (k < -32768) {
5180 k = -32768;
5181 }
5182 g->rxgain[j] = AST_LIN2MU(k);
5183 } else {
5184 g->rxgain[j] = j;
5185 }
5186 }
5187 break;
5188 }
5189}
5190
5191static int set_actual_txgain(int fd, float gain, float drc, int law)
5192{
5193 struct dahdi_gains g;
5194 int res;
5195
5196 memset(&g, 0, sizeof(g));
5197 res = ioctl(fd, DAHDI_GETGAINS, &g);
5198 if (res) {
5199 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5200 return res;
5201 }
5202
5203 fill_txgain(&g, gain, drc, law);
5204
5205 return ioctl(fd, DAHDI_SETGAINS, &g);
5206}
5207
5208static int set_actual_rxgain(int fd, float gain, float drc, int law)
5209{
5210 struct dahdi_gains g;
5211 int res;
5212
5213 memset(&g, 0, sizeof(g));
5214 res = ioctl(fd, DAHDI_GETGAINS, &g);
5215 if (res) {
5216 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5217 return res;
5218 }
5219
5220 fill_rxgain(&g, gain, drc, law);
5221
5222 return ioctl(fd, DAHDI_SETGAINS, &g);
5223}
5224
5225static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
5226{
5227 return set_actual_txgain(fd, txgain, txdrc, law) | set_actual_rxgain(fd, rxgain, rxdrc, law);
5228}
5229
5230static int bump_gains(struct dahdi_pvt *p)
5231{
5232 int res;
5233
5234 /* Bump receive gain by value stored in cid_rxgain */
5235 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain + p->cid_rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5236 if (res) {
5237 ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
5238 return -1;
5239 }
5240
5241 return 0;
5242}
5243
5244static int restore_gains(struct dahdi_pvt *p)
5245{
5246 int res;
5247
5248 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5249 if (res) {
5250 ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
5251 return -1;
5252 }
5253
5254 return 0;
5255}
5256
5257static inline int dahdi_set_hook(int fd, int hs)
5258{
5259 int x, res;
5260
5261 x = hs;
5262 res = ioctl(fd, DAHDI_HOOK, &x);
5263
5264 if (res < 0) {
5265 if (errno == EINPROGRESS)
5266 return 0;
5267 ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
5268 /* will expectedly fail if phone is off hook during operation, such as during a restart */
5269 }
5270
5271 return res;
5272}
5273
5274static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
5275{
5276 int x, res;
5277
5278 x = muted;
5279#if defined(HAVE_PRI) || defined(HAVE_SS7)
5280 switch (p->sig) {
5281#if defined(HAVE_PRI)
5283 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
5284 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
5285 break;
5286 }
5287 /* Fall through */
5288#endif /* defined(HAVE_PRI) */
5289#if defined(HAVE_SS7)
5290 case SIG_SS7:
5291#endif /* defined(HAVE_SS7) */
5292 {
5293 int y = 1;
5294
5295 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
5296 if (res)
5297 ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n",
5298 p->channel, strerror(errno));
5299 }
5300 break;
5301 default:
5302 break;
5303 }
5304#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5305 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
5306 if (res < 0)
5307 ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
5308 return res;
5309}
5310
5311static int save_conference(struct dahdi_pvt *p)
5312{
5313 struct dahdi_confinfo c;
5314 int res;
5315 if (p->saveconf.confmode) {
5316 ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
5317 return -1;
5318 }
5319 p->saveconf.chan = 0;
5320 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
5321 if (res) {
5322 ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
5323 p->saveconf.confmode = 0;
5324 return -1;
5325 }
5326 memset(&c, 0, sizeof(c));
5327 c.confmode = DAHDI_CONF_NORMAL;
5328 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
5329 if (res) {
5330 ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
5331 return -1;
5332 }
5333 ast_debug(1, "Disabled conferencing\n");
5334 return 0;
5335}
5336
5337static int restore_conference(struct dahdi_pvt *p)
5338{
5339 int res;
5340 if (p->saveconf.confmode) {
5341 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
5342 p->saveconf.confmode = 0;
5343 if (res) {
5344 ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
5345 return -1;
5346 }
5347 ast_debug(1, "Restored conferencing\n");
5348 }
5349 return 0;
5350}
5351
5352static int send_cwcidspill(struct dahdi_pvt *p)
5353{
5354 p->callwaitcas = 0;
5355 p->cidcwexpire = 0;
5356 p->cid_suppress_expire = 0;
5358 return -1;
5360 /* Make sure we account for the end */
5361 p->cidlen += READ_SIZE * 4;
5362 p->cidpos = 0;
5363 send_callerid(p);
5364 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
5365 return 0;
5366}
5367
5368static int has_voicemail(struct dahdi_pvt *p)
5369{
5370 int new_msgs;
5371 RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
5372
5373 /* A manual MWI disposition has been requested, use that instead
5374 * if this is for sending the new MWI indication. */
5375 if (p->mwioverride_active) {
5376 /* We don't clear p->mwioverride_active automatically,
5377 * because otherwise do_monitor would just change it back to the way it was.
5378 * We need to keep the override active until explicitly disabled by the user,
5379 * so that we can keep returning the correct answer in subsequent calls to do_monitor. */
5380 ast_debug(6, "MWI manual override active on channel %d: pretending that it should be %s\n",
5381 p->channel, p->mwioverride_disposition ? "active" : "inactive");
5382 return p->mwioverride_disposition;
5383 }
5384
5386 if (mwi_message) {
5387 struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
5388 new_msgs = mwi_state->new_msgs;
5389 } else {
5391 }
5392
5393 return new_msgs;
5394}
5395
5396
5397
5398static int send_callerid(struct dahdi_pvt *p)
5399{
5400 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
5401 int res;
5402 /* Take out of linear mode if necessary */
5403 if (p->subs[SUB_REAL].linear) {
5404 p->subs[SUB_REAL].linear = 0;
5406 }
5407 while (p->cidpos < p->cidlen) {
5408 res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
5409 ast_debug(4, "writing callerid at pos %d of %d, res = %d\n", p->cidpos, p->cidlen, res);
5410 if (res < 0) {
5411 if (errno == EAGAIN)
5412 return 0;
5413 else {
5414 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
5415 return -1;
5416 }
5417 }
5418 if (!res)
5419 return 0;
5420 p->cidpos += res;
5421 }
5423 ast_free(p->cidspill);
5424 p->cidspill = NULL;
5425 if (p->callwaitcas) {
5426 /* Wait for CID/CW to expire */
5429 } else
5431 return 0;
5432}
5433
5434static int dahdi_callwait(struct ast_channel *ast)
5435{
5436 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5437
5439 if (p->cidspill) {
5440 ast_log(LOG_WARNING, "Spill already exists?!?\n");
5441 ast_free(p->cidspill);
5442 }
5443
5444 /*
5445 * SAS: Subscriber Alert Signal, 440Hz for 300ms
5446 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
5447 */
5448 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
5449 return -1;
5450 save_conference(p);
5451 /* Silence */
5452 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
5453 if (!p->callwaitrings && p->callwaitingcallerid) {
5454 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
5455 p->callwaitcas = 1;
5456 p->cidlen = 2400 + 680 + READ_SIZE * 4;
5457 } else {
5458 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
5459 p->callwaitcas = 0;
5460 p->cidlen = 2400 + READ_SIZE * 4;
5461 }
5462 p->cidpos = 0;
5463 send_callerid(p);
5464
5465 return 0;
5466}
5467
5468static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
5469{
5470 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5471 int x, res, mysig;
5472 char *dest;
5474 AST_APP_ARG(group); /* channel/group token */
5475 AST_APP_ARG(ext); /* extension token */
5476 //AST_APP_ARG(opts); /* options token */
5477 AST_APP_ARG(other); /* Any remaining unused arguments */
5478 );
5479
5480 ast_mutex_lock(&p->lock);
5481 ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
5482
5483 /* Split the dialstring */
5484 dest = ast_strdupa(rdest);
5485 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
5486 if (!args.ext) {
5487 args.ext = "";
5488 }
5489
5490#if defined(HAVE_PRI)
5492 char *subaddr;
5493
5494 sig_pri_extract_called_num_subaddr(p->sig_pvt, rdest, p->exten, sizeof(p->exten));
5495
5496 /* Remove any subaddress for uniformity with incoming calls. */
5497 subaddr = strchr(p->exten, ':');
5498 if (subaddr) {
5499 *subaddr = '\0';
5500 }
5501 } else
5502#endif /* defined(HAVE_PRI) */
5503 {
5504 ast_copy_string(p->exten, args.ext, sizeof(p->exten));
5505 }
5506
5507 if ((ast_channel_state(ast) == AST_STATE_BUSY)) {
5508 p->subs[SUB_REAL].needbusy = 1;
5510 return 0;
5511 }
5513 ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
5515 return -1;
5516 }
5517 p->waitingfordt.tv_sec = 0;
5518 p->dialednone = 0;
5519 if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
5520 {
5521 /* Special pseudo -- automatically up */
5524 return 0;
5525 }
5526 x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
5527 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
5528 if (res)
5529 ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
5530 p->outgoing = 1;
5531
5533 set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
5534 } else {
5535 set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5536 }
5537
5538#ifdef HAVE_PRI
5540 res = sig_pri_call(p->sig_pvt, ast, rdest, timeout,
5541 (p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW);
5543 return res;
5544 }
5545#endif
5546
5547#if defined(HAVE_SS7)
5548 if (p->sig == SIG_SS7) {
5549 res = sig_ss7_call(p->sig_pvt, ast, rdest);
5551 return res;
5552 }
5553#endif /* defined(HAVE_SS7) */
5554
5555 /* If this is analog signalling we can exit here */
5556 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
5557 p->callwaitrings = 0;
5558 res = analog_call(p->sig_pvt, ast, rdest, timeout);
5560 return res;
5561 }
5562
5563 mysig = p->outsigmod > -1 ? p->outsigmod : p->sig;
5564 switch (mysig) {
5565 case 0:
5566 /* Special pseudo -- automatically up*/
5568 break;
5569 case SIG_MFCR2:
5570 break;
5571 default:
5572 ast_debug(1, "not yet implemented\n");
5574 return -1;
5575 }
5576
5577#ifdef HAVE_OPENR2
5578 if (p->mfcr2) {
5579 openr2_calling_party_category_t chancat;
5580 int callres = 0;
5581 char *c, *l;
5582
5583 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
5584 p->dialdest[0] = '\0';
5585
5586 c = args.ext;
5587 if (!p->hidecallerid) {
5589 } else {
5590 l = NULL;
5591 }
5592 if (strlen(c) < p->stripmsd) {
5593 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
5595 return -1;
5596 }
5597 p->dialing = 1;
5598 chancat = dahdi_r2_get_channel_category(ast);
5599 callres = openr2_chan_make_call(p->r2chan, l, (c + p->stripmsd), chancat);
5600 if (-1 == callres) {
5602 ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
5603 return -1;
5604 }
5605 p->mfcr2_call_accepted = 0;
5606 p->mfcr2_progress_sent = 0;
5608 }
5609#endif /* HAVE_OPENR2 */
5611 return 0;
5612}
5613
5614/*!
5615 * \internal
5616 * \brief Insert the given chan_dahdi interface structure into the interface list.
5617 * \since 1.8
5618 *
5619 * \param pvt chan_dahdi private interface structure to insert.
5620 *
5621 * \details
5622 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5623 * Any duplicates are inserted after the existing entries.
5624 *
5625 * \note The new interface must not already be in the list.
5626 */
5627static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
5628{
5629 struct dahdi_pvt *cur;
5630
5632
5633 /* Find place in middle of list for the new interface. */
5634 for (cur = iflist; cur; cur = cur->next) {
5635 if (pvt->channel < cur->channel) {
5636 /* New interface goes before the current interface. */
5637 pvt->prev = cur->prev;
5638 pvt->next = cur;
5639 if (cur->prev) {
5640 /* Insert into the middle of the list. */
5641 cur->prev->next = pvt;
5642 } else {
5643 /* Insert at head of list. */
5644 iflist = pvt;
5645 }
5646 cur->prev = pvt;
5647 return;
5648 }
5649 }
5650
5651 /* New interface goes onto the end of the list */
5652 pvt->prev = ifend;
5653 pvt->next = NULL;
5654 if (ifend) {
5655 ifend->next = pvt;
5656 }
5657 ifend = pvt;
5658 if (!iflist) {
5659 /* List was empty */
5660 iflist = pvt;
5661 }
5662}
5663
5664/*!
5665 * \internal
5666 * \brief Extract the given chan_dahdi interface structure from the interface list.
5667 * \since 1.8
5668 *
5669 * \param pvt chan_dahdi private interface structure to extract.
5670 *
5671 * \note
5672 * The given interface structure can be either in the interface list or a stand alone
5673 * structure that has not been put in the list if the next and prev pointers are NULL.
5674 */
5675static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
5676{
5677 /* Extract from the forward chain. */
5678 if (pvt->prev) {
5679 pvt->prev->next = pvt->next;
5680 } else if (iflist == pvt) {
5681 /* Node is at the head of the list. */
5682 iflist = pvt->next;
5683 }
5684
5685 /* Extract from the reverse chain. */
5686 if (pvt->next) {
5687 pvt->next->prev = pvt->prev;
5688 } else if (ifend == pvt) {
5689 /* Node is at the end of the list. */
5690 ifend = pvt->prev;
5691 }
5692
5693 /* Node is no longer in the list. */
5695 pvt->prev = NULL;
5696 pvt->next = NULL;
5697}
5698
5699#if defined(HAVE_PRI)
5700/*!
5701 * \internal
5702 * \brief Insert the given chan_dahdi interface structure into the no B channel list.
5703 * \since 1.8
5704 *
5705 * \param pri sig_pri span control structure holding no B channel list.
5706 * \param pvt chan_dahdi private interface structure to insert.
5707 *
5708 * \details
5709 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5710 * Any duplicates are inserted after the existing entries.
5711 *
5712 * \note The new interface must not already be in the list.
5713 */
5714static void dahdi_nobch_insert(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5715{
5716 struct dahdi_pvt *cur;
5717
5718 pvt->which_iflist = DAHDI_IFLIST_NO_B_CHAN;
5719
5720 /* Find place in middle of list for the new interface. */
5721 for (cur = pri->no_b_chan_iflist; cur; cur = cur->next) {
5722 if (pvt->channel < cur->channel) {
5723 /* New interface goes before the current interface. */
5724 pvt->prev = cur->prev;
5725 pvt->next = cur;
5726 if (cur->prev) {
5727 /* Insert into the middle of the list. */
5728 cur->prev->next = pvt;
5729 } else {
5730 /* Insert at head of list. */
5731 pri->no_b_chan_iflist = pvt;
5732 }
5733 cur->prev = pvt;
5734 return;
5735 }
5736 }
5737
5738 /* New interface goes onto the end of the list */
5739 pvt->prev = pri->no_b_chan_end;
5740 pvt->next = NULL;
5741 if (pri->no_b_chan_end) {
5742 ((struct dahdi_pvt *) pri->no_b_chan_end)->next = pvt;
5743 }
5744 pri->no_b_chan_end = pvt;
5745 if (!pri->no_b_chan_iflist) {
5746 /* List was empty */
5747 pri->no_b_chan_iflist = pvt;
5748 }
5749}
5750#endif /* defined(HAVE_PRI) */
5751
5752#if defined(HAVE_PRI)
5753/*!
5754 * \internal
5755 * \brief Extract the given chan_dahdi interface structure from the no B channel list.
5756 * \since 1.8
5757 *
5758 * \param pri sig_pri span control structure holding no B channel list.
5759 * \param pvt chan_dahdi private interface structure to extract.
5760 *
5761 * \note
5762 * The given interface structure can be either in the interface list or a stand alone
5763 * structure that has not been put in the list if the next and prev pointers are NULL.
5764 */
5765static void dahdi_nobch_extract(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5766{
5767 /* Extract from the forward chain. */
5768 if (pvt->prev) {
5769 pvt->prev->next = pvt->next;
5770 } else if (pri->no_b_chan_iflist == pvt) {
5771 /* Node is at the head of the list. */
5772 pri->no_b_chan_iflist = pvt->next;
5773 }
5774
5775 /* Extract from the reverse chain. */
5776 if (pvt->next) {
5777 pvt->next->prev = pvt->prev;
5778 } else if (pri->no_b_chan_end == pvt) {
5779 /* Node is at the end of the list. */
5780 pri->no_b_chan_end = pvt->prev;
5781 }
5782
5783 /* Node is no longer in the list. */
5785 pvt->prev = NULL;
5786 pvt->next = NULL;
5787}
5788#endif /* defined(HAVE_PRI) */
5789
5790#if defined(HAVE_PRI)
5791/*!
5792 * \internal
5793 * \brief Unlink the channel interface from the PRI private pointer array.
5794 * \since 1.8
5795 *
5796 * \param pvt chan_dahdi private interface structure to unlink.
5797 */
5798static void dahdi_unlink_pri_pvt(struct dahdi_pvt *pvt)
5799{
5800 unsigned idx;
5801 struct sig_pri_span *pri;
5802
5803 pri = pvt->pri;
5804 if (!pri) {
5805 /* Not PRI signaling so cannot be in a PRI private pointer array. */
5806 return;
5807 }
5808 ast_mutex_lock(&pri->lock);
5809 for (idx = 0; idx < pri->numchans; ++idx) {
5810 if (pri->pvts[idx] == pvt->sig_pvt) {
5811 pri->pvts[idx] = NULL;
5812 ast_mutex_unlock(&pri->lock);
5813 return;
5814 }
5815 }
5816 ast_mutex_unlock(&pri->lock);
5817}
5818#endif /* defined(HAVE_PRI) */
5819
5820#if defined(HAVE_SS7)
5821/*!
5822 * \internal
5823 * \brief Unlink the channel interface from the SS7 private pointer array.
5824 * \since 1.8
5825 *
5826 * \param pvt chan_dahdi private interface structure to unlink.
5827 */
5828static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
5829{
5830 unsigned idx;
5831 struct sig_ss7_linkset *ss7;
5832
5833 ss7 = pvt->ss7;
5834 if (!ss7) {
5835 /* Not SS7 signaling so cannot be in a SS7 private pointer array. */
5836 return;
5837 }
5838 ast_mutex_lock(&ss7->lock);
5839 for (idx = 0; idx < ss7->numchans; ++idx) {
5840 if (ss7->pvts[idx] == pvt->sig_pvt) {
5841 ss7->pvts[idx] = NULL;
5842 ast_mutex_unlock(&ss7->lock);
5843 return;
5844 }
5845 }
5846 ast_mutex_unlock(&ss7->lock);
5847}
5848#endif /* defined(HAVE_SS7) */
5849
5850#if defined(HAVE_OPENR2)
5851/*!
5852 * \internal
5853 * \brief Unlink the channel interface from the MFC/R2 private pointer array.
5854 *
5855 * \param pvt chan_dahdi private interface structure to unlink.
5856 */
5857static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
5858{
5859 unsigned idx;
5860 struct dahdi_mfcr2 *mfcr2;
5861 int should_destroy_link = 0;
5862
5863 ast_mutex_lock(&pvt->lock);
5864 if (pvt->r2chan) {
5865 ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
5866 openr2_chan_disable_read(pvt->r2chan);
5867 }
5868 mfcr2 = pvt->mfcr2;
5869 if (mfcr2) {
5870 for (idx = 0; idx < mfcr2->numchans; ++idx) {
5871 if (mfcr2->pvts[idx] == pvt) {
5872 ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
5873 mfcr2->pvts[idx] = NULL;
5874 mfcr2->live_chans--;
5875 break;
5876 }
5877 }
5878 if (!mfcr2->live_chans) {
5879 ast_debug(1, "MFC/R2 link is now empty\n");
5880 should_destroy_link = 1;
5881 }
5882 }
5883 ast_mutex_unlock(&pvt->lock);
5884 if (should_destroy_link) {
5885 ast_debug(1, "MFC/R2 link is now empty\n");
5886 mfcr2_queue_for_destruction(pvt);
5887 }
5888}
5889#endif /* defined(HAVE_OPENR2) */
5890
5892{
5893 if (cur->next && cur->next->span == cur->span) {
5894 return cur->next;
5895 } else if (cur->prev && cur->prev->span == cur->span) {
5896 return cur->prev;
5897 }
5898
5899 return NULL;
5900}
5901
5902static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
5903{
5904 struct dahdi_pvt *p = pvt;
5905
5906 if (p->manages_span_alarms) {
5908 if (next) {
5910 }
5911 }
5912
5913 /* Remove channel from the list */
5914#if defined(HAVE_PRI)
5915 dahdi_unlink_pri_pvt(p);
5916#endif /* defined(HAVE_PRI) */
5917#if defined(HAVE_SS7)
5918 dahdi_unlink_ss7_pvt(p);
5919#endif /* defined(HAVE_SS7) */
5920#if defined(HAVE_OPENR2)
5921 dahdi_unlink_mfcr2_pvt(p);
5922#endif /* defined(HAVE_SS7) */
5923 switch (pvt->which_iflist) {
5924 case DAHDI_IFLIST_NONE:
5925 break;
5926 case DAHDI_IFLIST_MAIN:
5928 break;
5929#if defined(HAVE_PRI)
5930 case DAHDI_IFLIST_NO_B_CHAN:
5931 if (p->pri) {
5932 dahdi_nobch_extract(p->pri, p);
5933 }
5934 break;
5935#endif /* defined(HAVE_PRI) */
5936 }
5937
5938 if (p->sig_pvt) {
5939 if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
5941 }
5942 switch (p->sig) {
5943#if defined(HAVE_PRI)
5946 break;
5947#endif /* defined(HAVE_PRI) */
5948#if defined(HAVE_SS7)
5949 case SIG_SS7:
5951 break;
5952#endif /* defined(HAVE_SS7) */
5953 default:
5954 break;
5955 }
5956 }
5957 ast_free(p->cidspill);
5958 if (p->use_smdi) {
5960 }
5961 if (p->mwi_event_sub) {
5963 }
5964 if (p->vars) {
5966 }
5967 if (p->cc_params) {
5969 }
5970
5973
5976 if (p->owner) {
5978 }
5979 ast_free(p);
5980}
5981
5982static void destroy_channel(struct dahdi_pvt *cur, int now)
5983{
5984 int i;
5985
5986 if (!now) {
5987 /* Do not destroy the channel now if it is owned by someone. */
5988 if (cur->owner) {
5989 return;
5990 }
5991 for (i = 0; i < 3; i++) {
5992 if (cur->subs[i].owner) {
5993 return;
5994 }
5995 }
5996 }
5997 destroy_dahdi_pvt(cur);
5998}
5999
6000static void destroy_all_channels(void)
6001{
6002 int chan;
6003#if defined(HAVE_PRI)
6004 unsigned span;
6005 struct sig_pri_span *pri;
6006#endif /* defined(HAVE_PRI) */
6007 struct dahdi_pvt *p;
6008
6009 while (num_restart_pending) {
6010 usleep(1);
6011 }
6012
6014 /* Destroy all the interfaces and free their memory */
6015 while (iflist) {
6016 p = iflist;
6017
6018 chan = p->channel;
6019#if defined(HAVE_PRI_SERVICE_MESSAGES)
6020 {
6021 char db_chan_name[20];
6022 char db_answer[5];
6023 char state;
6024 int why = -1;
6025
6026 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, p->span, chan);
6027 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
6028 sscanf(db_answer, "%1c:%30d", &state, &why);
6029 }
6030 if (!why) {
6031 /* SRVST persistence is not required */
6032 ast_db_del(db_chan_name, SRVST_DBKEY);
6033 }
6034 }
6035#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
6036 /* Free associated memory */
6038 ast_verb(3, "Unregistered channel %d\n", chan);
6039 }
6040 ifcount = 0;
6042
6043#if defined(HAVE_PRI)
6044 /* Destroy all of the no B channel interface lists */
6045 for (span = 0; span < NUM_SPANS; ++span) {
6046 if (!pris[span].dchannels[0]) {
6047 break;
6048 }
6049 pri = &pris[span].pri;
6050 ast_mutex_lock(&pri->lock);
6051 while (pri->no_b_chan_iflist) {
6052 p = pri->no_b_chan_iflist;
6053
6054 /* Free associated memory */
6056 }
6057 ast_mutex_unlock(&pri->lock);
6058 }
6059#endif /* defined(HAVE_PRI) */
6060}
6061
6062#if defined(HAVE_PRI)
6063static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
6064
6065static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, const char *digits)
6066{
6067 /* Data will be our digit string */
6068 struct dahdi_pvt *p;
6069
6070 if (ast_strlen_zero(digits)) {
6071 ast_debug(1, "No digit string sent to application!\n");
6072 return -1;
6073 }
6074
6075 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6076
6077 if (!p) {
6078 ast_debug(1, "Unable to find technology private\n");
6079 return -1;
6080 }
6081
6083
6084 return 0;
6085}
6086#endif /* defined(HAVE_PRI) */
6087
6088#if defined(HAVE_PRI)
6089#if defined(HAVE_PRI_PROG_W_CAUSE)
6090static char *dahdi_send_callrerouting_facility_app = "DAHDISendCallreroutingFacility";
6091
6092static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, const char *data)
6093{
6094 /* Data will be our digit string */
6095 struct dahdi_pvt *pvt;
6096 char *parse;
6097 int res;
6099 AST_APP_ARG(destination);
6100 AST_APP_ARG(original);
6101 AST_APP_ARG(reason);
6102 );
6103
6104 if (ast_strlen_zero(data)) {
6105 ast_debug(1, "No data sent to application!\n");
6106 return -1;
6107 }
6108 if (ast_channel_tech(chan) != &dahdi_tech) {
6109 ast_debug(1, "Only DAHDI technology accepted!\n");
6110 return -1;
6111 }
6112 pvt = (struct dahdi_pvt *) ast_channel_tech_pvt(chan);
6113 if (!pvt) {
6114 ast_debug(1, "Unable to find technology private\n");
6115 return -1;
6116 }
6117 switch (pvt->sig) {
6119 break;
6120 default:
6121 ast_debug(1, "callrerouting attempted on non-ISDN channel %s\n",
6122 ast_channel_name(chan));
6123 return -1;
6124 }
6125
6126 parse = ast_strdupa(data);
6128
6129 if (ast_strlen_zero(args.destination)) {
6130 ast_log(LOG_WARNING, "callrerouting facility requires at least destination number argument\n");
6131 return -1;
6132 }
6133
6134 if (ast_strlen_zero(args.original)) {
6135 ast_log(LOG_WARNING, "Callrerouting Facility without original called number argument\n");
6136 args.original = NULL;
6137 }
6138
6139 if (ast_strlen_zero(args.reason)) {
6140 ast_log(LOG_NOTICE, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n");
6141 args.reason = NULL;
6142 }
6143
6145 args.destination, args.original, args.reason);
6146 if (!res) {
6147 /*
6148 * Wait up to 5 seconds for a reply before hanging up this call
6149 * leg if the peer does not disconnect first.
6150 */
6151 ast_safe_sleep(chan, 5000);
6152 }
6153
6154 return -1;
6155}
6156#endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
6157#endif /* defined(HAVE_PRI) */
6158
6159#if defined(HAVE_OPENR2)
6160static const char * const dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
6161
6162static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
6163{
6164 /* data is whether to accept with charge or no charge */
6165 openr2_call_mode_t accept_mode;
6166 int res, timeout, maxloops;
6167 struct ast_frame *f;
6168 struct dahdi_pvt *p;
6169 char *parse;
6171 AST_APP_ARG(charge);
6172 );
6173
6174 if (ast_strlen_zero(data)) {
6175 ast_debug(1, "No data sent to application!\n");
6176 return -1;
6177 }
6178
6179 if (ast_channel_tech(chan) != &dahdi_tech) {
6180 ast_debug(1, "Only DAHDI technology accepted!\n");
6181 return -1;
6182 }
6183
6184 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6185 if (!p) {
6186 ast_debug(1, "Unable to find technology private!\n");
6187 return -1;
6188 }
6189
6190 parse = ast_strdupa(data);
6192
6193 if (ast_strlen_zero(args.charge)) {
6194 ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
6195 return -1;
6196 }
6197
6198 ast_mutex_lock(&p->lock);
6199 if (!p->mfcr2 || !p->mfcr2call) {
6201 ast_debug(1, "Channel %s does not seems to be an R2 active channel!\n", ast_channel_name(chan));
6202 return -1;
6203 }
6204
6205 if (p->mfcr2_call_accepted) {
6207 ast_debug(1, "MFC/R2 call already accepted on channel %s!\n", ast_channel_name(chan));
6208 return 0;
6209 }
6210 accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
6211 if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
6213 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6214 return -1;
6215 }
6217
6218 res = 0;
6219 timeout = 100;
6220 maxloops = 50; /* wait up to 5 seconds */
6221 /* we need to read() until the call is accepted */
6222 while (maxloops > 0) {
6223 maxloops--;
6224 if (ast_check_hangup(chan)) {
6225 break;
6226 }
6227 res = ast_waitfor(chan, timeout);
6228 if (res < 0) {
6229 ast_debug(1, "ast_waitfor failed on channel %s, going out ...\n", ast_channel_name(chan));
6230 res = -1;
6231 break;
6232 }
6233 if (res == 0) {
6234 continue;
6235 }
6236 res = 0;
6237 f = ast_read(chan);
6238 if (!f) {
6239 ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
6240 res = -1;
6241 break;
6242 }
6244 ast_debug(1, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
6245 ast_frfree(f);
6246 res = -1;
6247 break;
6248 }
6249 ast_frfree(f);
6250 ast_mutex_lock(&p->lock);
6251 if (p->mfcr2_call_accepted) {
6253 ast_debug(1, "Accepted MFC/R2 call!\n");
6254 break;
6255 }
6257 }
6258 if (res == -1) {
6259 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6260 }
6261 return res;
6262}
6263
6264static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
6265{
6266 openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
6267 switch (cause) {
6270 case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
6271 r2cause = OR2_CAUSE_BUSY_NUMBER;
6272 break;
6273
6276 r2cause = OR2_CAUSE_NETWORK_CONGESTION;
6277 break;
6278
6280 r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
6281 break;
6282
6285 r2cause = OR2_CAUSE_OUT_OF_ORDER;
6286 break;
6287
6290 r2cause = OR2_CAUSE_NO_ANSWER;
6291 break;
6292
6293 default:
6294 r2cause = OR2_CAUSE_NORMAL_CLEARING;
6295 break;
6296 }
6297 ast_debug(1, "ast cause %d resulted in openr2 cause %d/%s\n",
6298 cause, r2cause, openr2_proto_get_disconnect_string(r2cause));
6299 return r2cause;
6300}
6301#endif
6302
6303static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
6304{
6305 if (p->bufferoverrideinuse) {
6306 /* faxbuffers are in use, revert them */
6307 struct dahdi_bufferinfo bi = {
6308 .txbufpolicy = p->buf_policy,
6309 .rxbufpolicy = p->buf_policy,
6310 .bufsize = p->bufsize,
6311 .numbufs = p->buf_no
6312 };
6313 int bpres;
6314
6315 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
6316 ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast_channel_name(ast), strerror(errno));
6317 }
6318 p->bufferoverrideinuse = 0;
6319 return bpres;
6320 }
6321
6322 return -1;
6323}
6324
6325static int dahdi_hangup(struct ast_channel *ast)
6326{
6327 int res = 0;
6328 int idx,x;
6329 int law;
6330 /*static int restore_gains(struct dahdi_pvt *p);*/
6331 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6332 struct dahdi_params par;
6333
6334 ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast));
6335 if (!ast_channel_tech_pvt(ast)) {
6336 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
6337 return 0;
6338 }
6339
6340 ast_mutex_lock(&p->lock);
6341 p->exten[0] = '\0';
6342 /* Always use sig_analog hangup handling for operator mode */
6343 if (dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6344 p->oprmode = 0;
6345 dahdi_confmute(p, 0);
6346 restore_gains(p);
6347 p->ignoredtmf = 0;
6348 p->waitingfordt.tv_sec = 0;
6349
6350 res = analog_hangup(p->sig_pvt, ast);
6351 revert_fax_buffers(p, ast);
6352
6353 goto hangup_out;
6354 } else {
6355 p->cid_num[0] = '\0';
6356 p->cid_name[0] = '\0';
6357 p->cid_subaddr[0] = '\0';
6358 }
6359
6360#if defined(HAVE_PRI)
6362 x = 1;
6363 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6364
6365 dahdi_confmute(p, 0);
6366 p->muting = 0;
6367 restore_gains(p);
6368 if (p->dsp) {
6369 ast_dsp_free(p->dsp);
6370 p->dsp = NULL;
6371 }
6372 p->ignoredtmf = 0;
6373
6374 /* Real channel, do some fixup */
6375 p->subs[SUB_REAL].owner = NULL;
6376 p->subs[SUB_REAL].needbusy = 0;
6378
6379 p->owner = NULL;
6380 p->cid_tag[0] = '\0';
6381 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6382 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6383 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6384 p->outgoing = 0;
6385 p->digital = 0;
6386 p->faxhandled = 0;
6387 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6388
6389 revert_fax_buffers(p, ast);
6390
6391 p->law = p->law_default;
6392 law = p->law_default;
6393 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6394 if (res < 0) {
6395 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6396 p->channel, strerror(errno));
6397 }
6398
6399 sig_pri_hangup(p->sig_pvt, ast);
6400
6401 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6403
6404 x = 0;
6405 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6406 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6407
6408 p->rdnis[0] = '\0';
6410 reset_conf(p);
6411
6412 /* Restore data mode */
6413 x = 0;
6414 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6415
6416 if (num_restart_pending == 0) {
6418 }
6419 goto hangup_out;
6420 }
6421#endif /* defined(HAVE_PRI) */
6422
6423#if defined(HAVE_SS7)
6424 if (p->sig == SIG_SS7) {
6425 x = 1;
6426 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6427
6428 dahdi_confmute(p, 0);
6429 p->muting = 0;
6430 restore_gains(p);
6431 if (p->dsp) {
6432 ast_dsp_free(p->dsp);
6433 p->dsp = NULL;
6434 }
6435 p->ignoredtmf = 0;
6436
6437 /* Real channel, do some fixup */
6438 p->subs[SUB_REAL].owner = NULL;
6439 p->subs[SUB_REAL].needbusy = 0;
6441
6442 p->owner = NULL;
6443 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6444 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6445 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6446 p->outgoing = 0;
6447 p->digital = 0;
6448 p->faxhandled = 0;
6449 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6450
6451 revert_fax_buffers(p, ast);
6452
6453 p->law = p->law_default;
6454 law = p->law_default;
6455 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6456 if (res < 0) {
6457 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6458 p->channel, strerror(errno));
6459 }
6460
6461 sig_ss7_hangup(p->sig_pvt, ast);
6462
6463 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6465
6466 x = 0;
6467 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6468 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6469
6471 reset_conf(p);
6472
6473 /* Restore data mode */
6474 x = 0;
6475 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6476
6477 if (num_restart_pending == 0) {
6479 }
6480 goto hangup_out;
6481 }
6482#endif /* defined(HAVE_SS7) */
6483
6484 idx = dahdi_get_index(ast, p, 1);
6485
6486 dahdi_confmute(p, 0);
6487 p->muting = 0;
6488 restore_gains(p);
6489 if (p->origcid_num) {
6490 ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
6492 p->origcid_num = NULL;
6493 }
6494 if (p->origcid_name) {
6495 ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
6497 p->origcid_name = NULL;
6498 }
6499 if (p->dsp)
6501
6502 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
6503 p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
6504 p->ignoredtmf = 0;
6505
6506 if (idx > -1) {
6507 /* Real channel, do some fixup */
6508 p->subs[idx].owner = NULL;
6509 p->subs[idx].needanswer = 0;
6510 p->subs[idx].needflash = 0;
6511 p->subs[idx].needringing = 0;
6512 p->subs[idx].needbusy = 0;
6513 p->subs[idx].needcongestion = 0;
6514 p->subs[idx].linear = 0;
6516 dahdi_setlinear(p->subs[idx].dfd, 0);
6517 if (idx == SUB_REAL) {
6518 if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
6519 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
6520 if (p->subs[SUB_CALLWAIT].inthreeway) {
6521 /* We had flipped over to answer a callwait and now it's gone */
6522 ast_debug(1, "We were flipped over to the callwait, moving back and not owning.\n");
6523 /* Move to the call-wait, but un-own us until they flip back. */
6526 p->owner = NULL;
6527 } else {
6528 /* The three way hung up, but we still have a call wait */
6529 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
6532 if (p->subs[SUB_REAL].inthreeway) {
6533 /* This was part of a three way call. Immediately make way for
6534 another call */
6535 ast_debug(1, "Call was complete, setting owner to former third call\n");
6536 p->owner = p->subs[SUB_REAL].owner;
6537 } else {
6538 /* This call hasn't been completed yet... Set owner to NULL */
6539 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6540 p->owner = NULL;
6541 }
6542 p->subs[SUB_REAL].inthreeway = 0;
6543 }
6544 } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
6545 /* Move to the call-wait and switch back to them. */
6548 p->owner = p->subs[SUB_REAL].owner;
6550 p->subs[SUB_REAL].needanswer = 1;
6552 } else if (p->subs[SUB_THREEWAY].dfd > -1) {
6555 if (p->subs[SUB_REAL].inthreeway) {
6556 /* This was part of a three way call. Immediately make way for
6557 another call */
6558 ast_debug(1, "Call was complete, setting owner to former third call\n");
6559 p->owner = p->subs[SUB_REAL].owner;
6560 } else {
6561 /* This call hasn't been completed yet... Set owner to NULL */
6562 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6563 p->owner = NULL;
6564 }
6565 p->subs[SUB_REAL].inthreeway = 0;
6566 }
6567 } else if (idx == SUB_CALLWAIT) {
6568 /* Ditch the holding callwait call, and immediately make it available */
6569 if (p->subs[SUB_CALLWAIT].inthreeway) {
6570 /* This is actually part of a three way, placed on hold. Place the third part
6571 on music on hold now */
6572 if (p->subs[SUB_THREEWAY].owner) {
6574 }
6576 /* Make it the call wait now */
6579 } else
6581 } else if (idx == SUB_THREEWAY) {
6582 if (p->subs[SUB_CALLWAIT].inthreeway) {
6583 /* The other party of the three way call is currently in a call-wait state.
6584 Start music on hold for them, and take the main guy out of the third call */
6585 if (p->subs[SUB_CALLWAIT].owner) {
6587 }
6589 }
6590 p->subs[SUB_REAL].inthreeway = 0;
6591 /* If this was part of a three way call index, let us make
6592 another three way call */
6594 } else {
6595 /* This wasn't any sort of call, but how are we an index? */
6596 ast_log(LOG_WARNING, "Index found but not any type of call?\n");
6597 }
6598 }
6599
6600 if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
6601 p->owner = NULL;
6602 p->ringt = 0;
6603 p->distinctivering = 0;
6604 p->confirmanswer = 0;
6605 p->outgoing = 0;
6606 p->digital = 0;
6607 p->faxhandled = 0;
6608 p->pulsedial = 0;
6609 if (p->dsp) {
6610 ast_dsp_free(p->dsp);
6611 p->dsp = NULL;
6612 }
6613
6614 revert_fax_buffers(p, ast);
6615
6616 p->law = p->law_default;
6617 law = p->law_default;
6618 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6619 if (res < 0)
6620 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
6621 /* Perform low level hangup if no owner left */
6622#ifdef HAVE_OPENR2
6623 if (p->mfcr2 && p->mfcr2call && openr2_chan_get_direction(p->r2chan) != OR2_DIR_STOPPED) {
6624 ast_debug(1, "disconnecting MFC/R2 call on chan %d\n", p->channel);
6625 /* If it's an incoming call, check the mfcr2_forced_release setting */
6626 if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
6627 dahdi_r2_disconnect_call(p, OR2_CAUSE_FORCED_RELEASE);
6628 } else {
6629 const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
6630 int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
6631 openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
6632 : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast));
6633 dahdi_r2_disconnect_call(p, r2cause);
6634 }
6635 } else if (p->mfcr2call) {
6636 ast_debug(1, "Clearing call request on channel %d\n", p->channel);
6637 /* since ast_request() was called but not ast_call() we have not yet dialed
6638 and the openr2 stack will not call on_call_end callback, we need to unset
6639 the mfcr2call flag and bump the monitor count so the monitor thread can take
6640 care of this channel events from now on */
6641 p->mfcr2call = 0;
6642 }
6643#endif
6644 switch (p->sig) {
6645 case SIG_SS7:
6646 case SIG_MFCR2:
6648 case 0:
6649 break;
6650 default:
6651 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
6652 break;
6653 }
6654 if (res < 0) {
6655 ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast_channel_name(ast));
6656 }
6657 switch (p->sig) {
6658 case SIG_FXOGS:
6659 case SIG_FXOLS:
6660 case SIG_FXOKS:
6661 memset(&par, 0, sizeof(par));
6662 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
6663 if (!res) {
6664 struct analog_pvt *analog_p = p->sig_pvt;
6665#if 0
6666 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
6667#endif
6668 /* If they're off hook, try playing congestion */
6669 if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
6670 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
6671 else
6672 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6673 analog_p->fxsoffhookstate = par.rxisoffhook;
6674 }
6675 break;
6676 case SIG_FXSGS:
6677 case SIG_FXSLS:
6678 case SIG_FXSKS:
6679 /* Make sure we're not made available for at least two seconds assuming
6680 we were actually used for an inbound or outbound call. */
6682 time(&p->guardtime);
6683 p->guardtime += 2;
6684 }
6685 break;
6686 default:
6687 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6688 break;
6689 }
6690 if (p->sig)
6692 x = 0;
6693 ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
6694 ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
6695 p->didtdd = 0;
6696 p->callwaitcas = 0;
6699 if (dahdi_analog_lib_handles(p->sig, p->radio, 0) && !p->owner) {
6700 /* The code in sig_analog handles resetting to permdialmode on originations;
6701 * this addresses the edge case of multiple calls that do not involve
6702 * origination inbetween, i.e. multiple incoming calls. */
6703 struct analog_pvt *analog_p = p->sig_pvt;
6704 /* If no calls remain, reset dialmode.
6705 * This way, if the next call is an incoming call,
6706 * it's already been reset. */
6707 analog_p->dialmode = analog_p->permdialmode;
6708 }
6709 p->waitingfordt.tv_sec = 0;
6710 p->dialing = 0;
6711 p->rdnis[0] = '\0';
6713 reset_conf(p);
6714 /* Restore data mode */
6715 switch (p->sig) {
6717 case SIG_SS7:
6718 x = 0;
6719 ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
6720 break;
6721 default:
6722 break;
6723 }
6724 if (num_restart_pending == 0)
6726 }
6727
6728 p->callwaitingrepeat = 0;
6729 p->cidcwexpire = 0;
6730 p->cid_suppress_expire = 0;
6731 p->oprmode = 0;
6732hangup_out:
6734 ast_free(p->cidspill);
6735 p->cidspill = NULL;
6736
6737 if (p->reoriginate && p->sig == SIG_FXOKS && dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6738 /* Automatic reorigination: if all calls towards a user have hung up,
6739 * give dial tone again, so user doesn't need to cycle the hook state manually. */
6740 if (my_is_off_hook(p) && !p->owner) {
6741 /* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
6742 ast_debug(1, "Queuing reorigination for channel %d\n", p->channel);
6743 my_play_tone(p, SUB_REAL, -1); /* Stop any congestion tone that may be present. */
6744 /* Must wait for the loop disconnect to end.
6745 * Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
6746 * Calling usleep on an active DAHDI channel is a no-no, but this is okay.
6747 */
6748 usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
6749 /* If the line is still off-hook and ownerless, actually queue the reorigination.
6750 * do_monitor will actually go ahead and do it. */
6751 if (!p->owner && my_is_off_hook(p)) {
6752 p->doreoriginate = 1; /* Tell do_monitor to reoriginate this channel */
6753 /* Note, my_off_hook will fail if called before the loop disconnect has finished
6754 * (important for FXOKS signaled channels). This is because DAHDI will reject
6755 * DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
6756 * so we have to wait for that to finish (see comment above).
6757 * do_monitor itself cannot block, so make the blocking usleep call
6758 * here in the channel thread instead.
6759 */
6760 my_off_hook(p); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
6761 } else {
6762 ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p->channel);
6763 }
6764 }
6765 }
6766
6768 ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
6769
6771 if (p->restartpending) {
6773 }
6774
6775 if (p->destroy) {
6776 destroy_channel(p, 0);
6777 }
6779
6781 return 0;
6782}
6783
6784static int dahdi_answer(struct ast_channel *ast)
6785{
6786 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6787 int res = 0;
6788 int idx;
6789 ast_setstate(ast, AST_STATE_UP);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
6790 ast_mutex_lock(&p->lock);
6791 idx = dahdi_get_index(ast, p, 0);
6792 if (idx < 0)
6793 idx = SUB_REAL;
6794 /* nothing to do if a radio channel */
6795 if ((p->radio || (p->oprmode < 0))) {
6797 return 0;
6798 }
6799
6800 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
6801 res = analog_answer(p->sig_pvt, ast);
6803 return res;
6804 }
6805
6806 switch (p->sig) {
6807#if defined(HAVE_PRI)
6809 res = sig_pri_answer(p->sig_pvt, ast);
6810 break;
6811#endif /* defined(HAVE_PRI) */
6812#if defined(HAVE_SS7)
6813 case SIG_SS7:
6814 res = sig_ss7_answer(p->sig_pvt, ast);
6815 break;
6816#endif /* defined(HAVE_SS7) */
6817#ifdef HAVE_OPENR2
6818 case SIG_MFCR2:
6819 if (!p->mfcr2_call_accepted) {
6820 /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
6821 openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
6822 p->mfcr2_answer_pending = 1;
6823 if (p->mfcr2_charge_calls) {
6824 ast_debug(1, "Accepting MFC/R2 call with charge before answering on chan %d\n", p->channel);
6825 openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
6826 } else {
6827 ast_debug(1, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p->channel);
6828 openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
6829 }
6830 } else {
6831 ast_debug(1, "Answering MFC/R2 call on chan %d\n", p->channel);
6832 dahdi_r2_answer(p);
6833 }
6834 break;
6835#endif
6836 case 0:
6838 return 0;
6839 default:
6840 ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
6841 res = -1;
6842 break;
6843 }
6845 return res;
6846}
6847
6849{
6850 int val = 0;
6851
6852 p->ignoredtmf = 1;
6853
6854 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6855
6856 if (!p->hardwaredtmf && p->dsp) {
6857 p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
6859 }
6860}
6861
6863{
6864 int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
6865
6866 if (p->channel == CHAN_PSEUDO)
6867 return;
6868
6869 p->ignoredtmf = 0;
6870
6871 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6872
6873 if (!p->hardwaredtmf && p->dsp) {
6876 }
6877}
6878
6879static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
6880{
6881 char *cp;
6882 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
6883
6884 /* all supported options require data */
6885 if (!p || !data || (*datalen < 1)) {
6886 errno = EINVAL;
6887 return -1;
6888 }
6889
6890 switch (option) {
6891 case AST_OPTION_TDD:
6892 cp = (char *) data;
6893 if (p->mate) {
6894 *cp = 2;
6895 } else {
6896 *cp = p->tdd ? 1 : 0;
6897 }
6898 break;
6900 cp = (char *) data;
6901 *cp = p->ignoredtmf ? 0 : 1;
6902 ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6903 break;
6905 cp = (char *) data;
6906 *cp = (p->dsp_features & DSP_FEATURE_FAX_DETECT) ? 0 : 1;
6907 ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6908 break;
6910#if defined(HAVE_PRI)
6911#if defined(HAVE_PRI_CCSS)
6913 ast_copy_string((char *) data, dahdi_pri_cc_type, *datalen);
6914 break;
6915 }
6916#endif /* defined(HAVE_PRI_CCSS) */
6917#endif /* defined(HAVE_PRI) */
6918 return -1;
6919 default:
6920 return -1;
6921 }
6922
6923 errno = 0;
6924
6925 return 0;
6926}
6927
6928static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
6929{
6930 char *cp;
6931 signed char *scp;
6932 int x;
6933 int idx;
6934 struct dahdi_pvt *p = ast_channel_tech_pvt(chan), *pp;
6935 struct oprmode *oprmode;
6936
6937
6938 /* all supported options require data */
6939 if (!p || !data || (datalen < 1)) {
6940 errno = EINVAL;
6941 return -1;
6942 }
6943
6944 switch (option) {
6945 case AST_OPTION_TXGAIN:
6946 scp = (signed char *) data;
6947 idx = dahdi_get_index(chan, p, 0);
6948 if (idx < 0) {
6949 ast_log(LOG_WARNING, "No index in TXGAIN?\n");
6950 return -1;
6951 }
6952 ast_debug(1, "Setting actual tx gain on %s to %f\n", ast_channel_name(chan), p->txgain + (float) *scp);
6953 return set_actual_txgain(p->subs[idx].dfd, p->txgain + (float) *scp, p->txdrc, p->law);
6954 case AST_OPTION_RXGAIN:
6955 scp = (signed char *) data;
6956 idx = dahdi_get_index(chan, p, 0);
6957 if (idx < 0) {
6958 ast_log(LOG_WARNING, "No index in RXGAIN?\n");
6959 return -1;
6960 }
6961 ast_debug(1, "Setting actual rx gain on %s to %f\n", ast_channel_name(chan), p->rxgain + (float) *scp);
6962 return set_actual_rxgain(p->subs[idx].dfd, p->rxgain + (float) *scp, p->rxdrc, p->law);
6964 if (!p->dsp)
6965 break;
6966 cp = (char *) data;
6967 switch (*cp) {
6968 case 1:
6969 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",ast_channel_name(chan));
6970 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */
6971 break;
6972 case 2:
6973 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",ast_channel_name(chan));
6974 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */
6975 break;
6976 default:
6977 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",ast_channel_name(chan));
6978 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */
6979 break;
6980 }
6981 break;
6982 case AST_OPTION_TDD:
6983 /* turn on or off TDD */
6984 cp = (char *) data;
6985 p->mate = 0;
6986 if (!*cp) { /* turn it off */
6987 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",ast_channel_name(chan));
6988 if (p->tdd)
6989 tdd_free(p->tdd);
6990 p->tdd = 0;
6991 break;
6992 }
6993 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
6994 (*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
6996 /* otherwise, turn it on */
6997 if (!p->didtdd) { /* if haven't done it yet */
6998 unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
6999 unsigned char *buf;
7000 int size, res, fd, len;
7001 struct pollfd fds[1];
7002
7003 buf = mybuf;
7004 memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
7005 ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */
7006 len = 40000;
7007 idx = dahdi_get_index(chan, p, 0);
7008 if (idx < 0) {
7009 ast_log(LOG_WARNING, "No index in TDD?\n");
7010 return -1;
7011 }
7012 fd = p->subs[idx].dfd;
7013 while (len) {
7014 if (ast_check_hangup(chan))
7015 return -1;
7016 size = len;
7017 if (size > READ_SIZE)
7018 size = READ_SIZE;
7019 fds[0].fd = fd;
7020 fds[0].events = POLLPRI | POLLOUT;
7021 fds[0].revents = 0;
7022 res = poll(fds, 1, -1);
7023 if (!res) {
7024 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
7025 continue;
7026 }
7027 /* if got exception */
7028 if (fds[0].revents & POLLPRI)
7029 return -1;
7030 if (!(fds[0].revents & POLLOUT)) {
7031 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
7032 continue;
7033 }
7034 res = write(fd, buf, size);
7035 if (res != size) {
7036 if (res == -1) return -1;
7037 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
7038 break;
7039 }
7040 len -= size;
7041 buf += size;
7042 }
7043 p->didtdd = 1; /* set to have done it now */
7044 }
7045 if (*cp == 2) { /* Mate mode */
7046 if (p->tdd)
7047 tdd_free(p->tdd);
7048 p->tdd = 0;
7049 p->mate = 1;
7050 break;
7051 }
7052 if (!p->tdd) { /* if we don't have one yet */
7053 p->tdd = tdd_new(); /* allocate one */
7054 }
7055 break;
7056 case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */
7057 if (!p->dsp)
7058 break;
7059 cp = (char *) data;
7060 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
7061 *cp ? "ON" : "OFF", (int) *cp, ast_channel_name(chan));
7063 break;
7064 case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */
7065#if defined(HAVE_PRI)
7067 && ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
7068 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
7069 break;
7070 }
7071#endif /* defined(HAVE_PRI) */
7072
7073 cp = (char *) data;
7074 if (!*cp) {
7075 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
7076 x = 0;
7078 } else {
7079 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
7080 x = 1;
7081 }
7082 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
7083 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
7084 break;
7085 case AST_OPTION_OPRMODE: /* Operator services mode */
7086 oprmode = (struct oprmode *) data;
7087 /* We don't support operator mode across technologies */
7088 if (strcasecmp(ast_channel_tech(chan)->type, ast_channel_tech(oprmode->peer)->type)) {
7089 ast_log(LOG_NOTICE, "Operator mode not supported on %s to %s calls.\n",
7091 errno = EINVAL;
7092 return -1;
7093 }
7095 p->oprmode = pp->oprmode = 0;
7096 /* setup peers */
7097 p->oprpeer = pp;
7098 pp->oprpeer = p;
7099 /* setup modes, if any */
7100 if (oprmode->mode)
7101 {
7102 pp->oprmode = oprmode->mode;
7103 p->oprmode = -oprmode->mode;
7104 }
7105 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
7107 break;
7108 case AST_OPTION_ECHOCAN:
7109 cp = (char *) data;
7110 if (*cp) {
7111 ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
7112 dahdi_ec_enable(p);
7113 } else {
7114 ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
7116 }
7117 break;
7119 cp = (char *) data;
7120 ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7121 if (*cp) {
7123 } else {
7125 }
7126 break;
7128 cp = (char *) data;
7129 if (p->dsp) {
7130 ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7131 if (*cp) {
7133 } else {
7134 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7135 }
7137 }
7138 break;
7139 default:
7140 return -1;
7141 }
7142 errno = 0;
7143
7144 return 0;
7145}
7146
7147static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
7148{
7149 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7150 int res = 0;
7151
7152 if (!p) {
7153 /* No private structure! */
7154 *buf = '\0';
7155 return -1;
7156 }
7157
7158 if (!strcasecmp(data, "rxgain")) {
7159 ast_mutex_lock(&p->lock);
7160 snprintf(buf, len, "%f", p->rxgain);
7162 } else if (!strcasecmp(data, "txgain")) {
7163 ast_mutex_lock(&p->lock);
7164 snprintf(buf, len, "%f", p->txgain);
7166 } else if (!strcasecmp(data, "dahdi_channel")) {
7167 ast_mutex_lock(&p->lock);
7168 snprintf(buf, len, "%d", p->channel);
7170 } else if (!strcasecmp(data, "dahdi_span")) {
7171 ast_mutex_lock(&p->lock);
7172 snprintf(buf, len, "%d", p->span);
7174 } else if (!strcasecmp(data, "dahdi_group")) {
7175 ast_mutex_lock(&p->lock);
7176 snprintf(buf, len, "%llu", p->group);
7178 } else if (!strcasecmp(data, "dahdi_type")) {
7179 ast_mutex_lock(&p->lock);
7180 switch (p->sig) {
7181#if defined(HAVE_OPENR2)
7182 case SIG_MFCR2:
7183 ast_copy_string(buf, "mfc/r2", len);
7184 break;
7185#endif /* defined(HAVE_OPENR2) */
7186#if defined(HAVE_PRI)
7188 ast_copy_string(buf, "pri", len);
7189 break;
7190#endif /* defined(HAVE_PRI) */
7191 case 0:
7192 ast_copy_string(buf, "pseudo", len);
7193 break;
7194#if defined(HAVE_SS7)
7195 case SIG_SS7:
7196 ast_copy_string(buf, "ss7", len);
7197 break;
7198#endif /* defined(HAVE_SS7) */
7199 default:
7200 /* The only thing left is analog ports. */
7201 ast_copy_string(buf, "analog", len);
7202 break;
7203 }
7205#if defined(HAVE_PRI)
7206#if defined(HAVE_PRI_REVERSE_CHARGE)
7207 } else if (!strcasecmp(data, "reversecharge")) {
7208 ast_mutex_lock(&p->lock);
7209 switch (p->sig) {
7211 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->reverse_charging_indication);
7212 break;
7213 default:
7214 *buf = '\0';
7215 res = -1;
7216 break;
7217 }
7219#endif
7220#if defined(HAVE_PRI_SETUP_KEYPAD)
7221 } else if (!strcasecmp(data, "keypad_digits")) {
7222 ast_mutex_lock(&p->lock);
7223 switch (p->sig) {
7225 ast_copy_string(buf, ((struct sig_pri_chan *) p->sig_pvt)->keypad_digits,
7226 len);
7227 break;
7228 default:
7229 *buf = '\0';
7230 res = -1;
7231 break;
7232 }
7234#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
7235 } else if (!strcasecmp(data, "no_media_path")) {
7236 ast_mutex_lock(&p->lock);
7237 switch (p->sig) {
7239 /*
7240 * TRUE if the call is on hold or is call waiting because
7241 * there is no media path available.
7242 */
7243 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel);
7244 break;
7245 default:
7246 *buf = '\0';
7247 res = -1;
7248 break;
7249 }
7251#endif /* defined(HAVE_PRI) */
7252 } else if (!strcasecmp(data, "dialmode")) {
7253 struct analog_pvt *analog_p;
7254 ast_mutex_lock(&p->lock);
7255 analog_p = p->sig_pvt;
7256 /* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
7257 if (dahdi_analog_lib_handles(p->sig, 0, 0) && analog_p) {
7258 switch (analog_p->dialmode) {
7260 ast_copy_string(buf, "both", len);
7261 break;
7263 ast_copy_string(buf, "pulse", len);
7264 break;
7266 ast_copy_string(buf, "dtmf", len);
7267 break;
7269 ast_copy_string(buf, "none", len);
7270 break;
7271 }
7272 } else {
7273 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7274 *buf = '\0';
7275 res = -1;
7276 }
7278 } else {
7279 *buf = '\0';
7280 res = -1;
7281 }
7282
7283 return res;
7284}
7285
7286
7287static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
7288{
7289 int res;
7290 char policy_str[21] = "";
7291
7292 if ((res = sscanf(parse, "%30d,%20s", num_buffers, policy_str)) != 2) {
7293 ast_log(LOG_WARNING, "Parsing buffer string '%s' failed.\n", parse);
7294 return 1;
7295 }
7296 if (*num_buffers < 0) {
7297 ast_log(LOG_WARNING, "Invalid buffer count given '%d'.\n", *num_buffers);
7298 return -1;
7299 }
7300 if (!strcasecmp(policy_str, "full")) {
7301 *policy = DAHDI_POLICY_WHEN_FULL;
7302 } else if (!strcasecmp(policy_str, "immediate")) {
7303 *policy = DAHDI_POLICY_IMMEDIATE;
7304#if defined(HAVE_DAHDI_HALF_FULL)
7305 } else if (!strcasecmp(policy_str, "half")) {
7306 *policy = DAHDI_POLICY_HALF_FULL;
7307#endif
7308 } else {
7309 ast_log(LOG_WARNING, "Invalid policy name given '%s'.\n", policy_str);
7310 return -1;
7311 }
7312
7313 return 0;
7314}
7315
7316static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
7317{
7318 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7319 int res = 0;
7320
7321 if (!p) {
7322 /* No private structure! */
7323 return -1;
7324 }
7325
7326 if (!strcasecmp(data, "buffers")) {
7327 int num_bufs, policy;
7328
7329 if (!(parse_buffers_policy(value, &num_bufs, &policy))) {
7330 struct dahdi_bufferinfo bi = {
7331 .txbufpolicy = policy,
7332 .rxbufpolicy = policy,
7333 .bufsize = p->bufsize,
7334 .numbufs = num_bufs,
7335 };
7336 int bpres;
7337
7338 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7339 ast_log(LOG_WARNING, "Channel '%d' unable to override buffer policy: %s\n", p->channel, strerror(errno));
7340 } else {
7341 p->bufferoverrideinuse = 1;
7342 }
7343 } else {
7344 res = -1;
7345 }
7346 } else if (!strcasecmp(data, "echocan_mode")) {
7347 if (!strcasecmp(value, "on")) {
7348 ast_mutex_lock(&p->lock);
7349 dahdi_ec_enable(p);
7351 } else if (!strcasecmp(value, "off")) {
7352 ast_mutex_lock(&p->lock);
7355#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7356 } else if (!strcasecmp(value, "fax")) {
7357 int blah = 1;
7358
7359 ast_mutex_lock(&p->lock);
7360 if (!p->echocanon) {
7361 dahdi_ec_enable(p);
7362 }
7363 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7364 ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
7365 }
7367 } else if (!strcasecmp(value, "voice")) {
7368 int blah = 0;
7369
7370 ast_mutex_lock(&p->lock);
7371 if (!p->echocanon) {
7372 dahdi_ec_enable(p);
7373 }
7374 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7375 ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
7376 }
7378#endif
7379 } else {
7380 ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
7381 res = -1;
7382 }
7383 } else if (!strcasecmp(data, "dialmode")) {
7384 struct analog_pvt *analog_p;
7385
7386 ast_mutex_lock(&p->lock);
7387 analog_p = p->sig_pvt;
7388 if (!dahdi_analog_lib_handles(p->sig, 0, 0) || !analog_p) {
7389 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7391 return -1;
7392 }
7393 /* analog pvt is used for pulse dialing, so update both */
7394 if (!strcasecmp(value, "pulse")) {
7395 analog_p->dialmode = ANALOG_DIALMODE_PULSE;
7396 } else if (!strcasecmp(value, "dtmf") || !strcasecmp(value, "tone")) {
7397 analog_p->dialmode = ANALOG_DIALMODE_DTMF;
7398 } else if (!strcasecmp(value, "none")) {
7399 analog_p->dialmode = ANALOG_DIALMODE_NONE;
7400 } else if (!strcasecmp(value, "both")) {
7401 analog_p->dialmode = ANALOG_DIALMODE_BOTH;
7402 } else {
7403 ast_log(LOG_WARNING, "'%s' is an invalid setting for %s\n", value, data);
7404 res = -1;
7405 }
7407 } else if (!strcasecmp(data, "waitfordialtone")) {
7408 if (ast_strlen_zero(value)) {
7409 ast_log(LOG_WARNING, "waitfordialtone requires a duration in ms\n");
7410 return -1;
7411 }
7412
7413 ast_mutex_lock(&p->lock);
7414 if (!CANPROGRESSDETECT(p)) {
7415 ast_log(LOG_WARNING, "%s only supported on analog trunks\n", data);
7417 return -1;
7418 }
7419 /* Only set the temp waitfordialtone setting, not the permanent one. */
7420 p->waitfordialtonetemp = atoi(value);
7422 } else {
7423 res = -1;
7424 }
7425
7426 return res;
7427}
7428
7429void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
7430{
7431 /* Unlink a specific slave or all slaves/masters from a given master */
7432 int x;
7433 int hasslaves;
7434 if (!master)
7435 return;
7436 if (needlock) {
7437 ast_mutex_lock(&master->lock);
7438 if (slave) {
7439 while (ast_mutex_trylock(&slave->lock)) {
7440 DEADLOCK_AVOIDANCE(&master->lock);
7441 }
7442 }
7443 }
7444 hasslaves = 0;
7445 for (x = 0; x < MAX_SLAVES; x++) {
7446 if (master->slaves[x]) {
7447 if (!slave || (master->slaves[x] == slave)) {
7448 /* Take slave out of the conference */
7449 ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
7450 conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
7451 conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
7452 master->slaves[x]->master = NULL;
7453 master->slaves[x] = NULL;
7454 } else
7455 hasslaves = 1;
7456 }
7457 if (!hasslaves)
7458 master->inconference = 0;
7459 }
7460 if (!slave) {
7461 if (master->master) {
7462 /* Take master out of the conference */
7463 conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
7464 conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
7465 hasslaves = 0;
7466 for (x = 0; x < MAX_SLAVES; x++) {
7467 if (master->master->slaves[x] == master)
7468 master->master->slaves[x] = NULL;
7469 else if (master->master->slaves[x])
7470 hasslaves = 1;
7471 }
7472 if (!hasslaves)
7473 master->master->inconference = 0;
7474 }
7475 master->master = NULL;
7476 }
7477 dahdi_conf_update(master);
7478 if (needlock) {
7479 if (slave)
7480 ast_mutex_unlock(&slave->lock);
7481 ast_mutex_unlock(&master->lock);
7482 }
7483}
7484
7485void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
7486{
7487 int x;
7488 if (!slave || !master) {
7489 ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
7490 return;
7491 }
7492 for (x = 0; x < MAX_SLAVES; x++) {
7493 if (!master->slaves[x]) {
7494 master->slaves[x] = slave;
7495 break;
7496 }
7497 }
7498 if (x >= MAX_SLAVES) {
7499 ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
7500 master->slaves[MAX_SLAVES - 1] = slave;
7501 }
7502 if (slave->master)
7503 ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
7504 slave->master = master;
7505
7506 ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
7507}
7508
7509static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
7510{
7511 struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
7512 int x;
7513
7514 ast_mutex_lock(&p->lock);
7515
7516 ast_debug(1, "New owner for channel %d is %s\n", p->channel, ast_channel_name(newchan));
7517 if (p->owner == oldchan) {
7518 p->owner = newchan;
7519 }
7520 for (x = 0; x < 3; x++) {
7521 if (p->subs[x].owner == oldchan) {
7522 if (!x) {
7524 }
7525 p->subs[x].owner = newchan;
7526 }
7527 }
7528 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
7529 analog_fixup(oldchan, newchan, p->sig_pvt);
7530#if defined(HAVE_PRI)
7531 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
7532 sig_pri_fixup(oldchan, newchan, p->sig_pvt);
7533#endif /* defined(HAVE_PRI) */
7534#if defined(HAVE_SS7)
7535 } else if (p->sig == SIG_SS7) {
7536 sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
7537#endif /* defined(HAVE_SS7) */
7538 }
7540
7542
7543 if (ast_channel_state(newchan) == AST_STATE_RINGING) {
7545 }
7546 return 0;
7547}
7548
7549static int dahdi_ring_phone(struct dahdi_pvt *p)
7550{
7551 int x;
7552 int res;
7553 /* Make sure our transmit state is on hook */
7554 x = 0;
7555 x = DAHDI_ONHOOK;
7556 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7557 do {
7558 x = DAHDI_RING;
7559 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7560 if (res) {
7561 switch (errno) {
7562 case EBUSY:
7563 case EINTR:
7564 /* Wait just in case */
7565 usleep(10000);
7566 continue;
7567 case EINPROGRESS:
7568 res = 0;
7569 break;
7570 default:
7571 ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
7572 res = 0;
7573 }
7574 }
7575 } while (res);
7576 return res;
7577}
7578
7579static void *analog_ss_thread(void *data);
7580
7581/*!
7582 * \internal
7583 * \brief Attempt to transfer 3-way call.
7584 *
7585 * \param p DAHDI private structure.
7586 *
7587 * \note On entry these locks are held: real-call, private, 3-way call.
7588 * \note On exit these locks are held: real-call, private.
7589 *
7590 * \retval 0 on success.
7591 * \retval -1 on error.
7592 */
7593static int attempt_transfer(struct dahdi_pvt *p)
7594{
7595 struct ast_channel *owner_real;
7596 struct ast_channel *owner_3way;
7597 enum ast_transfer_result xfer_res;
7598 int res = 0;
7599
7600 owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
7601 owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
7602
7603 ast_verb(3, "TRANSFERRING %s to %s\n",
7604 ast_channel_name(owner_3way), ast_channel_name(owner_real));
7605
7606 ast_channel_unlock(owner_real);
7607 ast_channel_unlock(owner_3way);
7609
7610 xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
7611 if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
7613 res = -1;
7614 }
7615
7616 /* Must leave with these locked. */
7617 ast_channel_lock(owner_real);
7618 ast_mutex_lock(&p->lock);
7619
7620 ast_channel_unref(owner_real);
7621 ast_channel_unref(owner_3way);
7622
7623 return res;
7624}
7625
7626static int check_for_conference(struct dahdi_pvt *p)
7627{
7628 struct dahdi_confinfo ci;
7629 /* Fine if we already have a master, etc */
7630 if (p->master || (p->confno > -1))
7631 return 0;
7632 memset(&ci, 0, sizeof(ci));
7633 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
7634 ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
7635 return 0;
7636 }
7637 /* If we have no master and don't have a confno, then
7638 if we're in a conference, it's probably a MeetMe room or
7639 some such, so don't let us 3-way out! */
7640 if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
7641 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
7642 return 1;
7643 }
7644 return 0;
7645}
7646
7647/*! Checks channel for alarms
7648 * \param p a channel to check for alarms.
7649 * \returns the alarms on the span to which the channel belongs, or alarms on
7650 * the channel if no span alarms.
7651 */
7652static int get_alarms(struct dahdi_pvt *p)
7653{
7654 int res;
7655 struct dahdi_spaninfo zi;
7656 struct dahdi_params params;
7657
7658 memset(&zi, 0, sizeof(zi));
7659 zi.spanno = p->span;
7660
7661 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
7662 if (zi.alarms != DAHDI_ALARM_NONE)
7663 return zi.alarms;
7664 } else {
7665 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
7666 return 0;
7667 }
7668
7669 /* No alarms on the span. Check for channel alarms. */
7670 memset(&params, 0, sizeof(params));
7671 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
7672 return params.chan_alarms;
7673
7674 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
7675
7676 return DAHDI_ALARM_NONE;
7677}
7678
7679static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
7680{
7681 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7682 struct ast_frame *f = *dest;
7683
7684 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
7685 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
7686 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
7687
7688 if (p->confirmanswer) {
7689 if (f->frametype == AST_FRAME_DTMF_END) {
7690 ast_debug(1, "Confirm answer on %s!\n", ast_channel_name(ast));
7691 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
7692 of a DTMF digit */
7695 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
7696 p->confirmanswer = 0;
7697 } else {
7698 p->subs[idx].f.frametype = AST_FRAME_NULL;
7699 p->subs[idx].f.subclass.integer = 0;
7700 }
7701 *dest = &p->subs[idx].f;
7702 } else if (p->callwaitcas) {
7703 if (f->frametype == AST_FRAME_DTMF_END) {
7704 if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
7705 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
7706 ast_free(p->cidspill);
7707 p->cidspill = NULL;
7708 send_cwcidspill(p);
7709 }
7710 p->callwaitcas = 0;
7711 }
7712 p->subs[idx].f.frametype = AST_FRAME_NULL;
7713 p->subs[idx].f.subclass.integer = 0;
7714 *dest = &p->subs[idx].f;
7715 } else if (f->subclass.integer == 'f') {
7716 if (f->frametype == AST_FRAME_DTMF_END) {
7717 /* Fax tone -- Handle and return NULL */
7718 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
7719 /* If faxbuffers are configured, use them for the fax transmission */
7720 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
7721 struct dahdi_bufferinfo bi = {
7722 .txbufpolicy = p->faxbuf_policy,
7723 .bufsize = p->bufsize,
7724 .numbufs = p->faxbuf_no
7725 };
7726 int res;
7727
7728 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7729 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
7730 } else {
7731 p->bufferoverrideinuse = 1;
7732 }
7733 }
7734 p->faxhandled = 1;
7735 if (p->dsp) {
7736 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7738 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
7739 }
7740 if (strcmp(ast_channel_exten(ast), "fax")) {
7741 const char *target_context = ast_channel_context(ast);
7742
7743 /*
7744 * We need to unlock 'ast' here because ast_exists_extension has the
7745 * potential to start autoservice on the channel. Such action is prone
7746 * to deadlock if the channel is locked.
7747 *
7748 * ast_async_goto() has its own restriction on not holding the
7749 * channel lock.
7750 */
7752 ast_channel_unlock(ast);
7753 if (ast_exists_extension(ast, target_context, "fax", 1,
7754 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
7755 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
7756 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
7757 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
7758 if (ast_async_goto(ast, target_context, "fax", 1))
7759 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
7760 } else {
7761 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
7762 }
7763 ast_channel_lock(ast);
7764 ast_mutex_lock(&p->lock);
7765 } else {
7766 ast_debug(1, "Already in a fax extension, not redirecting\n");
7767 }
7768 } else {
7769 ast_debug(1, "Fax already handled\n");
7770 }
7771 dahdi_confmute(p, 0);
7772 }
7773 p->subs[idx].f.frametype = AST_FRAME_NULL;
7774 p->subs[idx].f.subclass.integer = 0;
7775 *dest = &p->subs[idx].f;
7776 }
7777}
7778
7779static void publish_span_alarm(int span, const char *alarm_txt)
7780{
7781 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7782
7783 body = ast_json_pack("{s: i, s: s}",
7784 "Span", span,
7785 "Alarm", alarm_txt);
7786 if (!body) {
7787 return;
7788 }
7789
7790 ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
7791}
7792
7793static void publish_channel_alarm(int channel, const char *alarm_txt)
7794{
7795 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7796 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
7797 if (!dahdi_chan) {
7798 return;
7799 }
7800
7801 ast_str_set(&dahdi_chan, 0, "%d", channel);
7802 body = ast_json_pack("{s: s, s: s}",
7803 "DAHDIChannel", ast_str_buffer(dahdi_chan),
7804 "Alarm", alarm_txt);
7805 if (!body) {
7806 return;
7807 }
7808
7810}
7811
7812static void handle_alarms(struct dahdi_pvt *p, int alms)
7813{
7814 const char *alarm_str;
7815
7816#if defined(HAVE_PRI)
7818 return;
7819 }
7820#endif /* defined(HAVE_PRI) */
7821
7822 alarm_str = alarm2str(alms);
7824 ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
7825 publish_channel_alarm(p->channel, alarm_str);
7826 }
7827
7829 ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
7830 publish_span_alarm(p->span, alarm_str);
7831 }
7832}
7833
7834static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
7835{
7836 int res, x;
7837 int idx, mysig;
7838 char *c;
7839 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7840 pthread_t threadid;
7841 struct ast_channel *chan;
7842 struct ast_frame *f;
7843
7844 idx = dahdi_get_index(ast, p, 0);
7845 if (idx < 0) {
7846 return &ast_null_frame;
7847 }
7848 mysig = p->sig;
7849 if (p->outsigmod > -1)
7850 mysig = p->outsigmod;
7851 p->subs[idx].f.frametype = AST_FRAME_NULL;
7852 p->subs[idx].f.subclass.integer = 0;
7853 p->subs[idx].f.datalen = 0;
7854 p->subs[idx].f.samples = 0;
7855 p->subs[idx].f.mallocd = 0;
7856 p->subs[idx].f.offset = 0;
7857 p->subs[idx].f.src = "dahdi_handle_event";
7858 p->subs[idx].f.data.ptr = NULL;
7859 f = &p->subs[idx].f;
7860
7861 if (p->fake_event) {
7862 res = p->fake_event;
7863 p->fake_event = 0;
7864 } else
7865 res = dahdi_get_event(p->subs[idx].dfd);
7866
7867 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
7868
7869 if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
7870 p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
7871 ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
7872#if defined(HAVE_PRI)
7874 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7875 && p->pri
7876 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7877 /* absorb event */
7878 } else
7879#endif /* defined(HAVE_PRI) */
7880 {
7881 /* Unmute conference */
7882 dahdi_confmute(p, 0);
7884 p->subs[idx].f.subclass.integer = res & 0xff;
7885 dahdi_handle_dtmf(ast, idx, &f);
7886 }
7887 return f;
7888 }
7889
7890 if (res & DAHDI_EVENT_DTMFDOWN) {
7891 ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
7892#if defined(HAVE_PRI)
7894 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7895 && p->pri
7896 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7897 /* absorb event */
7898 } else
7899#endif /* defined(HAVE_PRI) */
7900 {
7901 /* Mute conference */
7902 dahdi_confmute(p, 1);
7904 p->subs[idx].f.subclass.integer = res & 0xff;
7905 dahdi_handle_dtmf(ast, idx, &f);
7906 }
7907 return &p->subs[idx].f;
7908 }
7909
7910 switch (res) {
7911 case DAHDI_EVENT_EC_DISABLED:
7912 ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
7913 p->echocanon = 0;
7914 break;
7915#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7916 case DAHDI_EVENT_TX_CED_DETECTED:
7917 ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
7918 break;
7919 case DAHDI_EVENT_RX_CED_DETECTED:
7920 ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
7921 break;
7922 case DAHDI_EVENT_EC_NLP_DISABLED:
7923 ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
7924 break;
7925 case DAHDI_EVENT_EC_NLP_ENABLED:
7926 ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
7927 break;
7928#endif
7929 case DAHDI_EVENT_BITSCHANGED:
7930#ifdef HAVE_OPENR2
7931 if (p->sig != SIG_MFCR2) {
7932 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7933 } else {
7934 ast_debug(1, "bits changed in chan %d\n", p->channel);
7935 openr2_chan_handle_cas(p->r2chan);
7936 }
7937#else
7938 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7939#endif
7940 break;
7941 case DAHDI_EVENT_PULSE_START:
7942 /* Stop tone if there's a pulse start and the PBX isn't started */
7943 if (!ast_channel_pbx(ast))
7944 tone_zone_play_tone(p->subs[idx].dfd, -1);
7945 break;
7946 case DAHDI_EVENT_DIALCOMPLETE:
7947 /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
7948#if defined(HAVE_PRI)
7950 if (p->inalarm) {
7951 break;
7952 }
7953 if (ioctl(p->subs[idx].dfd, DAHDI_DIALING, &x) == -1) {
7954 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
7955 ast_channel_name(ast), strerror(errno));
7956 return NULL;
7957 }
7958 if (x) {
7959 /* Still dialing in DAHDI driver */
7960 break;
7961 }
7962 /*
7963 * The ast channel is locked and the private may be locked more
7964 * than once.
7965 */
7967 break;
7968 }
7969#endif /* defined(HAVE_PRI) */
7970#ifdef HAVE_OPENR2
7971 if ((p->sig & SIG_MFCR2) && p->r2chan && ast_channel_state(ast) != AST_STATE_UP) {
7972 /* we don't need to do anything for this event for R2 signaling
7973 if the call is being setup */
7974 break;
7975 }
7976#endif
7977 if (p->inalarm) break;
7978 if ((p->radio || (p->oprmode < 0))) break;
7979 if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
7980 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",ast_channel_name(ast), strerror(errno));
7981 return NULL;
7982 }
7983 if (!x) { /* if not still dialing in driver */
7984 dahdi_ec_enable(p);
7985 if (p->echobreak) {
7986 dahdi_train_ec(p);
7987 ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
7988 p->dop.op = DAHDI_DIAL_OP_REPLACE;
7989 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
7990 p->echobreak = 0;
7991 } else {
7992 p->dialing = 0;
7993 if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
7994 /* if thru with dialing after offhook */
7999 break;
8000 } else { /* if to state wait for offhook to dial rest */
8001 /* we now wait for off hook */
8003 }
8004 }
8006 if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
8007 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
8008 } else if (p->confirmanswer || (!p->dialednone
8009 && ((mysig == SIG_EM) || (mysig == SIG_EM_E1)
8010 || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD)
8011 || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF)
8012 || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA)
8013 || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB)
8014 || (mysig == SIG_SF) || (mysig == SIG_SFWINK)
8015 || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF)
8016 || (mysig == SIG_SF_FEATB)))) {
8018 } else if (!p->answeronpolarityswitch) {
8022 /* If aops=0 and hops=1, this is necessary */
8024 } else {
8025 /* Start clean, so we can catch the change to REV polarity when party answers */
8027 }
8028 }
8029 }
8030 }
8031 break;
8032 case DAHDI_EVENT_ALARM:
8033 switch (p->sig) {
8034#if defined(HAVE_PRI)
8037 break;
8038#endif /* defined(HAVE_PRI) */
8039#if defined(HAVE_SS7)
8040 case SIG_SS7:
8042 break;
8043#endif /* defined(HAVE_SS7) */
8044 default:
8045 p->inalarm = 1;
8046 break;
8047 }
8048 res = get_alarms(p);
8049 handle_alarms(p, res);
8050#ifdef HAVE_PRI
8051 if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
8052 /* fall through intentionally */
8053 } else {
8054 break;
8055 }
8056#endif
8057#if defined(HAVE_SS7)
8058 if (p->sig == SIG_SS7)
8059 break;
8060#endif /* defined(HAVE_SS7) */
8061#ifdef HAVE_OPENR2
8062 if (p->sig == SIG_MFCR2)
8063 break;
8064#endif
8065 case DAHDI_EVENT_ONHOOK:
8066 if (p->radio) {
8069 break;
8070 }
8071 if (p->oprmode < 0)
8072 {
8073 if (p->oprmode != -1) { /* Operator flash recall */
8074 ast_verb(4, "Operator mode enabled on channel %d, holding line for channel %d\n", p->channel, p->oprpeer->channel);
8075 break;
8076 }
8077 /* Otherwise, immediate recall */
8078 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
8079 {
8080 /* Make sure it starts ringing */
8081 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8082 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
8084 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8085 ast_verb(4, "Operator recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8086 }
8087 break;
8088 }
8089 switch (p->sig) {
8090 case SIG_FXOLS:
8091 case SIG_FXOGS:
8092 case SIG_FXOKS:
8093 /* Check for some special conditions regarding call waiting */
8094 if (idx == SUB_REAL) {
8095 /* The normal line was hung up */
8096 if (p->subs[SUB_CALLWAIT].owner) {
8097 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
8099 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
8101#if 0
8102 p->subs[idx].needanswer = 0;
8103 p->subs[idx].needringing = 0;
8104#endif
8105 p->callwaitingrepeat = 0;
8106 p->cidcwexpire = 0;
8107 p->cid_suppress_expire = 0;
8108 p->owner = NULL;
8109 /* Don't start streaming audio yet if the incoming call isn't up yet */
8111 p->dialing = 1;
8113 } else if (p->subs[SUB_THREEWAY].owner) {
8114 unsigned int mssinceflash;
8115 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
8116 the private structure -- not especially easy or clean */
8118 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
8119 DLA_UNLOCK(&p->lock);
8121 /* We can grab ast and p in that order, without worry. We should make sure
8122 nothing seriously bad has happened though like some sort of bizarre double
8123 masquerade! */
8124 DLA_LOCK(&p->lock);
8125 if (p->owner != ast) {
8126 ast_log(LOG_WARNING, "This isn't good...\n");
8127 return NULL;
8128 }
8129 }
8130 if (!p->subs[SUB_THREEWAY].owner) {
8131 ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
8132 return NULL;
8133 }
8134 mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
8135 ast_debug(1, "Last flash was %u ms ago\n", mssinceflash);
8136 if (mssinceflash < MIN_MS_SINCE_FLASH) {
8137 /* It hasn't been long enough since the last flashook. This is probably a bounce on
8138 hanging up. Hangup both channels now */
8139 if (p->subs[SUB_THREEWAY].owner)
8142 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
8144 } else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
8145 if (p->transfer) {
8146 /* In any case this isn't a threeway call anymore */
8147 p->subs[SUB_REAL].inthreeway = 0;
8149 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
8150 if (!p->transfertobusy && ast_channel_state(ast) == AST_STATE_BUSY) {
8152 /* Swap subs and dis-own channel */
8154 p->owner = NULL;
8155 /* Ring the phone */
8157 } else if (!attempt_transfer(p)) {
8158 /*
8159 * Transfer successful. Don't actually hang up at this point.
8160 * Let our channel legs of the calls die off as the transfer
8161 * percolates through the core.
8162 */
8163 break;
8164 }
8165 } else {
8167 if (p->subs[SUB_THREEWAY].owner)
8169 }
8170 } else {
8172 /* Swap subs and dis-own channel */
8174 p->owner = NULL;
8175 /* Ring the phone */
8177 }
8178 }
8179 } else {
8180 ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
8181 }
8182 /* Fall through */
8183 default:
8185 return NULL;
8186 }
8187 break;
8188 case DAHDI_EVENT_RINGOFFHOOK:
8189 if (p->inalarm) break;
8190 if (p->oprmode < 0)
8191 {
8192 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
8193 {
8194 /* Make sure it stops ringing */
8195 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8196 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
8198 ast_debug(1, "Operator recall by channel %d for channel %d complete\n", p->oprpeer->channel, p->channel);
8199 }
8200 break;
8201 }
8202 if (p->radio)
8203 {
8206 break;
8207 }
8208 /* for E911, its supposed to wait for offhook then dial
8209 the second half of the dial string */
8210 if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast_channel_state(ast) == AST_STATE_DIALING_OFFHOOK)) {
8211 c = strchr(p->dialdest, '/');
8212 if (c)
8213 c++;
8214 else
8215 c = p->dialdest;
8216
8217 if (*c) {
8218 int numchars = snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
8219 if (numchars >= sizeof(p->dop.dialstr)) {
8220 ast_log(LOG_WARNING, "Dial string '%s' truncated\n", c);
8221 }
8222 } else {
8223 ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
8224 }
8225
8226 if (strlen(p->dop.dialstr) > 4) {
8227 memset(p->echorest, 'w', sizeof(p->echorest) - 1);
8228 strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
8229 p->echorest[sizeof(p->echorest) - 1] = '\0';
8230 p->echobreak = 1;
8231 p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
8232 } else
8233 p->echobreak = 0;
8234 if (dahdi_dial_str(p, p->dop.op, p->dop.dialstr)) {
8235 x = DAHDI_ONHOOK;
8236 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
8237 return NULL;
8238 }
8239 p->dialing = 1;
8240 return &p->subs[idx].f;
8241 }
8242 switch (p->sig) {
8243 case SIG_FXOLS:
8244 case SIG_FXOGS:
8245 case SIG_FXOKS:
8246 switch (ast_channel_state(ast)) {
8247 case AST_STATE_RINGING:
8248 dahdi_ec_enable(p);
8249 dahdi_train_ec(p);
8252 /* Make sure it stops ringing */
8253 p->subs[SUB_REAL].needringing = 0;
8254 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8255 ast_debug(1, "channel %d answered\n", p->channel);
8256
8257 /* Cancel any running CallerID spill */
8258 ast_free(p->cidspill);
8259 p->cidspill = NULL;
8261
8262 p->dialing = 0;
8263 p->callwaitcas = 0;
8264 if (p->confirmanswer) {
8265 /* Ignore answer if "confirm answer" is enabled */
8266 p->subs[idx].f.frametype = AST_FRAME_NULL;
8267 p->subs[idx].f.subclass.integer = 0;
8268 } else if (!ast_strlen_zero(p->dop.dialstr)) {
8269 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
8270 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8271 if (res) {
8272 p->dop.dialstr[0] = '\0';
8273 return NULL;
8274 } else {
8275 ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
8276 p->subs[idx].f.frametype = AST_FRAME_NULL;
8277 p->subs[idx].f.subclass.integer = 0;
8278 p->dialing = 1;
8279 }
8280 p->dop.dialstr[0] = '\0';
8282 } else
8284 return &p->subs[idx].f;
8285 case AST_STATE_DOWN:
8287 ast_channel_rings_set(ast, 1);
8290 ast_debug(1, "channel %d picked up\n", p->channel);
8291 return &p->subs[idx].f;
8292 case AST_STATE_UP:
8293 /* Make sure it stops ringing */
8294 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8295 /* Okay -- probably call waiting*/
8297 p->subs[idx].needunhold = 1;
8298 break;
8299 case AST_STATE_RESERVED:
8300 /* Start up dialtone */
8301 if (has_voicemail(p))
8302 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
8303 else
8304 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
8305 break;
8306 default:
8307 ast_log(LOG_WARNING, "FXO phone off hook in weird state %u??\n", ast_channel_state(ast));
8308 }
8309 break;
8310 case SIG_FXSLS:
8311 case SIG_FXSGS:
8312 case SIG_FXSKS:
8313 if (ast_channel_state(ast) == AST_STATE_RING) {
8314 p->ringt = p->ringt_base;
8315 }
8316
8317 /* If we get a ring then we cannot be in
8318 * reversed polarity. So we reset to idle */
8319 ast_debug(1, "Setting IDLE polarity due "
8320 "to ring. Old polarity was %d\n",
8321 p->polarity);
8323
8324 /* Fall through */
8325 case SIG_EM:
8326 case SIG_EM_E1:
8327 case SIG_EMWINK:
8328 case SIG_FEATD:
8329 case SIG_FEATDMF:
8330 case SIG_FEATDMF_TA:
8331 case SIG_E911:
8332 case SIG_FGC_CAMA:
8333 case SIG_FGC_CAMAMF:
8334 case SIG_FEATB:
8335 case SIG_SF:
8336 case SIG_SFWINK:
8337 case SIG_SF_FEATD:
8338 case SIG_SF_FEATDMF:
8339 case SIG_SF_FEATB:
8343 ast_debug(1, "Ring detected\n");
8346 } else if (p->outgoing && ((ast_channel_state(ast) == AST_STATE_RINGING) || (ast_channel_state(ast) == AST_STATE_DIALING))) {
8347 ast_debug(1, "Line answered\n");
8348 if (p->confirmanswer) {
8349 p->subs[idx].f.frametype = AST_FRAME_NULL;
8350 p->subs[idx].f.subclass.integer = 0;
8351 } else {
8355 }
8356 } else if (ast_channel_state(ast) != AST_STATE_RING)
8357 ast_log(LOG_WARNING, "Ring/Off-hook in strange state %u on channel %d\n", ast_channel_state(ast), p->channel);
8358 break;
8359 default:
8360 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8361 }
8362 break;
8363 case DAHDI_EVENT_RINGBEGIN:
8364 switch (p->sig) {
8365 case SIG_FXSLS:
8366 case SIG_FXSGS:
8367 case SIG_FXSKS:
8368 if (ast_channel_state(ast) == AST_STATE_RING) {
8369 p->ringt = p->ringt_base;
8370 }
8371 break;
8372 }
8373 break;
8374 case DAHDI_EVENT_RINGERON:
8375 break;
8376 case DAHDI_EVENT_NOALARM:
8377 switch (p->sig) {
8378#if defined(HAVE_PRI)
8381 break;
8382#endif /* defined(HAVE_PRI) */
8383#if defined(HAVE_SS7)
8384 case SIG_SS7:
8386 break;
8387#endif /* defined(HAVE_SS7) */
8388 default:
8389 p->inalarm = 0;
8390 break;
8391 }
8393 break;
8394 case DAHDI_EVENT_WINKFLASH:
8395 if (p->inalarm) break;
8396 if (p->radio) break;
8397 if (p->oprmode < 0) break;
8398 if (p->oprmode > 1)
8399 {
8400 struct dahdi_params par;
8401
8402 memset(&par, 0, sizeof(par));
8403 if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
8404 {
8405 if (!par.rxisoffhook)
8406 {
8407 /* Make sure it stops ringing */
8408 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8409 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
8410 save_conference(p);
8411 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8412 ast_verb(4, "Operator flash recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8413 }
8414 }
8415 break;
8416 }
8417 /* Remember last time we got a flash-hook */
8418 p->flashtime = ast_tvnow();
8419 switch (mysig) {
8420 case SIG_FXOLS:
8421 case SIG_FXOGS:
8422 case SIG_FXOKS:
8423 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
8425
8426 /* Cancel any running CallerID spill */
8427 ast_free(p->cidspill);
8428 p->cidspill = NULL;
8430 p->callwaitcas = 0;
8431
8432 if (idx != SUB_REAL) {
8433 ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
8434 goto winkflashdone;
8435 }
8436
8437 if (p->subs[SUB_CALLWAIT].owner) {
8438 /* Swap to call-wait */
8440 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
8441 p->owner = p->subs[SUB_REAL].owner;
8442 ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));
8445 p->subs[SUB_REAL].needanswer = 1;
8446 }
8447 p->callwaitingrepeat = 0;
8448 p->cidcwexpire = 0;
8449 p->cid_suppress_expire = 0;
8450 /* Start music on hold if appropriate */
8451 if (!p->subs[SUB_CALLWAIT].inthreeway) {
8453 }
8454 p->subs[SUB_CALLWAIT].needhold = 1;
8456 p->subs[SUB_REAL].needunhold = 1;
8457 } else if (!p->subs[SUB_THREEWAY].owner) {
8458 if (!p->threewaycalling) {
8459 /* Just send a flash if no 3-way calling */
8460 p->subs[SUB_REAL].needflash = 1;
8461 goto winkflashdone;
8462 } else if (!check_for_conference(p)) {
8463 ast_callid callid = 0;
8464 int callid_created;
8465 char cid_num[256];
8466 char cid_name[256];
8467
8468 cid_num[0] = 0;
8469 cid_name[0] = 0;
8470 if (p->dahditrcallerid && p->owner) {
8474 sizeof(cid_num));
8475 }
8479 sizeof(cid_name));
8480 }
8481 }
8482 /* XXX This section needs much more error checking!!! XXX */
8483 /* Start a 3-way call if feasible */
8484 if (!((ast_channel_pbx(ast)) ||
8485 (ast_channel_state(ast) == AST_STATE_UP) ||
8486 (ast_channel_state(ast) == AST_STATE_RING))) {
8487 ast_debug(1, "Flash when call not up or ringing\n");
8488 goto winkflashdone;
8489 }
8490 if (alloc_sub(p, SUB_THREEWAY)) {
8491 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
8492 goto winkflashdone;
8493 }
8494 callid_created = ast_callid_threadstorage_auto(&callid);
8495 /*
8496 * Make new channel
8497 *
8498 * We cannot hold the p or ast locks while creating a new
8499 * channel.
8500 */
8502 ast_channel_unlock(ast);
8503 chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, NULL, callid);
8504 ast_channel_lock(ast);
8505 ast_mutex_lock(&p->lock);
8506 if (p->dahditrcallerid) {
8507 if (!p->origcid_num)
8509 if (!p->origcid_name)
8511 ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
8512 ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
8513 }
8514 /* Swap things around between the three-way and real call */
8516 /* Disable echo canceller for better dialing */
8518 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
8519 if (res)
8520 ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
8521 p->owner = chan;
8522 if (!chan) {
8523 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
8524 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
8525 ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
8526 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
8527 dahdi_ec_enable(p);
8528 ast_hangup(chan);
8529 } else {
8530 ast_verb(3, "Started three way call on channel %d\n", p->channel);
8531
8532 /* Start music on hold */
8534 p->subs[SUB_THREEWAY].needhold = 1;
8535 }
8536 ast_callid_threadstorage_auto_clean(callid, callid_created);
8537 }
8538 } else {
8539 /* Already have a 3 way call */
8540 if (p->subs[SUB_THREEWAY].inthreeway) {
8541 /* Call is already up, drop the last person */
8542 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
8543 /* If the primary call isn't answered yet, use it */
8545 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
8547 p->owner = p->subs[SUB_REAL].owner;
8548 }
8549 /* Drop the last call and stop the conference */
8550 ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8552 p->subs[SUB_REAL].inthreeway = 0;
8554 } else {
8555 /* Lets see what we're up to */
8556 if (((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) &&
8558 int otherindex = SUB_THREEWAY;
8559
8560 ast_verb(3, "Building conference call with %s and %s\n",
8563 /* Put them in the threeway, and flip */
8565 p->subs[SUB_REAL].inthreeway = 1;
8566 if (ast_channel_state(ast) == AST_STATE_UP) {
8568 otherindex = SUB_REAL;
8569 }
8570 if (p->subs[otherindex].owner) {
8571 ast_queue_unhold(p->subs[otherindex].owner);
8572 }
8573 p->subs[otherindex].needunhold = 1;
8574 p->owner = p->subs[SUB_REAL].owner;
8575 } else {
8576 ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8579 p->owner = p->subs[SUB_REAL].owner;
8580 if (p->subs[SUB_REAL].owner) {
8582 }
8583 p->subs[SUB_REAL].needunhold = 1;
8584 dahdi_ec_enable(p);
8585 }
8586 }
8587 }
8588winkflashdone:
8590 break;
8591 case SIG_EM:
8592 case SIG_EM_E1:
8593 case SIG_FEATD:
8594 case SIG_SF:
8595 case SIG_SFWINK:
8596 case SIG_SF_FEATD:
8597 case SIG_FXSLS:
8598 case SIG_FXSGS:
8599 if (p->dialing)
8600 ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
8601 else
8602 ast_debug(1, "Got wink in weird state %u on channel %d\n", ast_channel_state(ast), p->channel);
8603 break;
8604 case SIG_FEATDMF_TA:
8605 switch (p->whichwink) {
8606 case 0:
8607 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p->owner)->ani2,
8610 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#",
8614 break;
8615 case 1:
8616 ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
8617 break;
8618 case 2:
8619 ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
8620 return NULL;
8621 }
8622 p->whichwink++;
8623 /* Fall through */
8624 case SIG_FEATDMF:
8625 case SIG_E911:
8626 case SIG_FGC_CAMAMF:
8627 case SIG_FGC_CAMA:
8628 case SIG_FEATB:
8629 case SIG_SF_FEATDMF:
8630 case SIG_SF_FEATB:
8631 case SIG_EMWINK:
8632 /* FGD MF and EMWINK *Must* wait for wink */
8633 if (!ast_strlen_zero(p->dop.dialstr)) {
8634 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8635 if (res) {
8636 p->dop.dialstr[0] = '\0';
8637 return NULL;
8638 } else
8639 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8640 }
8641 p->dop.dialstr[0] = '\0';
8642 break;
8643 default:
8644 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8645 }
8646 break;
8647 case DAHDI_EVENT_HOOKCOMPLETE:
8648 if (p->inalarm) break;
8649 if ((p->radio || (p->oprmode < 0))) break;
8650 if (p->waitingfordt.tv_sec) break;
8651 switch (mysig) {
8652 case SIG_FXSLS: /* only interesting for FXS */
8653 case SIG_FXSGS:
8654 case SIG_FXSKS:
8655 case SIG_EM:
8656 case SIG_EM_E1:
8657 case SIG_EMWINK:
8658 case SIG_FEATD:
8659 case SIG_SF:
8660 case SIG_SFWINK:
8661 case SIG_SF_FEATD:
8662 if (!ast_strlen_zero(p->dop.dialstr)) {
8663 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8664 if (res) {
8665 p->dop.dialstr[0] = '\0';
8666 return NULL;
8667 } else
8668 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8669 }
8670 p->dop.dialstr[0] = '\0';
8671 p->dop.op = DAHDI_DIAL_OP_REPLACE;
8672 break;
8673 case SIG_FEATDMF:
8674 case SIG_FEATDMF_TA:
8675 case SIG_E911:
8676 case SIG_FGC_CAMA:
8677 case SIG_FGC_CAMAMF:
8678 case SIG_FEATB:
8679 case SIG_SF_FEATDMF:
8680 case SIG_SF_FEATB:
8681 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
8682 break;
8683 default:
8684 break;
8685 }
8686 break;
8687 case DAHDI_EVENT_POLARITY:
8688 /*
8689 * If we get a Polarity Switch event, check to see
8690 * if we should change the polarity state and
8691 * mark the channel as UP or if this is an indication
8692 * of remote end disconnect.
8693 */
8694 if (p->polarity == POLARITY_IDLE) {
8696 if (p->answeronpolarityswitch &&
8699 ast_debug(1, "Answering on polarity switch!\n");
8701 if (p->hanguponpolarityswitch) {
8703 }
8704 } else
8705 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8706 }
8707 /* Removed else statement from here as it was preventing hangups from ever happening*/
8708 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
8709 if (p->hanguponpolarityswitch &&
8710 (p->polarityonanswerdelay > 0) &&
8711 (p->polarity == POLARITY_REV) &&
8713 /* Added log_debug information below to provide a better indication of what is going on */
8714 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) );
8715
8717 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
8720 } else
8721 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));
8722
8723 } else {
8725 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8726 }
8727 /* Added more log_debug information below to provide a better indication of what is going on */
8728 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) );
8729 break;
8730 default:
8731 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
8732 }
8733 return &p->subs[idx].f;
8734}
8735
8736static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
8737{
8738 int res;
8739 int idx;
8740 struct ast_frame *f;
8741 int usedindex = -1;
8742 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8743
8744 if ((idx = dahdi_get_index(ast, p, 0)) < 0) {
8745 idx = SUB_REAL;
8746 }
8747
8748 p->subs[idx].f.frametype = AST_FRAME_NULL;
8749 p->subs[idx].f.datalen = 0;
8750 p->subs[idx].f.samples = 0;
8751 p->subs[idx].f.mallocd = 0;
8752 p->subs[idx].f.offset = 0;
8753 p->subs[idx].f.subclass.integer = 0;
8754 p->subs[idx].f.delivery = ast_tv(0,0);
8755 p->subs[idx].f.src = "dahdi_exception";
8756 p->subs[idx].f.data.ptr = NULL;
8757
8758
8759 if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
8760 /* If nobody owns us, absorb the event appropriately, otherwise
8761 we loop indefinitely. This occurs when, during call waiting, the
8762 other end hangs up our channel so that it no longer exists, but we
8763 have neither FLASH'd nor ONHOOK'd to signify our desire to
8764 change to the other channel. */
8765 if (p->fake_event) {
8766 res = p->fake_event;
8767 p->fake_event = 0;
8768 } else
8769 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
8770 /* Switch to real if there is one and this isn't something really silly... */
8771 if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
8772 (res != DAHDI_EVENT_HOOKCOMPLETE)) {
8773 ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
8774 p->owner = p->subs[SUB_REAL].owner;
8775 if (p->owner) {
8777 }
8778 p->subs[SUB_REAL].needunhold = 1;
8779 }
8780 switch (res) {
8781 case DAHDI_EVENT_ONHOOK:
8783 if (p->owner) {
8784 ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
8786 p->callwaitingrepeat = 0;
8787 p->cidcwexpire = 0;
8788 p->cid_suppress_expire = 0;
8789 } else
8790 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8792 break;
8793 case DAHDI_EVENT_RINGOFFHOOK:
8794 dahdi_ec_enable(p);
8795 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
8796 if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
8797 p->subs[SUB_REAL].needanswer = 1;
8798 p->dialing = 0;
8799 }
8800 break;
8801 case DAHDI_EVENT_HOOKCOMPLETE:
8802 case DAHDI_EVENT_RINGERON:
8803 case DAHDI_EVENT_RINGEROFF:
8804 /* Do nothing */
8805 break;
8806 case DAHDI_EVENT_WINKFLASH:
8807 p->flashtime = ast_tvnow();
8808 if (p->owner) {
8809 ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, ast_channel_name(p->owner));
8811 /* Answer if necessary */
8812 usedindex = dahdi_get_index(p->owner, p, 0);
8813 if (usedindex > -1) {
8814 p->subs[usedindex].needanswer = 1;
8815 }
8817 }
8818 p->callwaitingrepeat = 0;
8819 p->cidcwexpire = 0;
8820 p->cid_suppress_expire = 0;
8822 p->subs[SUB_REAL].needunhold = 1;
8823 } else
8824 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8826 break;
8827 default:
8828 ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
8829 }
8830 f = &p->subs[idx].f;
8831 return f;
8832 }
8833 if (!(p->radio || (p->oprmode < 0)))
8834 ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast, 0), p->channel);
8835 /* If it's not us, return NULL immediately */
8836 if (ast != p->owner) {
8837 if (p->owner) {
8838 ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
8839 }
8840 f = &p->subs[idx].f;
8841 return f;
8842 }
8843
8844 f = dahdi_handle_event(ast);
8845 if (!f) {
8846 const char *name = ast_strdupa(ast_channel_name(ast));
8847
8848 /* Tell the CDR this DAHDI device hung up */
8850 ast_channel_unlock(ast);
8851 ast_set_hangupsource(ast, name, 0);
8852 ast_channel_lock(ast);
8853 ast_mutex_lock(&p->lock);
8854 }
8855 return f;
8856}
8857
8858static struct ast_frame *dahdi_exception(struct ast_channel *ast)
8859{
8860 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8861 struct ast_frame *f;
8862 ast_mutex_lock(&p->lock);
8863 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
8864 struct analog_pvt *analog_p = p->sig_pvt;
8865 f = analog_exception(analog_p, ast);
8866 } else {
8867 f = __dahdi_exception(ast);
8868 }
8870 return f;
8871}
8872
8873static struct ast_frame *dahdi_read(struct ast_channel *ast)
8874{
8875 struct dahdi_pvt *p;
8876 int res;
8877 int idx;
8878 void *readbuf;
8879 struct ast_frame *f;
8880
8881 /*
8882 * For analog channels, we must do deadlock avoidance because
8883 * analog ports can have more than one Asterisk channel using
8884 * the same private structure.
8885 */
8886 p = ast_channel_tech_pvt(ast);
8887 while (ast_mutex_trylock(&p->lock)) {
8889
8890 /*
8891 * Check to see if the channel is still associated with the same
8892 * private structure. While the Asterisk channel was unlocked
8893 * the following events may have occurred:
8894 *
8895 * 1) A masquerade may have associated the channel with another
8896 * technology or private structure.
8897 *
8898 * 2) For PRI calls, call signaling could change the channel
8899 * association to another B channel (private structure).
8900 */
8901 if (ast_channel_tech_pvt(ast) != p) {
8902 /* The channel is no longer associated. Quit gracefully. */
8903 return &ast_null_frame;
8904 }
8905 }
8906
8907 idx = dahdi_get_index(ast, p, 0);
8908
8909 /* Hang up if we don't really exist */
8910 if (idx < 0) {
8911 ast_log(LOG_WARNING, "We don't exist?\n");
8913 return NULL;
8914 }
8915
8916 if ((p->radio || (p->oprmode < 0)) && p->inalarm) {
8918 return NULL;
8919 }
8920
8921 p->subs[idx].f.frametype = AST_FRAME_NULL;
8922 p->subs[idx].f.datalen = 0;
8923 p->subs[idx].f.samples = 0;
8924 p->subs[idx].f.mallocd = 0;
8925 p->subs[idx].f.offset = 0;
8926 p->subs[idx].f.subclass.integer = 0;
8927 p->subs[idx].f.delivery = ast_tv(0,0);
8928 p->subs[idx].f.src = "dahdi_read";
8929 p->subs[idx].f.data.ptr = NULL;
8930
8931 /* make sure it sends initial key state as first frame */
8932 if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
8933 {
8934 struct dahdi_params ps;
8935
8936 memset(&ps, 0, sizeof(ps));
8937 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
8939 return NULL;
8940 }
8941 p->firstradio = 1;
8943 if (ps.rxisoffhook)
8944 {
8946 }
8947 else
8948 {
8950 }
8952 return &p->subs[idx].f;
8953 }
8954 if (p->ringt > 0) {
8955 if (!(--p->ringt)) {
8957 return NULL;
8958 }
8959 }
8960
8961#ifdef HAVE_OPENR2
8962 if (p->mfcr2) {
8963 openr2_chan_process_event(p->r2chan);
8964 if (OR2_DIR_FORWARD == openr2_chan_get_direction(p->r2chan)) {
8966 /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
8967 * now enqueue a progress frame to bridge the media up */
8968 if (p->mfcr2_call_accepted &&
8969 !p->mfcr2_progress_sent &&
8971 ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
8972 ast_queue_frame(p->owner, &fr);
8973 p->mfcr2_progress_sent = 1;
8974 }
8975 }
8976 }
8977#endif
8978
8979 if (p->subs[idx].needringing) {
8980 /* Send ringing frame if requested */
8981 p->subs[idx].needringing = 0;
8986 return &p->subs[idx].f;
8987 }
8988
8989 if (p->subs[idx].needbusy) {
8990 /* Send busy frame if requested */
8991 p->subs[idx].needbusy = 0;
8995 return &p->subs[idx].f;
8996 }
8997
8998 if (p->subs[idx].needcongestion) {
8999 /* Send congestion frame if requested */
9000 p->subs[idx].needcongestion = 0;
9004 return &p->subs[idx].f;
9005 }
9006
9007 if (p->subs[idx].needanswer) {
9008 /* Send answer frame if requested */
9009 p->subs[idx].needanswer = 0;
9013 return &p->subs[idx].f;
9014 }
9015#ifdef HAVE_OPENR2
9016 if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
9017 /* openr2 took care of reading and handling any event
9018 (needanswer, needbusy etc), if we continue we will read()
9019 twice, lets just return a null frame. This should only
9020 happen when openr2 is dialing out */
9022 return &ast_null_frame;
9023 }
9024#endif
9025
9026 if (p->subs[idx].needflash) {
9027 /* Send answer frame if requested */
9028 p->subs[idx].needflash = 0;
9032 return &p->subs[idx].f;
9033 }
9034
9035 if (p->subs[idx].needhold) {
9036 /* Send answer frame if requested */
9037 p->subs[idx].needhold = 0;
9041 ast_debug(1, "Sending hold on '%s'\n", ast_channel_name(ast));
9042 return &p->subs[idx].f;
9043 }
9044
9045 if (p->subs[idx].needunhold) {
9046 /* Send answer frame if requested */
9047 p->subs[idx].needunhold = 0;
9051 ast_debug(1, "Sending unhold on '%s'\n", ast_channel_name(ast));
9052 return &p->subs[idx].f;
9053 }
9054
9055 /*
9056 * If we have a fake_event, fake an exception to handle it only
9057 * if this channel owns the private.
9058 */
9059 if (p->fake_event && p->owner == ast) {
9060 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9061 struct analog_pvt *analog_p = p->sig_pvt;
9062
9063 f = analog_exception(analog_p, ast);
9064 } else {
9065 f = __dahdi_exception(ast);
9066 }
9068 return f;
9069 }
9070
9072 if (!p->subs[idx].linear) {
9073 p->subs[idx].linear = 1;
9074 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9075 if (res)
9076 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
9077 }
9078 } else {
9079 if (p->subs[idx].linear) {
9080 p->subs[idx].linear = 0;
9081 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9082 if (res)
9083 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
9084 }
9085 }
9086 readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
9087 CHECK_BLOCKING(ast);
9088 res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9090 /* Check for hangup */
9091 if (res < 0) {
9092 f = NULL;
9093 if (res == -1) {
9094 if (errno == EAGAIN) {
9095 /* Return "NULL" frame if there is nobody there */
9097 return &p->subs[idx].f;
9098 } else if (errno == ELAST) {
9099 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9100 struct analog_pvt *analog_p = p->sig_pvt;
9101 f = analog_exception(analog_p, ast);
9102 } else {
9103 f = __dahdi_exception(ast);
9104 }
9105 } else
9106 ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
9107 }
9109 return f;
9110 }
9111 if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
9112 ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9113 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9114 struct analog_pvt *analog_p = p->sig_pvt;
9115 f = analog_exception(analog_p, ast);
9116 } else {
9117 f = __dahdi_exception(ast);
9118 }
9120 return f;
9121 }
9122 if (p->tdd) { /* if in TDD mode, see if we receive that */
9123 int c;
9124
9125 c = tdd_feed(p->tdd,readbuf,READ_SIZE);
9126 if (c < 0) {
9127 ast_debug(1,"tdd_feed failed\n");
9129 return NULL;
9130 }
9131 if (c) { /* if a char to return */
9132 p->subs[idx].f.subclass.integer = 0;
9133 p->subs[idx].f.frametype = AST_FRAME_TEXT;
9134 p->subs[idx].f.mallocd = 0;
9135 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9136 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
9137 p->subs[idx].f.datalen = 1;
9138 *((char *) p->subs[idx].f.data.ptr) = c;
9140 return &p->subs[idx].f;
9141 }
9142 }
9143 if (idx == SUB_REAL) {
9144 /* Ensure the CW timers decrement only on a single subchannel */
9145 if (p->cidcwexpire) {
9146 if (!--p->cidcwexpire) {
9147 /* Expired CID/CW */
9148 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
9150 }
9151 }
9152 if (p->cid_suppress_expire) {
9154 }
9155 if (p->callwaitingrepeat) {
9156 if (!--p->callwaitingrepeat) {
9157 /* Expired, Repeat callwaiting tone */
9158 ++p->callwaitrings;
9159 dahdi_callwait(ast);
9160 }
9161 }
9162 }
9163 if (p->subs[idx].linear) {
9164 p->subs[idx].f.datalen = READ_SIZE * 2;
9165 } else
9166 p->subs[idx].f.datalen = READ_SIZE;
9167
9168 /* Handle CallerID Transmission */
9169 if ((p->owner == ast) && p->cidspill) {
9170 send_callerid(p);
9171 }
9172
9173 p->subs[idx].f.frametype = AST_FRAME_VOICE;
9175 p->subs[idx].f.samples = READ_SIZE;
9176 p->subs[idx].f.mallocd = 0;
9177 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9178 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
9179#if 0
9180 ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
9181#endif
9182 if ((p->dialing && !p->waitingfordt.tv_sec) || p->radio || /* Transmitting something */
9183 (idx && (ast_channel_state(ast) != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
9184 ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
9185 ) {
9186 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
9187 don't send anything */
9188 p->subs[idx].f.frametype = AST_FRAME_NULL;
9189 p->subs[idx].f.subclass.integer = 0;
9190 p->subs[idx].f.samples = 0;
9191 p->subs[idx].f.mallocd = 0;
9192 p->subs[idx].f.offset = 0;
9193 p->subs[idx].f.data.ptr = NULL;
9194 p->subs[idx].f.datalen= 0;
9195 }
9196 if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec || p->dialtone_detect) && !idx) {
9197 /* Perform busy detection etc on the dahdi line */
9198 int mute;
9199
9201 && p->faxdetect_timeout
9203 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
9205 ast_debug(1, "Channel driver fax CNG detection timeout on %s\n",
9206 ast_channel_name(ast));
9207 }
9208
9209 f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
9210
9211 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
9212 mute = ast_dsp_was_muted(p->dsp);
9213 if (p->muting != mute) {
9214 p->muting = mute;
9215 dahdi_confmute(p, mute);
9216 }
9217
9218 if (f) {
9220 && !p->outgoing && ast_channel_state(ast) == AST_STATE_UP) {
9222 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9224 }
9225 }
9227 if ((ast_channel_state(ast) == AST_STATE_UP) && !p->outgoing) {
9228 /*
9229 * Treat this as a "hangup" instead of a "busy" on the
9230 * assumption that a busy means the incoming call went away.
9231 */
9232 ast_frfree(f);
9233 f = NULL;
9234 }
9235 } else if (p->dialtone_detect && !p->outgoing && f->frametype == AST_FRAME_VOICE) {
9237 /* Dialtone detected on inbound call; hangup the channel */
9238 ast_frfree(f);
9239 f = NULL;
9240 }
9241 } else if (f->frametype == AST_FRAME_DTMF_BEGIN
9242 || f->frametype == AST_FRAME_DTMF_END) {
9243#ifdef HAVE_PRI
9245 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
9246 && p->pri
9247 && ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING))
9248 || (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
9249 /* Don't accept in-band DTMF when in overlap dial mode */
9250 ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n",
9251 f->frametype == AST_FRAME_DTMF_BEGIN ? "begin" : "end",
9252 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
9253
9255 f->subclass.integer = 0;
9256 }
9257#endif
9258 /* DSP clears us of being pulse */
9259 p->pulsedial = 0;
9260 } else if (p->waitingfordt.tv_sec) {
9262 p->waitingfordt.tv_sec = 0;
9263 ast_log(LOG_NOTICE, "Never saw dialtone on channel %d\n", p->channel);
9264 ast_frfree(f);
9265 f = NULL;
9266 } else if (f->frametype == AST_FRAME_VOICE) {
9268 f->subclass.integer = 0;
9270 p->waitingfordt.tv_sec = 0;
9271 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9273 ast_debug(1, "Got 10 samples of dialtone!\n");
9274 if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */
9275 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
9276 if (res) {
9277 p->dop.dialstr[0] = '\0';
9279 ast_frfree(f);
9280 return NULL;
9281 } else {
9282 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
9283 p->dialing = 1;
9284 p->dop.dialstr[0] = '\0';
9285 p->dop.op = DAHDI_DIAL_OP_REPLACE;
9287 }
9288 }
9289 }
9290 }
9291 }
9292 }
9293 } else
9294 f = &p->subs[idx].f;
9295
9296 if (f) {
9297 struct analog_pvt *analog_p = p->sig_pvt;
9298 switch (f->frametype) {
9300 case AST_FRAME_DTMF_END:
9301 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9302 analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
9303 } else {
9304 dahdi_handle_dtmf(ast, idx, &f);
9305 }
9306 if (!(analog_p->dialmode == ANALOG_DIALMODE_BOTH || analog_p->dialmode == ANALOG_DIALMODE_DTMF)) {
9307 if (f->frametype == AST_FRAME_DTMF_END) { /* only show this message when the key is let go of */
9308 ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f->subclass.integer);
9309 }
9311 f->subclass.integer = 0;
9312 }
9313 break;
9314 case AST_FRAME_VOICE:
9315 if (p->cidspill || p->cid_suppress_expire) {
9316 /* We are/were sending a caller id spill. Suppress any echo. */
9317 p->subs[idx].f.frametype = AST_FRAME_NULL;
9318 p->subs[idx].f.subclass.integer = 0;
9319 p->subs[idx].f.samples = 0;
9320 p->subs[idx].f.mallocd = 0;
9321 p->subs[idx].f.offset = 0;
9322 p->subs[idx].f.data.ptr = NULL;
9323 p->subs[idx].f.datalen= 0;
9324 }
9325 break;
9326 default:
9327 break;
9328 }
9329 }
9330
9332 return f;
9333}
9334
9335static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
9336{
9337 int sent=0;
9338 int size;
9339 int res;
9340 int fd;
9341 fd = p->subs[idx].dfd;
9342 while (len) {
9343 size = len;
9344 if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
9345 size = (linear ? READ_SIZE * 2 : READ_SIZE);
9346 res = write(fd, buf, size);
9347 if (res != size) {
9348 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
9349 return sent;
9350 }
9351 len -= size;
9352 buf += size;
9353 }
9354 return sent;
9355}
9356
9357static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
9358{
9359 struct dahdi_pvt *p;
9360 int res;
9361 int idx;
9362
9363 /* Write a frame of (presumably voice) data */
9364 if (frame->frametype != AST_FRAME_VOICE) {
9365 if (frame->frametype != AST_FRAME_IMAGE) {
9366 ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n",
9367 frame->frametype);
9368 }
9369 return 0;
9370 }
9371
9372 /* Return if it's not valid data */
9373 if (!frame->data.ptr || !frame->datalen) {
9374 return 0;
9375 }
9376
9377 p = ast_channel_tech_pvt(ast);
9378 ast_mutex_lock(&p->lock);
9379
9380 idx = dahdi_get_index(ast, p, 0);
9381 if (idx < 0) {
9383 ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast_channel_name(ast));
9384 return -1;
9385 }
9386
9387 if (p->sig == SIG_FXOLS || p->sig == SIG_FXOKS || p->sig == SIG_FXOGS) {
9388 struct analog_pvt *analog_p = p->sig_pvt;
9389 if (analog_p->callwaitingdeluxepending) {
9390 unsigned int mssinceflash = ast_tvdiff_ms(ast_tvnow(), analog_p->flashtime);
9391 if (mssinceflash >= 1000) {
9392 /* Timer expired: the user hasn't yet selected an option. Take the default action and get on with it. */
9393 /* Note: If in the future Advanced Call Waiting Deluxe (*76) is supported, then as part of the
9394 * dialing code, we'll need to automatically invoke the preselected behavior about 2-3 seconds after
9395 * the call waiting begins (this allows for the SAS, CAS, and CWCID spill to be sent first).
9396 */
9397 analog_p->callwaitingdeluxepending = 0;
9398 analog_callwaiting_deluxe(analog_p, 0);
9399 }
9401 /* The user shouldn't hear anything after hook flashing, until a decision is made, by the user or when the timer expires. */
9402 ast_debug(5, "Dropping frame since Call Waiting Deluxe pending on %s\n", ast_channel_name(ast));
9403 return 0;
9404 }
9405 }
9406
9407 if (p->dialing) {
9409 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9410 ast_channel_name(ast));
9411 return 0;
9412 }
9413 if (!p->owner) {
9415 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9416 ast_channel_name(ast));
9417 return 0;
9418 }
9419 if (p->cidspill) {
9421 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9422 ast_channel_name(ast));
9423 return 0;
9424 }
9425
9427 if (!p->subs[idx].linear) {
9428 p->subs[idx].linear = 1;
9429 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9430 if (res)
9431 ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
9432 }
9433 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
9436 /* x-law already */
9437 if (p->subs[idx].linear) {
9438 p->subs[idx].linear = 0;
9439 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9440 if (res)
9441 ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
9442 }
9443 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
9444 } else {
9446 ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
9448 return -1;
9449 }
9451 if (res < 0) {
9452 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
9453 return -1;
9454 }
9455 return 0;
9456}
9457
9458static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
9459{
9460 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9461 int res=-1;
9462 int idx;
9463 int func = DAHDI_FLASH;
9464
9465 ast_mutex_lock(&p->lock);
9466 ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
9467 switch (p->sig) {
9468#if defined(HAVE_PRI)
9470 res = sig_pri_indicate(p->sig_pvt, chan, condition, data, datalen);
9472 return res;
9473#endif /* defined(HAVE_PRI) */
9474#if defined(HAVE_SS7)
9475 case SIG_SS7:
9476 res = sig_ss7_indicate(p->sig_pvt, chan, condition, data, datalen);
9478 return res;
9479#endif /* defined(HAVE_SS7) */
9480 default:
9481 break;
9482 }
9483#ifdef HAVE_OPENR2
9484 if (p->mfcr2 && !p->mfcr2_call_accepted) {
9486 /* if this is an R2 call and the call is not yet accepted, we don't want the
9487 tone indications to mess up with the MF tones */
9488 return 0;
9489 }
9490#endif
9491 idx = dahdi_get_index(chan, p, 0);
9492 if (idx == SUB_REAL) {
9493 switch (condition) {
9494 case AST_CONTROL_BUSY:
9495 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
9496 break;
9498 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
9499
9500 if (ast_channel_state(chan) != AST_STATE_UP) {
9501 if ((ast_channel_state(chan) != AST_STATE_RING) ||
9502 ((p->sig != SIG_FXSKS) &&
9503 (p->sig != SIG_FXSLS) &&
9504 (p->sig != SIG_FXSGS))) {
9505 /* We're playing audible ringback tone on the channel,
9506 * so set state to AST_STATE_RING, not AST_STATE_RINGING. */
9508 }
9509 }
9510 break;
9512 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan));
9513 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9514 res = 0;
9515 break;
9517 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan));
9518 /* don't continue in ast_indicate */
9519 res = 0;
9520 break;
9522 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan));
9523 /* don't continue in ast_indicate */
9524 res = 0;
9525 break;
9527 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9528 switch (ast_channel_hangupcause(chan)) {
9531 case 0:/* Cause has not been set. */
9532 /* Supply a more appropriate cause. */
9534 break;
9535 default:
9536 break;
9537 }
9538 break;
9539 case AST_CONTROL_HOLD:
9540 ast_moh_start(chan, data, p->mohinterpret);
9541 break;
9542 case AST_CONTROL_UNHOLD:
9543 ast_moh_stop(chan);
9544 break;
9546 if (p->radio)
9547 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
9548 res = 0;
9549 break;
9551 if (p->radio)
9552 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
9553 res = 0;
9554 break;
9555 case AST_CONTROL_FLASH:
9556 /* flash hookswitch */
9557 if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
9558 /* Clear out the dial buffer */
9559 p->dop.dialstr[0] = '\0';
9560 if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
9561 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
9562 ast_channel_name(chan), strerror(errno));
9563 } else
9564 res = 0;
9565 } else
9566 res = 0;
9567 break;
9569 res = 0;
9570 break;
9571 case -1:
9572 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
9573 break;
9574 }
9575 } else {
9576 res = 0;
9577 }
9579 return res;
9580}
9581
9582#if defined(HAVE_PRI)
9583static struct ast_str *create_channel_name(struct dahdi_pvt *i, int is_outgoing, char *address)
9584#else
9585static struct ast_str *create_channel_name(struct dahdi_pvt *i)
9586#endif /* defined(HAVE_PRI) */
9587{
9588 struct ast_str *chan_name;
9589 int x, y;
9590
9591 /* Create the new channel name tail. */
9592 if (!(chan_name = ast_str_create(32))) {
9593 return NULL;
9594 }
9595 if (i->channel == CHAN_PSEUDO) {
9596 ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
9597#if defined(HAVE_PRI)
9598 } else if (i->pri) {
9599 ast_mutex_lock(&i->pri->lock);
9600 y = ++i->pri->new_chan_seq;
9601 if (is_outgoing) {
9602 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, address, (unsigned)y);
9603 address[0] = '\0';
9604 } else if (ast_strlen_zero(i->cid_subaddr)) {
9605 /* Put in caller-id number only since there is no subaddress. */
9606 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, i->cid_num, (unsigned)y);
9607 } else {
9608 /* Put in caller-id number and subaddress. */
9609 ast_str_set(&chan_name, 0, "i%d/%s:%s-%x", i->pri->span, i->cid_num,
9610 i->cid_subaddr, (unsigned)y);
9611 }
9612 ast_mutex_unlock(&i->pri->lock);
9613#endif /* defined(HAVE_PRI) */
9614 } else {
9615 y = 1;
9616 do {
9617 ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
9618 for (x = 0; x < 3; ++x) {
9619 if (i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name),
9620 ast_channel_name(i->subs[x].owner) + 6)) {
9621 break;
9622 }
9623 }
9624 ++y;
9625 } while (x < 3);
9626 }
9627 return chan_name;
9628}
9629
9630static 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)
9631{
9632 struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, assignedids, requestor, callid);
9633
9635
9636 return new_channel;
9637}
9638
9639static 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)
9640{
9641 struct ast_channel *tmp;
9642 struct ast_format_cap *caps;
9643 struct ast_format *deflaw;
9644 int x;
9645 int features;
9646 struct ast_str *chan_name;
9647 struct ast_variable *v;
9648 char *dashptr;
9649 char device_name[AST_CHANNEL_NAME];
9650
9651 if (i->subs[idx].owner) {
9652 ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
9653 return NULL;
9654 }
9655
9656#if defined(HAVE_PRI)
9657 /*
9658 * The dnid has been stuffed with the called-number[:subaddress]
9659 * by dahdi_request() for outgoing calls.
9660 */
9661 chan_name = create_channel_name(i, i->outgoing, i->dnid);
9662#else
9663 chan_name = create_channel_name(i);
9664#endif /* defined(HAVE_PRI) */
9665 if (!chan_name) {
9666 return NULL;
9667 }
9668
9670 if (!caps) {
9671 ast_free(chan_name);
9672 return NULL;
9673 }
9674
9675 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));
9676 ast_free(chan_name);
9677 if (!tmp) {
9678 ao2_ref(caps, -1);
9679 return NULL;
9680 }
9681
9683
9684 if (callid) {
9685 ast_channel_callid_set(tmp, callid);
9686 }
9687
9689#if defined(HAVE_PRI)
9690 if (i->pri) {
9692 }
9693#endif /* defined(HAVE_PRI) */
9695 if (law) {
9696 i->law = law;
9697 if (law == DAHDI_LAW_ALAW) {
9698 deflaw = ast_format_alaw;
9699 } else {
9700 deflaw = ast_format_ulaw;
9701 }
9702 } else {
9703 switch (i->sig) {
9705 /* Make sure companding law is known. */
9706 i->law = (i->law_default == DAHDI_LAW_ALAW)
9707 ? DAHDI_LAW_ALAW : DAHDI_LAW_MULAW;
9708 break;
9709 default:
9710 i->law = i->law_default;
9711 break;
9712 }
9713 if (i->law_default == DAHDI_LAW_ALAW) {
9714 deflaw = ast_format_alaw;
9715 } else {
9716 deflaw = ast_format_ulaw;
9717 }
9718 }
9719 ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
9720 ast_format_cap_append(caps, deflaw, 0);
9722 ao2_ref(caps, -1);
9723 /* Start out assuming ulaw since it's smaller :) */
9724 ast_channel_set_rawreadformat(tmp, deflaw);
9725 ast_channel_set_readformat(tmp, deflaw);
9726 ast_channel_set_rawwriteformat(tmp, deflaw);
9727 ast_channel_set_writeformat(tmp, deflaw);
9728 i->subs[idx].linear = 0;
9729 dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
9730 features = 0;
9731 if (idx == SUB_REAL) {
9732 if (i->busydetect && CANBUSYDETECT(i))
9733 features |= DSP_FEATURE_BUSY_DETECT;
9735 features |= DSP_FEATURE_CALL_PROGRESS;
9737 features |= DSP_FEATURE_WAITDIALTONE;
9738 if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
9740 features |= DSP_FEATURE_FAX_DETECT;
9741 }
9742 x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
9743 if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
9744 i->hardwaredtmf = 0;
9745 features |= DSP_FEATURE_DIGIT_DETECT;
9746 } else if (NEED_MFDETECT(i)) {
9747 i->hardwaredtmf = 1;
9748 features |= DSP_FEATURE_DIGIT_DETECT;
9749 }
9750 }
9751 if (features) {
9752 if (i->dsp) {
9753 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp));
9754 } else {
9755 if (i->channel != CHAN_PSEUDO)
9756 i->dsp = ast_dsp_new();
9757 else
9758 i->dsp = NULL;
9759 if (i->dsp) {
9760 i->dsp_features = features;
9761#if defined(HAVE_PRI) || defined(HAVE_SS7)
9762 /* We cannot do progress detection until receive PROGRESS message */
9763 if (i->outgoing && (dahdi_sig_pri_lib_handles(i->sig) || (i->sig == SIG_SS7))) {
9764 /* Remember requested DSP features, don't treat
9765 talking as ANSWER */
9766 i->dsp_features = features & ~DSP_PROGRESS_TALK;
9767 features = 0;
9768 }
9769#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9770 ast_dsp_set_features(i->dsp, features);
9774 if (i->busydetect && CANBUSYDETECT(i)) {
9777 }
9778 }
9779 }
9780 }
9781
9783
9784 if (state == AST_STATE_RING)
9785 ast_channel_rings_set(tmp, 1);
9787 if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
9788 /* Only FXO signalled stuff can be picked up */
9793 }
9794 if (!ast_strlen_zero(i->parkinglot))
9795 ast_channel_parkinglot_set(tmp, i->parkinglot);
9796 if (!ast_strlen_zero(i->language))
9797 ast_channel_language_set(tmp, i->language);
9798 if (!i->owner)
9799 i->owner = tmp;
9801 ast_channel_accountcode_set(tmp, i->accountcode);
9802 if (i->amaflags)
9804 i->subs[idx].owner = tmp;
9806 if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
9807 ast_channel_call_forward_set(tmp, i->call_forward);
9808 }
9809 /* If we've been told "no ADSI" then enforce it */
9810 if (!i->adsi)
9812 if (!ast_strlen_zero(i->exten))
9814 if (!ast_strlen_zero(i->rdnis)) {
9817 }
9818 if (!ast_strlen_zero(i->dnid)) {
9820 }
9821
9822 /* Don't use ast_set_callerid() here because it will
9823 * generate a needless NewCallerID event */
9824#if defined(HAVE_PRI) || defined(HAVE_SS7)
9825 if (!ast_strlen_zero(i->cid_ani)) {
9827 ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_ani);
9828 } else if (!ast_strlen_zero(i->cid_num)) {
9831 }
9832#else
9833 if (!ast_strlen_zero(i->cid_num)) {
9836 }
9837#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9841 ast_channel_caller(tmp)->ani2 = i->cid_ani2;
9843 /* clear the fake event in case we posted one before we had ast_channel */
9844 i->fake_event = 0;
9845 /* Assure there is no confmute on this channel */
9846 dahdi_confmute(i, 0);
9847 i->muting = 0;
9848 /* Configure the new channel jb */
9850
9851 /* Set initial device state */
9852 ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name));
9853 dashptr = strrchr(device_name, '-');
9854 if (dashptr) {
9855 *dashptr = '\0';
9856 }
9859
9860 for (v = i->vars ; v ; v = v->next)
9862
9864
9865 ast_channel_unlock(tmp);
9866
9868
9870 if (startpbx) {
9871#ifdef HAVE_OPENR2
9872 if (i->mfcr2call) {
9873 pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
9874 }
9875#endif
9876 if (ast_pbx_start(tmp)) {
9877 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
9878 ast_hangup(tmp);
9879 return NULL;
9880 }
9881 }
9882 return tmp;
9883}
9884
9885
9886static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
9887{
9888 char c;
9889
9890 *str = 0; /* start with empty output buffer */
9891 for (;;)
9892 {
9893 /* Wait for the first digit (up to specified ms). */
9894 c = ast_waitfordigit(chan, ms);
9895 /* if timeout, hangup or error, return as such */
9896 if (c < 1)
9897 return c;
9898 *str++ = c;
9899 *str = 0;
9900 if (strchr(term, c))
9901 return 1;
9902 }
9903}
9904
9905static int dahdi_wink(struct dahdi_pvt *p, int idx)
9906{
9907 int j;
9908 dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
9909 for (;;)
9910 {
9911 /* set bits of interest */
9912 j = DAHDI_IOMUX_SIGEVENT;
9913 /* wait for some happening */
9914 if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
9915 /* exit loop if we have it */
9916 if (j & DAHDI_IOMUX_SIGEVENT) break;
9917 }
9918 /* get the event info */
9919 if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
9920 return 0;
9921}
9922
9923static void publish_dnd_state(int channel, const char *status)
9924{
9925 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
9926 RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
9927 if (!dahdichan) {
9928 return;
9929 }
9930
9931 ast_str_set(&dahdichan, 0, "%d", channel);
9932
9933 body = ast_json_pack("{s: s, s: s}",
9934 "DAHDIChannel", ast_str_buffer(dahdichan),
9935 "Status", status);
9936 if (!body) {
9937 return;
9938 }
9939
9941}
9942
9943/*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9944 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9945 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9946 *
9947 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9948 * DAHDI channel). Use this to enable or disable it.
9949 *
9950 * \bug the use of the word "channel" for those dahdichans is really confusing.
9951 */
9952static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
9953{
9954 if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
9955 return analog_dnd(dahdichan->sig_pvt, flag);
9956 }
9957
9958 if (flag == -1) {
9959 return dahdichan->dnd;
9960 }
9961
9962 /* Do not disturb */
9963 dahdichan->dnd = flag;
9964 ast_verb(3, "%s DND on channel %d\n",
9965 flag? "Enabled" : "Disabled",
9966 dahdichan->channel);
9967 publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
9968 return 0;
9969}
9970
9971static int canmatch_featurecode(const char *pickupexten, const char *exten)
9972{
9973 int extlen = strlen(exten);
9974
9975 if (!extlen) {
9976 return 1;
9977 }
9978
9979 if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
9980 return 1;
9981 }
9982 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9983 if (exten[0] == '*' && extlen < 3) {
9984 if (extlen == 1) {
9985 return 1;
9986 }
9987 /* "*0" should be processed before it gets here */
9988 switch (exten[1]) {
9989 case '6':
9990 case '7':
9991 case '8':
9992 return 1;
9993 }
9994 }
9995 return 0;
9996}
9997
9998static void *analog_ss_thread(void *data)
9999{
10000 struct ast_channel *chan = data;
10001 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
10002 char exten[AST_MAX_EXTENSION] = "";
10003 char exten2[AST_MAX_EXTENSION] = "";
10004 unsigned char buf[256];
10005 char dtmfcid[300];
10006 char dtmfbuf[300];
10007 struct callerid_state *cs = NULL;
10008 char *name = NULL, *number = NULL;
10009 int distMatches;
10010 int curRingData[3];
10011 int receivedRingT;
10012 int counter1;
10013 int counter;
10014 int samples = 0;
10015 struct ast_smdi_md_message *smdi_msg = NULL;
10016 int flags = 0;
10017 int i;
10018 int timeout;
10019 int getforward = 0;
10020 char *s1, *s2;
10021 int len = 0;
10022 int res;
10023 int idx;
10024 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
10025 const char *pickupexten;
10026
10030 /* in the bizarre case where the channel has become a zombie before we
10031 even get started here, abort safely
10032 */
10033 if (!p) {
10034 ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
10035 ast_hangup(chan);
10036 goto quit;
10037 }
10038 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
10039 idx = dahdi_get_index(chan, p, 1);
10040 if (idx < 0) {
10041 ast_log(LOG_WARNING, "Huh?\n");
10042 ast_hangup(chan);
10043 goto quit;
10044 }
10045
10046 ast_channel_lock(chan);
10047 pickup_cfg = ast_get_chan_features_pickup_config(chan);
10048 if (!pickup_cfg) {
10049 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
10050 pickupexten = "";
10051 } else {
10052 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
10053 }
10054 ast_channel_unlock(chan);
10055
10056 if (p->dsp)
10058 switch (p->sig) {
10059 case SIG_FEATD:
10060 case SIG_FEATDMF:
10061 case SIG_FEATDMF_TA:
10062 case SIG_E911:
10063 case SIG_FGC_CAMAMF:
10064 case SIG_FEATB:
10065 case SIG_EMWINK:
10066 case SIG_SF_FEATD:
10067 case SIG_SF_FEATDMF:
10068 case SIG_SF_FEATB:
10069 case SIG_SFWINK:
10070 if (dahdi_wink(p, idx))
10071 goto quit;
10072 /* Fall through */
10073 case SIG_EM:
10074 case SIG_EM_E1:
10075 case SIG_SF:
10076 case SIG_FGC_CAMA:
10077 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10078 if (p->dsp)
10080 /* set digit mode appropriately */
10081 if (p->dsp) {
10082 if (NEED_MFDETECT(p))
10084 else
10086 }
10087 memset(dtmfbuf, 0, sizeof(dtmfbuf));
10088 /* Wait for the first digit only if immediate=no */
10089 if (!p->immediate)
10090 /* Wait for the first digit (up to 5 seconds). */
10091 res = ast_waitfordigit(chan, 5000);
10092 else
10093 res = 0;
10094 if (res > 0) {
10095 /* save first char */
10096 dtmfbuf[0] = res;
10097 switch (p->sig) {
10098 case SIG_FEATD:
10099 case SIG_SF_FEATD:
10100 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10101 if (res > 0)
10102 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10103 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10104 break;
10105 case SIG_FEATDMF_TA:
10106 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10107 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10108 if (dahdi_wink(p, idx)) goto quit;
10109 dtmfbuf[0] = 0;
10110 /* Wait for the first digit (up to 5 seconds). */
10111 res = ast_waitfordigit(chan, 5000);
10112 if (res <= 0) break;
10113 dtmfbuf[0] = res;
10114 /* fall through intentionally */
10115 case SIG_FEATDMF:
10116 case SIG_E911:
10117 case SIG_FGC_CAMAMF:
10118 case SIG_SF_FEATDMF:
10119 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10120 /* if international caca, do it again to get real ANO */
10121 if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
10122 {
10123 if (dahdi_wink(p, idx)) goto quit;
10124 dtmfbuf[0] = 0;
10125 /* Wait for the first digit (up to 5 seconds). */
10126 res = ast_waitfordigit(chan, 5000);
10127 if (res <= 0) break;
10128 dtmfbuf[0] = res;
10129 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10130 }
10131 if (res > 0) {
10132 /* if E911, take off hook */
10133 if (p->sig == SIG_E911)
10134 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10135 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
10136 }
10137 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10138 break;
10139 case SIG_FEATB:
10140 case SIG_SF_FEATB:
10141 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10142 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10143 break;
10144 case SIG_EMWINK:
10145 /* if we received a '*', we are actually receiving Feature Group D
10146 dial syntax, so use that mode; otherwise, fall through to normal
10147 mode
10148 */
10149 if (res == '*') {
10150 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10151 if (res > 0)
10152 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10153 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10154 break;
10155 }
10156 default:
10157 /* If we got the first digit, get the rest */
10158 len = 1;
10159 dtmfbuf[len] = '\0';
10160 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10161 if (ast_exists_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10162 timeout = p->matchdigit_timeout;
10163 } else {
10164 timeout = p->interdigit_timeout;
10165 }
10166 res = ast_waitfordigit(chan, timeout);
10167 if (res < 0) {
10168 ast_debug(1, "waitfordigit returned < 0...\n");
10169 ast_hangup(chan);
10170 goto quit;
10171 } else if (res) {
10172 dtmfbuf[len++] = res;
10173 dtmfbuf[len] = '\0';
10174 } else {
10175 break;
10176 }
10177 }
10178 break;
10179 }
10180 }
10181 if (res == -1) {
10182 ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
10183 ast_hangup(chan);
10184 goto quit;
10185 } else if (res < 0) {
10186 ast_debug(1, "Got hung up before digits finished\n");
10187 ast_hangup(chan);
10188 goto quit;
10189 }
10190
10191 if (p->sig == SIG_FGC_CAMA) {
10192 char anibuf[100];
10193
10194 if (ast_safe_sleep(chan,1000) == -1) {
10195 ast_hangup(chan);
10196 goto quit;
10197 }
10198 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10200 res = my_getsigstr(chan, anibuf, "#", 10000);
10201 if ((res > 0) && (strlen(anibuf) > 2)) {
10202 if (anibuf[strlen(anibuf) - 1] == '#')
10203 anibuf[strlen(anibuf) - 1] = 0;
10204 ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
10205 }
10207 }
10208
10209 ast_copy_string(exten, dtmfbuf, sizeof(exten));
10210 if (ast_strlen_zero(exten))
10211 ast_copy_string(exten, "s", sizeof(exten));
10212 if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
10213 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10214 if (exten[0] == '*') {
10215 char *stringp=NULL;
10216 ast_copy_string(exten2, exten, sizeof(exten2));
10217 /* Parse out extension and callerid */
10218 stringp=exten2 +1;
10219 s1 = strsep(&stringp, "*");
10220 s2 = strsep(&stringp, "*");
10221 if (s2) {
10222 if (!ast_strlen_zero(p->cid_num))
10223 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10224 else
10225 ast_set_callerid(chan, s1, NULL, s1);
10226 ast_copy_string(exten, s2, sizeof(exten));
10227 } else
10228 ast_copy_string(exten, s1, sizeof(exten));
10229 } else if (p->sig == SIG_FEATD)
10230 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10231 }
10232 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10233 if (exten[0] == '*') {
10234 char *stringp=NULL;
10235 ast_copy_string(exten2, exten, sizeof(exten2));
10236 /* Parse out extension and callerid */
10237 stringp=exten2 +1;
10238 s1 = strsep(&stringp, "#");
10239 s2 = strsep(&stringp, "#");
10240 if (s2) {
10241 if (!ast_strlen_zero(p->cid_num))
10242 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10243 else
10244 if (*(s1 + 2))
10245 ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
10246 ast_copy_string(exten, s2 + 1, sizeof(exten));
10247 } else
10248 ast_copy_string(exten, s1 + 2, sizeof(exten));
10249 } else
10250 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10251 }
10252 if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
10253 if (exten[0] == '*') {
10254 char *stringp=NULL;
10255 ast_copy_string(exten2, exten, sizeof(exten2));
10256 /* Parse out extension and callerid */
10257 stringp=exten2 +1;
10258 s1 = strsep(&stringp, "#");
10259 s2 = strsep(&stringp, "#");
10260 if (s2 && (*(s2 + 1) == '0')) {
10261 if (*(s2 + 2))
10262 ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
10263 }
10264 if (s1) ast_copy_string(exten, s1, sizeof(exten));
10265 else ast_copy_string(exten, "911", sizeof(exten));
10266 } else
10267 ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
10268 }
10269 if (p->sig == SIG_FEATB) {
10270 if (exten[0] == '*') {
10271 char *stringp=NULL;
10272 ast_copy_string(exten2, exten, sizeof(exten2));
10273 /* Parse out extension and callerid */
10274 stringp=exten2 +1;
10275 s1 = strsep(&stringp, "#");
10276 ast_copy_string(exten, exten2 + 1, sizeof(exten));
10277 } else
10278 ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
10279 }
10280 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10281 dahdi_wink(p, idx);
10282 /* some switches require a minimum guard time between
10283 the last FGD wink and something that answers
10284 immediately. This ensures it */
10285 if (ast_safe_sleep(chan, 100)) {
10286 ast_hangup(chan);
10287 goto quit;
10288 }
10289 }
10290 dahdi_ec_enable(p);
10291 if (NEED_MFDETECT(p)) {
10292 if (p->dsp) {
10293 if (!p->hardwaredtmf)
10295 else {
10296 ast_dsp_free(p->dsp);
10297 p->dsp = NULL;
10298 }
10299 }
10300 }
10301
10302 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1,
10303 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10304 ast_channel_exten_set(chan, exten);
10305 if (p->dsp) ast_dsp_digitreset(p->dsp);
10306 res = ast_pbx_run(chan);
10307 if (res) {
10308 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10309 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10310 }
10311 goto quit;
10312 } else {
10313 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, ast_channel_context(chan));
10314 sleep(2);
10315 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
10316 if (res < 0)
10317 ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
10318 else
10319 sleep(1);
10320 res = ast_streamfile(chan, "ss-noservice", ast_channel_language(chan));
10321 if (res >= 0)
10322 ast_waitstream(chan, "");
10323 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10324 ast_hangup(chan);
10325 goto quit;
10326 }
10327 break;
10328 case SIG_FXOLS:
10329 case SIG_FXOGS:
10330 case SIG_FXOKS:
10331 /* Read the first digit */
10332 timeout = p->firstdigit_timeout;
10333 /* If starting a threeway call, never timeout on the first digit so someone
10334 can use flash-hook as a "hold" feature */
10335 if (p->subs[SUB_THREEWAY].owner)
10336 timeout = INT_MAX;
10337 while (len < AST_MAX_EXTENSION-1) {
10338 int is_exten_parking = 0;
10339
10340 /* Read digit unless it's supposed to be immediate, in which case the
10341 only answer is 's' */
10342 if (p->immediate)
10343 res = 's';
10344 else
10345 res = ast_waitfordigit(chan, timeout);
10346 timeout = 0;
10347 if (res < 0) {
10348 ast_debug(1, "waitfordigit returned < 0...\n");
10349 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10350 ast_hangup(chan);
10351 goto quit;
10352 } else if (res) {
10353 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
10354 exten[len++]=res;
10355 exten[len] = '\0';
10356 }
10357 if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
10358 tone_zone_play_tone(p->subs[idx].dfd, -1);
10359 } else {
10360 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10361 }
10363 is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
10364 }
10365 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
10366 if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
10367 if (getforward) {
10368 /* Record this as the forwarding extension */
10369 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
10370 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
10371 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10372 if (res)
10373 break;
10374 usleep(500000);
10375 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10376 sleep(1);
10377 memset(exten, 0, sizeof(exten));
10378 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10379 len = 0;
10380 getforward = 0;
10381 } else {
10382 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10383 ast_channel_lock(chan);
10384 ast_channel_exten_set(chan, exten);
10385 if (!ast_strlen_zero(p->cid_num)) {
10386 if (!p->hidecallerid)
10387 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10388 else
10389 ast_set_callerid(chan, NULL, NULL, p->cid_num);
10390 }
10391 if (!ast_strlen_zero(p->cid_name)) {
10392 if (!p->hidecallerid)
10393 ast_set_callerid(chan, NULL, p->cid_name, NULL);
10394 }
10396 ast_channel_unlock(chan);
10397 dahdi_ec_enable(p);
10398 res = ast_pbx_run(chan);
10399 if (res) {
10400 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10401 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10402 }
10403 goto quit;
10404 }
10405 } else {
10406 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10407 so just set the timeout to matchdigit_timeout and wait some more */
10408 timeout = p->matchdigit_timeout;
10409 }
10410 } else if (res == 0) {
10411 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10412 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10413 dahdi_wait_event(p->subs[idx].dfd);
10414 ast_hangup(chan);
10415 goto quit;
10416 } else if (p->callwaiting && !strcmp(exten, "*70")) {
10417 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
10418 /* Disable call waiting if enabled */
10419 p->callwaiting = 0;
10420 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10421 if (res) {
10422 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10423 ast_channel_name(chan), strerror(errno));
10424 }
10425 len = 0;
10426 ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
10427 memset(exten, 0, sizeof(exten));
10428 timeout = p->firstdigit_timeout;
10429
10430 } else if (!strcmp(exten, pickupexten)) {
10431 /* Scan all channels and see if there are any
10432 * ringing channels that have call groups
10433 * that equal this channels pickup group
10434 */
10435 if (idx == SUB_REAL) {
10436 /* Switch us from Third call to Call Wait */
10437 if (p->subs[SUB_THREEWAY].owner) {
10438 /* If you make a threeway call and the *8# a call, it should actually
10439 look like a callwait */
10443 }
10444 dahdi_ec_enable(p);
10445 if (ast_pickup_call(chan)) {
10446 ast_debug(1, "No call pickup possible...\n");
10447 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10448 dahdi_wait_event(p->subs[idx].dfd);
10449 }
10450 ast_hangup(chan);
10451 goto quit;
10452 } else {
10453 ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
10454 ast_hangup(chan);
10455 goto quit;
10456 }
10457
10458 } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
10459 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
10460 /* Disable Caller*ID if enabled */
10461 p->hidecallerid = 1;
10466 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10467 if (res) {
10468 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10469 ast_channel_name(chan), strerror(errno));
10470 }
10471 len = 0;
10472 memset(exten, 0, sizeof(exten));
10473 timeout = p->firstdigit_timeout;
10474 } else if (p->callreturn && !strcmp(exten, "*69")) {
10475 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10476 break;
10477 } else if (!strcmp(exten, "*78")) {
10478 dahdi_dnd(p, 1);
10479 /* Do not disturb */
10480 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10481 getforward = 0;
10482 memset(exten, 0, sizeof(exten));
10483 len = 0;
10484 } else if (!strcmp(exten, "*79")) {
10485 dahdi_dnd(p, 0);
10486 /* Do not disturb */
10487 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10488 getforward = 0;
10489 memset(exten, 0, sizeof(exten));
10490 len = 0;
10491 } else if (p->cancallforward && !strcmp(exten, "*72")) {
10492 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10493 getforward = 1;
10494 memset(exten, 0, sizeof(exten));
10495 len = 0;
10496 } else if (p->cancallforward && !strcmp(exten, "*73")) {
10497 ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
10498 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10499 memset(p->call_forward, 0, sizeof(p->call_forward));
10500 getforward = 0;
10501 memset(exten, 0, sizeof(exten));
10502 len = 0;
10503 } else if ((p->transfer || p->canpark) && is_exten_parking
10504 && p->subs[SUB_THREEWAY].owner) {
10505 struct ast_bridge_channel *bridge_channel;
10506
10507 /*
10508 * This is a three way call, the main call being a real channel,
10509 * and we're parking the first call.
10510 */
10514 if (bridge_channel) {
10515 if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
10516 /*
10517 * Swap things around between the three-way and real call so we
10518 * can hear where the channel got parked.
10519 */
10520 ast_mutex_lock(&p->lock);
10521 p->owner = p->subs[SUB_THREEWAY].owner;
10524
10525 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
10527 ao2_ref(bridge_channel, -1);
10528 goto quit;
10529 }
10530 ao2_ref(bridge_channel, -1);
10531 }
10532 break;
10533 } else if (p->hidecallerid && !strcmp(exten, "*82")) {
10534 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
10535 /* Enable Caller*ID if enabled */
10536 p->hidecallerid = 0;
10538 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10539 if (res) {
10540 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10541 ast_channel_name(chan), strerror(errno));
10542 }
10543 len = 0;
10544 memset(exten, 0, sizeof(exten));
10545 timeout = p->firstdigit_timeout;
10546 } else if (!strcmp(exten, "*0")) {
10547 struct ast_channel *nbridge =
10549 struct dahdi_pvt *pbridge = NULL;
10550 RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
10551
10552 /* set up the private struct of the bridged one, if any */
10553 if (nbridge && bridged) {
10554 pbridge = ast_channel_tech_pvt(bridged);
10555 }
10556 if (nbridge && pbridge &&
10557 (ast_channel_tech(nbridge) == &dahdi_tech) &&
10558 (ast_channel_tech(bridged) == &dahdi_tech) &&
10559 ISTRUNK(pbridge)) {
10560 int func = DAHDI_FLASH;
10561 /* Clear out the dial buffer */
10562 p->dop.dialstr[0] = '\0';
10563 /* flash hookswitch */
10564 if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
10565 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
10566 ast_channel_name(nbridge), strerror(errno));
10567 }
10570 p->owner = p->subs[SUB_REAL].owner;
10572 ast_hangup(chan);
10573 goto quit;
10574 } else {
10575 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10576 dahdi_wait_event(p->subs[idx].dfd);
10577 tone_zone_play_tone(p->subs[idx].dfd, -1);
10580 p->owner = p->subs[SUB_REAL].owner;
10581 ast_hangup(chan);
10582 goto quit;
10583 }
10584 } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
10585 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
10586 && !canmatch_featurecode(pickupexten, exten)) {
10587 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
10588 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
10589 ast_channel_context(chan));
10590 break;
10591 }
10592 if (!timeout)
10593 timeout = p->interdigit_timeout;
10595 tone_zone_play_tone(p->subs[idx].dfd, -1);
10596 }
10597 break;
10598 case SIG_FXSLS:
10599 case SIG_FXSGS:
10600 case SIG_FXSKS:
10601 /* check for SMDI messages */
10602 if (p->use_smdi && p->smdi_iface) {
10604
10605 if (smdi_msg != NULL) {
10606 ast_channel_exten_set(chan, smdi_msg->fwd_st);
10607
10608 if (smdi_msg->type == 'B')
10609 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
10610 else if (smdi_msg->type == 'N')
10611 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
10612
10613 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan));
10614 } else {
10615 ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
10616 }
10617 }
10618
10619 if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
10620 number = smdi_msg->calling_st;
10621
10622 /* If we want caller id, we're in a prering state due to a polarity reversal
10623 * and we're set to use a polarity reversal to trigger the start of caller id,
10624 * grab the caller id and wait for ringing to start... */
10625 } else if (p->use_callerid && (ast_channel_state(chan) == AST_STATE_PRERING &&
10627 /* If set to use DTMF CID signalling, listen for DTMF */
10628 if (p->cid_signalling == CID_SIG_DTMF) {
10629 int k = 0;
10630 int off_ms;
10631 struct timeval start = ast_tvnow();
10632 int ms;
10633 cs = NULL;
10634 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
10635 dahdi_setlinear(p->subs[idx].dfd, 0);
10636 /*
10637 * We are the only party interested in the Rx stream since
10638 * we have not answered yet. We don't need or even want DTMF
10639 * emulation. The DTMF digits can come so fast that emulation
10640 * can drop some of them.
10641 */
10642 ast_channel_lock(chan);
10644 ast_channel_unlock(chan);
10645 off_ms = 4000;/* This is a typical OFF time between rings. */
10646 for (;;) {
10647 struct ast_frame *f;
10648
10649 ms = ast_remaining_ms(start, off_ms);
10650 res = ast_waitfor(chan, ms);
10651 if (res <= 0) {
10652 /*
10653 * We do not need to restore the dahdi_setlinear()
10654 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10655 * are hanging up the channel.
10656 */
10657 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10658 "Exiting simple switch\n");
10659 ast_hangup(chan);
10660 goto quit;
10661 }
10662 f = ast_read(chan);
10663 if (!f)
10664 break;
10665 if (f->frametype == AST_FRAME_DTMF) {
10666 if (k < ARRAY_LEN(dtmfbuf) - 1) {
10667 dtmfbuf[k++] = f->subclass.integer;
10668 }
10669 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10670 start = ast_tvnow();
10671 }
10672 ast_frfree(f);
10673 if (ast_channel_state(chan) == AST_STATE_RING ||
10675 break; /* Got ring */
10676 }
10677 ast_channel_lock(chan);
10679 ast_channel_unlock(chan);
10680 dtmfbuf[k] = '\0';
10681 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10682 /* Got cid and ring. */
10683 ast_debug(1, "CID got string '%s'\n", dtmfbuf);
10684 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10685 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid, flags);
10686 /* If first byte is NULL, we have no cid */
10687 if (!ast_strlen_zero(dtmfcid))
10688 number = dtmfcid;
10689 else
10690 number = NULL;
10691 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10692 } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
10694 if (cs) {
10695 int off_ms;
10696 struct timeval start;
10697 int ms;
10698 samples = 0;
10699#if 1
10700 bump_gains(p);
10701#endif
10702 /* Take out of linear mode for Caller*ID processing */
10703 dahdi_setlinear(p->subs[idx].dfd, 0);
10704
10705 /* First we wait and listen for the Caller*ID */
10706 for (;;) {
10707 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10708 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10709 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10710 callerid_free(cs);
10711 ast_hangup(chan);
10712 goto quit;
10713 }
10714 if (i & DAHDI_IOMUX_SIGEVENT) {
10715 res = dahdi_get_event(p->subs[idx].dfd);
10716 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10717 if (res == DAHDI_EVENT_NOALARM) {
10718 p->inalarm = 0;
10719 }
10720
10721 if (p->cid_signalling == CID_SIG_V23_JP) {
10722 if (res == DAHDI_EVENT_RINGBEGIN) {
10723 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10724 usleep(1);
10725 }
10726 } else {
10727 res = 0;
10728 break;
10729 }
10730 } else if (i & DAHDI_IOMUX_READ) {
10731 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10732 if (res < 0) {
10733 if (errno != ELAST) {
10734 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10735 callerid_free(cs);
10736 ast_hangup(chan);
10737 goto quit;
10738 }
10739 break;
10740 }
10741 samples += res;
10742
10743 if (p->cid_signalling == CID_SIG_V23_JP) {
10744 res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
10745 } else {
10746 res = callerid_feed(cs, buf, res, AST_LAW(p));
10747 }
10748 if (res < 0) {
10749 /*
10750 * The previous diagnostic message output likely
10751 * explains why it failed.
10752 */
10754 "Failed to decode CallerID on channel '%s'\n",
10755 ast_channel_name(chan));
10756 break;
10757 } else if (res)
10758 break;
10759 else if (samples > (8000 * 10))
10760 break;
10761 }
10762 }
10763 if (res == 1) {
10764 callerid_get(cs, &name, &number, &flags);
10765 ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
10766 }
10767
10768 if (p->cid_signalling == CID_SIG_V23_JP) {
10769 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
10770 usleep(1);
10771 }
10772
10773 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10774 start = ast_tvnow();
10775 off_ms = 4000;/* This is a typical OFF time between rings. */
10776 for (;;) {
10777 struct ast_frame *f;
10778
10779 ms = ast_remaining_ms(start, off_ms);
10780 res = ast_waitfor(chan, ms);
10781 if (res <= 0) {
10782 ast_log(LOG_WARNING, "CID timed out waiting for ring. "
10783 "Exiting simple switch\n");
10784 ast_hangup(chan);
10785 goto quit;
10786 }
10787 if (!(f = ast_read(chan))) {
10788 ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
10789 ast_hangup(chan);
10790 goto quit;
10791 }
10792 ast_frfree(f);
10793 if (ast_channel_state(chan) == AST_STATE_RING ||
10795 break; /* Got ring */
10796 }
10797
10798 /* We must have a ring by now, so, if configured, lets try to listen for
10799 * distinctive ringing */
10801 len = 0;
10802 distMatches = 0;
10803 /* Clear the current ring data array so we don't have old data in it. */
10804 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10805 curRingData[receivedRingT] = 0;
10806 receivedRingT = 0;
10807 counter = 0;
10808 counter1 = 0;
10809 /* Check to see if context is what it should be, if not set to be. */
10810 if (strcmp(p->context,p->defcontext) != 0) {
10811 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10813 }
10814
10815 for (;;) {
10816 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10817 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10818 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10819 callerid_free(cs);
10820 ast_hangup(chan);
10821 goto quit;
10822 }
10823 if (i & DAHDI_IOMUX_SIGEVENT) {
10824 res = dahdi_get_event(p->subs[idx].dfd);
10825 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10826 if (res == DAHDI_EVENT_NOALARM) {
10827 p->inalarm = 0;
10828 }
10829 res = 0;
10830 /* Let us detect distinctive ring */
10831
10832 curRingData[receivedRingT] = p->ringt;
10833
10834 if (p->ringt < p->ringt_base/2)
10835 break;
10836 /* Increment the ringT counter so we can match it against
10837 values in chan_dahdi.conf for distinctive ring */
10838 if (++receivedRingT == ARRAY_LEN(curRingData))
10839 break;
10840 } else if (i & DAHDI_IOMUX_READ) {
10841 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10842 if (res < 0) {
10843 if (errno != ELAST) {
10844 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10845 callerid_free(cs);
10846 ast_hangup(chan);
10847 goto quit;
10848 }
10849 break;
10850 }
10851 if (p->ringt > 0) {
10852 if (!(--p->ringt)) {
10853 res = -1;
10854 break;
10855 }
10856 }
10857 }
10858 }
10859 /* this only shows up if you have n of the dring patterns filled in */
10860 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
10861 for (counter = 0; counter < 3; counter++) {
10862 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10863 channel */
10864 distMatches = 0;
10865 for (counter1 = 0; counter1 < 3; counter1++) {
10866 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
10867 if (p->drings.ringnum[counter].ring[counter1] == -1) {
10868 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10869 curRingData[counter1]);
10870 distMatches++;
10871 } else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
10872 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
10873 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10874 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
10875 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
10876 distMatches++;
10877 }
10878 }
10879
10880 if (distMatches == 3) {
10881 /* The ring matches, set the context to whatever is for distinctive ring.. */
10882 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
10884 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
10885 break;
10886 }
10887 }
10888 }
10889 /* Restore linear mode (if appropriate) for Caller*ID processing */
10890 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10891#if 1
10892 restore_gains(p);
10893#endif
10894 } else
10895 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
10896 } else {
10897 ast_log(LOG_WARNING, "Channel %s in prering "
10898 "state, but I have nothing to do. "
10899 "Terminating simple switch, should be "
10900 "restarted by the actual ring.\n",
10901 ast_channel_name(chan));
10902 ast_hangup(chan);
10903 goto quit;
10904 }
10905 } else if (p->use_callerid && p->cid_start == CID_START_RING) {
10906 if (p->cid_signalling == CID_SIG_DTMF) {
10907 int k = 0;
10908 int off_ms;
10909 struct timeval start;
10910 int ms;
10911 cs = NULL;
10912 dahdi_setlinear(p->subs[idx].dfd, 0);
10913 off_ms = 2000;
10914 start = ast_tvnow();
10915 for (;;) {
10916 struct ast_frame *f;
10917
10918 ms = ast_remaining_ms(start, off_ms);
10919 res = ast_waitfor(chan, ms);
10920 if (res <= 0) {
10921 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10922 "Exiting simple switch\n");
10923 ast_hangup(chan);
10924 goto quit;
10925 }
10926 f = ast_read(chan);
10927 if (!f) {
10928 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10929 ast_hangup(chan);
10930 goto quit;
10931 }
10932 if (f->frametype == AST_FRAME_DTMF) {
10933 dtmfbuf[k++] = f->subclass.integer;
10934 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10935 start = ast_tvnow();
10936 }
10937 ast_frfree(f);
10938
10939 if (p->ringt_base == p->ringt)
10940 break;
10941 }
10942 dtmfbuf[k] = '\0';
10943 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10944 /* Got cid and ring. */
10945 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10946 ast_debug(1, "CID is '%s', flags %d\n",
10947 dtmfcid, flags);
10948 /* If first byte is NULL, we have no cid */
10949 if (!ast_strlen_zero(dtmfcid))
10950 number = dtmfcid;
10951 else
10952 number = NULL;
10953 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10954 } else {
10955 /* FSK Bell202 callerID */
10957 if (cs) {
10958#if 1
10959 bump_gains(p);
10960#endif
10961 samples = 0;
10962 len = 0;
10963 distMatches = 0;
10964 /* Clear the current ring data array so we don't have old data in it. */
10965 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10966 curRingData[receivedRingT] = 0;
10967 receivedRingT = 0;
10968 counter = 0;
10969 counter1 = 0;
10970 /* Check to see if context is what it should be, if not set to be. */
10971 if (strcmp(p->context,p->defcontext) != 0) {
10972 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10974 }
10975
10976 /* Take out of linear mode for Caller*ID processing */
10977 dahdi_setlinear(p->subs[idx].dfd, 0);
10978 for (;;) {
10979 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10980 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10981 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10982 callerid_free(cs);
10983 ast_hangup(chan);
10984 goto quit;
10985 }
10986 if (i & DAHDI_IOMUX_SIGEVENT) {
10987 res = dahdi_get_event(p->subs[idx].dfd);
10988 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10989 if (res == DAHDI_EVENT_NOALARM) {
10990 p->inalarm = 0;
10991 }
10992 /* If we get a PR event, they hung up while processing calerid */
10993 if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
10994 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
10996 callerid_free(cs);
10997 ast_hangup(chan);
10998 goto quit;
10999 }
11000 res = 0;
11001 /* Let us detect callerid when the telco uses distinctive ring */
11002
11003 curRingData[receivedRingT] = p->ringt;
11004
11005 if (p->ringt < p->ringt_base/2)
11006 break;
11007 /* Increment the ringT counter so we can match it against
11008 values in chan_dahdi.conf for distinctive ring */
11009 if (++receivedRingT == ARRAY_LEN(curRingData))
11010 break;
11011 } else if (i & DAHDI_IOMUX_READ) {
11012 res = read(p->subs[idx].dfd, buf, sizeof(buf));
11013 if (res < 0) {
11014 if (errno != ELAST) {
11015 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11016 callerid_free(cs);
11017 ast_hangup(chan);
11018 goto quit;
11019 }
11020 break;
11021 }
11022 if (p->ringt > 0) {
11023 if (!(--p->ringt)) {
11024 res = -1;
11025 break;
11026 }
11027 }
11028 samples += res;
11029 res = callerid_feed(cs, buf, res, AST_LAW(p));
11030 if (res < 0) {
11031 /*
11032 * The previous diagnostic message output likely
11033 * explains why it failed.
11034 */
11036 "Failed to decode CallerID on channel '%s'\n",
11037 ast_channel_name(chan));
11038 break;
11039 } else if (res)
11040 break;
11041 else if (samples > (8000 * 10))
11042 break;
11043 }
11044 }
11045 if (res == 1) {
11046 callerid_get(cs, &name, &number, &flags);
11047 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
11048 }
11049 if (distinctiveringaftercid == 1) {
11050 /* Clear the current ring data array so we don't have old data in it. */
11051 for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
11052 curRingData[receivedRingT] = 0;
11053 }
11054 receivedRingT = 0;
11055 ast_verb(3, "Detecting post-CID distinctive ring\n");
11056 for (;;) {
11057 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11058 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
11059 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11060 callerid_free(cs);
11061 ast_hangup(chan);
11062 goto quit;
11063 }
11064 if (i & DAHDI_IOMUX_SIGEVENT) {
11065 res = dahdi_get_event(p->subs[idx].dfd);
11066 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
11067 if (res == DAHDI_EVENT_NOALARM) {
11068 p->inalarm = 0;
11069 }
11070 res = 0;
11071 /* Let us detect callerid when the telco uses distinctive ring */
11072
11073 curRingData[receivedRingT] = p->ringt;
11074
11075 if (p->ringt < p->ringt_base/2)
11076 break;
11077 /* Increment the ringT counter so we can match it against
11078 values in chan_dahdi.conf for distinctive ring */
11079 if (++receivedRingT == ARRAY_LEN(curRingData))
11080 break;
11081 } else if (i & DAHDI_IOMUX_READ) {
11082 res = read(p->subs[idx].dfd, buf, sizeof(buf));
11083 if (res < 0) {
11084 if (errno != ELAST) {
11085 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11086 callerid_free(cs);
11087 ast_hangup(chan);
11088 goto quit;
11089 }
11090 break;
11091 }
11092 if (p->ringt > 0) {
11093 if (!(--p->ringt)) {
11094 res = -1;
11095 break;
11096 }
11097 }
11098 }
11099 }
11100 }
11102 /* this only shows up if you have n of the dring patterns filled in */
11103 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
11104
11105 for (counter = 0; counter < 3; counter++) {
11106 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
11107 channel */
11108 /* this only shows up if you have n of the dring patterns filled in */
11109 ast_verb(3, "Checking %d,%d,%d\n",
11110 p->drings.ringnum[counter].ring[0],
11111 p->drings.ringnum[counter].ring[1],
11112 p->drings.ringnum[counter].ring[2]);
11113 distMatches = 0;
11114 for (counter1 = 0; counter1 < 3; counter1++) {
11115 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
11116 if (p->drings.ringnum[counter].ring[counter1] == -1) {
11117 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
11118 curRingData[counter1]);
11119 distMatches++;
11120 }
11121 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
11122 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
11123 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
11124 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
11125 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
11126 distMatches++;
11127 }
11128 }
11129 if (distMatches == 3) {
11130 /* The ring matches, set the context to whatever is for distinctive ring.. */
11131 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
11133 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
11134 break;
11135 }
11136 }
11137 }
11138 /* Restore linear mode (if appropriate) for Caller*ID processing */
11139 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
11140#if 1
11141 restore_gains(p);
11142#endif
11143 if (res < 0) {
11144 ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
11145 }
11146 } else
11147 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
11148 }
11149 } else
11150 cs = NULL;
11151
11152 if (number)
11155
11156 ao2_cleanup(smdi_msg);
11157
11158 if (cs)
11159 callerid_free(cs);
11160
11161 my_handle_notify_message(chan, p, flags, -1);
11162
11163 ast_channel_lock(chan);
11165 ast_channel_rings_set(chan, 1);
11166 ast_channel_unlock(chan);
11167 p->ringt = p->ringt_base;
11168 res = ast_pbx_run(chan);
11169 if (res) {
11170 ast_hangup(chan);
11171 ast_log(LOG_WARNING, "PBX exited non-zero\n");
11172 }
11173 goto quit;
11174 default:
11175 ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
11176 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11177 if (res < 0)
11178 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11179 }
11180 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11181 if (res < 0)
11182 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11183 ast_hangup(chan);
11184quit:
11189 return NULL;
11190}
11191
11194 unsigned char buf[READ_SIZE];
11195 size_t len;
11196};
11197
11198static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
11199{
11200 int x;
11201 int sum = 0;
11202
11203 if (!len)
11204 return 0;
11205
11206 for (x = 0; x < len; x++)
11207 sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
11208
11209 return sum / len;
11210}
11211
11212static void *mwi_thread(void *data)
11213{
11214 struct mwi_thread_data *mtd = data;
11215 struct callerid_state *cs;
11216 pthread_t threadid;
11217 int samples = 0;
11218 char *name, *number;
11219 int flags;
11220 int i, res;
11221 unsigned int spill_done = 0;
11222 int spill_result = -1;
11223
11224 if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
11225 goto quit_no_clean;
11226 }
11227
11228 callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
11229
11230 bump_gains(mtd->pvt);
11231
11232 for (;;) {
11233 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11234 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
11235 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11236 goto quit;
11237 }
11238
11239 if (i & DAHDI_IOMUX_SIGEVENT) {
11240 struct ast_channel *chan;
11241 ast_callid callid = 0;
11242 int callid_created;
11243
11244 /* If we get an event, screen out events that we do not act on.
11245 * Otherwise, cancel and go to the simple switch to let it deal with it.
11246 */
11247 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
11248
11249 switch (res) {
11250 case DAHDI_EVENT_NEONMWI_ACTIVE:
11251 case DAHDI_EVENT_NEONMWI_INACTIVE:
11252 case DAHDI_EVENT_NONE:
11253 case DAHDI_EVENT_BITSCHANGED:
11254 break;
11255 case DAHDI_EVENT_NOALARM:
11256 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11257 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11258
11259 analog_p->inalarm = 0;
11260 }
11261 mtd->pvt->inalarm = 0;
11263 break;
11264 case DAHDI_EVENT_ALARM:
11265 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11266 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11267
11268 analog_p->inalarm = 1;
11269 }
11270 mtd->pvt->inalarm = 1;
11271 res = get_alarms(mtd->pvt);
11272 handle_alarms(mtd->pvt, res);
11273 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11274 default:
11275 callid_created = ast_callid_threadstorage_auto(&callid);
11276 ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to analog_ss_thread\n", res, event2str(res));
11277 callerid_free(cs);
11278
11279 restore_gains(mtd->pvt);
11280 mtd->pvt->ringt = mtd->pvt->ringt_base;
11281
11282 if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid))) {
11283 int result;
11284
11285 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11287 } else {
11289 }
11290 if (result) {
11291 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
11292 res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11293 if (res < 0)
11294 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
11295 ast_hangup(chan);
11296 }
11297 } else {
11298 ast_log(LOG_WARNING, "Could not create channel to handle call\n");
11299 }
11300
11301 ast_callid_threadstorage_auto_clean(callid, callid_created);
11302 goto quit_no_clean;
11303 }
11304 } else if (i & DAHDI_IOMUX_READ) {
11305 if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
11306 if (errno != ELAST) {
11307 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11308 goto quit;
11309 }
11310 break;
11311 }
11312 samples += res;
11313 if (!spill_done) {
11314 if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
11315 /*
11316 * The previous diagnostic message output likely
11317 * explains why it failed.
11318 */
11319 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
11320 break;
11321 } else if (spill_result) {
11322 spill_done = 1;
11323 }
11324 } else {
11325 /* keep reading data until the energy level drops below the threshold
11326 so we don't get another 'trigger' on the remaining carrier signal
11327 */
11328 if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
11329 break;
11330 }
11331 if (samples > (8000 * 4)) /*Termination case - time to give up*/
11332 break;
11333 }
11334 }
11335
11336 if (spill_result == 1) {
11337 callerid_get(cs, &name, &number, &flags);
11338 if (flags & CID_MSGWAITING) {
11339 ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
11340 notify_message(mtd->pvt->mailbox, 1);
11341 } else if (flags & CID_NOMSGWAITING) {
11342 ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
11343 notify_message(mtd->pvt->mailbox, 0);
11344 } else {
11345 ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
11346 }
11347 }
11348
11349
11350quit:
11351 callerid_free(cs);
11352
11353 restore_gains(mtd->pvt);
11354
11355quit_no_clean:
11356 mtd->pvt->mwimonitoractive = 0;
11357 ast_free(mtd);
11358
11359 return NULL;
11360}
11361
11362/*
11363* The following three functions (mwi_send_init, mwi_send_process_buffer,
11364* mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11365* that are sent out via FXS port on voicemail state change. The execution of
11366* the mwi send is state driven and can either generate a ring pulse prior to
11367* sending the fsk spill or simply send an fsk spill.
11368*/
11369static int mwi_send_init(struct dahdi_pvt * pvt)
11370{
11371 int x;
11372
11373#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11374 /* Determine how this spill is to be sent */
11375 if (pvt->mwisend_rpas) {
11377 pvt->mwisendactive = 1;
11378 } else if (pvt->mwisend_fsk) {
11380 pvt->mwisendactive = 1;
11381 } else {
11382 pvt->mwisendactive = 0;
11383 return 0;
11384 }
11385#else
11386 if (mwisend_rpas) {
11388 } else {
11390 }
11391 pvt->mwisendactive = 1;
11392#endif
11393
11394 if (pvt->cidspill) {
11395 ast_log(LOG_WARNING, "cidspill already exists when trying to send FSK MWI\n");
11396 ast_free(pvt->cidspill);
11397 pvt->cidspill = NULL;
11398 pvt->cidpos = 0;
11399 pvt->cidlen = 0;
11400 }
11402 if (!pvt->cidspill) {
11403 pvt->mwisendactive = 0;
11404 return -1;
11405 }
11406 x = DAHDI_FLUSH_BOTH;
11407 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
11408 x = 3000;
11409 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
11410#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11411 if (pvt->mwisend_fsk) {
11412#endif
11414 CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
11415 pvt->cidpos = 0;
11416#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11417 }
11418#endif
11419 return 0;
11420}
11421
11422static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
11423{
11424 struct timeval now;
11425 int res;
11426
11427 /* sanity check to catch if this had been interrupted previously
11428 * i.e. state says there is more to do but there is no spill allocated
11429 */
11430 if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) {
11432 } else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
11433 /* Normal processing -- Perform mwi send action */
11434 switch ( pvt->mwisend_data.mwisend_current) {
11435 case MWI_SEND_SA:
11436 /* Send the Ring Pulse Signal Alert */
11437 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
11438 if (res) {
11439 ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
11440 goto quit;
11441 }
11442 res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING);
11444 break;
11445 case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */
11446 break;
11447 case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/
11448#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11449 if (pvt->mwisend_fsk) {
11450#endif
11451 gettimeofday(&now, NULL);
11452 if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) {
11454 }
11455#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11456 } else { /* support for mwisendtype=nofsk */
11458 }
11459#endif
11460 break;
11461 case MWI_SEND_SPILL:
11462 /* We read some number of bytes. Write an equal amount of data */
11463 if (0 < num_read) {
11464 if (num_read > pvt->cidlen - pvt->cidpos) {
11465 num_read = pvt->cidlen - pvt->cidpos;
11466 }
11467 res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
11468 if (res > 0) {
11469 pvt->cidpos += res;
11470 if (pvt->cidpos >= pvt->cidlen) {
11472 }
11473 } else {
11474 ast_log(LOG_WARNING, "MWI FSK Send Write failed: %s\n", strerror(errno));
11475 goto quit;
11476 }
11477 }
11478 break;
11479 case MWI_SEND_CLEANUP:
11480 /* For now, do nothing */
11482 break;
11483 default:
11484 /* Should not get here, punt*/
11485 goto quit;
11486 }
11487 }
11488
11490 if (pvt->cidspill) {
11491 ast_free(pvt->cidspill);
11492 pvt->cidspill = NULL;
11493 pvt->cidpos = 0;
11494 pvt->cidlen = 0;
11495 }
11496 pvt->mwisendactive = 0;
11497 }
11498 return 0;
11499quit:
11500 if (pvt->cidspill) {
11501 ast_free(pvt->cidspill);
11502 pvt->cidspill = NULL;
11503 pvt->cidpos = 0;
11504 pvt->cidlen = 0;
11505 }
11506 pvt->mwisendactive = 0;
11507 return -1;
11508}
11509
11510static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
11511{
11512 int handled = 0;
11513
11515 switch (event) {
11516 case DAHDI_EVENT_RINGEROFF:
11518 handled = 1;
11519
11520 if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
11521 ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
11522 ast_free(pvt->cidspill);
11523 pvt->cidspill = NULL;
11525 pvt->mwisendactive = 0;
11526 } else {
11528 gettimeofday(&pvt->mwisend_data.pause, NULL);
11529 }
11530 }
11531 break;
11532 /* Going off hook, I need to punt this spill */
11533 case DAHDI_EVENT_RINGOFFHOOK:
11534 if (pvt->cidspill) {
11535 ast_free(pvt->cidspill);
11536 pvt->cidspill = NULL;
11537 pvt->cidpos = 0;
11538 pvt->cidlen = 0;
11539 }
11541 pvt->mwisendactive = 0;
11542 break;
11543 case DAHDI_EVENT_RINGERON:
11544 case DAHDI_EVENT_HOOKCOMPLETE:
11545 break;
11546 default:
11547 break;
11548 }
11549 }
11550 return handled;
11551}
11552
11553/* destroy a range DAHDI channels, identified by their number */
11554static void dahdi_destroy_channel_range(int start, int end)
11555{
11556 struct dahdi_pvt *cur;
11557 struct dahdi_pvt *next;
11558 int destroyed_first = 0;
11559 int destroyed_last = 0;
11560
11562 ast_debug(1, "range: %d-%d\n", start, end);
11563 for (cur = iflist; cur; cur = next) {
11564 next = cur->next;
11565 if (cur->channel >= start && cur->channel <= end) {
11566 int x = DAHDI_FLASH;
11567
11568 if (cur->channel > destroyed_last) {
11569 destroyed_last = cur->channel;
11570 }
11571 if (destroyed_first < 1 || cur->channel < destroyed_first) {
11572 destroyed_first = cur->channel;
11573 }
11574 ast_debug(3, "Destroying %d\n", cur->channel);
11575 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11576 ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11577
11578 destroy_channel(cur, 1);
11580 }
11581 }
11583 if (destroyed_first > start || destroyed_last < end) {
11584 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11585 start, end, destroyed_first, destroyed_last);
11586 }
11587}
11588
11589#ifdef HAVE_OPENR2
11590static void dahdi_r2_destroy_nodev(void)
11591{
11592 struct r2link_entry *cur;
11593 AST_LIST_LOCK(&nodev_r2links);
11594 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
11595 int i;
11596 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
11597 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
11598 for (i = 0; i < r2->numchans; i++) {
11599 int channel;
11600 struct dahdi_pvt *pvt = r2->pvts[i];
11601 if (!pvt) {
11602 continue;
11603 }
11604 channel = pvt->channel;
11605 ast_debug(3, "About to destroy B-channel %d.\n", channel);
11607 }
11608 ast_debug(3, "Destroying R2 link\n");
11609 AST_LIST_REMOVE(&nodev_r2links, cur, list);
11610 if (r2->r2master != AST_PTHREADT_NULL) {
11611 pthread_cancel(r2->r2master);
11612 pthread_join(r2->r2master, NULL);
11613 r2->r2master = AST_PTHREADT_NULL;
11614 openr2_context_delete(r2->protocol_context);
11615 }
11616 ast_free(cur);
11617 }
11619 AST_LIST_UNLOCK(&nodev_r2links);
11620}
11621#endif
11622
11623static int setup_dahdi(int reload);
11624static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
11625
11626/*!
11627 * \internal
11628 * \brief create a range of new DAHDI channels
11629 *
11630 * \param start first channel in the range
11631 * \param end last channel in the range
11632 *
11633 * \retval RESULT_SUCCESS on success.
11634 * \retval RESULT_FAILURE on error.
11635 */
11636static int dahdi_create_channel_range(int start, int end)
11637{
11638 struct dahdi_pvt *cur;
11639 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
11640 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
11642 int ret = RESULT_FAILURE; /* be pessimistic */
11643
11644 ast_debug(1, "channel range caps: %d - %d\n", start, end);
11646 for (cur = iflist; cur; cur = cur->next) {
11647 if (cur->channel >= start && cur->channel <= end) {
11649 "channel range %d-%d is occupied\n",
11650 start, end);
11651 goto out;
11652 }
11653 }
11654#ifdef HAVE_PRI
11655 {
11656 int i, x;
11657 for (x = 0; x < NUM_SPANS; x++) {
11658 struct dahdi_pri *pri = pris + x;
11659
11660 if (!pris[x].pri.pvts[0]) {
11661 break;
11662 }
11663 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
11664 int channo = pri->dchannels[i];
11665
11666 if (!channo) {
11667 break;
11668 }
11669 if (!pri->pri.fds[i]) {
11670 break;
11671 }
11672 if (channo >= start && channo <= end) {
11674 "channel range %d-%d is occupied by span %d\n",
11675 start, end, x + 1);
11676 goto out;
11677 }
11678 }
11679 }
11680 }
11681#endif
11682 if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
11683 !conf.chan.cc_params) {
11684 goto out;
11685 }
11686 default_conf.wanted_channels_start = start;
11687 base_conf.wanted_channels_start = start;
11688 conf.wanted_channels_start = start;
11689 default_conf.wanted_channels_end = end;
11690 base_conf.wanted_channels_end = end;
11691 conf.wanted_channels_end = end;
11692 if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
11693 ret = RESULT_SUCCESS;
11694 }
11695out:
11698 ast_cc_config_params_destroy(conf.chan.cc_params);
11700 return ret;
11701}
11702
11703
11704static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
11705{
11706 int res;
11707 pthread_t threadid;
11708 struct ast_channel *chan;
11709 ast_callid callid = 0;
11710 int callid_created;
11711
11712 /* Handle an event on a given channel for the monitor thread. */
11713
11714 switch (event) {
11715 case DAHDI_EVENT_NONE:
11716 case DAHDI_EVENT_BITSCHANGED:
11717 break;
11718 case DAHDI_EVENT_WINKFLASH:
11719 case DAHDI_EVENT_RINGOFFHOOK:
11720 if (i->inalarm) break;
11721 if (i->radio) break;
11722 /* Got a ring/answer. What kind of channel are we? */
11723 switch (i->sig) {
11724 case SIG_FXOLS:
11725 case SIG_FXOGS:
11726 case SIG_FXOKS:
11727 res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11728 if (res && (errno == EBUSY)) {
11729 break;
11730 }
11731
11732 callid_created = ast_callid_threadstorage_auto(&callid);
11733
11734 /* Cancel VMWI spill */
11735 ast_free(i->cidspill);
11736 i->cidspill = NULL;
11738
11739 if (i->immediate) {
11740 dahdi_ec_enable(i);
11741 /* The channel is immediately up. Start right away */
11742 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
11743 chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, NULL, callid);
11744 if (!chan) {
11745 ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
11746 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11747 if (res < 0)
11748 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11749 }
11750 } else {
11751 /* Check for callerid, digits, etc */
11752 chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, NULL, callid);
11753 if (chan) {
11754 if (has_voicemail(i))
11755 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
11756 else
11757 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
11758 if (res < 0)
11759 ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
11760 if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11761 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11762 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11763 if (res < 0)
11764 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11765 ast_hangup(chan);
11766 }
11767 } else
11768 ast_log(LOG_WARNING, "Unable to create channel\n");
11769 }
11770
11772 break;
11773 case SIG_FXSLS:
11774 case SIG_FXSGS:
11775 case SIG_FXSKS:
11776 i->ringt = i->ringt_base;
11777 /* Fall through */
11778 case SIG_EMWINK:
11779 case SIG_FEATD:
11780 case SIG_FEATDMF:
11781 case SIG_FEATDMF_TA:
11782 case SIG_E911:
11783 case SIG_FGC_CAMA:
11784 case SIG_FGC_CAMAMF:
11785 case SIG_FEATB:
11786 case SIG_EM:
11787 case SIG_EM_E1:
11788 case SIG_SFWINK:
11789 case SIG_SF_FEATD:
11790 case SIG_SF_FEATDMF:
11791 case SIG_SF_FEATB:
11792 case SIG_SF:
11793 /* Check for callerid, digits, etc */
11794 callid_created = ast_callid_threadstorage_auto(&callid);
11795 if (i->cid_start == CID_START_POLARITY_IN) {
11796 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11797 } else {
11798 chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid);
11799 }
11800
11801 if (!chan) {
11802 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11803 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11804 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11805 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11806 if (res < 0) {
11807 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11808 }
11809 ast_hangup(chan);
11810 }
11811
11813 break;
11814 default:
11815 ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11816 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11817 if (res < 0)
11818 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11819 return NULL;
11820 }
11821 break;
11822 case DAHDI_EVENT_NOALARM:
11823 switch (i->sig) {
11824#if defined(HAVE_PRI)
11826 ast_mutex_lock(&i->lock);
11829 break;
11830#endif /* defined(HAVE_PRI) */
11831#if defined(HAVE_SS7)
11832 case SIG_SS7:
11834 break;
11835#endif /* defined(HAVE_SS7) */
11836 default:
11837 i->inalarm = 0;
11838 break;
11839 }
11841 break;
11842 case DAHDI_EVENT_ALARM:
11843 switch (i->sig) {
11844#if defined(HAVE_PRI)
11846 ast_mutex_lock(&i->lock);
11849 break;
11850#endif /* defined(HAVE_PRI) */
11851#if defined(HAVE_SS7)
11852 case SIG_SS7:
11854 break;
11855#endif /* defined(HAVE_SS7) */
11856 default:
11857 i->inalarm = 1;
11858 break;
11859 }
11860 res = get_alarms(i);
11861 handle_alarms(i, res);
11862 /* fall thru intentionally */
11863 case DAHDI_EVENT_ONHOOK:
11864 if (i->radio)
11865 break;
11866 /* Back on hook. Hang up. */
11867 switch (i->sig) {
11868 case SIG_FXOLS:
11869 case SIG_FXOGS:
11870 case SIG_FEATD:
11871 case SIG_FEATDMF:
11872 case SIG_FEATDMF_TA:
11873 case SIG_E911:
11874 case SIG_FGC_CAMA:
11875 case SIG_FGC_CAMAMF:
11876 case SIG_FEATB:
11877 case SIG_EM:
11878 case SIG_EM_E1:
11879 case SIG_EMWINK:
11880 case SIG_SF_FEATD:
11881 case SIG_SF_FEATDMF:
11882 case SIG_SF_FEATB:
11883 case SIG_SF:
11884 case SIG_SFWINK:
11885 case SIG_FXSLS:
11886 case SIG_FXSGS:
11887 case SIG_FXSKS:
11888 case SIG_FXOKS:
11890 /* Diddle the battery for the zhone */
11891#ifdef ZHONE_HACK
11892 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11893 usleep(1);
11894#endif
11895 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11896 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
11897 break;
11898 case SIG_SS7:
11901 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11902 break;
11903 default:
11904 ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11905 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11906 return NULL;
11907 }
11908 break;
11909 case DAHDI_EVENT_POLARITY:
11910 switch (i->sig) {
11911 case SIG_FXSLS:
11912 case SIG_FXSKS:
11913 case SIG_FXSGS:
11914 /* We have already got a PR before the channel was
11915 created, but it wasn't handled. We need polarity
11916 to be REV for remote hangup detection to work.
11917 At least in Spain */
11918 callid_created = ast_callid_threadstorage_auto(&callid);
11923 ast_verb(2, "Starting post polarity "
11924 "CID detection on channel %d\n",
11925 i->channel);
11926 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11927 if (!chan) {
11928 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11929 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11930 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11931 ast_hangup(chan);
11932 }
11933 }
11935 break;
11936 default:
11937 ast_log(LOG_WARNING, "handle_init_event detected "
11938 "polarity reversal on non-FXO (SIG_FXS) "
11939 "interface %d\n", i->channel);
11940 }
11941 break;
11942 case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
11944 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11945 i->channel);
11946 return i;
11947 case DAHDI_EVENT_NEONMWI_ACTIVE:
11948 if (i->mwimonitor_neon) {
11949 notify_message(i->mailbox, 1);
11950 ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
11951 }
11952 break;
11953 case DAHDI_EVENT_NEONMWI_INACTIVE:
11954 if (i->mwimonitor_neon) {
11955 notify_message(i->mailbox, 0);
11956 ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
11957 }
11958 break;
11959 }
11960 return NULL;
11961}
11962
11963static void monitor_pfds_clean(void *arg) {
11964 struct pollfd **pfds = arg;
11965 ast_free(*pfds);
11966}
11967
11968static void *do_monitor(void *data)
11969{
11970 int count, res, res2, spoint, pollres=0;
11971 struct dahdi_pvt *i;
11972 struct dahdi_pvt *last = NULL;
11973 struct dahdi_pvt *doomed;
11974 time_t thispass = 0, lastpass = 0;
11975 int found;
11976 char buf[1024];
11977 struct pollfd *pfds=NULL;
11978 int lastalloc = -1;
11979 /* This thread monitors all the frame relay interfaces which are not yet in use
11980 (and thus do not have a separate thread) indefinitely */
11981 /* From here on out, we die whenever asked */
11982#if 0
11983 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
11984 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
11985 return NULL;
11986 }
11987 ast_debug(1, "Monitor starting...\n");
11988#endif
11989 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11990
11991 pthread_cleanup_push(monitor_pfds_clean, &pfds);
11992 for (;;) {
11993 /* Lock the interface list */
11995 if (!pfds || (lastalloc != ifcount)) {
11996 if (pfds) {
11997 ast_free(pfds);
11998 pfds = NULL;
11999 }
12000 if (ifcount) {
12001 if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
12003 return NULL;
12004 }
12005 }
12006 lastalloc = ifcount;
12007 }
12008 /* Build the stuff we're going to poll on, that is the socket of every
12009 dahdi_pvt that does not have an associated owner channel */
12010 count = 0;
12011 for (i = iflist; i; i = i->next) {
12012 ast_mutex_lock(&i->lock);
12013 if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
12014 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12015 struct analog_pvt *p = i->sig_pvt;
12016
12017 if (!p) {
12018 ast_log(LOG_ERROR, "No sig_pvt?\n");
12019 } else if (!p->owner && !p->subs[SUB_REAL].owner) {
12020 /* This needs to be watched, as it lacks an owner */
12021 pfds[count].fd = i->subs[SUB_REAL].dfd;
12022 pfds[count].events = POLLPRI;
12023 pfds[count].revents = 0;
12024 /* Message waiting or r2 channels also get watched for reading */
12025 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12026 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12027 pfds[count].events |= POLLIN;
12028 }
12029 count++;
12030 }
12031 } else {
12032 if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
12033 /* This needs to be watched, as it lacks an owner */
12034 pfds[count].fd = i->subs[SUB_REAL].dfd;
12035 pfds[count].events = POLLPRI;
12036 pfds[count].revents = 0;
12037 /* If we are monitoring for VMWI or sending CID, we need to
12038 read from the channel as well */
12039 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12040 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12041 pfds[count].events |= POLLIN;
12042 }
12043 count++;
12044 }
12045 }
12046 }
12048 }
12049 /* Okay, now that we know what to do, release the interface lock */
12051
12052 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
12053 pthread_testcancel();
12054 /* Wait at least a second for something to happen */
12055 res = poll(pfds, count, 1000);
12056 pthread_testcancel();
12057 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
12058
12059 /* Okay, poll has finished. Let's see what happened. */
12060 if (res < 0) {
12061 if ((errno != EAGAIN) && (errno != EINTR))
12062 ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
12063 continue;
12064 }
12065 /* Alright, lock the interface list again, and let's look and see what has
12066 happened */
12068 found = 0;
12069 spoint = 0;
12070 lastpass = thispass;
12071 thispass = time(NULL);
12072 doomed = NULL;
12073 for (i = iflist;; i = i->next) {
12074 if (doomed) {
12076 doomed = NULL;
12077 }
12078 if (!i) {
12079 break;
12080 }
12081
12082 if (thispass != lastpass) {
12083 if (!found && ((i == last) || ((i == iflist) && !last))) {
12084 last = i;
12085 if (last) {
12086 struct analog_pvt *analog_p = last->sig_pvt;
12087 /* Only allow MWI to be initiated on a quiescent fxs port */
12088 if (analog_p
12089 && !last->mwisendactive
12090 && (last->sig & __DAHDI_SIG_FXO)
12091 && !analog_p->fxsoffhookstate
12092 && !last->owner
12093 && (!ast_strlen_zero(last->mailbox) || last->mwioverride_active)
12094 && !analog_p->subs[SUB_REAL].owner /* could be a recall ring from a flash hook hold */
12095 && (thispass - analog_p->onhooktime > 3)
12096 /* In some cases, all of the above checks will pass even if the line is really off-hook.
12097 * This last check will give the right answer 100% of the time, but is relatively
12098 * "expensive" (it requires an ioctl), so it is last to avoid unnecessary system calls. */
12099 && !my_is_off_hook(last)) {
12100 res = has_voicemail(last);
12101 if (analog_p->msgstate != res) {
12102 /* Set driver resources for signalling VMWI */
12103 res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
12104 if (res2) {
12105 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
12106 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
12107 }
12108 /* If enabled for FSK spill then initiate it */
12109 ast_debug(5, "Initiating MWI FSK spill on channel %d\n", last->channel);
12110 if (mwi_send_init(last)) {
12111 ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
12112 }
12113 analog_p->msgstate = res;
12114 found ++;
12115 }
12116 }
12117 last = last->next;
12118 }
12119 }
12120 }
12121 if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
12122 if (i->radio && !i->owner)
12123 {
12124 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12125 if (res)
12126 {
12127 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
12128 /* Don't hold iflock while handling init events */
12130 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12132 else
12133 doomed = handle_init_event(i, res);
12135 }
12136 continue;
12137 }
12138 pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
12139 if (pollres & POLLIN) {
12140 if (i->owner || i->subs[SUB_REAL].owner) {
12141#ifdef HAVE_PRI
12142 if (!i->pri)
12143#endif
12144 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
12145 continue;
12146 }
12148 ast_log(LOG_WARNING, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
12149 continue;
12150 }
12151 res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
12152 if (res > 0) {
12153 if (i->mwimonitor_fsk) {
12154 if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
12155 pthread_attr_t attr;
12156 pthread_t threadid;
12157 struct mwi_thread_data *mtd;
12158
12159 pthread_attr_init(&attr);
12160 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
12161
12162 ast_debug(1, "Maybe some MWI on port %d!\n", i->channel);
12163 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
12164 mtd->pvt = i;
12165 memcpy(mtd->buf, buf, res);
12166 mtd->len = res;
12167 i->mwimonitoractive = 1;
12168 if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
12169 ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
12170 i->mwimonitoractive = 0;
12171 ast_free(mtd);
12172 }
12173 }
12174 }
12175 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
12176 } else if (i->cid_start == CID_START_DTMF_NOALERT) {
12177 int energy;
12178 struct timeval now;
12179 /* State machine dtmfcid_holdoff_state allows for the line to settle
12180 * before checking again for dtmf energy. Presently waits for 500 mS before checking again
12181 */
12182 if (1 == i->dtmfcid_holdoff_state) {
12183 gettimeofday(&i->dtmfcid_delay, NULL);
12184 i->dtmfcid_holdoff_state = 2;
12185 } else if (2 == i->dtmfcid_holdoff_state) {
12186 gettimeofday(&now, NULL);
12187 if ((int)(now.tv_sec - i->dtmfcid_delay.tv_sec) * 1000000 + (int)now.tv_usec - (int)i->dtmfcid_delay.tv_usec > 500000) {
12188 i->dtmfcid_holdoff_state = 0;
12189 }
12190 } else {
12191 energy = calc_energy((unsigned char *) buf, res, AST_LAW(i));
12192 if (!i->mwisendactive && energy > dtmfcid_level) {
12193 pthread_t threadid;
12194 struct ast_channel *chan;
12196 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12197 /* just in case this event changes or somehow destroys a channel, set doomed here too */
12199 i->dtmfcid_holdoff_state = 1;
12200 } else {
12201 ast_callid callid = 0;
12202 int callid_created = ast_callid_threadstorage_auto(&callid);
12203 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
12204 if (!chan) {
12205 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
12206 } else {
12207 res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
12208 if (res) {
12209 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
12210 ast_hangup(chan);
12211 } else {
12212 i->dtmfcid_holdoff_state = 1;
12213 }
12214 }
12216 }
12218 }
12219 }
12220 }
12221 if (i->mwisendactive) {
12223 }
12224 } else {
12225 ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
12226 }
12227 }
12228 if (pollres & POLLPRI) {
12229 if (i->owner || i->subs[SUB_REAL].owner) {
12230#ifdef HAVE_PRI
12231 if (!i->pri)
12232#endif
12233 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
12234 continue;
12235 }
12236 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12237 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
12238 /* Don't hold iflock while handling init events */
12240 if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
12241 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12243 else
12244 doomed = handle_init_event(i, res);
12245 }
12246 if (i->doreoriginate && res == DAHDI_EVENT_HOOKCOMPLETE) {
12247 /* Actually automatically reoriginate this FXS line, if directed to.
12248 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12249 * doing its thing (one reason why this is for FXOKS only: FXOLS
12250 * hangups don't give us any DAHDI events to piggyback off of)*/
12251 i->doreoriginate = 0;
12252 /* Double check the channel is still off-hook. There's only about a millisecond
12253 * between when doreoriginate is set high and we see that here, but just to be safe. */
12254 if (!my_is_off_hook(i)) {
12255 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i->channel);
12256 } else {
12257 ast_verb(3, "Automatic reorigination on channel %d\n", i->channel);
12258 res = DAHDI_EVENT_RINGOFFHOOK; /* Pretend that the physical channel just went off hook */
12259 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12261 } else {
12262 doomed = handle_init_event(i, res);
12263 }
12264 }
12265 }
12267 }
12268 }
12269 }
12272#ifdef HAVE_OPENR2
12273 dahdi_r2_destroy_nodev();
12274#endif
12275 }
12276 /* Never reached */
12277 pthread_cleanup_pop(1);
12278 return NULL;
12279
12280}
12281
12282static int restart_monitor(void)
12283{
12284 /* If we're supposed to be stopped -- stay stopped */
12286 return 0;
12288 if (monitor_thread == pthread_self()) {
12290 ast_log(LOG_WARNING, "Cannot kill myself\n");
12291 return -1;
12292 }
12294 /* Wake up the thread */
12295 pthread_kill(monitor_thread, SIGURG);
12296 } else {
12297 /* Start a new monitor */
12300 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
12301 return -1;
12302 }
12303 }
12305 return 0;
12306}
12307
12308#if defined(HAVE_PRI)
12309static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
12310{
12311 int x;
12312 int trunkgroup;
12313 /* Get appropriate trunk group if there is one */
12314 trunkgroup = pris[*span].mastertrunkgroup;
12315 if (trunkgroup) {
12316 /* Select a specific trunk group */
12317 for (x = 0; x < NUM_SPANS; x++) {
12318 if (pris[x].pri.trunkgroup == trunkgroup) {
12319 *span = x;
12320 return 0;
12321 }
12322 }
12323 ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
12324 *span = -1;
12325 } else {
12326 if (pris[*span].pri.trunkgroup) {
12327 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);
12328 *span = -1;
12329 } else if (pris[*span].mastertrunkgroup) {
12330 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
12331 *span = -1;
12332 } else {
12333 if (si->totalchans == 31) {
12334 /* E1 */
12335 pris[*span].dchannels[0] = 16 + offset;
12336 } else if (si->totalchans == 24) {
12337 /* T1 or J1 */
12338 pris[*span].dchannels[0] = 24 + offset;
12339 } else if (si->totalchans == 3) {
12340 /* BRI */
12341 pris[*span].dchannels[0] = 3 + offset;
12342 } else {
12343 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);
12344 *span = -1;
12345 return 0;
12346 }
12347 pris[*span].pri.span = *span + 1;
12348 }
12349 }
12350 return 0;
12351}
12352#endif /* defined(HAVE_PRI) */
12353
12354#if defined(HAVE_PRI)
12355static int pri_create_trunkgroup(int trunkgroup, int *channels)
12356{
12357 struct dahdi_spaninfo si;
12358 struct dahdi_params p;
12359 int fd;
12360 int span;
12361 int ospan=0;
12362 int x,y;
12363 for (x = 0; x < NUM_SPANS; x++) {
12364 if (pris[x].pri.trunkgroup == trunkgroup) {
12365 ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
12366 return -1;
12367 }
12368 }
12369 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12370 if (!channels[y])
12371 break;
12372 memset(&si, 0, sizeof(si));
12373 memset(&p, 0, sizeof(p));
12374 fd = open("/dev/dahdi/channel", O_RDWR);
12375 if (fd < 0) {
12376 ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
12377 return -1;
12378 }
12379 x = channels[y];
12380 if (ioctl(fd, DAHDI_SPECIFY, &x)) {
12381 ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
12382 close(fd);
12383 return -1;
12384 }
12385 if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
12386 ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
12387 close(fd);
12388 return -1;
12389 }
12390 if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
12391 ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
12392 close(fd);
12393 return -1;
12394 }
12395 span = p.spanno - 1;
12396 if (pris[span].pri.trunkgroup) {
12397 ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].pri.trunkgroup);
12398 close(fd);
12399 return -1;
12400 }
12401 if (pris[span].pri.pvts[0]) {
12402 ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
12403 close(fd);
12404 return -1;
12405 }
12406 if (!y) {
12407 pris[span].pri.trunkgroup = trunkgroup;
12408 ospan = span;
12409 }
12410 pris[ospan].dchannels[y] = channels[y];
12411 pris[span].pri.span = span + 1;
12412 close(fd);
12413 }
12414 return 0;
12415}
12416#endif /* defined(HAVE_PRI) */
12417
12418#if defined(HAVE_PRI)
12419static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
12420{
12421 if (pris[span].mastertrunkgroup) {
12422 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);
12423 return -1;
12424 }
12425 pris[span].mastertrunkgroup = trunkgroup;
12426 pris[span].prilogicalspan = logicalspan;
12427 return 0;
12428}
12429#endif /* defined(HAVE_PRI) */
12430
12431#if defined(HAVE_SS7)
12432static unsigned int parse_pointcode(const char *pcstring)
12433{
12434 unsigned int code1, code2, code3;
12435 int numvals;
12436
12437 numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
12438 if (numvals == 1)
12439 return code1;
12440 if (numvals == 3)
12441 return (code1 << 16) | (code2 << 8) | code3;
12442
12443 return 0;
12444}
12445#endif /* defined(HAVE_SS7) */
12446
12447#if defined(HAVE_SS7)
12448static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
12449{
12450 if ((linkset < 0) || (linkset >= NUM_SPANS))
12451 return NULL;
12452 else
12453 return &linksets[linkset - 1];
12454}
12455#endif /* defined(HAVE_SS7) */
12456
12457#ifdef HAVE_OPENR2
12458static void dahdi_r2_destroy_links(void)
12459{
12460 struct r2link_entry *cur;
12461
12462 /* Queue everything for removal */
12463 AST_LIST_LOCK(&r2links);
12464 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
12465 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
12466 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
12467 }
12469 AST_LIST_UNLOCK(&r2links);
12470 /* Now destroy properly */
12471 dahdi_r2_destroy_nodev();
12472}
12473
12474/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12475#define R2_LINK_CAPACITY 30
12476static struct r2link_entry *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
12477{
12478 struct r2link_entry *cur = NULL;
12479 /* Only create a new R2 link if
12480 1. This is the first link requested
12481 2. Configuration changed
12482 3. We got more channels than supported per link */
12483 AST_LIST_LOCK(&r2links);
12484 if (! AST_LIST_EMPTY(&r2links)) {
12485 cur = AST_LIST_LAST(&r2links);
12486 if (memcmp(&conf->mfcr2, &cur->mfcr2.conf, sizeof(conf->mfcr2))) {
12487 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12488 cur = NULL;
12489 } else if (cur->mfcr2.numchans == R2_LINK_CAPACITY) {
12490 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY);
12491 cur = NULL;
12492 }
12493 }
12494 if (!cur) {
12495 struct r2link_entry *tmp = NULL;
12496 int new_idx = r2links_count + 1;
12497 int i;
12498 for (i = 1; i <= r2links_count; i++) {
12499 int i_unused = 1;
12500 AST_LIST_TRAVERSE(&r2links, tmp, list) {
12501 if (i == tmp->mfcr2.index) {
12502 i_unused = 0;
12503 break;
12504 }
12505 }
12506 if (i_unused) {
12507 new_idx = i;
12508 break;
12509 }
12510 }
12511 cur = ast_calloc(1, sizeof(*cur));
12512 if (!cur) {
12513 ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
12514 return NULL;
12515 }
12516 cur->mfcr2.index = new_idx;
12517 cur->mfcr2.r2master = AST_PTHREADT_NULL;
12518 r2links_count++;
12519 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx, r2links_count);
12520 AST_LIST_INSERT_TAIL(&r2links, cur, list);
12521 }
12522 AST_LIST_UNLOCK(&r2links);
12523 return cur;
12524}
12525
12526static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_chan_conf *conf)
12527{
12528 char tmplogdir[] = "/tmp";
12529 char logdir[OR2_MAX_PATH];
12530 int threshold = 0;
12531 int snres = 0;
12532 r2_link->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
12533 &dahdi_r2_transcode_iface, conf->mfcr2.variant, conf->mfcr2.max_ani,
12534 conf->mfcr2.max_dnis);
12535 if (!r2_link->protocol_context) {
12536 return -1;
12537 }
12538 openr2_context_set_log_level(r2_link->protocol_context, conf->mfcr2.loglevel);
12539 openr2_context_set_ani_first(r2_link->protocol_context, conf->mfcr2.get_ani_first);
12540#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12541 openr2_context_set_skip_category_request(r2_link->protocol_context, conf->mfcr2.skip_category_request);
12542#endif
12543 openr2_context_set_mf_threshold(r2_link->protocol_context, threshold);
12544 openr2_context_set_mf_back_timeout(r2_link->protocol_context, conf->mfcr2.mfback_timeout);
12545 openr2_context_set_metering_pulse_timeout(r2_link->protocol_context, conf->mfcr2.metering_pulse_timeout);
12546 openr2_context_set_double_answer(r2_link->protocol_context, conf->mfcr2.double_answer);
12547 openr2_context_set_immediate_accept(r2_link->protocol_context, conf->mfcr2.immediate_accept);
12548#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12549 openr2_context_set_dtmf_dialing(r2_link->protocol_context, conf->mfcr2.dtmf_dialing, conf->mfcr2.dtmf_time_on, conf->mfcr2.dtmf_time_off);
12550 openr2_context_set_dtmf_detection(r2_link->protocol_context, conf->mfcr2.dtmf_detection);
12551#endif
12552#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12553 openr2_context_set_dtmf_detection_end_timeout(r2_link->protocol_context, conf->mfcr2.dtmf_end_timeout);
12554#endif
12555 if (ast_strlen_zero(conf->mfcr2.logdir)) {
12556 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12557 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12558 }
12559 } else {
12560 snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", conf->mfcr2.logdir);
12561 if (snres >= sizeof(logdir)) {
12562 ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
12563 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12564 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12565 }
12566 } else {
12567 if (openr2_context_set_log_directory(r2_link->protocol_context, logdir)) {
12568 ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
12569 }
12570 }
12571 }
12572 if (!ast_strlen_zero(conf->mfcr2.r2proto_file)) {
12573 if (openr2_context_configure_from_advanced_file(r2_link->protocol_context, conf->mfcr2.r2proto_file)) {
12574 ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", conf->mfcr2.r2proto_file);
12575 }
12576 }
12577 /* Save the configuration used to setup this link */
12578 memcpy(&r2_link->conf, &conf->mfcr2, sizeof(r2_link->conf));
12579 return 0;
12580}
12581#endif
12582
12583/* converts a DAHDI sigtype to signalling as can be configured from
12584 * chan_dahdi.conf.
12585 * While both have basically the same values, this will later be the
12586 * place to add filters and sanity checks
12587 */
12589{
12590 return sigtype;
12591}
12592
12593/*!
12594 * \internal
12595 * \brief Initialize/create a channel interface.
12596 *
12597 * \param channel Channel interface number to initialize/create.
12598 * \param conf Configuration parameters to initialize interface with.
12599 * \param reloading What we are doing now:
12600 * 0 - initial module load,
12601 * 1 - module reload,
12602 * 2 - module restart
12603 *
12604 * \retval Interface-pointer initialized/created
12605 * \retval NULL if error
12606 */
12607static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
12608{
12609 /* Make a dahdi_pvt structure for this interface */
12610 struct dahdi_pvt *tmp;/*!< Current channel structure initializing */
12611 char fn[80];
12612 struct dahdi_bufferinfo bi;
12613
12614 int res;
12615#if defined(HAVE_PRI)
12616 int span = 0;
12617#endif /* defined(HAVE_PRI) */
12618 int here = 0;/*!< TRUE if the channel interface already exists. */
12619 int x;
12620 struct analog_pvt *analog_p = NULL;
12621 struct dahdi_params p;
12622#if defined(HAVE_PRI)
12623 struct dahdi_spaninfo si;
12624 struct sig_pri_chan *pri_chan = NULL;
12625#endif /* defined(HAVE_PRI) */
12626#if defined(HAVE_SS7)
12627 struct sig_ss7_chan *ss7_chan = NULL;
12628#endif /* defined(HAVE_SS7) */
12629
12630 /* Search channel interface list to see if it already exists. */
12631 for (tmp = iflist; tmp; tmp = tmp->next) {
12632 if (!tmp->destroy) {
12633 if (tmp->channel == channel) {
12634 /* The channel interface already exists. */
12635 here = 1;
12636 break;
12637 }
12638 if (tmp->channel > channel) {
12639 /* No way it can be in the sorted list. */
12640 tmp = NULL;
12641 break;
12642 }
12643 }
12644 }
12645
12646 if (!here && reloading != 1) {
12647 tmp = ast_calloc(1, sizeof(*tmp));
12648 if (!tmp) {
12649 return NULL;
12650 }
12652 if (!tmp->cc_params) {
12653 ast_free(tmp);
12654 return NULL;
12655 }
12656 ast_mutex_init(&tmp->lock);
12657 ifcount++;
12658 for (x = 0; x < 3; x++)
12659 tmp->subs[x].dfd = -1;
12660 tmp->channel = channel;
12661 tmp->priindication_oob = conf->chan.priindication_oob;
12662 }
12663
12664 if (tmp) {
12665 int chan_sig = conf->chan.sig;
12666
12667 /* If there are variables in tmp before it is updated to match the new config, clear them */
12668 if (reloading && tmp->vars) {
12670 tmp->vars = NULL;
12671 }
12672
12673 if (!here) {
12674 /* Can only get here if this is a new channel interface being created. */
12675 if ((channel != CHAN_PSEUDO)) {
12676 int count = 0;
12677
12678 snprintf(fn, sizeof(fn), "%d", channel);
12679 /* Open non-blocking */
12680 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12681 /* Retry open on restarts, but don't keep retrying if the channel doesn't exist (e.g. not configured) */
12682 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 */
12683 usleep(1);
12684 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12685 count++;
12686 }
12687 /* Allocate a DAHDI structure */
12688 if (tmp->subs[SUB_REAL].dfd < 0) {
12689 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);
12690 destroy_dahdi_pvt(tmp);
12691 return NULL;
12692 }
12693 memset(&p, 0, sizeof(p));
12694 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
12695 if (res < 0) {
12696 ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
12697 destroy_dahdi_pvt(tmp);
12698 return NULL;
12699 }
12700 if (conf->is_sig_auto)
12701 chan_sig = sigtype_to_signalling(p.sigtype);
12702 if (p.sigtype != (chan_sig & 0x3ffff)) {
12703 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));
12704 destroy_dahdi_pvt(tmp);
12705 return NULL;
12706 }
12707 tmp->law_default = p.curlaw;
12708 tmp->law = p.curlaw;
12709 tmp->span = p.spanno;
12710#if defined(HAVE_PRI)
12711 span = p.spanno - 1;
12712#endif /* defined(HAVE_PRI) */
12713 } else {
12714 chan_sig = 0;
12715 }
12716 tmp->sig = chan_sig;
12717 tmp->outsigmod = conf->chan.outsigmod;
12718
12719 if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
12720 analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
12721 if (!analog_p) {
12722 destroy_dahdi_pvt(tmp);
12723 return NULL;
12724 }
12725 tmp->sig_pvt = analog_p;
12726 }
12727#if defined(HAVE_SS7)
12728 if (chan_sig == SIG_SS7) {
12729 struct dahdi_ss7 *ss7;
12730 int clear = 0;
12731
12732 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
12733 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12734 destroy_dahdi_pvt(tmp);
12735 return NULL;
12736 }
12737
12738 ss7 = ss7_resolve_linkset(cur_linkset);
12739 if (!ss7) {
12740 ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
12741 destroy_dahdi_pvt(tmp);
12742 return NULL;
12743 }
12744 ss7->ss7.span = cur_linkset;
12745 if (cur_cicbeginswith < 0) {
12746 ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
12747 destroy_dahdi_pvt(tmp);
12748 return NULL;
12749 }
12750 ss7_chan = sig_ss7_chan_new(tmp, &ss7->ss7);
12751 if (!ss7_chan) {
12752 destroy_dahdi_pvt(tmp);
12753 return NULL;
12754 }
12755 tmp->sig_pvt = ss7_chan;
12756 tmp->ss7 = &ss7->ss7;
12757
12758 ss7_chan->channel = tmp->channel;
12759 ss7_chan->cic = cur_cicbeginswith++;
12760
12761 /* DB: Add CIC's DPC information */
12762 ss7_chan->dpc = cur_defaultdpc;
12763
12764 ss7->ss7.pvts[ss7->ss7.numchans++] = ss7_chan;
12765
12766 ast_copy_string(ss7->ss7.internationalprefix, conf->ss7.ss7.internationalprefix, sizeof(ss7->ss7.internationalprefix));
12767 ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
12768 ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
12769 ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
12770 ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
12771
12772 ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
12773 ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
12774 }
12775#endif /* defined(HAVE_SS7) */
12776#ifdef HAVE_OPENR2
12777 if (chan_sig == SIG_MFCR2) {
12778 struct dahdi_mfcr2 *r2_link;
12779 struct r2link_entry *r2_le = dahdi_r2_get_link(conf);
12780 r2_link = &r2_le->mfcr2;
12781 if (!r2_link) {
12782 ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
12783 destroy_dahdi_pvt(tmp);
12784 return NULL;
12785 }
12786 if (!r2_link->protocol_context && dahdi_r2_set_context(r2_link, conf)) {
12787 ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
12788 destroy_dahdi_pvt(tmp);
12789 return NULL;
12790 }
12791 if (r2_link->numchans == ARRAY_LEN(r2_link->pvts)) {
12792 ast_log(LOG_ERROR, "Cannot add more channels to this link!\n");
12793 destroy_dahdi_pvt(tmp);
12794 return NULL;
12795 }
12796 r2_link->pvts[r2_link->numchans++] = tmp;
12797 tmp->r2chan = openr2_chan_new_from_fd(r2_link->protocol_context,
12798 tmp->subs[SUB_REAL].dfd,
12799 NULL, NULL);
12800 if (!tmp->r2chan) {
12801 openr2_liberr_t err = openr2_context_get_last_error(r2_link->protocol_context);
12802 ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
12803 destroy_dahdi_pvt(tmp);
12804 return NULL;
12805 }
12806 r2_link->live_chans++;
12807 tmp->mfcr2 = r2_link;
12808 if (conf->mfcr2.call_files) {
12809 openr2_chan_enable_call_files(tmp->r2chan);
12810 }
12811 openr2_chan_set_client_data(tmp->r2chan, tmp);
12812 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12813 openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
12814 openr2_chan_set_log_level(tmp->r2chan, conf->mfcr2.loglevel);
12815 tmp->mfcr2_category = conf->mfcr2.category;
12816 tmp->mfcr2_charge_calls = conf->mfcr2.charge_calls;
12817 tmp->mfcr2_allow_collect_calls = conf->mfcr2.allow_collect_calls;
12818 tmp->mfcr2_forced_release = conf->mfcr2.forced_release;
12819 tmp->mfcr2_accept_on_offer = conf->mfcr2.accept_on_offer;
12820 tmp->mfcr2call = 0;
12821 tmp->mfcr2_dnis_index = 0;
12822 tmp->mfcr2_ani_index = 0;
12823 }
12824#endif
12825#ifdef HAVE_PRI
12826 if (dahdi_sig_pri_lib_handles(chan_sig)) {
12827 int offset;
12828 int matchesdchan;
12829 int x,y;
12830 int myswitchtype = 0;
12831
12832 offset = 0;
12833 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
12834 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12835 destroy_dahdi_pvt(tmp);
12836 return NULL;
12837 }
12838 if (span >= NUM_SPANS) {
12839 ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
12840 destroy_dahdi_pvt(tmp);
12841 return NULL;
12842 } else {
12843 si.spanno = 0;
12844 if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
12845 ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
12846 destroy_dahdi_pvt(tmp);
12847 return NULL;
12848 }
12849 /* Store the logical span first based upon the real span */
12850 tmp->logicalspan = pris[span].prilogicalspan;
12851 pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
12852 if (span < 0) {
12853 ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
12854 destroy_dahdi_pvt(tmp);
12855 return NULL;
12856 }
12857 myswitchtype = conf->pri.pri.switchtype;
12858 /* Make sure this isn't a d-channel */
12859 matchesdchan=0;
12860 for (x = 0; x < NUM_SPANS; x++) {
12861 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12862 if (pris[x].dchannels[y] == tmp->channel) {
12863 matchesdchan = 1;
12864 break;
12865 }
12866 }
12867 }
12868 if (!matchesdchan) {
12869 if (pris[span].pri.nodetype && (pris[span].pri.nodetype != conf->pri.pri.nodetype)) {
12870 ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].pri.nodetype));
12871 destroy_dahdi_pvt(tmp);
12872 return NULL;
12873 }
12874 if (pris[span].pri.switchtype && (pris[span].pri.switchtype != myswitchtype)) {
12875 ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].pri.switchtype));
12876 destroy_dahdi_pvt(tmp);
12877 return NULL;
12878 }
12879 if ((pris[span].pri.dialplan) && (pris[span].pri.dialplan != conf->pri.pri.dialplan)) {
12880 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));
12881 destroy_dahdi_pvt(tmp);
12882 return NULL;
12883 }
12884 if (!ast_strlen_zero(pris[span].pri.idledial) && strcmp(pris[span].pri.idledial, conf->pri.pri.idledial)) {
12885 ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.pri.idledial);
12886 destroy_dahdi_pvt(tmp);
12887 return NULL;
12888 }
12889 if (!ast_strlen_zero(pris[span].pri.idleext) && strcmp(pris[span].pri.idleext, conf->pri.pri.idleext)) {
12890 ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.pri.idleext);
12891 destroy_dahdi_pvt(tmp);
12892 return NULL;
12893 }
12894 if (pris[span].pri.minunused && (pris[span].pri.minunused != conf->pri.pri.minunused)) {
12895 ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.pri.minunused);
12896 destroy_dahdi_pvt(tmp);
12897 return NULL;
12898 }
12899 if (pris[span].pri.minidle && (pris[span].pri.minidle != conf->pri.pri.minidle)) {
12900 ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.pri.minidle);
12901 destroy_dahdi_pvt(tmp);
12902 return NULL;
12903 }
12904 if (pris[span].pri.numchans >= ARRAY_LEN(pris[span].pri.pvts)) {
12905 ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
12906 pris[span].pri.trunkgroup);
12907 destroy_dahdi_pvt(tmp);
12908 return NULL;
12909 }
12910
12911 pri_chan = sig_pri_chan_new(tmp, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
12912 if (!pri_chan) {
12913 destroy_dahdi_pvt(tmp);
12914 return NULL;
12915 }
12916 tmp->sig_pvt = pri_chan;
12917 tmp->pri = &pris[span].pri;
12918
12919 tmp->priexclusive = conf->chan.priexclusive;
12920
12921 if (!tmp->pri->cc_params) {
12923 if (!tmp->pri->cc_params) {
12924 destroy_dahdi_pvt(tmp);
12925 return NULL;
12926 }
12927 }
12929 conf->chan.cc_params);
12930
12931 pris[span].pri.sig = chan_sig;
12932 pris[span].pri.nodetype = conf->pri.pri.nodetype;
12933 pris[span].pri.switchtype = myswitchtype;
12934 pris[span].pri.nsf = conf->pri.pri.nsf;
12935 pris[span].pri.dialplan = conf->pri.pri.dialplan;
12936 pris[span].pri.localdialplan = conf->pri.pri.localdialplan;
12937 pris[span].pri.cpndialplan = conf->pri.pri.cpndialplan;
12938 pris[span].pri.pvts[pris[span].pri.numchans++] = tmp->sig_pvt;
12939 pris[span].pri.minunused = conf->pri.pri.minunused;
12940 pris[span].pri.minidle = conf->pri.pri.minidle;
12941 pris[span].pri.overlapdial = conf->pri.pri.overlapdial;
12942 pris[span].pri.qsigchannelmapping = conf->pri.pri.qsigchannelmapping;
12943 pris[span].pri.discardremoteholdretrieval = conf->pri.pri.discardremoteholdretrieval;
12944#if defined(HAVE_PRI_SERVICE_MESSAGES)
12945 pris[span].pri.enable_service_message_support = conf->pri.pri.enable_service_message_support;
12946#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12947#ifdef HAVE_PRI_INBANDDISCONNECT
12948 pris[span].pri.inbanddisconnect = conf->pri.pri.inbanddisconnect;
12949#endif
12950#if defined(HAVE_PRI_CALL_HOLD)
12951 pris[span].pri.hold_disconnect_transfer =
12952 conf->pri.pri.hold_disconnect_transfer;
12953#endif /* defined(HAVE_PRI_CALL_HOLD) */
12954#if defined(HAVE_PRI_CCSS)
12955 pris[span].pri.cc_ptmp_recall_mode =
12956 conf->pri.pri.cc_ptmp_recall_mode;
12957 pris[span].pri.cc_qsig_signaling_link_req =
12958 conf->pri.pri.cc_qsig_signaling_link_req;
12959 pris[span].pri.cc_qsig_signaling_link_rsp =
12960 conf->pri.pri.cc_qsig_signaling_link_rsp;
12961#endif /* defined(HAVE_PRI_CCSS) */
12962#if defined(HAVE_PRI_CALL_WAITING)
12963 pris[span].pri.max_call_waiting_calls =
12964 conf->pri.pri.max_call_waiting_calls;
12965 pris[span].pri.allow_call_waiting_calls =
12966 conf->pri.pri.allow_call_waiting_calls;
12967#endif /* defined(HAVE_PRI_CALL_WAITING) */
12968 pris[span].pri.transfer = conf->chan.transfer;
12969 pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
12970#if defined(HAVE_PRI_L2_PERSISTENCE)
12971 pris[span].pri.l2_persistence = conf->pri.pri.l2_persistence;
12972#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12973 pris[span].pri.colp_send = conf->pri.pri.colp_send;
12974#if defined(HAVE_PRI_AOC_EVENTS)
12975 pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
12976 pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
12977#endif /* defined(HAVE_PRI_AOC_EVENTS) */
12978 if (chan_sig == SIG_BRI_PTMP) {
12979 pris[span].pri.layer1_ignored = conf->pri.pri.layer1_ignored;
12980 } else {
12981 /* Option does not apply to this line type. */
12982 pris[span].pri.layer1_ignored = 0;
12983 }
12984 pris[span].pri.append_msn_to_user_tag = conf->pri.pri.append_msn_to_user_tag;
12985 pris[span].pri.inband_on_setup_ack = conf->pri.pri.inband_on_setup_ack;
12986 pris[span].pri.inband_on_proceeding = conf->pri.pri.inband_on_proceeding;
12987 ast_copy_string(pris[span].pri.initial_user_tag, conf->chan.cid_tag, sizeof(pris[span].pri.initial_user_tag));
12988 ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
12989#if defined(HAVE_PRI_MWI)
12990 ast_copy_string(pris[span].pri.mwi_mailboxes,
12991 conf->pri.pri.mwi_mailboxes,
12992 sizeof(pris[span].pri.mwi_mailboxes));
12993 ast_copy_string(pris[span].pri.mwi_vm_boxes,
12994 conf->pri.pri.mwi_vm_boxes,
12995 sizeof(pris[span].pri.mwi_vm_boxes));
12996 ast_copy_string(pris[span].pri.mwi_vm_numbers,
12997 conf->pri.pri.mwi_vm_numbers,
12998 sizeof(pris[span].pri.mwi_vm_numbers));
12999#endif /* defined(HAVE_PRI_MWI) */
13000 ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
13001 ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
13002 ast_copy_string(pris[span].pri.internationalprefix, conf->pri.pri.internationalprefix, sizeof(pris[span].pri.internationalprefix));
13003 ast_copy_string(pris[span].pri.nationalprefix, conf->pri.pri.nationalprefix, sizeof(pris[span].pri.nationalprefix));
13004 ast_copy_string(pris[span].pri.localprefix, conf->pri.pri.localprefix, sizeof(pris[span].pri.localprefix));
13005 ast_copy_string(pris[span].pri.privateprefix, conf->pri.pri.privateprefix, sizeof(pris[span].pri.privateprefix));
13006 ast_copy_string(pris[span].pri.unknownprefix, conf->pri.pri.unknownprefix, sizeof(pris[span].pri.unknownprefix));
13007 pris[span].pri.moh_signaling = conf->pri.pri.moh_signaling;
13008 pris[span].pri.resetinterval = conf->pri.pri.resetinterval;
13009#if defined(HAVE_PRI_DISPLAY_TEXT)
13010 pris[span].pri.display_flags_send = conf->pri.pri.display_flags_send;
13011 pris[span].pri.display_flags_receive = conf->pri.pri.display_flags_receive;
13012#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
13013#if defined(HAVE_PRI_MCID)
13014 pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
13015#endif /* defined(HAVE_PRI_MCID) */
13016 pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
13017#if defined(HAVE_PRI_DATETIME_SEND)
13018 pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
13019#endif /* defined(HAVE_PRI_DATETIME_SEND) */
13020
13021 for (x = 0; x < PRI_MAX_TIMERS; x++) {
13022 pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
13023 }
13024
13025#if defined(HAVE_PRI_CALL_WAITING)
13026 /* Channel initial config parameters. */
13027 pris[span].pri.ch_cfg.stripmsd = conf->chan.stripmsd;
13028 pris[span].pri.ch_cfg.hidecallerid = conf->chan.hidecallerid;
13029 pris[span].pri.ch_cfg.hidecalleridname = conf->chan.hidecalleridname;
13030 pris[span].pri.ch_cfg.immediate = conf->chan.immediate;
13031 pris[span].pri.ch_cfg.priexclusive = conf->chan.priexclusive;
13032 pris[span].pri.ch_cfg.priindication_oob = conf->chan.priindication_oob;
13033 pris[span].pri.ch_cfg.use_callerid = conf->chan.use_callerid;
13034 pris[span].pri.ch_cfg.use_callingpres = conf->chan.use_callingpres;
13035 ast_copy_string(pris[span].pri.ch_cfg.context, conf->chan.context, sizeof(pris[span].pri.ch_cfg.context));
13036 ast_copy_string(pris[span].pri.ch_cfg.mohinterpret, conf->chan.mohinterpret, sizeof(pris[span].pri.ch_cfg.mohinterpret));
13037#endif /* defined(HAVE_PRI_CALL_WAITING) */
13038 } else {
13039 ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", p.chanpos);
13040 destroy_dahdi_pvt(tmp);
13041 return NULL;
13042 }
13043 }
13044 }
13045#endif
13046 } else {
13047 /* already exists in interface list */
13048 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));
13049 chan_sig = tmp->sig;
13050 if (tmp->subs[SUB_REAL].dfd > -1) {
13051 memset(&p, 0, sizeof(p));
13052 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13053 }
13054 }
13055 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
13056 switch (chan_sig) {
13057 case SIG_FXSKS:
13058 case SIG_FXSLS:
13059 case SIG_EM:
13060 case SIG_EM_E1:
13061 case SIG_EMWINK:
13062 case SIG_FEATD:
13063 case SIG_FEATDMF:
13064 case SIG_FEATDMF_TA:
13065 case SIG_FEATB:
13066 case SIG_E911:
13067 case SIG_SF:
13068 case SIG_SFWINK:
13069 case SIG_FGC_CAMA:
13070 case SIG_FGC_CAMAMF:
13071 case SIG_SF_FEATD:
13072 case SIG_SF_FEATDMF:
13073 case SIG_SF_FEATB:
13074 p.starttime = 250;
13075 break;
13076 }
13077
13078 if (tmp->radio) {
13079 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
13080 p.channo = channel;
13081 p.rxwinktime = 1;
13082 p.rxflashtime = 1;
13083 p.starttime = 1;
13084 p.debouncetime = 5;
13085 } else {
13086 p.channo = channel;
13087 /* Override timing settings based on config file */
13088 if (conf->timing.prewinktime >= 0)
13089 p.prewinktime = conf->timing.prewinktime;
13090 if (conf->timing.preflashtime >= 0)
13091 p.preflashtime = conf->timing.preflashtime;
13092 if (conf->timing.winktime >= 0)
13093 p.winktime = conf->timing.winktime;
13094 if (conf->timing.flashtime >= 0)
13095 p.flashtime = conf->timing.flashtime;
13096 if (conf->timing.starttime >= 0)
13097 p.starttime = conf->timing.starttime;
13098 if (conf->timing.rxwinktime >= 0)
13099 p.rxwinktime = conf->timing.rxwinktime;
13100 if (conf->timing.rxflashtime >= 0)
13101 p.rxflashtime = conf->timing.rxflashtime;
13102 if (conf->timing.debouncetime >= 0)
13103 p.debouncetime = conf->timing.debouncetime;
13104 }
13105
13106 /* don't set parms on a pseudo-channel */
13107 if (tmp->subs[SUB_REAL].dfd >= 0)
13108 {
13109 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
13110 if (res < 0) {
13111 ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
13112 destroy_dahdi_pvt(tmp);
13113 return NULL;
13114 }
13115 }
13116#if 1
13117 if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
13118 memset(&bi, 0, sizeof(bi));
13119 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13120 if (!res) {
13121 bi.txbufpolicy = conf->chan.buf_policy;
13122 bi.rxbufpolicy = conf->chan.buf_policy;
13123 bi.numbufs = conf->chan.buf_no;
13124 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13125 if (res < 0) {
13126 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
13127 }
13128 } else {
13129 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
13130 }
13131 tmp->buf_policy = conf->chan.buf_policy;
13132 tmp->buf_no = conf->chan.buf_no;
13133 tmp->usefaxbuffers = conf->chan.usefaxbuffers;
13134 tmp->faxbuf_policy = conf->chan.faxbuf_policy;
13135 tmp->faxbuf_no = conf->chan.faxbuf_no;
13136 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
13137 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
13138 * The reason the ioctl call above failed should to be determined before worrying about the
13139 * faxbuffer-related ioctl calls */
13140 tmp->bufsize = bi.bufsize;
13141 }
13142#endif
13143 tmp->immediate = conf->chan.immediate;
13144 tmp->immediatering = conf->chan.immediatering;
13145 tmp->transfertobusy = conf->chan.transfertobusy;
13146 tmp->permdialmode = conf->chan.permdialmode;
13147 if (chan_sig & __DAHDI_SIG_FXS) {
13148 tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
13149 tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
13150 tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
13151 }
13152 tmp->ringt_base = ringt_base;
13153 tmp->firstradio = 0;
13154 if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
13155 tmp->permcallwaiting = conf->chan.callwaiting;
13156 else
13157 tmp->permcallwaiting = 0;
13158 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
13159 tmp->destroy = 0;
13160 tmp->drings = conf->chan.drings;
13161
13162 /* 10 is a nice default. */
13163 if (tmp->drings.ringnum[0].range == 0)
13164 tmp->drings.ringnum[0].range = 10;
13165 if (tmp->drings.ringnum[1].range == 0)
13166 tmp->drings.ringnum[1].range = 10;
13167 if (tmp->drings.ringnum[2].range == 0)
13168 tmp->drings.ringnum[2].range = 10;
13169
13171 tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
13172 tmp->callwaitingdeluxe = conf->chan.callwaitingdeluxe; /* Not used in DAHDI pvt, only analog pvt */
13173 tmp->threewaycalling = conf->chan.threewaycalling;
13174 tmp->threewaysilenthold = conf->chan.threewaysilenthold;
13175 tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
13176 tmp->adsi = conf->chan.adsi;
13177 tmp->use_smdi = conf->chan.use_smdi;
13178 tmp->permhidecallerid = conf->chan.hidecallerid;
13179 tmp->hidecalleridname = conf->chan.hidecalleridname;
13180 tmp->callreturn = conf->chan.callreturn;
13181 tmp->lastnumredial = conf->chan.lastnumredial; /* Not used in DAHDI pvt, only analog pvt */
13182 tmp->echocancel = conf->chan.echocancel;
13183 tmp->echotraining = conf->chan.echotraining;
13184 tmp->pulse = conf->chan.pulse;
13185 if (tmp->echocancel.head.tap_length) {
13186 tmp->echocanbridged = conf->chan.echocanbridged;
13187 } else {
13188 if (conf->chan.echocanbridged)
13189 ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
13190 tmp->echocanbridged = 0;
13191 }
13192 tmp->busydetect = conf->chan.busydetect;
13193 tmp->busycount = conf->chan.busycount;
13194 tmp->busy_cadence = conf->chan.busy_cadence;
13195 tmp->callprogress = conf->chan.callprogress;
13196 tmp->waitfordialtone = conf->chan.waitfordialtone;
13197 tmp->dialtone_detect = conf->chan.dialtone_detect;
13198 tmp->faxdetect_timeout = conf->chan.faxdetect_timeout;
13199 tmp->firstdigit_timeout = conf->chan.firstdigit_timeout;
13200 tmp->interdigit_timeout = conf->chan.interdigit_timeout;
13201 tmp->matchdigit_timeout = conf->chan.matchdigit_timeout;
13202 tmp->cancallforward = conf->chan.cancallforward;
13203 tmp->dtmfrelax = conf->chan.dtmfrelax;
13204 tmp->callwaiting = tmp->permcallwaiting;
13205 tmp->hidecallerid = tmp->permhidecallerid;
13206 tmp->channel = channel;
13207 tmp->stripmsd = conf->chan.stripmsd;
13208 tmp->use_callerid = conf->chan.use_callerid;
13209 tmp->cid_signalling = conf->chan.cid_signalling;
13210 tmp->cid_start = conf->chan.cid_start;
13211 tmp->dahditrcallerid = conf->chan.dahditrcallerid;
13212 tmp->restrictcid = conf->chan.restrictcid;
13213 tmp->use_callingpres = conf->chan.use_callingpres;
13214 if (tmp->usedistinctiveringdetection) {
13215 if (!tmp->use_callerid) {
13216 ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
13217 tmp->use_callerid = 1;
13218 }
13219 }
13220
13221 if (tmp->cid_signalling == CID_SIG_SMDI) {
13222 if (!tmp->use_smdi) {
13223 ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13224 tmp->use_smdi = 1;
13225 }
13226 }
13227 if (tmp->use_smdi) {
13228 tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
13229 if (!(tmp->smdi_iface)) {
13230 ast_log(LOG_ERROR, "Invalid SMDI port specified, disabling SMDI support\n");
13231 tmp->use_smdi = 0;
13232 }
13233 }
13234
13235 ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
13236 tmp->amaflags = conf->chan.amaflags;
13237 if (!here) {
13238 tmp->confno = -1;
13239 tmp->propconfno = -1;
13240 }
13241 tmp->canpark = conf->chan.canpark;
13242 tmp->transfer = conf->chan.transfer;
13243 ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
13244 ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
13245 ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
13246 ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
13247 ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
13248 ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
13249 ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
13250 tmp->cid_ton = 0;
13251 if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
13252 ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
13253 ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
13254 } else {
13255 tmp->cid_num[0] = '\0';
13256 tmp->cid_name[0] = '\0';
13257 }
13258#if defined(HAVE_PRI)
13259 if (dahdi_sig_pri_lib_handles(tmp->sig)) {
13260 tmp->cid_tag[0] = '\0';
13261 } else
13262#endif /* defined(HAVE_PRI) */
13263 {
13264 ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
13265 }
13266 tmp->cid_subaddr[0] = '\0';
13267 ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
13268 if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
13269 /* This module does not handle MWI in an event-based manner. However, it
13270 * subscribes to MWI for each mailbox that is configured so that the core
13271 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13272 * event cache instead of checking the mailbox directly. */
13274 }
13275#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13276 tmp->mwisend_setting = conf->chan.mwisend_setting;
13277 tmp->mwisend_fsk = conf->chan.mwisend_fsk;
13278 tmp->mwisend_rpas = conf->chan.mwisend_rpas;
13279#endif
13280
13281 tmp->group = conf->chan.group;
13282 tmp->callgroup = conf->chan.callgroup;
13283 tmp->pickupgroup= conf->chan.pickupgroup;
13285 tmp->named_callgroups = ast_ref_namedgroups(conf->chan.named_callgroups);
13287 tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
13288 if (conf->chan.vars) {
13289 struct ast_variable *v, *tmpvar;
13290 for (v = conf->chan.vars ; v ; v = v->next) {
13291 if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
13292 if (ast_variable_list_replace(&tmp->vars, tmpvar)) {
13293 tmpvar->next = tmp->vars;
13294 tmp->vars = tmpvar;
13295 }
13296 }
13297 }
13298 }
13299 tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
13300 tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
13301 tmp->hwrxgain = conf->chan.hwrxgain;
13302 tmp->hwtxgain = conf->chan.hwtxgain;
13303 tmp->cid_rxgain = conf->chan.cid_rxgain;
13304 tmp->rxgain = conf->chan.rxgain;
13305 tmp->txgain = conf->chan.txgain;
13306 tmp->txdrc = conf->chan.txdrc;
13307 tmp->rxdrc = conf->chan.rxdrc;
13308 tmp->tonezone = conf->chan.tonezone;
13309 if (tmp->subs[SUB_REAL].dfd > -1) {
13310 if (tmp->hwrxgain_enabled) {
13311 tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
13312 }
13313 if (tmp->hwtxgain_enabled) {
13314 tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
13315 }
13316 set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
13317 if (tmp->dsp)
13319 dahdi_conf_update(tmp);
13320 if (!here) {
13321 switch (chan_sig) {
13323 case SIG_SS7:
13324 case SIG_MFCR2:
13325 break;
13326 default:
13327 /* Hang it up to be sure it's good */
13328 dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
13329 break;
13330 }
13331 }
13332 ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
13333 if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
13334 /* the dchannel is down so put the channel in alarm */
13335 switch (tmp->sig) {
13336#ifdef HAVE_PRI
13338 sig_pri_set_alarm(tmp->sig_pvt, 1);
13339 break;
13340#endif
13341#if defined(HAVE_SS7)
13342 case SIG_SS7:
13343 sig_ss7_set_alarm(tmp->sig_pvt, 1);
13344 break;
13345#endif /* defined(HAVE_SS7) */
13346 default:
13347 /* The only sig submodule left should be sig_analog. */
13348 analog_p = tmp->sig_pvt;
13349 if (analog_p) {
13350 analog_p->inalarm = 1;
13351 }
13352 tmp->inalarm = 1;
13353 break;
13354 }
13355 handle_alarms(tmp, res);
13356 }
13357 }
13358
13359 tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13360 tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13361 tmp->ani_info_digits = conf->chan.ani_info_digits;
13362 tmp->ani_wink_time = conf->chan.ani_wink_time;
13363 tmp->ani_timeout = conf->chan.ani_timeout;
13364 tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13365 tmp->reoriginate = conf->chan.reoriginate;
13366 tmp->sendcalleridafter = conf->chan.sendcalleridafter;
13367 ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
13368
13369 if (!here) {
13370 tmp->locallyblocked = 0;
13371 tmp->remotelyblocked = 0;
13372 switch (tmp->sig) {
13373#if defined(HAVE_PRI)
13375 tmp->inservice = 1;/* Inservice until actually implemented. */
13376#if defined(HAVE_PRI_SERVICE_MESSAGES)
13377 ((struct sig_pri_chan *) tmp->sig_pvt)->service_status = 0;
13378 if (chan_sig == SIG_PRI) {
13379 char db_chan_name[20];
13380 char db_answer[5];
13381
13382 /*
13383 * Initialize the active out-of-service status
13384 * and delete any record if the feature is not enabled.
13385 */
13386 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, tmp->channel);
13387 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
13388 unsigned *why;
13389
13390 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
13391 if (tmp->pri->enable_service_message_support) {
13392 char state;
13393
13394 sscanf(db_answer, "%1c:%30u", &state, why);
13395
13396 /* Ensure that only the implemented bits could be set.*/
13397 *why &= (SRVST_NEAREND | SRVST_FAREND);
13398 }
13399 if (!*why) {
13400 ast_db_del(db_chan_name, SRVST_DBKEY);
13401 }
13402 }
13403 }
13404#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13405 break;
13406#endif /* defined(HAVE_PRI) */
13407#if defined(HAVE_SS7)
13408 case SIG_SS7:
13409 tmp->inservice = 0;
13410 if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
13412 }
13413 break;
13414#endif /* defined(HAVE_SS7) */
13415 default:
13416 /* We default to in service on protocols that don't have a reset */
13417 tmp->inservice = 1;
13418 break;
13419 }
13420 }
13421
13422 switch (tmp->sig) {
13423#if defined(HAVE_PRI)
13425 if (pri_chan) {
13426 pri_chan->channel = tmp->channel;
13427 pri_chan->hidecallerid = tmp->hidecallerid;
13428 pri_chan->hidecalleridname = tmp->hidecalleridname;
13429 pri_chan->immediate = tmp->immediate;
13430 pri_chan->inalarm = tmp->inalarm;
13431 pri_chan->priexclusive = tmp->priexclusive;
13432 pri_chan->priindication_oob = tmp->priindication_oob;
13433 pri_chan->use_callerid = tmp->use_callerid;
13434 pri_chan->use_callingpres = tmp->use_callingpres;
13435 ast_copy_string(pri_chan->context, tmp->context,
13436 sizeof(pri_chan->context));
13438 sizeof(pri_chan->mohinterpret));
13439 pri_chan->stripmsd = tmp->stripmsd;
13440 }
13441 break;
13442#endif /* defined(HAVE_PRI) */
13443#if defined(HAVE_SS7)
13444 case SIG_SS7:
13445 if (ss7_chan) {
13446 ss7_chan->inalarm = tmp->inalarm;
13447 ss7_chan->inservice = tmp->inservice;
13448
13449 ss7_chan->stripmsd = tmp->stripmsd;
13450 ss7_chan->hidecallerid = tmp->hidecallerid;
13451 ss7_chan->use_callerid = tmp->use_callerid;
13452 ss7_chan->use_callingpres = tmp->use_callingpres;
13453 ss7_chan->immediate = tmp->immediate;
13454 ss7_chan->locallyblocked = tmp->locallyblocked;
13455 ss7_chan->remotelyblocked = tmp->remotelyblocked;
13456 ast_copy_string(ss7_chan->context, tmp->context,
13457 sizeof(ss7_chan->context));
13459 sizeof(ss7_chan->mohinterpret));
13460 }
13461 break;
13462#endif /* defined(HAVE_SS7) */
13463 default:
13464 /* The only sig submodule left should be sig_analog. */
13465 analog_p = tmp->sig_pvt;
13466 if (analog_p) {
13467 analog_p->channel = tmp->channel;
13468 analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13469 analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13470 analog_p->ani_info_digits = conf->chan.ani_info_digits;
13471 analog_p->ani_timeout = conf->chan.ani_timeout;
13472 analog_p->ani_wink_time = conf->chan.ani_wink_time;
13473 analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13474 analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
13475 analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
13476 analog_p->callreturn = conf->chan.callreturn;
13477 analog_p->lastnumredial = conf->chan.lastnumredial; /* Only actually used in analog pvt, not DAHDI pvt */
13478 analog_p->cancallforward = conf->chan.cancallforward;
13479 analog_p->canpark = conf->chan.canpark;
13480 analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
13481 analog_p->immediate = conf->chan.immediate;
13482 analog_p->immediatering = conf->chan.immediatering;
13483 analog_p->permhidecallerid = conf->chan.hidecallerid; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13484 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13485 analog_p->pulse = conf->chan.pulse;
13486 analog_p->threewaycalling = conf->chan.threewaycalling;
13487 analog_p->transfer = conf->chan.transfer;
13488 analog_p->transfertobusy = conf->chan.transfertobusy;
13489 analog_p->permdialmode = conf->chan.permdialmode;
13490 analog_p->use_callerid = tmp->use_callerid;
13492 analog_p->use_smdi = tmp->use_smdi;
13493 analog_p->smdi_iface = tmp->smdi_iface;
13494 analog_p->outsigmod = ANALOG_SIG_NONE;
13495 analog_p->echotraining = conf->chan.echotraining;
13496 analog_p->cid_signalling = conf->chan.cid_signalling;
13497 analog_p->stripmsd = conf->chan.stripmsd;
13498 switch (conf->chan.cid_start) {
13499 case CID_START_POLARITY:
13501 break;
13504 break;
13507 break;
13508 default:
13509 analog_p->cid_start = ANALOG_CID_START_RING;
13510 break;
13511 }
13512 analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;
13513 analog_p->callwaitingdeluxe = conf->chan.callwaitingdeluxe;
13514 analog_p->ringt = conf->chan.ringt;
13515 analog_p->ringt_base = ringt_base;
13516 analog_p->onhooktime = time(NULL);
13517 if (chan_sig & __DAHDI_SIG_FXO) {
13518 memset(&p, 0, sizeof(p));
13519 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13520 if (!res) {
13521 analog_p->fxsoffhookstate = p.rxisoffhook;
13522 }
13523#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13524 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
13525#endif
13526 }
13527 analog_p->msgstate = -1;
13528
13529 ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
13530 ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
13531 ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
13532
13533 analog_config_complete(analog_p);
13534 }
13535 break;
13536 }
13537#if defined(HAVE_PRI)
13538 if (tmp->channel == CHAN_PSEUDO) {
13539 /*
13540 * Save off pseudo channel buffer policy values for dynamic creation of
13541 * no B channel interfaces.
13542 */
13543 dahdi_pseudo_parms.buf_no = tmp->buf_no;
13544 dahdi_pseudo_parms.buf_policy = tmp->buf_policy;
13545 dahdi_pseudo_parms.faxbuf_no = tmp->faxbuf_no;
13546 dahdi_pseudo_parms.faxbuf_policy = tmp->faxbuf_policy;
13547 }
13548#endif /* defined(HAVE_PRI) */
13549 }
13550 if (tmp && !here) {
13551 /* Add the new channel interface to the sorted channel interface list. */
13553 }
13554 return tmp;
13555}
13556
13557static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
13558{
13559#if defined(HAVE_PRI)
13560 if (0 < span) {
13561 /* The channel must be on the specified PRI span. */
13562 if (!p->pri || p->pri->span != span) {
13563 return 0;
13564 }
13565 if (!groupmatch && channelmatch == -1) {
13566 /* Match any group since it only needs to be on the PRI span. */
13567 *groupmatched = 1;
13568 return 1;
13569 }
13570 }
13571#endif /* defined(HAVE_PRI) */
13572 /* check group matching */
13573 if (groupmatch) {
13574 if ((p->group & groupmatch) != groupmatch)
13575 /* Doesn't match the specified group, try the next one */
13576 return 0;
13577 *groupmatched = 1;
13578 }
13579 /* Check to see if we have a channel match */
13580 if (channelmatch != -1) {
13581 if (p->channel != channelmatch)
13582 /* Doesn't match the specified channel, try the next one */
13583 return 0;
13584 *channelmatched = 1;
13585 }
13586
13587 return 1;
13588}
13589
13590static int available(struct dahdi_pvt **pvt, int is_specific_channel)
13591{
13592 struct dahdi_pvt *p = *pvt;
13593
13594 if (p->inalarm)
13595 return 0;
13596
13597 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
13598 return analog_available(p->sig_pvt);
13599
13600 switch (p->sig) {
13601#if defined(HAVE_PRI)
13603 {
13604 struct sig_pri_chan *pvt_chan;
13605 int res;
13606
13607 pvt_chan = p->sig_pvt;
13608 res = sig_pri_available(&pvt_chan, is_specific_channel);
13609 *pvt = pvt_chan->chan_pvt;
13610 return res;
13611 }
13612#endif /* defined(HAVE_PRI) */
13613#if defined(HAVE_SS7)
13614 case SIG_SS7:
13615 return sig_ss7_available(p->sig_pvt);
13616#endif /* defined(HAVE_SS7) */
13617 default:
13618 break;
13619 }
13620
13621 if (p->locallyblocked || p->remotelyblocked) {
13622 return 0;
13623 }
13624
13625 /* If no owner definitely available */
13626 if (!p->owner) {
13627#ifdef HAVE_OPENR2
13628 /* Trust MFC/R2 */
13629 if (p->mfcr2) {
13630 if (p->mfcr2call) {
13631 return 0;
13632 } else {
13633 return 1;
13634 }
13635 }
13636#endif
13637 return 1;
13638 }
13639
13640 return 0;
13641}
13642
13643#if defined(HAVE_PRI)
13644#if defined(HAVE_PRI_CALL_WAITING)
13645/*!
13646 * \internal
13647 * \brief Init the private channel configuration using the span controller.
13648 * \since 1.8
13649 *
13650 * \param priv Channel to init the configuration.
13651 * \param pri sig_pri PRI control structure.
13652 *
13653 * \note Assumes the pri->lock is already obtained.
13654 */
13655static void my_pri_init_config(void *priv, struct sig_pri_span *pri)
13656{
13657 struct dahdi_pvt *pvt = priv;
13658
13659 pvt->stripmsd = pri->ch_cfg.stripmsd;
13660 pvt->hidecallerid = pri->ch_cfg.hidecallerid;
13661 pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
13662 pvt->immediate = pri->ch_cfg.immediate;
13663 pvt->priexclusive = pri->ch_cfg.priexclusive;
13664 pvt->priindication_oob = pri->ch_cfg.priindication_oob;
13665 pvt->use_callerid = pri->ch_cfg.use_callerid;
13666 pvt->use_callingpres = pri->ch_cfg.use_callingpres;
13667 ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
13668 ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
13669}
13670#endif /* defined(HAVE_PRI_CALL_WAITING) */
13671#endif /* defined(HAVE_PRI) */
13672
13673#if defined(HAVE_PRI)
13674/*!
13675 * \internal
13676 * \brief Create a no B channel interface.
13677 * \since 1.8
13678 *
13679 * \param pri sig_pri span controller to add interface.
13680 *
13681 * \note Assumes the pri->lock is already obtained.
13682 *
13683 * \retval array-index into private pointer array on success.
13684 * \retval -1 on error.
13685 */
13686static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri)
13687{
13688 int pvt_idx;
13689 int res;
13690 unsigned idx;
13691 struct dahdi_pvt *pvt;
13692 struct sig_pri_chan *chan;
13693 struct dahdi_bufferinfo bi;
13694
13695 static int nobch_channel = CHAN_PSEUDO;
13696
13697 /* Find spot in the private pointer array for new interface. */
13698 for (pvt_idx = 0; pvt_idx < pri->numchans; ++pvt_idx) {
13699 if (!pri->pvts[pvt_idx]) {
13700 break;
13701 }
13702 }
13703 if (pri->numchans == pvt_idx) {
13704 if (ARRAY_LEN(pri->pvts) <= pvt_idx) {
13705 ast_log(LOG_ERROR, "Unable to add a no-B-channel interface!\n");
13706 return -1;
13707 }
13708
13709 /* Add new spot to the private pointer array. */
13710 pri->pvts[pvt_idx] = NULL;
13711 ++pri->numchans;
13712 }
13713
13714 pvt = ast_calloc(1, sizeof(*pvt));
13715 if (!pvt) {
13716 return -1;
13717 }
13719 if (!pvt->cc_params) {
13720 ast_free(pvt);
13721 return -1;
13722 }
13723 ast_mutex_init(&pvt->lock);
13724 for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
13725 pvt->subs[idx].dfd = -1;
13726 }
13727 pvt->buf_no = dahdi_pseudo_parms.buf_no;
13728 pvt->buf_policy = dahdi_pseudo_parms.buf_policy;
13729 pvt->faxbuf_no = dahdi_pseudo_parms.faxbuf_no;
13730 pvt->faxbuf_policy = dahdi_pseudo_parms.faxbuf_policy;
13731
13732 chan = sig_pri_chan_new(pvt, pri, 0, 0, 0);
13733 if (!chan) {
13734 destroy_dahdi_pvt(pvt);
13735 return -1;
13736 }
13737 chan->no_b_channel = 1;
13738
13739 /*
13740 * Pseudo channel companding law.
13741 * Needed for outgoing call waiting calls.
13742 * XXX May need to make this determined by switchtype or user option.
13743 */
13744 pvt->law_default = DAHDI_LAW_ALAW;
13745
13746 pvt->sig = pri->sig;
13747 pvt->outsigmod = -1;
13748 pvt->pri = pri;
13749 pvt->sig_pvt = chan;
13750 pri->pvts[pvt_idx] = chan;
13751
13752 pvt->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13753 if (pvt->subs[SUB_REAL].dfd < 0) {
13754 ast_log(LOG_ERROR, "Unable to open no B channel interface pseudo channel: %s\n",
13755 strerror(errno));
13756 destroy_dahdi_pvt(pvt);
13757 return -1;
13758 }
13759 memset(&bi, 0, sizeof(bi));
13760 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13761 if (!res) {
13762 pvt->bufsize = bi.bufsize;
13763 bi.txbufpolicy = pvt->buf_policy;
13764 bi.rxbufpolicy = pvt->buf_policy;
13765 bi.numbufs = pvt->buf_no;
13766 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13767 if (res < 0) {
13769 "Unable to set buffer policy on no B channel interface: %s\n",
13770 strerror(errno));
13771 }
13772 } else
13774 "Unable to check buffer policy on no B channel interface: %s\n",
13775 strerror(errno));
13776
13777 --nobch_channel;
13778 if (CHAN_PSEUDO < nobch_channel) {
13779 nobch_channel = CHAN_PSEUDO - 1;
13780 }
13781 pvt->channel = nobch_channel;
13782 pvt->span = pri->span;
13783 chan->channel = pvt->channel;
13784
13785 dahdi_nobch_insert(pri, pvt);
13786
13787 return pvt_idx;
13788}
13789#endif /* defined(HAVE_PRI) */
13790
13791/* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13792 structures; it makes no attempt to safely copy regular channel private
13793 structures that might contain reference-counted object pointers and other
13794 scary bits
13795*/
13796static struct dahdi_pvt *duplicate_pseudo(struct dahdi_pvt *src)
13797{
13798 struct dahdi_pvt *p;
13799 struct dahdi_bufferinfo bi;
13800 int res;
13801
13802 p = ast_malloc(sizeof(*p));
13803 if (!p) {
13804 return NULL;
13805 }
13806 *p = *src;
13807
13808 /* Must deep copy the cc_params. */
13810 if (!p->cc_params) {
13811 ast_free(p);
13812 return NULL;
13813 }
13815
13817 p->next = NULL;
13818 p->prev = NULL;
13819 ast_mutex_init(&p->lock);
13820 p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13821 if (p->subs[SUB_REAL].dfd < 0) {
13822 ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
13824 return NULL;
13825 }
13826 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13827 if (!res) {
13828 bi.txbufpolicy = src->buf_policy;
13829 bi.rxbufpolicy = src->buf_policy;
13830 bi.numbufs = src->buf_no;
13831 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13832 if (res < 0) {
13833 ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
13834 }
13835 } else
13836 ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
13837 p->destroy = 1;
13839 return p;
13840}
13841
13843 /*! Group matching mask. Zero if not specified. */
13845 /*! DAHDI channel to match with. -1 if not specified. */
13847 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13849 /*! ISDN span where channels can be picked (Zero if not specified) */
13850 int span;
13851 /*! Analog channel distinctive ring cadence index. */
13853 /*! Dialing option. c/r/d if present and valid. */
13854 char opt;
13855 /*! TRUE if to search the channel list backwards. */
13857 /*! TRUE if search is done with round robin sequence. */
13859};
13860static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi_starting_point *param)
13861{
13862 char *dest;
13863 char *s;
13864 int x;
13865 int res = 0;
13866 struct dahdi_pvt *p;
13867 char *subdir = NULL;
13869 AST_APP_ARG(group); /* channel/group token */
13870 //AST_APP_ARG(ext); /* extension token */
13871 //AST_APP_ARG(opts); /* options token */
13872 AST_APP_ARG(other); /* Any remaining unused arguments */
13873 );
13874
13875 /*
13876 * data is ---v
13877 * Dial(DAHDI/pseudo[/extension[/options]])
13878 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13879 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13880 * Dial(DAHDI/i<span>[/extension[/options]])
13881 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13882 *
13883 * i - ISDN span channel restriction.
13884 * Used by CC to ensure that the CC recall goes out the same span.
13885 * Also to make ISDN channel names dialable when the sequence number
13886 * is stripped off. (Used by DTMF attended transfer feature.)
13887 *
13888 * g - channel group allocation search forward
13889 * G - channel group allocation search backward
13890 * r - channel group allocation round robin search forward
13891 * R - channel group allocation round robin search backward
13892 *
13893 * c - Wait for DTMF digit to confirm answer
13894 * r<cadence#> - Set distinctive ring cadence number
13895 * d - Force bearer capability for ISDN/SS7 call to digital.
13896 */
13897
13898 if (data) {
13899 dest = ast_strdupa(data);
13900 } else {
13901 ast_log(LOG_WARNING, "Channel requested with no data\n");
13902 return NULL;
13903 }
13904 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
13905 if (!args.argc || ast_strlen_zero(args.group)) {
13906 ast_log(LOG_WARNING, "No channel/group specified\n");
13907 return NULL;
13908 }
13909
13910 /* Initialize the output parameters */
13911 memset(param, 0, sizeof(*param));
13912 param->channelmatch = -1;
13913
13914 if (strchr(args.group, '!') != NULL) {
13915 char *prev = args.group;
13916 while ((s = strchr(prev, '!')) != NULL) {
13917 *s++ = '/';
13918 prev = s;
13919 }
13920 *(prev - 1) = '\0';
13921 subdir = args.group;
13922 args.group = prev;
13923 } else if (args.group[0] == 'i') {
13924 /* Extract the ISDN span channel restriction specifier. */
13925 res = sscanf(args.group + 1, "%30d", &x);
13926 if (res < 1) {
13927 ast_log(LOG_WARNING, "Unable to determine ISDN span for data %s\n", data);
13928 return NULL;
13929 }
13930 param->span = x;
13931
13932 /* Remove the ISDN span channel restriction specifier. */
13933 s = strchr(args.group, '-');
13934 if (!s) {
13935 /* Search all groups since we are ISDN span restricted. */
13936 return iflist;
13937 }
13938 args.group = s + 1;
13939 res = 0;
13940 }
13941 if (toupper(args.group[0]) == 'G' || toupper(args.group[0])=='R') {
13942 /* Retrieve the group number */
13943 s = args.group + 1;
13944 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13945 if (res < 1) {
13946 ast_log(LOG_WARNING, "Unable to determine group for data %s\n", data);
13947 return NULL;
13948 }
13949 param->groupmatch = ((ast_group_t) 1 << x);
13950
13951 if (toupper(args.group[0]) == 'G') {
13952 if (args.group[0] == 'G') {
13953 param->backwards = 1;
13954 p = ifend;
13955 } else
13956 p = iflist;
13957 } else {
13958 if (ARRAY_LEN(round_robin) <= x) {
13959 ast_log(LOG_WARNING, "Round robin index %d out of range for data %s\n",
13960 x, data);
13961 return NULL;
13962 }
13963 if (args.group[0] == 'R') {
13964 param->backwards = 1;
13965 p = round_robin[x] ? round_robin[x]->prev : ifend;
13966 if (!p)
13967 p = ifend;
13968 } else {
13969 p = round_robin[x] ? round_robin[x]->next : iflist;
13970 if (!p)
13971 p = iflist;
13972 }
13973 param->roundrobin = 1;
13974 param->rr_starting_point = x;
13975 }
13976 } else {
13977 s = args.group;
13978 if (!strcasecmp(s, "pseudo")) {
13979 /* Special case for pseudo */
13980 x = CHAN_PSEUDO;
13981 param->channelmatch = x;
13982 } else {
13983 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13984 if (res < 1) {
13985 ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", data);
13986 return NULL;
13987 } else {
13988 param->channelmatch = x;
13989 }
13990 }
13991 if (subdir) {
13992 char path[PATH_MAX];
13993 struct stat stbuf;
13994
13995 snprintf(path, sizeof(path), "/dev/dahdi/%s/%d",
13996 subdir, param->channelmatch);
13997 if (stat(path, &stbuf) < 0) {
13998 ast_log(LOG_WARNING, "stat(%s) failed: %s\n",
13999 path, strerror(errno));
14000 return NULL;
14001 }
14002 if (!S_ISCHR(stbuf.st_mode)) {
14003 ast_log(LOG_ERROR, "%s: Not a character device file\n",
14004 path);
14005 return NULL;
14006 }
14007 param->channelmatch = minor(stbuf.st_rdev);
14008 }
14009
14010 p = iflist;
14011 }
14012
14013 if (param->opt == 'r' && res < 3) {
14014 ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", data);
14015 param->opt = '\0';
14016 }
14017
14018 return p;
14019}
14020
14021static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
14022 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
14023 const char *data, int *cause)
14024{
14025 int callwait = 0;
14026 struct dahdi_pvt *p;
14027 struct ast_channel *tmp = NULL;
14028 struct dahdi_pvt *exitpvt;
14029 int channelmatched = 0;
14030 int foundowner = 0;
14031 int groupmatched = 0;
14032#if defined(HAVE_PRI) || defined(HAVE_SS7)
14033 int transcapdigital = 0;
14034#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14035 struct dahdi_starting_point start;
14036 ast_callid callid = 0;
14037 int callid_created = ast_callid_threadstorage_auto(&callid);
14038
14040 p = determine_starting_point(data, &start);
14041 if (!p) {
14042 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
14044 ast_callid_threadstorage_auto_clean(callid, callid_created);
14045 return NULL;
14046 }
14047
14048 /* Search for an unowned channel */
14049 exitpvt = p;
14050 while (p && !tmp) {
14051 if (start.roundrobin)
14052 round_robin[start.rr_starting_point] = p;
14053
14054 if (p->owner) {
14055 foundowner++;
14056 }
14057
14058 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
14059 && available(&p, channelmatched)) {
14060 ast_debug(1, "Using channel %d\n", p->channel);
14061
14062 callwait = (p->owner != NULL);
14063#ifdef HAVE_OPENR2
14064 if (p->mfcr2) {
14065 ast_mutex_lock(&p->lock);
14066 if (p->mfcr2call) {
14068 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
14069 goto next;
14070 }
14071 p->mfcr2call = 1;
14073 }
14074#endif
14075 if (p->channel == CHAN_PSEUDO) {
14076 p = duplicate_pseudo(p);
14077 if (!p) {
14078 break;
14079 }
14080 }
14081
14082 p->distinctivering = 0;
14083 /* Make special notes */
14084 switch (start.opt) {
14085 case '\0':
14086 /* No option present. */
14087 break;
14088 case 'c':
14089 /* Confirm answer */
14090 p->confirmanswer = 1;
14091 break;
14092 case 'r':
14093 /* Distinctive ring */
14094 p->distinctivering = start.cadence;
14095 break;
14096 case 'd':
14097#if defined(HAVE_PRI) || defined(HAVE_SS7)
14098 /* If this is an ISDN call, make it digital */
14099 transcapdigital = AST_TRANS_CAP_DIGITAL;
14100#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14101 break;
14102 default:
14103 ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", start.opt, data);
14104 break;
14105 }
14106
14107 p->outgoing = 1;
14108 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
14109 tmp = analog_request(p->sig_pvt, &callwait, requestor);
14110#ifdef HAVE_PRI
14111 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
14112 /*
14113 * We already have the B channel reserved for this call. We
14114 * just need to make sure that dahdi_hangup() has completed
14115 * cleaning up before continuing.
14116 */
14117 ast_mutex_lock(&p->lock);
14119
14121 sizeof(p->dnid));
14122 tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, assignedids, requestor, transcapdigital);
14123#endif
14124#if defined(HAVE_SS7)
14125 } else if (p->sig == SIG_SS7) {
14126 tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, assignedids, requestor, transcapdigital);
14127#endif /* defined(HAVE_SS7) */
14128 } else {
14129 tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, assignedids, requestor, callid);
14130 }
14131 if (!tmp) {
14132 p->outgoing = 0;
14133#if defined(HAVE_PRI)
14134 switch (p->sig) {
14136#if defined(HAVE_PRI_CALL_WAITING)
14137 if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
14138 ((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
14139 ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
14140 }
14141#endif /* defined(HAVE_PRI_CALL_WAITING) */
14142 /*
14143 * This should be the last thing to clear when we are done with
14144 * the channel.
14145 */
14146 ((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
14147 break;
14148 default:
14149 break;
14150 }
14151#endif /* defined(HAVE_PRI) */
14152 } else {
14153 snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", data);
14154 }
14155 break;
14156 }
14157#ifdef HAVE_OPENR2
14158next:
14159#endif
14160 if (start.backwards) {
14161 p = p->prev;
14162 if (!p)
14163 p = ifend;
14164 } else {
14165 p = p->next;
14166 if (!p)
14167 p = iflist;
14168 }
14169 /* stop when you roll to the one that we started from */
14170 if (p == exitpvt)
14171 break;
14172 }
14175 if (cause && !tmp) {
14176 if (callwait || (channelmatched && foundowner)) {
14177 *cause = AST_CAUSE_BUSY;
14178 } else if (groupmatched) {
14179 *cause = AST_CAUSE_CONGESTION;
14180 } else {
14181 /*
14182 * We did not match any channel requested.
14183 * Dialplan error requesting non-existant channel?
14184 */
14185 }
14186 }
14187
14188 ast_callid_threadstorage_auto_clean(callid, callid_created);
14189 return tmp;
14190}
14191
14192/*!
14193 * \internal
14194 * \brief Determine the device state for a given DAHDI device if we can.
14195 * \since 1.8
14196 *
14197 * \param data DAHDI device name after "DAHDI/".
14198 *
14199 * \retval device_state enum ast_device_state value.
14200 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
14201 */
14202static int dahdi_devicestate(const char *data)
14203{
14204#if defined(HAVE_PRI)
14205 const char *device;
14206 unsigned span;
14207 int res;
14208
14209 device = data;
14210
14211 if (*device != 'I') {
14212 /* The request is not for an ISDN span device. */
14213 return AST_DEVICE_UNKNOWN;
14214 }
14215 res = sscanf(device, "I%30u", &span);
14216 if (res != 1 || !span || NUM_SPANS < span) {
14217 /* Bad format for ISDN span device name. */
14218 return AST_DEVICE_UNKNOWN;
14219 }
14220 device = strchr(device, '/');
14221 if (!device) {
14222 /* Bad format for ISDN span device name. */
14223 return AST_DEVICE_UNKNOWN;
14224 }
14225
14226 /*
14227 * Since there are currently no other span devstate's defined,
14228 * it must be congestion.
14229 */
14230#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14231 ++device;
14232 if (!strcmp(device, "congestion"))
14233#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14234 {
14235 return pris[span - 1].pri.congestion_devstate;
14236 }
14237#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14238 else if (!strcmp(device, "threshold")) {
14239 return pris[span - 1].pri.threshold_devstate;
14240 }
14241 return AST_DEVICE_UNKNOWN;
14242#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14243#else
14244 return AST_DEVICE_UNKNOWN;
14245#endif /* defined(HAVE_PRI) */
14246}
14247
14248/*!
14249 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14250 * \since 1.8
14251 *
14252 * \param inbound Incoming asterisk channel.
14253 * \param dest Same dial string passed to dahdi_request().
14254 * \param callback Callback into CC core to announce a busy channel available for CC.
14255 *
14256 * \details
14257 * This callback acts like a forked dial with all prongs of the fork busy.
14258 * Essentially, for each channel that could have taken the call, indicate that
14259 * it is busy.
14260 *
14261 * \retval 0 on success.
14262 * \retval -1 on error.
14263 */
14264static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
14265{
14266 struct dahdi_pvt *p;
14267 struct dahdi_pvt *exitpvt;
14268 struct dahdi_starting_point start;
14269 int groupmatched = 0;
14270 int channelmatched = 0;
14271
14273 p = determine_starting_point(dest, &start);
14274 if (!p) {
14276 return -1;
14277 }
14278 exitpvt = p;
14279 for (;;) {
14280 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)) {
14281 /* We found a potential match. call the callback */
14282 struct ast_str *device_name;
14283 char *dash;
14284 const char *monitor_type;
14285 char dialstring[AST_CHANNEL_NAME];
14286 char full_device_name[AST_CHANNEL_NAME];
14287
14290 break;
14294#if defined(HAVE_PRI)
14296 /*
14297 * ISDN is in a trunk busy condition so we need to monitor
14298 * the span congestion device state.
14299 */
14300 snprintf(full_device_name, sizeof(full_device_name),
14301 "DAHDI/I%d/congestion", p->pri->span);
14302 } else
14303#endif /* defined(HAVE_PRI) */
14304 {
14305#if defined(HAVE_PRI)
14306 device_name = create_channel_name(p, 1, "");
14307#else
14308 device_name = create_channel_name(p);
14309#endif /* defined(HAVE_PRI) */
14310 snprintf(full_device_name, sizeof(full_device_name), "DAHDI/%s",
14311 device_name ? ast_str_buffer(device_name) : "");
14312 ast_free(device_name);
14313 /*
14314 * The portion after the '-' in the channel name is either a random
14315 * number, a sequence number, or a subchannel number. None are
14316 * necessary so strip them off.
14317 */
14318 dash = strrchr(full_device_name, '-');
14319 if (dash) {
14320 *dash = '\0';
14321 }
14322 }
14323 snprintf(dialstring, sizeof(dialstring), "DAHDI/%s", dest);
14324
14325 /*
14326 * Analog can only do generic monitoring.
14327 * ISDN is in a trunk busy condition and any "device" is going
14328 * to be busy until a B channel becomes available. The generic
14329 * monitor can do this task.
14330 */
14331 monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
14332 callback(inbound,
14333#if defined(HAVE_PRI)
14334 p->pri ? p->pri->cc_params : p->cc_params,
14335#else
14336 p->cc_params,
14337#endif /* defined(HAVE_PRI) */
14338 monitor_type, full_device_name, dialstring, NULL);
14339 break;
14340 }
14341 }
14342 p = start.backwards ? p->prev : p->next;
14343 if (!p) {
14344 p = start.backwards ? ifend : iflist;
14345 }
14346 if (p == exitpvt) {
14347 break;
14348 }
14349 }
14351 return 0;
14352}
14353
14354#if defined(HAVE_SS7)
14355static void dahdi_ss7_message(struct ss7 *ss7, char *s)
14356{
14357 int i;
14358
14359 if (ss7) {
14360 for (i = 0; i < NUM_SPANS; i++) {
14361 if (linksets[i].ss7.ss7 == ss7) {
14362 ast_verbose_callid(0, "[%d] %s", i + 1, s);
14363 return;
14364 }
14365 }
14366 }
14367 ast_verbose_callid(0, "%s", s);
14368}
14369#endif /* defined(HAVE_SS7) */
14370
14371#if defined(HAVE_SS7)
14372static void dahdi_ss7_error(struct ss7 *ss7, char *s)
14373{
14374 int i;
14375
14376 if (ss7) {
14377 for (i = 0; i < NUM_SPANS; i++) {
14378 if (linksets[i].ss7.ss7 == ss7) {
14379 ast_log_callid(LOG_ERROR, 0, "[%d] %s", i + 1, s);
14380 return;
14381 }
14382 }
14383 }
14384 ast_log_callid(LOG_ERROR, 0, "%s", s);
14385}
14386#endif /* defined(HAVE_SS7) */
14387
14388#if defined(HAVE_OPENR2)
14389static void *mfcr2_monitor(void *data)
14390{
14391 struct dahdi_mfcr2 *mfcr2 = data;
14392 struct dahdi_pvt *pvt;
14393
14394 /* we should be using pthread_key_create
14395 and allocate pollers dynamically.
14396 I think do_monitor() could be leaking, since it
14397 could be cancelled at any time and is not
14398 using thread keys, why?, */
14399 struct pollfd pollers[ARRAY_LEN(mfcr2->pvts)];
14400 int res = 0;
14401 int i = 0;
14402 int oldstate = 0;
14403 int quit_loop = 0;
14404 int maxsleep = 20;
14405 int was_idle = 0;
14406 int pollsize = 0;
14407 /* now that we're ready to get calls, unblock our side and
14408 get current line state */
14409 for (i = 0; i < mfcr2->numchans; i++) {
14410 pvt = mfcr2->pvts[i];
14411 if (!pvt) {
14412 continue;
14413 }
14414 openr2_chan_set_idle(pvt->r2chan);
14415 openr2_chan_handle_cas(pvt->r2chan);
14416 }
14417 while (1) {
14418 /* we trust here that the mfcr2 channel list will not ever change once
14419 the module is loaded */
14420 pollsize = 0;
14421 for (i = 0; i < mfcr2->numchans; i++) {
14422 pollers[i].revents = 0;
14423 pollers[i].events = 0;
14424 pvt = mfcr2->pvts[i];
14425 if (!pvt) {
14426 continue;
14427 }
14428 if (pvt->owner) {
14429 continue;
14430 }
14431 if (mfcr2->nodev) {
14432 continue;
14433 }
14434 if (!pvt->r2chan) {
14435 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
14436 quit_loop = 1;
14437 break;
14438 }
14439 openr2_chan_enable_read(pvt->r2chan);
14440 pollers[i].events = POLLIN | POLLPRI;
14441 pollers[i].fd = pvt->subs[SUB_REAL].dfd;
14442 pollsize++;
14443 }
14444 if (quit_loop) {
14445 break;
14446 }
14447 if (pollsize == 0) {
14448 if (!was_idle) {
14449 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14450 was_idle = 1;
14451 }
14452 poll(NULL, 0, maxsleep);
14453 continue;
14454 }
14455 was_idle = 0;
14456 /* probably poll() is a valid cancel point, lets just be on the safe side
14457 by calling pthread_testcancel */
14458 pthread_testcancel();
14459 res = poll(pollers, mfcr2->numchans, maxsleep);
14460 pthread_testcancel();
14461 if ((res < 0) && (errno != EINTR)) {
14462 ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
14463 break;
14464 }
14465 /* do we want to allow to cancel while processing events? */
14466 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
14467 for (i = 0; i < mfcr2->numchans; i++) {
14468 pvt = mfcr2->pvts[i];
14469 if (!pvt) {
14470 continue;
14471 }
14472 if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
14473 openr2_chan_process_event(pvt->r2chan);
14474 }
14475 }
14476 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
14477 }
14478 ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
14479 return 0;
14480}
14481#endif /* HAVE_OPENR2 */
14482
14483#if defined(HAVE_PRI)
14484static void dahdi_pri_message(struct pri *pri, char *s)
14485{
14486 int x;
14487 int y;
14488 int dchan = -1;
14489 int span = -1;
14490 int dchancount = 0;
14491
14492 if (pri) {
14493 for (x = 0; x < NUM_SPANS; x++) {
14494 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14495 if (pris[x].pri.dchans[y]) {
14496 dchancount++;
14497 }
14498
14499 if (pris[x].pri.dchans[y] == pri) {
14500 dchan = y;
14501 }
14502 }
14503 if (dchan >= 0) {
14504 span = x;
14505 break;
14506 }
14507 dchancount = 0;
14508 }
14509 if (-1 < span) {
14510 if (1 < dchancount) {
14511 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14512 } else {
14513 ast_verbose_callid(0, "PRI Span: %d %s", span + 1, s);
14514 }
14515 } else {
14516 ast_verbose_callid(0, "PRI Span: ? %s", s);
14517 }
14518 } else {
14519 ast_verbose_callid(0, "PRI Span: ? %s", s);
14520 }
14521
14522 ast_mutex_lock(&pridebugfdlock);
14523
14524 if (pridebugfd >= 0) {
14525 if (write(pridebugfd, s, strlen(s)) < 0) {
14526 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14527 }
14528 }
14529
14530 ast_mutex_unlock(&pridebugfdlock);
14531}
14532#endif /* defined(HAVE_PRI) */
14533
14534#if defined(HAVE_PRI)
14535static void dahdi_pri_error(struct pri *pri, char *s)
14536{
14537 int x;
14538 int y;
14539 int dchan = -1;
14540 int span = -1;
14541 int dchancount = 0;
14542
14543 if (pri) {
14544 for (x = 0; x < NUM_SPANS; x++) {
14545 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14546 if (pris[x].pri.dchans[y]) {
14547 dchancount++;
14548 }
14549
14550 if (pris[x].pri.dchans[y] == pri) {
14551 dchan = y;
14552 }
14553 }
14554 if (dchan >= 0) {
14555 span = x;
14556 break;
14557 }
14558 dchancount = 0;
14559 }
14560 if (-1 < span) {
14561 if (1 < dchancount) {
14562 ast_log_callid(LOG_ERROR, 0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14563 } else {
14564 ast_log_callid(LOG_ERROR, 0, "PRI Span: %d %s", span + 1, s);
14565 }
14566 } else {
14567 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14568 }
14569 } else {
14570 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14571 }
14572
14573 ast_mutex_lock(&pridebugfdlock);
14574
14575 if (pridebugfd >= 0) {
14576 if (write(pridebugfd, s, strlen(s)) < 0) {
14577 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14578 }
14579 }
14580
14581 ast_mutex_unlock(&pridebugfdlock);
14582}
14583#endif /* defined(HAVE_PRI) */
14584
14585#if defined(HAVE_PRI)
14586static int prepare_pri(struct dahdi_pri *pri)
14587{
14588 int i, res, x;
14589 struct dahdi_params p;
14590 struct dahdi_bufferinfo bi;
14591 struct dahdi_spaninfo si;
14592
14593 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
14594 if (!pri->dchannels[i])
14595 break;
14596 if (pri->pri.fds[i] >= 0) {
14597 /* A partial range addition. Not a complete setup. */
14598 break;
14599 }
14600 pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
14601 if ((pri->pri.fds[i] < 0)) {
14602 ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
14603 pri->pri.fds[i], strerror(errno));
14604 return -1;
14605 }
14606 x = pri->dchannels[i];
14607 res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
14608 if (res) {
14609 dahdi_close_pri_fd(pri, i);
14610 ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
14611 return -1;
14612 }
14613 memset(&p, 0, sizeof(p));
14614 res = ioctl(pri->pri.fds[i], DAHDI_GET_PARAMS, &p);
14615 if (res) {
14616 dahdi_close_pri_fd(pri, i);
14617 ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
14618 return -1;
14619 }
14620 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
14621 dahdi_close_pri_fd(pri, i);
14622 ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
14623 return -1;
14624 }
14625 memset(&si, 0, sizeof(si));
14626 res = ioctl(pri->pri.fds[i], DAHDI_SPANSTAT, &si);
14627 if (res) {
14628 dahdi_close_pri_fd(pri, i);
14629 ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
14630 }
14631 if (!si.alarms) {
14632 pri_event_noalarm(&pri->pri, i, 1);
14633 } else {
14634 pri_event_alarm(&pri->pri, i, 1);
14635 }
14636 memset(&bi, 0, sizeof(bi));
14637 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
14638 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
14639 bi.numbufs = 32;
14640 bi.bufsize = 1024;
14641 if (ioctl(pri->pri.fds[i], DAHDI_SET_BUFINFO, &bi)) {
14642 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
14643 dahdi_close_pri_fd(pri, i);
14644 return -1;
14645 }
14646 pri->pri.dchan_logical_span[i] = pris[p.spanno - 1].prilogicalspan;
14647 }
14648 return 0;
14649}
14650#endif /* defined(HAVE_PRI) */
14651
14652#if defined(HAVE_PRI)
14653static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
14654{
14655 int which, span;
14656 char *ret = NULL;
14657
14658 if (pos != rpos)
14659 return ret;
14660
14661 for (which = span = 0; span < NUM_SPANS; span++) {
14662 if (pris[span].pri.pri && ++which > state) {
14663 if (ast_asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
14664 ret = NULL;
14665 }
14666 break;
14667 }
14668 }
14669 return ret;
14670}
14671#endif /* defined(HAVE_PRI) */
14672
14673#if defined(HAVE_PRI)
14674static char *complete_span_4(const char *line, const char *word, int pos, int state)
14675{
14676 return complete_span_helper(line,word,pos,state,3);
14677}
14678#endif /* defined(HAVE_PRI) */
14679
14680#if defined(HAVE_PRI)
14681static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14682{
14683 int myfd;
14684 switch (cmd) {
14685 case CLI_INIT:
14686 e->command = "pri set debug file";
14687 e->usage = "Usage: pri set debug file [output-file]\n"
14688 " Sends PRI debug output to the specified output file\n";
14689 return NULL;
14690 case CLI_GENERATE:
14691 return NULL;
14692 }
14693 if (a->argc < 5)
14694 return CLI_SHOWUSAGE;
14695
14696 if (ast_strlen_zero(a->argv[4]))
14697 return CLI_SHOWUSAGE;
14698
14699 myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
14700 if (myfd < 0) {
14701 ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
14702 return CLI_SUCCESS;
14703 }
14704
14705 ast_mutex_lock(&pridebugfdlock);
14706
14707 if (pridebugfd >= 0)
14708 close(pridebugfd);
14709
14710 pridebugfd = myfd;
14711 ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
14712 ast_mutex_unlock(&pridebugfdlock);
14713 ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
14714 return CLI_SUCCESS;
14715}
14716#endif /* defined(HAVE_PRI) */
14717
14718#if defined(HAVE_PRI)
14719static int action_pri_debug_file_set(struct mansession *s, const struct message *m)
14720{
14721 const char *output_file = astman_get_header(m, "File");
14722 int myfd;
14723
14724 if (ast_strlen_zero(output_file)) {
14725 astman_send_error(s, m, "Action must define a 'File'");
14726 }
14727
14728 myfd = open(output_file, O_CREAT|O_WRONLY, AST_FILE_MODE);
14729 if (myfd < 0) {
14730 astman_send_error(s, m, "Unable to open requested file for writing");
14731 return 0;
14732 }
14733
14734 ast_mutex_lock(&pridebugfdlock);
14735
14736 if (pridebugfd >= 0) {
14737 close(pridebugfd);
14738 }
14739
14740 pridebugfd = myfd;
14741 ast_copy_string(pridebugfilename, output_file, sizeof(pridebugfilename));
14742 ast_mutex_unlock(&pridebugfdlock);
14743 astman_send_ack(s, m, "PRI debug output will now be sent to requested file.");
14744
14745 return 0;
14746}
14747#endif /* defined(HAVE_PRI) */
14748
14749#if defined(HAVE_PRI)
14750static int action_pri_debug_file_unset(struct mansession *s, const struct message *m)
14751{
14752 ast_mutex_lock(&pridebugfdlock);
14753
14754 if (pridebugfd >= 0) {
14755 close(pridebugfd);
14756 }
14757
14758 pridebugfd = -1;
14759
14760 ast_mutex_unlock(&pridebugfdlock);
14761
14762 astman_send_ack(s, m, "PRI Debug output to file disabled");
14763 return 0;
14764}
14765#endif /* defined(HAVE_PRI) */
14766
14767#if defined(HAVE_PRI)
14768static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14769{
14770 int span;
14771 int x;
14772 int debugmask = 0;
14773 int level = 0;
14774 switch (cmd) {
14775 case CLI_INIT:
14776 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";
14777 e->usage =
14778 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14779 " Enables debugging on a given PRI span\n"
14780 " Level is a bitmap of the following values:\n"
14781 " 1 General debugging incl. state changes\n"
14782 " 2 Decoded Q.931 messages\n"
14783 " 4 Decoded Q.921 messages\n"
14784 " 8 Raw hex dumps of Q.921 frames\n"
14785 " on - equivalent to 3\n"
14786 " hex - equivalent to 8\n"
14787 " intense - equivalent to 15\n";
14788 return NULL;
14789 case CLI_GENERATE:
14790 return complete_span_4(a->line, a->word, a->pos, a->n);
14791 }
14792 if (a->argc < 6) {
14793 return CLI_SHOWUSAGE;
14794 }
14795
14796 if (!strcasecmp(a->argv[3], "on")) {
14797 level = 3;
14798 } else if (!strcasecmp(a->argv[3], "off")) {
14799 level = 0;
14800 } else if (!strcasecmp(a->argv[3], "intense")) {
14801 level = 15;
14802 } else if (!strcasecmp(a->argv[3], "hex")) {
14803 level = 8;
14804 } else {
14805 level = atoi(a->argv[3]);
14806 }
14807 span = atoi(a->argv[5]);
14808 if ((span < 1) || (span > NUM_SPANS)) {
14809 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[5], 1, NUM_SPANS);
14810 return CLI_SUCCESS;
14811 }
14812 if (!pris[span-1].pri.pri) {
14813 ast_cli(a->fd, "No PRI running on span %d\n", span);
14814 return CLI_SUCCESS;
14815 }
14816
14817 if (level & 1) debugmask |= SIG_PRI_DEBUG_NORMAL;
14818 if (level & 2) debugmask |= PRI_DEBUG_Q931_DUMP;
14819 if (level & 4) debugmask |= PRI_DEBUG_Q921_DUMP;
14820 if (level & 8) debugmask |= PRI_DEBUG_Q921_RAW;
14821
14822 /* Set debug level in libpri */
14823 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14824 if (pris[span - 1].pri.dchans[x]) {
14825 pri_set_debug(pris[span - 1].pri.dchans[x], debugmask);
14826 }
14827 }
14828 if (level == 0) {
14829 /* Close the debugging file if it's set */
14830 ast_mutex_lock(&pridebugfdlock);
14831 if (0 <= pridebugfd) {
14832 close(pridebugfd);
14833 pridebugfd = -1;
14834 ast_cli(a->fd, "Disabled PRI debug output to file '%s'\n",
14835 pridebugfilename);
14836 }
14837 ast_mutex_unlock(&pridebugfdlock);
14838 }
14839 pris[span - 1].pri.debug = (level) ? 1 : 0;
14840 ast_cli(a->fd, "%s debugging on span %d\n", (level) ? "Enabled" : "Disabled", span);
14841 return CLI_SUCCESS;
14842}
14843#endif /* defined(HAVE_PRI) */
14844
14845#if defined(HAVE_PRI)
14846static int action_pri_debug_set(struct mansession *s, const struct message *m)
14847{
14848 const char *level = astman_get_header(m, "Level");
14849 const char *span = astman_get_header(m, "Span");
14850 int level_val;
14851 int span_val;
14852 int x;
14853 int debugmask = 0;
14854
14855 if (ast_strlen_zero(level)) {
14856 astman_send_error(s, m, "'Level' was not specified");
14857 return 0;
14858 }
14859
14860 if (ast_strlen_zero(span)) {
14861 astman_send_error(s, m, "'Span' was not specified");
14862 return 0;
14863 }
14864
14865 if (!strcasecmp(level, "on")) {
14866 level_val = 3;
14867 } else if (!strcasecmp(level, "off")) {
14868 level_val = 0;
14869 } else if (!strcasecmp(level, "intense")) {
14870 level_val = 15;
14871 } else if (!strcasecmp(level, "hex")) {
14872 level_val = 8;
14873 } else {
14874 if (sscanf(level, "%30d", &level_val) != 1) {
14875 astman_send_error(s, m, "Invalid value for 'Level'");
14876 return 0;
14877 }
14878 }
14879
14880 if (sscanf(span, "%30d", &span_val) != 1) {
14881 astman_send_error(s, m, "Invalid value for 'Span'");
14882 }
14883
14884 if ((span_val < 1) || (span_val > NUM_SPANS)) {
14885 const char *id = astman_get_header(m, "ActionID");
14886 char id_text[256] = "";
14887
14888 if (!ast_strlen_zero(id)) {
14889 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
14890 }
14891
14892 astman_append(s, "Response: Error\r\n"
14893 "%s" /* id_text */
14894 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14895 "\r\n",
14896 id_text,
14897 span, NUM_SPANS);
14898
14899 return 0;
14900 }
14901
14902 if (!pris[span_val-1].pri.pri) {
14903 astman_send_error(s, m, "No PRI running on requested span");
14904 return 0;
14905 }
14906
14907 if (level_val & 1) {
14908 debugmask |= SIG_PRI_DEBUG_NORMAL;
14909 }
14910 if (level_val & 2) {
14911 debugmask |= PRI_DEBUG_Q931_DUMP;
14912 }
14913 if (level_val & 4) {
14914 debugmask |= PRI_DEBUG_Q921_DUMP;
14915 }
14916 if (level_val & 8) {
14917 debugmask |= PRI_DEBUG_Q921_RAW;
14918 }
14919
14920 /* Set debug level in libpri */
14921 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14922 if (pris[span_val - 1].pri.dchans[x]) {
14923 pri_set_debug(pris[span_val - 1].pri.dchans[x], debugmask);
14924 }
14925 }
14926
14927 pris[span_val - 1].pri.debug = (level_val) ? 1 : 0;
14928 astman_send_ack(s, m, "Debug level set for requested span");
14929
14930 return 0;
14931}
14932#endif /* defined(HAVE_PRI) */
14933
14934#if defined(HAVE_PRI)
14935#if defined(HAVE_PRI_SERVICE_MESSAGES)
14936static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
14937{
14938 unsigned *why;
14939 int channel;
14940 int trunkgroup;
14941 int x, y, fd = a->fd;
14942 int interfaceid = 0;
14943 char db_chan_name[20], db_answer[15];
14944 struct dahdi_pvt *tmp;
14945 struct dahdi_pri *pri;
14946
14947 if (a->argc < 5 || a->argc > 6)
14948 return CLI_SHOWUSAGE;
14949 if (strchr(a->argv[4], ':')) {
14950 if (sscanf(a->argv[4], "%30d:%30d", &trunkgroup, &channel) != 2)
14951 return CLI_SHOWUSAGE;
14952 if ((trunkgroup < 1) || (channel < 1))
14953 return CLI_SHOWUSAGE;
14954 pri = NULL;
14955 for (x=0;x<NUM_SPANS;x++) {
14956 if (pris[x].pri.trunkgroup == trunkgroup) {
14957 pri = pris + x;
14958 break;
14959 }
14960 }
14961 if (!pri) {
14962 ast_cli(fd, "No such trunk group %d\n", trunkgroup);
14963 return CLI_FAILURE;
14964 }
14965 } else
14966 channel = atoi(a->argv[4]);
14967
14968 if (a->argc == 6)
14969 interfaceid = atoi(a->argv[5]);
14970
14971 /* either servicing a D-Channel */
14972 for (x = 0; x < NUM_SPANS; x++) {
14973 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14974 if (pris[x].dchannels[y] == channel) {
14975 pri = pris + x;
14976 if (pri->pri.enable_service_message_support) {
14977 ast_mutex_lock(&pri->pri.lock);
14978 pri_maintenance_service(pri->pri.pri, interfaceid, -1, changestatus);
14979 ast_mutex_unlock(&pri->pri.lock);
14980 } else {
14981 ast_cli(fd,
14982 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14983 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14984 }
14985 return CLI_SUCCESS;
14986 }
14987 }
14988 }
14989
14990 /* or servicing a B-Channel */
14992 for (tmp = iflist; tmp; tmp = tmp->next) {
14993 if (tmp->pri && tmp->channel == channel) {
14995 ast_mutex_lock(&tmp->pri->lock);
14996 if (!tmp->pri->enable_service_message_support) {
14997 ast_mutex_unlock(&tmp->pri->lock);
14998 ast_cli(fd,
14999 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
15000 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
15001 return CLI_SUCCESS;
15002 }
15003 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, channel);
15004 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
15005 switch(changestatus) {
15006 case 0: /* enable */
15007 /* Near end wants to be in service now. */
15008 ast_db_del(db_chan_name, SRVST_DBKEY);
15009 *why &= ~SRVST_NEAREND;
15010 if (*why) {
15011 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
15012 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
15013 } else {
15014 dahdi_pri_update_span_devstate(tmp->pri);
15015 }
15016 break;
15017 /* case 1: -- loop */
15018 case 2: /* disable */
15019 /* Near end wants to be out-of-service now. */
15020 ast_db_del(db_chan_name, SRVST_DBKEY);
15021 *why |= SRVST_NEAREND;
15022 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
15023 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
15024 dahdi_pri_update_span_devstate(tmp->pri);
15025 break;
15026 /* case 3: -- continuity */
15027 /* case 4: -- shutdown */
15028 default:
15029 ast_log(LOG_WARNING, "Unsupported changestatus: '%d'\n", changestatus);
15030 break;
15031 }
15032 pri_maintenance_bservice(tmp->pri->pri, tmp->sig_pvt, changestatus);
15033 ast_mutex_unlock(&tmp->pri->lock);
15034 return CLI_SUCCESS;
15035 }
15036 }
15038
15039 ast_cli(fd, "Unable to find given channel %d, possibly not a PRI\n", channel);
15040 return CLI_FAILURE;
15041}
15042
15043static char *handle_pri_service_enable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15044{
15045 switch (cmd) {
15046 case CLI_INIT:
15047 e->command = "pri service enable channel";
15048 e->usage =
15049 "Usage: pri service enable channel <channel> [<interface id>]\n"
15050 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15051 " to restore a channel to service, with optional interface id\n"
15052 " as agreed upon with remote switch operator\n";
15053 return NULL;
15054 case CLI_GENERATE:
15055 return NULL;
15056 }
15057 return handle_pri_service_generic(e, cmd, a, 0);
15058}
15059
15060static char *handle_pri_service_disable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15061{
15062 switch (cmd) {
15063 case CLI_INIT:
15064 e->command = "pri service disable channel";
15065 e->usage =
15066 "Usage: pri service disable channel <chan num> [<interface id>]\n"
15067 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15068 " to remove a channel from service, with optional interface id\n"
15069 " as agreed upon with remote switch operator\n";
15070 return NULL;
15071 case CLI_GENERATE:
15072 return NULL;
15073 }
15074 return handle_pri_service_generic(e, cmd, a, 2);
15075}
15076#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15077#endif /* defined(HAVE_PRI) */
15078
15079#if defined(HAVE_PRI)
15080static char *handle_pri_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15081{
15082 int span;
15083
15084 switch (cmd) {
15085 case CLI_INIT:
15086 e->command = "pri show channels";
15087 e->usage =
15088 "Usage: pri show channels\n"
15089 " Displays PRI channel information such as the current mapping\n"
15090 " of DAHDI B channels to Asterisk channel names and which calls\n"
15091 " are on hold or call-waiting. Calls on hold or call-waiting\n"
15092 " are not associated with any B channel.\n";
15093 return NULL;
15094 case CLI_GENERATE:
15095 return NULL;
15096 }
15097
15098 if (a->argc != 3)
15099 return CLI_SHOWUSAGE;
15100
15102 for (span = 0; span < NUM_SPANS; ++span) {
15103 if (pris[span].pri.pri) {
15104 sig_pri_cli_show_channels(a->fd, &pris[span].pri);
15105 }
15106 }
15107 return CLI_SUCCESS;
15108}
15109#endif /* defined(HAVE_PRI) */
15110
15111#if defined(HAVE_PRI)
15112static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15113{
15114 int span;
15115
15116 switch (cmd) {
15117 case CLI_INIT:
15118 e->command = "pri show spans";
15119 e->usage =
15120 "Usage: pri show spans\n"
15121 " Displays PRI span information\n";
15122 return NULL;
15123 case CLI_GENERATE:
15124 return NULL;
15125 }
15126
15127 if (a->argc != 3)
15128 return CLI_SHOWUSAGE;
15129
15130 for (span = 0; span < NUM_SPANS; span++) {
15131 if (pris[span].pri.pri) {
15132 sig_pri_cli_show_spans(a->fd, span + 1, &pris[span].pri);
15133 }
15134 }
15135 return CLI_SUCCESS;
15136}
15137#endif /* defined(HAVE_PRI) */
15138
15139#if defined(HAVE_PRI)
15140#define container_of(ptr, type, member) \
15141 ((type *)((char *)(ptr) - offsetof(type, member)))
15142/*!
15143 * \internal
15144 * \brief Destroy a D-Channel of a PRI span
15145 * \since 12
15146 *
15147 * \param pri the pri span
15148 *
15149 * Shuts down a span and destroys its D-Channel. Further destruction
15150 * of the B-channels using dahdi_destroy_channel() would probably be required
15151 * for the B-Channels.
15152 */
15153static void pri_destroy_span(struct sig_pri_span *pri)
15154{
15155 int i;
15156 int res;
15157 int cancel_code;
15158 struct dahdi_pri* dahdi_pri;
15159 pthread_t master = pri->master;
15160
15161 if (!master || (master == AST_PTHREADT_NULL)) {
15162 return;
15163 }
15164 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
15165 for (i = 0; i < pri->numchans; i++) {
15166 int channel;
15167 struct sig_pri_chan *pvt = pri->pvts[i];
15168
15169 if (!pvt) {
15170 continue;
15171 }
15172 channel = pvt->channel;
15173 ast_debug(2, "About to destroy B-channel %d.\n", channel);
15175 }
15176
15177 cancel_code = pthread_cancel(master);
15178 pthread_kill(master, SIGURG);
15179 ast_debug(4,
15180 "Waiting to join thread of span %d "
15181 "with pid=%p cancel_code=%d\n",
15182 pri->span, (void *)master, cancel_code);
15183 res = pthread_join(master, NULL);
15184 if (res != 0) {
15185 ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
15186 }
15188
15189 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
15190 dahdi_pri = container_of(pri, struct dahdi_pri, pri);
15191 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
15192 ast_debug(4, "closing pri_fd %d\n", i);
15193 dahdi_close_pri_fd(dahdi_pri, i);
15194 dahdi_pri->dchannels[i] = 0;
15195 }
15197 ast_debug(1, "PRI span %d destroyed\n", pri->span);
15198}
15199
15200static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
15201 struct ast_cli_args *a)
15202{
15203 int span;
15204 int res;
15205 struct sig_pri_span *pri;
15206
15207 switch (cmd) {
15208 case CLI_INIT:
15209 e->command = "pri destroy span";
15210 e->usage =
15211 "Usage: pri destroy span <span>\n"
15212 " Destroys D-channel of span and its B-channels.\n"
15213 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15214 return NULL;
15215 case CLI_GENERATE:
15216 return complete_span_4(a->line, a->word, a->pos, a->n);
15217 }
15218
15219 if (a->argc < 4) {
15220 return CLI_SHOWUSAGE;
15221 }
15222 res = sscanf(a->argv[3], "%30d", &span);
15223 if ((res != 1) || span < 1 || span > NUM_SPANS) {
15224 ast_cli(a->fd,
15225 "Invalid span '%s'. Should be a number from %d to %d\n",
15226 a->argv[3], 1, NUM_SPANS);
15227 return CLI_SUCCESS;
15228 }
15229 pri = &pris[span - 1].pri;
15230 if (!pri->pri) {
15231 ast_cli(a->fd, "No PRI running on span %d\n", span);
15232 return CLI_SUCCESS;
15233 }
15234
15235 pri_destroy_span(pri);
15236 return CLI_SUCCESS;
15237}
15238
15239#endif /* defined(HAVE_PRI) */
15240
15241#if defined(HAVE_PRI)
15242static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15243{
15244 int span;
15245
15246 switch (cmd) {
15247 case CLI_INIT:
15248 e->command = "pri show span";
15249 e->usage =
15250 "Usage: pri show span <span>\n"
15251 " Displays PRI Information on a given PRI span\n";
15252 return NULL;
15253 case CLI_GENERATE:
15254 return complete_span_4(a->line, a->word, a->pos, a->n);
15255 }
15256
15257 if (a->argc < 4)
15258 return CLI_SHOWUSAGE;
15259 span = atoi(a->argv[3]);
15260 if ((span < 1) || (span > NUM_SPANS)) {
15261 ast_cli(a->fd, "Invalid span '%s'. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
15262 return CLI_SUCCESS;
15263 }
15264 if (!pris[span-1].pri.pri) {
15265 ast_cli(a->fd, "No PRI running on span %d\n", span);
15266 return CLI_SUCCESS;
15267 }
15268
15269 sig_pri_cli_show_span(a->fd, pris[span-1].dchannels, &pris[span-1].pri);
15270
15271 return CLI_SUCCESS;
15272}
15273#endif /* defined(HAVE_PRI) */
15274
15275#if defined(HAVE_PRI)
15276static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15277{
15278 int x;
15279 int span;
15280 int count=0;
15281 int debug;
15282
15283 switch (cmd) {
15284 case CLI_INIT:
15285 e->command = "pri show debug";
15286 e->usage =
15287 "Usage: pri show debug\n"
15288 " Show the debug state of pri spans\n";
15289 return NULL;
15290 case CLI_GENERATE:
15291 return NULL;
15292 }
15293
15294 for (span = 0; span < NUM_SPANS; span++) {
15295 if (pris[span].pri.pri) {
15296 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
15297 if (pris[span].pri.dchans[x]) {
15298 debug = pri_get_debug(pris[span].pri.dchans[x]);
15299 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" );
15300 count++;
15301 }
15302 }
15303 }
15304
15305 }
15306 ast_mutex_lock(&pridebugfdlock);
15307 if (pridebugfd >= 0)
15308 ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
15309 ast_mutex_unlock(&pridebugfdlock);
15310
15311 if (!count)
15312 ast_cli(a->fd, "No PRI running\n");
15313 return CLI_SUCCESS;
15314}
15315#endif /* defined(HAVE_PRI) */
15316
15317#if defined(HAVE_PRI)
15318static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15319{
15320 switch (cmd) {
15321 case CLI_INIT:
15322 e->command = "pri show version";
15323 e->usage =
15324 "Usage: pri show version\n"
15325 "Show libpri version information\n";
15326 return NULL;
15327 case CLI_GENERATE:
15328 return NULL;
15329 }
15330
15331 ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
15332
15333 return CLI_SUCCESS;
15334}
15335#endif /* defined(HAVE_PRI) */
15336
15337#if defined(HAVE_PRI)
15338static struct ast_cli_entry dahdi_pri_cli[] = {
15339 AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
15340#if defined(HAVE_PRI_SERVICE_MESSAGES)
15341 AST_CLI_DEFINE(handle_pri_service_enable_channel, "Return a channel to service"),
15342 AST_CLI_DEFINE(handle_pri_service_disable_channel, "Remove a channel from service"),
15343#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15344 AST_CLI_DEFINE(handle_pri_show_channels, "Displays PRI channel information"),
15345 AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI span information"),
15346 AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI span information"),
15347 AST_CLI_DEFINE(handle_pri_destroy_span, "Destroy a PRI span"),
15348 AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
15349 AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
15350 AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
15351};
15352#endif /* defined(HAVE_PRI) */
15353
15354#ifdef HAVE_OPENR2
15355
15356static char *handle_mfcr2_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15357{
15358 switch (cmd) {
15359 case CLI_INIT:
15360 e->command = "mfcr2 show version";
15361 e->usage =
15362 "Usage: mfcr2 show version\n"
15363 " Shows the version of the OpenR2 library being used.\n";
15364 return NULL;
15365 case CLI_GENERATE:
15366 return NULL;
15367 }
15368 ast_cli(a->fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15369 return CLI_SUCCESS;
15370}
15371
15372static char *handle_mfcr2_show_variants(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15373{
15374#define FORMAT "%4s %40s\n"
15375 int i = 0;
15376 int numvariants = 0;
15377 const openr2_variant_entry_t *variants;
15378 switch (cmd) {
15379 case CLI_INIT:
15380 e->command = "mfcr2 show variants";
15381 e->usage =
15382 "Usage: mfcr2 show variants\n"
15383 " Shows the list of MFC/R2 variants supported.\n";
15384 return NULL;
15385 case CLI_GENERATE:
15386 return NULL;
15387 }
15388 if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
15389 ast_cli(a->fd, "Failed to get list of variants.\n");
15390 return CLI_FAILURE;
15391 }
15392 ast_cli(a->fd, FORMAT, "Variant Code", "Country");
15393 for (i = 0; i < numvariants; i++) {
15394 ast_cli(a->fd, FORMAT, variants[i].name, variants[i].country);
15395 }
15396 return CLI_SUCCESS;
15397#undef FORMAT
15398}
15399
15400static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15401{
15402#define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15403 int filtertype = 0;
15404 int targetnum = 0;
15405 char channo[5];
15406 char linkno[5];
15407 char anino[5];
15408 char dnisno[5];
15409 struct dahdi_pvt *p;
15410 openr2_context_t *r2context;
15411 openr2_variant_t r2variant;
15412 switch (cmd) {
15413 case CLI_INIT:
15414 e->command = "mfcr2 show channels [group|context]";
15415 e->usage =
15416 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15417 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15418 return NULL;
15419 case CLI_GENERATE:
15420 return NULL;
15421 }
15422 if (!((a->argc == 3) || (a->argc == 5))) {
15423 return CLI_SHOWUSAGE;
15424 }
15425 if (a->argc == 5) {
15426 if (!strcasecmp(a->argv[3], "group")) {
15427 targetnum = atoi(a->argv[4]);
15428 if ((targetnum < 0) || (targetnum > 63))
15429 return CLI_SHOWUSAGE;
15430 targetnum = 1 << targetnum;
15431 filtertype = 1;
15432 } else if (!strcasecmp(a->argv[3], "context")) {
15433 filtertype = 2;
15434 } else {
15435 return CLI_SHOWUSAGE;
15436 }
15437 }
15438 ast_cli(a->fd, FORMAT, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15440 for (p = iflist; p; p = p->next) {
15441 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15442 continue;
15443 }
15444 if (filtertype) {
15445 switch(filtertype) {
15446 case 1: /* mfcr2 show channels group <group> */
15447 if (p->group != targetnum) {
15448 continue;
15449 }
15450 break;
15451 case 2: /* mfcr2 show channels context <context> */
15452 if (strcasecmp(p->context, a->argv[4])) {
15453 continue;
15454 }
15455 break;
15456 default:
15457 ;
15458 }
15459 }
15460 r2context = openr2_chan_get_context(p->r2chan);
15461 r2variant = openr2_context_get_variant(r2context);
15462 snprintf(channo, sizeof(channo), "%d", p->channel);
15463 snprintf(linkno, sizeof(linkno), "%d", p->mfcr2->index);
15464 snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
15465 snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
15466 ast_cli(a->fd, FORMAT, channo, linkno, openr2_proto_get_variant_string(r2variant),
15467 anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
15468 openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
15469 openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
15470 }
15472 return CLI_SUCCESS;
15473#undef FORMAT
15474}
15475
15476static char *handle_mfcr2_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15477{
15478 struct dahdi_pvt *p = NULL;
15479 int channo = 0;
15480 char *toklevel = NULL;
15481 char *saveptr = NULL;
15482 char *logval = NULL;
15483 openr2_log_level_t loglevel = OR2_LOG_NOTHING;
15484 openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
15485 switch (cmd) {
15486 case CLI_INIT:
15487 e->command = "mfcr2 set debug";
15488 e->usage =
15489 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15490 " Set a new logging level for the specified channel.\n"
15491 " If no channel is specified the logging level will be applied to all channels.\n";
15492 return NULL;
15493 case CLI_GENERATE:
15494 return NULL;
15495 }
15496 if (a->argc < 4) {
15497 return CLI_SHOWUSAGE;
15498 }
15499 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15500 logval = ast_strdupa(a->argv[3]);
15501 toklevel = strtok_r(logval, ",", &saveptr);
15502 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15503 ast_cli(a->fd, "Invalid MFC/R2 logging level '%s'.\n", a->argv[3]);
15504 return CLI_FAILURE;
15505 } else if (OR2_LOG_NOTHING == tmplevel) {
15506 loglevel = tmplevel;
15507 } else {
15508 loglevel |= tmplevel;
15509 while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
15510 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15511 ast_cli(a->fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
15512 continue;
15513 }
15514 loglevel |= tmplevel;
15515 }
15516 }
15518 for (p = iflist; p; p = p->next) {
15519 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15520 continue;
15521 }
15522 if ((channo != -1) && (p->channel != channo )) {
15523 continue;
15524 }
15525 openr2_chan_set_log_level(p->r2chan, loglevel);
15526 if (channo != -1) {
15527 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for channel %d.\n", a->argv[3], p->channel);
15528 break;
15529 }
15530 }
15531 if ((channo != -1) && !p) {
15532 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15533 }
15534 if (channo == -1) {
15535 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for all channels.\n", a->argv[3]);
15536 }
15538 return CLI_SUCCESS;
15539}
15540
15541static char *handle_mfcr2_call_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15542{
15543 struct dahdi_pvt *p = NULL;
15544 int channo = 0;
15545 switch (cmd) {
15546 case CLI_INIT:
15547 e->command = "mfcr2 call files [on|off]";
15548 e->usage =
15549 "Usage: mfcr2 call files [on|off] <channel>\n"
15550 " Enable call files creation on the specified channel.\n"
15551 " If no channel is specified call files creation policy will be applied to all channels.\n";
15552 return NULL;
15553 case CLI_GENERATE:
15554 return NULL;
15555 }
15556 if (a->argc < 4) {
15557 return CLI_SHOWUSAGE;
15558 }
15559 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15561 for (p = iflist; p; p = p->next) {
15562 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15563 continue;
15564 }
15565 if ((channo != -1) && (p->channel != channo )) {
15566 continue;
15567 }
15568 if (ast_true(a->argv[3])) {
15569 openr2_chan_enable_call_files(p->r2chan);
15570 } else {
15571 openr2_chan_disable_call_files(p->r2chan);
15572 }
15573 if (channo != -1) {
15574 if (ast_true(a->argv[3])) {
15575 ast_cli(a->fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
15576 } else {
15577 ast_cli(a->fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
15578 }
15579 break;
15580 }
15581 }
15582 if ((channo != -1) && !p) {
15583 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15584 }
15585 if (channo == -1) {
15586 if (ast_true(a->argv[3])) {
15587 ast_cli(a->fd, "MFC/R2 Call files enabled for all channels.\n");
15588 } else {
15589 ast_cli(a->fd, "MFC/R2 Call files disabled for all channels.\n");
15590 }
15591 }
15593 return CLI_SUCCESS;
15594}
15595
15596static char *handle_mfcr2_set_idle(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15597{
15598 struct dahdi_pvt *p = NULL;
15599 int channo = 0;
15600 switch (cmd) {
15601 case CLI_INIT:
15602 e->command = "mfcr2 set idle";
15603 e->usage =
15604 "Usage: mfcr2 set idle <channel>\n"
15605 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15606 " Force the given channel into IDLE state.\n"
15607 " If no channel is specified, all channels will be set to IDLE.\n";
15608 return NULL;
15609 case CLI_GENERATE:
15610 return NULL;
15611 }
15612 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15614 for (p = iflist; p; p = p->next) {
15615 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15616 continue;
15617 }
15618 if ((channo != -1) && (p->channel != channo )) {
15619 continue;
15620 }
15621 openr2_chan_set_idle(p->r2chan);
15622 ast_mutex_lock(&p->lock);
15623 p->locallyblocked = 0;
15624 p->mfcr2call = 0;
15626 if (channo != -1) {
15627 break;
15628 }
15629 }
15630 if ((channo != -1) && !p) {
15631 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15632 }
15634 return CLI_SUCCESS;
15635}
15636
15637static char *handle_mfcr2_set_blocked(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15638{
15639 struct dahdi_pvt *p = NULL;
15640 int channo = 0;
15641 switch (cmd) {
15642 case CLI_INIT:
15643 e->command = "mfcr2 set blocked";
15644 e->usage =
15645 "Usage: mfcr2 set blocked <channel>\n"
15646 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15647 " Force the given channel into BLOCKED state.\n"
15648 " If no channel is specified, all channels will be set to BLOCKED.\n";
15649 return NULL;
15650 case CLI_GENERATE:
15651 return NULL;
15652 }
15653 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15655 for (p = iflist; p; p = p->next) {
15656 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15657 continue;
15658 }
15659 if ((channo != -1) && (p->channel != channo )) {
15660 continue;
15661 }
15662 openr2_chan_set_blocked(p->r2chan);
15663 ast_mutex_lock(&p->lock);
15664 p->locallyblocked = 1;
15666 if (channo != -1) {
15667 break;
15668 }
15669 }
15670 if ((channo != -1) && !p) {
15671 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15672 }
15674 return CLI_SUCCESS;
15675}
15676
15677static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_head, const char *title)
15678{
15679#define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15680 AST_LIST_LOCK(list_head);
15681 if (! AST_LIST_EMPTY(list_head)) {
15682 int x = 0;
15683 char index[5];
15684 char live_chans_str[5];
15685 char channel_list[R2_LINK_CAPACITY * 4];
15686 struct r2link_entry *cur;
15687 ast_cli(a->fd, "%s\n", title);
15688 ast_cli(a->fd, FORMAT, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15689 AST_LIST_TRAVERSE(list_head, cur, list) {
15690 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15691 const char *thread_status = NULL;
15692 int i;
15693 int len;
15694 int inside_range;
15695 int channo;
15696 int prev_channo;
15697 x++;
15698 if (mfcr2->r2master == 0L) {
15699 thread_status = "zero";
15700 } else if (mfcr2->r2master == AST_PTHREADT_NULL) {
15701 thread_status = "none";
15702 } else {
15703 thread_status = "created";
15704 }
15705 snprintf(index, sizeof(index), "%d", mfcr2->index);
15706 snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
15707 channo = 0;
15708 prev_channo = 0;
15709 inside_range = 0;
15710 len = 0;
15711 /* Prepare nice string in channel_list[] */
15712 for (i = 0; i < mfcr2->numchans && len < sizeof(channel_list) - 1; i++) {
15713 struct dahdi_pvt *p = mfcr2->pvts[i];
15714 if (!p) {
15715 continue;
15716 }
15717 channo = p->channel;
15718 /* Don't show a range until we know the last channel number */
15719 if (prev_channo && prev_channo == channo - 1) {
15720 prev_channo = channo;
15721 inside_range = 1;
15722 continue;
15723 }
15724 if (inside_range) {
15725 /* Close range */
15726 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d,%d", prev_channo, channo);
15727 inside_range = 0;
15728 } else if (prev_channo) {
15729 /* Non-sequential channel numbers */
15730 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15731 } else {
15732 /* First channel number */
15733 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "%d", channo);
15734 }
15735 prev_channo = channo;
15736 }
15737 /* Handle leftover channels */
15738 if (inside_range) {
15739 /* Close range */
15740 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d", channo);
15741 inside_range = 0;
15742 } else if (prev_channo) {
15743 /* Non-sequential channel numbers */
15744 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15745 }
15746 // channel_list[len] = '\0';
15747 ast_cli(a->fd, FORMAT,
15748 index,
15749 thread_status,
15750 (mfcr2->nodev) ? "MISSING" : "OK",
15751 live_chans_str,
15752 channel_list);
15753 }
15754 }
15755 AST_LIST_UNLOCK(list_head);
15756#undef FORMAT
15757}
15758
15759static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15760{
15761 switch (cmd) {
15762 case CLI_INIT:
15763 e->command = "mfcr2 show links";
15764 e->usage =
15765 "Usage: mfcr2 show links\n"
15766 " Shows the DAHDI MFC/R2 links.\n";
15767 return NULL;
15768 case CLI_GENERATE:
15769 return NULL;
15770 }
15771 if (a->argc != 3) {
15772 return CLI_SHOWUSAGE;
15773 }
15774 mfcr2_show_links_of(a, &r2links, "Live links\n");
15775 mfcr2_show_links_of(a, &nodev_r2links, "Links to be removed (device missing)\n");
15776 return CLI_SUCCESS;
15777}
15778
15779static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15780{
15781 int res;
15782 int wanted_link_index;
15783 int found_link = 0;
15784 struct r2link_entry *cur = NULL;
15785
15786 switch (cmd) {
15787 case CLI_INIT:
15788 e->command = "mfcr2 destroy link";
15789 e->usage =
15790 "Usage: mfcr2 destroy link <index-number>\n"
15791 " Destroys D-channel of link and its B-channels.\n"
15792 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15793 return NULL;
15794 case CLI_GENERATE:
15795 return NULL;
15796 }
15797 if (a->argc < 4) {
15798 return CLI_SHOWUSAGE;
15799 }
15800 res = sscanf(a->argv[3], "%30d", &wanted_link_index);
15801 if ((res != 1) || wanted_link_index < 1) {
15802 ast_cli(a->fd,
15803 "Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
15804 return CLI_SUCCESS;
15805 }
15806 AST_LIST_LOCK(&r2links);
15807 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
15808 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15809 if (wanted_link_index == mfcr2->index) {
15810 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
15811 r2links_count--;
15812 break;
15813 }
15814 }
15816 AST_LIST_UNLOCK(&r2links);
15817 if (! found_link) {
15818 ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
15819 return CLI_FAILURE;
15820 }
15821 return CLI_SUCCESS;
15822}
15823
15824static struct ast_cli_entry dahdi_mfcr2_cli[] = {
15825 AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
15826 AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
15827 AST_CLI_DEFINE(handle_mfcr2_show_channels, "Show MFC/R2 channels"),
15828 AST_CLI_DEFINE(handle_mfcr2_show_links, "Show MFC/R2 links"),
15829 AST_CLI_DEFINE(handle_mfcr2_set_debug, "Set MFC/R2 channel logging level"),
15830 AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
15831 AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
15832 AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
15833 AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
15834};
15835
15836#endif /* HAVE_OPENR2 */
15837
15838static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15839{
15840 int start;
15841 int end;
15842 switch (cmd) {
15843 case CLI_INIT:
15844 e->command = "dahdi destroy channels";
15845 e->usage =
15846 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15847 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15848 return NULL;
15849 case CLI_GENERATE:
15850 return NULL;
15851 }
15852 if ((a->argc < 4) || a->argc > 5) {
15853 return CLI_SHOWUSAGE;
15854 }
15855 start = atoi(a->argv[3]);
15856 if (start < 1) {
15857 ast_cli(a->fd, "Invalid starting channel number %s.\n",
15858 a->argv[4]);
15859 return CLI_FAILURE;
15860 }
15861 if (a->argc == 5) {
15862 end = atoi(a->argv[4]);
15863 if (end < 1) {
15864 ast_cli(a->fd, "Invalid ending channel number %s.\n",
15865 a->argv[4]);
15866 return CLI_FAILURE;
15867 }
15868 } else {
15869 end = start;
15870 }
15871
15872 if (end < start) {
15873 ast_cli(a->fd,
15874 "range end (%d) is smaller than range start (%d)\n",
15875 end, start);
15876 return CLI_FAILURE;
15877 }
15879 return CLI_SUCCESS;
15880}
15881
15882static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15883{
15884 int start;
15885 int end;
15886 int ret;
15887
15888 switch (cmd) {
15889 case CLI_INIT:
15890 e->command = "dahdi create channels";
15891 e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15892 " dahdi create channels new - add channels not yet created\n"
15893 "For ISDN and SS7 the range should include complete spans.\n";
15894 return NULL;
15895 case CLI_GENERATE:
15896 return NULL;
15897 }
15898 if ((a->argc < 4) || a->argc > 5) {
15899 return CLI_SHOWUSAGE;
15900 }
15901 if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
15902 ret = dahdi_create_channel_range(0, 0);
15903 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15904 }
15905 start = atoi(a->argv[3]);
15906 if (start <= 0) {
15907 ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
15908 a->argv[3]);
15909 return CLI_FAILURE;
15910 }
15911 if (a->argc == 5) {
15912 end = atoi(a->argv[4]);
15913 if (end <= 0) {
15914 ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
15915 a->argv[4]);
15916 return CLI_FAILURE;
15917 }
15918 } else {
15919 end = start;
15920 }
15921 if (end < start) {
15922 ast_cli(a->fd,
15923 "range end (%d) is smaller than range start (%d)\n",
15924 end, start);
15925 return CLI_FAILURE;
15926 }
15927 ret = dahdi_create_channel_range(start, end);
15928 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15929}
15930
15931static void dahdi_softhangup_all(void)
15932{
15933 struct dahdi_pvt *p;
15934retry:
15936 for (p = iflist; p; p = p->next) {
15937 ast_mutex_lock(&p->lock);
15938 if (p->owner && !p->restartpending) {
15939 if (ast_channel_trylock(p->owner)) {
15940 if (DEBUG_ATLEAST(3))
15941 ast_verbose("Avoiding deadlock\n");
15942 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15945 goto retry;
15946 }
15947 if (DEBUG_ATLEAST(3))
15948 ast_verbose("Softhanging up on %s\n", ast_channel_name(p->owner));
15950 p->restartpending = 1;
15953 }
15955 }
15957}
15958
15959static int dahdi_restart(void)
15960{
15961#if defined(HAVE_PRI) || defined(HAVE_SS7)
15962 int i, j;
15963#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15964 int cancel_code;
15965 struct dahdi_pvt *p;
15966
15968 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15970 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15971#ifdef HAVE_OPENR2
15972 dahdi_r2_destroy_links();
15973#endif
15974
15975#if defined(HAVE_PRI)
15976 for (i = 0; i < NUM_SPANS; i++) {
15977 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
15978 cancel_code = pthread_cancel(pris[i].pri.master);
15979 pthread_kill(pris[i].pri.master, SIGURG);
15980 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);
15981 pthread_join(pris[i].pri.master, NULL);
15982 ast_debug(4, "Joined thread of span %d\n", i);
15983 }
15984 }
15985#endif
15986
15987#if defined(HAVE_SS7)
15988 for (i = 0; i < NUM_SPANS; i++) {
15989 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
15990 cancel_code = pthread_cancel(linksets[i].ss7.master);
15991 pthread_kill(linksets[i].ss7.master, SIGURG);
15992 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);
15993 pthread_join(linksets[i].ss7.master, NULL);
15994 ast_debug(4, "Joined thread of span %d\n", i);
15995 }
15996 }
15997#endif /* defined(HAVE_SS7) */
15998
16001 cancel_code = pthread_cancel(monitor_thread);
16002 pthread_kill(monitor_thread, SIGURG);
16003 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
16004 pthread_join(monitor_thread, NULL);
16005 ast_debug(4, "Joined monitor thread\n");
16006 }
16007 monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
16008
16010 while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
16011 int x = DAHDI_FLASH;
16012 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count);
16013
16015 for (p = iflist; p; p = p->next) {
16016 if (p->owner) {
16017 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
16018 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
16019 }
16020 }
16023 }
16024
16025 /* ensure any created channels before monitor threads were stopped are hungup */
16027 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
16029 memset(round_robin, 0, sizeof(round_robin));
16030 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
16031
16033
16034#ifdef HAVE_PRI
16035 for (i = 0; i < NUM_SPANS; i++) {
16036 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++)
16037 dahdi_close_pri_fd(&(pris[i]), j);
16038 }
16039
16040 memset(pris, 0, sizeof(pris));
16041 for (i = 0; i < NUM_SPANS; i++) {
16042 sig_pri_init_pri(&pris[i].pri);
16043 }
16044 pri_set_error(dahdi_pri_error);
16045 pri_set_message(dahdi_pri_message);
16046#endif
16047#if defined(HAVE_SS7)
16048 for (i = 0; i < NUM_SPANS; i++) {
16049 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++)
16050 dahdi_close_ss7_fd(&(linksets[i]), j);
16051 }
16052
16053 memset(linksets, 0, sizeof(linksets));
16054 for (i = 0; i < NUM_SPANS; i++) {
16055 sig_ss7_init_linkset(&linksets[i].ss7);
16056 }
16057 ss7_set_error(dahdi_ss7_error);
16058 ss7_set_message(dahdi_ss7_message);
16059 ss7_set_hangup(sig_ss7_cb_hangup);
16060 ss7_set_notinservice(sig_ss7_cb_notinservice);
16061 ss7_set_call_null(sig_ss7_cb_call_null);
16062#endif /* defined(HAVE_SS7) */
16063
16064 if (setup_dahdi(2) != 0) {
16065 ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
16067 return 1;
16068 }
16071 return 0;
16072}
16073
16074static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16075{
16076 switch (cmd) {
16077 case CLI_INIT:
16078 e->command = "dahdi restart";
16079 e->usage =
16080 "Usage: dahdi restart\n"
16081 " Restarts the DAHDI channels: destroys them all and then\n"
16082 " re-reads them from chan_dahdi.conf.\n"
16083 " Note that this will STOP any running CALL on DAHDI channels.\n"
16084 "";
16085 return NULL;
16086 case CLI_GENERATE:
16087 return NULL;
16088 }
16089 if (a->argc != 2)
16090 return CLI_SHOWUSAGE;
16091
16092 if (dahdi_restart() != 0)
16093 return CLI_FAILURE;
16094 return CLI_SUCCESS;
16095}
16096
16097static int action_dahdirestart(struct mansession *s, const struct message *m)
16098{
16099 if (dahdi_restart() != 0) {
16100 astman_send_error(s, m, "Failed rereading DAHDI configuration");
16101 return 1;
16102 }
16103 astman_send_ack(s, m, "DAHDIRestart: Success");
16104 return 0;
16105}
16106
16107static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16108{
16109#define FORMAT "%7s %4d %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16110#define FORMAT2 "%7s %4s %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16111 ast_group_t targetnum = 0;
16112 int filtertype = 0;
16113 struct dahdi_pvt *tmp = NULL;
16114 char tmps[20];
16115 char blockstr[20];
16116
16117 switch (cmd) {
16118 case CLI_INIT:
16119 e->command = "dahdi show channels [group|context]";
16120 e->usage =
16121 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
16122 " Shows a list of available channels with optional filtering\n"
16123 " <group> must be a number between 0 and 63\n";
16124 return NULL;
16125 case CLI_GENERATE:
16126 return NULL;
16127 }
16128
16129 /* syntax: dahdi show channels [ group <group> | context <context> ] */
16130
16131 if (!((a->argc == 3) || (a->argc == 5))) {
16132 return CLI_SHOWUSAGE;
16133 }
16134
16135 if (a->argc == 5) {
16136 if (!strcasecmp(a->argv[3], "group")) {
16137 targetnum = atoi(a->argv[4]);
16138 if (63 < targetnum) {
16139 return CLI_SHOWUSAGE;
16140 }
16141 targetnum = ((ast_group_t) 1) << targetnum;
16142 filtertype = 1;
16143 } else if (!strcasecmp(a->argv[3], "context")) {
16144 filtertype = 2;
16145 }
16146 }
16147
16148 ast_cli(a->fd, FORMAT2, "Chan", "Span", "Signalling", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Alarms", "Description");
16150 for (tmp = iflist; tmp; tmp = tmp->next) {
16151 int alm = 0;
16152 if (filtertype) {
16153 switch(filtertype) {
16154 case 1: /* dahdi show channels group <group> */
16155 if (!(tmp->group & targetnum)) {
16156 continue;
16157 }
16158 break;
16159 case 2: /* dahdi show channels context <context> */
16160 if (strcasecmp(tmp->context, a->argv[4])) {
16161 continue;
16162 }
16163 break;
16164 default:
16165 break;
16166 }
16167 }
16168 if (tmp->channel > 0) {
16169 snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
16170 alm = get_alarms(tmp);
16171 } else {
16172 ast_copy_string(tmps, "pseudo", sizeof(tmps));
16173 }
16174
16175 blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
16176 blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
16177 blockstr[2] = '\0';
16178
16179 ast_cli(a->fd, FORMAT, tmps, tmp->span, sig2str(tmp->sig), tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No",
16180 alarm2str(alm), tmp->description);
16181 }
16183 return CLI_SUCCESS;
16184#undef FORMAT
16185#undef FORMAT2
16186}
16187
16188static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16189{
16190 int channel;
16191 struct dahdi_pvt *tmp = NULL;
16192 struct dahdi_confinfo ci;
16193 struct dahdi_params ps;
16194 int x;
16195 char hwrxgain[15];
16196 char hwtxgain[15];
16197
16198 switch (cmd) {
16199 case CLI_INIT:
16200 e->command = "dahdi show channel";
16201 e->usage =
16202 "Usage: dahdi show channel <chan num>\n"
16203 " Detailed information about a given channel\n";
16204 return NULL;
16205 case CLI_GENERATE:
16206 return NULL;
16207 }
16208
16209 if (a->argc != 4)
16210 return CLI_SHOWUSAGE;
16211
16212 channel = atoi(a->argv[3]);
16213
16215 for (tmp = iflist; tmp; tmp = tmp->next) {
16216 if (tmp->channel == channel) {
16217 ast_cli(a->fd, "Channel: %d\n", tmp->channel);
16218 ast_cli(a->fd, "Description: %s\n", tmp->description);
16219 ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
16220 ast_cli(a->fd, "Span: %d\n", tmp->span);
16221 ast_cli(a->fd, "Extension: %s\n", tmp->exten);
16222 ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
16223 ast_cli(a->fd, "Context: %s\n", tmp->context);
16224 ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
16225 ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
16226#if defined(HAVE_PRI)
16227#if defined(HAVE_PRI_SUBADDR)
16228 ast_cli(a->fd, "Caller ID subaddress: %s\n", tmp->cid_subaddr);
16229#endif /* defined(HAVE_PRI_SUBADDR) */
16230#endif /* defined(HAVE_PRI) */
16231 ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
16232 ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
16233 if (tmp->vars) {
16234 struct ast_variable *v;
16235 ast_cli(a->fd, "Variables:\n");
16236 for (v = tmp->vars ; v ; v = v->next)
16237 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
16238 }
16239 ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
16240 ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
16241 ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
16242 ast_cli(a->fd, "Radio: %d\n", tmp->radio);
16243 ast_cli(a->fd, "Owner: %s\n", tmp->owner ? ast_channel_name(tmp->owner) : "<None>");
16244 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)" : "");
16245 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)" : "");
16246 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)" : "");
16247 ast_cli(a->fd, "Confno: %d\n", tmp->confno);
16248 ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
16249 ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
16250 ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
16251 ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
16252 if (tmp->busydetect) {
16253#if defined(BUSYDETECT_TONEONLY)
16254 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16255#elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16256 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16257#endif
16258#ifdef BUSYDETECT_DEBUG
16259 ast_cli(a->fd, " Busy Detector Debug: Enabled\n");
16260#endif
16261 ast_cli(a->fd, " Busy Count: %d\n", tmp->busycount);
16262 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);
16263 }
16264 ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
16265 ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
16266 ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
16267 ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
16268 ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
16269 ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
16270 if (tmp->hwrxgain_enabled) {
16271 snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
16272 } else {
16273 ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
16274 }
16275 if (tmp->hwtxgain_enabled) {
16276 snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
16277 } else {
16278 ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
16279 }
16280 ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
16281 ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
16282 ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
16283 ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
16284 ast_cli(a->fd, "Echo Cancellation:\n");
16285
16286 if (tmp->echocancel.head.tap_length) {
16287 ast_cli(a->fd, "\t%u taps\n", tmp->echocancel.head.tap_length);
16288 for (x = 0; x < tmp->echocancel.head.param_count; x++) {
16289 ast_cli(a->fd, "\t\t%s: %dd\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
16290 }
16291 ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
16292 } else {
16293 ast_cli(a->fd, "\tnone\n");
16294 }
16295 ast_cli(a->fd, "Wait for dialtone: %dms\n", tmp->waitfordialtone);
16296 if (tmp->master)
16297 ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
16298 for (x = 0; x < MAX_SLAVES; x++) {
16299 if (tmp->slaves[x])
16300 ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
16301 }
16302#ifdef HAVE_OPENR2
16303 if (tmp->mfcr2) {
16304 char calldir[OR2_MAX_PATH];
16305 openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
16306 openr2_variant_t r2variant = openr2_context_get_variant(r2context);
16307 ast_cli(a->fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
16308 ast_cli(a->fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
16309 ast_cli(a->fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
16310 ast_cli(a->fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
16311 ast_cli(a->fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
16312 ast_cli(a->fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
16313 ast_cli(a->fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
16314 ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
16315#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16316 ast_cli(a->fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
16317 ast_cli(a->fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
16318#endif
16319 ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
16320#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16321 ast_cli(a->fd, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
16322#endif
16323 ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
16324 ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
16325 ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
16326 ast_cli(a->fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
16327 ast_cli(a->fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
16328 ast_cli(a->fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
16329 ast_cli(a->fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
16330 ast_cli(a->fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
16331 ast_cli(a->fd, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
16332 ast_cli(a->fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
16333 ast_cli(a->fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
16334 ast_cli(a->fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
16335 }
16336#endif
16337#if defined(HAVE_SS7)
16338 if (tmp->ss7) {
16339 struct sig_ss7_chan *chan = tmp->sig_pvt;
16340
16341 ast_cli(a->fd, "CIC: %d\n", chan->cic);
16342 }
16343#endif /* defined(HAVE_SS7) */
16344#ifdef HAVE_PRI
16345 if (tmp->pri) {
16346 struct sig_pri_chan *chan = tmp->sig_pvt;
16347
16348 ast_cli(a->fd, "PRI Flags: ");
16349 if (chan->resetting != SIG_PRI_RESET_IDLE) {
16350 ast_cli(a->fd, "Resetting=%u ", chan->resetting);
16351 }
16352 if (chan->call)
16353 ast_cli(a->fd, "Call ");
16354 if (chan->allocated) {
16355 ast_cli(a->fd, "Allocated ");
16356 }
16357 ast_cli(a->fd, "\n");
16358 if (tmp->logicalspan)
16359 ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
16360 else
16361 ast_cli(a->fd, "PRI Logical Span: Implicit\n");
16362 }
16363#endif
16364 memset(&ci, 0, sizeof(ci));
16365 ps.channo = tmp->channel;
16366 if (tmp->subs[SUB_REAL].dfd > -1) {
16367 memset(&ci, 0, sizeof(ci));
16368 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
16369 ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, (unsigned)ci.confmode);
16370 }
16371 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
16372 ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
16373 }
16374 memset(&ps, 0, sizeof(ps));
16375 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
16376 ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
16377 } else {
16378 ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
16379 }
16380 }
16382 return CLI_SUCCESS;
16383 }
16384 }
16386
16387 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16388 return CLI_FAILURE;
16389}
16390
16391static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16392{
16393 int i, j;
16394 switch (cmd) {
16395 case CLI_INIT:
16396 e->command = "dahdi show cadences";
16397 e->usage =
16398 "Usage: dahdi show cadences\n"
16399 " Shows all cadences currently defined\n";
16400 return NULL;
16401 case CLI_GENERATE:
16402 return NULL;
16403 }
16404 for (i = 0; i < num_cadence; i++) {
16405 char output[1024];
16406 char tmp[16], tmp2[64];
16407 snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
16408 term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
16409
16410 for (j = 0; j < 16; j++) {
16411 if (cadences[i].ringcadence[j] == 0)
16412 break;
16413 snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
16414 if (cidrings[i] * 2 - 1 == j)
16415 term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
16416 else
16417 term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
16418 if (j != 0)
16419 strncat(output, ",", sizeof(output) - strlen(output) - 1);
16420 strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
16421 }
16422 ast_cli(a->fd,"%s\n",output);
16423 }
16424 return CLI_SUCCESS;
16425}
16426
16427static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
16428{
16429 alarmstr[0] = '\0';
16430 if (spaninfo->alarms > 0) {
16431 if (spaninfo->alarms & DAHDI_ALARM_BLUE) {
16432 strcat(alarmstr, "BLU/");
16433 }
16434 if (spaninfo->alarms & DAHDI_ALARM_YELLOW) {
16435 strcat(alarmstr, "YEL/");
16436 }
16437 if (spaninfo->alarms & DAHDI_ALARM_RED) {
16438 strcat(alarmstr, "RED/");
16439 }
16440 if (spaninfo->alarms & DAHDI_ALARM_LOOPBACK) {
16441 strcat(alarmstr, "LB/");
16442 }
16443 if (spaninfo->alarms & DAHDI_ALARM_RECOVER) {
16444 strcat(alarmstr, "REC/");
16445 }
16446 if (spaninfo->alarms & DAHDI_ALARM_NOTOPEN) {
16447 strcat(alarmstr, "NOP/");
16448 }
16449 if (!strlen(alarmstr)) {
16450 strcat(alarmstr, "UUU/");
16451 }
16452 if (strlen(alarmstr)) {
16453 /* Strip trailing / */
16454 alarmstr[strlen(alarmstr) - 1] = '\0';
16455 }
16456 } else {
16457 if (spaninfo->numchans) {
16458 strcpy(alarmstr, "OK");
16459 } else {
16460 strcpy(alarmstr, "UNCONFIGURED");
16461 }
16462 }
16463}
16464
16465/* Based on irqmiss.c */
16466static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16467{
16468 #define FORMAT "%4d %-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16469 #define FORMAT2 "%4s %-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16470 int span;
16471 int res;
16472 char alarmstr[50];
16473
16474 int ctl;
16475 struct dahdi_spaninfo s;
16476
16477 switch (cmd) {
16478 case CLI_INIT:
16479 e->command = "dahdi show status";
16480 e->usage =
16481 "Usage: dahdi show status\n"
16482 " Shows a list of DAHDI cards with status\n";
16483 return NULL;
16484 case CLI_GENERATE:
16485 return NULL;
16486 }
16487 ctl = open("/dev/dahdi/ctl", O_RDWR);
16488 if (ctl < 0) {
16489 ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
16490 return CLI_FAILURE;
16491 }
16492 ast_cli(a->fd, FORMAT2, "Span", "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16493
16494 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
16495 s.spanno = span;
16496 res = ioctl(ctl, DAHDI_SPANSTAT, &s);
16497 if (res) {
16498 continue;
16499 }
16500 build_alarm_info(alarmstr, &s);
16501 ast_cli(a->fd, FORMAT, span, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count,
16502 s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
16503 s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
16504 s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
16505 "CAS",
16506 s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
16507 s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
16508 s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
16509 "Unknown",
16510 s.lineconfig & DAHDI_CONFIG_CRC4 ?
16511 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
16512 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
16513 lbostr[s.lbo]
16514 );
16515 }
16516 close(ctl);
16517
16518 return CLI_SUCCESS;
16519#undef FORMAT
16520#undef FORMAT2
16521}
16522
16523static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16524{
16525 int pseudo_fd = -1;
16526 struct dahdi_versioninfo vi;
16527
16528 switch (cmd) {
16529 case CLI_INIT:
16530 e->command = "dahdi show version";
16531 e->usage =
16532 "Usage: dahdi show version\n"
16533 " Shows the DAHDI version in use\n";
16534 return NULL;
16535 case CLI_GENERATE:
16536 return NULL;
16537 }
16538 if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
16539 ast_cli(a->fd, "Failed to open control file to get version.\n");
16540 return CLI_SUCCESS;
16541 }
16542
16543 strcpy(vi.version, "Unknown");
16544 strcpy(vi.echo_canceller, "Unknown");
16545
16546 if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
16547 ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
16548 else
16549 ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
16550
16551 close(pseudo_fd);
16552
16553 return CLI_SUCCESS;
16554}
16555
16556static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16557{
16558 int channel;
16559 float gain;
16560 int tx;
16561 struct dahdi_pvt *tmp = NULL;
16562
16563 switch (cmd) {
16564 case CLI_INIT:
16565 e->command = "dahdi set hwgain {rx|tx}";
16566 e->usage =
16567 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16568 " Sets the hardware gain on a given channel and overrides the\n"
16569 " value provided at module loadtime. Changes take effect\n"
16570 " immediately whether the channel is in use or not.\n"
16571 "\n"
16572 " <rx|tx> which direction do you want to change (relative to our module)\n"
16573 " <chan num> is the channel number relative to the device\n"
16574 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16575 "\n"
16576 " Please note:\n"
16577 " * hwgain is only supportable by hardware with analog ports because\n"
16578 " hwgain works on the analog side of an analog-digital conversion.\n";
16579 return NULL;
16580 case CLI_GENERATE:
16581 return NULL;
16582 }
16583
16584 if (a->argc != 6)
16585 return CLI_SHOWUSAGE;
16586
16587 if (!strcasecmp("rx", a->argv[3]))
16588 tx = 0; /* rx */
16589 else if (!strcasecmp("tx", a->argv[3]))
16590 tx = 1; /* tx */
16591 else
16592 return CLI_SHOWUSAGE;
16593
16594 channel = atoi(a->argv[4]);
16595 gain = atof(a->argv[5]);
16596
16598
16599 for (tmp = iflist; tmp; tmp = tmp->next) {
16600
16601 if (tmp->channel != channel)
16602 continue;
16603
16604 if (tmp->subs[SUB_REAL].dfd == -1)
16605 break;
16606
16607 if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
16608 ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
16610 return CLI_FAILURE;
16611 }
16612 ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
16613 tx ? "tx" : "rx", gain, channel);
16614
16615 if (tx) {
16616 tmp->hwtxgain_enabled = 1;
16617 tmp->hwtxgain = gain;
16618 } else {
16619 tmp->hwrxgain_enabled = 1;
16620 tmp->hwrxgain = gain;
16621 }
16622 break;
16623 }
16624
16626
16627 if (tmp)
16628 return CLI_SUCCESS;
16629
16630 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16631 return CLI_FAILURE;
16632
16633}
16634
16635static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16636{
16637 int channel;
16638 float gain;
16639 int tx;
16640 int res;
16641 struct dahdi_pvt *tmp = NULL;
16642
16643 switch (cmd) {
16644 case CLI_INIT:
16645 e->command = "dahdi set swgain {rx|tx}";
16646 e->usage =
16647 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16648 " Sets the software gain on a given channel and overrides the\n"
16649 " value provided at module loadtime. Changes take effect\n"
16650 " immediately whether the channel is in use or not.\n"
16651 "\n"
16652 " <rx|tx> which direction do you want to change (relative to our module)\n"
16653 " <chan num> is the channel number relative to the device\n"
16654 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16655 return NULL;
16656 case CLI_GENERATE:
16657 return NULL;
16658 }
16659
16660 if (a->argc != 6)
16661 return CLI_SHOWUSAGE;
16662
16663 if (!strcasecmp("rx", a->argv[3]))
16664 tx = 0; /* rx */
16665 else if (!strcasecmp("tx", a->argv[3]))
16666 tx = 1; /* tx */
16667 else
16668 return CLI_SHOWUSAGE;
16669
16670 channel = atoi(a->argv[4]);
16671 gain = atof(a->argv[5]);
16672
16674 for (tmp = iflist; tmp; tmp = tmp->next) {
16675
16676 if (tmp->channel != channel)
16677 continue;
16678
16679 if (tmp->subs[SUB_REAL].dfd == -1)
16680 break;
16681
16682 if (tx)
16683 res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, gain, tmp->txdrc, tmp->law);
16684 else
16685 res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, gain, tmp->rxdrc, tmp->law);
16686
16687 if (res) {
16688 ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
16690 return CLI_FAILURE;
16691 }
16692
16693 ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
16694 tx ? "tx" : "rx", gain, channel);
16695
16696 if (tx) {
16697 tmp->txgain = gain;
16698 } else {
16699 tmp->rxgain = gain;
16700 }
16701 break;
16702 }
16704
16705 if (tmp)
16706 return CLI_SUCCESS;
16707
16708 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16709 return CLI_FAILURE;
16710
16711}
16712
16713static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16714{
16715 int channel;
16716 int on;
16717 struct dahdi_pvt *dahdi_chan = NULL;
16718
16719 switch (cmd) {
16720 case CLI_INIT:
16721 e->command = "dahdi set dnd";
16722 e->usage =
16723 "Usage: dahdi set dnd <chan#> <on|off>\n"
16724 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16725 " Changes take effect immediately.\n"
16726 " <chan num> is the channel number\n"
16727 " <on|off> Enable or disable DND mode?\n"
16728 ;
16729 return NULL;
16730 case CLI_GENERATE:
16731 return NULL;
16732 }
16733
16734 if (a->argc != 5)
16735 return CLI_SHOWUSAGE;
16736
16737 if ((channel = atoi(a->argv[3])) <= 0) {
16738 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16739 return CLI_SHOWUSAGE;
16740 }
16741
16742 if (ast_true(a->argv[4]))
16743 on = 1;
16744 else if (ast_false(a->argv[4]))
16745 on = 0;
16746 else {
16747 ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
16748 return CLI_SHOWUSAGE;
16749 }
16750
16752 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16753 if (dahdi_chan->channel != channel)
16754 continue;
16755
16756 /* Found the channel. Actually set it */
16757 dahdi_dnd(dahdi_chan, on);
16758 break;
16759 }
16761
16762 if (!dahdi_chan) {
16763 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16764 return CLI_FAILURE;
16765 }
16766
16767 return CLI_SUCCESS;
16768}
16769
16770static char *dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16771{
16772 int channel;
16773 int on;
16774 int override = 1;
16775 struct dahdi_pvt *dahdi_chan = NULL;
16776
16777 switch (cmd) {
16778 case CLI_INIT:
16779 e->command = "dahdi set mwi";
16780 e->usage =
16781 "Usage: dahdi set mwi <chan#> <on|off|reset>\n"
16782 " Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
16783 " This may be used regardless of whether the channel is assigned any mailboxes.\n"
16784 " When active, this setting will override the voicemail status to set MWI.\n"
16785 " Once cleared, the voicemail status will resume control of MWI.\n"
16786 " Changes are queued for when the channel is idle and persist until cleared.\n"
16787 " <chan num> is the channel number\n"
16788 " <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
16789 ;
16790 return NULL;
16791 case CLI_GENERATE:
16792 return NULL;
16793 }
16794
16795 if (a->argc != 5)
16796 return CLI_SHOWUSAGE;
16797
16798 if ((channel = atoi(a->argv[3])) <= 0) {
16799 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16800 return CLI_SHOWUSAGE;
16801 }
16802
16803 if (ast_true(a->argv[4])) {
16804 on = 1;
16805 } else if (ast_false(a->argv[4])) {
16806 on = 0;
16807 } else if (!strcmp(a->argv[4], "reset")) {
16808 override = 0;
16809 } else {
16810 ast_cli(a->fd, "Expected 'on' or 'off' or 'reset', got '%s'\n", a->argv[4]);
16811 return CLI_SHOWUSAGE;
16812 }
16813
16815 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16816 if (dahdi_chan->channel != channel)
16817 continue;
16818
16819 /* Found the channel. Actually set it */
16820 if (override) {
16821 dahdi_chan->mwioverride_disposition = on;
16822 ast_cli(a->fd, "MWI '%s' queued for channel %d\n", on ? "enable" : "disable", channel);
16823 }
16824 dahdi_chan->mwioverride_active = override;
16825 /* The do_monitor thread will take care of actually sending the MWI
16826 * at an appropriate time for the channel. */
16827 break;
16828 }
16830
16831 if (!dahdi_chan) {
16832 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16833 return CLI_FAILURE;
16834 }
16835
16836 return CLI_SUCCESS;
16837}
16838
16839static struct ast_cli_entry dahdi_cli[] = {
16841 AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
16842 AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
16843 AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
16844 AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
16845 AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
16846 AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
16847 AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
16848 AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
16849 AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
16850 AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16851 AST_CLI_DEFINE(dahdi_set_mwi, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
16852};
16853
16854#define TRANSFER 0
16855#define HANGUP 1
16856
16857static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
16858{
16859 if (p) {
16860 switch (mode) {
16861 case TRANSFER:
16862 p->fake_event = DAHDI_EVENT_WINKFLASH;
16863 break;
16864 case HANGUP:
16865 p->fake_event = DAHDI_EVENT_ONHOOK;
16866 break;
16867 default:
16868 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));
16869 }
16870 }
16871 return 0;
16872}
16873static struct dahdi_pvt *find_channel(int channel)
16874{
16875 struct dahdi_pvt *p;
16876
16878 for (p = iflist; p; p = p->next) {
16879 if (p->channel == channel) {
16880 break;
16881 }
16882 }
16884 return p;
16885}
16886
16887/*!
16888 * \internal
16889 * \brief Get private struct using given numeric channel string.
16890 *
16891 * \param channel Numeric channel number string get private struct.
16892 *
16893 * \retval pvt on success.
16894 * \retval NULL on error.
16895 */
16896static struct dahdi_pvt *find_channel_from_str(const char *channel)
16897{
16898 int chan_num;
16899
16900 if (sscanf(channel, "%30d", &chan_num) != 1) {
16901 /* Not numeric string. */
16902 return NULL;
16903 }
16904
16905 return find_channel(chan_num);
16906}
16907
16908static int action_dahdidndon(struct mansession *s, const struct message *m)
16909{
16910 struct dahdi_pvt *p;
16911 const char *channel = astman_get_header(m, "DAHDIChannel");
16912
16913 if (ast_strlen_zero(channel)) {
16914 astman_send_error(s, m, "No channel specified");
16915 return 0;
16916 }
16918 if (!p) {
16919 astman_send_error(s, m, "No such channel");
16920 return 0;
16921 }
16922 dahdi_dnd(p, 1);
16923 astman_send_ack(s, m, "DND Enabled");
16924 return 0;
16925}
16926
16927static int action_dahdidndoff(struct mansession *s, const struct message *m)
16928{
16929 struct dahdi_pvt *p;
16930 const char *channel = astman_get_header(m, "DAHDIChannel");
16931
16932 if (ast_strlen_zero(channel)) {
16933 astman_send_error(s, m, "No channel specified");
16934 return 0;
16935 }
16937 if (!p) {
16938 astman_send_error(s, m, "No such channel");
16939 return 0;
16940 }
16941 dahdi_dnd(p, 0);
16942 astman_send_ack(s, m, "DND Disabled");
16943 return 0;
16944}
16945
16946static int action_transfer(struct mansession *s, const struct message *m)
16947{
16948 struct dahdi_pvt *p;
16949 const char *channel = astman_get_header(m, "DAHDIChannel");
16950
16951 if (ast_strlen_zero(channel)) {
16952 astman_send_error(s, m, "No channel specified");
16953 return 0;
16954 }
16956 if (!p) {
16957 astman_send_error(s, m, "No such channel");
16958 return 0;
16959 }
16960 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
16961 astman_send_error(s, m, "Channel signaling is not analog");
16962 return 0;
16963 }
16965 astman_send_ack(s, m, "DAHDITransfer");
16966 return 0;
16967}
16968
16969static int action_transferhangup(struct mansession *s, const struct message *m)
16970{
16971 struct dahdi_pvt *p;
16972 const char *channel = astman_get_header(m, "DAHDIChannel");
16973
16974 if (ast_strlen_zero(channel)) {
16975 astman_send_error(s, m, "No channel specified");
16976 return 0;
16977 }
16979 if (!p) {
16980 astman_send_error(s, m, "No such channel");
16981 return 0;
16982 }
16983 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
16984 astman_send_error(s, m, "Channel signaling is not analog");
16985 return 0;
16986 }
16988 astman_send_ack(s, m, "DAHDIHangup");
16989 return 0;
16990}
16991
16992static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
16993{
16994 struct dahdi_pvt *p;
16995 const char *channel = astman_get_header(m, "DAHDIChannel");
16996 const char *number = astman_get_header(m, "Number");
16997 int i;
16998
16999 if (ast_strlen_zero(channel)) {
17000 astman_send_error(s, m, "No channel specified");
17001 return 0;
17002 }
17003 if (ast_strlen_zero(number)) {
17004 astman_send_error(s, m, "No number specified");
17005 return 0;
17006 }
17008 if (!p) {
17009 astman_send_error(s, m, "No such channel");
17010 return 0;
17011 }
17012 if (!p->owner) {
17013 astman_send_error(s, m, "Channel does not have it's owner");
17014 return 0;
17015 }
17016 for (i = 0; i < strlen(number); i++) {
17017 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = number[i] };
17018 dahdi_queue_frame(p, &f);
17019 }
17020 astman_send_ack(s, m, "DAHDIDialOffhook");
17021 return 0;
17022}
17023
17024static int action_dahdishowchannels(struct mansession *s, const struct message *m)
17025{
17026 struct dahdi_pvt *tmp = NULL;
17027 const char *id = astman_get_header(m, "ActionID");
17028 const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
17029 char idText[256];
17030 int channels = 0;
17031 int dahdichanquery;
17032
17033 if (!dahdichannel || sscanf(dahdichannel, "%30d", &dahdichanquery) != 1) {
17034 /* Not numeric string. */
17035 dahdichanquery = -1;
17036 }
17037
17038 idText[0] = '\0';
17039 if (!ast_strlen_zero(id)) {
17040 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17041 }
17042
17043 astman_send_listack(s, m, "DAHDI channel status will follow", "start");
17044
17046
17047 for (tmp = iflist; tmp; tmp = tmp->next) {
17048 if (tmp->channel > 0) {
17049 int alm;
17050
17051 /* If a specific channel is queried for, only deliver status for that channel */
17052 if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
17053 continue;
17054
17055 alm = get_alarms(tmp);
17056 channels++;
17057 if (tmp->owner) {
17058 /* Add data if we have a current call */
17059 astman_append(s,
17060 "Event: DAHDIShowChannels\r\n"
17061 "DAHDIChannel: %d\r\n"
17062 "Channel: %s\r\n"
17063 "Uniqueid: %s\r\n"
17064 "AccountCode: %s\r\n"
17065 "Signalling: %s\r\n"
17066 "SignallingCode: %d\r\n"
17067 "Context: %s\r\n"
17068 "DND: %s\r\n"
17069 "Alarm: %s\r\n"
17070 "Description: %s\r\n"
17071 "%s"
17072 "\r\n",
17073 tmp->channel,
17074 ast_channel_name(tmp->owner),
17077 sig2str(tmp->sig),
17078 tmp->sig,
17079 tmp->context,
17080 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17081 alarm2str(alm),
17082 tmp->description, idText);
17083 } else {
17084 astman_append(s,
17085 "Event: DAHDIShowChannels\r\n"
17086 "DAHDIChannel: %d\r\n"
17087 "Signalling: %s\r\n"
17088 "SignallingCode: %d\r\n"
17089 "Context: %s\r\n"
17090 "DND: %s\r\n"
17091 "Alarm: %s\r\n"
17092 "Description: %s\r\n"
17093 "%s"
17094 "\r\n",
17095 tmp->channel, sig2str(tmp->sig), tmp->sig,
17096 tmp->context,
17097 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17098 alarm2str(alm),
17099 tmp->description, idText);
17100 }
17101 }
17102 }
17103
17105
17106 astman_send_list_complete_start(s, m, "DAHDIShowChannelsComplete", channels);
17107 astman_append(s, "Items: %d\r\n", channels);
17109 return 0;
17110}
17111
17112static int action_dahdishowstatus(struct mansession *s, const struct message *m)
17113{
17114 const char *id = astman_get_header(m, "ActionID");
17115 int span;
17116 int res;
17117 char alarmstr[50];
17118 int ctl;
17119 char idText[256];
17120 int numspans = 0;
17121 struct dahdi_spaninfo spaninfo;
17122
17123 ctl = open("/dev/dahdi/ctl", O_RDWR);
17124 if (ctl < 0) {
17125 astman_send_error(s, m, "No DAHDI detected");
17126 return 0;
17127 }
17128
17129 idText[0] = '\0';
17130 if (!ast_strlen_zero(id)) {
17131 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17132 }
17133 astman_send_listack(s, m, "DAHDI span statuses will follow", "start");
17134
17135 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
17136 spaninfo.spanno = span;
17137 res = ioctl(ctl, DAHDI_SPANSTAT, &spaninfo);
17138 if (res) {
17139 continue;
17140 }
17141 numspans++;
17142 build_alarm_info(alarmstr, &spaninfo);
17143 astman_append(s,
17144 "Event: DAHDIShowStatus\r\n"
17145 "Span: %d\r\n"
17146 "Description: %s\r\n"
17147 "Alarms: %s\r\n"
17148 "IRQ: %d\r\n"
17149 "bpviol: %d\r\n"
17150 "CRC: %d\r\n"
17151 "Framing: %s\r\n"
17152 "Coding: %s\r\n"
17153 "Options: %s\r\n"
17154 "LBO: %s\r\n"
17155 "%s"
17156 "\r\n",
17157 span, spaninfo.desc, alarmstr, spaninfo.irqmisses, spaninfo.bpvcount, spaninfo.crc4count,
17158 spaninfo.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
17159 spaninfo.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
17160 spaninfo.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
17161 "CAS",
17162 spaninfo.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
17163 spaninfo.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
17164 spaninfo.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
17165 "Unk",
17166 spaninfo.lineconfig & DAHDI_CONFIG_CRC4 ?
17167 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
17168 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
17169 lbostr[spaninfo.lbo],
17170 idText);
17171 }
17172 close(ctl);
17173
17174 astman_send_list_complete_start(s, m, "DAHDIShowStatusComplete", numspans);
17175 astman_append(s, "Items: %d\r\n", numspans);
17177 return 0;
17178}
17179
17180#if defined(HAVE_PRI)
17181static int action_prishowspans(struct mansession *s, const struct message *m)
17182{
17183 int count;
17184 int idx;
17185 int span_query;
17186 struct dahdi_pri *dspan;
17187 const char *id = astman_get_header(m, "ActionID");
17188 const char *span_str = astman_get_header(m, "Span");
17189 char action_id[256];
17190 const char *show_cmd = "PRIShowSpans";
17191
17192 /* NOTE: Asking for span 0 gets all spans. */
17193 if (!ast_strlen_zero(span_str)) {
17194 span_query = atoi(span_str);
17195 } else {
17196 span_query = 0;
17197 }
17198
17199 if (!ast_strlen_zero(id)) {
17200 snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
17201 } else {
17202 action_id[0] = '\0';
17203 }
17204
17205 astman_send_listack(s, m, "Span status will follow", "start");
17206
17207 count = 0;
17208 for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
17209 dspan = &pris[idx];
17210
17211 /* If a specific span is asked for, only deliver status for that span. */
17212 if (0 < span_query && dspan->pri.span != span_query) {
17213 continue;
17214 }
17215
17216 if (dspan->pri.pri) {
17217 count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
17218 action_id);
17219 }
17220 }
17221
17222 astman_send_list_complete_start(s, m, "PRIShowSpansComplete", count);
17223 astman_append(s, "Items: %d\r\n", count);
17225 return 0;
17226}
17227#endif /* defined(HAVE_PRI) */
17228
17229#if defined(HAVE_SS7)
17230static int linkset_addsigchan(int sigchan)
17231{
17232 struct dahdi_ss7 *link;
17233 int res;
17234 int curfd;
17235 struct dahdi_params params;
17236 struct dahdi_bufferinfo bi;
17237 struct dahdi_spaninfo si;
17238
17239 if (sigchan < 0) {
17240 ast_log(LOG_ERROR, "Invalid sigchan!\n");
17241 return -1;
17242 }
17243 if (cur_ss7type < 0) {
17244 ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
17245 return -1;
17246 }
17247 if (cur_pointcode < 0) {
17248 ast_log(LOG_ERROR, "Unspecified pointcode!\n");
17249 return -1;
17250 }
17251 if (cur_adjpointcode < 0) {
17252 ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
17253 return -1;
17254 }
17255 if (cur_defaultdpc < 0) {
17256 ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
17257 return -1;
17258 }
17259 if (cur_networkindicator < 0) {
17260 ast_log(LOG_ERROR, "Invalid networkindicator!\n");
17261 return -1;
17262 }
17263 link = ss7_resolve_linkset(cur_linkset);
17264 if (!link) {
17265 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
17266 return -1;
17267 }
17268 if (link->ss7.numsigchans >= SIG_SS7_NUM_DCHANS) {
17269 ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
17270 return -1;
17271 }
17272
17273 curfd = link->ss7.numsigchans;
17274
17275 /* Open signaling channel */
17276 link->ss7.fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
17277 if (link->ss7.fds[curfd] < 0) {
17278 ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan,
17279 strerror(errno));
17280 return -1;
17281 }
17282 if (ioctl(link->ss7.fds[curfd], DAHDI_SPECIFY, &sigchan) == -1) {
17283 dahdi_close_ss7_fd(link, curfd);
17284 ast_log(LOG_ERROR, "Unable to specify SS7 sigchan %d (%s)\n", sigchan,
17285 strerror(errno));
17286 return -1;
17287 }
17288
17289 /* Get signaling channel parameters */
17290 memset(&params, 0, sizeof(params));
17291 res = ioctl(link->ss7.fds[curfd], DAHDI_GET_PARAMS, &params);
17292 if (res) {
17293 dahdi_close_ss7_fd(link, curfd);
17294 ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan,
17295 strerror(errno));
17296 return -1;
17297 }
17298 if (params.sigtype != DAHDI_SIG_HDLCFCS
17299 && params.sigtype != DAHDI_SIG_HARDHDLC
17300 && params.sigtype != DAHDI_SIG_MTP2) {
17301 dahdi_close_ss7_fd(link, curfd);
17302 ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
17303 return -1;
17304 }
17305
17306 /* Set signaling channel buffer policy. */
17307 memset(&bi, 0, sizeof(bi));
17308 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
17309 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
17310 bi.numbufs = 32;
17311 bi.bufsize = 512;
17312 if (ioctl(link->ss7.fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
17313 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n",
17314 sigchan, strerror(errno));
17315 dahdi_close_ss7_fd(link, curfd);
17316 return -1;
17317 }
17318
17319 /* Get current signaling channel alarm status. */
17320 memset(&si, 0, sizeof(si));
17321 res = ioctl(link->ss7.fds[curfd], DAHDI_SPANSTAT, &si);
17322 if (res) {
17323 dahdi_close_ss7_fd(link, curfd);
17324 ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan,
17325 strerror(errno));
17326 }
17327
17328 res = sig_ss7_add_sigchan(&link->ss7, curfd, cur_ss7type,
17329 (params.sigtype == DAHDI_SIG_MTP2)
17330 ? SS7_TRANSPORT_DAHDIMTP2
17331 : SS7_TRANSPORT_DAHDIDCHAN,
17332 si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
17333 if (res) {
17334 dahdi_close_ss7_fd(link, curfd);
17335 return -1;
17336 }
17337
17338 ++link->ss7.numsigchans;
17339
17340 return 0;
17341}
17342#endif /* defined(HAVE_SS7) */
17343
17344#if defined(HAVE_SS7)
17345static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17346{
17347 int span;
17348 switch (cmd) {
17349 case CLI_INIT:
17350 e->command = "ss7 set debug {on|off} linkset";
17351 e->usage =
17352 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
17353 " Enables debugging on a given SS7 linkset\n";
17354 return NULL;
17355 case CLI_GENERATE:
17356 return NULL;
17357 }
17358
17359 if (a->argc < 6) {
17360 return CLI_SHOWUSAGE;
17361 }
17362
17363 span = atoi(a->argv[5]);
17364 if ((span < 1) || (span > NUM_SPANS)) {
17365 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
17366 return CLI_SUCCESS;
17367 }
17368 if (!linksets[span-1].ss7.ss7) {
17369 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
17370 } else {
17371 if (!strcasecmp(a->argv[3], "on")) {
17372 linksets[span - 1].ss7.debug = 1;
17373 ss7_set_debug(linksets[span-1].ss7.ss7, SIG_SS7_DEBUG);
17374 ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
17375 } else {
17376 linksets[span - 1].ss7.debug = 0;
17377 ss7_set_debug(linksets[span-1].ss7.ss7, 0);
17378 ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
17379 }
17380 }
17381
17382 return CLI_SUCCESS;
17383}
17384#endif /* defined(HAVE_SS7) */
17385
17386#if defined(HAVE_SS7)
17387static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17388{
17389 int linkset, cic;
17390 int blocked, i;
17391 int do_block = 0;
17392 unsigned int dpc;
17393
17394 switch (cmd) {
17395 case CLI_INIT:
17396 e->command = "ss7 {block|unblock} cic";
17397 e->usage =
17398 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17399 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17400 return NULL;
17401 case CLI_GENERATE:
17402 return NULL;
17403 }
17404
17405 if (a->argc == 6) {
17406 linkset = atoi(a->argv[3]);
17407 } else {
17408 return CLI_SHOWUSAGE;
17409 }
17410
17411 if (!strcasecmp(a->argv[1], "block")) {
17412 do_block = 1;
17413 } else if (strcasecmp(a->argv[1], "unblock")) {
17414 return CLI_SHOWUSAGE;
17415 }
17416
17417 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17418 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17419 return CLI_SUCCESS;
17420 }
17421
17422 if (!linksets[linkset-1].ss7.ss7) {
17423 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17424 return CLI_SUCCESS;
17425 }
17426
17427 cic = atoi(a->argv[5]);
17428 if (cic < 1) {
17429 ast_cli(a->fd, "Invalid CIC specified!\n");
17430 return CLI_SUCCESS;
17431 }
17432
17433 dpc = atoi(a->argv[4]);
17434 if (dpc < 1) {
17435 ast_cli(a->fd, "Invalid DPC specified!\n");
17436 return CLI_SUCCESS;
17437 }
17438
17439 for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
17440 if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
17441 blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
17442 if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
17443 if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
17444 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17445 } else {
17446 ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
17447 }
17448 } else if (!do_block && blocked) {
17449 ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
17450 } else {
17451 ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
17452 }
17453 return CLI_SUCCESS;
17454 }
17455 }
17456
17457 ast_cli(a->fd, "Invalid CIC specified!\n");
17458 return CLI_SUCCESS;
17459}
17460#endif /* defined(HAVE_SS7) */
17461
17462#if defined(HAVE_SS7)
17463static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17464{
17465 int linkset, i;
17466 enum {
17467 DO_BLOCK,
17468 DO_UNBLOCK,
17469 DO_RESET,
17470 } do_what;
17471
17472 switch (cmd) {
17473 case CLI_INIT:
17474 e->command = "ss7 {reset|block|unblock} linkset";
17475 e->usage =
17476 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17477 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17478 return NULL;
17479 case CLI_GENERATE:
17480 return NULL;
17481 }
17482
17483 if (a->argc == 4) {
17484 linkset = atoi(a->argv[3]);
17485 } else {
17486 return CLI_SHOWUSAGE;
17487 }
17488
17489 if (!strcasecmp(a->argv[1], "block")) {
17490 do_what = DO_BLOCK;
17491 } else if (!strcasecmp(a->argv[1], "unblock")) {
17492 do_what = DO_UNBLOCK;
17493 } else if (!strcasecmp(a->argv[1], "reset")) {
17494 do_what = DO_RESET;
17495 } else {
17496 return CLI_SHOWUSAGE;
17497 }
17498
17499 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17500 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17501 return CLI_SUCCESS;
17502 }
17503
17504 if (!linksets[linkset - 1].ss7.ss7) {
17505 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17506 return CLI_SUCCESS;
17507 }
17508
17509 for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
17510 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17511 if (linksets[linkset - 1].ss7.pvts[i]) {
17512 switch (do_what) {
17513 case DO_BLOCK:
17514 case DO_UNBLOCK:
17515 if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
17516 ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
17517 (do_what == DO_BLOCK) ? "blocking" : "unblocking",
17518 linksets[linkset - 1].ss7.pvts[i]->cic);
17519 }
17520 break;
17521 case DO_RESET:
17522 if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
17523 linksets[linkset - 1].ss7.pvts[i]->cic,
17524 linksets[linkset - 1].ss7.pvts[i]->dpc)) {
17525 ast_cli(a->fd, "Sent reset request on CIC %d\n",
17526 linksets[linkset - 1].ss7.pvts[i]->cic);
17527 }
17528 break;
17529 }
17530 }
17531 }
17532
17533 return CLI_SUCCESS;
17534}
17535#endif /* defined(HAVE_SS7) */
17536
17537#if defined(HAVE_SS7)
17538static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17539{
17540 int linkset, cic, range, chanpos;
17541 int i, dpc, orient = 0;
17542 int do_block = 0;
17543 unsigned char state[255];
17544
17545 switch (cmd) {
17546 case CLI_INIT:
17547 e->command = "ss7 {block|unblock} group";
17548 e->usage =
17549 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17550 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17551 return NULL;
17552 case CLI_GENERATE:
17553 return NULL;
17554 }
17555
17556 if (a->argc == 7 || a->argc == 8) {
17557 linkset = atoi(a->argv[3]);
17558 } else {
17559 return CLI_SHOWUSAGE;
17560 }
17561
17562 if (!strcasecmp(a->argv[1], "block")) {
17563 do_block = 1;
17564 } else if (strcasecmp(a->argv[1], "unblock")) {
17565 return CLI_SHOWUSAGE;
17566 }
17567
17568 if (a->argc == 8) {
17569 if (!strcasecmp(a->argv[7], "H")) {
17570 orient = 1;
17571 } else {
17572 return CLI_SHOWUSAGE;
17573 }
17574 }
17575
17576 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17577 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17578 return CLI_SUCCESS;
17579 }
17580
17581 if (!linksets[linkset-1].ss7.ss7) {
17582 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17583 return CLI_SUCCESS;
17584 }
17585
17586 cic = atoi(a->argv[5]);
17587 if (cic < 1) {
17588 ast_cli(a->fd, "Invalid CIC specified!\n");
17589 return CLI_SUCCESS;
17590 }
17591
17592 range = atoi(a->argv[6]);
17593 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17594 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17595 ast_cli(a->fd, "Invalid range specified!\n");
17596 return CLI_SUCCESS;
17597 }
17598
17599 dpc = atoi(a->argv[4]);
17600 if (dpc < 1) {
17601 ast_cli(a->fd, "Invalid DPC specified!\n");
17602 return CLI_SUCCESS;
17603 }
17604
17605 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17606 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17607 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17608 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17609 return CLI_SHOWUSAGE;
17610 }
17611
17612 memset(state, 0, sizeof(state));
17613 for (i = 0; i <= range; ++i) {
17614 state[i] = 1;
17615 }
17616
17617 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17618 chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
17619 if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
17620 ast_cli(a->fd, "Unable allocate new ss7call\n");
17621 } else {
17622 ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17623 orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
17624 }
17625
17626 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17627
17628 /* Break poll on the linkset so it sends our messages */
17629 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17630 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17631 }
17632 return CLI_SUCCESS;
17633}
17634#endif /* defined(HAVE_SS7) */
17635
17636#if defined(HAVE_SS7)
17637static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17638{
17639 int linkset, cic, range;
17640 unsigned int dpc;
17641
17642 switch (cmd) {
17643 case CLI_INIT:
17644 e->command = "ss7 reset group";
17645 e->usage =
17646 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17647 " Send a GRS for the given CIC range on the specified linkset\n";
17648 return NULL;
17649 case CLI_GENERATE:
17650 return NULL;
17651 }
17652
17653 if (a->argc == 7) {
17654 linkset = atoi(a->argv[3]);
17655 } else {
17656 return CLI_SHOWUSAGE;
17657 }
17658
17659 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17660 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17661 return CLI_SUCCESS;
17662 }
17663
17664 if (!linksets[linkset-1].ss7.ss7) {
17665 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17666 return CLI_SUCCESS;
17667 }
17668
17669 cic = atoi(a->argv[5]);
17670
17671 if (cic < 1) {
17672 ast_cli(a->fd, "Invalid CIC specified!\n");
17673 return CLI_SUCCESS;
17674 }
17675
17676 range = atoi(a->argv[6]);
17677 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17678 ast_cli(a->fd, "Invalid range specified!\n");
17679 return CLI_SUCCESS;
17680 }
17681
17682 dpc = atoi(a->argv[4]);
17683 if (dpc < 1) {
17684 ast_cli(a->fd, "Invalid DPC specified!\n");
17685 return CLI_SUCCESS;
17686 }
17687
17688 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17689 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17690 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17691 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17692 return CLI_SHOWUSAGE;
17693 }
17694
17695 if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
17696 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17697 } else {
17698 ast_cli(a->fd, "GRS sent ... \n");
17699 }
17700
17701 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17702
17703 /* Break poll on the linkset so it sends our messages */
17704 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17705 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17706 }
17707 return CLI_SUCCESS;
17708}
17709#endif /* defined(HAVE_SS7) */
17710
17711#if defined(HAVE_SS7)
17712static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17713{
17714 int linkset;
17715
17716 switch (cmd) {
17717 case CLI_INIT:
17718 e->command = "ss7 show calls";
17719 e->usage =
17720 "Usage: ss7 show calls <linkset>\n"
17721 " Show SS7 calls on the specified linkset\n";
17722 return NULL;
17723 case CLI_GENERATE:
17724 return NULL;
17725 }
17726
17727 if (a->argc == 4) {
17728 linkset = atoi(a->argv[3]);
17729 } else {
17730 return CLI_SHOWUSAGE;
17731 }
17732
17733 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17734 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17735 return CLI_SUCCESS;
17736 }
17737
17738 if (!linksets[linkset-1].ss7.ss7) {
17739 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17740 return CLI_SUCCESS;
17741 }
17742
17743 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17744 isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
17745 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17746
17747 return CLI_SUCCESS;
17748}
17749#endif /* defined(HAVE_SS7) */
17750
17751#if defined(HAVE_SS7)
17752static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17753{
17754 int linkset, cic, res;
17755 unsigned int dpc;
17756
17757 switch (cmd) {
17758 case CLI_INIT:
17759 e->command = "ss7 reset cic";
17760 e->usage =
17761 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17762 " Send a RSC for the given CIC on the specified linkset\n";
17763 return NULL;
17764 case CLI_GENERATE:
17765 return NULL;
17766 }
17767
17768 if (a->argc == 6) {
17769 linkset = atoi(a->argv[3]);
17770 } else {
17771 return CLI_SHOWUSAGE;
17772 }
17773
17774 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17775 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17776 return CLI_SUCCESS;
17777 }
17778
17779 if (!linksets[linkset-1].ss7.ss7) {
17780 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17781 return CLI_SUCCESS;
17782 }
17783
17784 cic = atoi(a->argv[5]);
17785
17786 if (cic < 1) {
17787 ast_cli(a->fd, "Invalid CIC specified!\n");
17788 return CLI_SUCCESS;
17789 }
17790
17791 dpc = atoi(a->argv[4]);
17792 if (dpc < 1) {
17793 ast_cli(a->fd, "Invalid DPC specified!\n");
17794 return CLI_SUCCESS;
17795 }
17796
17797 res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
17798
17799 ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
17800
17801 return CLI_SUCCESS;
17802}
17803#endif /* defined(HAVE_SS7) */
17804
17805#if defined(HAVE_SS7)
17806static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17807{
17808 int linkset;
17809 unsigned int slc;
17810 unsigned int arg = 0;
17811 const char *res;
17812
17813 switch (cmd) {
17814 case CLI_INIT:
17815 e->command = "ss7 mtp3";
17816 e->usage =
17817 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
17818 " Send a NET MNG message\n"
17819 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
17820 return NULL;
17821 case CLI_GENERATE:
17822 return NULL;
17823 }
17824
17825 if (a->argc < 5) {
17826 return CLI_SHOWUSAGE;
17827 }
17828
17829 linkset = atoi(a->argv[2]);
17830 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17831 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
17832 return CLI_SUCCESS;
17833 }
17834 if (!linksets[linkset-1].ss7.ss7) {
17835 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17836 return CLI_SUCCESS;
17837 }
17838
17839 slc = atoi(a->argv[3]);
17840
17841 if (a->argc == 6) {
17842 arg = atoi(a->argv[5]);
17843 }
17844
17845 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17846 res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
17847 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17848
17849 /* Break poll on the linkset so it sends our messages */
17850 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17851 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17852 }
17853
17854 ast_cli(a->fd, "%s", res);
17855
17856 return CLI_SUCCESS;
17857}
17858#endif /* defined(HAVE_SS7) */
17859
17860#if defined(HAVE_SS7)
17861static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17862{
17863 int linkset;
17864 unsigned int slc = 0;
17865
17866 switch (cmd) {
17867 case CLI_INIT:
17868 e->command = "ss7 restart mtp3";
17869 e->usage =
17870 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
17871 " Restart link\n";
17872 return NULL;
17873 case CLI_GENERATE:
17874 return NULL;
17875 }
17876
17877 if (a->argc < 5) {
17878 return CLI_SHOWUSAGE;
17879 }
17880
17881 linkset = atoi(a->argv[3]);
17882 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17883 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
17884 return CLI_SUCCESS;
17885 }
17886 if (!linksets[linkset-1].ss7.ss7) {
17887 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17888 return CLI_SUCCESS;
17889 }
17890
17891 slc = atoi(a->argv[4]);
17892
17893 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17894 mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
17895 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17896
17897 /* Break poll on the linkset so it sends our messages */
17898 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17899 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17900 }
17901
17902 return CLI_SUCCESS;
17903}
17904#endif /* defined(HAVE_SS7) */
17905
17906#if defined(HAVE_SS7)
17907static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17908{
17909 int linkset;
17910 struct sig_ss7_linkset *ss7;
17911 switch (cmd) {
17912 case CLI_INIT:
17913 e->command = "ss7 show linkset";
17914 e->usage =
17915 "Usage: ss7 show linkset <span>\n"
17916 " Shows the status of an SS7 linkset.\n";
17917 return NULL;
17918 case CLI_GENERATE:
17919 return NULL;
17920 }
17921
17922 if (a->argc < 4) {
17923 return CLI_SHOWUSAGE;
17924 }
17925
17926 linkset = atoi(a->argv[3]);
17927 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17928 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17929 return CLI_SUCCESS;
17930 }
17931 ss7 = &linksets[linkset - 1].ss7;
17932 if (!ss7->ss7) {
17933 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17934 return CLI_SUCCESS;
17935 }
17936
17937 ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
17938 ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
17939 ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
17940 ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
17941 ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
17942 ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
17943 ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
17944 ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
17945 ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
17946 ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
17947
17948 return CLI_SUCCESS;
17949}
17950#endif /* defined(HAVE_SS7) */
17951
17952#if defined(HAVE_SS7)
17953static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17954{
17955 int linkset;
17956
17957 switch (cmd) {
17958 case CLI_INIT:
17959 e->command = "ss7 show channels";
17960 e->usage =
17961 "Usage: ss7 show channels\n"
17962 " Displays SS7 channel information at a glance.\n";
17963 return NULL;
17964 case CLI_GENERATE:
17965 return NULL;
17966 }
17967
17968 if (a->argc != 3) {
17969 return CLI_SHOWUSAGE;
17970 }
17971
17973 for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
17974 if (linksets[linkset].ss7.ss7) {
17975 sig_ss7_cli_show_channels(a->fd, &linksets[linkset].ss7);
17976 }
17977 }
17978 return CLI_SUCCESS;
17979}
17980#endif /* defined(HAVE_SS7) */
17981
17982#if defined(HAVE_SS7)
17983static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17984{
17985#define FORMAT "%5s %5s %6s %12s %-12s\n"
17986#define FORMAT2 "%5i %5i %6i %12s %-12s\n"
17987 int i, linkset, dpc = 0;
17988 struct sig_ss7_linkset *ss7;
17989 char *state;
17990 char blocking[12];
17991
17992 switch (cmd) {
17993 case CLI_INIT:
17994 e->command = "ss7 show cics";
17995 e->usage =
17996 "Usage: ss7 show cics <linkset> [dpc]\n"
17997 " Shows the cics of an SS7 linkset.\n";
17998 return NULL;
17999 case CLI_GENERATE:
18000 return NULL;
18001 }
18002
18003 if (a->argc < 4 || a->argc > 5) {
18004 return CLI_SHOWUSAGE;
18005 }
18006
18007 linkset = atoi(a->argv[3]);
18008
18009 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18010 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
18011 return CLI_SUCCESS;
18012 }
18013
18014 if (!linksets[linkset-1].ss7.ss7) {
18015 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18016 return CLI_SUCCESS;
18017 }
18018 ss7 = &linksets[linkset-1].ss7;
18019
18020 if (a->argc == 5) {
18021 dpc = atoi(a->argv[4]);
18022 if (dpc < 1) {
18023 ast_cli(a->fd, "Invalid DPC specified!\n");
18024 return CLI_SUCCESS;
18025 }
18026 }
18027
18028 ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
18029
18030 for (i = 0; i < ss7->numchans; i++) {
18031 if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
18032 struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
18033
18034 if (ss7->pvts[i]->owner) {
18035 state = "Used";
18036 } else if (ss7->pvts[i]->ss7call) {
18037 state = "Pending";
18038 } else if (!p->inservice) {
18039 state = "NotInServ";
18040 } else {
18041 state = "Idle";
18042 }
18043
18044 if (p->locallyblocked) {
18045 strcpy(blocking, "L:");
18047 strcat(blocking, "M");
18048 } else {
18049 strcat(blocking, " ");
18050 }
18051
18053 strcat(blocking, "H");
18054 } else {
18055 strcat(blocking, " ");
18056 }
18057 } else {
18058 strcpy(blocking, " ");
18059 }
18060
18061 if (p->remotelyblocked) {
18062 strcat(blocking, " R:");
18064 strcat(blocking, "M");
18065 } else {
18066 strcat(blocking, " ");
18067 }
18068
18070 strcat(blocking, "H");
18071 } else {
18072 strcat(blocking, " ");
18073 }
18074 }
18075
18076 ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
18077 }
18078 }
18079
18080 return CLI_SUCCESS;
18081#undef FORMAT
18082#undef FORMAT2
18083}
18084#endif /* defined(HAVE_SS7) */
18085
18086#if defined(HAVE_SS7)
18087static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18088{
18089 switch (cmd) {
18090 case CLI_INIT:
18091 e->command = "ss7 show version";
18092 e->usage =
18093 "Usage: ss7 show version\n"
18094 " Show the libss7 version\n";
18095 return NULL;
18096 case CLI_GENERATE:
18097 return NULL;
18098 }
18099
18100 ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
18101
18102 return CLI_SUCCESS;
18103}
18104#endif /* defined(HAVE_SS7) */
18105
18106#if defined(HAVE_SS7)
18107static struct ast_cli_entry dahdi_ss7_cli[] = {
18108 AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
18109 AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
18110 AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
18111 AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
18112 AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
18113 AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
18114 AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
18115 AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
18116 AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
18117 AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
18118 AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
18119 AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
18120 AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
18121};
18122#endif /* defined(HAVE_SS7) */
18123
18124#if defined(HAVE_PRI)
18125#if defined(HAVE_PRI_CCSS)
18126/*!
18127 * \internal
18128 * \brief CC agent initialization.
18129 * \since 1.8
18130 *
18131 * \param agent CC core agent control.
18132 * \param chan Original channel the agent will attempt to recall.
18133 *
18134 * \details
18135 * This callback is called when the CC core is initialized. Agents should allocate
18136 * any private data necessary for the call and assign it to the private_data
18137 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
18138 * specific agent type, they should be set in this function as well.
18139 *
18140 * \retval 0 on success.
18141 * \retval -1 on error.
18142 */
18143static int dahdi_pri_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
18144{
18145 struct dahdi_pvt *pvt;
18146 struct sig_pri_chan *pvt_chan;
18147 int res;
18148
18149 ast_assert(!strcmp(ast_channel_tech(chan)->type, "DAHDI"));
18150
18151 pvt = ast_channel_tech_pvt(chan);
18152 if (dahdi_sig_pri_lib_handles(pvt->sig)) {
18153 pvt_chan = pvt->sig_pvt;
18154 } else {
18155 pvt_chan = NULL;
18156 }
18157 if (!pvt_chan) {
18158 return -1;
18159 }
18160
18162
18163 res = sig_pri_cc_agent_init(agent, pvt_chan);
18164 if (res) {
18166 }
18167 return res;
18168}
18169#endif /* defined(HAVE_PRI_CCSS) */
18170#endif /* defined(HAVE_PRI) */
18171
18172#if defined(HAVE_PRI)
18173#if defined(HAVE_PRI_CCSS)
18174/*!
18175 * \internal
18176 * \brief Destroy private data on the agent.
18177 * \since 1.8
18178 *
18179 * \param agent CC core agent control.
18180 *
18181 * \details
18182 * The core will call this function upon completion
18183 * or failure of CC.
18184 */
18185static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent *agent)
18186{
18188
18190}
18191#endif /* defined(HAVE_PRI_CCSS) */
18192#endif /* defined(HAVE_PRI) */
18193
18194#if defined(HAVE_PRI)
18195#if defined(HAVE_PRI_CCSS)
18196static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = {
18197 .type = dahdi_pri_cc_type,
18198 .init = dahdi_pri_cc_agent_init,
18199 .start_offer_timer = sig_pri_cc_agent_start_offer_timer,
18200 .stop_offer_timer = sig_pri_cc_agent_stop_offer_timer,
18201 .respond = sig_pri_cc_agent_req_rsp,
18202 .status_request = sig_pri_cc_agent_status_req,
18203 .stop_ringing = sig_pri_cc_agent_stop_ringing,
18204 .party_b_free = sig_pri_cc_agent_party_b_free,
18205 .start_monitoring = sig_pri_cc_agent_start_monitoring,
18206 .callee_available = sig_pri_cc_agent_callee_available,
18207 .destructor = dahdi_pri_cc_agent_destructor,
18208};
18209#endif /* defined(HAVE_PRI_CCSS) */
18210#endif /* defined(HAVE_PRI) */
18211
18212#if defined(HAVE_PRI)
18213#if defined(HAVE_PRI_CCSS)
18214static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks = {
18215 .type = dahdi_pri_cc_type,
18216 .request_cc = sig_pri_cc_monitor_req_cc,
18217 .suspend = sig_pri_cc_monitor_suspend,
18218 .unsuspend = sig_pri_cc_monitor_unsuspend,
18219 .status_response = sig_pri_cc_monitor_status_rsp,
18220 .cancel_available_timer = sig_pri_cc_monitor_cancel_available_timer,
18221 .destructor = sig_pri_cc_monitor_destructor,
18222};
18223#endif /* defined(HAVE_PRI_CCSS) */
18224#endif /* defined(HAVE_PRI) */
18225
18226static int __unload_module(void)
18227{
18228 struct dahdi_pvt *p;
18229#if defined(HAVE_PRI) || defined(HAVE_SS7)
18230 int i, j;
18231#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18232
18233#ifdef HAVE_PRI
18234 for (i = 0; i < NUM_SPANS; i++) {
18235 if (pris[i].pri.master != AST_PTHREADT_NULL) {
18236 pthread_cancel(pris[i].pri.master);
18237 pthread_kill(pris[i].pri.master, SIGURG);
18238 }
18239 }
18240 ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
18241 ast_unregister_application(dahdi_send_keypad_facility_app);
18242#ifdef HAVE_PRI_PROG_W_CAUSE
18243 ast_unregister_application(dahdi_send_callrerouting_facility_app);
18244#endif
18245#endif
18246#if defined(HAVE_SS7)
18247 for (i = 0; i < NUM_SPANS; i++) {
18248 if (linksets[i].ss7.master != AST_PTHREADT_NULL) {
18249 pthread_cancel(linksets[i].ss7.master);
18250 pthread_kill(linksets[i].ss7.master, SIGURG);
18251 }
18252 }
18253 ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
18254#endif /* defined(HAVE_SS7) */
18255#if defined(HAVE_OPENR2)
18256 dahdi_r2_destroy_links();
18257 ast_cli_unregister_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
18258 ast_unregister_application(dahdi_accept_r2_call_app);
18259#endif
18260
18262
18264 ast_manager_unregister("DAHDIDialOffhook");
18265 ast_manager_unregister("DAHDIHangup");
18266 ast_manager_unregister("DAHDITransfer");
18267 ast_manager_unregister("DAHDIDNDoff");
18268 ast_manager_unregister("DAHDIDNDon");
18269 ast_manager_unregister("DAHDIShowChannels");
18270 ast_manager_unregister("DAHDIShowStatus");
18271 ast_manager_unregister("DAHDIRestart");
18272#if defined(HAVE_PRI)
18273 ast_manager_unregister("PRIShowSpans");
18274 ast_manager_unregister("PRIDebugSet");
18275 ast_manager_unregister("PRIDebugFileSet");
18276 ast_manager_unregister("PRIDebugFileUnset");
18277#endif /* defined(HAVE_PRI) */
18279
18280 /* Hangup all interfaces if they have an owner */
18282 for (p = iflist; p; p = p->next) {
18283 if (p->owner)
18285 }
18287
18290 pthread_cancel(monitor_thread);
18291 pthread_kill(monitor_thread, SIGURG);
18292 pthread_join(monitor_thread, NULL);
18293 }
18296
18298
18299#if defined(HAVE_PRI)
18300 for (i = 0; i < NUM_SPANS; i++) {
18301 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
18302 pthread_join(pris[i].pri.master, NULL);
18303 }
18304 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) {
18305 dahdi_close_pri_fd(&(pris[i]), j);
18306 }
18307 sig_pri_stop_pri(&pris[i].pri);
18308 }
18309#if defined(HAVE_PRI_CCSS)
18310 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks);
18311 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks);
18312#endif /* defined(HAVE_PRI_CCSS) */
18314#endif
18315
18316#if defined(HAVE_SS7)
18317 for (i = 0; i < NUM_SPANS; i++) {
18318 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
18319 pthread_join(linksets[i].ss7.master, NULL);
18320 }
18321 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
18322 dahdi_close_ss7_fd(&(linksets[i]), j);
18323 }
18324 if (linksets[i].ss7.ss7) {
18325 ss7_destroy(linksets[i].ss7.ss7);
18326 linksets[i].ss7.ss7 = NULL;
18327 }
18328 }
18329#endif /* defined(HAVE_SS7) */
18331
18333
18336 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
18337 return 0;
18338}
18339
18340static int unload_module(void)
18341{
18342#if defined(HAVE_PRI) || defined(HAVE_SS7)
18343 int y;
18344#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18345#ifdef HAVE_PRI
18346 for (y = 0; y < NUM_SPANS; y++)
18347 ast_mutex_destroy(&pris[y].pri.lock);
18348#endif
18349#if defined(HAVE_SS7)
18350 for (y = 0; y < NUM_SPANS; y++)
18351 ast_mutex_destroy(&linksets[y].ss7.lock);
18352#endif /* defined(HAVE_SS7) */
18353 return __unload_module();
18354}
18355
18356static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
18357{
18358 char *c, *chan;
18359 int x, start, finish;
18360 struct dahdi_pvt *tmp;
18361
18362 if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
18363 ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
18364 return -1;
18365 }
18366
18367 c = ast_strdupa(value);
18368
18369 while ((chan = strsep(&c, ","))) {
18370 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
18371 /* Range */
18372 } else if (sscanf(chan, "%30d", &start)) {
18373 /* Just one */
18374 finish = start;
18375 } else if (!strcasecmp(chan, "pseudo")) {
18376 finish = start = CHAN_PSEUDO;
18377 } else {
18378 ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
18379 return -1;
18380 }
18381 if (finish < start) {
18382 ast_log(LOG_WARNING, "Silliness: %d < %d\n", start, finish);
18383 x = finish;
18384 finish = start;
18385 start = x;
18386 }
18387
18388 for (x = start; x <= finish; x++) {
18389 if (conf->wanted_channels_start &&
18390 (x < conf->wanted_channels_start ||
18391 x > conf->wanted_channels_end)
18392 ) {
18393 continue;
18394 }
18395 tmp = mkintf(x, conf, reload);
18396
18397 if (tmp) {
18398 ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
18399 } else {
18400 ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
18401 (reload == 1) ? "reconfigure" : "register", value);
18402 return -1;
18403 }
18404 if (x == CHAN_PSEUDO) {
18405 has_pseudo = 1;
18406 }
18407 }
18408 }
18409
18410 return 0;
18411}
18412
18413/** The length of the parameters list of 'dahdichan'.
18414 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18415#define MAX_CHANLIST_LEN 80
18416
18417static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
18418{
18419 char *parse = ast_strdupa(data);
18420 char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
18421 unsigned int param_count;
18422 unsigned int x;
18423
18424 if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
18425 return;
18426
18427 memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
18428
18429 /* first parameter is tap length, process it here */
18430
18431 x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
18432
18433 if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
18434 confp->chan.echocancel.head.tap_length = x;
18435 else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
18436 confp->chan.echocancel.head.tap_length = 128;
18437
18438 /* now process any remaining parameters */
18439
18440 for (x = 1; x < param_count; x++) {
18441 struct {
18442 char *name;
18443 char *value;
18444 } param;
18445
18446 if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
18447 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, params[x]);
18448 continue;
18449 }
18450
18451 if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
18452 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, param.name);
18453 continue;
18454 }
18455
18456 strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
18457
18458 if (param.value) {
18459 if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
18460 ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line, param.value);
18461 continue;
18462 }
18463 }
18464 confp->chan.echocancel.head.param_count++;
18465 }
18466}
18467
18468#if defined(HAVE_PRI)
18469#if defined(HAVE_PRI_DISPLAY_TEXT)
18470/*!
18471 * \internal
18472 * \brief Determine the configured display text options.
18473 * \since 10.0
18474 *
18475 * \param value Configuration value string.
18476 *
18477 * \return Configured display text option flags.
18478 */
18479static unsigned long dahdi_display_text_option(const char *value)
18480{
18481 char *val_str;
18482 char *opt_str;
18483 unsigned long options;
18484
18485 options = 0;
18486 val_str = ast_strdupa(value);
18487
18488 for (;;) {
18489 opt_str = strsep(&val_str, ",");
18490 if (!opt_str) {
18491 break;
18492 }
18493 opt_str = ast_strip(opt_str);
18494 if (!*opt_str) {
18495 continue;
18496 }
18497
18498 if (!strcasecmp(opt_str, "block")) {
18499 options |= PRI_DISPLAY_OPTION_BLOCK;
18500 } else if (!strcasecmp(opt_str, "name_initial")) {
18501 options |= PRI_DISPLAY_OPTION_NAME_INITIAL;
18502 } else if (!strcasecmp(opt_str, "name_update")) {
18503 options |= PRI_DISPLAY_OPTION_NAME_UPDATE;
18504 } else if (!strcasecmp(opt_str, "name")) {
18505 options |= (PRI_DISPLAY_OPTION_NAME_INITIAL | PRI_DISPLAY_OPTION_NAME_UPDATE);
18506 } else if (!strcasecmp(opt_str, "text")) {
18507 options |= PRI_DISPLAY_OPTION_TEXT;
18508 }
18509 }
18510 return options;
18511}
18512#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18513#endif /* defined(HAVE_PRI) */
18514
18515#if defined(HAVE_PRI)
18516#if defined(HAVE_PRI_DATETIME_SEND)
18517/*!
18518 * \internal
18519 * \brief Determine the configured date/time send policy option.
18520 * \since 10.0
18521 *
18522 * \param value Configuration value string.
18523 *
18524 * \return Configured date/time send policy option.
18525 */
18526static int dahdi_datetime_send_option(const char *value)
18527{
18528 int option;
18529
18530 option = PRI_DATE_TIME_SEND_DEFAULT;
18531
18532 if (ast_false(value)) {
18533 option = PRI_DATE_TIME_SEND_NO;
18534 } else if (!strcasecmp(value, "date")) {
18535 option = PRI_DATE_TIME_SEND_DATE;
18536 } else if (!strcasecmp(value, "date_hh")) {
18537 option = PRI_DATE_TIME_SEND_DATE_HH;
18538 } else if (!strcasecmp(value, "date_hhmm")) {
18539 option = PRI_DATE_TIME_SEND_DATE_HHMM;
18540 } else if (!strcasecmp(value, "date_hhmmss")) {
18541 option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
18542 }
18543
18544 return option;
18545}
18546#endif /* defined(HAVE_PRI_DATETIME_SEND) */
18547#endif /* defined(HAVE_PRI) */
18548
18549/*! process_dahdi() - ignore keyword 'channel' and similar */
18550#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18551/*! process_dahdi() - No warnings on non-existing configuration keywords */
18552#define PROC_DAHDI_OPT_NOWARN (1 << 1)
18553
18554static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
18555{
18556 int count_pattern = 0;
18557 int norval = 0;
18558 char *temp = NULL;
18559
18560 for (; ;) {
18561 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18562 if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
18563 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18564 break;
18565 }
18566
18567 busy_cadence->pattern[count_pattern] = norval;
18568
18569 count_pattern++;
18570 if (count_pattern == 4) {
18571 break;
18572 }
18573
18574 temp = strchr(v->value, ',');
18575 if (temp == NULL) {
18576 break;
18577 }
18578 v->value = temp + 1;
18579 }
18580 busy_cadence->length = count_pattern;
18581
18582 if (count_pattern % 2 != 0) {
18583 /* The pattern length must be divisible by two */
18584 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18585 }
18586
18587}
18588
18589static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
18590{
18591 struct dahdi_pvt *tmp;
18592 int y;
18593 struct ast_variable *dahdichan = NULL;
18594
18595 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18597
18598 for (; v; v = v->next) {
18600 continue;
18601
18602 /* Create the interface list */
18603 if (!strcasecmp(v->name, "channel") || !strcasecmp(v->name, "channels")) {
18605 ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
18606 continue;
18607 }
18608 if (build_channels(confp, v->value, reload, v->lineno)) {
18609 if (confp->ignore_failed_channels) {
18610 ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
18611 continue;
18612 } else {
18613 return -1;
18614 }
18615 }
18616 ast_debug(1, "Channel '%s' configured.\n", v->value);
18617 } else if (!strcasecmp(v->name, "ignore_failed_channels")) {
18619 } else if (!strcasecmp(v->name, "buffers")) {
18620 if (parse_buffers_policy(v->value, &confp->chan.buf_no, &confp->chan.buf_policy)) {
18621 ast_log(LOG_WARNING, "Using default buffer policy.\n");
18622 confp->chan.buf_no = numbufs;
18623 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
18624 }
18625 } else if (!strcasecmp(v->name, "faxbuffers")) {
18626 if (!parse_buffers_policy(v->value, &confp->chan.faxbuf_no, &confp->chan.faxbuf_policy)) {
18627 confp->chan.usefaxbuffers = 1;
18628 }
18629 } else if (!strcasecmp(v->name, "dahdichan")) {
18630 /* Only process the last dahdichan value. */
18631 dahdichan = v;
18632 } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
18634 } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
18636 } else if (!strcasecmp(v->name, "dring1context")) {
18638 } else if (!strcasecmp(v->name, "dring2context")) {
18640 } else if (!strcasecmp(v->name, "dring3context")) {
18642 } else if (!strcasecmp(v->name, "dring1range")) {
18643 confp->chan.drings.ringnum[0].range = atoi(v->value);
18644 } else if (!strcasecmp(v->name, "dring2range")) {
18645 confp->chan.drings.ringnum[1].range = atoi(v->value);
18646 } else if (!strcasecmp(v->name, "dring3range")) {
18647 confp->chan.drings.ringnum[2].range = atoi(v->value);
18648 } else if (!strcasecmp(v->name, "dring1")) {
18649 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]);
18650 } else if (!strcasecmp(v->name, "dring2")) {
18651 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]);
18652 } else if (!strcasecmp(v->name, "dring3")) {
18653 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]);
18654 } else if (!strcasecmp(v->name, "usecallerid")) {
18655 confp->chan.use_callerid = ast_true(v->value);
18656 } else if (!strcasecmp(v->name, "cidsignalling")) {
18657 if (!strcasecmp(v->value, "bell"))
18659 else if (!strcasecmp(v->value, "v23"))
18661 else if (!strcasecmp(v->value, "dtmf"))
18663 else if (!strcasecmp(v->value, "smdi"))
18665 else if (!strcasecmp(v->value, "v23_jp"))
18667 else if (ast_true(v->value))
18669 } else if (!strcasecmp(v->name, "cidstart")) {
18670 if (!strcasecmp(v->value, "ring"))
18671 confp->chan.cid_start = CID_START_RING;
18672 else if (!strcasecmp(v->value, "polarity_in"))
18674 else if (!strcasecmp(v->value, "polarity"))
18676 else if (!strcasecmp(v->value, "dtmf"))
18678 else if (ast_true(v->value))
18679 confp->chan.cid_start = CID_START_RING;
18680 } else if (!strcasecmp(v->name, "threewaycalling")) {
18681 confp->chan.threewaycalling = ast_true(v->value);
18682 } else if (!strcasecmp(v->name, "threewaysilenthold")) {
18684 } else if (!strcasecmp(v->name, "cancallforward")) {
18685 confp->chan.cancallforward = ast_true(v->value);
18686 } else if (!strcasecmp(v->name, "relaxdtmf")) {
18687 if (ast_true(v->value))
18689 else
18690 confp->chan.dtmfrelax = 0;
18691 } else if (!strcasecmp(v->name, "mailbox")) {
18692 ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
18693 } else if (!strcasecmp(v->name, "description")) {
18694 ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
18695 } else if (!strcasecmp(v->name, "adsi")) {
18696 confp->chan.adsi = ast_true(v->value);
18697 } else if (!strcasecmp(v->name, "usesmdi")) {
18698 confp->chan.use_smdi = ast_true(v->value);
18699 } else if (!strcasecmp(v->name, "smdiport")) {
18700 ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
18701 } else if (!strcasecmp(v->name, "transfer")) {
18702 confp->chan.transfer = ast_true(v->value);
18703 } else if (!strcasecmp(v->name, "canpark")) {
18704 confp->chan.canpark = ast_true(v->value);
18705 } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
18706 confp->chan.echocanbridged = ast_true(v->value);
18707 } else if (!strcasecmp(v->name, "busydetect")) {
18708 confp->chan.busydetect = ast_true(v->value);
18709 } else if (!strcasecmp(v->name, "busycount")) {
18710 confp->chan.busycount = atoi(v->value);
18711 } else if (!strcasecmp(v->name, "busypattern")) {
18713 } else if (!strcasecmp(v->name, "calledsubscriberheld")) {
18715 } else if (!strcasecmp(v->name, "lastnumredial")) {
18716 confp->chan.lastnumredial = ast_true(v->value);
18717 } else if (!strcasecmp(v->name, "callprogress")) {
18718 confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
18719 if (ast_true(v->value))
18721 } else if (!strcasecmp(v->name, "waitfordialtone")) {
18722 confp->chan.waitfordialtone = atoi(v->value);
18723 } else if (!strcasecmp(v->name, "dialtone_detect")) {
18724 if (!strcasecmp(v->value, "always")) {
18725 confp->chan.dialtone_detect = -1;
18726 } else if (ast_true(v->value)) {
18728 } else if (ast_false(v->value)) {
18729 confp->chan.dialtone_detect = 0;
18730 } else {
18731 confp->chan.dialtone_detect = ast_strlen_zero(v->value) ? 0 : (8 * atoi(v->value)) / READ_SIZE;
18732 }
18733 } else if (!strcasecmp(v->name, "faxdetect")) {
18734 confp->chan.callprogress &= ~CALLPROGRESS_FAX;
18735 if (!strcasecmp(v->value, "incoming")) {
18737 } else if (!strcasecmp(v->value, "outgoing")) {
18739 } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
18741 } else if (!strcasecmp(v->name, "faxdetect_timeout")) {
18742 if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) {
18743 confp->chan.faxdetect_timeout = 0;
18744 }
18745 } else if (!strcasecmp(v->name, "firstdigit_timeout")) {
18746 if (sscanf(v->value, "%30d", &confp->chan.firstdigit_timeout) != 1
18747 || confp->chan.firstdigit_timeout <= 0) {
18749 }
18750 } else if (!strcasecmp(v->name, "interdigit_timeout")) {
18751 if (sscanf(v->value, "%30d", &confp->chan.interdigit_timeout) != 1
18752 || confp->chan.interdigit_timeout <= 0) {
18754 }
18755 } else if (!strcasecmp(v->name, "matchdigit_timeout")) {
18756 if (sscanf(v->value, "%30d", &confp->chan.matchdigit_timeout) != 1
18757 || confp->chan.matchdigit_timeout <= 0) {
18759 }
18760 } else if (!strcasecmp(v->name, "echocancel")) {
18761 process_echocancel(confp, v->value, v->lineno);
18762 } else if (!strcasecmp(v->name, "echotraining")) {
18763 if (sscanf(v->value, "%30d", &y) == 1) {
18764 if ((y < 10) || (y > 4000)) {
18765 ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);
18766 } else {
18767 confp->chan.echotraining = y;
18768 }
18769 } else if (ast_true(v->value)) {
18770 confp->chan.echotraining = 400;
18771 } else
18772 confp->chan.echotraining = 0;
18773 } else if (!strcasecmp(v->name, "hidecallerid")) {
18774 confp->chan.hidecallerid = ast_true(v->value);
18775 } else if (!strcasecmp(v->name, "hidecalleridname")) {
18776 confp->chan.hidecalleridname = ast_true(v->value);
18777 } else if (!strcasecmp(v->name, "pulsedial")) {
18778 confp->chan.pulse = ast_true(v->value);
18779 } else if (!strcasecmp(v->name, "callreturn")) {
18780 confp->chan.callreturn = ast_true(v->value);
18781 } else if (!strcasecmp(v->name, "callwaiting")) {
18782 confp->chan.callwaiting = ast_true(v->value);
18783 } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
18785 } else if (!strcasecmp(v->name, "callwaitingdeluxe")) {
18786 confp->chan.callwaitingdeluxe = ast_true(v->value);
18787 } else if (!strcasecmp(v->name, "context")) {
18788 ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
18789 } else if (!strcasecmp(v->name, "language")) {
18790 ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
18791 } else if (!strcasecmp(v->name, "progzone")) {
18792 ast_copy_string(progzone, v->value, sizeof(progzone));
18793 } else if (!strcasecmp(v->name, "mohinterpret")
18794 ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
18795 ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
18796 } else if (!strcasecmp(v->name, "mohsuggest")) {
18797 ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
18798 } else if (!strcasecmp(v->name, "parkinglot")) {
18799 ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
18800 } else if (!strcasecmp(v->name, "stripmsd")) {
18801 ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
18802 confp->chan.stripmsd = atoi(v->value);
18803 } else if (!strcasecmp(v->name, "jitterbuffers")) {
18804 numbufs = atoi(v->value);
18805 } else if (!strcasecmp(v->name, "group")) {
18806 confp->chan.group = ast_get_group(v->value);
18807 } else if (!strcasecmp(v->name, "callgroup")) {
18808 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18809 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a call group\n");
18810 }
18811 if (!strcasecmp(v->value, "none"))
18812 confp->chan.callgroup = 0;
18813 else
18814 confp->chan.callgroup = ast_get_group(v->value);
18815 } else if (!strcasecmp(v->name, "pickupgroup")) {
18816 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18817 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a pickup group\n");
18818 }
18819 if (!strcasecmp(v->value, "none"))
18820 confp->chan.pickupgroup = 0;
18821 else
18822 confp->chan.pickupgroup = ast_get_group(v->value);
18823 } else if (!strcasecmp(v->name, "namedcallgroup")) {
18824 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18825 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named call group\n");
18826 }
18828 } else if (!strcasecmp(v->name, "namedpickupgroup")) {
18829 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18830 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named pickup group\n");
18831 }
18833 } else if (!strcasecmp(v->name, "setvar")) {
18834 if (v->value) {
18835 char *varval = NULL;
18836 struct ast_variable *tmpvar;
18837 char varname[strlen(v->value) + 1];
18838 strcpy(varname, v->value); /* safe */
18839 if ((varval = strchr(varname, '='))) {
18840 *varval++ = '\0';
18841 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
18842 if (ast_variable_list_replace(&confp->chan.vars, tmpvar)) {
18843 tmpvar->next = confp->chan.vars;
18844 confp->chan.vars = tmpvar;
18845 }
18846 }
18847 }
18848 }
18849 } else if (!strcasecmp(v->name, "immediate")) {
18850 confp->chan.immediate = ast_true(v->value);
18851 } else if (!strcasecmp(v->name, "immediatering")) {
18852 confp->chan.immediatering = ast_true(v->value);
18853 } else if (!strcasecmp(v->name, "transfertobusy")) {
18854 confp->chan.transfertobusy = ast_true(v->value);
18855 } else if (!strcasecmp(v->name, "dialmode")) {
18856 if (!strcasecmp(v->value, "pulse")) {
18858 } else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
18860 } else if (!strcasecmp(v->value, "none")) {
18862 } else {
18864 }
18865 } else if (!strcasecmp(v->name, "mwimonitor")) {
18866 confp->chan.mwimonitor_neon = 0;
18867 confp->chan.mwimonitor_fsk = 0;
18868 confp->chan.mwimonitor_rpas = 0;
18869 if (strcasestr(v->value, "fsk")) {
18870 confp->chan.mwimonitor_fsk = 1;
18871 }
18872 if (strcasestr(v->value, "rpas")) {
18873 confp->chan.mwimonitor_rpas = 1;
18874 }
18875 if (strcasestr(v->value, "neon")) {
18876 confp->chan.mwimonitor_neon = 1;
18877 }
18878 /* If set to true or yes, assume that simple fsk is desired */
18879 if (ast_true(v->value)) {
18880 confp->chan.mwimonitor_fsk = 1;
18881 }
18882 } else if (!strcasecmp(v->name, "hwrxgain")) {
18883 confp->chan.hwrxgain_enabled = 0;
18884 if (strcasecmp(v->value, "disabled")) {
18885 if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
18886 confp->chan.hwrxgain_enabled = 1;
18887 } else {
18888 ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
18889 }
18890 }
18891 } else if (!strcasecmp(v->name, "hwtxgain")) {
18892 confp->chan.hwtxgain_enabled = 0;
18893 if (strcasecmp(v->value, "disabled")) {
18894 if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
18895 confp->chan.hwtxgain_enabled = 1;
18896 } else {
18897 ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
18898 }
18899 }
18900 } else if (!strcasecmp(v->name, "cid_rxgain")) {
18901 if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
18902 ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
18903 }
18904 } else if (!strcasecmp(v->name, "rxgain")) {
18905 if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
18906 ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
18907 }
18908 } else if (!strcasecmp(v->name, "txgain")) {
18909 if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
18910 ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
18911 }
18912 } else if (!strcasecmp(v->name, "txdrc")) {
18913 if (sscanf(v->value, "%f", &confp->chan.txdrc) != 1) {
18914 ast_log(LOG_WARNING, "Invalid txdrc: %s\n", v->value);
18915 }
18916 } else if (!strcasecmp(v->name, "rxdrc")) {
18917 if (sscanf(v->value, "%f", &confp->chan.rxdrc) != 1) {
18918 ast_log(LOG_WARNING, "Invalid rxdrc: %s\n", v->value);
18919 }
18920 } else if (!strcasecmp(v->name, "tonezone")) {
18921 if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
18922 ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
18923 }
18924 } else if (!strcasecmp(v->name, "callerid")) {
18925 if (!strcasecmp(v->value, "asreceived")) {
18926 confp->chan.cid_num[0] = '\0';
18927 confp->chan.cid_name[0] = '\0';
18928 } else {
18929 ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
18930 }
18931 } else if (!strcasecmp(v->name, "fullname")) {
18932 ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
18933 } else if (!strcasecmp(v->name, "cid_number")) {
18934 ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
18935 } else if (!strcasecmp(v->name, "cid_tag")) {
18936 ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
18937 } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
18938 confp->chan.dahditrcallerid = ast_true(v->value);
18939 } else if (!strcasecmp(v->name, "restrictcid")) {
18940 confp->chan.restrictcid = ast_true(v->value);
18941 } else if (!strcasecmp(v->name, "usecallingpres")) {
18942 confp->chan.use_callingpres = ast_true(v->value);
18943 } else if (!strcasecmp(v->name, "accountcode")) {
18944 ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
18945 } else if (!strcasecmp(v->name, "amaflags")) {
18947 if (y < 0)
18948 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
18949 else
18950 confp->chan.amaflags = y;
18951 } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
18952 confp->chan.polarityonanswerdelay = atoi(v->value);
18953 } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
18955 } else if (!strcasecmp(v->name, "ani_info_digits")) {
18956 confp->chan.ani_info_digits = atoi(v->value);
18957 } else if (!strcasecmp(v->name, "ani_wink_time")) {
18958 confp->chan.ani_wink_time = atoi(v->value);
18959 } else if (!strcasecmp(v->name, "ani_timeout")) {
18960 confp->chan.ani_timeout = atoi(v->value);
18961 } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
18963 } else if (!strcasecmp(v->name, "autoreoriginate")) {
18964 confp->chan.reoriginate = ast_true(v->value);
18965 } else if (!strcasecmp(v->name, "sendcalleridafter")) {
18966 confp->chan.sendcalleridafter = atoi(v->value);
18967 } else if (!strcasecmp(v->name, "mwimonitornotify")) {
18969 } else if (ast_cc_is_config_param(v->name)) {
18970 ast_cc_set_param(confp->chan.cc_params, v->name, v->value);
18971 } else if (!strcasecmp(v->name, "mwisendtype")) {
18972#ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
18973 if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
18974 mwisend_rpas = 1;
18975 } else {
18976 mwisend_rpas = 0;
18977 }
18978#else
18979 /* Default is fsk, to turn it off you must specify nofsk */
18980 memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
18981 if (strcasestr(v->value, "nofsk")) { /* NoFSK */
18982 confp->chan.mwisend_fsk = 0;
18983 } else { /* Default FSK */
18984 confp->chan.mwisend_fsk = 1;
18985 }
18986 if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
18987 confp->chan.mwisend_rpas = 1;
18988 } else {
18989 confp->chan.mwisend_rpas = 0;
18990 }
18991 if (strcasestr(v->value, "lrev")) { /* Line Reversal */
18992 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
18993 }
18994 if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
18995 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
18996 }
18997 if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) { /* 90V DC pulses */
18998 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
18999 }
19000#endif
19001 } else if (reload != 1) {
19002 if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
19003 int orig_radio = confp->chan.radio;
19004 int orig_outsigmod = confp->chan.outsigmod;
19005 int orig_auto = confp->is_sig_auto;
19006
19007 confp->chan.radio = 0;
19008 confp->chan.outsigmod = -1;
19009 confp->is_sig_auto = 0;
19010 if (!strcasecmp(v->value, "em")) {
19011 confp->chan.sig = SIG_EM;
19012 } else if (!strcasecmp(v->value, "em_e1")) {
19013 confp->chan.sig = SIG_EM_E1;
19014 } else if (!strcasecmp(v->value, "em_w")) {
19015 confp->chan.sig = SIG_EMWINK;
19016 } else if (!strcasecmp(v->value, "fxs_ls")) {
19017 confp->chan.sig = SIG_FXSLS;
19018 } else if (!strcasecmp(v->value, "fxs_gs")) {
19019 confp->chan.sig = SIG_FXSGS;
19020 } else if (!strcasecmp(v->value, "fxs_ks")) {
19021 confp->chan.sig = SIG_FXSKS;
19022 } else if (!strcasecmp(v->value, "fxo_ls")) {
19023 confp->chan.sig = SIG_FXOLS;
19024 } else if (!strcasecmp(v->value, "fxo_gs")) {
19025 confp->chan.sig = SIG_FXOGS;
19026 } else if (!strcasecmp(v->value, "fxo_ks")) {
19027 confp->chan.sig = SIG_FXOKS;
19028 } else if (!strcasecmp(v->value, "fxs_rx")) {
19029 confp->chan.sig = SIG_FXSKS;
19030 confp->chan.radio = 1;
19031 } else if (!strcasecmp(v->value, "fxo_rx")) {
19032 confp->chan.sig = SIG_FXOLS;
19033 confp->chan.radio = 1;
19034 } else if (!strcasecmp(v->value, "fxs_tx")) {
19035 confp->chan.sig = SIG_FXSLS;
19036 confp->chan.radio = 1;
19037 } else if (!strcasecmp(v->value, "fxo_tx")) {
19038 confp->chan.sig = SIG_FXOGS;
19039 confp->chan.radio = 1;
19040 } else if (!strcasecmp(v->value, "em_rx")) {
19041 confp->chan.sig = SIG_EM;
19042 confp->chan.radio = 1;
19043 } else if (!strcasecmp(v->value, "em_tx")) {
19044 confp->chan.sig = SIG_EM;
19045 confp->chan.radio = 1;
19046 } else if (!strcasecmp(v->value, "em_rxtx")) {
19047 confp->chan.sig = SIG_EM;
19048 confp->chan.radio = 2;
19049 } else if (!strcasecmp(v->value, "em_txrx")) {
19050 confp->chan.sig = SIG_EM;
19051 confp->chan.radio = 2;
19052 } else if (!strcasecmp(v->value, "sf")) {
19053 confp->chan.sig = SIG_SF;
19054 } else if (!strcasecmp(v->value, "sf_w")) {
19055 confp->chan.sig = SIG_SFWINK;
19056 } else if (!strcasecmp(v->value, "sf_featd")) {
19057 confp->chan.sig = SIG_FEATD;
19058 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19059 confp->chan.sig = SIG_FEATDMF;
19060 } else if (!strcasecmp(v->value, "sf_featb")) {
19061 confp->chan.sig = SIG_SF_FEATB;
19062 } else if (!strcasecmp(v->value, "sf")) {
19063 confp->chan.sig = SIG_SF;
19064 } else if (!strcasecmp(v->value, "sf_rx")) {
19065 confp->chan.sig = SIG_SF;
19066 confp->chan.radio = 1;
19067 } else if (!strcasecmp(v->value, "sf_tx")) {
19068 confp->chan.sig = SIG_SF;
19069 confp->chan.radio = 1;
19070 } else if (!strcasecmp(v->value, "sf_rxtx")) {
19071 confp->chan.sig = SIG_SF;
19072 confp->chan.radio = 2;
19073 } else if (!strcasecmp(v->value, "sf_txrx")) {
19074 confp->chan.sig = SIG_SF;
19075 confp->chan.radio = 2;
19076 } else if (!strcasecmp(v->value, "featd")) {
19077 confp->chan.sig = SIG_FEATD;
19078 } else if (!strcasecmp(v->value, "featdmf")) {
19079 confp->chan.sig = SIG_FEATDMF;
19080 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19081 confp->chan.sig = SIG_FEATDMF_TA;
19082 } else if (!strcasecmp(v->value, "e911")) {
19083 confp->chan.sig = SIG_E911;
19084 } else if (!strcasecmp(v->value, "fgccama")) {
19085 confp->chan.sig = SIG_FGC_CAMA;
19086 } else if (!strcasecmp(v->value, "fgccamamf")) {
19087 confp->chan.sig = SIG_FGC_CAMAMF;
19088 } else if (!strcasecmp(v->value, "featb")) {
19089 confp->chan.sig = SIG_FEATB;
19090#ifdef HAVE_PRI
19091 } else if (!strcasecmp(v->value, "pri_net")) {
19092 confp->chan.sig = SIG_PRI;
19093 confp->pri.pri.nodetype = PRI_NETWORK;
19094 } else if (!strcasecmp(v->value, "pri_cpe")) {
19095 confp->chan.sig = SIG_PRI;
19096 confp->pri.pri.nodetype = PRI_CPE;
19097 } else if (!strcasecmp(v->value, "bri_cpe")) {
19098 confp->chan.sig = SIG_BRI;
19099 confp->pri.pri.nodetype = PRI_CPE;
19100 } else if (!strcasecmp(v->value, "bri_net")) {
19101 confp->chan.sig = SIG_BRI;
19102 confp->pri.pri.nodetype = PRI_NETWORK;
19103 } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
19104 confp->chan.sig = SIG_BRI_PTMP;
19105 confp->pri.pri.nodetype = PRI_CPE;
19106 } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
19107#if defined(HAVE_PRI_CALL_HOLD)
19108 confp->chan.sig = SIG_BRI_PTMP;
19109 confp->pri.pri.nodetype = PRI_NETWORK;
19110#else
19111 ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v->lineno);
19112#endif /* !defined(HAVE_PRI_CALL_HOLD) */
19113#endif
19114#if defined(HAVE_SS7)
19115 } else if (!strcasecmp(v->value, "ss7")) {
19116 confp->chan.sig = SIG_SS7;
19117#endif /* defined(HAVE_SS7) */
19118#ifdef HAVE_OPENR2
19119 } else if (!strcasecmp(v->value, "mfcr2")) {
19120 confp->chan.sig = SIG_MFCR2;
19121#endif
19122 } else if (!strcasecmp(v->value, "auto")) {
19123 confp->is_sig_auto = 1;
19124 } else {
19125 confp->chan.outsigmod = orig_outsigmod;
19126 confp->chan.radio = orig_radio;
19127 confp->is_sig_auto = orig_auto;
19128 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19129 }
19130 } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
19131 if (!strcasecmp(v->value, "em")) {
19132 confp->chan.outsigmod = SIG_EM;
19133 } else if (!strcasecmp(v->value, "em_e1")) {
19134 confp->chan.outsigmod = SIG_EM_E1;
19135 } else if (!strcasecmp(v->value, "em_w")) {
19136 confp->chan.outsigmod = SIG_EMWINK;
19137 } else if (!strcasecmp(v->value, "sf")) {
19138 confp->chan.outsigmod = SIG_SF;
19139 } else if (!strcasecmp(v->value, "sf_w")) {
19140 confp->chan.outsigmod = SIG_SFWINK;
19141 } else if (!strcasecmp(v->value, "sf_featd")) {
19142 confp->chan.outsigmod = SIG_FEATD;
19143 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19144 confp->chan.outsigmod = SIG_FEATDMF;
19145 } else if (!strcasecmp(v->value, "sf_featb")) {
19146 confp->chan.outsigmod = SIG_SF_FEATB;
19147 } else if (!strcasecmp(v->value, "sf")) {
19148 confp->chan.outsigmod = SIG_SF;
19149 } else if (!strcasecmp(v->value, "featd")) {
19150 confp->chan.outsigmod = SIG_FEATD;
19151 } else if (!strcasecmp(v->value, "featdmf")) {
19152 confp->chan.outsigmod = SIG_FEATDMF;
19153 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19154 confp->chan.outsigmod = SIG_FEATDMF_TA;
19155 } else if (!strcasecmp(v->value, "e911")) {
19156 confp->chan.outsigmod = SIG_E911;
19157 } else if (!strcasecmp(v->value, "fgccama")) {
19158 confp->chan.outsigmod = SIG_FGC_CAMA;
19159 } else if (!strcasecmp(v->value, "fgccamamf")) {
19160 confp->chan.outsigmod = SIG_FGC_CAMAMF;
19161 } else if (!strcasecmp(v->value, "featb")) {
19162 confp->chan.outsigmod = SIG_FEATB;
19163 } else {
19164 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19165 }
19166#ifdef HAVE_PRI
19167 } else if (!strcasecmp(v->name, "pridialplan")) {
19168 if (!strcasecmp(v->value, "national")) {
19169 confp->pri.pri.dialplan = PRI_NATIONAL_ISDN + 1;
19170 } else if (!strcasecmp(v->value, "unknown")) {
19171 confp->pri.pri.dialplan = PRI_UNKNOWN + 1;
19172 } else if (!strcasecmp(v->value, "private")) {
19173 confp->pri.pri.dialplan = PRI_PRIVATE + 1;
19174 } else if (!strcasecmp(v->value, "international")) {
19175 confp->pri.pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
19176 } else if (!strcasecmp(v->value, "local")) {
19177 confp->pri.pri.dialplan = PRI_LOCAL_ISDN + 1;
19178 } else if (!strcasecmp(v->value, "dynamic")) {
19179 confp->pri.pri.dialplan = -1;
19180 } else if (!strcasecmp(v->value, "redundant")) {
19181 confp->pri.pri.dialplan = -2;
19182 } else {
19183 ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
19184 }
19185 } else if (!strcasecmp(v->name, "prilocaldialplan")) {
19186 if (!strcasecmp(v->value, "national")) {
19187 confp->pri.pri.localdialplan = PRI_NATIONAL_ISDN + 1;
19188 } else if (!strcasecmp(v->value, "unknown")) {
19189 confp->pri.pri.localdialplan = PRI_UNKNOWN + 1;
19190 } else if (!strcasecmp(v->value, "private")) {
19191 confp->pri.pri.localdialplan = PRI_PRIVATE + 1;
19192 } else if (!strcasecmp(v->value, "international")) {
19193 confp->pri.pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
19194 } else if (!strcasecmp(v->value, "local")) {
19195 confp->pri.pri.localdialplan = PRI_LOCAL_ISDN + 1;
19196 } else if (!strcasecmp(v->value, "from_channel")) {
19197 confp->pri.pri.localdialplan = 0;
19198 } else if (!strcasecmp(v->value, "dynamic")) {
19199 confp->pri.pri.localdialplan = -1;
19200 } else if (!strcasecmp(v->value, "redundant")) {
19201 confp->pri.pri.localdialplan = -2;
19202 } else {
19203 ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
19204 }
19205 } else if (!strcasecmp(v->name, "pricpndialplan")) {
19206 if (!strcasecmp(v->value, "national")) {
19207 confp->pri.pri.cpndialplan = PRI_NATIONAL_ISDN + 1;
19208 } else if (!strcasecmp(v->value, "unknown")) {
19209 confp->pri.pri.cpndialplan = PRI_UNKNOWN + 1;
19210 } else if (!strcasecmp(v->value, "private")) {
19211 confp->pri.pri.cpndialplan = PRI_PRIVATE + 1;
19212 } else if (!strcasecmp(v->value, "international")) {
19213 confp->pri.pri.cpndialplan = PRI_INTERNATIONAL_ISDN + 1;
19214 } else if (!strcasecmp(v->value, "local")) {
19215 confp->pri.pri.cpndialplan = PRI_LOCAL_ISDN + 1;
19216 } else if (!strcasecmp(v->value, "from_channel")) {
19217 confp->pri.pri.cpndialplan = 0;
19218 } else if (!strcasecmp(v->value, "dynamic")) {
19219 confp->pri.pri.cpndialplan = -1;
19220 } else if (!strcasecmp(v->value, "redundant")) {
19221 confp->pri.pri.cpndialplan = -2;
19222 } else {
19223 ast_log(LOG_WARNING, "Unknown PRI cpndialplan '%s' at line %d.\n", v->value, v->lineno);
19224 }
19225 } else if (!strcasecmp(v->name, "switchtype")) {
19226 if (!strcasecmp(v->value, "national"))
19227 confp->pri.pri.switchtype = PRI_SWITCH_NI2;
19228 else if (!strcasecmp(v->value, "ni1"))
19229 confp->pri.pri.switchtype = PRI_SWITCH_NI1;
19230 else if (!strcasecmp(v->value, "dms100"))
19231 confp->pri.pri.switchtype = PRI_SWITCH_DMS100;
19232 else if (!strcasecmp(v->value, "4ess"))
19233 confp->pri.pri.switchtype = PRI_SWITCH_ATT4ESS;
19234 else if (!strcasecmp(v->value, "5ess"))
19235 confp->pri.pri.switchtype = PRI_SWITCH_LUCENT5E;
19236 else if (!strcasecmp(v->value, "euroisdn"))
19237 confp->pri.pri.switchtype = PRI_SWITCH_EUROISDN_E1;
19238 else if (!strcasecmp(v->value, "qsig"))
19239 confp->pri.pri.switchtype = PRI_SWITCH_QSIG;
19240 else {
19241 ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
19242 return -1;
19243 }
19244 } else if (!strcasecmp(v->name, "msn")) {
19245 ast_copy_string(confp->pri.pri.msn_list, v->value,
19246 sizeof(confp->pri.pri.msn_list));
19247 } else if (!strcasecmp(v->name, "nsf")) {
19248 if (!strcasecmp(v->value, "sdn"))
19249 confp->pri.pri.nsf = PRI_NSF_SDN;
19250 else if (!strcasecmp(v->value, "megacom"))
19251 confp->pri.pri.nsf = PRI_NSF_MEGACOM;
19252 else if (!strcasecmp(v->value, "tollfreemegacom"))
19253 confp->pri.pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
19254 else if (!strcasecmp(v->value, "accunet"))
19255 confp->pri.pri.nsf = PRI_NSF_ACCUNET;
19256 else if (!strcasecmp(v->value, "none"))
19257 confp->pri.pri.nsf = PRI_NSF_NONE;
19258 else {
19259 ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
19260 confp->pri.pri.nsf = PRI_NSF_NONE;
19261 }
19262 } else if (!strcasecmp(v->name, "priindication")) {
19263 if (!strcasecmp(v->value, "outofband"))
19264 confp->chan.priindication_oob = 1;
19265 else if (!strcasecmp(v->value, "inband"))
19266 confp->chan.priindication_oob = 0;
19267 else
19268 ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
19269 v->value, v->lineno);
19270 } else if (!strcasecmp(v->name, "priexclusive")) {
19271 confp->chan.priexclusive = ast_true(v->value);
19272 } else if (!strcasecmp(v->name, "internationalprefix")) {
19273 ast_copy_string(confp->pri.pri.internationalprefix, v->value, sizeof(confp->pri.pri.internationalprefix));
19274 } else if (!strcasecmp(v->name, "nationalprefix")) {
19275 ast_copy_string(confp->pri.pri.nationalprefix, v->value, sizeof(confp->pri.pri.nationalprefix));
19276 } else if (!strcasecmp(v->name, "localprefix")) {
19277 ast_copy_string(confp->pri.pri.localprefix, v->value, sizeof(confp->pri.pri.localprefix));
19278 } else if (!strcasecmp(v->name, "privateprefix")) {
19279 ast_copy_string(confp->pri.pri.privateprefix, v->value, sizeof(confp->pri.pri.privateprefix));
19280 } else if (!strcasecmp(v->name, "unknownprefix")) {
19281 ast_copy_string(confp->pri.pri.unknownprefix, v->value, sizeof(confp->pri.pri.unknownprefix));
19282 } else if (!strcasecmp(v->name, "resetinterval")) {
19283 if (!strcasecmp(v->value, "never"))
19284 confp->pri.pri.resetinterval = -1;
19285 else if (atoi(v->value) >= 60)
19286 confp->pri.pri.resetinterval = atoi(v->value);
19287 else
19288 ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
19289 v->value, v->lineno);
19290 } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
19291 confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
19292 } else if (!strcasecmp(v->name, "minunused")) {
19293 confp->pri.pri.minunused = atoi(v->value);
19294 } else if (!strcasecmp(v->name, "minidle")) {
19295 confp->pri.pri.minidle = atoi(v->value);
19296 } else if (!strcasecmp(v->name, "idleext")) {
19297 ast_copy_string(confp->pri.pri.idleext, v->value, sizeof(confp->pri.pri.idleext));
19298 } else if (!strcasecmp(v->name, "idledial")) {
19299 ast_copy_string(confp->pri.pri.idledial, v->value, sizeof(confp->pri.pri.idledial));
19300 } else if (!strcasecmp(v->name, "overlapdial")) {
19301 if (ast_true(v->value)) {
19302 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19303 } else if (!strcasecmp(v->value, "incoming")) {
19304 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
19305 } else if (!strcasecmp(v->value, "outgoing")) {
19306 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
19307 } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
19308 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19309 } else {
19310 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
19311 }
19312#ifdef HAVE_PRI_PROG_W_CAUSE
19313 } else if (!strcasecmp(v->name, "qsigchannelmapping")) {
19314 if (!strcasecmp(v->value, "logical")) {
19315 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_LOGICAL;
19316 } else if (!strcasecmp(v->value, "physical")) {
19317 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19318 } else {
19319 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19320 }
19321#endif
19322 } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) {
19323 confp->pri.pri.discardremoteholdretrieval = ast_true(v->value);
19324#if defined(HAVE_PRI_SERVICE_MESSAGES)
19325 } else if (!strcasecmp(v->name, "service_message_support")) {
19326 /* assuming switchtype for this channel group has been configured already */
19327 if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
19328 || confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
19329 || confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
19330 confp->pri.pri.enable_service_message_support = 1;
19331 } else {
19332 confp->pri.pri.enable_service_message_support = 0;
19333 }
19334#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
19335#ifdef HAVE_PRI_INBANDDISCONNECT
19336 } else if (!strcasecmp(v->name, "inbanddisconnect")) {
19337 confp->pri.pri.inbanddisconnect = ast_true(v->value);
19338#endif
19339 } else if (!strcasecmp(v->name, "pritimer")) {
19340#ifdef PRI_GETSET_TIMERS
19341 char tmp[20];
19342 char *timerc;
19343 char *c;
19344 int timer;
19345 int timeridx;
19346
19347 ast_copy_string(tmp, v->value, sizeof(tmp));
19348 c = tmp;
19349 timerc = strsep(&c, ",");
19350 if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
19351 timeridx = pri_timer2idx(timerc);
19352 timer = atoi(c);
19353 if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
19355 "'%s' is not a valid ISDN timer at line %d.\n", timerc,
19356 v->lineno);
19357 } else if (!timer) {
19359 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19360 c, timerc, v->lineno);
19361 } else {
19362 confp->pri.pri.pritimers[timeridx] = timer;
19363 }
19364 } else {
19366 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19367 v->value, v->lineno);
19368 }
19369#endif /* PRI_GETSET_TIMERS */
19370 } else if (!strcasecmp(v->name, "facilityenable")) {
19371 confp->pri.pri.facilityenable = ast_true(v->value);
19372#if defined(HAVE_PRI_AOC_EVENTS)
19373 } else if (!strcasecmp(v->name, "aoc_enable")) {
19374 confp->pri.pri.aoc_passthrough_flag = 0;
19375 if (strchr(v->value, 's') || strchr(v->value, 'S')) {
19376 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_S;
19377 }
19378 if (strchr(v->value, 'd') || strchr(v->value, 'D')) {
19379 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_D;
19380 }
19381 if (strchr(v->value, 'e') || strchr(v->value, 'E')) {
19382 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_E;
19383 }
19384 } else if (!strcasecmp(v->name, "aoce_delayhangup")) {
19385 confp->pri.pri.aoce_delayhangup = ast_true(v->value);
19386#endif /* defined(HAVE_PRI_AOC_EVENTS) */
19387#if defined(HAVE_PRI_CALL_HOLD)
19388 } else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
19389 confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
19390#endif /* defined(HAVE_PRI_CALL_HOLD) */
19391 } else if (!strcasecmp(v->name, "moh_signaling")
19392 || !strcasecmp(v->name, "moh_signalling")) {
19393 if (!strcasecmp(v->value, "moh")) {
19394 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19395 } else if (!strcasecmp(v->value, "notify")) {
19396 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_NOTIFY;
19397#if defined(HAVE_PRI_CALL_HOLD)
19398 } else if (!strcasecmp(v->value, "hold")) {
19399 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_HOLD;
19400#endif /* defined(HAVE_PRI_CALL_HOLD) */
19401 } else {
19402 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19403 }
19404#if defined(HAVE_PRI_CCSS)
19405 } else if (!strcasecmp(v->name, "cc_ptmp_recall_mode")) {
19406 if (!strcasecmp(v->value, "global")) {
19407 confp->pri.pri.cc_ptmp_recall_mode = 0;/* globalRecall */
19408 } else if (!strcasecmp(v->value, "specific")) {
19409 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19410 } else {
19411 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19412 }
19413 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_req")) {
19414 if (!strcasecmp(v->value, "release")) {
19415 confp->pri.pri.cc_qsig_signaling_link_req = 0;/* release */
19416 } else if (!strcasecmp(v->value, "retain")) {
19417 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19418 } else if (!strcasecmp(v->value, "do_not_care")) {
19419 confp->pri.pri.cc_qsig_signaling_link_req = 2;/* do-not-care */
19420 } else {
19421 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19422 }
19423 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_rsp")) {
19424 if (!strcasecmp(v->value, "release")) {
19425 confp->pri.pri.cc_qsig_signaling_link_rsp = 0;/* release */
19426 } else if (!strcasecmp(v->value, "retain")) {
19427 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19428 } else {
19429 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19430 }
19431#endif /* defined(HAVE_PRI_CCSS) */
19432#if defined(HAVE_PRI_CALL_WAITING)
19433 } else if (!strcasecmp(v->name, "max_call_waiting_calls")) {
19434 confp->pri.pri.max_call_waiting_calls = atoi(v->value);
19435 if (confp->pri.pri.max_call_waiting_calls < 0) {
19436 /* Negative values are not allowed. */
19437 confp->pri.pri.max_call_waiting_calls = 0;
19438 }
19439 } else if (!strcasecmp(v->name, "allow_call_waiting_calls")) {
19440 confp->pri.pri.allow_call_waiting_calls = ast_true(v->value);
19441#endif /* defined(HAVE_PRI_CALL_WAITING) */
19442#if defined(HAVE_PRI_MWI)
19443 } else if (!strcasecmp(v->name, "mwi_mailboxes")) {
19444 ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
19445 sizeof(confp->pri.pri.mwi_mailboxes));
19446 } else if (!strcasecmp(v->name, "mwi_vm_boxes")) {
19447 ast_copy_string(confp->pri.pri.mwi_vm_boxes, v->value,
19448 sizeof(confp->pri.pri.mwi_vm_boxes));
19449 } else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
19450 ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
19451 sizeof(confp->pri.pri.mwi_vm_numbers));
19452#endif /* defined(HAVE_PRI_MWI) */
19453 } else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
19454 confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
19455 } else if (!strcasecmp(v->name, "inband_on_setup_ack")) {
19456 confp->pri.pri.inband_on_setup_ack = ast_true(v->value);
19457 } else if (!strcasecmp(v->name, "inband_on_proceeding")) {
19458 confp->pri.pri.inband_on_proceeding = ast_true(v->value);
19459#if defined(HAVE_PRI_DISPLAY_TEXT)
19460 } else if (!strcasecmp(v->name, "display_send")) {
19461 confp->pri.pri.display_flags_send = dahdi_display_text_option(v->value);
19462 } else if (!strcasecmp(v->name, "display_receive")) {
19463 confp->pri.pri.display_flags_receive = dahdi_display_text_option(v->value);
19464#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19465#if defined(HAVE_PRI_MCID)
19466 } else if (!strcasecmp(v->name, "mcid_send")) {
19467 confp->pri.pri.mcid_send = ast_true(v->value);
19468#endif /* defined(HAVE_PRI_MCID) */
19469#if defined(HAVE_PRI_DATETIME_SEND)
19470 } else if (!strcasecmp(v->name, "datetime_send")) {
19471 confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
19472#endif /* defined(HAVE_PRI_DATETIME_SEND) */
19473 } else if (!strcasecmp(v->name, "layer1_presence")) {
19474 if (!strcasecmp(v->value, "required")) {
19475 confp->pri.pri.layer1_ignored = 0;
19476 } else if (!strcasecmp(v->value, "ignore")) {
19477 confp->pri.pri.layer1_ignored = 1;
19478 } else {
19479 /* Default */
19480 confp->pri.pri.layer1_ignored = 0;
19481 }
19482#if defined(HAVE_PRI_L2_PERSISTENCE)
19483 } else if (!strcasecmp(v->name, "layer2_persistence")) {
19484 if (!strcasecmp(v->value, "keep_up")) {
19485 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_KEEP_UP;
19486 } else if (!strcasecmp(v->value, "leave_down")) {
19487 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_LEAVE_DOWN;
19488 } else {
19489 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_DEFAULT;
19490 }
19491#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19492 } else if (!strcasecmp(v->name, "colp_send")) {
19493 if (!strcasecmp(v->value, "block")) {
19494 confp->pri.pri.colp_send = SIG_PRI_COLP_BLOCK;
19495 } else if (!strcasecmp(v->value, "connect")) {
19496 confp->pri.pri.colp_send = SIG_PRI_COLP_CONNECT;
19497 } else if (!strcasecmp(v->value, "update")) {
19498 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19499 } else {
19500 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19501 }
19502#endif /* HAVE_PRI */
19503#if defined(HAVE_SS7)
19504 } else if (!strcasecmp(v->name, "ss7type")) {
19505 if (!strcasecmp(v->value, "itu")) {
19506 cur_ss7type = SS7_ITU;
19507 } else if (!strcasecmp(v->value, "ansi")) {
19508 cur_ss7type = SS7_ANSI;
19509 } else {
19510 ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
19511 }
19512 } else if (!strcasecmp(v->name, "slc")) {
19513 cur_slc = atoi(v->value);
19514 } else if (!strcasecmp(v->name, "linkset")) {
19515 cur_linkset = atoi(v->value);
19516 } else if (!strcasecmp(v->name, "pointcode")) {
19517 cur_pointcode = parse_pointcode(v->value);
19518 } else if (!strcasecmp(v->name, "adjpointcode")) {
19519 cur_adjpointcode = parse_pointcode(v->value);
19520 } else if (!strcasecmp(v->name, "defaultdpc")) {
19521 cur_defaultdpc = parse_pointcode(v->value);
19522 } else if (!strcasecmp(v->name, "cicbeginswith")) {
19523 cur_cicbeginswith = atoi(v->value);
19524 } else if (!strcasecmp(v->name, "networkindicator")) {
19525 if (!strcasecmp(v->value, "national")) {
19526 cur_networkindicator = SS7_NI_NAT;
19527 } else if (!strcasecmp(v->value, "national_spare")) {
19528 cur_networkindicator = SS7_NI_NAT_SPARE;
19529 } else if (!strcasecmp(v->value, "international")) {
19530 cur_networkindicator = SS7_NI_INT;
19531 } else if (!strcasecmp(v->value, "international_spare")) {
19532 cur_networkindicator = SS7_NI_INT_SPARE;
19533 } else {
19534 cur_networkindicator = -1;
19535 }
19536 } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
19537 ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
19538 } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
19539 ast_copy_string(confp->ss7.ss7.nationalprefix, v->value, sizeof(confp->ss7.ss7.nationalprefix));
19540 } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
19541 ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
19542 } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
19543 ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
19544 } else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
19545 ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
19546 } else if (!strcasecmp(v->name, "ss7_called_nai")) {
19547 if (!strcasecmp(v->value, "national")) {
19548 confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
19549 } else if (!strcasecmp(v->value, "international")) {
19550 confp->ss7.ss7.called_nai = SS7_NAI_INTERNATIONAL;
19551 } else if (!strcasecmp(v->value, "subscriber")) {
19552 confp->ss7.ss7.called_nai = SS7_NAI_SUBSCRIBER;
19553 } else if (!strcasecmp(v->value, "unknown")) {
19554 confp->ss7.ss7.called_nai = SS7_NAI_UNKNOWN;
19555 } else if (!strcasecmp(v->value, "dynamic")) {
19556 confp->ss7.ss7.called_nai = SS7_NAI_DYNAMIC;
19557 } else {
19558 ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
19559 }
19560 } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
19561 if (!strcasecmp(v->value, "national")) {
19562 confp->ss7.ss7.calling_nai = SS7_NAI_NATIONAL;
19563 } else if (!strcasecmp(v->value, "international")) {
19564 confp->ss7.ss7.calling_nai = SS7_NAI_INTERNATIONAL;
19565 } else if (!strcasecmp(v->value, "subscriber")) {
19566 confp->ss7.ss7.calling_nai = SS7_NAI_SUBSCRIBER;
19567 } else if (!strcasecmp(v->value, "unknown")) {
19568 confp->ss7.ss7.calling_nai = SS7_NAI_UNKNOWN;
19569 } else if (!strcasecmp(v->value, "dynamic")) {
19570 confp->ss7.ss7.calling_nai = SS7_NAI_DYNAMIC;
19571 } else {
19572 ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
19573 }
19574 } else if (!strcasecmp(v->name, "sigchan")) {
19575 int sigchan, res;
19576 sigchan = atoi(v->value);
19577 res = linkset_addsigchan(sigchan);
19578 if (res < 0) {
19579 return -1;
19580 }
19581 } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
19582 struct dahdi_ss7 *link;
19583 link = ss7_resolve_linkset(cur_linkset);
19584 if (!link) {
19585 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19586 return -1;
19587 }
19588 if (ast_true(v->value)) {
19589 link->ss7.flags |= LINKSET_FLAG_EXPLICITACM;
19590 } else {
19591 link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
19592 }
19593 } else if (!strcasecmp(v->name, "ss7_autoacm")) {
19594 struct dahdi_ss7 *link;
19595 link = ss7_resolve_linkset(cur_linkset);
19596 if (!link) {
19597 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19598 return -1;
19599 }
19600 if (ast_true(v->value)) {
19601 link->ss7.flags |= LINKSET_FLAG_AUTOACM;
19602 } else {
19603 link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
19604 }
19605 } else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
19606 struct dahdi_ss7 *link;
19607 link = ss7_resolve_linkset(cur_linkset);
19608 if (!link) {
19609 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19610 return -1;
19611 }
19612 if (ast_true(v->value)) {
19613 link->ss7.flags |= LINKSET_FLAG_INITIALHWBLO;
19614 } else {
19615 link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
19616 }
19617 } else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
19618 struct dahdi_ss7 *link;
19619 link = ss7_resolve_linkset(cur_linkset);
19620 if (!link) {
19621 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19622 return -1;
19623 }
19624 if (ast_true(v->value)) {
19625 link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
19626 } else {
19627 link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
19628 }
19629 } else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
19630 struct dahdi_ss7 *link;
19631 link = ss7_resolve_linkset(cur_linkset);
19632 if (!link) {
19633 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19634 return -1;
19635 }
19636 if (ast_true(v->value)) {
19637 link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
19638 } else {
19639 link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
19640 }
19641 } else if (!strncasecmp(v->name, "isup_timer.", 11)) {
19642 struct dahdi_ss7 *link;
19643 link = ss7_resolve_linkset(cur_linkset);
19644 if (!link) {
19645 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19646 return -1;
19647 }
19648 if (!link->ss7.ss7) {
19649 ast_log(LOG_ERROR, "Please specify isup timers after sigchan!\n");
19650 } else if (!ss7_set_isup_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19651 ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
19652 }
19653 } else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
19654 struct dahdi_ss7 *link;
19655 link = ss7_resolve_linkset(cur_linkset);
19656 if (!link) {
19657 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19658 return -1;
19659 }
19660 if (!link->ss7.ss7) {
19661 ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
19662 } else if (!ss7_set_mtp3_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19663 ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
19664 }
19665 } else if (!strcasecmp(v->name, "inr_if_no_calling")) {
19666 struct dahdi_ss7 *link;
19667 link = ss7_resolve_linkset(cur_linkset);
19668 if (!link) {
19669 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19670 return -1;
19671 }
19672 if (!link->ss7.ss7) {
19673 ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
19674 } else if (ast_true(v->value)) {
19675 ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19676 } else {
19677 ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19678 }
19679 } else if (!strcasecmp(v->name, "non_isdn_access")) {
19680 struct dahdi_ss7 *link;
19681 link = ss7_resolve_linkset(cur_linkset);
19682 if (!link) {
19683 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19684 return -1;
19685 }
19686 if (!link->ss7.ss7) {
19687 ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
19688 } else if (ast_true(v->value)) {
19689 ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19690 } else {
19691 ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19692 }
19693 } else if (!strcasecmp(v->name, "sls_shift")) {
19694 struct dahdi_ss7 *link;
19695 int sls_shift = atoi(v->value);
19696
19697 if (sls_shift < 0 || sls_shift > 7) {
19698 ast_log(LOG_ERROR, "Invalid sls_shift value. Must be between 0 and 7\n");
19699 return -1;
19700 }
19701
19702 link = ss7_resolve_linkset(cur_linkset);
19703 if (!link) {
19704 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19705 return -1;
19706 }
19707 if (!link->ss7.ss7) {
19708 ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
19709 } else {
19710 ss7_set_sls_shift(link->ss7.ss7, sls_shift);
19711 }
19712 } else if (!strcasecmp(v->name, "cause_location")) {
19713 struct dahdi_ss7 *link;
19714 int cause_location = atoi(v->value);
19715
19716 if (cause_location < 0 || cause_location > 15) {
19717 ast_log(LOG_ERROR, "Invalid cause_location value. Must be between 0 and 15\n");
19718 return -1;
19719 }
19720 link = ss7_resolve_linkset(cur_linkset);
19721 if (!link) {
19722 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19723 return -1;
19724 }
19725 if (!link->ss7.ss7) {
19726 ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
19727 } else {
19728 ss7_set_cause_location(link->ss7.ss7, cause_location);
19729 }
19730#endif /* defined(HAVE_SS7) */
19731#ifdef HAVE_OPENR2
19732 } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
19733 ast_copy_string(confp->mfcr2.r2proto_file, v->value, sizeof(confp->mfcr2.r2proto_file));
19734 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);
19735 } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
19736 ast_copy_string(confp->mfcr2.logdir, v->value, sizeof(confp->mfcr2.logdir));
19737 } else if (!strcasecmp(v->name, "mfcr2_variant")) {
19738 confp->mfcr2.variant = openr2_proto_get_variant(v->value);
19739 if (OR2_VAR_UNKNOWN == confp->mfcr2.variant) {
19740 ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v->value, v->lineno);
19741 confp->mfcr2.variant = OR2_VAR_ITU;
19742 }
19743 } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
19744 confp->mfcr2.mfback_timeout = atoi(v->value);
19745 if (!confp->mfcr2.mfback_timeout) {
19746 ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19747 confp->mfcr2.mfback_timeout = -1;
19748 } else if (confp->mfcr2.mfback_timeout > 0 && confp->mfcr2.mfback_timeout < 500) {
19749 ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19750 }
19751 } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
19752 confp->mfcr2.metering_pulse_timeout = atoi(v->value);
19753 if (confp->mfcr2.metering_pulse_timeout > 500) {
19754 ast_log(LOG_WARNING, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19755 }
19756#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19757 } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
19758 confp->mfcr2.dtmf_detection = ast_true(v->value) ? 1 : 0;
19759 } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
19760 confp->mfcr2.dtmf_dialing = ast_true(v->value) ? 1 : 0;
19761 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
19762 confp->mfcr2.dtmf_time_on = atoi(v->value);
19763 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
19764 confp->mfcr2.dtmf_time_off = atoi(v->value);
19765#endif
19766#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19767 } else if (!strcasecmp(v->name, "mfcr2_dtmf_end_timeout")) {
19768 confp->mfcr2.dtmf_end_timeout = atoi(v->value);
19769#endif
19770 } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
19771 confp->mfcr2.get_ani_first = ast_true(v->value) ? 1 : 0;
19772 } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
19773 confp->mfcr2.double_answer = ast_true(v->value) ? 1 : 0;
19774 } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
19775 confp->mfcr2.charge_calls = ast_true(v->value) ? 1 : 0;
19776 } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
19777 confp->mfcr2.accept_on_offer = ast_true(v->value) ? 1 : 0;
19778 } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
19779 confp->mfcr2.allow_collect_calls = ast_true(v->value) ? 1 : 0;
19780 } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
19781 confp->mfcr2.forced_release = ast_true(v->value) ? 1 : 0;
19782 } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
19783 confp->mfcr2.immediate_accept = ast_true(v->value) ? 1 : 0;
19784#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19785 } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
19786 confp->mfcr2.skip_category_request = ast_true(v->value) ? 1 : 0;
19787#endif
19788 } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
19789 confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
19790 } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
19791 confp->mfcr2.max_ani = atoi(v->value);
19792 if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
19793 confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
19794 }
19795 } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
19796 confp->mfcr2.max_dnis = atoi(v->value);
19797 if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
19798 confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
19799 }
19800 } else if (!strcasecmp(v->name, "mfcr2_category")) {
19801 confp->mfcr2.category = openr2_proto_get_category(v->value);
19802 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == confp->mfcr2.category) {
19803 confp->mfcr2.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
19804 ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19805 v->value, v->lineno);
19806 }
19807 } else if (!strcasecmp(v->name, "mfcr2_logging")) {
19808 openr2_log_level_t tmplevel;
19809 char *clevel;
19810 char *logval;
19811 char copy[strlen(v->value) + 1];
19812 strcpy(copy, v->value); /* safe */
19813 logval = copy;
19814 while (logval) {
19815 clevel = strsep(&logval,",");
19816 if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
19817 ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", clevel, v->lineno);
19818 continue;
19819 }
19820 confp->mfcr2.loglevel |= tmplevel;
19821 }
19822#endif /* HAVE_OPENR2 */
19823 } else if (!strcasecmp(v->name, "cadence")) {
19824 /* setup to scan our argument */
19825 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
19826 int i;
19827 struct dahdi_ring_cadence new_cadence;
19828 int cid_location = -1;
19829 int firstcadencepos = 0;
19830 char original_args[80];
19831 int cadence_is_ok = 1;
19832
19833 ast_copy_string(original_args, v->value, sizeof(original_args));
19834 /* 16 cadences allowed (8 pairs) */
19835 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]);
19836
19837 /* Cadence must be even (on/off) */
19838 if (element_count % 2 == 1) {
19839 ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
19840 cadence_is_ok = 0;
19841 }
19842
19843 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
19844 if (element_count > ARRAY_LEN(c)) {
19845 element_count = ARRAY_LEN(c);
19846 }
19847
19848 /* Ring cadences cannot be negative */
19849 for (i = 0; i < element_count; i++) {
19850 if (c[i] == 0) {
19851 ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
19852 cadence_is_ok = 0;
19853 break;
19854 } else if (c[i] < 0) {
19855 if (i % 2 == 1) {
19856 /* Silence duration, negative possibly okay */
19857 if (cid_location == -1) {
19858 cid_location = i;
19859 c[i] *= -1;
19860 } else {
19861 ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
19862 cadence_is_ok = 0;
19863 break;
19864 }
19865 } else {
19866 if (firstcadencepos == 0) {
19867 firstcadencepos = i; /* only recorded to avoid duplicate specification */
19868 /* duration will be passed negative to the DAHDI driver */
19869 } else {
19870 ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
19871 cadence_is_ok = 0;
19872 break;
19873 }
19874 }
19875 }
19876 }
19877
19878 /* Substitute our scanned cadence */
19879 for (i = 0; i < 16; i++) {
19880 new_cadence.ringcadence[i] = c[i];
19881 }
19882
19883 if (cadence_is_ok) {
19884 /* ---we scanned it without getting annoyed; now some sanity checks--- */
19885 if (element_count < 2) {
19886 ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
19887 } else {
19888 if (cid_location == -1) {
19889 /* user didn't say; default to first pause */
19890 cid_location = 1;
19891 } else {
19892 /* convert element_index to cidrings value */
19893 cid_location = (cid_location + 1) / 2;
19894 }
19895 /* ---we like their cadence; try to install it--- */
19897 /* this is the first user-defined cadence; clear the default user cadences */
19898 num_cadence = 0;
19899 if ((num_cadence+1) >= NUM_CADENCE_MAX)
19900 ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
19901 else {
19902 cadences[num_cadence] = new_cadence;
19903 cidrings[num_cadence++] = cid_location;
19904 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
19905 }
19906 }
19907 }
19908 } else if (!strcasecmp(v->name, "ringtimeout")) {
19909 ringt_base = (atoi(v->value) * 8) / READ_SIZE;
19910 } else if (!strcasecmp(v->name, "prewink")) {
19911 confp->timing.prewinktime = atoi(v->value);
19912 } else if (!strcasecmp(v->name, "preflash")) {
19913 confp->timing.preflashtime = atoi(v->value);
19914 } else if (!strcasecmp(v->name, "wink")) {
19915 confp->timing.winktime = atoi(v->value);
19916 } else if (!strcasecmp(v->name, "flash")) {
19917 confp->timing.flashtime = atoi(v->value);
19918 } else if (!strcasecmp(v->name, "start")) {
19919 confp->timing.starttime = atoi(v->value);
19920 } else if (!strcasecmp(v->name, "rxwink")) {
19921 confp->timing.rxwinktime = atoi(v->value);
19922 } else if (!strcasecmp(v->name, "rxflash")) {
19923 confp->timing.rxflashtime = atoi(v->value);
19924 } else if (!strcasecmp(v->name, "debounce")) {
19925 confp->timing.debouncetime = atoi(v->value);
19926 } else if (!strcasecmp(v->name, "toneduration")) {
19927 int toneduration;
19928 int ctlfd;
19929 int res;
19930 struct dahdi_dialparams dps;
19931
19932 ctlfd = open("/dev/dahdi/ctl", O_RDWR);
19933 if (ctlfd == -1) {
19934 ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
19935 return -1;
19936 }
19937
19938 toneduration = atoi(v->value);
19939 if (toneduration > -1) {
19940 memset(&dps, 0, sizeof(dps));
19941
19942 dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
19943 res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
19944 if (res < 0) {
19945 ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
19946 close(ctlfd);
19947 return -1;
19948 }
19949 }
19950 close(ctlfd);
19951 } else if (!strcasecmp(v->name, "defaultcic")) {
19953 } else if (!strcasecmp(v->name, "defaultozz")) {
19955 } else if (!strcasecmp(v->name, "mwilevel")) {
19956 mwilevel = atoi(v->value);
19957 } else if (!strcasecmp(v->name, "dtmfcidlevel")) {
19958 dtmfcid_level = atoi(v->value);
19959 } else if (!strcasecmp(v->name, "reportalarms")) {
19960 if (!strcasecmp(v->value, "all"))
19962 if (!strcasecmp(v->value, "none"))
19963 report_alarms = 0;
19964 else if (!strcasecmp(v->value, "channels"))
19966 else if (!strcasecmp(v->value, "spans"))
19968 }
19969 } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
19970 ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
19971 }
19972
19973 if (dahdichan) {
19974 /* Process the deferred dahdichan value. */
19975 if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
19976 if (confp->ignore_failed_channels) {
19978 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
19979 dahdichan->value);
19980 } else {
19981 return -1;
19982 }
19983 }
19984 }
19985
19986 /*
19987 * Since confp has already filled individual dahdi_pvt objects with channels
19988 * at this point, clear the variables in confp's pvt.
19989 */
19990 if (confp->chan.vars) {
19992 confp->chan.vars = NULL;
19993 }
19994
19995 /* mark the first channels of each DAHDI span to watch for their span alarms */
19996 for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
19997 if (!tmp->destroy && tmp->span != y) {
19998 tmp->manages_span_alarms = 1;
19999 y = tmp->span;
20000 } else {
20001 tmp->manages_span_alarms = 0;
20002 }
20003 }
20004
20005 /*< \todo why check for the pseudo in the per-channel section.
20006 * Any actual use for manual setup of the pseudo channel? */
20007 if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
20008 /* use the default configuration for a channel, so
20009 that any settings from real configured channels
20010 don't "leak" into the pseudo channel config
20011 */
20013
20014 if (conf.chan.cc_params) {
20015 tmp = mkintf(CHAN_PSEUDO, &conf, reload);
20016 } else {
20017 tmp = NULL;
20018 }
20019 if (tmp) {
20020 ast_verb(3, "Automatically generated pseudo channel\n");
20021 has_pseudo = 1;
20022 } else {
20023 ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
20024 }
20025 ast_cc_config_params_destroy(conf.chan.cc_params);
20026 }
20027
20028 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
20031
20032 return 0;
20033}
20034
20035/*!
20036 * \internal
20037 * \brief Deep copy struct dahdi_chan_conf.
20038 * \since 1.8
20039 *
20040 * \param dest Destination.
20041 * \param src Source.
20042 */
20043static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
20044{
20045 struct ast_cc_config_params *cc_params;
20046
20047 cc_params = dest->chan.cc_params;
20048 *dest = *src;
20049 dest->chan.cc_params = cc_params;
20051}
20052
20053/*!
20054 * \internal
20055 * \brief Setup DAHDI channel driver.
20056 *
20057 * \param reload enum: load_module(0), reload(1), restart(2).
20058 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
20059 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
20060 * \param conf Local config parameters. So cc_params can be properly destroyed.
20061 *
20062 * \retval 0 on success.
20063 * \retval -1 on error.
20064 */
20065static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
20066{
20067 struct ast_config *cfg;
20068 struct ast_config;
20069 struct ast_variable *v;
20070 struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
20071 const char *chans;
20072 const char *cat;
20073 int res;
20074
20075#ifdef HAVE_PRI
20076 char *c;
20077 int spanno;
20078 int i;
20079 int logicalspan;
20080 int trunkgroup;
20081 int dchannels[SIG_PRI_NUM_DCHANS];
20082#endif
20083 int have_cfg_now;
20084 static int had_cfg_before = 1;/* So initial load will complain if we don't have cfg. */
20085
20086 cfg = ast_config_load(config, config_flags);
20087 have_cfg_now = !!cfg;
20088 if (!cfg) {
20089 /* Error if we have no config file */
20090 if (had_cfg_before) {
20091 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
20093 }
20094 cfg = ast_config_new();/* Dummy config */
20095 if (!cfg) {
20096 return 0;
20097 }
20098 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
20100 cfg = ast_config_load(config, config_flags);
20101 have_cfg_now = !!cfg;
20102 if (!cfg) {
20103 if (had_cfg_before) {
20104 /* We should have been able to load the config. */
20105 ast_log(LOG_ERROR, "Bad. Unable to load config %s\n", config);
20106 return 0;
20107 }
20108 cfg = ast_config_new();/* Dummy config */
20109 if (!cfg) {
20110 return 0;
20111 }
20112 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20113 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20114 return 0;
20115 }
20116 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20117 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20118 return 0;
20119 } else {
20121 }
20122 had_cfg_before = have_cfg_now;
20123
20124 /* It's a little silly to lock it, but we might as well just to be sure */
20126#ifdef HAVE_PRI
20127 if (reload != 1) {
20128 /* Process trunkgroups first */
20129 v = ast_variable_browse(cfg, "trunkgroups");
20130 while (v) {
20131 if (!strcasecmp(v->name, "trunkgroup")) {
20132 trunkgroup = atoi(v->value);
20133 if (trunkgroup > 0) {
20134 if ((c = strchr(v->value, ','))) {
20135 i = 0;
20136 memset(dchannels, 0, sizeof(dchannels));
20137 while (c && (i < SIG_PRI_NUM_DCHANS)) {
20138 dchannels[i] = atoi(c + 1);
20139 if (dchannels[i] < 0) {
20140 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);
20141 } else
20142 i++;
20143 c = strchr(c + 1, ',');
20144 }
20145 if (i) {
20146 if (pri_create_trunkgroup(trunkgroup, dchannels)) {
20147 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);
20148 } else
20149 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");
20150 } else
20151 ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20152 } else
20153 ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20154 } else
20155 ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20156 } else if (!strcasecmp(v->name, "spanmap")) {
20157 spanno = atoi(v->value);
20158 if (spanno > 0) {
20159 if ((c = strchr(v->value, ','))) {
20160 trunkgroup = atoi(c + 1);
20161 if (trunkgroup > 0) {
20162 if ((c = strchr(c + 1, ',')))
20163 logicalspan = atoi(c + 1);
20164 else
20165 logicalspan = 0;
20166 if (logicalspan >= 0) {
20167 if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
20168 ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20169 } else
20170 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20171 } else
20172 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);
20173 } else
20174 ast_log(LOG_WARNING, "Trunk group must be a positive number at line %d of chan_dahdi.conf\n", v->lineno);
20175 } else
20176 ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
20177 } else
20178 ast_log(LOG_WARNING, "Span number must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20179 } else {
20180 ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
20181 }
20182 v = v->next;
20183 }
20184 }
20185#endif
20186
20187 /* Copy the default jb config over global_jbconf */
20188 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
20189
20190 mwimonitornotify[0] = '\0';
20191
20192 v = ast_variable_browse(cfg, "channels");
20193 if ((res = process_dahdi(base_conf,
20194 "" /* Must be empty for the channels category. Silly voicemail mailbox. */,
20195 v, reload, 0))) {
20197 ast_config_destroy(cfg);
20198 return res;
20199 }
20200
20201 /* Now get configuration from all normal sections in chan_dahdi.conf: */
20202 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
20203 /* [channels] and [trunkgroups] are used. Let's also reserve
20204 * [globals] and [general] for future use
20205 */
20206 if (!strcasecmp(cat, "general") ||
20207 !strcasecmp(cat, "trunkgroups") ||
20208 !strcasecmp(cat, "globals") ||
20209 !strcasecmp(cat, "channels")) {
20210 continue;
20211 }
20212
20213 chans = ast_variable_retrieve(cfg, cat, "dahdichan");
20214 if (ast_strlen_zero(chans)) {
20215 /* Section is useless without a dahdichan value present. */
20216 continue;
20217 }
20218
20219 /* Copy base_conf to conf. */
20220 deep_copy_dahdi_chan_conf(conf, base_conf);
20221
20222 if ((res = process_dahdi(conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
20224 ast_config_destroy(cfg);
20225 return res;
20226 }
20227 }
20228
20229 ast_config_destroy(cfg);
20231
20232#ifdef HAVE_PRI
20233 if (reload != 1) {
20234 int x;
20235 for (x = 0; x < NUM_SPANS; x++) {
20236 if (pris[x].pri.pvts[0] &&
20237 pris[x].pri.master == AST_PTHREADT_NULL) {
20238 prepare_pri(pris + x);
20239 if (sig_pri_start_pri(&pris[x].pri)) {
20240 ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
20241 return -1;
20242 } else
20243 ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
20244 }
20245 }
20246 }
20247#endif
20248#if defined(HAVE_SS7)
20249 if (reload != 1) {
20250 int x;
20251 for (x = 0; x < NUM_SPANS; x++) {
20252 if (linksets[x].ss7.ss7) {
20253 if (ast_pthread_create(&linksets[x].ss7.master, NULL, ss7_linkset, &linksets[x].ss7)) {
20254 ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
20255 return -1;
20256 } else
20257 ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
20258 }
20259 }
20260 }
20261#endif /* defined(HAVE_SS7) */
20262#ifdef HAVE_OPENR2
20263 if (reload != 1) {
20264 struct r2link_entry *cur;
20265 int x = 0;
20266 AST_LIST_LOCK(&r2links);
20267 AST_LIST_TRAVERSE(&r2links, cur, list) {
20268 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
20269 if (r2->r2master == AST_PTHREADT_NULL) {
20270 if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
20271 ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
20272 return -1;
20273 } else {
20274 ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
20275 }
20276 x++;
20277 }
20278 }
20279 AST_LIST_UNLOCK(&r2links);
20280 }
20281#endif
20282 /* And start the monitor for the first time */
20284 return 0;
20285}
20286
20287/*!
20288 * \internal
20289 * \brief Setup DAHDI channel driver.
20290 *
20291 * \param reload enum: load_module(0), reload(1), restart(2).
20292 *
20293 * \retval 0 on success.
20294 * \retval -1 on error.
20295 */
20296static int setup_dahdi(int reload)
20297{
20298 int res;
20299 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
20300 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
20302
20303 if (default_conf.chan.cc_params && base_conf.chan.cc_params && conf.chan.cc_params) {
20304 res = setup_dahdi_int(reload, &default_conf, &base_conf, &conf);
20305 } else {
20306 res = -1;
20307 }
20310 ast_cc_config_params_destroy(conf.chan.cc_params);
20311
20312 return res;
20313}
20314
20315/*!
20316 * \brief Load the module
20317 *
20318 * Module loading including tests for configuration or dependencies.
20319 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20320 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20321 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20322 * configuration file or other non-critical problem return
20323 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20324 */
20325static int load_module(void)
20326{
20327 int res;
20328#if defined(HAVE_PRI) || defined(HAVE_SS7)
20329 int y;
20330#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20331
20332 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
20334 }
20335
20338 }
20342
20346 }
20347
20348#ifdef HAVE_PRI
20349 memset(pris, 0, sizeof(pris));
20350 for (y = 0; y < NUM_SPANS; y++) {
20351 sig_pri_init_pri(&pris[y].pri);
20352 }
20353 pri_set_error(dahdi_pri_error);
20354 pri_set_message(dahdi_pri_message);
20355 ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec);
20356#ifdef HAVE_PRI_PROG_W_CAUSE
20357 ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
20358#endif
20359#if defined(HAVE_PRI_CCSS)
20360 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks)
20361 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) {
20364 }
20365#endif /* defined(HAVE_PRI_CCSS) */
20366 if (sig_pri_load(
20367#if defined(HAVE_PRI_CCSS)
20368 dahdi_pri_cc_type
20369#else
20370 NULL
20371#endif /* defined(HAVE_PRI_CCSS) */
20372 )) {
20375 }
20376#endif
20377#if defined(HAVE_SS7)
20378 memset(linksets, 0, sizeof(linksets));
20379 for (y = 0; y < NUM_SPANS; y++) {
20380 sig_ss7_init_linkset(&linksets[y].ss7);
20381 }
20382 ss7_set_error(dahdi_ss7_error);
20383 ss7_set_message(dahdi_ss7_message);
20384 ss7_set_hangup(sig_ss7_cb_hangup);
20385 ss7_set_notinservice(sig_ss7_cb_notinservice);
20386 ss7_set_call_null(sig_ss7_cb_call_null);
20387#endif /* defined(HAVE_SS7) */
20388 res = setup_dahdi(0);
20389 /* Make sure we can register our DAHDI channel type */
20390 if (res) {
20393 }
20395 ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
20398 }
20399#ifdef HAVE_PRI
20400 ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
20401#endif
20402#if defined(HAVE_SS7)
20403 ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
20404#endif /* defined(HAVE_SS7) */
20405#ifdef HAVE_OPENR2
20406 ast_cli_register_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
20407 ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
20408#endif
20409
20411
20413 memset(round_robin, 0, sizeof(round_robin));
20414 ast_manager_register_xml("DAHDITransfer", 0, action_transfer);
20416 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook);
20419 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
20420 ast_manager_register_xml("DAHDIShowStatus", 0, action_dahdishowstatus);
20422#if defined(HAVE_PRI)
20423 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
20424 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
20425 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM, action_pri_debug_file_set);
20426 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset);
20427#endif /* defined(HAVE_PRI) */
20428
20430
20431 return res;
20432}
20433
20434static int dahdi_sendtext(struct ast_channel *c, const char *text)
20435{
20436#define END_SILENCE_LEN 400
20437#define HEADER_MS 50
20438#define TRAILER_MS 5
20439#define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20440#define ASCII_BYTES_PER_CHAR 80
20441
20442 unsigned char *buf,*mybuf;
20443 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
20444 struct pollfd fds[1];
20445 int size,res,fd,len,x;
20446 int bytes=0;
20447 int idx;
20448
20449 /*
20450 * Initial carrier (imaginary)
20451 *
20452 * Note: The following float variables are used by the
20453 * PUT_CLID_MARKMS and PUT_CLID() macros.
20454 */
20455 float cr = 1.0;
20456 float ci = 0.0;
20457 float scont = 0.0;
20458
20459 if (!text[0]) {
20460 return(0); /* if nothing to send, don't */
20461 }
20462 idx = dahdi_get_index(c, p, 0);
20463 if (idx < 0) {
20464 ast_log(LOG_WARNING, "Huh? I don't exist?\n");
20465 return -1;
20466 }
20467 if ((!p->tdd) && (!p->mate)) {
20468#if defined(HAVE_PRI)
20469#if defined(HAVE_PRI_DISPLAY_TEXT)
20470 ast_mutex_lock(&p->lock);
20472 sig_pri_sendtext(p->sig_pvt, text);
20473 }
20475#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20476#endif /* defined(HAVE_PRI) */
20477 return(0); /* if not in TDD mode, just return */
20478 }
20479 if (p->mate)
20481 else
20482 buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
20483 if (!buf)
20484 return -1;
20485 mybuf = buf;
20486 if (p->mate) {
20487 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20488 struct ast_format *codec = AST_LAW(p);
20489
20490 for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
20492 }
20493 /* Put actual message */
20494 for (x = 0; text[x]; x++) {
20495 PUT_CLID(text[x]);
20496 }
20497 for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
20499 }
20500 len = bytes;
20501 buf = mybuf;
20502 } else {
20503 len = tdd_generate(p->tdd, buf, text);
20504 if (len < 1) {
20505 ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
20506 ast_free(mybuf);
20507 return -1;
20508 }
20509 }
20510 memset(buf + len, 0x7f, END_SILENCE_LEN);
20512 fd = p->subs[idx].dfd;
20513 while (len) {
20514 if (ast_check_hangup(c)) {
20515 ast_free(mybuf);
20516 return -1;
20517 }
20518 size = len;
20519 if (size > READ_SIZE)
20520 size = READ_SIZE;
20521 fds[0].fd = fd;
20522 fds[0].events = POLLOUT | POLLPRI;
20523 fds[0].revents = 0;
20524 res = poll(fds, 1, -1);
20525 if (!res) {
20526 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
20527 continue;
20528 }
20529 /* if got exception */
20530 if (fds[0].revents & POLLPRI) {
20531 ast_free(mybuf);
20532 return -1;
20533 }
20534 if (!(fds[0].revents & POLLOUT)) {
20535 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
20536 continue;
20537 }
20538 res = write(fd, buf, size);
20539 if (res != size) {
20540 if (res == -1) {
20541 ast_free(mybuf);
20542 return -1;
20543 }
20544 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
20545 break;
20546 }
20547 len -= size;
20548 buf += size;
20549 }
20550 ast_free(mybuf);
20551 return(0);
20552}
20553
20554
20555static int reload(void)
20556{
20557 int res = 0;
20558
20559 res = setup_dahdi(1);
20560 if (res) {
20561 ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
20562 return -1;
20563 }
20564 return 0;
20565}
20566
20567/* This is a workaround so that menuselect displays a proper description
20568 * AST_MODULE_INFO(, , "DAHDI Telephony"
20569 */
20570
20572 .support_level = AST_MODULE_SUPPORT_CORE,
20573 .load = load_module,
20574 .unload = unload_module,
20575 .reload = reload,
20576 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
20577 .requires = "ccss",
20578 .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.
Definition: abstract_jb.c:593
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
Definition: abstract_jb.c:545
ADSI Support (built upon Caller*ID)
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:1768
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
static struct chans chans
#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
enum cc_state state
Definition: ccss.c:399
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
Definition: chan_console.c:174
#define CALLPROGRESS_FAX_INCOMING
Definition: chan_dahdi.c:756
static int dahdi_create_channel_range(int start, int end)
Definition: chan_dahdi.c:11636
static int dahdi_confmute(struct dahdi_pvt *p, int muted)
Definition: chan_dahdi.c:5274
static ast_mutex_t ss_thread_lock
Definition: chan_dahdi.c:838
static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
Definition: chan_dahdi.c:11198
#define CALLWAITING_SUPPRESS_SAMPLES
Definition: chan_dahdi.c:876
static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
Definition: chan_dahdi.c:4830
static void release_doomed_pris(void)
Definition: chan_dahdi.c:1358
static struct dahdi_pvt * round_robin[64]
Definition: chan_dahdi.c:3765
#define HANGUP
Definition: chan_dahdi.c:16855
static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
Definition: chan_dahdi.c:2309
static int restore_gains(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5244
static void publish_channel_alarm_clear(int channel)
Definition: chan_dahdi.c:3840
static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index)
Definition: chan_dahdi.c:4841
static char * dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16107
static void my_set_confirmanswer(void *pvt, int flag)
Definition: chan_dahdi.c:2265
#define CIDCW_EXPIRE_SAMPLES
Definition: chan_dahdi.c:877
static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
Definition: chan_dahdi.c:9335
static int my_callwait(void *pvt)
Definition: chan_dahdi.c:1739
static int restore_conference(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5337
static void publish_span_alarm_clear(int span)
Definition: chan_dahdi.c:3858
static ast_mutex_t iflock
Protect the interface list (of dahdi_pvt's)
Definition: chan_dahdi.c:821
static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Definition: chan_dahdi.c:9458
static void notify_message(char *mailbox, int thereornot)
Send MWI state change.
Definition: chan_dahdi.c:3628
static struct dahdi_pvt * mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
Definition: chan_dahdi.c:12607
static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel)
Definition: chan_dahdi.c:4792
static int unalloc_sub(struct dahdi_pvt *p, int x)
Definition: chan_dahdi.c:4539
static int my_check_confirmanswer(void *pvt)
Definition: chan_dahdi.c:2271
static const char *const events[]
Definition: chan_dahdi.c:4672
static int reset_conf(struct dahdi_pvt *p)
Definition: chan_dahdi.c:4904
static int my_is_dialing(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:3033
static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
Definition: chan_dahdi.c:3004
static struct ast_manager_event_blob * dahdichannel_to_ami(struct stasis_message *msg)
Definition: chan_dahdi.c:1985
static void my_cancel_cidspill(void *pvt)
Definition: chan_dahdi.c:2288
static int numbufs
Definition: chan_dahdi.c:806
static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
Definition: chan_dahdi.c:4860
static int my_set_echocanceller(void *pvt, int enable)
Definition: chan_dahdi.c:2828
static int dahdi_wink(struct dahdi_pvt *p, int index)
Definition: chan_dahdi.c:9905
static char mwimonitornotify[PATH_MAX]
Definition: chan_dahdi.c:796
static char * alarm2str(int alm)
Definition: chan_dahdi.c:4707
static void my_hangup_polarityswitch(void *pvt)
Definition: chan_dahdi.c:2901
static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
Definition: chan_dahdi.c:13557
static int dahdi_ring_phone(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7549
static char * dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16466
#define CALLWAITING_REPEAT_SAMPLES
Definition: chan_dahdi.c:875
static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
Definition: chan_dahdi.c:3799
#define DEFAULT_RINGT
Definition: chan_dahdi.c:879
#define CALLPROGRESS_FAX_OUTGOING
Definition: chan_dahdi.c:755
static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
Definition: chan_dahdi.c:5468
static int my_stop_cid_detect(void *pvt)
Definition: chan_dahdi.c:1488
static int my_get_sub_fd(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:2125
static void my_set_needringing(void *pvt, int value)
Definition: chan_dahdi.c:2864
static char * dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:15838
static struct ast_jb_conf default_jbconf
Definition: chan_dahdi.c:693
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().
Definition: chan_dahdi.c:14264
static struct dahdi_pvt * find_channel_from_str(const char *channel)
Definition: chan_dahdi.c:16896
static int __unload_module(void)
Definition: chan_dahdi.c:18226
static void dahdi_softhangup_all(void)
Definition: chan_dahdi.c:15931
static void dahdi_train_ec(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5028
static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
Definition: chan_dahdi.c:18356
static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
Definition: chan_dahdi.c:9357
static enum analog_event dahdievent_to_analogevent(int event)
Definition: chan_dahdi.c:2681
static int dahdi_digit_begin(struct ast_channel *ast, char digit)
Definition: chan_dahdi.c:4572
static void my_unlock_private(void *pvt)
Definition: chan_dahdi.c:1972
#define HEADER_MS
#define TRANSFER
Definition: chan_dahdi.c:16854
static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_dahdi.c:7509
static void my_set_dialing(void *pvt, int is_dialing)
Definition: chan_dahdi.c:2158
static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
Definition: chan_dahdi.c:1892
static struct dahdi_pvt * fxo_pvt(struct ast_channel *chan)
Return DAHDI pivot if channel is FXO signalled.
Definition: chan_dahdi.c:2917
static int mwisend_rpas
Definition: chan_dahdi.c:798
static void publish_dnd_state(int channel, const char *status)
Definition: chan_dahdi.c:9923
static int my_on_hook(void *pvt)
Definition: chan_dahdi.c:3049
static int attempt_transfer(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7593
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:776
static void my_set_pulsedial(void *pvt, int flag)
Definition: chan_dahdi.c:2303
static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_dahdi.c:4634
static char * dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16556
static int dahdi_wait_event(int fd)
Avoid the silly dahdi_waitevent which ignores a bunch of events.
Definition: chan_dahdi.c:857
static void publish_channel_alarm(int channel, const char *alarm_txt)
Definition: chan_dahdi.c:7793
static int canmatch_featurecode(const char *pickupexten, const char *exten)
Definition: chan_dahdi.c:9971
static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
Definition: chan_dahdi.c:3824
static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
Definition: chan_dahdi.c:5225
struct analog_callback analog_callbacks
Definition: chan_dahdi.c:3691
static void dahdi_destroy_channel_range(int start, int end)
Definition: chan_dahdi.c:11554
static char * dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16188
static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
Definition: chan_dahdi.c:2646
static void my_set_alarm(void *pvt, int in_alarm)
Definition: chan_dahdi.c:2151
static int num_restart_pending
Definition: chan_dahdi.c:841
static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
Definition: chan_dahdi.c:1835
static int my_get_event(void *pvt)
Definition: chan_dahdi.c:2785
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13590
static int dahdi_devicestate(const char *data)
Definition: chan_dahdi.c:14202
static int user_has_defined_cadences
Definition: chan_dahdi.c:761
static int dahdi_callwait(struct ast_channel *ast)
Definition: chan_dahdi.c:5434
static void wakeup_sub(struct dahdi_pvt *p, int a)
Definition: chan_dahdi.c:3815
static void my_set_callwaiting(void *pvt, int callwaiting_enable)
Definition: chan_dahdi.c:2281
static int distinctiveringaftercid
Definition: chan_dahdi.c:804
static int my_is_off_hook(void *pvt)
Definition: chan_dahdi.c:2799
char * name
Definition: chan_dahdi.c:4696
#define END_SILENCE_LEN
static int mwi_send_init(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:11369
static int dahdi_open(char *fn)
Definition: chan_dahdi.c:4421
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.
Definition: chan_dahdi.c:2016
static int my_check_waitingfordt(void *pvt)
Definition: chan_dahdi.c:2254
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
Definition: chan_dahdi.c:20065
static void publish_span_alarm(int span, const char *alarm_txt)
Definition: chan_dahdi.c:7779
static void my_set_outgoing(void *pvt, int is_outgoing)
Definition: chan_dahdi.c:2165
static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
Definition: chan_dahdi.c:16857
static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
Definition: chan_dahdi.c:2092
static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:5902
static int dahdi_hangup(struct ast_channel *ast)
Definition: chan_dahdi.c:6325
static void * analog_ss_thread(void *data)
Definition: chan_dahdi.c:9998
static int dahdi_sendtext(struct ast_channel *c, const char *text)
Definition: chan_dahdi.c:20434
static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
Definition: chan_dahdi.c:2043
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)
Definition: chan_dahdi.c:2454
#define PROC_DAHDI_OPT_NOCHAN
Definition: chan_dahdi.c:18550
static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
Definition: chan_dahdi.c:18554
static int analogsub_to_dahdisub(enum analog_sub analogsub)
Definition: chan_dahdi.c:1328
static void my_get_and_handle_alarms(void *pvt)
Definition: chan_dahdi.c:2102
static void my_lock_private(void *pvt)
Definition: chan_dahdi.c:1966
static int dahdi_answer(struct ast_channel *ast)
Definition: chan_dahdi.c:6784
static const char tdesc[]
Definition: chan_dahdi.c:723
static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
Definition: chan_dahdi.c:5093
static int dahdi_restart(void)
Definition: chan_dahdi.c:15959
static int action_transfer(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16946
static int bump_gains(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5230
static void * do_monitor(void *data)
Definition: chan_dahdi.c:11968
static int save_conference(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5311
static char * dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16713
static void handle_clear_alarms(struct dahdi_pvt *p)
Definition: chan_dahdi.c:3871
static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
Definition: chan_dahdi.c:6879
static char * dahdi_sig2str(int sig)
Definition: chan_dahdi.c:4726
static int dahdi_set_hook(int fd, int hs)
Definition: chan_dahdi.c:5257
static int my_stop_callwait(void *pvt)
Definition: chan_dahdi.c:1725
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)
Definition: chan_dahdi.c:9630
static int check_for_conference(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7626
static struct dahdi_ring_cadence AS_RP_cadence
Definition: chan_dahdi.c:784
static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
Definition: chan_dahdi.c:1601
#define NUM_SPANS
Definition: chan_dahdi.c:749
void dahdi_ec_enable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:4973
#define AST_LAW(p)
Definition: chan_dahdi.c:717
static int dahdi_setlinear(int dfd, int linear)
Definition: chan_dahdi.c:4496
static int restart_monitor(void)
Definition: chan_dahdi.c:12282
static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
Definition: chan_dahdi.c:3643
static int my_confmute(void *pvt, int mute)
Definition: chan_dahdi.c:2297
#define READ_SIZE
Definition: chan_dahdi.c:869
static void * mwi_thread(void *data)
Definition: chan_dahdi.c:11212
#define CALLPROGRESS_FAX
Definition: chan_dahdi.c:757
static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
Definition: chan_dahdi.c:1773
static int sigtype_to_signalling(int sigtype)
Definition: chan_dahdi.c:12588
static void my_decrease_ss_count(void)
Definition: chan_dahdi.c:2330
static char * handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16391
static int has_voicemail(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5368
static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:5675
void dahdi_conf_update(struct dahdi_pvt *p)
Definition: chan_dahdi.c:4918
static int alloc_sub(struct dahdi_pvt *p, int x)
Definition: chan_dahdi.c:4502
static void my_start_polarityswitch(void *pvt)
Definition: chan_dahdi.c:2881
static int digit_to_dtmfindex(char digit)
Definition: chan_dahdi.c:4556
static int setup_dahdi(int reload)
Definition: chan_dahdi.c:20296
STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type,.to_ami=dahdichannel_to_ami,)
static char * dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16770
static int action_dahdidndon(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16908
static int report_alarms
Definition: chan_dahdi.c:813
#define GET_CHANNEL(p)
Definition: chan_dahdi.c:1255
static int mwilevel
Definition: chan_dahdi.c:808
static struct dahdi_pvt * iflist
Definition: chan_dahdi.c:997
#define NEED_MFDETECT(p)
Signaling types that need to use MF detection should be placed in this macro.
Definition: chan_dahdi.c:721
static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: chan_dahdi.c:6928
static int set_actual_txgain(int fd, float gain, float drc, int law)
Definition: chan_dahdi.c:5191
static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
Definition: chan_dahdi.c:7316
static int my_wait_event(void *pvt)
Definition: chan_dahdi.c:2778
static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
Definition: chan_dahdi.c:9886
static struct ast_channel * my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
Definition: chan_dahdi.c:2498
static int analog_tone_to_dahditone(enum analog_tone tone)
Definition: chan_dahdi.c:1308
static struct ast_str * create_channel_name(struct dahdi_pvt *i)
Definition: chan_dahdi.c:9585
static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
Definition: chan_dahdi.c:1504
#define TRAILER_MS
static int set_actual_rxgain(int fd, float gain, float drc, int law)
Definition: chan_dahdi.c:5208
static int my_start(void *pvt)
Definition: chan_dahdi.c:2996
static ast_mutex_t restart_lock
Definition: chan_dahdi.c:839
static struct ast_frame * dahdi_handle_event(struct ast_channel *ast)
Definition: chan_dahdi.c:7834
static char defaultcic[64]
Definition: chan_dahdi.c:792
int alarm
Definition: chan_dahdi.c:4695
static const char config[]
Definition: chan_dahdi.c:744
static int action_dahdishowchannels(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:17024
void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:6862
static struct dahdi_pvt * find_next_iface_in_span(struct dahdi_pvt *cur)
Definition: chan_dahdi.c:5891
static ast_cond_t ss_thread_complete
Definition: chan_dahdi.c:837
static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
Definition: chan_dahdi.c:18417
static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:5627
static struct ast_frame * dahdi_exception(struct ast_channel *ast)
Definition: chan_dahdi.c:8858
static void my_answer_polarityswitch(void *pvt)
Definition: chan_dahdi.c:2890
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)
Definition: chan_dahdi.c:14021
#define SMDI_MD_WAIT_TIMEOUT
Definition: chan_dahdi.c:678
static int my_have_progressdetect(void *pvt)
Definition: chan_dahdi.c:3665
static char * dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16635
static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Definition: chan_dahdi.c:7147
#define CANPROGRESSDETECT(p)
Definition: chan_dahdi.c:790
static char * dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:15882
static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
Definition: chan_dahdi.c:5143
static int my_train_echocanceller(void *pvt)
Definition: chan_dahdi.c:3024
static const char * event2str(int event)
Definition: chan_dahdi.c:4717
#define CALLPROGRESS_PROGRESS
Definition: chan_dahdi.c:754
static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
Definition: chan_dahdi.c:4474
static void my_set_polarity(void *pvt, int value)
Definition: chan_dahdi.c:2870
void dahdi_ec_disable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5045
static struct ast_frame * __dahdi_exception(struct ast_channel *ast)
Definition: chan_dahdi.c:8736
static void handle_alarms(struct dahdi_pvt *p, int alms)
Definition: chan_dahdi.c:7812
static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
Definition: chan_dahdi.c:7679
static struct dahdi_chan_conf dahdi_chan_conf_default(void)
Definition: chan_dahdi.c:1065
static struct dahdi_pvt * duplicate_pseudo(struct dahdi_pvt *src)
Definition: chan_dahdi.c:13796
static void swap_subs(struct dahdi_pvt *p, int a, int b)
Definition: chan_dahdi.c:4393
#define ISTRUNK(p)
Definition: chan_dahdi.c:786
static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
Definition: chan_dahdi.c:2080
static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
Definition: chan_dahdi.c:9952
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)
Definition: chan_dahdi.c:9639
static int drc_sample(int sample, float drc)
Definition: chan_dahdi.c:5073
static int dahdi_get_event(int fd)
Avoid the silly dahdi_getevent which ignores a bunch of events.
Definition: chan_dahdi.c:848
static int ringt_base
Configured ring timeout base.
Definition: chan_dahdi.c:886
void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
Definition: chan_dahdi.c:7429
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:832
#define ASCII_BYTES_PER_CHAR
static void my_all_subchannels_hungup(void *pvt)
Definition: chan_dahdi.c:2338
static int my_ring(void *pvt)
Definition: chan_dahdi.c:2842
static int my_start_cid_detect(void *pvt, int cid_signalling)
Definition: chan_dahdi.c:1471
static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
Definition: chan_dahdi.c:7287
static struct dahdi_pvt * ifend
Definition: chan_dahdi.c:998
static char * dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16523
static int my_complete_conference_update(void *pvt, int needconference)
Definition: chan_dahdi.c:2398
static struct @114 alarms[]
#define DEFAULT_DIALTONE_DETECT_TIMEOUT
Definition: chan_dahdi.c:880
static int mwi_send_process_buffer(struct dahdi_pvt *pvt, int num_read)
Definition: chan_dahdi.c:11422
#define HEADER_LEN
static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
Definition: chan_dahdi.c:2132
static void my_increase_ss_count(void)
Definition: chan_dahdi.c:2323
#define REPORT_CHANNEL_ALARMS
Definition: chan_dahdi.c:811
static int has_pseudo
Definition: chan_dahdi.c:763
static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
Definition: chan_dahdi.c:2671
static int my_wink(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:1876
static struct ast_channel_tech dahdi_tech
Definition: chan_dahdi.c:1232
static struct ast_jb_conf global_jbconf
Definition: chan_dahdi.c:701
static int my_conf_add(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:2388
static int my_dsp_reset_and_flush_digits(void *pvt)
Definition: chan_dahdi.c:1826
void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:6848
#define PROC_DAHDI_OPT_NOWARN
Definition: chan_dahdi.c:18552
#define MIN_MS_SINCE_FLASH
Definition: chan_dahdi.c:878
static int my_has_voicemail(void *pvt)
Definition: chan_dahdi.c:2664
static char progzone[10]
Definition: chan_dahdi.c:801
static int load_module(void)
Load the module.
Definition: chan_dahdi.c:20325
#define sig2str
Definition: chan_dahdi.c:4790
static struct ast_frame * dahdi_read(struct ast_channel *ast)
Definition: chan_dahdi.c:8873
#define FORMAT
static const char * my_get_orig_dialstring(void *pvt)
Definition: chan_dahdi.c:2316
static int action_dahdirestart(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16097
static struct ast_custom_function polarity_function
Definition: chan_dahdi.c:2990
static int get_alarms(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7652
static struct dahdi_pvt * determine_starting_point(const char *data, struct dahdi_starting_point *param)
Definition: chan_dahdi.c:13860
#define gen_pvt_field_callback(type, field)
Definition: chan_dahdi.c:3678
static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
Definition: chan_dahdi.c:2949
static int send_cwcidspill(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5352
static int my_conf_del(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:2378
#define FORMAT2
static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX]
Definition: chan_dahdi.c:765
static int action_dahdidndoff(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16927
static int unload_module(void)
Definition: chan_dahdi.c:18340
static int reload(void)
Definition: chan_dahdi.c:20555
static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
Definition: chan_dahdi.c:18589
static struct ast_cli_entry dahdi_cli[]
Definition: chan_dahdi.c:16839
#define POLARITY_IDLE
Definition: chan_dahdi.c:988
#define DEFAULT_CIDRINGS
Typically, how many rings before we should send Caller*ID.
Definition: chan_dahdi.c:715
static int num_cadence
Definition: chan_dahdi.c:760
static enum analog_sigtype dahdisig_to_analogsig(int sig)
Definition: chan_dahdi.c:1257
static void dahdi_close(int fd)
Definition: chan_dahdi.c:4468
static char defaultozz[64]
Definition: chan_dahdi.c:793
void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
Definition: chan_dahdi.c:7485
static int dtmfcid_level
Definition: chan_dahdi.c:809
#define CHAN_PSEUDO
Definition: chan_dahdi.c:752
static int my_off_hook(void *pvt)
Definition: chan_dahdi.c:2858
const char *const subnames[]
Definition: chan_dahdi.c:991
static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
Definition: chan_dahdi.c:2655
static int usedistinctiveringdetection
Definition: chan_dahdi.c:803
static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: chan_dahdi.c:2963
static char * dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16074
static struct dahdi_pvt * find_channel(int channel)
Definition: chan_dahdi.c:16873
static void * my_get_sigpvt_bridged_channel(struct ast_channel *chan)
Definition: chan_dahdi.c:2111
static int send_callerid(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5398
static int set_hwgain(int fd, float gain, int tx_direction)
Definition: chan_dahdi.c:5063
static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
Definition: chan_dahdi.c:2214
static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
Definition: chan_dahdi.c:16427
static int my_check_for_conference(void *pvt)
Definition: chan_dahdi.c:2448
static int mwi_send_process_event(struct dahdi_pvt *pvt, int event)
Definition: chan_dahdi.c:11510
static int my_flash(void *pvt)
Definition: chan_dahdi.c:2849
#define POLARITY_REV
Definition: chan_dahdi.c:989
static int ss_thread_count
Definition: chan_dahdi.c:840
static const char *const lbostr[]
Definition: chan_dahdi.c:680
int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
Definition: chan_dahdi.c:3767
#define REPORT_SPAN_ALARMS
Definition: chan_dahdi.c:812
static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
Definition: chan_dahdi.c:20043
static void my_deadlock_avoidance_private(void *pvt)
Definition: chan_dahdi.c:1978
static struct dahdi_pvt * handle_init_event(struct dahdi_pvt *i, int event)
Definition: chan_dahdi.c:11704
static void destroy_channel(struct dahdi_pvt *cur, int now)
Definition: chan_dahdi.c:5982
static void my_set_ringtimeout(void *pvt, int ringt)
Definition: chan_dahdi.c:2208
static void monitor_pfds_clean(void *arg)
Definition: chan_dahdi.c:11963
static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16992
static int ifcount
Definition: chan_dahdi.c:824
#define NUM_CADENCE_MAX
Definition: chan_dahdi.c:759
static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
Definition: chan_dahdi.c:1425
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:836
static int action_transferhangup(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16969
#define CANBUSYDETECT(p)
Definition: chan_dahdi.c:789
static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
Definition: chan_dahdi.c:6303
static void destroy_all_channels(void)
Definition: chan_dahdi.c:6000
static int action_dahdishowstatus(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:17112
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[]
Definition: chan_ooh323.c:109
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:3145
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:2877
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:1559
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:1612
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2511
#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:10578
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1789
#define CHECK_BLOCKING(c)
Set the blocking indication on the channel.
Definition: channel.h:2921
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition: channel.h:2972
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:7720
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3132
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:10465
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:2997
struct ast_party_connected_line * ast_channel_connected(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
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:1975
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4223
#define ast_channel_trylock(chan)
Definition: channel.h:2974
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:1277
@ 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:1967
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition: channel.c:1606
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:7316
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:1205
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:1983
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:7657
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)
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
@ AST_SOFTHANGUP_DEV
Definition: channel.h:1141
@ AST_SOFTHANGUP_APPUNLOAD
Definition: channel.h:1163
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:2469
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2441
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:4313
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1255
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition: channel.c:1230
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:3008
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1659
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition: channel.c:2816
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:10596
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:2396
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2428
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition: channel.c:4327
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ast_namedgroups * ast_unref_namedgroups(struct ast_namedgroups *groups)
Definition: channel.c:7714
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:7404
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
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:3019
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:7600
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:1542
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
#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
Definition: channelstate.h:35
@ AST_STATE_RING
Definition: channelstate.h:40
@ AST_STATE_DIALING_OFFHOOK
Definition: channelstate.h:44
@ AST_STATE_RINGING
Definition: channelstate.h:41
@ AST_STATE_PRERING
Definition: channelstate.h:45
@ AST_STATE_DOWN
Definition: channelstate.h:36
@ AST_STATE_OFFHOOK
Definition: channelstate.h:38
@ AST_STATE_BUSY
Definition: channelstate.h:43
@ AST_STATE_DIALING
Definition: channelstate.h:39
@ AST_STATE_UP
Definition: channelstate.h:42
@ AST_STATE_RESERVED
Definition: channelstate.h:37
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7368
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
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#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)
Definition: codec_dahdi.c:277
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.
Definition: devicestate.c:513
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.
Definition: devicestate.c:474
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:1785
int ast_dsp_get_tcount(struct ast_dsp *dsp)
Get tcount (Threshold counter)
Definition: dsp.c:1918
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:1812
#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:1806
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:1501
#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:1859
#define DSP_DIGITMODE_MUTECONF
Definition: dsp.h:35
int ast_dsp_get_tstate(struct ast_dsp *dsp)
Get tstate (Tone State)
Definition: dsp.c:1913
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:1908
#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:1795
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1770
#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:1760
#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:1894
char * bs
Definition: eagi_proxy.c:73
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2204
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.
Definition: format_cache.c:86
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
@ 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 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:7695
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
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
Definition: main/config.c:753
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1260
@ CONFIG_FLAG_FILEUNCHANGED
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_NULL
@ AST_FRAME_IMAGE
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_VOICE
@ AST_FRAME_CONTROL
@ AST_FRAME_TEXT
@ AST_CONTROL_RING
@ AST_CONTROL_SRCUPDATE
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_RADIO_UNKEY
@ AST_CONTROL_BUSY
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HANGUP
@ AST_CONTROL_RADIO_KEY
@ AST_CONTROL_HOLD
@ 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,...)
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.
Definition: linkedlists.h:291
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
Definition: linkedlists.h:234
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_MOVE_CURRENT(newhead, field)
Move the current list entry to another list.
Definition: linkedlists.h:582
#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.
Definition: linkedlists.h:856
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
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:10141
#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:7748
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7758
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
struct stasis_forward * sub
Definition: res_corosync.c:240
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
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)
Definition: sig_analog.c:1293
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)
Definition: sig_analog.c:3956
int analog_dnd(struct analog_pvt *p, int flag)
Definition: sig_analog.c:4449
int analog_callwaiting_deluxe(struct analog_pvt *p, int option)
Definition: sig_analog.c:1635
int analog_config_complete(struct analog_pvt *p)
Definition: sig_analog.c:4393
void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
Definition: sig_analog.c:1764
int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest, int timeout)
Definition: sig_analog.c:1006
void analog_delete(struct analog_pvt *doomed)
Delete the analog private structure.
Definition: sig_analog.c:4388
struct analog_pvt * analog_new(enum analog_sigtype signallingtype, void *private_data)
Definition: sig_analog.c:4360
int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
Definition: sig_analog.c:4411
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)
Definition: sig_analog.c:4076
int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
Definition: sig_analog.c:1506
int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
Definition: sig_analog.c:3015
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.
struct ast_smdi_interface * 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_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 SMDI_MAX_FILENAME_LEN
Definition: smdi.h:42
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
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:836
#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.
Definition: stasis_cache.c:686
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
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
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 dahditrcallerid
Definition: sig_analog.h:296
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
int onhooktime
Definition: sig_analog.h:281
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
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 ringt_base
Definition: sig_analog.h:386
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
int stripmsd
Definition: sig_analog.h:328
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
char x
Definition: extconf.c:81
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
char chan_name[AST_CHANNEL_NAME]
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:217
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
unsigned int flags
union ast_frame::@231 data
const char * src
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::@213 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...
Definition: chan_dahdi.c:1027
char smdi_port[SMDI_MAX_FILENAME_LEN]
The serial port to listen for SMDI data on.
Definition: chan_dahdi.c:1049
int ignore_failed_channels
Definition: chan_dahdi.c:1043
struct dahdi_params timing
Definition: chan_dahdi.c:1040
int wanted_channels_end
Don't create channels above this number (infinity by default)
Definition: chan_dahdi.c:1061
struct dahdi_pvt chan
Definition: chan_dahdi.c:1028
int wanted_channels_start
Don't create channels below this number.
Definition: chan_dahdi.c:1055
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
int bufsize
Definition: chan_dahdi.h:138
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
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 oprmode
Definition: chan_dahdi.h:151
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
int tonezone
Definition: chan_dahdi.h:167
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
struct dahdi_pvt::@115 echocancel
Echo cancel parameters.
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
int confno
Definition: chan_dahdi.h:563
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
int amaflags
Definition: chan_dahdi.h:707
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
int buf_no
Definition: chan_dahdi.h:139
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
int channel
Definition: chan_dahdi.h:591
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
ast_group_t groupmatch
Definition: chan_dahdi.c:13844
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
Definition: astman.c:222
Definition: logger.c:169
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:323
struct dahdi_pvt * pvt
Definition: chan_dahdi.c:11193
unsigned char buf[READ_SIZE]
Definition: chan_dahdi.c:11194
mwisend_states mwisend_current
Definition: chan_dahdi.h:112
struct timeval pause
Definition: chan_dahdi.h:111
Number structure.
Definition: app_followme.c:157
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
int channel
Definition: sig_pri.h:290
unsigned int no_b_channel
TRUE if this interface has no B channel. (call hold and call waiting)
Definition: sig_pri.h:343
int stripmsd
Definition: sig_pri.h:289
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
int nodetype
Definition: sig_pri.h:555
int numchans
Definition: sig_pri.h:613
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 minidle
Definition: sig_pri.h:554
int trunkgroup
Definition: sig_pri.h:558
pthread_t master
Definition: sig_pri.h:615
int dialplan
Definition: sig_pri.h:504
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 channel
Definition: sig_ss7.h:200
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
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
Definition: ast_expr2.c:325
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
const char * args
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:978
#define ast_assert(a)
Definition: utils.h:776
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:621
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:629
#define ast_clear_flag(p, flag)
Definition: utils.h:77
long int ast_random(void)
Definition: utils.c:2348
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:625
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:703