Asterisk - The Open Source Telephony Project GIT-master-8924258
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
chan_dahdi.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2008, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief DAHDI for Pseudo TDM
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * Connects to the DAHDI telephony library as well as
26 * libpri. Libpri is optional and needed only if you are
27 * going to use ISDN connections.
28 *
29 * You need to install libraries before you attempt to compile
30 * and install the DAHDI channel.
31 *
32 * \ingroup channel_drivers
33 *
34 * \todo Deprecate the "musiconhold" configuration option post 1.4
35 */
36
37/*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
38 * \addtogroup configuration_file
39 */
40
41/*! \page chan_dahdi.conf chan_dahdi.conf
42 * \verbinclude chan_dahdi.conf.sample
43 */
44
45/*** MODULEINFO
46 <depend>dahdi</depend>
47 <depend>tonezone</depend>
48 <use type="module">res_smdi</use>
49 <use type="external">pri</use>
50 <use type="external">ss7</use>
51 <use type="external">openr2</use>
52 <support_level>core</support_level>
53 ***/
54
55#include "asterisk.h"
56
57#if defined(__NetBSD__) || defined(__FreeBSD__)
58#include <pthread.h>
59#else
60#include <sys/sysmacros.h>
61#endif
62#include <signal.h>
63#include <sys/stat.h>
64#include <math.h>
65
66#include "sig_analog.h"
67/* Analog signaling is currently still present in chan_dahdi for use with
68 * radio. Sig_analog does not currently handle any radio operations. If
69 * radio only uses analog signaling, then the radio handling logic could
70 * be placed in sig_analog and the duplicated code could be removed.
71 */
72
73#if defined(HAVE_PRI)
74#include "sig_pri.h"
75#ifndef PRI_RESTART
76#error "Upgrade your libpri"
77#endif
78#endif /* defined(HAVE_PRI) */
79
80#if defined(HAVE_SS7)
81#include "sig_ss7.h"
82#if !defined(LIBSS7_ABI_COMPATIBILITY)
83#error "Upgrade your libss7"
84#elif LIBSS7_ABI_COMPATIBILITY != 2
85#error "Your installed libss7 is not compatible"
86#endif
87#endif /* defined(HAVE_SS7) */
88
89#if defined(HAVE_OPENR2)
90/* put this here until sig_mfcr2 comes along */
91#define SIG_MFCR2_MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
92#endif /* defined(HAVE_OPENR2) */
93
94#include "asterisk/lock.h"
95#include "asterisk/channel.h"
96#include "asterisk/config.h"
97#include "asterisk/module.h"
98#include "asterisk/pbx.h"
99#include "asterisk/file.h"
100#include "asterisk/ulaw.h"
101#include "asterisk/alaw.h"
102#include "asterisk/callerid.h"
103#include "asterisk/adsi.h"
104#include "asterisk/cli.h"
105#include "asterisk/pickup.h"
106#include "asterisk/features.h"
107#include "asterisk/musiconhold.h"
108#include "asterisk/say.h"
109#include "asterisk/tdd.h"
110#include "asterisk/mwi.h"
111#include "asterisk/dsp.h"
112#include "asterisk/astdb.h"
113#include "asterisk/manager.h"
114#include "asterisk/causes.h"
115#include "asterisk/term.h"
116#include "asterisk/utils.h"
117#include "asterisk/transcap.h"
119#include "asterisk/abstract_jb.h"
120#include "asterisk/smdi.h"
121#include "asterisk/devicestate.h"
122#include "asterisk/paths.h"
123#include "asterisk/ccss.h"
125#include "asterisk/bridge.h"
127#include "asterisk/parking.h"
129#include "chan_dahdi.h"
131
132/*** DOCUMENTATION
133 <application name="DAHDISendKeypadFacility" language="en_US">
134 <since>
135 <version>1.4.22</version>
136 </since>
137 <synopsis>
138 Send digits out of band over a PRI.
139 </synopsis>
140 <syntax>
141 <parameter name="digits" required="true" />
142 </syntax>
143 <description>
144 <para>This application will send the given string of digits in a Keypad
145 Facility IE over the current channel.</para>
146 </description>
147 </application>
148 <application name="DAHDISendCallreroutingFacility" language="en_US">
149 <since>
150 <version>1.6.2.0</version>
151 </since>
152 <synopsis>
153 Send an ISDN call rerouting/deflection facility message.
154 </synopsis>
155 <syntax argsep=",">
156 <parameter name="destination" required="true">
157 <para>Destination number.</para>
158 </parameter>
159 <parameter name="original">
160 <para>Original called number.</para>
161 </parameter>
162 <parameter name="reason">
163 <para>Diversion reason, if not specified defaults to <literal>unknown</literal></para>
164 </parameter>
165 </syntax>
166 <description>
167 <para>This application will send an ISDN switch specific call
168 rerouting/deflection facility message over the current channel.
169 Supported switches depend upon the version of libpri in use.</para>
170 </description>
171 </application>
172 <application name="DAHDIAcceptR2Call" language="en_US">
173 <since>
174 <version>1.6.1.0</version>
175 </since>
176 <synopsis>
177 Accept an R2 call if its not already accepted (you still need to answer it)
178 </synopsis>
179 <syntax>
180 <parameter name="charge" required="true">
181 <para>Yes or No.</para>
182 <para>Whether you want to accept the call with charge or without charge.</para>
183 </parameter>
184 </syntax>
185 <description>
186 <para>This application will Accept the R2 call either with charge or no charge.</para>
187 </description>
188 </application>
189 <function name="POLARITY" language="en_US">
190 <since>
191 <version>16.28.0</version>
192 <version>18.14.0</version>
193 <version>19.6.0</version>
194 </since>
195 <synopsis>
196 Set or get the polarity of a DAHDI channel.
197 </synopsis>
198 <syntax />
199 <description>
200 <para>The POLARITY function can be used to set the polarity of a DAHDI channel.</para>
201 <para>Applies only to FXS channels (using FXO signalling) with supporting hardware.</para>
202 <para>The polarity can be set to the following numeric or named values:</para>
203 <enumlist>
204 <enum name="0" />
205 <enum name="idle" />
206 <enum name="1" />
207 <enum name="reverse" />
208 </enumlist>
209 <para>However, when read, the function will always return 0 or 1.</para>
210 <example title="Set idle polarity">
211 same => n,Set(POLARITY()=0)
212 </example>
213 <example title="Set reverse polarity">
214 same => n,NoOp(Current Polarity: ${POLARITY()})
215 same => n,Set(POLARITY()=reverse)
216 same => n,NoOp(New Polarity: ${POLARITY()})
217 </example>
218 <example title="Reverse the polarity from whatever it is currently">
219 same => n,Set(POLARITY()=${IF($[ "${POLARITY()}" = "1" ]?0:1)})
220 </example>
221 </description>
222 </function>
223 <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 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 <enumlist>
286 <enum name="both" />
287 <enum name="pulse" />
288 <enum name="dtmf" />
289 <enum name="tone" />
290 <enum name="none" />
291 </enumlist>
292 </enum>
293 <enum name="waitfordialtone">
294 <para>W/O Duration in ms for which to wait for dial tone on the current call.</para>
295 <para>This setting is will temporarily override the <literal>waitfordialtone</literal>
296 setting in <literal>chan_dahdi.conf</literal> (typically if that setting is disabled).
297 You must call this in a pre-dial handler when making a call on an analog trunk
298 (e.g. FXS-signalled interface).</para>
299 <para>This allows, for example, being able to barge in on an in-use trunk,
300 if dialed specifically, but allows skipping the trunk when routing calls
301 if dial tone is not present on a channel.</para>
302 <para>This setting will only apply to the current (next) call made on the
303 DAHDI channel, and will not persist for future calls.</para>
304 <para>Please keep in mind that due to the way that chan_dahdi implements dial tone detection,
305 DTMF digits on an in-use channel will temporarily relay to any other channels attempting to use the channel for a call.
306 However, voice transmission will not leak.</para>
307 </enum>
308 </enumlist>
309 </info>
310 <info name="Dial_Resource" language="en_US" tech="DAHDI">
311 <para>DAHDI allows several modifiers to be specified as part of the resource.</para>
312 <para>The general syntax is :</para>
313 <para><literal>Dial(DAHDI/pseudo[/extension])</literal></para>
314 <para><literal>Dial(DAHDI/&lt;channel#&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
315 <para><literal>Dial(DAHDI/(g|G|r|R)&lt;group#(0-63)&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
316 <para>The following modifiers may be used before the channel number:</para>
317 <enumlist>
318 <enum name="g">
319 <para>Search forward, dialing on first available channel in group (lowest to highest).</para>
320 </enum>
321 <enum name="G">
322 <para>Search backward, dialing on first available channel in group (highest to lowest).</para>
323 </enum>
324 <enum name="r">
325 <para>Round robin search forward, picking up from where last left off (lowest to highest).</para>
326 </enum>
327 <enum name="R">
328 <para>Round robin search backward, picking up from where last left off (highest to lowest).</para>
329 </enum>
330 </enumlist>
331 <para>The following modifiers may be used after the channel number:</para>
332 <enumlist>
333 <enum name="c">
334 <para>Wait for DTMF digit <literal>#</literal> before providing answer supervision.</para>
335 <para>This can be useful on outbound calls via FXO ports, as otherwise
336 they would indicate answer immediately.</para>
337 </enum>
338 <enum name="d">
339 <para>Force bearer capability for ISDN/SS7 call to digital.</para>
340 </enum>
341 <enum name="i">
342 <para>ISDN span channel restriction.</para>
343 <para>Used by CC to ensure that the CC recall goes out the same span.
344 Also to make ISDN channel names dialable when the sequence number
345 is stripped off. (Used by DTMF attended transfer feature.)</para>
346 </enum>
347 <enum name="r">
348 <para>Specifies the distinctive ring cadence number to use immediately after
349 specifying this option. There are 4 default built-in cadences, and up to 24
350 total cadences may be configured.</para>
351 </enum>
352 </enumlist>
353 <example title="Dial 555-1212 on first available channel in group 1, searching from highest to lowest">
354 same => n,Dial(DAHDI/g1/5551212)
355 </example>
356 <example title="Ringing FXS channel 4 with ring cadence 2">
357 same => n,Dial(DAHDI/4r2)
358 </example>
359 <example title="Dial 555-1212 on channel 3 and require answer confirmation">
360 same => n,Dial(DAHDI/3c/5551212)
361 </example>
362 </info>
363 <manager name="DAHDITransfer" language="en_US">
364 <since>
365 <version>1.4.22</version>
366 </since>
367 <synopsis>
368 Transfer DAHDI Channel.
369 </synopsis>
370 <syntax>
371 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
372 <parameter name="DAHDIChannel" required="true">
373 <para>DAHDI channel number to transfer.</para>
374 </parameter>
375 </syntax>
376 <description>
377 <para>Simulate a flash hook event by the user connected to the channel.</para>
378 <note><para>Valid only for analog channels.</para></note>
379 </description>
380 </manager>
381 <manager name="DAHDIHangup" language="en_US">
382 <since>
383 <version>1.4.22</version>
384 </since>
385 <synopsis>
386 Hangup DAHDI Channel.
387 </synopsis>
388 <syntax>
389 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
390 <parameter name="DAHDIChannel" required="true">
391 <para>DAHDI channel number to hangup.</para>
392 </parameter>
393 </syntax>
394 <description>
395 <para>Simulate an on-hook event by the user connected to the channel.</para>
396 <note><para>Valid only for analog channels.</para></note>
397 </description>
398 </manager>
399 <manager name="DAHDIDialOffhook" language="en_US">
400 <since>
401 <version>1.4.22</version>
402 </since>
403 <synopsis>
404 Dial over DAHDI channel while offhook.
405 </synopsis>
406 <syntax>
407 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
408 <parameter name="DAHDIChannel" required="true">
409 <para>DAHDI channel number to dial digits.</para>
410 </parameter>
411 <parameter name="Number" required="true">
412 <para>Digits to dial.</para>
413 </parameter>
414 </syntax>
415 <description>
416 <para>Generate DTMF control frames to the bridged peer.</para>
417 </description>
418 </manager>
419 <manager name="DAHDIDNDon" language="en_US">
420 <since>
421 <version>1.4.22</version>
422 </since>
423 <synopsis>
424 Toggle DAHDI channel Do Not Disturb status ON.
425 </synopsis>
426 <syntax>
427 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
428 <parameter name="DAHDIChannel" required="true">
429 <para>DAHDI channel number to set DND on.</para>
430 </parameter>
431 </syntax>
432 <description>
433 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> on".</para>
434 <note><para>Feature only supported by analog channels.</para></note>
435 </description>
436 </manager>
437 <manager name="DAHDIDNDoff" language="en_US">
438 <since>
439 <version>1.4.22</version>
440 </since>
441 <synopsis>
442 Toggle DAHDI channel Do Not Disturb status OFF.
443 </synopsis>
444 <syntax>
445 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
446 <parameter name="DAHDIChannel" required="true">
447 <para>DAHDI channel number to set DND off.</para>
448 </parameter>
449 </syntax>
450 <description>
451 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> off".</para>
452 <note><para>Feature only supported by analog channels.</para></note>
453 </description>
454 </manager>
455 <manager name="DAHDIShowChannels" language="en_US">
456 <since>
457 <version>1.4.22</version>
458 </since>
459 <synopsis>
460 Show status of DAHDI channels.
461 </synopsis>
462 <syntax>
463 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
464 <parameter name="DAHDIChannel">
465 <para>Specify the specific channel number to show. Show all channels if zero or not present.</para>
466 </parameter>
467 </syntax>
468 <description>
469 <para>Similar to the CLI command "dahdi show channels".</para>
470 </description>
471 </manager>
472 <manager name="DAHDIShowStatus" language="en_US">
473 <since>
474 <version>21.3.0</version>
475 <version>20.8.0</version>
476 <version>18.23.0</version>
477 </since>
478 <synopsis>
479 Show status of DAHDI spans.
480 </synopsis>
481 <syntax/>
482 <description>
483 <para>Similar to the CLI command "dahdi show status".</para>
484 </description>
485 </manager>
486 <manager name="DAHDIRestart" language="en_US">
487 <since>
488 <version>1.4.22</version>
489 </since>
490 <synopsis>
491 Fully Restart DAHDI channels (terminates calls).
492 </synopsis>
493 <syntax>
494 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
495 </syntax>
496 <description>
497 <para>Equivalent to the CLI command "dahdi restart".</para>
498 </description>
499 </manager>
500 <manager name="PRIShowSpans" language="en_US">
501 <since>
502 <version>10.0.0</version>
503 </since>
504 <synopsis>
505 Show status of PRI spans.
506 </synopsis>
507 <syntax>
508 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
509 <parameter name="Span">
510 <para>Specify the specific span to show. Show all spans if zero or not present.</para>
511 </parameter>
512 </syntax>
513 <description>
514 <para>Similar to the CLI command "pri show spans".</para>
515 </description>
516 </manager>
517 <manager name="PRIDebugSet" language="en_US">
518 <since>
519 <version>13.0.0</version>
520 </since>
521 <synopsis>
522 Set PRI debug levels for a span
523 </synopsis>
524 <syntax>
525 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
526 <parameter name="Span" required="true">
527 <para>Which span to affect.</para>
528 </parameter>
529 <parameter name="Level" required="true">
530 <para>What debug level to set. May be a numerical value or a text value from the list below</para>
531 <enumlist>
532 <enum name="off" />
533 <enum name="on" />
534 <enum name="hex" />
535 <enum name="intense" />
536 </enumlist>
537 </parameter>
538 </syntax>
539 <description>
540 <para>Equivalent to the CLI command "pri set debug &lt;level&gt; span &lt;span&gt;".</para>
541 </description>
542 </manager>
543 <manager name="PRIDebugFileSet" language="en_US">
544 <since>
545 <version>13.0.0</version>
546 </since>
547 <synopsis>
548 Set the file used for PRI debug message output
549 </synopsis>
550 <syntax>
551 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
552 <parameter name="File" required="true">
553 <para>Path of file to write debug output.</para>
554 </parameter>
555 </syntax>
556 <description>
557 <para>Equivalent to the CLI command "pri set debug file &lt;output-file&gt;"</para>
558 </description>
559 </manager>
560 <manager name="PRIDebugFileUnset" language="en_US">
561 <since>
562 <version>13.0.0</version>
563 </since>
564 <synopsis>
565 Disables file output for PRI debug messages
566 </synopsis>
567 <syntax>
568 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
569 </syntax>
570 </manager>
571 <managerEvent language="en_US" name="AlarmClear">
572 <managerEventInstance class="EVENT_FLAG_SYSTEM">
573 <since>
574 <version>12.0.0</version>
575 </since>
576 <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
577 <syntax>
578 <parameter name="DAHDIChannel">
579 <para>The DAHDI channel on which the alarm was cleared.</para>
580 <note><para>This is not an Asterisk channel identifier.</para></note>
581 </parameter>
582 </syntax>
583 </managerEventInstance>
584 </managerEvent>
585 <managerEvent language="en_US" name="SpanAlarmClear">
586 <managerEventInstance class="EVENT_FLAG_SYSTEM">
587 <since>
588 <version>12.0.0</version>
589 </since>
590 <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
591 <syntax>
592 <parameter name="Span">
593 <para>The span on which the alarm was cleared.</para>
594 </parameter>
595 </syntax>
596 </managerEventInstance>
597 </managerEvent>
598 <managerEvent language="en_US" name="DNDState">
599 <managerEventInstance class="EVENT_FLAG_SYSTEM">
600 <since>
601 <version>12.0.0</version>
602 </since>
603 <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
604 <syntax>
605 <parameter name="DAHDIChannel">
606 <para>The DAHDI channel on which DND status changed.</para>
607 <note><para>This is not an Asterisk channel identifier.</para></note>
608 </parameter>
609 <parameter name="Status">
610 <enumlist>
611 <enum name="enabled"/>
612 <enum name="disabled"/>
613 </enumlist>
614 </parameter>
615 </syntax>
616 </managerEventInstance>
617 </managerEvent>
618 <managerEvent language="en_US" name="Alarm">
619 <managerEventInstance class="EVENT_FLAG_SYSTEM">
620 <since>
621 <version>12.0.0</version>
622 </since>
623 <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
624 <syntax>
625 <parameter name="DAHDIChannel">
626 <para>The channel on which the alarm occurred.</para>
627 <note><para>This is not an Asterisk channel identifier.</para></note>
628 </parameter>
629 <parameter name="Alarm">
630 <para>A textual description of the alarm that occurred.</para>
631 </parameter>
632 </syntax>
633 </managerEventInstance>
634 </managerEvent>
635 <managerEvent language="en_US" name="SpanAlarm">
636 <managerEventInstance class="EVENT_FLAG_SYSTEM">
637 <since>
638 <version>12.0.0</version>
639 </since>
640 <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
641 <syntax>
642 <parameter name="Span">
643 <para>The span on which the alarm occurred.</para>
644 </parameter>
645 <parameter name="Alarm">
646 <para>A textual description of the alarm that occurred.</para>
647 </parameter>
648 </syntax>
649 </managerEventInstance>
650 </managerEvent>
651 <managerEvent language="en_US" name="DAHDIChannel">
652 <managerEventInstance class="EVENT_FLAG_CALL">
653 <since>
654 <version>12.0.0</version>
655 </since>
656 <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
657 <syntax>
658 <channel_snapshot/>
659 <parameter name="DAHDIGroup">
660 <para>The DAHDI logical group associated with this channel.</para>
661 </parameter>
662 <parameter name="DAHDISpan">
663 <para>The DAHDI span associated with this channel.</para>
664 </parameter>
665 <parameter name="DAHDIChannel">
666 <para>The DAHDI channel associated with this channel.</para>
667 </parameter>
668 </syntax>
669 </managerEventInstance>
670 </managerEvent>
671 ***/
672
673#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
674
675static const char * const lbostr[] = {
676"0 db (CSU)/0-133 feet (DSX-1)",
677"133-266 feet (DSX-1)",
678"266-399 feet (DSX-1)",
679"399-533 feet (DSX-1)",
680"533-655 feet (DSX-1)",
681"-7.5db (CSU)",
682"-15db (CSU)",
683"-22.5db (CSU)"
684};
685
686/*! Global jitterbuffer configuration - by default, jb is disabled
687 * \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
689{
690 .flags = 0,
691 .max_size = 200,
692 .resync_threshold = 1000,
693 .impl = "fixed",
694 .target_extra = 40,
695};
697
698/*!
699 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
700 * the user hangs up to reset the state machine so ring works properly.
701 * This is used to be able to support kewlstart by putting the zhone in
702 * groundstart mode since their forward disconnect supervision is entirely
703 * broken even though their documentation says it isn't and their support
704 * is entirely unwilling to provide any assistance with their channel banks
705 * even though their web site says they support their products for life.
706 */
707/* #define ZHONE_HACK */
708
709/*! \brief Typically, how many rings before we should send Caller*ID */
710#define DEFAULT_CIDRINGS 1
711
712#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
713
714
715/*! \brief Signaling types that need to use MF detection should be placed in this macro */
716#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))
717
718static const char tdesc[] = "DAHDI Telephony"
719#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
720 " w/"
721 #if defined(HAVE_PRI)
722 "PRI"
723 #endif /* defined(HAVE_PRI) */
724 #if defined(HAVE_SS7)
725 #if defined(HAVE_PRI)
726 " & "
727 #endif /* defined(HAVE_PRI) */
728 "SS7"
729 #endif /* defined(HAVE_SS7) */
730 #if defined(HAVE_OPENR2)
731 #if defined(HAVE_PRI) || defined(HAVE_SS7)
732 " & "
733 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
734 "MFC/R2"
735 #endif /* defined(HAVE_OPENR2) */
736#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2) */
737;
738
739static const char config[] = "chan_dahdi.conf";
740
741#ifdef LOTS_OF_SPANS
742#define NUM_SPANS DAHDI_MAX_SPANS
743#else
744#define NUM_SPANS 32
745#endif
746
747#define CHAN_PSEUDO -2
748
749#define CALLPROGRESS_PROGRESS 1
750#define CALLPROGRESS_FAX_OUTGOING 2
751#define CALLPROGRESS_FAX_INCOMING 4
752#define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
753
754#define NUM_CADENCE_MAX 25
755static int num_cadence = 4;
757
758static int has_pseudo;
759
760static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
761 { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
762 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
763 { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
764 { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
765};
766
767/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
768 * is 1, the second pause is 2 and so on.
769 */
770
772 2, /*!< Right after first long ring */
773 4, /*!< Right after long part */
774 3, /*!< After third chirp */
775 2, /*!< Second spell */
776};
777
778/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
779static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
780
781#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
782 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
783
784#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
785#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
786
787static char defaultcic[64] = "";
788static char defaultozz[64] = "";
789
790/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
791static char mwimonitornotify[PATH_MAX] = "";
792#ifndef HAVE_DAHDI_LINEREVERSE_VMWI
793static int mwisend_rpas = 0;
794#endif
795
796static char progzone[10] = "";
797
800
801static int numbufs = 4;
802
803static int mwilevel = 512;
804static int dtmfcid_level = 256;
805
806#define REPORT_CHANNEL_ALARMS 1
807#define REPORT_SPAN_ALARMS 2
809
810#ifdef HAVE_PRI
811static int pridebugfd = -1;
812static char pridebugfilename[1024] = "";
813#endif
814
815/*! \brief Protect the interface list (of dahdi_pvt's) */
817
818
819static int ifcount = 0;
820
821#ifdef HAVE_PRI
822AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
823#endif
824
825/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
826 when it's doing something critical. */
828
829/*! \brief This is the thread for the monitor which checks for input on the channels
830 which are not currently in use. */
835static int ss_thread_count = 0;
836static int num_restart_pending = 0;
837
838static int restart_monitor(void);
839
840static int dahdi_sendtext(struct ast_channel *c, const char *text);
841
842/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
843static inline int dahdi_get_event(int fd)
844{
845 int j;
846 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
847 return -1;
848 return j;
849}
850
851/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
852static inline int dahdi_wait_event(int fd)
853{
854 int i, j = 0;
855 i = DAHDI_IOMUX_SIGEVENT;
856 if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
857 return -1;
858 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
859 return -1;
860 return j;
861}
862
863/*! Chunk size to read -- we use 20ms chunks to make things happy. */
864#define READ_SIZE 160
865
866#define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
867#define MASK_INUSE (1 << 1) /*!< Channel currently in use */
868
869#define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE) /*!< 300 ms */
870#define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
871#define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE) /*!< 100 ms */
872#define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE) /*!< 500 ms */
873#define MIN_MS_SINCE_FLASH ((2000) ) /*!< 2000 ms */
874#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
875#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
876
877/*!
878 * \brief Configured ring timeout base.
879 * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
880 */
882
883#if defined(HAVE_SS7)
884
885struct dahdi_ss7 {
886 struct sig_ss7_linkset ss7;
887};
888
889static struct dahdi_ss7 linksets[NUM_SPANS];
890
891static int cur_ss7type = -1;
892static int cur_slc = -1;
893static int cur_linkset = -1;
894static int cur_pointcode = -1;
895static int cur_cicbeginswith = -1;
896static int cur_adjpointcode = -1;
897static int cur_networkindicator = -1;
898static int cur_defaultdpc = -1;
899#endif /* defined(HAVE_SS7) */
900
901#ifdef HAVE_OPENR2
902struct dahdi_mfcr2_conf {
903 openr2_variant_t variant;
904 int mfback_timeout;
905 int metering_pulse_timeout;
906 int max_ani;
907 int max_dnis;
908#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
909 int dtmf_time_on;
910 int dtmf_time_off;
911#endif
912#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
913 int dtmf_end_timeout;
914#endif
915 signed int get_ani_first:2;
916#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
917 signed int skip_category_request:2;
918#endif
919 unsigned int call_files:1;
920 unsigned int allow_collect_calls:1;
921 unsigned int charge_calls:1;
922 unsigned int accept_on_offer:1;
923 unsigned int forced_release:1;
924 unsigned int double_answer:1;
925 signed int immediate_accept:2;
926#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
927 signed int dtmf_dialing:2;
928 signed int dtmf_detection:2;
929#endif
930 char logdir[OR2_MAX_PATH];
931 char r2proto_file[OR2_MAX_PATH];
932 openr2_log_level_t loglevel;
933 openr2_calling_party_category_t category;
934};
935
936/* MFC-R2 pseudo-link structure */
937struct dahdi_mfcr2 {
938 int index; /*!< Unique index for CLI */
939 pthread_t r2master; /*!< Thread of master */
940 openr2_context_t *protocol_context; /*!< OpenR2 context handle */
941 struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
942 int numchans; /*!< Number of channels in this R2 block */
943 int live_chans; /*!< Number of unremoved channels in this R2 block */
944 int nodev; /*!< Link disconnected? */
945 struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
946};
947
948struct r2link_entry {
949 struct dahdi_mfcr2 mfcr2;
950 AST_LIST_ENTRY(r2link_entry) list;
951};
952static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
953static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
954
955
956/* how many r2links have been malloc'd */
957static int r2links_count = 0;
958
959#endif /* HAVE_OPENR2 */
960
961#ifdef HAVE_PRI
962
963struct dahdi_pri {
964 int dchannels[SIG_PRI_NUM_DCHANS]; /*!< What channel are the dchannels on */
965 int mastertrunkgroup; /*!< What trunk group is our master */
966 int prilogicalspan; /*!< Logical span number within trunk group */
967 struct sig_pri_span pri;
968};
969
970static struct dahdi_pri pris[NUM_SPANS];
971
972#if defined(HAVE_PRI_CCSS)
973/*! DAHDI PRI CCSS agent and monitor type name. */
974static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
975#endif /* defined(HAVE_PRI_CCSS) */
976
977#else
978/*! Shut up the compiler */
979struct dahdi_pri;
980#endif
981
982/* Polarity states */
983#define POLARITY_IDLE 0
984#define POLARITY_REV 1
985
986const char * const subnames[] = {
987 "Real",
988 "Callwait",
989 "Threeway"
990};
991
992static struct dahdi_pvt *iflist = NULL; /*!< Main interface list start */
993static struct dahdi_pvt *ifend = NULL; /*!< Main interface list end */
994
995#if defined(HAVE_PRI)
996struct doomed_pri {
997 struct sig_pri_span *pri;
998 AST_LIST_ENTRY(doomed_pri) list;
999};
1000static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);
1001
1002static void pri_destroy_span(struct sig_pri_span *pri);
1003
1004static struct dahdi_parms_pseudo {
1005 int buf_no; /*!< Number of buffers */
1006 int buf_policy; /*!< Buffer policy */
1007 int faxbuf_no; /*!< Number of Fax buffers */
1008 int faxbuf_policy; /*!< Fax buffer policy */
1009} dahdi_pseudo_parms;
1010#endif /* defined(HAVE_PRI) */
1011
1012/*! \brief Channel configuration from chan_dahdi.conf .
1013 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
1014 * Generally there is a field here for every possible configuration item.
1015 *
1016 * The state of fields is saved along the parsing and whenever a 'channel'
1017 * statement is reached, the current dahdi_chan_conf is used to configure the
1018 * channel (struct dahdi_pvt)
1019 *
1020 * \see dahdi_chan_init for the default values.
1021 */
1024#ifdef HAVE_PRI
1025 struct dahdi_pri pri;
1026#endif
1027
1028#if defined(HAVE_SS7)
1029 struct dahdi_ss7 ss7;
1030#endif /* defined(HAVE_SS7) */
1031
1032#ifdef HAVE_OPENR2
1033 struct dahdi_mfcr2_conf mfcr2;
1034#endif
1035 struct dahdi_params timing;
1036 int is_sig_auto; /*!< Use channel signalling from DAHDI? */
1037 /*! Continue configuration even if a channel is not there. */
1039
1040 /*!
1041 * \brief The serial port to listen for SMDI data on
1042 * \note Set from the "smdiport" string read in from chan_dahdi.conf
1043 */
1045
1046 /*!
1047 * \brief Don't create channels below this number
1048 * \note by default is 0 (no limit)
1049 */
1051
1052 /*!
1053 * \brief Don't create channels above this number (infinity by default)
1054 * \note by default is 0 (special value that means "no limit").
1055 */
1057};
1058
1059/*! returns a new dahdi_chan_conf with default values (by-value) */
1061{
1062 /* recall that if a field is not included here it is initialized
1063 * to 0 or equivalent
1064 */
1065 struct dahdi_chan_conf conf = {
1066#ifdef HAVE_PRI
1067 .pri.pri = {
1068 .nsf = PRI_NSF_NONE,
1069 .switchtype = PRI_SWITCH_NI2,
1070 .dialplan = PRI_UNKNOWN + 1,
1071 .localdialplan = PRI_NATIONAL_ISDN + 1,
1072 .nodetype = PRI_CPE,
1073 .qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
1074
1075#if defined(HAVE_PRI_CCSS)
1076 .cc_ptmp_recall_mode = 1,/* specificRecall */
1077 .cc_qsig_signaling_link_req = 1,/* retain */
1078 .cc_qsig_signaling_link_rsp = 1,/* retain */
1079#endif /* defined(HAVE_PRI_CCSS) */
1080
1081 .minunused = 2,
1082 .idleext = "",
1083 .idledial = "",
1084 .internationalprefix = "",
1085 .nationalprefix = "",
1086 .localprefix = "",
1087 .privateprefix = "",
1088 .unknownprefix = "",
1089 .colp_send = SIG_PRI_COLP_UPDATE,
1090 .resetinterval = -1,
1091 },
1092#endif
1093#if defined(HAVE_SS7)
1094 .ss7.ss7 = {
1095 .called_nai = SS7_NAI_NATIONAL,
1096 .calling_nai = SS7_NAI_NATIONAL,
1097 .internationalprefix = "",
1098 .nationalprefix = "",
1099 .subscriberprefix = "",
1100 .unknownprefix = "",
1101 .networkroutedprefix = ""
1102 },
1103#endif /* defined(HAVE_SS7) */
1104#ifdef HAVE_OPENR2
1105 .mfcr2 = {
1106 .variant = OR2_VAR_ITU,
1107 .mfback_timeout = -1,
1108 .metering_pulse_timeout = -1,
1109 .max_ani = 10,
1110 .max_dnis = 4,
1111 .get_ani_first = -1,
1112#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
1113 .skip_category_request = -1,
1114#endif
1115 .call_files = 0,
1116 .allow_collect_calls = 0,
1117 .charge_calls = 1,
1118 .accept_on_offer = 1,
1119 .forced_release = 0,
1120 .double_answer = 0,
1121 .immediate_accept = -1,
1122#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
1123 .dtmf_dialing = -1,
1124 .dtmf_detection = -1,
1125 .dtmf_time_on = OR2_DEFAULT_DTMF_ON,
1126 .dtmf_time_off = OR2_DEFAULT_DTMF_OFF,
1127#endif
1128#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
1129 .dtmf_end_timeout = -1,
1130#endif
1131 .logdir = "",
1132 .r2proto_file = "",
1133 .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
1134 .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
1135 },
1136#endif
1137 .chan = {
1138 .context = "default",
1139 .immediatering = 1,
1140 .cid_num = "",
1141 .cid_name = "",
1142 .cid_tag = "",
1143 .mohinterpret = "default",
1144 .mohsuggest = "",
1145 .parkinglot = "",
1146 .transfertobusy = 1,
1147 .dialmode = 0,
1148
1149 .ani_info_digits = 2,
1150 .ani_wink_time = 1000,
1151 .ani_timeout = 10000,
1152
1153 .cid_signalling = CID_SIG_BELL,
1154 .cid_start = CID_START_RING,
1155 .dahditrcallerid = 0,
1156 .use_callerid = 1,
1157 .sig = -1,
1158 .outsigmod = -1,
1159
1160 .cid_rxgain = +5.0,
1161
1162 .tonezone = -1,
1163
1164 .echocancel.head.tap_length = 1,
1165
1166 .busycount = 3,
1167
1168 .accountcode = "",
1169
1170 .mailbox = "",
1171
1172#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
1173 .mwisend_fsk = 1,
1174#endif
1175 .polarityonanswerdelay = 600,
1176
1177 .sendcalleridafter = DEFAULT_CIDRINGS,
1178
1179 .buf_policy = DAHDI_POLICY_IMMEDIATE,
1180 .buf_no = numbufs,
1181 .usefaxbuffers = 0,
1182 .cc_params = ast_cc_config_params_init(),
1183 .firstdigit_timeout = ANALOG_FIRST_DIGIT_TIMEOUT,
1184 .interdigit_timeout = ANALOG_INTER_DIGIT_TIMEOUT,
1185 .matchdigit_timeout = ANALOG_MATCH_DIGIT_TIMEOUT,
1186 },
1187 .timing = {
1188 .prewinktime = -1,
1189 .preflashtime = -1,
1190 .winktime = -1,
1191 .flashtime = -1,
1192 .starttime = -1,
1193 .rxwinktime = -1,
1194 .rxflashtime = -1,
1195 .debouncetime = -1
1196 },
1197 .is_sig_auto = 1,
1198 .ignore_failed_channels = 1,
1199 .smdi_port = "/dev/ttyS0",
1200 };
1201
1202 return conf;
1203}
1204
1205
1206static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
1207 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
1208 const char *data, int *cause);
1209static int dahdi_digit_begin(struct ast_channel *ast, char digit);
1210static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
1211static int dahdi_sendtext(struct ast_channel *c, const char *text);
1212static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout);
1213static int dahdi_hangup(struct ast_channel *ast);
1214static int dahdi_answer(struct ast_channel *ast);
1215static struct ast_frame *dahdi_read(struct ast_channel *ast);
1216static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
1217static struct ast_frame *dahdi_exception(struct ast_channel *ast);
1218static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
1219static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1220static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
1221static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
1222static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
1223static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
1224static int dahdi_devicestate(const char *data);
1225static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
1226
1228 .type = "DAHDI",
1229 .description = tdesc,
1230 .requester = dahdi_request,
1231 .send_digit_begin = dahdi_digit_begin,
1232 .send_digit_end = dahdi_digit_end,
1233 .send_text = dahdi_sendtext,
1234 .call = dahdi_call,
1235 .hangup = dahdi_hangup,
1236 .answer = dahdi_answer,
1237 .read = dahdi_read,
1238 .write = dahdi_write,
1239 .exception = dahdi_exception,
1240 .indicate = dahdi_indicate,
1241 .fixup = dahdi_fixup,
1242 .setoption = dahdi_setoption,
1243 .queryoption = dahdi_queryoption,
1244 .func_channel_read = dahdi_func_read,
1245 .func_channel_write = dahdi_func_write,
1246 .devicestate = dahdi_devicestate,
1247 .cc_callback = dahdi_cc_callback,
1248};
1249
1250#define GET_CHANNEL(p) ((p)->channel)
1251
1253{
1254 switch (sig) {
1255 case SIG_FXOLS:
1256 return ANALOG_SIG_FXOLS;
1257 case SIG_FXOGS:
1258 return ANALOG_SIG_FXOGS;
1259 case SIG_FXOKS:
1260 return ANALOG_SIG_FXOKS;
1261 case SIG_FXSLS:
1262 return ANALOG_SIG_FXSLS;
1263 case SIG_FXSGS:
1264 return ANALOG_SIG_FXSGS;
1265 case SIG_FXSKS:
1266 return ANALOG_SIG_FXSKS;
1267 case SIG_EMWINK:
1268 return ANALOG_SIG_EMWINK;
1269 case SIG_EM:
1270 return ANALOG_SIG_EM;
1271 case SIG_EM_E1:
1272 return ANALOG_SIG_EM_E1;
1273 case SIG_FEATD:
1274 return ANALOG_SIG_FEATD;
1275 case SIG_FEATDMF:
1276 return ANALOG_SIG_FEATDMF;
1277 case SIG_E911:
1278 return SIG_E911;
1279 case SIG_FGC_CAMA:
1280 return ANALOG_SIG_FGC_CAMA;
1281 case SIG_FGC_CAMAMF:
1282 return ANALOG_SIG_FGC_CAMAMF;
1283 case SIG_FEATB:
1284 return ANALOG_SIG_FEATB;
1285 case SIG_SFWINK:
1286 return ANALOG_SIG_SFWINK;
1287 case SIG_SF:
1288 return ANALOG_SIG_SF;
1289 case SIG_SF_FEATD:
1290 return ANALOG_SIG_SF_FEATD;
1291 case SIG_SF_FEATDMF:
1292 return ANALOG_SIG_SF_FEATDMF;
1293 case SIG_FEATDMF_TA:
1294 return ANALOG_SIG_FEATDMF_TA;
1295 case SIG_SF_FEATB:
1296 return ANALOG_SIG_FEATB;
1297 default:
1298 return -1;
1299 }
1300}
1301
1302
1304{
1305 switch (tone) {
1307 return DAHDI_TONE_RINGTONE;
1309 return DAHDI_TONE_STUTTER;
1311 return DAHDI_TONE_CONGESTION;
1313 return DAHDI_TONE_DIALTONE;
1315 return DAHDI_TONE_DIALRECALL;
1316 case ANALOG_TONE_INFO:
1317 return DAHDI_TONE_INFO;
1318 default:
1319 return -1;
1320 }
1321}
1322
1323static int analogsub_to_dahdisub(enum analog_sub analogsub)
1324{
1325 int index;
1326
1327 switch (analogsub) {
1328 case ANALOG_SUB_REAL:
1329 index = SUB_REAL;
1330 break;
1332 index = SUB_CALLWAIT;
1333 break;
1335 index = SUB_THREEWAY;
1336 break;
1337 default:
1338 ast_log(LOG_ERROR, "Unidentified sub!\n");
1339 index = SUB_REAL;
1340 }
1341
1342 return index;
1343}
1344
1345/*!
1346 * \internal
1347 * \brief release all members on the doomed pris list
1348 * \since 13.0
1349 *
1350 * Called periodically by the monitor threads to release spans marked for
1351 * removal.
1352 */
1353static void release_doomed_pris(void)
1354{
1355#ifdef HAVE_PRI
1356 struct doomed_pri *entry;
1357
1358 AST_LIST_LOCK(&doomed_pris);
1359 while ((entry = AST_LIST_REMOVE_HEAD(&doomed_pris, list))) {
1360 /* The span destruction must be done with this lock not held */
1361 AST_LIST_UNLOCK(&doomed_pris);
1362 ast_debug(4, "Destroying span %d from doomed queue.\n",
1363 entry->pri->span);
1364 pri_destroy_span(entry->pri);
1365 ast_free(entry);
1366 AST_LIST_LOCK(&doomed_pris);
1367 }
1368 AST_LIST_UNLOCK(&doomed_pris);
1369#endif
1370}
1371
1372#ifdef HAVE_PRI
1373/*!
1374 * \brief Queue a span for destruction
1375 * \since 13.0
1376 *
1377 * \param pri the span to destroy
1378 *
1379 * Add a span to the list of spans to be destroyed later on
1380 * by the monitor thread. Allows destroying a span while holding its
1381 * lock.
1382 */
1383static void pri_queue_for_destruction(struct sig_pri_span *pri)
1384{
1385 struct doomed_pri *entry;
1386
1387 AST_LIST_LOCK(&doomed_pris);
1388 AST_LIST_TRAVERSE(&doomed_pris, entry, list) {
1389 if (entry->pri == pri) {
1390 AST_LIST_UNLOCK(&doomed_pris);
1391 return;
1392 }
1393 }
1394 entry = ast_calloc(sizeof(struct doomed_pri), 1);
1395 if (!entry) {
1396 /* Nothing useful to do here. Panic? */
1397 ast_log(LOG_WARNING, "Failed allocating memory for a doomed_pri.\n");
1398 AST_LIST_UNLOCK(&doomed_pris);
1399 return;
1400 }
1401 entry->pri = pri;
1402 ast_debug(4, "Queue span %d for destruction.\n", pri->span);
1403 AST_LIST_INSERT_TAIL(&doomed_pris, entry, list);
1404 AST_LIST_UNLOCK(&doomed_pris);
1405}
1406#endif
1407
1408/*!
1409 * \internal
1410 * \brief Send a dial string to DAHDI.
1411 * \since 12.0.0
1412 *
1413 * \param pvt DAHDI private pointer
1414 * \param operation DAHDI dial operation to do to string
1415 * \param dial_str Dial string to send
1416 *
1417 * \retval 0 on success.
1418 * \retval non-zero on error.
1419 */
1420static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
1421{
1422 int res;
1423 int offset;
1424 const char *pos;
1425 struct dahdi_dialoperation zo = {
1426 .op = operation,
1427 };
1428
1429 /* Convert the W's to ww. */
1430 pos = dial_str;
1431 for (offset = 0; offset < sizeof(zo.dialstr) - 1; ++offset) {
1432 if (!*pos) {
1433 break;
1434 }
1435 if (*pos == 'W') {
1436 /* Convert 'W' to "ww" */
1437 ++pos;
1438 if (offset >= sizeof(zo.dialstr) - 3) {
1439 /* No room to expand */
1440 break;
1441 }
1442 zo.dialstr[offset] = 'w';
1443 ++offset;
1444 zo.dialstr[offset] = 'w';
1445 continue;
1446 }
1447 zo.dialstr[offset] = *pos++;
1448 }
1449 /* The zo initialization has already terminated the dialstr. */
1450
1451 ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
1452 pvt->channel, dial_str, zo.dialstr);
1453 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
1454 if (res) {
1455 ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
1456 pvt->channel, dial_str, strerror(errno));
1457 }
1458
1459 return res;
1460}
1461
1463static int bump_gains(struct dahdi_pvt *p);
1464static int dahdi_setlinear(int dfd, int linear);
1465
1466static int my_start_cid_detect(void *pvt, int cid_signalling)
1467{
1468 struct dahdi_pvt *p = pvt;
1469 int index = SUB_REAL;
1471 if (!p->cs) {
1472 ast_log(LOG_ERROR, "Unable to alloc callerid\n");
1473 return -1;
1474 }
1475 bump_gains(p);
1476 dahdi_setlinear(p->subs[index].dfd, 0);
1477
1478 return 0;
1479}
1480
1481static int restore_gains(struct dahdi_pvt *p);
1482
1483static int my_stop_cid_detect(void *pvt)
1484{
1485 struct dahdi_pvt *p = pvt;
1486 int index = SUB_REAL;
1487
1488 if (p->cs) {
1489 callerid_free(p->cs);
1490 }
1491
1492 /* Restore linear mode after Caller*ID processing */
1493 dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
1494 restore_gains(p);
1495
1496 return 0;
1497}
1498
1499static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
1500{
1501 struct dahdi_pvt *p = pvt;
1502 struct analog_pvt *analog_p = p->sig_pvt;
1503 struct pollfd poller;
1504 char *name, *num;
1505 int index = SUB_REAL;
1506 int res;
1507 unsigned char buf[256];
1508 int flags;
1509 int redirecting;
1510
1511 poller.fd = p->subs[SUB_REAL].dfd;
1512 poller.events = POLLPRI | POLLIN;
1513 poller.revents = 0;
1514
1515 res = poll(&poller, 1, timeout);
1516
1517 if (poller.revents & POLLPRI) {
1519 return 1;
1520 }
1521
1522 if (poller.revents & POLLIN) {
1523 /*** NOTES ***/
1524 /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
1525 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
1526 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
1527 * a failure and die, and returning 2 means no event was received. */
1528 res = read(p->subs[index].dfd, buf, sizeof(buf));
1529 if (res < 0) {
1530 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1531 return -1;
1532 }
1533
1534 if (analog_p->ringt > 0) {
1535 if (!(--analog_p->ringt)) {
1536 /* only return if we timeout from a ring event */
1537 return -1;
1538 }
1539 }
1540
1541 if (p->cid_signalling == CID_SIG_V23_JP) {
1542 res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
1543 } else {
1544 res = callerid_feed(p->cs, buf, res, AST_LAW(p));
1545 }
1546 if (res < 0) {
1547 /*
1548 * The previous diagnostic message output likely
1549 * explains why it failed.
1550 */
1551 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
1552 return -1;
1553 }
1554
1555 if (res == 1) {
1556 struct ast_channel *chan = analog_p->ss_astchan;
1558 if (name)
1560 if (num)
1561 ast_copy_string(numbuf, num, ANALOG_MAX_CID);
1562
1564 /* If we got a presentation, we must set it on the channel */
1565 struct ast_party_caller caller;
1566
1568 caller.id.name.presentation = caller.id.number.presentation = (flags & CID_PRIVATE_NUMBER) ?
1571 ast_party_caller_free(&caller);
1572 }
1573 if (redirecting) {
1574 /* There is a redirecting reason available in the Caller*ID received.
1575 * No idea what the redirecting number is, since the Caller*ID protocol
1576 * has no parameter for that, but at least we know WHY it was redirected. */
1577 ast_channel_redirecting(chan)->reason.code = redirecting;
1578 }
1579
1580 if (flags & CID_QUALIFIER) {
1581 /* This is the inverse of how the qualifier is set in sig_analog */
1582 pbx_builtin_setvar_helper(chan, "CALL_QUALIFIER", "1");
1583 }
1584
1585 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));
1586 return 0;
1587 }
1588 }
1589
1590 *ev = ANALOG_EVENT_NONE;
1591 return 2;
1592}
1593
1594static const char *event2str(int event);
1595
1596static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
1597{
1598 unsigned char buf[256];
1599 int distMatches;
1600 int curRingData[RING_PATTERNS];
1601 int receivedRingT;
1602 int counter1;
1603 int counter;
1604 int i;
1605 int res;
1606 int checkaftercid = 0;
1607 const char *matched_context;
1608 struct dahdi_pvt *p = pvt;
1609 struct analog_pvt *analog_p = p->sig_pvt;
1610
1611 if (ringdata == NULL) {
1612 ringdata = curRingData;
1613 } else {
1614 checkaftercid = 1;
1615 }
1616
1617 /* We must have a ring by now so lets try to listen for distinctive ringing */
1618 if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
1619 /* Clear the current ring data array so we don't have old data in it. */
1620 for (receivedRingT = 0; receivedRingT < RING_PATTERNS; receivedRingT++)
1621 ringdata[receivedRingT] = 0;
1622 receivedRingT = 0;
1623
1624 if (checkaftercid && distinctiveringaftercid) {
1625 ast_verb(3, "Detecting post-CID distinctive ring\n");
1626 }
1627
1628 for (;;) {
1629 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
1630 res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i);
1631 if (res) {
1632 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
1633 ast_hangup(chan);
1634 return 1;
1635 }
1636 if (i & DAHDI_IOMUX_SIGEVENT) {
1637 res = dahdi_get_event(p->subs[idx].dfd);
1638 ast_debug(3, "Got event %d (%s)...\n", res, event2str(res));
1639 if (res == DAHDI_EVENT_NOALARM) {
1640 p->inalarm = 0;
1641 analog_p->inalarm = 0;
1642 } else if (res == DAHDI_EVENT_RINGOFFHOOK) {
1643 /* Let us detect distinctive ring */
1644 ringdata[receivedRingT] = analog_p->ringt;
1645
1646 if (analog_p->ringt < analog_p->ringt_base / 2) {
1647 break;
1648 }
1649 /* Increment the ringT counter so we can match it against
1650 values in chan_dahdi.conf for distinctive ring */
1651 if (++receivedRingT == RING_PATTERNS) {
1652 break;
1653 }
1654 }
1655 } else if (i & DAHDI_IOMUX_READ) {
1656 res = read(p->subs[idx].dfd, buf, sizeof(buf));
1657 if (res < 0) {
1658 if (errno != ELAST) {
1659 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1660 ast_hangup(chan);
1661 return 1;
1662 }
1663 break;
1664 }
1665 if (analog_p->ringt > 0) {
1666 if (!(--analog_p->ringt)) {
1667 break;
1668 }
1669 }
1670 }
1671 }
1672 }
1673
1674 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
1675 ast_verb(3, "Detected ring pattern: %d,%d,%d\n", ringdata[0], ringdata[1], ringdata[2]);
1676 matched_context = p->defcontext;
1677 for (counter = 0; counter < 3; counter++) {
1678 int range = p->drings.ringnum[counter].range;
1679
1680 distMatches = 0;
1681 ast_verb(3, "Checking %d,%d,%d with +/- %d range\n",
1682 p->drings.ringnum[counter].ring[0],
1683 p->drings.ringnum[counter].ring[1],
1684 p->drings.ringnum[counter].ring[2],
1685 range);
1686 for (counter1 = 0; counter1 < 3; counter1++) {
1687 int ring = p->drings.ringnum[counter].ring[counter1];
1688
1689 if (ring == -1) {
1690 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
1691 ringdata[counter1]);
1692 distMatches++;
1693 } else if (ring - range <= ringdata[counter1] && ringdata[counter1] <= ring + range) {
1694 ast_verb(3, "Ring pattern %d is in range: %d to %d\n",
1695 ringdata[counter1], ring - range, ring + range);
1696 distMatches++;
1697 } else {
1698 /* The current dring pattern cannot match. */
1699 break;
1700 }
1701 }
1702
1703 if (distMatches == 3) {
1704 /* The ring matches, set the context to whatever is for distinctive ring.. */
1705 matched_context = S_OR(p->drings.ringContext[counter].contextData, p->defcontext);
1706 ast_verb(3, "Matched Distinctive Ring context %s\n", matched_context);
1707 break;
1708 }
1709 }
1710
1711 /* Set selected distinctive ring context if not already set. */
1712 if (strcmp(p->context, matched_context) != 0) {
1713 ast_copy_string(p->context, matched_context, sizeof(p->context));
1714 ast_channel_context_set(chan, matched_context);
1715 }
1716
1717 return 0;
1718}
1719
1720static int my_stop_callwait(void *pvt)
1721{
1722 struct dahdi_pvt *p = pvt;
1723 p->callwaitingrepeat = 0;
1724 p->cidcwexpire = 0;
1725 p->cid_suppress_expire = 0;
1726
1727 return 0;
1728}
1729
1730static int send_callerid(struct dahdi_pvt *p);
1731static int save_conference(struct dahdi_pvt *p);
1732static int restore_conference(struct dahdi_pvt *p);
1733
1734static int my_callwait(void *pvt)
1735{
1736 struct dahdi_pvt *p = pvt;
1737
1739 if (p->cidspill) {
1740 ast_log(LOG_WARNING, "Spill already exists?!?\n");
1741 ast_free(p->cidspill);
1742 }
1743
1744 /*
1745 * SAS: Subscriber Alert Signal, 440Hz for 300ms
1746 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
1747 */
1748 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
1749 return -1;
1750 save_conference(p);
1751 /* Silence */
1752 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
1753 if (!p->callwaitrings && p->callwaitingcallerid) {
1754 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
1755 p->callwaitcas = 1;
1756 p->cidlen = 2400 + 680 + READ_SIZE * 4;
1757 } else {
1758 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
1759 p->callwaitcas = 0;
1760 p->cidlen = 2400 + READ_SIZE * 4;
1761 }
1762 p->cidpos = 0;
1763 send_callerid(p);
1764
1765 return 0;
1766}
1767
1768static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
1769{
1770 struct dahdi_pvt *p = pvt;
1771 struct analog_pvt *analog_p = p->sig_pvt;
1772
1773 ast_debug(2, "Starting cid spill\n");
1774
1775 if (p->cidspill) {
1776 ast_log(LOG_WARNING, "cidspill already exists??\n");
1777 ast_free(p->cidspill);
1778 }
1779
1781 int pres = ast_party_id_presentation(&caller->id);
1782 if (cwcid == 0) {
1783 /* Some CPE support additional parameters for on-hook Caller*ID,
1784 * such as redirecting reason and call qualifier, so send those
1785 * if available.
1786 * I don't know of any CPE that supports this for Call Waiting (unfortunately),
1787 * so don't send those for call waiting as that will just lengthen the CID spill
1788 * for no good reason.
1789 */
1791 caller->id.name.str,
1793 NULL,
1794 analog_p->redirecting_reason,
1795 pres,
1796 analog_p->call_qualifier,
1798 AST_LAW(p));
1799 } else {
1800 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
1802 p->callwaitcas = 0;
1803 p->cidcwexpire = 0;
1805 caller->id.name.str,
1807 NULL,
1808 -1,
1809 pres,
1810 0,
1811 AST_LAW(p));
1812 p->cidlen += READ_SIZE * 4;
1813 }
1814 p->cidpos = 0;
1815 p->cid_suppress_expire = 0;
1816 send_callerid(p);
1817 }
1818 return 0;
1819}
1820
1822{
1823 struct dahdi_pvt *p = pvt;
1824 if (p->dsp)
1826
1827 return 0;
1828}
1829
1830static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
1831{
1832 struct dahdi_pvt *p = pvt;
1833
1834 if (p->channel == CHAN_PSEUDO)
1835 ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
1836
1837 if (mode == ANALOG_DIGITMODE_DTMF) {
1838 /* If we do hardware dtmf, no need for a DSP */
1839 if (p->hardwaredtmf) {
1840 if (p->dsp) {
1841 ast_dsp_free(p->dsp);
1842 p->dsp = NULL;
1843 }
1844 return 0;
1845 }
1846
1847 if (!p->dsp) {
1848 p->dsp = ast_dsp_new();
1849 if (!p->dsp) {
1850 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1851 return -1;
1852 }
1853 }
1854
1856 } else if (mode == ANALOG_DIGITMODE_MF) {
1857 if (!p->dsp) {
1858 p->dsp = ast_dsp_new();
1859 if (!p->dsp) {
1860 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1861 return -1;
1862 }
1863 }
1865 }
1866 return 0;
1867}
1868
1869static int dahdi_wink(struct dahdi_pvt *p, int index);
1870
1871static int my_wink(void *pvt, enum analog_sub sub)
1872{
1873 struct dahdi_pvt *p = pvt;
1874 int index = analogsub_to_dahdisub(sub);
1875 if (index != SUB_REAL) {
1876 ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
1877 }
1878 return dahdi_wink(p, index);
1879}
1880
1881static void wakeup_sub(struct dahdi_pvt *p, int a);
1882
1883static int reset_conf(struct dahdi_pvt *p);
1884
1885static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
1886
1887static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
1888{
1889 struct ast_frame *f = *dest;
1890 struct dahdi_pvt *p = pvt;
1891 int idx = analogsub_to_dahdisub(analog_index);
1892
1893 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
1894 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
1895 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
1896
1897 if (f->subclass.integer == 'f') {
1898 if (f->frametype == AST_FRAME_DTMF_END) {
1899 /* Fax tone -- Handle and return NULL */
1900 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
1901 /* If faxbuffers are configured, use them for the fax transmission */
1902 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
1903 struct dahdi_bufferinfo bi = {
1904 .txbufpolicy = p->faxbuf_policy,
1905 .bufsize = p->bufsize,
1906 .numbufs = p->faxbuf_no
1907 };
1908 int res;
1909
1910 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
1911 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
1912 } else {
1913 p->bufferoverrideinuse = 1;
1914 }
1915 }
1916 p->faxhandled = 1;
1917 if (p->dsp) {
1918 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
1920 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
1921 }
1922 if (strcmp(ast_channel_exten(ast), "fax")) {
1923 const char *target_context = ast_channel_context(ast);
1924
1925 /*
1926 * We need to unlock 'ast' here because ast_exists_extension has the
1927 * potential to start autoservice on the channel. Such action is prone
1928 * to deadlock if the channel is locked.
1929 *
1930 * ast_async_goto() has its own restriction on not holding the
1931 * channel lock.
1932 */
1934 ast_channel_unlock(ast);
1935 if (ast_exists_extension(ast, target_context, "fax", 1,
1936 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
1937 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
1938 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
1939 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
1940 if (ast_async_goto(ast, target_context, "fax", 1))
1941 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
1942 } else {
1943 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
1944 }
1945 ast_channel_lock(ast);
1946 ast_mutex_lock(&p->lock);
1947 } else {
1948 ast_debug(1, "Already in a fax extension, not redirecting\n");
1949 }
1950 } else {
1951 ast_debug(1, "Fax already handled\n");
1952 }
1953 dahdi_confmute(p, 0);
1954 }
1955 p->subs[idx].f.frametype = AST_FRAME_NULL;
1956 p->subs[idx].f.subclass.integer = 0;
1957 *dest = &p->subs[idx].f;
1958 }
1959}
1960
1961static void my_lock_private(void *pvt)
1962{
1963 struct dahdi_pvt *p = pvt;
1964 ast_mutex_lock(&p->lock);
1965}
1966
1967static void my_unlock_private(void *pvt)
1968{
1969 struct dahdi_pvt *p = pvt;
1971}
1972
1973static void my_deadlock_avoidance_private(void *pvt)
1974{
1975 struct dahdi_pvt *p = pvt;
1976
1978}
1979
1981{
1982 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1983 struct ast_channel_blob *obj = stasis_message_data(msg);
1984 struct ast_json *group, *span, *channel;
1985
1986 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1987 if (!channel_string) {
1988 return NULL;
1989 }
1990
1991 group = ast_json_object_get(obj->blob, "group");
1992 span = ast_json_object_get(obj->blob, "span");
1993 channel = ast_json_object_get(obj->blob, "channel");
1994
1995 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
1996 "%s"
1997 "DAHDIGroup: %llu\r\n"
1998 "DAHDISpan: %u\r\n"
1999 "DAHDIChannel: %s\r\n",
2000 ast_str_buffer(channel_string),
2002 (unsigned int)ast_json_integer_get(span),
2003 ast_json_string_get(channel));
2004}
2005
2008 );
2009
2010/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
2011static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
2012{
2013 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
2014
2015 ast_assert(dahdi_channel != NULL);
2016
2017 blob = ast_json_pack("{s: I, s: i, s: s}",
2018 "group", (ast_json_int_t)group,
2019 "span", span,
2020 "channel", dahdi_channel);
2021 if (!blob) {
2022 return;
2023 }
2024
2025 ast_channel_lock(chan);
2026 ast_channel_publish_blob(chan, dahdichannel_type(), blob);
2027 ast_channel_unlock(chan);
2028}
2029
2030/*!
2031 * \internal
2032 * \brief Post an AMI DAHDI channel association event.
2033 * \since 1.8
2034 *
2035 * \param p DAHDI private pointer
2036 * \param chan Channel associated with the private pointer
2037 */
2038static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
2039{
2040 char ch_name[23];
2041
2042 if (p->channel < CHAN_PSEUDO) {
2043 /* No B channel */
2044 snprintf(ch_name, sizeof(ch_name), "no-media (%d)", p->channel);
2045 } else if (p->channel == CHAN_PSEUDO) {
2046 /* Pseudo channel */
2047 strcpy(ch_name, "pseudo");
2048 } else {
2049 /* Real channel */
2050 snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
2051 }
2052 publish_dahdichannel(chan, p->group, p->span, ch_name);
2053}
2054
2055#ifdef HAVE_PRI
2056/*!
2057 * \internal
2058 * \brief Post an AMI DAHDI channel association event.
2059 * \since 1.8
2060 *
2061 * \param pvt DAHDI private pointer
2062 * \param chan Channel associated with the private pointer
2063 */
2064static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
2065{
2066 struct dahdi_pvt *p = pvt;
2067
2068 dahdi_ami_channel_event(p, chan);
2069}
2070#endif
2071
2072/* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
2073* returns the last value of the linear setting
2074*/
2075static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
2076{
2077 struct dahdi_pvt *p = pvt;
2078 int oldval;
2079 int idx = analogsub_to_dahdisub(sub);
2080
2081 dahdi_setlinear(p->subs[idx].dfd, linear_mode);
2082 oldval = p->subs[idx].linear;
2083 p->subs[idx].linear = linear_mode ? 1 : 0;
2084 return oldval;
2085}
2086
2087static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
2088{
2089 struct dahdi_pvt *p = pvt;
2090 int idx = analogsub_to_dahdisub(sub);
2091
2092 p->subs[idx].inthreeway = inthreeway;
2093}
2094
2095static int get_alarms(struct dahdi_pvt *p);
2096static void handle_alarms(struct dahdi_pvt *p, int alms);
2097static void my_get_and_handle_alarms(void *pvt)
2098{
2099 int res;
2100 struct dahdi_pvt *p = pvt;
2101
2102 res = get_alarms(p);
2103 handle_alarms(p, res);
2104}
2105
2107{
2109
2110 if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
2111 struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
2112
2113 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
2114 return p->sig_pvt;
2115 }
2116 }
2117 return NULL;
2118}
2119
2120static int my_get_sub_fd(void *pvt, enum analog_sub sub)
2121{
2122 struct dahdi_pvt *p = pvt;
2123 int dahdi_sub = analogsub_to_dahdisub(sub);
2124 return p->subs[dahdi_sub].dfd;
2125}
2126
2127static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
2128{
2129 struct dahdi_pvt *p = pvt;
2130
2131 /* Choose proper cadence */
2132 if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
2133 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
2134 ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast_channel_name(ast), strerror(errno));
2135 *cid_rings = cidrings[p->distinctivering - 1];
2136 } else {
2137 if (p->distinctivering > 0) {
2138 ast_log(LOG_WARNING, "Cadence %d is not defined, falling back to default ring cadence\n", p->distinctivering);
2139 }
2140 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
2141 ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast), strerror(errno));
2142 *cid_rings = p->sendcalleridafter;
2143 }
2144}
2145
2146static void my_set_alarm(void *pvt, int in_alarm)
2147{
2148 struct dahdi_pvt *p = pvt;
2149
2150 p->inalarm = in_alarm;
2151}
2152
2153static void my_set_dialing(void *pvt, int is_dialing)
2154{
2155 struct dahdi_pvt *p = pvt;
2156
2157 p->dialing = is_dialing;
2158}
2159
2160static void my_set_outgoing(void *pvt, int is_outgoing)
2161{
2162 struct dahdi_pvt *p = pvt;
2163
2164 p->outgoing = is_outgoing;
2165}
2166
2167#if defined(HAVE_PRI) || defined(HAVE_SS7)
2168static void my_set_digital(void *pvt, int is_digital)
2169{
2170 struct dahdi_pvt *p = pvt;
2171
2172 p->digital = is_digital;
2173}
2174#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2175
2176#if defined(HAVE_SS7)
2177static void my_set_inservice(void *pvt, int is_inservice)
2178{
2179 struct dahdi_pvt *p = pvt;
2180
2181 p->inservice = is_inservice;
2182}
2183#endif /* defined(HAVE_SS7) */
2184
2185#if defined(HAVE_SS7)
2186static void my_set_locallyblocked(void *pvt, int is_blocked)
2187{
2188 struct dahdi_pvt *p = pvt;
2189
2190 p->locallyblocked = is_blocked;
2191}
2192#endif /* defined(HAVE_SS7) */
2193
2194#if defined(HAVE_SS7)
2195static void my_set_remotelyblocked(void *pvt, int is_blocked)
2196{
2197 struct dahdi_pvt *p = pvt;
2198
2199 p->remotelyblocked = is_blocked;
2200}
2201#endif /* defined(HAVE_SS7) */
2202
2203static void my_set_ringtimeout(void *pvt, int ringt)
2204{
2205 struct dahdi_pvt *p = pvt;
2206 p->ringt = ringt;
2207}
2208
2209static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
2210{
2211 struct dahdi_pvt *p = pvt;
2212
2213 /* We reset p->waitfordialtonetemp here, to prevent leaking to future calls,
2214 * but we also need to check against this value until we get dialtone
2215 * or the timer expires, since waitingfordt is when the timer started,
2216 * not when it should expire.
2217 *
2218 * Critically, we only set p->waitingfordt here if waitfordialtone or waitfordialtonetemp
2219 * has already been set, as waitingfordt is what is checked at runtime to determine
2220 * if we should be waiting for dial tone. This ensures that if a second call
2221 * is initiated concurrently, the first one "consumes" waitfordialtonetemp and resets it,
2222 * preventing leaking to other calls while remaining available to check on the first one while dialing.
2223 */
2225 p->waitfordialtonetemp = 0;
2226
2228 return;
2229 }
2230
2231 /* Because the DSP is allocated when the channel is created,
2232 * if we requested waitfordialtone later (in a predial handler),
2233 * we need to create it now */
2234 if (!p->dsp) {
2235 p->dsp = ast_dsp_new();
2236 if (!p->dsp) {
2237 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
2238 return;
2239 }
2240 }
2243
2244 ast_debug(1, "Defer dialing for %dms or dialtone\n", p->waitfordialtoneduration);
2245 gettimeofday(&p->waitingfordt, NULL);
2247}
2248
2249static int my_check_waitingfordt(void *pvt)
2250{
2251 struct dahdi_pvt *p = pvt;
2252
2253 if (p->waitingfordt.tv_sec) {
2254 return 1;
2255 }
2256
2257 return 0;
2258}
2259
2260static void my_set_confirmanswer(void *pvt, int flag)
2261{
2262 struct dahdi_pvt *p = pvt;
2263 p->confirmanswer = flag;
2264}
2265
2266static int my_check_confirmanswer(void *pvt)
2267{
2268 struct dahdi_pvt *p = pvt;
2269 if (p->confirmanswer) {
2270 return 1;
2271 }
2272
2273 return 0;
2274}
2275
2276static void my_set_callwaiting(void *pvt, int callwaiting_enable)
2277{
2278 struct dahdi_pvt *p = pvt;
2279
2280 p->callwaiting = callwaiting_enable;
2281}
2282
2283static void my_cancel_cidspill(void *pvt)
2284{
2285 struct dahdi_pvt *p = pvt;
2286
2287 ast_free(p->cidspill);
2288 p->cidspill = NULL;
2290}
2291
2292static int my_confmute(void *pvt, int mute)
2293{
2294 struct dahdi_pvt *p = pvt;
2295 return dahdi_confmute(p, mute);
2296}
2297
2298static void my_set_pulsedial(void *pvt, int flag)
2299{
2300 struct dahdi_pvt *p = pvt;
2301 p->pulsedial = flag;
2302}
2303
2304static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
2305{
2306 struct dahdi_pvt *p = pvt;
2307
2308 p->owner = new_owner;
2309}
2310
2311static const char *my_get_orig_dialstring(void *pvt)
2312{
2313 struct dahdi_pvt *p = pvt;
2314
2315 return p->dialstring;
2316}
2317
2318static void my_increase_ss_count(void)
2319{
2323}
2324
2325static void my_decrease_ss_count(void)
2326{
2331}
2332
2333static void my_all_subchannels_hungup(void *pvt)
2334{
2335 struct dahdi_pvt *p = pvt;
2336 int res, law;
2337
2338 p->faxhandled = 0;
2339 p->didtdd = 0;
2340
2341 if (p->dsp) {
2342 ast_dsp_free(p->dsp);
2343 p->dsp = NULL;
2344 }
2345
2346 p->law = p->law_default;
2347 law = p->law_default;
2348 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
2349 if (res < 0)
2350 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
2351
2353
2354#if 1
2355 {
2356 int i;
2357 p->owner = NULL;
2358 /* Cleanup owners here */
2359 for (i = 0; i < 3; i++) {
2360 p->subs[i].owner = NULL;
2361 }
2362 }
2363#endif
2364
2365 reset_conf(p);
2366 if (num_restart_pending == 0) {
2368 }
2369}
2370
2371static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
2372
2373static int my_conf_del(void *pvt, enum analog_sub sub)
2374{
2375 struct dahdi_pvt *p = pvt;
2376 int x = analogsub_to_dahdisub(sub);
2377
2378 return conf_del(p, &p->subs[x], x);
2379}
2380
2381static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
2382
2383static int my_conf_add(void *pvt, enum analog_sub sub)
2384{
2385 struct dahdi_pvt *p = pvt;
2386 int x = analogsub_to_dahdisub(sub);
2387
2388 return conf_add(p, &p->subs[x], x, 0);
2389}
2390
2391static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
2392
2393static int my_complete_conference_update(void *pvt, int needconference)
2394{
2395 struct dahdi_pvt *p = pvt;
2396 int needconf = needconference;
2397 int x;
2398 int useslavenative;
2399 struct dahdi_pvt *slave = NULL;
2400
2401 useslavenative = isslavenative(p, &slave);
2402
2403 /* If we have a slave, add him to our conference now. or DAX
2404 if this is slave native */
2405 for (x = 0; x < MAX_SLAVES; x++) {
2406 if (p->slaves[x]) {
2407 if (useslavenative)
2408 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
2409 else {
2410 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
2411 needconf++;
2412 }
2413 }
2414 }
2415 /* If we're supposed to be in there, do so now */
2416 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
2417 if (useslavenative)
2418 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
2419 else {
2420 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
2421 needconf++;
2422 }
2423 }
2424 /* If we have a master, add ourselves to his conference */
2425 if (p->master) {
2426 if (isslavenative(p->master, NULL)) {
2428 } else {
2429 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
2430 }
2431 }
2432 if (!needconf) {
2433 /* Nobody is left (or should be left) in our conference.
2434 Kill it. */
2435 p->confno = -1;
2436 }
2437
2438 return 0;
2439}
2440
2441static int check_for_conference(struct dahdi_pvt *p);
2442
2443static int my_check_for_conference(void *pvt)
2444{
2445 struct dahdi_pvt *p = pvt;
2446 return check_for_conference(p);
2447}
2448
2449static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
2450{
2451 struct dahdi_pvt *p = pvt;
2452 int da, db;
2453 int tchan;
2454 int tinthreeway;
2455
2458
2459 tchan = p->subs[da].chan;
2460 p->subs[da].chan = p->subs[db].chan;
2461 p->subs[db].chan = tchan;
2462
2463 tinthreeway = p->subs[da].inthreeway;
2464 p->subs[da].inthreeway = p->subs[db].inthreeway;
2465 p->subs[db].inthreeway = tinthreeway;
2466
2467 p->subs[da].owner = ast_a;
2468 p->subs[db].owner = ast_b;
2469
2470 if (ast_a)
2471 ast_channel_set_fd(ast_a, 0, p->subs[da].dfd);
2472 if (ast_b)
2473 ast_channel_set_fd(ast_b, 0, p->subs[db].dfd);
2474
2475 wakeup_sub(p, a);
2476 wakeup_sub(p, b);
2477
2478 return;
2479}
2480
2481/*!
2482 * \internal
2483 * \brief performs duties of dahdi_new, but also removes and possibly unbinds (if callid_created is 1) before returning
2484 * \note this variant of dahdi should only be used in conjunction with ast_callid_threadstorage_auto()
2485 *
2486 * \param callid_created value returned from ast_callid_threadstorage_auto()
2487 * \param i, state, startpbx, idx, law, assignedids, requestor, callid
2488 */
2489static 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);
2490
2491static 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);
2492
2493static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
2494{
2495 ast_callid callid = 0;
2496 int callid_created = ast_callid_threadstorage_auto(&callid);
2497 struct dahdi_pvt *p = pvt;
2498 int dsub = analogsub_to_dahdisub(sub);
2499
2500 return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, NULL, requestor, callid, callid_created);
2501}
2502
2503#if defined(HAVE_PRI) || defined(HAVE_SS7)
2504static int dahdi_setlaw(int dfd, int law)
2505{
2506 int res;
2507 res = ioctl(dfd, DAHDI_SETLAW, &law);
2508 if (res)
2509 return res;
2510 return 0;
2511}
2512#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2513
2514#if defined(HAVE_PRI)
2515static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state,
2516 enum sig_pri_law law, char *exten, const struct ast_assigned_ids *assignedids,
2517 const struct ast_channel *requestor)
2518{
2519 struct dahdi_pvt *p = pvt;
2520 int audio;
2521 int newlaw = -1;
2522 ast_callid callid = 0;
2523 int callid_created = ast_callid_threadstorage_auto(&callid);
2524
2525 switch (p->sig) {
2527 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
2528 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
2529 break;
2530 }
2531 /* Fall through */
2532 default:
2533 /* Set to audio mode at this point */
2534 audio = 1;
2535 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) {
2536 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
2537 p->channel, audio, strerror(errno));
2538 }
2539 break;
2540 }
2541
2542 if (law != SIG_PRI_DEFLAW) {
2543 dahdi_setlaw(p->subs[SUB_REAL].dfd, (law == SIG_PRI_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
2544 }
2545
2546 ast_copy_string(p->exten, exten, sizeof(p->exten));
2547
2548 switch (law) {
2549 case SIG_PRI_DEFLAW:
2550 newlaw = 0;
2551 break;
2552 case SIG_PRI_ALAW:
2553 newlaw = DAHDI_LAW_ALAW;
2554 break;
2555 case SIG_PRI_ULAW:
2556 newlaw = DAHDI_LAW_MULAW;
2557 break;
2558 }
2559
2560 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
2561}
2562#endif /* defined(HAVE_PRI) */
2563
2564static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law);
2565
2566#if defined(HAVE_PRI) || defined(HAVE_SS7)
2567/*!
2568 * \internal
2569 * \brief Open the PRI/SS7 channel media path.
2570 * \since 1.8
2571 *
2572 * \param p Channel private control structure.
2573 */
2574static void my_pri_ss7_open_media(void *p)
2575{
2576 struct dahdi_pvt *pvt = p;
2577 int res;
2578 int dfd;
2579 int set_val;
2580
2581 dfd = pvt->subs[SUB_REAL].dfd;
2582
2583 /* Open the media path. */
2584 set_val = 1;
2585 res = ioctl(dfd, DAHDI_AUDIOMODE, &set_val);
2586 if (res < 0) {
2587 ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n",
2588 pvt->channel, strerror(errno));
2589 }
2590
2591 /* Set correct companding law for this call. */
2592 res = dahdi_setlaw(dfd, pvt->law);
2593 if (res < 0) {
2594 ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pvt->channel);
2595 }
2596
2597 /* Set correct gain for this call. */
2598 if (pvt->digital) {
2599 res = set_actual_gain(dfd, 0, 0, pvt->rxdrc, pvt->txdrc, pvt->law);
2600 } else {
2601 res = set_actual_gain(dfd, pvt->rxgain, pvt->txgain, pvt->rxdrc, pvt->txdrc,
2602 pvt->law);
2603 }
2604 if (res < 0) {
2605 ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pvt->channel);
2606 }
2607
2608 if (pvt->dsp_features && pvt->dsp) {
2610 }
2611}
2612#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2613
2614#if defined(HAVE_PRI)
2615/*!
2616 * \internal
2617 * \brief Ask DAHDI to dial the given dial string.
2618 * \since 1.8.11
2619 *
2620 * \param p Channel private control structure.
2621 * \param dial_string String to pass to DAHDI to dial.
2622 *
2623 * \note The channel private lock needs to be held when calling.
2624 */
2625static void my_pri_dial_digits(void *p, const char *dial_string)
2626{
2627 char dial_str[DAHDI_MAX_DTMF_BUF];
2628 struct dahdi_pvt *pvt = p;
2629 int res;
2630
2631 snprintf(dial_str, sizeof(dial_str), "T%s", dial_string);
2632 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
2633 if (!res) {
2634 pvt->dialing = 1;
2635 }
2636}
2637#endif /* defined(HAVE_PRI) */
2638
2639static int unalloc_sub(struct dahdi_pvt *p, int x);
2640
2641static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
2642{
2643 struct dahdi_pvt *p = pvt;
2644
2645 return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
2646}
2647
2648static int alloc_sub(struct dahdi_pvt *p, int x);
2649
2650static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
2651{
2652 struct dahdi_pvt *p = pvt;
2653
2654 return alloc_sub(p, analogsub_to_dahdisub(analogsub));
2655}
2656
2657static int has_voicemail(struct dahdi_pvt *p);
2658
2659static int my_has_voicemail(void *pvt)
2660{
2661 struct dahdi_pvt *p = pvt;
2662
2663 return has_voicemail(p);
2664}
2665
2666static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
2667{
2668 struct dahdi_pvt *p = pvt;
2669 int index;
2670
2671 index = analogsub_to_dahdisub(sub);
2672
2673 return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
2674}
2675
2677{
2678 enum analog_event res;
2679
2680 switch (event) {
2681 case DAHDI_EVENT_ONHOOK:
2682 res = ANALOG_EVENT_ONHOOK;
2683 break;
2684 case DAHDI_EVENT_RINGOFFHOOK:
2686 break;
2687 case DAHDI_EVENT_WINKFLASH:
2689 break;
2690 case DAHDI_EVENT_ALARM:
2691 res = ANALOG_EVENT_ALARM;
2692 break;
2693 case DAHDI_EVENT_NOALARM:
2695 break;
2696 case DAHDI_EVENT_DIALCOMPLETE:
2698 break;
2699 case DAHDI_EVENT_RINGERON:
2701 break;
2702 case DAHDI_EVENT_RINGEROFF:
2704 break;
2705 case DAHDI_EVENT_HOOKCOMPLETE:
2707 break;
2708 case DAHDI_EVENT_PULSE_START:
2710 break;
2711 case DAHDI_EVENT_POLARITY:
2713 break;
2714 case DAHDI_EVENT_RINGBEGIN:
2716 break;
2717 case DAHDI_EVENT_EC_DISABLED:
2719 break;
2720 case DAHDI_EVENT_REMOVED:
2722 break;
2723 case DAHDI_EVENT_NEONMWI_ACTIVE:
2725 break;
2726 case DAHDI_EVENT_NEONMWI_INACTIVE:
2728 break;
2729#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
2730 case DAHDI_EVENT_TX_CED_DETECTED:
2732 break;
2733 case DAHDI_EVENT_RX_CED_DETECTED:
2735 break;
2736 case DAHDI_EVENT_EC_NLP_DISABLED:
2738 break;
2739 case DAHDI_EVENT_EC_NLP_ENABLED:
2741 break;
2742#endif
2743 case DAHDI_EVENT_PULSEDIGIT:
2745 break;
2746 case DAHDI_EVENT_DTMFDOWN:
2748 break;
2749 case DAHDI_EVENT_DTMFUP:
2750 res = ANALOG_EVENT_DTMFUP;
2751 break;
2752 default:
2753 switch(event & 0xFFFF0000) {
2754 case DAHDI_EVENT_PULSEDIGIT:
2755 case DAHDI_EVENT_DTMFDOWN:
2756 case DAHDI_EVENT_DTMFUP:
2757 /* The event includes a digit number in the low word.
2758 * Converting it to a 'enum analog_event' would remove
2759 * that information. Thus it is returned as-is.
2760 */
2761 return event;
2762 }
2763
2764 res = ANALOG_EVENT_ERROR;
2765 break;
2766 }
2767
2768 return res;
2769}
2770
2771static inline int dahdi_wait_event(int fd);
2772
2773static int my_wait_event(void *pvt)
2774{
2775 struct dahdi_pvt *p = pvt;
2776
2777 return dahdi_wait_event(p->subs[SUB_REAL].dfd);
2778}
2779
2780static int my_get_event(void *pvt)
2781{
2782 struct dahdi_pvt *p = pvt;
2783 int res;
2784
2785 if (p->fake_event) {
2786 res = p->fake_event;
2787 p->fake_event = 0;
2788 } else
2789 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
2790
2791 return dahdievent_to_analogevent(res);
2792}
2793
2794static int my_is_off_hook(void *pvt)
2795{
2796 struct dahdi_pvt *p = pvt;
2797 int res;
2798 struct dahdi_params par;
2799
2800 memset(&par, 0, sizeof(par));
2801
2802 if (p->subs[SUB_REAL].dfd > -1)
2803 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
2804 else {
2805 /* Assume not off hook on CVRS */
2806 res = 0;
2807 par.rxisoffhook = 0;
2808 }
2809 if (res) {
2810 ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
2811 }
2812
2813 if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
2814 /* When "onhook" that means no battery on the line, and thus
2815 it is out of service..., if it's on a TDM card... If it's a channel
2816 bank, there is no telling... */
2817 return (par.rxbits > -1) || par.rxisoffhook;
2818 }
2819
2820 return par.rxisoffhook;
2821}
2822
2823static int my_set_echocanceller(void *pvt, int enable)
2824{
2825 struct dahdi_pvt *p = pvt;
2826
2827 if (enable)
2828 dahdi_ec_enable(p);
2829 else
2831
2832 return 0;
2833}
2834
2835static int dahdi_ring_phone(struct dahdi_pvt *p);
2836
2837static int my_ring(void *pvt)
2838{
2839 struct dahdi_pvt *p = pvt;
2840
2841 return dahdi_ring_phone(p);
2842}
2843
2844static int my_flash(void *pvt)
2845{
2846 struct dahdi_pvt *p = pvt;
2847 int func = DAHDI_FLASH;
2848 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &func);
2849}
2850
2851static inline int dahdi_set_hook(int fd, int hs);
2852
2853static int my_off_hook(void *pvt)
2854{
2855 struct dahdi_pvt *p = pvt;
2856 return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
2857}
2858
2859static void my_set_needringing(void *pvt, int value)
2860{
2861 struct dahdi_pvt *p = pvt;
2863}
2864
2865static void my_set_polarity(void *pvt, int value)
2866{
2867 struct dahdi_pvt *p = pvt;
2868
2869 if (p->channel == CHAN_PSEUDO) {
2870 return;
2871 }
2872 p->polarity = value;
2873 ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETPOLARITY, &value);
2874}
2875
2876static void my_start_polarityswitch(void *pvt)
2877{
2878 struct dahdi_pvt *p = pvt;
2879
2881 my_set_polarity(pvt, 0);
2882 }
2883}
2884
2885static void my_answer_polarityswitch(void *pvt)
2886{
2887 struct dahdi_pvt *p = pvt;
2888
2889 if (!p->answeronpolarityswitch) {
2890 return;
2891 }
2892
2893 my_set_polarity(pvt, 1);
2894}
2895
2896static void my_hangup_polarityswitch(void *pvt)
2897{
2898 struct dahdi_pvt *p = pvt;
2899
2900 if (!p->hanguponpolarityswitch) {
2901 return;
2902 }
2903
2904 if (p->answeronpolarityswitch) {
2905 my_set_polarity(pvt, 0);
2906 } else {
2907 my_set_polarity(pvt, 1);
2908 }
2909}
2910
2911/*! \brief Return DAHDI pivot if channel is FXO signalled */
2912static struct dahdi_pvt *fxo_pvt(struct ast_channel *chan)
2913{
2914 int res;
2915 struct dahdi_params dahdip;
2916 struct dahdi_pvt *pvt = NULL;
2917
2918 if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
2919 ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
2920 return NULL;
2921 }
2922
2923 memset(&dahdip, 0, sizeof(dahdip));
2924 res = ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip);
2925
2926 if (res) {
2927 ast_log(LOG_WARNING, "Unable to get parameters of %s: %s\n", ast_channel_name(chan), strerror(errno));
2928 return NULL;
2929 }
2930 if (!(dahdip.sigtype & __DAHDI_SIG_FXO)) {
2931 ast_log(LOG_WARNING, "%s is not FXO signalled\n", ast_channel_name(chan));
2932 return NULL;
2933 }
2934
2935 pvt = ast_channel_tech_pvt(chan);
2936 if (!dahdi_analog_lib_handles(pvt->sig, 0, 0)) {
2937 ast_log(LOG_WARNING, "Channel signalling is not analog");
2938 return NULL;
2939 }
2940
2941 return pvt;
2942}
2943
2944static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
2945{
2946 struct dahdi_pvt *pvt;
2947
2948 pvt = fxo_pvt(chan);
2949 if (!pvt) {
2950 return -1;
2951 }
2952
2953 snprintf(buffer, buflen, "%d", pvt->polarity);
2954
2955 return 0;
2956}
2957
2958static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
2959{
2960 struct dahdi_pvt *pvt;
2961 int polarity;
2962
2963 pvt = fxo_pvt(chan);
2964 if (!pvt) {
2965 return -1;
2966 }
2967
2968 if (!strcasecmp(value, "idle")) {
2970 } else if (!strcasecmp(value, "reverse")) {
2972 } else {
2973 polarity = atoi(value);
2974 }
2975
2977 ast_log(LOG_WARNING, "Invalid polarity: '%s'\n", value);
2978 return -1;
2979 }
2980
2982 return 0;
2983}
2984
2986 .name = "POLARITY",
2987 .write = polarity_write,
2988 .read = polarity_read,
2989};
2990
2991static int my_start(void *pvt)
2992{
2993 struct dahdi_pvt *p = pvt;
2994 int x = DAHDI_START;
2995
2996 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
2997}
2998
2999static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
3000{
3001 struct dahdi_pvt *p = pvt;
3002
3003 if (dop->op != ANALOG_DIAL_OP_REPLACE) {
3004 ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
3005 return -1;
3006 }
3007
3008 if (sub != ANALOG_SUB_REAL) {
3009 ast_log(LOG_ERROR, "Trying to dial_digits '%s' on channel %d subchannel %u\n",
3010 dop->dialstr, p->channel, sub);
3011 return -1;
3012 }
3013
3014 return dahdi_dial_str(p, DAHDI_DIAL_OP_REPLACE, dop->dialstr);
3015}
3016
3017static void dahdi_train_ec(struct dahdi_pvt *p);
3018
3019static int my_train_echocanceller(void *pvt)
3020{
3021 struct dahdi_pvt *p = pvt;
3022
3023 dahdi_train_ec(p);
3024
3025 return 0;
3026}
3027
3028static int my_is_dialing(void *pvt, enum analog_sub sub)
3029{
3030 struct dahdi_pvt *p = pvt;
3031 int index;
3032 int x;
3033
3034 index = analogsub_to_dahdisub(sub);
3035
3036 if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
3037 ast_debug(1, "DAHDI_DIALING ioctl failed!\n");
3038 return -1;
3039 }
3040
3041 return x;
3042}
3043
3044static int my_on_hook(void *pvt)
3045{
3046 struct dahdi_pvt *p = pvt;
3047 return dahdi_set_hook(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_ONHOOK);
3048}
3049
3050#if defined(HAVE_PRI)
3051static void my_pri_fixup_chans(void *chan_old, void *chan_new)
3052{
3053 struct dahdi_pvt *old_chan = chan_old;
3054 struct dahdi_pvt *new_chan = chan_new;
3055
3056 new_chan->owner = old_chan->owner;
3057 old_chan->owner = NULL;
3058 if (new_chan->owner) {
3059 ast_channel_tech_pvt_set(new_chan->owner, new_chan);
3060 ast_channel_internal_fd_set(new_chan->owner, 0, new_chan->subs[SUB_REAL].dfd);
3061 new_chan->subs[SUB_REAL].owner = old_chan->subs[SUB_REAL].owner;
3062 old_chan->subs[SUB_REAL].owner = NULL;
3063 }
3064 /* Copy any DSP that may be present */
3065 new_chan->dsp = old_chan->dsp;
3066 new_chan->dsp_features = old_chan->dsp_features;
3067 old_chan->dsp = NULL;
3068 old_chan->dsp_features = 0;
3069
3070 /* Transfer flags from the old channel. */
3071 new_chan->dialing = old_chan->dialing;
3072 new_chan->digital = old_chan->digital;
3073 new_chan->outgoing = old_chan->outgoing;
3074 old_chan->dialing = 0;
3075 old_chan->digital = 0;
3076 old_chan->outgoing = 0;
3077
3078 /* More stuff to transfer to the new channel. */
3079 new_chan->law = old_chan->law;
3080 strcpy(new_chan->dialstring, old_chan->dialstring);
3081}
3082#endif /* defined(HAVE_PRI) */
3083
3084#if defined(HAVE_PRI)
3085static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
3086{
3087 switch (tone) {
3089 return DAHDI_TONE_RINGTONE;
3091 return DAHDI_TONE_STUTTER;
3093 return DAHDI_TONE_CONGESTION;
3095 return DAHDI_TONE_DIALTONE;
3097 return DAHDI_TONE_DIALRECALL;
3098 case SIG_PRI_TONE_INFO:
3099 return DAHDI_TONE_INFO;
3100 case SIG_PRI_TONE_BUSY:
3101 return DAHDI_TONE_BUSY;
3102 default:
3103 return -1;
3104 }
3105}
3106#endif /* defined(HAVE_PRI) */
3107
3108#if defined(HAVE_PRI)
3109static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
3110{
3111 int x;
3112
3113 ioctl(pri->fds[index], DAHDI_GETEVENT, &x);
3114 switch (x) {
3115 case DAHDI_EVENT_NONE:
3116 break;
3117 case DAHDI_EVENT_ALARM:
3118 case DAHDI_EVENT_NOALARM:
3119 if (sig_pri_is_alarm_ignored(pri)) {
3120 break;
3121 }
3122 /* Fall through */
3123 default:
3124 ast_log(LOG_NOTICE, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
3125 event2str(x), x, pri->span);
3126 break;
3127 }
3128 /* Keep track of alarm state */
3129 switch (x) {
3130 case DAHDI_EVENT_ALARM:
3131 pri_event_alarm(pri, index, 0);
3132 break;
3133 case DAHDI_EVENT_NOALARM:
3134 pri_event_noalarm(pri, index, 0);
3135 break;
3136 case DAHDI_EVENT_REMOVED:
3137 pri_queue_for_destruction(pri);
3138 break;
3139 default:
3140 break;
3141 }
3142}
3143#endif /* defined(HAVE_PRI) */
3144
3145#if defined(HAVE_PRI)
3146static int my_pri_play_tone(void *pvt, enum sig_pri_tone tone)
3147{
3148 struct dahdi_pvt *p = pvt;
3149
3150 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_pri_tone_to_dahditone(tone));
3151}
3152#endif /* defined(HAVE_PRI) */
3153
3154#if defined(HAVE_PRI) || defined(HAVE_SS7)
3155/*!
3156 * \internal
3157 * \brief Set the caller id information.
3158 * \since 1.8
3159 *
3160 * \param pvt DAHDI private structure
3161 * \param caller Caller-id information to set.
3162 */
3163static void my_set_callerid(void *pvt, const struct ast_party_caller *caller)
3164{
3165 struct dahdi_pvt *p = pvt;
3166
3168 S_COR(caller->id.number.valid, caller->id.number.str, ""),
3169 sizeof(p->cid_num));
3171 S_COR(caller->id.name.valid, caller->id.name.str, ""),
3172 sizeof(p->cid_name));
3174 S_COR(caller->id.subaddress.valid, caller->id.subaddress.str, ""),
3175 sizeof(p->cid_subaddr));
3176 p->cid_ton = caller->id.number.plan;
3178 if (caller->id.tag) {
3179 ast_copy_string(p->cid_tag, caller->id.tag, sizeof(p->cid_tag));
3180 }
3181 ast_copy_string(p->cid_ani,
3182 S_COR(caller->ani.number.valid, caller->ani.number.str, ""),
3183 sizeof(p->cid_ani));
3184 p->cid_ani2 = caller->ani2;
3185}
3186#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3187
3188#if defined(HAVE_PRI) || defined(HAVE_SS7)
3189/*!
3190 * \internal
3191 * \brief Set the Dialed Number Identifier.
3192 * \since 1.8
3193 *
3194 * \param pvt DAHDI private structure
3195 * \param dnid Dialed Number Identifier string.
3196 */
3197static void my_set_dnid(void *pvt, const char *dnid)
3198{
3199 struct dahdi_pvt *p = pvt;
3200
3201 ast_copy_string(p->dnid, dnid, sizeof(p->dnid));
3202}
3203#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3204
3205#if defined(HAVE_PRI)
3206/*!
3207 * \internal
3208 * \brief Set the Redirecting Directory Number Information Service (RDNIS).
3209 * \since 1.8
3210 *
3211 * \param pvt DAHDI private structure
3212 * \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
3213 */
3214static void my_set_rdnis(void *pvt, const char *rdnis)
3215{
3216 struct dahdi_pvt *p = pvt;
3217
3218 ast_copy_string(p->rdnis, rdnis, sizeof(p->rdnis));
3219}
3220#endif /* defined(HAVE_PRI) */
3221
3222#if defined(HAVE_PRI)
3223/*!
3224 * \internal
3225 * \brief Make a dialstring for native ISDN CC to recall properly.
3226 * \since 1.8
3227 *
3228 * \param priv Channel private control structure.
3229 * \param buf Where to put the modified dialstring.
3230 * \param buf_size Size of modified dialstring buffer.
3231 *
3232 * \details
3233 * original dialstring:
3234 * \verbatim
3235 DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3236 \endverbatim
3237 *
3238 * The modified dialstring will have prefixed the channel-group section
3239 * with the ISDN channel restriction.
3240 *
3241 * buf:
3242 * \verbatim
3243 DAHDI/i<span>-(g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3244 \endverbatim
3245 *
3246 * The routine will check to see if the ISDN channel restriction is already
3247 * in the original dialstring.
3248 */
3249static void my_pri_make_cc_dialstring(void *priv, char *buf, size_t buf_size)
3250{
3251 char *dial;
3252 struct dahdi_pvt *pvt;
3254 AST_APP_ARG(tech); /* channel technology token */
3255 AST_APP_ARG(group); /* channel/group token */
3256 //AST_APP_ARG(ext); /* extension token */
3257 //AST_APP_ARG(opts); /* options token */
3258 //AST_APP_ARG(other); /* Any remaining unused arguments */
3259 );
3260
3261 pvt = priv;
3262 dial = ast_strdupa(pvt->dialstring);
3263 AST_NONSTANDARD_APP_ARGS(args, dial, '/');
3264 if (!args.tech) {
3265 ast_copy_string(buf, pvt->dialstring, buf_size);
3266 return;
3267 }
3268 if (!args.group) {
3269 /* Append the ISDN span channel restriction to the dialstring. */
3270 snprintf(buf, buf_size, "%s/i%d-", args.tech, pvt->pri->span);
3271 return;
3272 }
3273 if (isdigit(args.group[0]) || args.group[0] == 'i' || strchr(args.group, '!')) {
3274 /* The ISDN span channel restriction is not needed or already
3275 * in the dialstring. */
3276 ast_copy_string(buf, pvt->dialstring, buf_size);
3277 return;
3278 }
3279 /* Insert the ISDN span channel restriction into the dialstring. */
3280 snprintf(buf, buf_size, "%s/i%d-%s", args.tech, pvt->pri->span, args.group);
3281}
3282#endif /* defined(HAVE_PRI) */
3283
3284#if defined(HAVE_PRI)
3285/*!
3286 * \internal
3287 * \brief Reevaluate the PRI span device state.
3288 * \since 1.8
3289 *
3290 * \param pri Asterisk D channel control structure.
3291 *
3292 * \note Assumes the pri->lock is already obtained.
3293 */
3294static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
3295{
3296 unsigned idx;
3297 unsigned num_b_chans; /* Number of B channels provisioned on the span. */
3298 unsigned in_use; /* Number of B channels in use on the span. */
3299 unsigned in_alarm; /* TRUE if the span is in alarm condition. */
3300 enum ast_device_state new_state;
3301
3302 /* Count the number of B channels and the number of B channels in use. */
3303 num_b_chans = 0;
3304 in_use = 0;
3305 in_alarm = 1;
3306 for (idx = pri->numchans; idx--;) {
3307 if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
3308 /* This is a B channel interface. */
3309 ++num_b_chans;
3310 if (!sig_pri_is_chan_available(pri->pvts[idx])) {
3311 ++in_use;
3312 }
3313 if (!pri->pvts[idx]->inalarm) {
3314 /* There is a channel that is not in alarm. */
3315 in_alarm = 0;
3316 }
3317 }
3318 }
3319
3320 /* Update the span congestion device state and report any change. */
3321 if (in_alarm) {
3322 new_state = AST_DEVICE_UNAVAILABLE;
3323 } else {
3324 new_state = num_b_chans == in_use ? AST_DEVICE_BUSY : AST_DEVICE_NOT_INUSE;
3325 }
3326 if (pri->congestion_devstate != new_state) {
3327 pri->congestion_devstate = new_state;
3329 }
3330#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
3331 /* Update the span threshold device state and report any change. */
3332 if (in_alarm) {
3333 new_state = AST_DEVICE_UNAVAILABLE;
3334 } else if (!in_use) {
3335 new_state = AST_DEVICE_NOT_INUSE;
3336 } else if (!pri->user_busy_threshold) {
3337 new_state = in_use < num_b_chans ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
3338 } else {
3339 new_state = in_use < pri->user_busy_threshold ? AST_DEVICE_INUSE
3341 }
3342 if (pri->threshold_devstate != new_state) {
3343 pri->threshold_devstate = new_state;
3345 }
3346#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
3347}
3348#endif /* defined(HAVE_PRI) */
3349
3350#if defined(HAVE_PRI)
3351/*!
3352 * \internal
3353 * \brief Reference this module.
3354 * \since 1.8
3355 */
3356static void my_module_ref(void)
3357{
3359}
3360#endif /* defined(HAVE_PRI) */
3361
3362#if defined(HAVE_PRI)
3363/*!
3364 * \internal
3365 * \brief Unreference this module.
3366 * \since 1.8
3367 */
3368static void my_module_unref(void)
3369{
3371}
3372#endif /* defined(HAVE_PRI) */
3373
3374#if defined(HAVE_PRI)
3375#if defined(HAVE_PRI_CALL_WAITING)
3376static void my_pri_init_config(void *priv, struct sig_pri_span *pri);
3377#endif /* defined(HAVE_PRI_CALL_WAITING) */
3378static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri);
3379
3381{
3382 .handle_dchan_exception = my_handle_dchan_exception,
3383 .play_tone = my_pri_play_tone,
3384 .set_echocanceller = my_set_echocanceller,
3385 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3386 .lock_private = my_lock_private,
3387 .unlock_private = my_unlock_private,
3388 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3389 .new_ast_channel = my_new_pri_ast_channel,
3390 .fixup_chans = my_pri_fixup_chans,
3391 .set_alarm = my_set_alarm,
3392 .set_dialing = my_set_dialing,
3393 .set_outgoing = my_set_outgoing,
3394 .set_digital = my_set_digital,
3395 .set_callerid = my_set_callerid,
3396 .set_dnid = my_set_dnid,
3397 .set_rdnis = my_set_rdnis,
3398 .new_nobch_intf = dahdi_new_pri_nobch_channel,
3399#if defined(HAVE_PRI_CALL_WAITING)
3400 .init_config = my_pri_init_config,
3401#endif /* defined(HAVE_PRI_CALL_WAITING) */
3402 .get_orig_dialstring = my_get_orig_dialstring,
3403 .make_cc_dialstring = my_pri_make_cc_dialstring,
3404 .update_span_devstate = dahdi_pri_update_span_devstate,
3405 .module_ref = my_module_ref,
3406 .module_unref = my_module_unref,
3407 .dial_digits = my_pri_dial_digits,
3408 .open_media = my_pri_ss7_open_media,
3409 .ami_channel_event = my_ami_channel_event,
3410 .destroy_later = pri_queue_for_destruction,
3411};
3412#endif /* defined(HAVE_PRI) */
3413
3414#if defined(HAVE_SS7)
3415/*!
3416 * \internal
3417 * \brief Handle the SS7 link exception.
3418 * \since 1.8
3419 *
3420 * \param linkset Controlling linkset for the channel.
3421 * \param which Link index of the signaling channel.
3422 */
3423static void my_handle_link_exception(struct sig_ss7_linkset *linkset, int which)
3424{
3425 int event;
3426
3427 if (ioctl(linkset->fds[which], DAHDI_GETEVENT, &event)) {
3428 ast_log(LOG_ERROR, "SS7: Error in exception retrieval on span %d/%d!\n",
3429 linkset->span, which);
3430 return;
3431 }
3432 switch (event) {
3433 case DAHDI_EVENT_NONE:
3434 break;
3435 case DAHDI_EVENT_ALARM:
3436 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3437 event2str(event), event, linkset->span, which);
3438 sig_ss7_link_alarm(linkset, which);
3439 break;
3440 case DAHDI_EVENT_NOALARM:
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_noalarm(linkset, which);
3444 break;
3445 default:
3446 ast_log(LOG_NOTICE, "SS7 got event: %s(%d) on span %d/%d\n",
3447 event2str(event), event, linkset->span, which);
3448 break;
3449 }
3450}
3451#endif /* defined(HAVE_SS7) */
3452
3453#if defined(HAVE_SS7)
3454static void my_ss7_set_loopback(void *pvt, int enable)
3455{
3456 struct dahdi_pvt *p = pvt;
3457
3458 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
3459 ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel,
3460 strerror(errno));
3461 }
3462}
3463#endif /* defined(HAVE_SS7) */
3464
3465#if defined(HAVE_SS7)
3466/*!
3467 * \internal
3468 * \brief Find the linkset to which SS7 belongs.
3469 * \since 11.0
3470 *
3471 * \param ss7 structure to match on.
3472 *
3473 * \retval linkset if found.
3474 * \retval NULL if not found.
3475 */
3476static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
3477{
3478 int idx;
3479
3480 if (!ss7) {
3481 return NULL;
3482 }
3483
3484 for (idx = 0; idx < NUM_SPANS; ++idx) {
3485 if (linksets[idx].ss7.ss7 == ss7) {
3486 return &linksets[idx].ss7;
3487 }
3488 }
3489 return NULL;
3490}
3491#endif /* defined(HAVE_SS7) */
3492
3493#if defined(HAVE_SS7)
3494/*!
3495 * \internal
3496 * \brief Create a new asterisk channel structure for SS7.
3497 * \since 1.8
3498 *
3499 * \param pvt Private channel structure.
3500 * \param state Initial state of new channel.
3501 * \param law Companding law to use.
3502 * \param exten Dialplan extension for incoming call.
3503 * \param requestor Channel requesting this new channel.
3504 * \param assignedids
3505 *
3506 * \retval ast_channel on success.
3507 * \retval NULL on error.
3508 */
3509static 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)
3510{
3511 struct dahdi_pvt *p = pvt;
3512 int audio;
3513 int newlaw;
3514 ast_callid callid = 0;
3515 int callid_created = ast_callid_threadstorage_auto(&callid);
3516
3517 /* Set to audio mode at this point */
3518 audio = 1;
3519 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1)
3520 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
3521 p->channel, audio, strerror(errno));
3522
3523 if (law != SIG_SS7_DEFLAW) {
3524 dahdi_setlaw(p->subs[SUB_REAL].dfd,
3525 (law == SIG_SS7_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
3526 }
3527
3528 ast_copy_string(p->exten, exten, sizeof(p->exten));
3529
3530 newlaw = -1;
3531 switch (law) {
3532 case SIG_SS7_DEFLAW:
3533 newlaw = 0;
3534 break;
3535 case SIG_SS7_ALAW:
3536 newlaw = DAHDI_LAW_ALAW;
3537 break;
3538 case SIG_SS7_ULAW:
3539 newlaw = DAHDI_LAW_MULAW;
3540 break;
3541 }
3542 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
3543}
3544#endif /* defined(HAVE_SS7) */
3545
3546#if defined(HAVE_SS7)
3547static int sig_ss7_tone_to_dahditone(enum sig_ss7_tone tone)
3548{
3549 switch (tone) {
3551 return DAHDI_TONE_RINGTONE;
3553 return DAHDI_TONE_STUTTER;
3555 return DAHDI_TONE_CONGESTION;
3557 return DAHDI_TONE_DIALTONE;
3559 return DAHDI_TONE_DIALRECALL;
3560 case SIG_SS7_TONE_INFO:
3561 return DAHDI_TONE_INFO;
3562 case SIG_SS7_TONE_BUSY:
3563 return DAHDI_TONE_BUSY;
3564 default:
3565 return -1;
3566 }
3567}
3568#endif /* defined(HAVE_SS7) */
3569
3570#if defined(HAVE_SS7)
3571static int my_ss7_play_tone(void *pvt, enum sig_ss7_tone tone)
3572{
3573 struct dahdi_pvt *p = pvt;
3574
3575 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_ss7_tone_to_dahditone(tone));
3576}
3577#endif /* defined(HAVE_SS7) */
3578
3579#if defined(HAVE_SS7)
3581{
3583 .unlock_private = my_unlock_private,
3584 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3585
3586 .set_echocanceller = my_set_echocanceller,
3587 .set_loopback = my_ss7_set_loopback,
3588
3589 .new_ast_channel = my_new_ss7_ast_channel,
3590 .play_tone = my_ss7_play_tone,
3591
3592 .handle_link_exception = my_handle_link_exception,
3593 .set_alarm = my_set_alarm,
3594 .set_dialing = my_set_dialing,
3595 .set_outgoing = my_set_outgoing,
3596 .set_digital = my_set_digital,
3597 .set_inservice = my_set_inservice,
3598 .set_locallyblocked = my_set_locallyblocked,
3599 .set_remotelyblocked = my_set_remotelyblocked,
3600 .set_callerid = my_set_callerid,
3601 .set_dnid = my_set_dnid,
3602 .open_media = my_pri_ss7_open_media,
3603 .find_linkset = my_ss7_find_linkset,
3604};
3605#endif /* defined(HAVE_SS7) */
3606
3607/*!
3608 * \brief Send MWI state change
3609 *
3610 * \param mailbox This is the mailbox associated with the FXO line that the
3611 * MWI state has changed on.
3612 * \param thereornot This argument should simply be set to 1 or 0, to indicate
3613 * whether there are messages waiting or not.
3614 *
3615 * This function does two things:
3616 *
3617 * 1) It generates an internal Asterisk event notifying any other module that
3618 * cares about MWI that the state of a mailbox has changed.
3619 *
3620 * 2) It runs the script specified by the mwimonitornotify option to allow
3621 * some custom handling of the state change.
3622 */
3623static void notify_message(char *mailbox, int thereornot)
3624{
3625 char s[sizeof(mwimonitornotify) + 164];
3626
3627 if (ast_strlen_zero(mailbox)) {
3628 return;
3629 }
3630
3631 ast_publish_mwi_state(mailbox, NULL, thereornot, thereornot);
3633 snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
3634 ast_safe_system(s);
3635 }
3636}
3637
3638static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
3639{
3640 struct dahdi_pvt *p = pvt;
3641
3642 if (neon_mwievent > -1 && !p->mwimonitor_neon)
3643 return;
3644
3645 if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
3646 ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
3647 notify_message(p->mailbox, 1);
3648 } else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
3649 ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
3650 notify_message(p->mailbox, 0);
3651 }
3652 /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
3653 /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
3654 if (neon_mwievent == -1 && p->mwimonitor_rpas) {
3655 ast_hangup(chan);
3656 return;
3657 }
3658}
3659
3660static int my_have_progressdetect(void *pvt)
3661{
3662 struct dahdi_pvt *p = pvt;
3663
3665 && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
3666 return 1;
3667 } else {
3668 /* Don't have progress detection. */
3669 return 0;
3670 }
3671}
3672
3673#define gen_pvt_field_callback(type, field) \
3674 static type my_get_##field(void *pvt) \
3675 { \
3676 struct dahdi_pvt *p = pvt; \
3677 return p->field; \
3678 }
3679
3683
3684#undef gen_pvt_field_callback
3685
3687{
3689 .get_event = my_get_event,
3690 .wait_event = my_wait_event,
3691 .is_off_hook = my_is_off_hook,
3692 .set_echocanceller = my_set_echocanceller,
3693 .ring = my_ring,
3694 .flash = my_flash,
3695 .off_hook = my_off_hook,
3696 .dial_digits = my_dial_digits,
3697 .train_echocanceller = my_train_echocanceller,
3698 .on_hook = my_on_hook,
3699 .is_dialing = my_is_dialing,
3700 .allocate_sub = my_allocate_sub,
3701 .unallocate_sub = my_unallocate_sub,
3702 .swap_subs = my_swap_subchannels,
3703 .has_voicemail = my_has_voicemail,
3704 .check_for_conference = my_check_for_conference,
3705 .conf_add = my_conf_add,
3706 .conf_del = my_conf_del,
3707 .complete_conference_update = my_complete_conference_update,
3708 .start = my_start,
3709 .all_subchannels_hungup = my_all_subchannels_hungup,
3710 .lock_private = my_lock_private,
3711 .unlock_private = my_unlock_private,
3712 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3713 .handle_dtmf = my_handle_dtmf,
3714 .wink = my_wink,
3715 .new_ast_channel = my_new_analog_ast_channel,
3716 .dsp_set_digitmode = my_dsp_set_digitmode,
3717 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3718 .send_callerid = my_send_callerid,
3719 .callwait = my_callwait,
3720 .stop_callwait = my_stop_callwait,
3721 .get_callerid = my_get_callerid,
3722 .start_cid_detect = my_start_cid_detect,
3723 .stop_cid_detect = my_stop_cid_detect,
3724 .handle_notify_message = my_handle_notify_message,
3725 .increase_ss_count = my_increase_ss_count,
3726 .decrease_ss_count = my_decrease_ss_count,
3727 .distinctive_ring = my_distinctive_ring,
3728 .set_linear_mode = my_set_linear_mode,
3729 .set_inthreeway = my_set_inthreeway,
3730 .get_and_handle_alarms = my_get_and_handle_alarms,
3731 .get_sigpvt_bridged_channel = my_get_sigpvt_bridged_channel,
3732 .get_sub_fd = my_get_sub_fd,
3733 .set_cadence = my_set_cadence,
3734 .set_alarm = my_set_alarm,
3735 .set_dialing = my_set_dialing,
3736 .set_outgoing = my_set_outgoing,
3737 .set_ringtimeout = my_set_ringtimeout,
3738 .set_waitingfordt = my_set_waitingfordt,
3739 .check_waitingfordt = my_check_waitingfordt,
3740 .set_confirmanswer = my_set_confirmanswer,
3741 .check_confirmanswer = my_check_confirmanswer,
3742 .set_callwaiting = my_set_callwaiting,
3743 .cancel_cidspill = my_cancel_cidspill,
3744 .confmute = my_confmute,
3745 .set_pulsedial = my_set_pulsedial,
3746 .set_new_owner = my_set_new_owner,
3747 .get_orig_dialstring = my_get_orig_dialstring,
3748 .set_needringing = my_set_needringing,
3749 .set_polarity = my_set_polarity,
3750 .start_polarityswitch = my_start_polarityswitch,
3751 .answer_polarityswitch = my_answer_polarityswitch,
3752 .hangup_polarityswitch = my_hangup_polarityswitch,
3753 .have_progressdetect = my_have_progressdetect,
3754 .get_firstdigit_timeout = my_get_firstdigit_timeout,
3755 .get_matchdigit_timeout = my_get_matchdigit_timeout,
3756 .get_interdigit_timeout = my_get_interdigit_timeout,
3757};
3758
3759/*! Round robin search locations. */
3760static struct dahdi_pvt *round_robin[64]; /* groups can range from 0-63 */
3761
3762int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
3763{
3764 int res;
3765 if (p->subs[SUB_REAL].owner == ast)
3766 res = 0;
3767 else if (p->subs[SUB_CALLWAIT].owner == ast)
3768 res = 1;
3769 else if (p->subs[SUB_THREEWAY].owner == ast)
3770 res = 2;
3771 else {
3772 res = -1;
3773 if (!nullok)
3775 "Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
3776 ast ? ast_channel_name(ast) : "", p->channel, fname, line);
3777 }
3778 return res;
3779}
3780
3781/*!
3782 * \internal
3783 * \brief Obtain the specified subchannel owner lock if the owner exists.
3784 *
3785 * \param pvt Channel private struct.
3786 * \param sub_idx Subchannel owner to lock.
3787 *
3788 * \note Assumes the pvt->lock is already obtained.
3789 *
3790 * \note
3791 * Because deadlock avoidance may have been necessary, you need to confirm
3792 * the state of things before continuing.
3793 */
3794static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
3795{
3796 for (;;) {
3797 if (!pvt->subs[sub_idx].owner) {
3798 /* No subchannel owner pointer */
3799 break;
3800 }
3801 if (!ast_channel_trylock(pvt->subs[sub_idx].owner)) {
3802 /* Got subchannel owner lock */
3803 break;
3804 }
3805 /* We must unlock the private to avoid the possibility of a deadlock */
3806 DEADLOCK_AVOIDANCE(&pvt->lock);
3807 }
3808}
3809
3810static void wakeup_sub(struct dahdi_pvt *p, int a)
3811{
3813 if (p->subs[a].owner) {
3816 }
3817}
3818
3819static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
3820{
3821 for (;;) {
3822 if (p->owner) {
3823 if (ast_channel_trylock(p->owner)) {
3825 } else {
3826 ast_queue_frame(p->owner, f);
3828 break;
3829 }
3830 } else
3831 break;
3832 }
3833}
3834
3836{
3837 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3838 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
3839 if (!dahdi_chan) {
3840 return;
3841 }
3842
3843 ast_str_set(&dahdi_chan, 0, "%d", channel);
3844 ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
3845 body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
3846 if (!body) {
3847 return;
3848 }
3849
3850 ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
3851}
3852
3854{
3855 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3856
3857 ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
3858 body = ast_json_pack("{s: i}", "Span", span);
3859 if (!body) {
3860 return;
3861 }
3862
3863 ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
3864}
3865
3866static void handle_clear_alarms(struct dahdi_pvt *p)
3867{
3868#if defined(HAVE_PRI)
3870 return;
3871 }
3872#endif /* defined(HAVE_PRI) */
3873
3876 }
3879 }
3880}
3881
3882#ifdef HAVE_OPENR2
3883static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
3884{
3885 const struct dahdi_mfcr2 *r2link = p->mfcr2;
3886 struct r2link_entry *cur;
3887 AST_LIST_LOCK(&r2links);
3888 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
3889 if (r2link == &cur->mfcr2) {
3890 ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
3891 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
3892 break;
3893 }
3894 }
3896 AST_LIST_UNLOCK(&r2links);
3897}
3898
3899static int dahdi_r2_answer(struct dahdi_pvt *p)
3900{
3901 int res = 0;
3902 /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
3903 * and does not has support for openr2_chan_answer_call_with_mode
3904 * */
3905#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
3906 const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
3907 int wants_double_answer = ast_true(double_answer) ? 1 : 0;
3908 if (!double_answer) {
3909 /* this still can result in double answer if the channel context
3910 * was configured that way */
3911 res = openr2_chan_answer_call(p->r2chan);
3912 } else if (wants_double_answer) {
3913 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
3914 } else {
3915 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
3916 }
3917#else
3918 res = openr2_chan_answer_call(p->r2chan);
3919#endif
3920 return res;
3921}
3922
3923
3924
3925/* should be called with the ast_channel locked */
3926static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
3927{
3928 openr2_calling_party_category_t cat;
3929 const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
3930 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
3931 if (ast_strlen_zero(catstr)) {
3932 ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
3933 ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3934 return p->mfcr2_category;
3935 }
3936 if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
3937 ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
3938 catstr, ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3939 return p->mfcr2_category;
3940 }
3941 ast_debug(1, "Using category %s\n", catstr);
3942 return cat;
3943}
3944
3945static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
3946{
3947 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3948 ast_mutex_lock(&p->lock);
3949 if (p->mfcr2call) {
3951 /* TODO: This can happen when some other thread just finished dahdi_request requesting this very same
3952 interface but has not yet seized the line (dahdi_call), and the far end wins and seize the line,
3953 can we avoid this somehow?, at this point when dahdi_call send the seize, it is likely that since
3954 the other end will see our seize as a forced release and drop the call, we will see an invalid
3955 pattern that will be seen and treated as protocol error. */
3956 ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
3957 return;
3958 }
3959 p->mfcr2call = 1;
3960 /* better safe than sorry ... */
3961 p->cid_name[0] = '\0';
3962 p->cid_num[0] = '\0';
3963 p->cid_subaddr[0] = '\0';
3964 p->rdnis[0] = '\0';
3965 p->exten[0] = '\0';
3966 p->mfcr2_ani_index = '\0';
3967 p->mfcr2_dnis_index = '\0';
3968 p->mfcr2_dnis_matched = 0;
3969 p->mfcr2_answer_pending = 0;
3970 p->mfcr2_call_accepted = 0;
3972 ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
3973}
3974
3975static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
3976{
3977 int res;
3978 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3979 ast_mutex_lock(&p->lock);
3980 p->inalarm = alarm ? 1 : 0;
3981 if (p->inalarm) {
3982 res = get_alarms(p);
3983 if (res == DAHDI_ALARM_NOTOPEN) {
3984 mfcr2_queue_for_destruction(p);
3985 }
3986 handle_alarms(p, res);
3987 } else {
3989 }
3991}
3992
3993static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
3994{
3995 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3996
3997 ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
3998 ast_mutex_lock(&p->lock);
3999 /* Disconnected? */
4000 if (errorcode == ENODEV) {
4001 struct dahdi_mfcr2 *r2link = p->mfcr2;
4002 p->mfcr2call = 0;
4003 if (r2link) {
4004 r2link->nodev = 1;
4005 }
4006 }
4008}
4009
4010static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
4011{
4012 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4013 ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
4014 if (p->owner) {
4017 }
4018 ast_mutex_lock(&p->lock);
4019 p->mfcr2call = 0;
4021}
4022
4023static void dahdi_r2_disconnect_call(struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
4024{
4025 if (openr2_chan_disconnect_call(p->r2chan, cause)) {
4026 ast_log(LOG_NOTICE, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
4027 p->channel, openr2_proto_get_disconnect_string(cause));
4028 /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
4029 openr2_chan_set_idle(p->r2chan);
4030 ast_mutex_lock(&p->lock);
4031 p->mfcr2call = 0;
4033 }
4034}
4035
4036static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
4037{
4038 struct dahdi_pvt *p;
4039 struct ast_channel *c;
4040 ast_callid callid = 0;
4041 int callid_created = ast_callid_threadstorage_auto(&callid);
4042 ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
4043 openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
4044 openr2_proto_get_category_string(category));
4045 p = openr2_chan_get_client_data(r2chan);
4046 /* if collect calls are not allowed and this is a collect call, reject it! */
4047 if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
4048 ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call\n");
4049 dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
4050 goto dahdi_r2_on_call_offered_cleanup;
4051 }
4052 ast_mutex_lock(&p->lock);
4053 p->mfcr2_recvd_category = category;
4054 /* if we're not supposed to use CID, clear whatever we have */
4055 if (!p->use_callerid) {
4056 ast_debug(1, "No CID allowed in configuration, CID is being cleared!\n");
4057 p->cid_num[0] = 0;
4058 p->cid_name[0] = 0;
4059 }
4060 /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
4061 if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
4062 ast_debug(1, "Setting exten => s because of immediate or 0 DNIS configured\n");
4063 p->exten[0] = 's';
4064 p->exten[1] = 0;
4065 }
4067 if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
4068 ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
4069 p->channel, p->exten, p->context);
4070 dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
4071 goto dahdi_r2_on_call_offered_cleanup;
4072 }
4073 if (!p->mfcr2_accept_on_offer) {
4074 /* The user wants us to start the PBX thread right away without accepting the call first */
4075 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4076 if (c) {
4077 /* Done here, don't disable reading now since we still need to generate MF tones to accept
4078 the call or reject it and detect the tone off condition of the other end, all of this
4079 will be done in the PBX thread now */
4080 goto dahdi_r2_on_call_offered_cleanup;
4081 }
4082 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4083 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4084 } else if (p->mfcr2_charge_calls) {
4085 ast_debug(1, "Accepting MFC/R2 call with charge on chan %d\n", p->channel);
4086 openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
4087 } else {
4088 ast_debug(1, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
4089 openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
4090 }
4091
4092dahdi_r2_on_call_offered_cleanup:
4094}
4095
4096static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
4097{
4098 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4099 ast_verbose("MFC/R2 call end on channel %d\n", p->channel);
4100 ast_mutex_lock(&p->lock);
4101 p->mfcr2call = 0;
4103}
4104
4105static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
4106{
4107 struct dahdi_pvt *p = NULL;
4108 struct ast_channel *c = NULL;
4109 ast_callid callid = 0;
4110 int callid_created = ast_callid_threadstorage_auto(&callid);
4111 p = openr2_chan_get_client_data(r2chan);
4112 dahdi_ec_enable(p);
4113 p->mfcr2_call_accepted = 1;
4114 /* if it's an incoming call ... */
4115 if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
4116 ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
4117 /* If accept on offer is not set, it means at this point the PBX thread is already
4118 launched (was launched in the 'on call offered' handler) and therefore this callback
4119 is being executed already in the PBX thread rather than the monitor thread, don't launch
4120 any other thread, just disable the openr2 reading and answer the call if needed */
4121 if (!p->mfcr2_accept_on_offer) {
4122 openr2_chan_disable_read(r2chan);
4123 if (p->mfcr2_answer_pending) {
4124 ast_debug(1, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
4125 dahdi_r2_answer(p);
4126 }
4127 goto dahdi_r2_on_call_accepted_cleanup;
4128 }
4129 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4130 if (c) {
4131 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
4132 library to forget about it */
4133 openr2_chan_disable_read(r2chan);
4134 goto dahdi_r2_on_call_accepted_cleanup;
4135 }
4136 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4137 /* failed to create the channel, bail out and report it as an out of order line */
4138 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4139 goto dahdi_r2_on_call_accepted_cleanup;
4140 }
4141 /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
4142 ast_verbose("MFC/R2 call has been accepted on forward channel %d\n", p->channel);
4143 p->subs[SUB_REAL].needringing = 1;
4144 p->dialing = 0;
4145 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the library to forget about it */
4146 openr2_chan_disable_read(r2chan);
4147
4148dahdi_r2_on_call_accepted_cleanup:
4150}
4151
4152static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
4153{
4154 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4155 ast_verbose("MFC/R2 call has been answered on channel %d\n", openr2_chan_get_number(r2chan));
4156 p->subs[SUB_REAL].needanswer = 1;
4157}
4158
4159static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
4160{
4161 /*ast_debug(1, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
4162}
4163
4164static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
4165{
4166 switch (cause) {
4167 case OR2_CAUSE_BUSY_NUMBER:
4168 return AST_CAUSE_BUSY;
4169 case OR2_CAUSE_NETWORK_CONGESTION:
4170 return AST_CAUSE_CONGESTION;
4171 case OR2_CAUSE_OUT_OF_ORDER:
4173 case OR2_CAUSE_UNALLOCATED_NUMBER:
4175 case OR2_CAUSE_NO_ANSWER:
4176 return AST_CAUSE_NO_ANSWER;
4177 case OR2_CAUSE_NORMAL_CLEARING:
4179 case OR2_CAUSE_UNSPECIFIED:
4180 default:
4181 return AST_CAUSE_NOTDEFINED;
4182 }
4183}
4184
4185static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
4186{
4187 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4188 char cause_str[50];
4189 struct ast_control_pvt_cause_code *cause_code;
4190 int datalen = sizeof(*cause_code);
4191
4192 ast_verbose("MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan));
4193 ast_mutex_lock(&p->lock);
4194 if (!p->owner) {
4196 /* no owner, therefore we can't use dahdi_hangup to disconnect, do it right now */
4197 dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
4198 return;
4199 }
4200
4201 snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
4202 datalen += strlen(cause_str);
4203 cause_code = ast_alloca(datalen);
4204 memset(cause_code, 0, datalen);
4205 cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
4207 ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
4209 ast_channel_hangupcause_hash_set(p->owner, cause_code, datalen);
4211
4212 /* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
4213 be done in dahdi_hangup */
4217 } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
4218 /* being the forward side we must report what happened to the call to whoever requested it */
4219 switch (cause) {
4220 case OR2_CAUSE_BUSY_NUMBER:
4221 p->subs[SUB_REAL].needbusy = 1;
4222 break;
4223 case OR2_CAUSE_NETWORK_CONGESTION:
4224 case OR2_CAUSE_OUT_OF_ORDER:
4225 case OR2_CAUSE_UNALLOCATED_NUMBER:
4226 case OR2_CAUSE_NO_ANSWER:
4227 case OR2_CAUSE_UNSPECIFIED:
4228 case OR2_CAUSE_NORMAL_CLEARING:
4230 break;
4231 default:
4233 }
4235 } else {
4237 /* being the backward side and not UP yet, we only need to request hangup */
4238 /* TODO: what about doing this same thing when were AST_STATE_UP? */
4239 ast_queue_hangup_with_cause(p->owner, dahdi_r2_cause_to_ast_cause(cause));
4240 }
4241}
4242
4243static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
4244{
4245 switch (level) {
4246 case OR2_LOG_NOTICE:
4247 ast_verbose("%s", logmessage);
4248 break;
4249 case OR2_LOG_WARNING:
4250 ast_log(LOG_WARNING, "%s", logmessage);
4251 break;
4252 case OR2_LOG_ERROR:
4253 ast_log(LOG_ERROR, "%s", logmessage);
4254 break;
4255 case OR2_LOG_STACK_TRACE:
4256 case OR2_LOG_MF_TRACE:
4257 case OR2_LOG_CAS_TRACE:
4258 case OR2_LOG_DEBUG:
4259 case OR2_LOG_EX_DEBUG:
4260 ast_debug(1, "%s", logmessage);
4261 break;
4262 default:
4263 ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
4264 ast_debug(1, "%s", logmessage);
4265 break;
4266 }
4267}
4268
4269static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
4270{
4271 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4272 ast_mutex_lock(&p->lock);
4273 p->remotelyblocked = 1;
4275 ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
4276}
4277
4278static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
4279{
4280 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4281 ast_mutex_lock(&p->lock);
4282 p->remotelyblocked = 0;
4284 ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
4285}
4286
4287static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4288 __attribute__((format (printf, 3, 0)));
4289static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4290{
4291#define CONTEXT_TAG "Context - "
4292 char logmsg[256];
4293 char completemsg[sizeof(logmsg) * 2];
4294 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4295 snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
4296 dahdi_r2_write_log(level, completemsg);
4297#undef CONTEXT_TAG
4298}
4299
4300static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4301 __attribute__((format (printf, 3, 0)));
4302static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4303{
4304#define CHAN_TAG "Chan "
4305 char logmsg[256];
4306 char completemsg[sizeof(logmsg) * 2];
4307 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4308 snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
4309 dahdi_r2_write_log(level, completemsg);
4310#undef CHAN_TAG
4311}
4312
4313static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
4314{
4315 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4316 /* if 'immediate' is set, let's stop requesting DNIS */
4317 if (p->immediate) {
4318 return 0;
4319 }
4320 p->exten[p->mfcr2_dnis_index] = digit;
4321 p->rdnis[p->mfcr2_dnis_index] = digit;
4322 p->mfcr2_dnis_index++;
4323 p->exten[p->mfcr2_dnis_index] = 0;
4324 p->rdnis[p->mfcr2_dnis_index] = 0;
4325 /* if the DNIS is a match and cannot match more, stop requesting DNIS */
4326 if ((p->mfcr2_dnis_matched ||
4327 (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
4329 return 0;
4330 }
4331 /* otherwise keep going */
4332 return 1;
4333}
4334
4335static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
4336{
4337 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4338 p->cid_num[p->mfcr2_ani_index] = digit;
4339 p->cid_name[p->mfcr2_ani_index] = digit;
4340 p->mfcr2_ani_index++;
4341 p->cid_num[p->mfcr2_ani_index] = 0;
4342 p->cid_name[p->mfcr2_ani_index] = 0;
4343}
4344
4345static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
4346{
4347 ast_verbose("MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
4348}
4349
4350static openr2_event_interface_t dahdi_r2_event_iface = {
4351 .on_call_init = dahdi_r2_on_call_init,
4352 .on_call_offered = dahdi_r2_on_call_offered,
4353 .on_call_accepted = dahdi_r2_on_call_accepted,
4354 .on_call_answered = dahdi_r2_on_call_answered,
4355 .on_call_disconnect = dahdi_r2_on_call_disconnect,
4356 .on_call_end = dahdi_r2_on_call_end,
4357 .on_call_read = dahdi_r2_on_call_read,
4358 .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
4359 .on_os_error = dahdi_r2_on_os_error,
4360 .on_protocol_error = dahdi_r2_on_protocol_error,
4361 .on_line_blocked = dahdi_r2_on_line_blocked,
4362 .on_line_idle = dahdi_r2_on_line_idle,
4363 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
4364 .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
4365 .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
4366 .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
4367 /* so far we do nothing with billing pulses */
4368 .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
4369};
4370
4371static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
4372{
4373 return AST_ALAW(sample);
4374}
4375
4376static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
4377{
4378 return AST_LIN2A(sample);
4379}
4380
4381static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
4382 dahdi_r2_alaw_to_linear,
4383 dahdi_r2_linear_to_alaw
4384};
4385
4386#endif /* HAVE_OPENR2 */
4387
4388static void swap_subs(struct dahdi_pvt *p, int a, int b)
4389{
4390 int tchan;
4391 int tinthreeway;
4392 struct ast_channel *towner;
4393
4394 ast_debug(1, "Swapping %d and %d\n", a, b);
4395
4396 tchan = p->subs[a].chan;
4397 towner = p->subs[a].owner;
4398 tinthreeway = p->subs[a].inthreeway;
4399
4400 p->subs[a].chan = p->subs[b].chan;
4401 p->subs[a].owner = p->subs[b].owner;
4402 p->subs[a].inthreeway = p->subs[b].inthreeway;
4403
4404 p->subs[b].chan = tchan;
4405 p->subs[b].owner = towner;
4406 p->subs[b].inthreeway = tinthreeway;
4407
4408 if (p->subs[a].owner)
4409 ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
4410 if (p->subs[b].owner)
4411 ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
4412 wakeup_sub(p, a);
4413 wakeup_sub(p, b);
4414}
4415
4416static int dahdi_open(char *fn)
4417{
4418 int fd;
4419 int isnum;
4420 int chan = 0;
4421 int bs;
4422 int x;
4423 isnum = 1;
4424 for (x = 0; x < strlen(fn); x++) {
4425 if (!isdigit(fn[x])) {
4426 isnum = 0;
4427 break;
4428 }
4429 }
4430 if (isnum) {
4431 chan = atoi(fn);
4432 if (chan < 1) {
4433 ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
4434 return -1;
4435 }
4436 fn = "/dev/dahdi/channel";
4437 }
4438 fd = open(fn, O_RDWR | O_NONBLOCK);
4439 if (fd < 0) {
4440 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
4441 return -1;
4442 }
4443 if (chan) {
4444 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
4445 x = errno;
4446 close(fd);
4447 errno = x;
4448 ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
4449 return -1;
4450 }
4451 }
4452 bs = READ_SIZE;
4453 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
4454 ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs, strerror(errno));
4455 x = errno;
4456 close(fd);
4457 errno = x;
4458 return -1;
4459 }
4460 return fd;
4461}
4462
4463static void dahdi_close(int fd)
4464{
4465 if (fd > 0)
4466 close(fd);
4467}
4468
4469static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
4470{
4471 dahdi_close(chan_pvt->subs[sub_num].dfd);
4472 chan_pvt->subs[sub_num].dfd = -1;
4473}
4474
4475#if defined(HAVE_PRI)
4476static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
4477{
4478 dahdi_close(pri->pri.fds[fd_num]);
4479 pri->pri.fds[fd_num] = -1;
4480}
4481#endif /* defined(HAVE_PRI) */
4482
4483#if defined(HAVE_SS7)
4484static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
4485{
4486 dahdi_close(ss7->ss7.fds[fd_num]);
4487 ss7->ss7.fds[fd_num] = -1;
4488}
4489#endif /* defined(HAVE_SS7) */
4490
4491static int dahdi_setlinear(int dfd, int linear)
4492{
4493 return ioctl(dfd, DAHDI_SETLINEAR, &linear);
4494}
4495
4496
4497static int alloc_sub(struct dahdi_pvt *p, int x)
4498{
4499 struct dahdi_bufferinfo bi;
4500 int res;
4501 if (p->subs[x].dfd >= 0) {
4502 ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
4503 return -1;
4504 }
4505
4506 p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
4507 if (p->subs[x].dfd <= -1) {
4508 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
4509 return -1;
4510 }
4511
4512 res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
4513 if (!res) {
4514 bi.txbufpolicy = p->buf_policy;
4515 bi.rxbufpolicy = p->buf_policy;
4516 bi.numbufs = p->buf_no;
4517 res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
4518 if (res < 0) {
4519 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
4520 }
4521 } else
4522 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
4523
4524 if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
4525 ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
4526 dahdi_close_sub(p, x);
4527 p->subs[x].dfd = -1;
4528 return -1;
4529 }
4530 ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
4531 return 0;
4532}
4533
4534static int unalloc_sub(struct dahdi_pvt *p, int x)
4535{
4536 if (!x) {
4537 ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
4538 return -1;
4539 }
4540 ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
4541 dahdi_close_sub(p, x);
4542 p->subs[x].linear = 0;
4543 p->subs[x].chan = 0;
4544 p->subs[x].owner = NULL;
4545 p->subs[x].inthreeway = 0;
4547 memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
4548 return 0;
4549}
4550
4552{
4553 if (isdigit(digit))
4554 return DAHDI_TONE_DTMF_BASE + (digit - '0');
4555 else if (digit >= 'A' && digit <= 'D')
4556 return DAHDI_TONE_DTMF_A + (digit - 'A');
4557 else if (digit >= 'a' && digit <= 'd')
4558 return DAHDI_TONE_DTMF_A + (digit - 'a');
4559 else if (digit == '*')
4560 return DAHDI_TONE_DTMF_s;
4561 else if (digit == '#')
4562 return DAHDI_TONE_DTMF_p;
4563 else
4564 return -1;
4565}
4566
4567static int dahdi_digit_begin(struct ast_channel *chan, char digit)
4568{
4569 struct dahdi_pvt *pvt;
4570 int idx;
4571 int dtmf;
4572 int res;
4573
4574 pvt = ast_channel_tech_pvt(chan);
4575
4576 ast_mutex_lock(&pvt->lock);
4577
4578 idx = dahdi_get_index(chan, pvt, 0);
4579
4580 if ((idx != SUB_REAL) || !pvt->owner)
4581 goto out;
4582
4583#ifdef HAVE_PRI
4584 switch (pvt->sig) {
4586 res = sig_pri_digit_begin(pvt->sig_pvt, chan, digit);
4587 if (!res)
4588 goto out;
4589 break;
4590 default:
4591 break;
4592 }
4593#endif
4594 dtmf = digit_to_dtmfindex(digit);
4595 if (dtmf == -1) {
4596 /* Not a valid DTMF digit */
4597 goto out;
4598 }
4599
4600 if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
4601 char dial_str[] = { 'T', digit, '\0' };
4602
4603 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
4604 if (!res) {
4605 pvt->dialing = 1;
4606 }
4607 } else {
4608 pvt->dialing = 1;
4609 pvt->begindigit = digit;
4610
4611 /* Flush the write buffer in DAHDI to start sending the digit immediately. */
4612 dtmf = DAHDI_FLUSH_WRITE;
4613 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &dtmf);
4614 if (res) {
4615 ast_log(LOG_WARNING, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
4616 pvt->channel, strerror(errno));
4617 }
4618
4619 ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
4620 ast_channel_name(chan), digit);
4621 }
4622
4623out:
4624 ast_mutex_unlock(&pvt->lock);
4625
4626 return 0;
4627}
4628
4629static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
4630{
4631 struct dahdi_pvt *pvt;
4632 int res = 0;
4633 int idx;
4634 int x;
4635
4636 pvt = ast_channel_tech_pvt(chan);
4637
4638 ast_mutex_lock(&pvt->lock);
4639
4640 idx = dahdi_get_index(chan, pvt, 0);
4641
4642 if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
4643 goto out;
4644
4645#ifdef HAVE_PRI
4646 /* This means that the digit was already sent via PRI signalling */
4647 if (dahdi_sig_pri_lib_handles(pvt->sig) && !pvt->begindigit) {
4648 goto out;
4649 }
4650#endif
4651
4652 if (pvt->begindigit) {
4653 x = -1;
4654 ast_debug(1, "Channel %s ending VLDTMF digit '%c'\n",
4655 ast_channel_name(chan), digit);
4656 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
4657 pvt->dialing = 0;
4658 pvt->begindigit = 0;
4659 }
4660
4661out:
4662 ast_mutex_unlock(&pvt->lock);
4663
4664 return res;
4665}
4666
4667static const char * const events[] = {
4668 "No event",
4669 "On hook",
4670 "Ring/Answered",
4671 "Wink/Flash",
4672 "Alarm",
4673 "No more alarm",
4674 "HDLC Abort",
4675 "HDLC Overrun",
4676 "HDLC Bad FCS",
4677 "Dial Complete",
4678 "Ringer On",
4679 "Ringer Off",
4680 "Hook Transition Complete",
4681 "Bits Changed",
4682 "Pulse Start",
4683 "Timer Expired",
4684 "Timer Ping",
4685 "Polarity Reversal",
4686 "Ring Begin",
4687};
4688
4689static struct {
4691 char *name;
4692} alarms[] = {
4693 { DAHDI_ALARM_RED, "Red Alarm" },
4694 { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
4695 { DAHDI_ALARM_BLUE, "Blue Alarm" },
4696 { DAHDI_ALARM_RECOVER, "Recovering" },
4697 { DAHDI_ALARM_LOOPBACK, "Loopback" },
4698 { DAHDI_ALARM_NOTOPEN, "Not Open" },
4699 { DAHDI_ALARM_NONE, "None" },
4701
4702static char *alarm2str(int alm)
4703{
4704 int x;
4705 for (x = 0; x < ARRAY_LEN(alarms); x++) {
4706 if (alarms[x].alarm & alm)
4707 return alarms[x].name;
4708 }
4709 return alm ? "Unknown Alarm" : "No Alarm";
4710}
4711
4712static const char *event2str(int event)
4713{
4714 static char buf[256];
4715 if ((event > -1) && (event < (ARRAY_LEN(events))) )
4716 return events[event];
4717 sprintf(buf, "Event %d", event); /* safe */
4718 return buf;
4719}
4720
4721static char *dahdi_sig2str(int sig)
4722{
4723 static char buf[256];
4724 switch (sig) {
4725 case SIG_EM:
4726 return "E & M Immediate";
4727 case SIG_EMWINK:
4728 return "E & M Wink";
4729 case SIG_EM_E1:
4730 return "E & M E1";
4731 case SIG_FEATD:
4732 return "Feature Group D (DTMF)";
4733 case SIG_FEATDMF:
4734 return "Feature Group D (MF)";
4735 case SIG_FEATDMF_TA:
4736 return "Feature Group D (MF) Tandem Access";
4737 case SIG_FEATB:
4738 return "Feature Group B (MF)";
4739 case SIG_E911:
4740 return "E911 (MF)";
4741 case SIG_FGC_CAMA:
4742 return "FGC/CAMA (Dialpulse)";
4743 case SIG_FGC_CAMAMF:
4744 return "FGC/CAMA (MF)";
4745 case SIG_FXSLS:
4746 return "FXS Loopstart";
4747 case SIG_FXSGS:
4748 return "FXS Groundstart";
4749 case SIG_FXSKS:
4750 return "FXS Kewlstart";
4751 case SIG_FXOLS:
4752 return "FXO Loopstart";
4753 case SIG_FXOGS:
4754 return "FXO Groundstart";
4755 case SIG_FXOKS:
4756 return "FXO Kewlstart";
4757 case SIG_PRI:
4758 return "ISDN PRI";
4759 case SIG_BRI:
4760 return "ISDN BRI Point to Point";
4761 case SIG_BRI_PTMP:
4762 return "ISDN BRI Point to MultiPoint";
4763 case SIG_SS7:
4764 return "SS7";
4765 case SIG_MFCR2:
4766 return "MFC/R2";
4767 case SIG_SF:
4768 return "SF (Tone) Immediate";
4769 case SIG_SFWINK:
4770 return "SF (Tone) Wink";
4771 case SIG_SF_FEATD:
4772 return "SF (Tone) with Feature Group D (DTMF)";
4773 case SIG_SF_FEATDMF:
4774 return "SF (Tone) with Feature Group D (MF)";
4775 case SIG_SF_FEATB:
4776 return "SF (Tone) with Feature Group B (MF)";
4777 case 0:
4778 return "Pseudo";
4779 default:
4780 snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
4781 return buf;
4782 }
4783}
4784
4785#define sig2str dahdi_sig2str
4786
4787static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
4788{
4789 /* If the conference already exists, and we're already in it
4790 don't bother doing anything */
4791 struct dahdi_confinfo zi;
4792
4793 memset(&zi, 0, sizeof(zi));
4794 zi.chan = 0;
4795
4796 if (slavechannel > 0) {
4797 /* If we have only one slave, do a digital mon */
4798 zi.confmode = DAHDI_CONF_DIGITALMON;
4799 zi.confno = slavechannel;
4800 } else {
4801 if (!idx) {
4802 /* Real-side and pseudo-side both participate in conference */
4803 zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
4804 DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4805 } else
4806 zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
4807 zi.confno = p->confno;
4808 }
4809 if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
4810 return 0;
4811 if (c->dfd < 0)
4812 return 0;
4813 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4814 ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
4815 return -1;
4816 }
4817 if (slavechannel < 1) {
4818 p->confno = zi.confno;
4819 }
4820 c->curconf = zi;
4821 ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4822 return 0;
4823}
4824
4825static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
4826{
4827 /* If they're listening to our channel, they're ours */
4828 if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
4829 return 1;
4830 /* If they're a talker on our (allocated) conference, they're ours */
4831 if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
4832 return 1;
4833 return 0;
4834}
4835
4836static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
4837{
4838 struct dahdi_confinfo zi;
4839 if (/* Can't delete if there's no dfd */
4840 (c->dfd < 0) ||
4841 /* Don't delete from the conference if it's not our conference */
4842 !isourconf(p, c)
4843 /* Don't delete if we don't think it's conferenced at all (implied) */
4844 ) return 0;
4845 memset(&zi, 0, sizeof(zi));
4846 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4847 ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
4848 return -1;
4849 }
4850 ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4851 memcpy(&c->curconf, &zi, sizeof(c->curconf));
4852 return 0;
4853}
4854
4855static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
4856{
4857 int x;
4858 int useslavenative;
4859 struct dahdi_pvt *slave = NULL;
4860 /* Start out optimistic */
4861 useslavenative = 1;
4862 /* Update conference state in a stateless fashion */
4863 for (x = 0; x < 3; x++) {
4864 /* Any three-way calling makes slave native mode *definitely* out
4865 of the question */
4866 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
4867 useslavenative = 0;
4868 }
4869 /* If we don't have any 3-way calls, check to see if we have
4870 precisely one slave */
4871 if (useslavenative) {
4872 for (x = 0; x < MAX_SLAVES; x++) {
4873 if (p->slaves[x]) {
4874 if (slave) {
4875 /* Whoops already have a slave! No
4876 slave native and stop right away */
4877 slave = NULL;
4878 useslavenative = 0;
4879 break;
4880 } else {
4881 /* We have one slave so far */
4882 slave = p->slaves[x];
4883 }
4884 }
4885 }
4886 }
4887 /* If no slave, slave native definitely out */
4888 if (!slave)
4889 useslavenative = 0;
4890 else if (slave->law != p->law) {
4891 useslavenative = 0;
4892 slave = NULL;
4893 }
4894 if (out)
4895 *out = slave;
4896 return useslavenative;
4897}
4898
4899static int reset_conf(struct dahdi_pvt *p)
4900{
4901 p->confno = -1;
4902 memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
4903 if (p->subs[SUB_REAL].dfd > -1) {
4904 struct dahdi_confinfo zi;
4905
4906 memset(&zi, 0, sizeof(zi));
4907 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
4908 ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
4909 }
4910 return 0;
4911}
4912
4914{
4915 int needconf = 0;
4916 int x;
4917 int useslavenative;
4918 struct dahdi_pvt *slave = NULL;
4919
4920 useslavenative = isslavenative(p, &slave);
4921 /* Start with the obvious, general stuff */
4922 for (x = 0; x < 3; x++) {
4923 /* Look for three way calls */
4924 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
4925 conf_add(p, &p->subs[x], x, 0);
4926 needconf++;
4927 } else {
4928 conf_del(p, &p->subs[x], x);
4929 }
4930 }
4931 /* If we have a slave, add him to our conference now. or DAX
4932 if this is slave native */
4933 for (x = 0; x < MAX_SLAVES; x++) {
4934 if (p->slaves[x]) {
4935 if (useslavenative)
4936 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
4937 else {
4938 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
4939 needconf++;
4940 }
4941 }
4942 }
4943 /* If we're supposed to be in there, do so now */
4944 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
4945 if (useslavenative)
4946 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
4947 else {
4948 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
4949 needconf++;
4950 }
4951 }
4952 /* If we have a master, add ourselves to his conference */
4953 if (p->master) {
4954 if (isslavenative(p->master, NULL)) {
4956 } else {
4957 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
4958 }
4959 }
4960 if (!needconf) {
4961 /* Nobody is left (or should be left) in our conference.
4962 Kill it. */
4963 p->confno = -1;
4964 }
4965 ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
4966}
4967
4969{
4970 int res;
4971 if (!p)
4972 return;
4973 if (p->echocanon) {
4974 ast_debug(1, "Echo cancellation already on\n");
4975 return;
4976 }
4977 if (p->digital) {
4978 ast_debug(1, "Echo cancellation isn't required on digital connection\n");
4979 return;
4980 }
4981 if (p->echocancel.head.tap_length) {
4982#if defined(HAVE_PRI) || defined(HAVE_SS7)
4983 switch (p->sig) {
4984#if defined(HAVE_PRI)
4986 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
4987 /*
4988 * PRI nobch pseudo channel. Does not need ec anyway.
4989 * Does not handle ioctl(DAHDI_AUDIOMODE)
4990 */
4991 return;
4992 }
4993 /* Fall through */
4994#endif /* defined(HAVE_PRI) */
4995#if defined(HAVE_SS7)
4996 case SIG_SS7:
4997#endif /* defined(HAVE_SS7) */
4998 {
4999 int x = 1;
5000
5001 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
5002 if (res)
5004 "Unable to enable audio mode on channel %d (%s)\n",
5005 p->channel, strerror(errno));
5006 }
5007 break;
5008 default:
5009 break;
5010 }
5011#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5012 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
5013 if (res) {
5014 ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
5015 } else {
5016 p->echocanon = 1;
5017 ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
5018 }
5019 } else
5020 ast_debug(1, "No echo cancellation requested\n");
5021}
5022
5023static void dahdi_train_ec(struct dahdi_pvt *p)
5024{
5025 int x;
5026 int res;
5027
5028 if (p && p->echocanon && p->echotraining) {
5029 x = p->echotraining;
5030 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
5031 if (res)
5032 ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
5033 else
5034 ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
5035 } else {
5036 ast_debug(1, "No echo training requested\n");
5037 }
5038}
5039
5041{
5042 int res;
5043
5044 if (p->echocanon) {
5045 struct dahdi_echocanparams ecp = { .tap_length = 0 };
5046
5047 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
5048
5049 if (res)
5050 ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
5051 else
5052 ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
5053 }
5054
5055 p->echocanon = 0;
5056}
5057
5058static int set_hwgain(int fd, float gain, int tx_direction)
5059{
5060 struct dahdi_hwgain hwgain;
5061
5062 hwgain.newgain = gain * 10.0;
5063 hwgain.tx = tx_direction;
5064 return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
5065}
5066
5067/* perform a dynamic range compression transform on the given sample */
5068static int drc_sample(int sample, float drc)
5069{
5070 float neg;
5071 float shallow, steep;
5072 float max = SHRT_MAX;
5073
5074 neg = (sample < 0 ? -1 : 1);
5075 steep = drc*sample;
5076 shallow = neg*(max-max/drc)+(float)sample/drc;
5077 if (fabsf(steep) < fabsf(shallow)) {
5078 sample = steep;
5079 }
5080 else {
5081 sample = shallow;
5082 }
5083
5084 return sample;
5085}
5086
5087
5088static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
5089{
5090 int j;
5091 int k;
5092
5093 float linear_gain = pow(10.0, gain / 20.0);
5094
5095 switch (law) {
5096 case DAHDI_LAW_ALAW:
5097 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5098 if (gain || drc) {
5099 k = AST_ALAW(j);
5100 if (drc) {
5101 k = drc_sample(k, drc);
5102 }
5103 k = (float)k * linear_gain;
5104 if (k > 32767) {
5105 k = 32767;
5106 } else if (k < -32768) {
5107 k = -32768;
5108 }
5109 g->txgain[j] = AST_LIN2A(k);
5110 } else {
5111 g->txgain[j] = j;
5112 }
5113 }
5114 break;
5115 case DAHDI_LAW_MULAW:
5116 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5117 if (gain || drc) {
5118 k = AST_MULAW(j);
5119 if (drc) {
5120 k = drc_sample(k, drc);
5121 }
5122 k = (float)k * linear_gain;
5123 if (k > 32767) {
5124 k = 32767;
5125 } else if (k < -32768) {
5126 k = -32768;
5127 }
5128 g->txgain[j] = AST_LIN2MU(k);
5129
5130 } else {
5131 g->txgain[j] = j;
5132 }
5133 }
5134 break;
5135 }
5136}
5137
5138static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
5139{
5140 int j;
5141 int k;
5142 float linear_gain = pow(10.0, gain / 20.0);
5143
5144 switch (law) {
5145 case DAHDI_LAW_ALAW:
5146 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5147 if (gain || drc) {
5148 k = AST_ALAW(j);
5149 if (drc) {
5150 k = drc_sample(k, drc);
5151 }
5152 k = (float)k * linear_gain;
5153 if (k > 32767) {
5154 k = 32767;
5155 } else if (k < -32768) {
5156 k = -32768;
5157 }
5158 g->rxgain[j] = AST_LIN2A(k);
5159 } else {
5160 g->rxgain[j] = j;
5161 }
5162 }
5163 break;
5164 case DAHDI_LAW_MULAW:
5165 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5166 if (gain || drc) {
5167 k = AST_MULAW(j);
5168 if (drc) {
5169 k = drc_sample(k, drc);
5170 }
5171 k = (float)k * linear_gain;
5172 if (k > 32767) {
5173 k = 32767;
5174 } else if (k < -32768) {
5175 k = -32768;
5176 }
5177 g->rxgain[j] = AST_LIN2MU(k);
5178 } else {
5179 g->rxgain[j] = j;
5180 }
5181 }
5182 break;
5183 }
5184}
5185
5186static int set_actual_txgain(int fd, float gain, float drc, int law)
5187{
5188 struct dahdi_gains g;
5189 int res;
5190
5191 memset(&g, 0, sizeof(g));
5192 res = ioctl(fd, DAHDI_GETGAINS, &g);
5193 if (res) {
5194 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5195 return res;
5196 }
5197
5198 fill_txgain(&g, gain, drc, law);
5199
5200 return ioctl(fd, DAHDI_SETGAINS, &g);
5201}
5202
5203static int set_actual_rxgain(int fd, float gain, float drc, int law)
5204{
5205 struct dahdi_gains g;
5206 int res;
5207
5208 memset(&g, 0, sizeof(g));
5209 res = ioctl(fd, DAHDI_GETGAINS, &g);
5210 if (res) {
5211 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5212 return res;
5213 }
5214
5215 fill_rxgain(&g, gain, drc, law);
5216
5217 return ioctl(fd, DAHDI_SETGAINS, &g);
5218}
5219
5220static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
5221{
5222 return set_actual_txgain(fd, txgain, txdrc, law) | set_actual_rxgain(fd, rxgain, rxdrc, law);
5223}
5224
5225static int bump_gains(struct dahdi_pvt *p)
5226{
5227 int res;
5228
5229 /* Bump receive gain by value stored in cid_rxgain */
5230 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain + p->cid_rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5231 if (res) {
5232 ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
5233 return -1;
5234 }
5235
5236 return 0;
5237}
5238
5239static int restore_gains(struct dahdi_pvt *p)
5240{
5241 int res;
5242
5243 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5244 if (res) {
5245 ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
5246 return -1;
5247 }
5248
5249 return 0;
5250}
5251
5252static inline int dahdi_set_hook(int fd, int hs)
5253{
5254 int x, res;
5255
5256 x = hs;
5257 res = ioctl(fd, DAHDI_HOOK, &x);
5258
5259 if (res < 0) {
5260 if (errno == EINPROGRESS)
5261 return 0;
5262 ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
5263 /* will expectedly fail if phone is off hook during operation, such as during a restart */
5264 }
5265
5266 return res;
5267}
5268
5269static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
5270{
5271 int x, res;
5272
5273 x = muted;
5274#if defined(HAVE_PRI) || defined(HAVE_SS7)
5275 switch (p->sig) {
5276#if defined(HAVE_PRI)
5278 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
5279 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
5280 break;
5281 }
5282 /* Fall through */
5283#endif /* defined(HAVE_PRI) */
5284#if defined(HAVE_SS7)
5285 case SIG_SS7:
5286#endif /* defined(HAVE_SS7) */
5287 {
5288 int y = 1;
5289
5290 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
5291 if (res)
5292 ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n",
5293 p->channel, strerror(errno));
5294 }
5295 break;
5296 default:
5297 break;
5298 }
5299#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5300 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
5301 if (res < 0)
5302 ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
5303 return res;
5304}
5305
5306static int save_conference(struct dahdi_pvt *p)
5307{
5308 struct dahdi_confinfo c;
5309 int res;
5310 if (p->saveconf.confmode) {
5311 ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
5312 return -1;
5313 }
5314 p->saveconf.chan = 0;
5315 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
5316 if (res) {
5317 ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
5318 p->saveconf.confmode = 0;
5319 return -1;
5320 }
5321 memset(&c, 0, sizeof(c));
5322 c.confmode = DAHDI_CONF_NORMAL;
5323 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
5324 if (res) {
5325 ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
5326 return -1;
5327 }
5328 ast_debug(1, "Disabled conferencing\n");
5329 return 0;
5330}
5331
5332static int restore_conference(struct dahdi_pvt *p)
5333{
5334 int res;
5335 if (p->saveconf.confmode) {
5336 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
5337 p->saveconf.confmode = 0;
5338 if (res) {
5339 ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
5340 return -1;
5341 }
5342 ast_debug(1, "Restored conferencing\n");
5343 }
5344 return 0;
5345}
5346
5347static int send_cwcidspill(struct dahdi_pvt *p)
5348{
5349 p->callwaitcas = 0;
5350 p->cidcwexpire = 0;
5351 p->cid_suppress_expire = 0;
5353 return -1;
5355 /* Make sure we account for the end */
5356 p->cidlen += READ_SIZE * 4;
5357 p->cidpos = 0;
5358 send_callerid(p);
5359 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
5360 return 0;
5361}
5362
5363static int has_voicemail(struct dahdi_pvt *p)
5364{
5365 int new_msgs;
5366 RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
5367
5368 /* A manual MWI disposition has been requested, use that instead
5369 * if this is for sending the new MWI indication. */
5370 if (p->mwioverride_active) {
5371 /* We don't clear p->mwioverride_active automatically,
5372 * because otherwise do_monitor would just change it back to the way it was.
5373 * We need to keep the override active until explicitly disabled by the user,
5374 * so that we can keep returning the correct answer in subsequent calls to do_monitor. */
5375 ast_debug(6, "MWI manual override active on channel %d: pretending that it should be %s\n",
5376 p->channel, p->mwioverride_disposition ? "active" : "inactive");
5377 return p->mwioverride_disposition;
5378 }
5379
5381 if (mwi_message) {
5382 struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
5383 new_msgs = mwi_state->new_msgs;
5384 } else {
5386 }
5387
5388 return new_msgs;
5389}
5390
5391
5392
5393static int send_callerid(struct dahdi_pvt *p)
5394{
5395 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
5396 int res;
5397 /* Take out of linear mode if necessary */
5398 if (p->subs[SUB_REAL].linear) {
5399 p->subs[SUB_REAL].linear = 0;
5401 }
5402 while (p->cidpos < p->cidlen) {
5403 res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
5404 ast_debug(4, "writing callerid at pos %d of %d, res = %d\n", p->cidpos, p->cidlen, res);
5405 if (res < 0) {
5406 if (errno == EAGAIN)
5407 return 0;
5408 else {
5409 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
5410 return -1;
5411 }
5412 }
5413 if (!res)
5414 return 0;
5415 p->cidpos += res;
5416 }
5418 ast_free(p->cidspill);
5419 p->cidspill = NULL;
5420 if (p->callwaitcas) {
5421 /* Wait for CID/CW to expire */
5424 } else
5426 return 0;
5427}
5428
5429static int dahdi_callwait(struct ast_channel *ast)
5430{
5431 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5432
5434 if (p->cidspill) {
5435 ast_log(LOG_WARNING, "Spill already exists?!?\n");
5436 ast_free(p->cidspill);
5437 }
5438
5439 /*
5440 * SAS: Subscriber Alert Signal, 440Hz for 300ms
5441 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
5442 */
5443 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
5444 return -1;
5445 save_conference(p);
5446 /* Silence */
5447 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
5448 if (!p->callwaitrings && p->callwaitingcallerid) {
5449 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
5450 p->callwaitcas = 1;
5451 p->cidlen = 2400 + 680 + READ_SIZE * 4;
5452 } else {
5453 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
5454 p->callwaitcas = 0;
5455 p->cidlen = 2400 + READ_SIZE * 4;
5456 }
5457 p->cidpos = 0;
5458 send_callerid(p);
5459
5460 return 0;
5461}
5462
5463static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
5464{
5465 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5466 int x, res, mysig;
5467 char *dest;
5469 AST_APP_ARG(group); /* channel/group token */
5470 AST_APP_ARG(ext); /* extension token */
5471 //AST_APP_ARG(opts); /* options token */
5472 AST_APP_ARG(other); /* Any remaining unused arguments */
5473 );
5474
5475 ast_mutex_lock(&p->lock);
5476 ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
5477
5478 /* Split the dialstring */
5479 dest = ast_strdupa(rdest);
5480 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
5481 if (!args.ext) {
5482 args.ext = "";
5483 }
5484
5485#if defined(HAVE_PRI)
5487 char *subaddr;
5488
5489 sig_pri_extract_called_num_subaddr(p->sig_pvt, rdest, p->exten, sizeof(p->exten));
5490
5491 /* Remove any subaddress for uniformity with incoming calls. */
5492 subaddr = strchr(p->exten, ':');
5493 if (subaddr) {
5494 *subaddr = '\0';
5495 }
5496 } else
5497#endif /* defined(HAVE_PRI) */
5498 {
5499 ast_copy_string(p->exten, args.ext, sizeof(p->exten));
5500 }
5501
5502 if ((ast_channel_state(ast) == AST_STATE_BUSY)) {
5503 p->subs[SUB_REAL].needbusy = 1;
5505 return 0;
5506 }
5508 ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
5510 return -1;
5511 }
5512 p->waitingfordt.tv_sec = 0;
5513 p->dialednone = 0;
5514 if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
5515 {
5516 /* Special pseudo -- automatically up */
5519 return 0;
5520 }
5521 x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
5522 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
5523 if (res)
5524 ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
5525 p->outgoing = 1;
5526
5528 set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
5529 } else {
5530 set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5531 }
5532
5533#ifdef HAVE_PRI
5535 res = sig_pri_call(p->sig_pvt, ast, rdest, timeout,
5536 (p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW);
5538 return res;
5539 }
5540#endif
5541
5542#if defined(HAVE_SS7)
5543 if (p->sig == SIG_SS7) {
5544 res = sig_ss7_call(p->sig_pvt, ast, rdest);
5546 return res;
5547 }
5548#endif /* defined(HAVE_SS7) */
5549
5550 /* If this is analog signalling we can exit here */
5551 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
5552 p->callwaitrings = 0;
5553 res = analog_call(p->sig_pvt, ast, rdest, timeout);
5555 return res;
5556 }
5557
5558 mysig = p->outsigmod > -1 ? p->outsigmod : p->sig;
5559 switch (mysig) {
5560 case 0:
5561 /* Special pseudo -- automatically up*/
5563 break;
5564 case SIG_MFCR2:
5565 break;
5566 default:
5567 ast_debug(1, "not yet implemented\n");
5569 return -1;
5570 }
5571
5572#ifdef HAVE_OPENR2
5573 if (p->mfcr2) {
5574 openr2_calling_party_category_t chancat;
5575 int callres = 0;
5576 char *c, *l;
5577
5578 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
5579 p->dialdest[0] = '\0';
5580
5581 c = args.ext;
5582 if (!p->hidecallerid) {
5584 } else {
5585 l = NULL;
5586 }
5587 if (strlen(c) < p->stripmsd) {
5588 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
5590 return -1;
5591 }
5592 p->dialing = 1;
5593 chancat = dahdi_r2_get_channel_category(ast);
5594 callres = openr2_chan_make_call(p->r2chan, l, (c + p->stripmsd), chancat);
5595 if (-1 == callres) {
5597 ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
5598 return -1;
5599 }
5600 p->mfcr2_call_accepted = 0;
5601 p->mfcr2_progress_sent = 0;
5603 }
5604#endif /* HAVE_OPENR2 */
5606 return 0;
5607}
5608
5609/*!
5610 * \internal
5611 * \brief Insert the given chan_dahdi interface structure into the interface list.
5612 * \since 1.8
5613 *
5614 * \param pvt chan_dahdi private interface structure to insert.
5615 *
5616 * \details
5617 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5618 * Any duplicates are inserted after the existing entries.
5619 *
5620 * \note The new interface must not already be in the list.
5621 */
5622static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
5623{
5624 struct dahdi_pvt *cur;
5625
5627
5628 /* Find place in middle of list for the new interface. */
5629 for (cur = iflist; cur; cur = cur->next) {
5630 if (pvt->channel < cur->channel) {
5631 /* New interface goes before the current interface. */
5632 pvt->prev = cur->prev;
5633 pvt->next = cur;
5634 if (cur->prev) {
5635 /* Insert into the middle of the list. */
5636 cur->prev->next = pvt;
5637 } else {
5638 /* Insert at head of list. */
5639 iflist = pvt;
5640 }
5641 cur->prev = pvt;
5642 return;
5643 }
5644 }
5645
5646 /* New interface goes onto the end of the list */
5647 pvt->prev = ifend;
5648 pvt->next = NULL;
5649 if (ifend) {
5650 ifend->next = pvt;
5651 }
5652 ifend = pvt;
5653 if (!iflist) {
5654 /* List was empty */
5655 iflist = pvt;
5656 }
5657}
5658
5659/*!
5660 * \internal
5661 * \brief Extract the given chan_dahdi interface structure from the interface list.
5662 * \since 1.8
5663 *
5664 * \param pvt chan_dahdi private interface structure to extract.
5665 *
5666 * \note
5667 * The given interface structure can be either in the interface list or a stand alone
5668 * structure that has not been put in the list if the next and prev pointers are NULL.
5669 */
5670static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
5671{
5672 /* Extract from the forward chain. */
5673 if (pvt->prev) {
5674 pvt->prev->next = pvt->next;
5675 } else if (iflist == pvt) {
5676 /* Node is at the head of the list. */
5677 iflist = pvt->next;
5678 }
5679
5680 /* Extract from the reverse chain. */
5681 if (pvt->next) {
5682 pvt->next->prev = pvt->prev;
5683 } else if (ifend == pvt) {
5684 /* Node is at the end of the list. */
5685 ifend = pvt->prev;
5686 }
5687
5688 /* Node is no longer in the list. */
5690 pvt->prev = NULL;
5691 pvt->next = NULL;
5692}
5693
5694#if defined(HAVE_PRI)
5695/*!
5696 * \internal
5697 * \brief Insert the given chan_dahdi interface structure into the no B channel list.
5698 * \since 1.8
5699 *
5700 * \param pri sig_pri span control structure holding no B channel list.
5701 * \param pvt chan_dahdi private interface structure to insert.
5702 *
5703 * \details
5704 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5705 * Any duplicates are inserted after the existing entries.
5706 *
5707 * \note The new interface must not already be in the list.
5708 */
5709static void dahdi_nobch_insert(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5710{
5711 struct dahdi_pvt *cur;
5712
5713 pvt->which_iflist = DAHDI_IFLIST_NO_B_CHAN;
5714
5715 /* Find place in middle of list for the new interface. */
5716 for (cur = pri->no_b_chan_iflist; cur; cur = cur->next) {
5717 if (pvt->channel < cur->channel) {
5718 /* New interface goes before the current interface. */
5719 pvt->prev = cur->prev;
5720 pvt->next = cur;
5721 if (cur->prev) {
5722 /* Insert into the middle of the list. */
5723 cur->prev->next = pvt;
5724 } else {
5725 /* Insert at head of list. */
5726 pri->no_b_chan_iflist = pvt;
5727 }
5728 cur->prev = pvt;
5729 return;
5730 }
5731 }
5732
5733 /* New interface goes onto the end of the list */
5734 pvt->prev = pri->no_b_chan_end;
5735 pvt->next = NULL;
5736 if (pri->no_b_chan_end) {
5737 ((struct dahdi_pvt *) pri->no_b_chan_end)->next = pvt;
5738 }
5739 pri->no_b_chan_end = pvt;
5740 if (!pri->no_b_chan_iflist) {
5741 /* List was empty */
5742 pri->no_b_chan_iflist = pvt;
5743 }
5744}
5745#endif /* defined(HAVE_PRI) */
5746
5747#if defined(HAVE_PRI)
5748/*!
5749 * \internal
5750 * \brief Extract the given chan_dahdi interface structure from the no B channel list.
5751 * \since 1.8
5752 *
5753 * \param pri sig_pri span control structure holding no B channel list.
5754 * \param pvt chan_dahdi private interface structure to extract.
5755 *
5756 * \note
5757 * The given interface structure can be either in the interface list or a stand alone
5758 * structure that has not been put in the list if the next and prev pointers are NULL.
5759 */
5760static void dahdi_nobch_extract(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5761{
5762 /* Extract from the forward chain. */
5763 if (pvt->prev) {
5764 pvt->prev->next = pvt->next;
5765 } else if (pri->no_b_chan_iflist == pvt) {
5766 /* Node is at the head of the list. */
5767 pri->no_b_chan_iflist = pvt->next;
5768 }
5769
5770 /* Extract from the reverse chain. */
5771 if (pvt->next) {
5772 pvt->next->prev = pvt->prev;
5773 } else if (pri->no_b_chan_end == pvt) {
5774 /* Node is at the end of the list. */
5775 pri->no_b_chan_end = pvt->prev;
5776 }
5777
5778 /* Node is no longer in the list. */
5780 pvt->prev = NULL;
5781 pvt->next = NULL;
5782}
5783#endif /* defined(HAVE_PRI) */
5784
5785#if defined(HAVE_PRI)
5786/*!
5787 * \internal
5788 * \brief Unlink the channel interface from the PRI private pointer array.
5789 * \since 1.8
5790 *
5791 * \param pvt chan_dahdi private interface structure to unlink.
5792 */
5793static void dahdi_unlink_pri_pvt(struct dahdi_pvt *pvt)
5794{
5795 unsigned idx;
5796 struct sig_pri_span *pri;
5797
5798 pri = pvt->pri;
5799 if (!pri) {
5800 /* Not PRI signaling so cannot be in a PRI private pointer array. */
5801 return;
5802 }
5803 ast_mutex_lock(&pri->lock);
5804 for (idx = 0; idx < pri->numchans; ++idx) {
5805 if (pri->pvts[idx] == pvt->sig_pvt) {
5806 pri->pvts[idx] = NULL;
5807 ast_mutex_unlock(&pri->lock);
5808 return;
5809 }
5810 }
5811 ast_mutex_unlock(&pri->lock);
5812}
5813#endif /* defined(HAVE_PRI) */
5814
5815#if defined(HAVE_SS7)
5816/*!
5817 * \internal
5818 * \brief Unlink the channel interface from the SS7 private pointer array.
5819 * \since 1.8
5820 *
5821 * \param pvt chan_dahdi private interface structure to unlink.
5822 */
5823static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
5824{
5825 unsigned idx;
5826 struct sig_ss7_linkset *ss7;
5827
5828 ss7 = pvt->ss7;
5829 if (!ss7) {
5830 /* Not SS7 signaling so cannot be in a SS7 private pointer array. */
5831 return;
5832 }
5833 ast_mutex_lock(&ss7->lock);
5834 for (idx = 0; idx < ss7->numchans; ++idx) {
5835 if (ss7->pvts[idx] == pvt->sig_pvt) {
5836 ss7->pvts[idx] = NULL;
5837 ast_mutex_unlock(&ss7->lock);
5838 return;
5839 }
5840 }
5841 ast_mutex_unlock(&ss7->lock);
5842}
5843#endif /* defined(HAVE_SS7) */
5844
5845#if defined(HAVE_OPENR2)
5846/*!
5847 * \internal
5848 * \brief Unlink the channel interface from the MFC/R2 private pointer array.
5849 *
5850 * \param pvt chan_dahdi private interface structure to unlink.
5851 */
5852static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
5853{
5854 unsigned idx;
5855 struct dahdi_mfcr2 *mfcr2;
5856 int should_destroy_link = 0;
5857
5858 ast_mutex_lock(&pvt->lock);
5859 if (pvt->r2chan) {
5860 ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
5861 openr2_chan_disable_read(pvt->r2chan);
5862 }
5863 mfcr2 = pvt->mfcr2;
5864 if (mfcr2) {
5865 for (idx = 0; idx < mfcr2->numchans; ++idx) {
5866 if (mfcr2->pvts[idx] == pvt) {
5867 ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
5868 mfcr2->pvts[idx] = NULL;
5869 mfcr2->live_chans--;
5870 break;
5871 }
5872 }
5873 if (!mfcr2->live_chans) {
5874 ast_debug(1, "MFC/R2 link is now empty\n");
5875 should_destroy_link = 1;
5876 }
5877 }
5878 ast_mutex_unlock(&pvt->lock);
5879 if (should_destroy_link) {
5880 ast_debug(1, "MFC/R2 link is now empty\n");
5881 mfcr2_queue_for_destruction(pvt);
5882 }
5883}
5884#endif /* defined(HAVE_OPENR2) */
5885
5887{
5888 if (cur->next && cur->next->span == cur->span) {
5889 return cur->next;
5890 } else if (cur->prev && cur->prev->span == cur->span) {
5891 return cur->prev;
5892 }
5893
5894 return NULL;
5895}
5896
5897static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
5898{
5899 struct dahdi_pvt *p = pvt;
5900
5901 if (p->manages_span_alarms) {
5903 if (next) {
5905 }
5906 }
5907
5908 /* Remove channel from the list */
5909#if defined(HAVE_PRI)
5910 dahdi_unlink_pri_pvt(p);
5911#endif /* defined(HAVE_PRI) */
5912#if defined(HAVE_SS7)
5913 dahdi_unlink_ss7_pvt(p);
5914#endif /* defined(HAVE_SS7) */
5915#if defined(HAVE_OPENR2)
5916 dahdi_unlink_mfcr2_pvt(p);
5917#endif /* defined(HAVE_SS7) */
5918 switch (pvt->which_iflist) {
5919 case DAHDI_IFLIST_NONE:
5920 break;
5921 case DAHDI_IFLIST_MAIN:
5923 break;
5924#if defined(HAVE_PRI)
5925 case DAHDI_IFLIST_NO_B_CHAN:
5926 if (p->pri) {
5927 dahdi_nobch_extract(p->pri, p);
5928 }
5929 break;
5930#endif /* defined(HAVE_PRI) */
5931 }
5932
5933 if (p->sig_pvt) {
5934 if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
5936 }
5937 switch (p->sig) {
5938#if defined(HAVE_PRI)
5941 break;
5942#endif /* defined(HAVE_PRI) */
5943#if defined(HAVE_SS7)
5944 case SIG_SS7:
5946 break;
5947#endif /* defined(HAVE_SS7) */
5948 default:
5949 break;
5950 }
5951 }
5952 ast_free(p->cidspill);
5953 if (p->use_smdi) {
5955 }
5956 if (p->mwi_event_sub) {
5958 }
5959 if (p->vars) {
5961 }
5962 if (p->cc_params) {
5964 }
5965
5968
5971 if (p->owner) {
5973 }
5974 ast_free(p);
5975}
5976
5977static void destroy_channel(struct dahdi_pvt *cur, int now)
5978{
5979 int i;
5980
5981 if (!now) {
5982 /* Do not destroy the channel now if it is owned by someone. */
5983 if (cur->owner) {
5984 return;
5985 }
5986 for (i = 0; i < 3; i++) {
5987 if (cur->subs[i].owner) {
5988 return;
5989 }
5990 }
5991 }
5992 destroy_dahdi_pvt(cur);
5993}
5994
5995static void destroy_all_channels(void)
5996{
5997 int chan;
5998#if defined(HAVE_PRI)
5999 unsigned span;
6000 struct sig_pri_span *pri;
6001#endif /* defined(HAVE_PRI) */
6002 struct dahdi_pvt *p;
6003
6004 while (num_restart_pending) {
6005 usleep(1);
6006 }
6007
6009 /* Destroy all the interfaces and free their memory */
6010 while (iflist) {
6011 p = iflist;
6012
6013 chan = p->channel;
6014#if defined(HAVE_PRI_SERVICE_MESSAGES)
6015 {
6016 char db_chan_name[20];
6017 char db_answer[5];
6018 char state;
6019 int why = -1;
6020
6021 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, p->span, chan);
6022 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
6023 sscanf(db_answer, "%1c:%30d", &state, &why);
6024 }
6025 if (!why) {
6026 /* SRVST persistence is not required */
6027 ast_db_del(db_chan_name, SRVST_DBKEY);
6028 }
6029 }
6030#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
6031 /* Free associated memory */
6033 ast_verb(3, "Unregistered channel %d\n", chan);
6034 }
6035 ifcount = 0;
6037
6038#if defined(HAVE_PRI)
6039 /* Destroy all of the no B channel interface lists */
6040 for (span = 0; span < NUM_SPANS; ++span) {
6041 if (!pris[span].dchannels[0]) {
6042 break;
6043 }
6044 pri = &pris[span].pri;
6045 ast_mutex_lock(&pri->lock);
6046 while (pri->no_b_chan_iflist) {
6047 p = pri->no_b_chan_iflist;
6048
6049 /* Free associated memory */
6051 }
6052 ast_mutex_unlock(&pri->lock);
6053 }
6054#endif /* defined(HAVE_PRI) */
6055}
6056
6057#if defined(HAVE_PRI)
6058static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
6059
6060static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, const char *digits)
6061{
6062 /* Data will be our digit string */
6063 struct dahdi_pvt *p;
6064
6065 if (ast_strlen_zero(digits)) {
6066 ast_debug(1, "No digit string sent to application!\n");
6067 return -1;
6068 }
6069
6070 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6071
6072 if (!p) {
6073 ast_debug(1, "Unable to find technology private\n");
6074 return -1;
6075 }
6076
6078
6079 return 0;
6080}
6081#endif /* defined(HAVE_PRI) */
6082
6083#if defined(HAVE_PRI)
6084#if defined(HAVE_PRI_PROG_W_CAUSE)
6085static char *dahdi_send_callrerouting_facility_app = "DAHDISendCallreroutingFacility";
6086
6087static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, const char *data)
6088{
6089 /* Data will be our digit string */
6090 struct dahdi_pvt *pvt;
6091 char *parse;
6092 int res;
6094 AST_APP_ARG(destination);
6095 AST_APP_ARG(original);
6096 AST_APP_ARG(reason);
6097 );
6098
6099 if (ast_strlen_zero(data)) {
6100 ast_debug(1, "No data sent to application!\n");
6101 return -1;
6102 }
6103 if (ast_channel_tech(chan) != &dahdi_tech) {
6104 ast_debug(1, "Only DAHDI technology accepted!\n");
6105 return -1;
6106 }
6107 pvt = (struct dahdi_pvt *) ast_channel_tech_pvt(chan);
6108 if (!pvt) {
6109 ast_debug(1, "Unable to find technology private\n");
6110 return -1;
6111 }
6112 switch (pvt->sig) {
6114 break;
6115 default:
6116 ast_debug(1, "callrerouting attempted on non-ISDN channel %s\n",
6117 ast_channel_name(chan));
6118 return -1;
6119 }
6120
6121 parse = ast_strdupa(data);
6123
6124 if (ast_strlen_zero(args.destination)) {
6125 ast_log(LOG_WARNING, "callrerouting facility requires at least destination number argument\n");
6126 return -1;
6127 }
6128
6129 if (ast_strlen_zero(args.original)) {
6130 ast_log(LOG_WARNING, "Callrerouting Facility without original called number argument\n");
6131 args.original = NULL;
6132 }
6133
6134 if (ast_strlen_zero(args.reason)) {
6135 ast_log(LOG_NOTICE, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n");
6136 args.reason = NULL;
6137 }
6138
6140 args.destination, args.original, args.reason);
6141 if (!res) {
6142 /*
6143 * Wait up to 5 seconds for a reply before hanging up this call
6144 * leg if the peer does not disconnect first.
6145 */
6146 ast_safe_sleep(chan, 5000);
6147 }
6148
6149 return -1;
6150}
6151#endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
6152#endif /* defined(HAVE_PRI) */
6153
6154#if defined(HAVE_OPENR2)
6155static const char * const dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
6156
6157static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
6158{
6159 /* data is whether to accept with charge or no charge */
6160 openr2_call_mode_t accept_mode;
6161 int res, timeout, maxloops;
6162 struct ast_frame *f;
6163 struct dahdi_pvt *p;
6164 char *parse;
6166 AST_APP_ARG(charge);
6167 );
6168
6169 if (ast_strlen_zero(data)) {
6170 ast_debug(1, "No data sent to application!\n");
6171 return -1;
6172 }
6173
6174 if (ast_channel_tech(chan) != &dahdi_tech) {
6175 ast_debug(1, "Only DAHDI technology accepted!\n");
6176 return -1;
6177 }
6178
6179 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6180 if (!p) {
6181 ast_debug(1, "Unable to find technology private!\n");
6182 return -1;
6183 }
6184
6185 parse = ast_strdupa(data);
6187
6188 if (ast_strlen_zero(args.charge)) {
6189 ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
6190 return -1;
6191 }
6192
6193 ast_mutex_lock(&p->lock);
6194 if (!p->mfcr2 || !p->mfcr2call) {
6196 ast_debug(1, "Channel %s does not seems to be an R2 active channel!\n", ast_channel_name(chan));
6197 return -1;
6198 }
6199
6200 if (p->mfcr2_call_accepted) {
6202 ast_debug(1, "MFC/R2 call already accepted on channel %s!\n", ast_channel_name(chan));
6203 return 0;
6204 }
6205 accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
6206 if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
6208 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6209 return -1;
6210 }
6212
6213 res = 0;
6214 timeout = 100;
6215 maxloops = 50; /* wait up to 5 seconds */
6216 /* we need to read() until the call is accepted */
6217 while (maxloops > 0) {
6218 maxloops--;
6219 if (ast_check_hangup(chan)) {
6220 break;
6221 }
6222 res = ast_waitfor(chan, timeout);
6223 if (res < 0) {
6224 ast_debug(1, "ast_waitfor failed on channel %s, going out ...\n", ast_channel_name(chan));
6225 res = -1;
6226 break;
6227 }
6228 if (res == 0) {
6229 continue;
6230 }
6231 res = 0;
6232 f = ast_read(chan);
6233 if (!f) {
6234 ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
6235 res = -1;
6236 break;
6237 }
6239 ast_debug(1, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
6240 ast_frfree(f);
6241 res = -1;
6242 break;
6243 }
6244 ast_frfree(f);
6245 ast_mutex_lock(&p->lock);
6246 if (p->mfcr2_call_accepted) {
6248 ast_debug(1, "Accepted MFC/R2 call!\n");
6249 break;
6250 }
6252 }
6253 if (res == -1) {
6254 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6255 }
6256 return res;
6257}
6258
6259static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
6260{
6261 openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
6262 switch (cause) {
6265 case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
6266 r2cause = OR2_CAUSE_BUSY_NUMBER;
6267 break;
6268
6271 r2cause = OR2_CAUSE_NETWORK_CONGESTION;
6272 break;
6273
6275 r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
6276 break;
6277
6280 r2cause = OR2_CAUSE_OUT_OF_ORDER;
6281 break;
6282
6285 r2cause = OR2_CAUSE_NO_ANSWER;
6286 break;
6287
6288 default:
6289 r2cause = OR2_CAUSE_NORMAL_CLEARING;
6290 break;
6291 }
6292 ast_debug(1, "ast cause %d resulted in openr2 cause %d/%s\n",
6293 cause, r2cause, openr2_proto_get_disconnect_string(r2cause));
6294 return r2cause;
6295}
6296#endif
6297
6298static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
6299{
6300 if (p->bufferoverrideinuse) {
6301 /* faxbuffers are in use, revert them */
6302 struct dahdi_bufferinfo bi = {
6303 .txbufpolicy = p->buf_policy,
6304 .rxbufpolicy = p->buf_policy,
6305 .bufsize = p->bufsize,
6306 .numbufs = p->buf_no
6307 };
6308 int bpres;
6309
6310 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
6311 ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast_channel_name(ast), strerror(errno));
6312 }
6313 p->bufferoverrideinuse = 0;
6314 return bpres;
6315 }
6316
6317 return -1;
6318}
6319
6320static int dahdi_hangup(struct ast_channel *ast)
6321{
6322 int res = 0;
6323 int idx,x;
6324 int law;
6325 /*static int restore_gains(struct dahdi_pvt *p);*/
6326 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6327 struct dahdi_params par;
6328
6329 ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast));
6330 if (!ast_channel_tech_pvt(ast)) {
6331 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
6332 return 0;
6333 }
6334
6335 ast_mutex_lock(&p->lock);
6336 p->exten[0] = '\0';
6337 /* Always use sig_analog hangup handling for operator mode */
6338 if (dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6339 p->oprmode = 0;
6340 dahdi_confmute(p, 0);
6341 restore_gains(p);
6342 p->ignoredtmf = 0;
6343 p->waitingfordt.tv_sec = 0;
6344
6345 res = analog_hangup(p->sig_pvt, ast);
6346 revert_fax_buffers(p, ast);
6347
6348 goto hangup_out;
6349 } else {
6350 p->cid_num[0] = '\0';
6351 p->cid_name[0] = '\0';
6352 p->cid_subaddr[0] = '\0';
6353 }
6354
6355#if defined(HAVE_PRI)
6357 x = 1;
6358 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6359
6360 dahdi_confmute(p, 0);
6361 p->muting = 0;
6362 restore_gains(p);
6363 if (p->dsp) {
6364 ast_dsp_free(p->dsp);
6365 p->dsp = NULL;
6366 }
6367 p->ignoredtmf = 0;
6368
6369 /* Real channel, do some fixup */
6370 p->subs[SUB_REAL].owner = NULL;
6371 p->subs[SUB_REAL].needbusy = 0;
6373
6374 p->owner = NULL;
6375 p->cid_tag[0] = '\0';
6376 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6377 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6378 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6379 p->outgoing = 0;
6380 p->digital = 0;
6381 p->faxhandled = 0;
6382 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6383
6384 revert_fax_buffers(p, ast);
6385
6386 p->law = p->law_default;
6387 law = p->law_default;
6388 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6389 if (res < 0) {
6390 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6391 p->channel, strerror(errno));
6392 }
6393
6394 sig_pri_hangup(p->sig_pvt, ast);
6395
6396 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6398
6399 x = 0;
6400 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6401 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6402
6403 p->rdnis[0] = '\0';
6405 reset_conf(p);
6406
6407 /* Restore data mode */
6408 x = 0;
6409 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6410
6411 if (num_restart_pending == 0) {
6413 }
6414 goto hangup_out;
6415 }
6416#endif /* defined(HAVE_PRI) */
6417
6418#if defined(HAVE_SS7)
6419 if (p->sig == SIG_SS7) {
6420 x = 1;
6421 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6422
6423 dahdi_confmute(p, 0);
6424 p->muting = 0;
6425 restore_gains(p);
6426 if (p->dsp) {
6427 ast_dsp_free(p->dsp);
6428 p->dsp = NULL;
6429 }
6430 p->ignoredtmf = 0;
6431
6432 /* Real channel, do some fixup */
6433 p->subs[SUB_REAL].owner = NULL;
6434 p->subs[SUB_REAL].needbusy = 0;
6436
6437 p->owner = NULL;
6438 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6439 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6440 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6441 p->outgoing = 0;
6442 p->digital = 0;
6443 p->faxhandled = 0;
6444 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6445
6446 revert_fax_buffers(p, ast);
6447
6448 p->law = p->law_default;
6449 law = p->law_default;
6450 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6451 if (res < 0) {
6452 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6453 p->channel, strerror(errno));
6454 }
6455
6456 sig_ss7_hangup(p->sig_pvt, ast);
6457
6458 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6460
6461 x = 0;
6462 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6463 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6464
6466 reset_conf(p);
6467
6468 /* Restore data mode */
6469 x = 0;
6470 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6471
6472 if (num_restart_pending == 0) {
6474 }
6475 goto hangup_out;
6476 }
6477#endif /* defined(HAVE_SS7) */
6478
6479 idx = dahdi_get_index(ast, p, 1);
6480
6481 dahdi_confmute(p, 0);
6482 p->muting = 0;
6483 restore_gains(p);
6484 if (p->origcid_num) {
6485 ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
6487 p->origcid_num = NULL;
6488 }
6489 if (p->origcid_name) {
6490 ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
6492 p->origcid_name = NULL;
6493 }
6494 if (p->dsp)
6496
6497 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
6498 p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
6499 p->ignoredtmf = 0;
6500
6501 if (idx > -1) {
6502 /* Real channel, do some fixup */
6503 p->subs[idx].owner = NULL;
6504 p->subs[idx].needanswer = 0;
6505 p->subs[idx].needflash = 0;
6506 p->subs[idx].needringing = 0;
6507 p->subs[idx].needbusy = 0;
6508 p->subs[idx].needcongestion = 0;
6509 p->subs[idx].linear = 0;
6511 dahdi_setlinear(p->subs[idx].dfd, 0);
6512 if (idx == SUB_REAL) {
6513 if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
6514 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
6515 if (p->subs[SUB_CALLWAIT].inthreeway) {
6516 /* We had flipped over to answer a callwait and now it's gone */
6517 ast_debug(1, "We were flipped over to the callwait, moving back and not owning.\n");
6518 /* Move to the call-wait, but un-own us until they flip back. */
6521 p->owner = NULL;
6522 } else {
6523 /* The three way hung up, but we still have a call wait */
6524 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
6527 if (p->subs[SUB_REAL].inthreeway) {
6528 /* This was part of a three way call. Immediately make way for
6529 another call */
6530 ast_debug(1, "Call was complete, setting owner to former third call\n");
6531 p->owner = p->subs[SUB_REAL].owner;
6532 } else {
6533 /* This call hasn't been completed yet... Set owner to NULL */
6534 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6535 p->owner = NULL;
6536 }
6537 p->subs[SUB_REAL].inthreeway = 0;
6538 }
6539 } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
6540 /* Move to the call-wait and switch back to them. */
6543 p->owner = p->subs[SUB_REAL].owner;
6545 p->subs[SUB_REAL].needanswer = 1;
6547 } else if (p->subs[SUB_THREEWAY].dfd > -1) {
6550 if (p->subs[SUB_REAL].inthreeway) {
6551 /* This was part of a three way call. Immediately make way for
6552 another call */
6553 ast_debug(1, "Call was complete, setting owner to former third call\n");
6554 p->owner = p->subs[SUB_REAL].owner;
6555 } else {
6556 /* This call hasn't been completed yet... Set owner to NULL */
6557 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6558 p->owner = NULL;
6559 }
6560 p->subs[SUB_REAL].inthreeway = 0;
6561 }
6562 } else if (idx == SUB_CALLWAIT) {
6563 /* Ditch the holding callwait call, and immediately make it available */
6564 if (p->subs[SUB_CALLWAIT].inthreeway) {
6565 /* This is actually part of a three way, placed on hold. Place the third part
6566 on music on hold now */
6567 if (p->subs[SUB_THREEWAY].owner) {
6569 }
6571 /* Make it the call wait now */
6574 } else
6576 } else if (idx == SUB_THREEWAY) {
6577 if (p->subs[SUB_CALLWAIT].inthreeway) {
6578 /* The other party of the three way call is currently in a call-wait state.
6579 Start music on hold for them, and take the main guy out of the third call */
6580 if (p->subs[SUB_CALLWAIT].owner) {
6582 }
6584 }
6585 p->subs[SUB_REAL].inthreeway = 0;
6586 /* If this was part of a three way call index, let us make
6587 another three way call */
6589 } else {
6590 /* This wasn't any sort of call, but how are we an index? */
6591 ast_log(LOG_WARNING, "Index found but not any type of call?\n");
6592 }
6593 }
6594
6595 if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
6596 p->owner = NULL;
6597 p->ringt = 0;
6598 p->distinctivering = 0;
6599 p->confirmanswer = 0;
6600 p->outgoing = 0;
6601 p->digital = 0;
6602 p->faxhandled = 0;
6603 p->pulsedial = 0;
6604 if (p->dsp) {
6605 ast_dsp_free(p->dsp);
6606 p->dsp = NULL;
6607 }
6608
6609 revert_fax_buffers(p, ast);
6610
6611 p->law = p->law_default;
6612 law = p->law_default;
6613 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6614 if (res < 0)
6615 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
6616 /* Perform low level hangup if no owner left */
6617#ifdef HAVE_OPENR2
6618 if (p->mfcr2 && p->mfcr2call && openr2_chan_get_direction(p->r2chan) != OR2_DIR_STOPPED) {
6619 ast_debug(1, "disconnecting MFC/R2 call on chan %d\n", p->channel);
6620 /* If it's an incoming call, check the mfcr2_forced_release setting */
6621 if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
6622 dahdi_r2_disconnect_call(p, OR2_CAUSE_FORCED_RELEASE);
6623 } else {
6624 const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
6625 int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
6626 openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
6627 : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast));
6628 dahdi_r2_disconnect_call(p, r2cause);
6629 }
6630 } else if (p->mfcr2call) {
6631 ast_debug(1, "Clearing call request on channel %d\n", p->channel);
6632 /* since ast_request() was called but not ast_call() we have not yet dialed
6633 and the openr2 stack will not call on_call_end callback, we need to unset
6634 the mfcr2call flag and bump the monitor count so the monitor thread can take
6635 care of this channel events from now on */
6636 p->mfcr2call = 0;
6637 }
6638#endif
6639 switch (p->sig) {
6640 case SIG_SS7:
6641 case SIG_MFCR2:
6643 case 0:
6644 break;
6645 default:
6646 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
6647 break;
6648 }
6649 if (res < 0) {
6650 ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast_channel_name(ast));
6651 }
6652 switch (p->sig) {
6653 case SIG_FXOGS:
6654 case SIG_FXOLS:
6655 case SIG_FXOKS:
6656 memset(&par, 0, sizeof(par));
6657 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
6658 if (!res) {
6659 struct analog_pvt *analog_p = p->sig_pvt;
6660#if 0
6661 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
6662#endif
6663 /* If they're off hook, try playing congestion */
6664 if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
6665 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
6666 else
6667 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6668 analog_p->fxsoffhookstate = par.rxisoffhook;
6669 }
6670 break;
6671 case SIG_FXSGS:
6672 case SIG_FXSLS:
6673 case SIG_FXSKS:
6674 /* Make sure we're not made available for at least two seconds assuming
6675 we were actually used for an inbound or outbound call. */
6677 time(&p->guardtime);
6678 p->guardtime += 2;
6679 }
6680 break;
6681 default:
6682 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6683 break;
6684 }
6685 if (p->sig)
6687 x = 0;
6688 ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
6689 ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
6690 p->didtdd = 0;
6691 p->callwaitcas = 0;
6694 p->waitingfordt.tv_sec = 0;
6695 p->dialing = 0;
6696 p->rdnis[0] = '\0';
6698 reset_conf(p);
6699 /* Restore data mode */
6700 switch (p->sig) {
6702 case SIG_SS7:
6703 x = 0;
6704 ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
6705 break;
6706 default:
6707 break;
6708 }
6709 if (num_restart_pending == 0)
6711 }
6712
6713 p->callwaitingrepeat = 0;
6714 p->cidcwexpire = 0;
6715 p->cid_suppress_expire = 0;
6716 p->oprmode = 0;
6717hangup_out:
6719 ast_free(p->cidspill);
6720 p->cidspill = NULL;
6721
6722 if (p->reoriginate && p->sig == SIG_FXOKS && dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6723 /* Automatic reorigination: if all calls towards a user have hung up,
6724 * give dial tone again, so user doesn't need to cycle the hook state manually. */
6725 if (my_is_off_hook(p) && !p->owner) {
6726 /* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
6727 ast_debug(1, "Queuing reorigination for channel %d\n", p->channel);
6728 my_play_tone(p, SUB_REAL, -1); /* Stop any congestion tone that may be present. */
6729 /* Must wait for the loop disconnect to end.
6730 * Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
6731 * Calling usleep on an active DAHDI channel is a no-no, but this is okay.
6732 */
6733 usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
6734 /* If the line is still off-hook and ownerless, actually queue the reorigination.
6735 * do_monitor will actually go ahead and do it. */
6736 if (!p->owner && my_is_off_hook(p)) {
6737 p->doreoriginate = 1; /* Tell do_monitor to reoriginate this channel */
6738 /* Note, my_off_hook will fail if called before the loop disconnect has finished
6739 * (important for FXOKS signaled channels). This is because DAHDI will reject
6740 * DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
6741 * so we have to wait for that to finish (see comment above).
6742 * do_monitor itself cannot block, so make the blocking usleep call
6743 * here in the channel thread instead.
6744 */
6745 my_off_hook(p); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
6746 } else {
6747 ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p->channel);
6748 }
6749 }
6750 }
6751
6753 ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
6754
6756 if (p->restartpending) {
6758 }
6759
6760 if (p->destroy) {
6761 destroy_channel(p, 0);
6762 }
6764
6766 return 0;
6767}
6768
6769static int dahdi_answer(struct ast_channel *ast)
6770{
6771 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6772 int res = 0;
6773 int idx;
6774 ast_setstate(ast, AST_STATE_UP);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
6775 ast_mutex_lock(&p->lock);
6776 idx = dahdi_get_index(ast, p, 0);
6777 if (idx < 0)
6778 idx = SUB_REAL;
6779 /* nothing to do if a radio channel */
6780 if ((p->radio || (p->oprmode < 0))) {
6782 return 0;
6783 }
6784
6785 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
6786 res = analog_answer(p->sig_pvt, ast);
6788 return res;
6789 }
6790
6791 switch (p->sig) {
6792#if defined(HAVE_PRI)
6794 res = sig_pri_answer(p->sig_pvt, ast);
6795 break;
6796#endif /* defined(HAVE_PRI) */
6797#if defined(HAVE_SS7)
6798 case SIG_SS7:
6799 res = sig_ss7_answer(p->sig_pvt, ast);
6800 break;
6801#endif /* defined(HAVE_SS7) */
6802#ifdef HAVE_OPENR2
6803 case SIG_MFCR2:
6804 if (!p->mfcr2_call_accepted) {
6805 /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
6806 openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
6807 p->mfcr2_answer_pending = 1;
6808 if (p->mfcr2_charge_calls) {
6809 ast_debug(1, "Accepting MFC/R2 call with charge before answering on chan %d\n", p->channel);
6810 openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
6811 } else {
6812 ast_debug(1, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p->channel);
6813 openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
6814 }
6815 } else {
6816 ast_debug(1, "Answering MFC/R2 call on chan %d\n", p->channel);
6817 dahdi_r2_answer(p);
6818 }
6819 break;
6820#endif
6821 case 0:
6823 return 0;
6824 default:
6825 ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
6826 res = -1;
6827 break;
6828 }
6830 return res;
6831}
6832
6834{
6835 int val = 0;
6836
6837 p->ignoredtmf = 1;
6838
6839 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6840
6841 if (!p->hardwaredtmf && p->dsp) {
6842 p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
6844 }
6845}
6846
6848{
6849 int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
6850
6851 if (p->channel == CHAN_PSEUDO)
6852 return;
6853
6854 p->ignoredtmf = 0;
6855
6856 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6857
6858 if (!p->hardwaredtmf && p->dsp) {
6861 }
6862}
6863
6864static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
6865{
6866 char *cp;
6867 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
6868
6869 /* all supported options require data */
6870 if (!p || !data || (*datalen < 1)) {
6871 errno = EINVAL;
6872 return -1;
6873 }
6874
6875 switch (option) {
6876 case AST_OPTION_TDD:
6877 cp = (char *) data;
6878 if (p->mate) {
6879 *cp = 2;
6880 } else {
6881 *cp = p->tdd ? 1 : 0;
6882 }
6883 break;
6885 cp = (char *) data;
6886 *cp = p->ignoredtmf ? 0 : 1;
6887 ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6888 break;
6890 cp = (char *) data;
6891 *cp = (p->dsp_features & DSP_FEATURE_FAX_DETECT) ? 0 : 1;
6892 ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6893 break;
6895#if defined(HAVE_PRI)
6896#if defined(HAVE_PRI_CCSS)
6898 ast_copy_string((char *) data, dahdi_pri_cc_type, *datalen);
6899 break;
6900 }
6901#endif /* defined(HAVE_PRI_CCSS) */
6902#endif /* defined(HAVE_PRI) */
6903 return -1;
6904 default:
6905 return -1;
6906 }
6907
6908 errno = 0;
6909
6910 return 0;
6911}
6912
6913static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
6914{
6915 char *cp;
6916 signed char *scp;
6917 int x;
6918 int idx;
6919 struct dahdi_pvt *p = ast_channel_tech_pvt(chan), *pp;
6920 struct oprmode *oprmode;
6921
6922
6923 /* all supported options require data */
6924 if (!p || !data || (datalen < 1)) {
6925 errno = EINVAL;
6926 return -1;
6927 }
6928
6929 switch (option) {
6930 case AST_OPTION_TXGAIN:
6931 scp = (signed char *) data;
6932 idx = dahdi_get_index(chan, p, 0);
6933 if (idx < 0) {
6934 ast_log(LOG_WARNING, "No index in TXGAIN?\n");
6935 return -1;
6936 }
6937 ast_debug(1, "Setting actual tx gain on %s to %f\n", ast_channel_name(chan), p->txgain + (float) *scp);
6938 return set_actual_txgain(p->subs[idx].dfd, p->txgain + (float) *scp, p->txdrc, p->law);
6939 case AST_OPTION_RXGAIN:
6940 scp = (signed char *) data;
6941 idx = dahdi_get_index(chan, p, 0);
6942 if (idx < 0) {
6943 ast_log(LOG_WARNING, "No index in RXGAIN?\n");
6944 return -1;
6945 }
6946 ast_debug(1, "Setting actual rx gain on %s to %f\n", ast_channel_name(chan), p->rxgain + (float) *scp);
6947 return set_actual_rxgain(p->subs[idx].dfd, p->rxgain + (float) *scp, p->rxdrc, p->law);
6949 if (!p->dsp)
6950 break;
6951 cp = (char *) data;
6952 switch (*cp) {
6953 case 1:
6954 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",ast_channel_name(chan));
6955 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */
6956 break;
6957 case 2:
6958 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",ast_channel_name(chan));
6959 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */
6960 break;
6961 default:
6962 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",ast_channel_name(chan));
6963 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */
6964 break;
6965 }
6966 break;
6967 case AST_OPTION_TDD:
6968 /* turn on or off TDD */
6969 cp = (char *) data;
6970 p->mate = 0;
6971 if (!*cp) { /* turn it off */
6972 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",ast_channel_name(chan));
6973 if (p->tdd)
6974 tdd_free(p->tdd);
6975 p->tdd = 0;
6976 break;
6977 }
6978 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
6979 (*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
6981 /* otherwise, turn it on */
6982 if (!p->didtdd) { /* if haven't done it yet */
6983 unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
6984 unsigned char *buf;
6985 int size, res, fd, len;
6986 struct pollfd fds[1];
6987
6988 buf = mybuf;
6989 memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
6990 ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */
6991 len = 40000;
6992 idx = dahdi_get_index(chan, p, 0);
6993 if (idx < 0) {
6994 ast_log(LOG_WARNING, "No index in TDD?\n");
6995 return -1;
6996 }
6997 fd = p->subs[idx].dfd;
6998 while (len) {
6999 if (ast_check_hangup(chan))
7000 return -1;
7001 size = len;
7002 if (size > READ_SIZE)
7003 size = READ_SIZE;
7004 fds[0].fd = fd;
7005 fds[0].events = POLLPRI | POLLOUT;
7006 fds[0].revents = 0;
7007 res = poll(fds, 1, -1);
7008 if (!res) {
7009 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
7010 continue;
7011 }
7012 /* if got exception */
7013 if (fds[0].revents & POLLPRI)
7014 return -1;
7015 if (!(fds[0].revents & POLLOUT)) {
7016 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
7017 continue;
7018 }
7019 res = write(fd, buf, size);
7020 if (res != size) {
7021 if (res == -1) return -1;
7022 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
7023 break;
7024 }
7025 len -= size;
7026 buf += size;
7027 }
7028 p->didtdd = 1; /* set to have done it now */
7029 }
7030 if (*cp == 2) { /* Mate mode */
7031 if (p->tdd)
7032 tdd_free(p->tdd);
7033 p->tdd = 0;
7034 p->mate = 1;
7035 break;
7036 }
7037 if (!p->tdd) { /* if we don't have one yet */
7038 p->tdd = tdd_new(); /* allocate one */
7039 }
7040 break;
7041 case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */
7042 if (!p->dsp)
7043 break;
7044 cp = (char *) data;
7045 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
7046 *cp ? "ON" : "OFF", (int) *cp, ast_channel_name(chan));
7048 break;
7049 case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */
7050#if defined(HAVE_PRI)
7052 && ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
7053 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
7054 break;
7055 }
7056#endif /* defined(HAVE_PRI) */
7057
7058 cp = (char *) data;
7059 if (!*cp) {
7060 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
7061 x = 0;
7063 } else {
7064 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
7065 x = 1;
7066 }
7067 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
7068 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
7069 break;
7070 case AST_OPTION_OPRMODE: /* Operator services mode */
7071 oprmode = (struct oprmode *) data;
7072 /* We don't support operator mode across technologies */
7073 if (strcasecmp(ast_channel_tech(chan)->type, ast_channel_tech(oprmode->peer)->type)) {
7074 ast_log(LOG_NOTICE, "Operator mode not supported on %s to %s calls.\n",
7076 errno = EINVAL;
7077 return -1;
7078 }
7080 p->oprmode = pp->oprmode = 0;
7081 /* setup peers */
7082 p->oprpeer = pp;
7083 pp->oprpeer = p;
7084 /* setup modes, if any */
7085 if (oprmode->mode)
7086 {
7087 pp->oprmode = oprmode->mode;
7088 p->oprmode = -oprmode->mode;
7089 }
7090 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
7092 break;
7093 case AST_OPTION_ECHOCAN:
7094 cp = (char *) data;
7095 if (*cp) {
7096 ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
7097 dahdi_ec_enable(p);
7098 } else {
7099 ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
7101 }
7102 break;
7104 cp = (char *) data;
7105 ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7106 if (*cp) {
7108 } else {
7110 }
7111 break;
7113 cp = (char *) data;
7114 if (p->dsp) {
7115 ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7116 if (*cp) {
7118 } else {
7119 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7120 }
7122 }
7123 break;
7124 default:
7125 return -1;
7126 }
7127 errno = 0;
7128
7129 return 0;
7130}
7131
7132static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
7133{
7134 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7135 int res = 0;
7136
7137 if (!p) {
7138 /* No private structure! */
7139 *buf = '\0';
7140 return -1;
7141 }
7142
7143 if (!strcasecmp(data, "rxgain")) {
7144 ast_mutex_lock(&p->lock);
7145 snprintf(buf, len, "%f", p->rxgain);
7147 } else if (!strcasecmp(data, "txgain")) {
7148 ast_mutex_lock(&p->lock);
7149 snprintf(buf, len, "%f", p->txgain);
7151 } else if (!strcasecmp(data, "dahdi_channel")) {
7152 ast_mutex_lock(&p->lock);
7153 snprintf(buf, len, "%d", p->channel);
7155 } else if (!strcasecmp(data, "dahdi_span")) {
7156 ast_mutex_lock(&p->lock);
7157 snprintf(buf, len, "%d", p->span);
7159 } else if (!strcasecmp(data, "dahdi_group")) {
7160 ast_mutex_lock(&p->lock);
7161 snprintf(buf, len, "%llu", p->group);
7163 } else if (!strcasecmp(data, "dahdi_type")) {
7164 ast_mutex_lock(&p->lock);
7165 switch (p->sig) {
7166#if defined(HAVE_OPENR2)
7167 case SIG_MFCR2:
7168 ast_copy_string(buf, "mfc/r2", len);
7169 break;
7170#endif /* defined(HAVE_OPENR2) */
7171#if defined(HAVE_PRI)
7173 ast_copy_string(buf, "pri", len);
7174 break;
7175#endif /* defined(HAVE_PRI) */
7176 case 0:
7177 ast_copy_string(buf, "pseudo", len);
7178 break;
7179#if defined(HAVE_SS7)
7180 case SIG_SS7:
7181 ast_copy_string(buf, "ss7", len);
7182 break;
7183#endif /* defined(HAVE_SS7) */
7184 default:
7185 /* The only thing left is analog ports. */
7186 ast_copy_string(buf, "analog", len);
7187 break;
7188 }
7190#if defined(HAVE_PRI)
7191#if defined(HAVE_PRI_REVERSE_CHARGE)
7192 } else if (!strcasecmp(data, "reversecharge")) {
7193 ast_mutex_lock(&p->lock);
7194 switch (p->sig) {
7196 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->reverse_charging_indication);
7197 break;
7198 default:
7199 *buf = '\0';
7200 res = -1;
7201 break;
7202 }
7204#endif
7205#if defined(HAVE_PRI_SETUP_KEYPAD)
7206 } else if (!strcasecmp(data, "keypad_digits")) {
7207 ast_mutex_lock(&p->lock);
7208 switch (p->sig) {
7210 ast_copy_string(buf, ((struct sig_pri_chan *) p->sig_pvt)->keypad_digits,
7211 len);
7212 break;
7213 default:
7214 *buf = '\0';
7215 res = -1;
7216 break;
7217 }
7219#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
7220 } else if (!strcasecmp(data, "no_media_path")) {
7221 ast_mutex_lock(&p->lock);
7222 switch (p->sig) {
7224 /*
7225 * TRUE if the call is on hold or is call waiting because
7226 * there is no media path available.
7227 */
7228 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel);
7229 break;
7230 default:
7231 *buf = '\0';
7232 res = -1;
7233 break;
7234 }
7236#endif /* defined(HAVE_PRI) */
7237 } else if (!strcasecmp(data, "dialmode")) {
7238 struct analog_pvt *analog_p;
7239 ast_mutex_lock(&p->lock);
7240 analog_p = p->sig_pvt;
7241 /* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
7242 if (dahdi_analog_lib_handles(p->sig, 0, 0) && analog_p) {
7243 switch (analog_p->dialmode) {
7245 ast_copy_string(buf, "both", len);
7246 break;
7248 ast_copy_string(buf, "pulse", len);
7249 break;
7251 ast_copy_string(buf, "dtmf", len);
7252 break;
7254 ast_copy_string(buf, "none", len);
7255 break;
7256 }
7257 } else {
7258 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7259 *buf = '\0';
7260 res = -1;
7261 }
7263 } else {
7264 *buf = '\0';
7265 res = -1;
7266 }
7267
7268 return res;
7269}
7270
7271
7272static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
7273{
7274 int res;
7275 char policy_str[21] = "";
7276
7277 if ((res = sscanf(parse, "%30d,%20s", num_buffers, policy_str)) != 2) {
7278 ast_log(LOG_WARNING, "Parsing buffer string '%s' failed.\n", parse);
7279 return 1;
7280 }
7281 if (*num_buffers < 0) {
7282 ast_log(LOG_WARNING, "Invalid buffer count given '%d'.\n", *num_buffers);
7283 return -1;
7284 }
7285 if (!strcasecmp(policy_str, "full")) {
7286 *policy = DAHDI_POLICY_WHEN_FULL;
7287 } else if (!strcasecmp(policy_str, "immediate")) {
7288 *policy = DAHDI_POLICY_IMMEDIATE;
7289#if defined(HAVE_DAHDI_HALF_FULL)
7290 } else if (!strcasecmp(policy_str, "half")) {
7291 *policy = DAHDI_POLICY_HALF_FULL;
7292#endif
7293 } else {
7294 ast_log(LOG_WARNING, "Invalid policy name given '%s'.\n", policy_str);
7295 return -1;
7296 }
7297
7298 return 0;
7299}
7300
7301static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
7302{
7303 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7304 int res = 0;
7305
7306 if (!p) {
7307 /* No private structure! */
7308 return -1;
7309 }
7310
7311 if (!strcasecmp(data, "buffers")) {
7312 int num_bufs, policy;
7313
7314 if (!(parse_buffers_policy(value, &num_bufs, &policy))) {
7315 struct dahdi_bufferinfo bi = {
7316 .txbufpolicy = policy,
7317 .rxbufpolicy = policy,
7318 .bufsize = p->bufsize,
7319 .numbufs = num_bufs,
7320 };
7321 int bpres;
7322
7323 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7324 ast_log(LOG_WARNING, "Channel '%d' unable to override buffer policy: %s\n", p->channel, strerror(errno));
7325 } else {
7326 p->bufferoverrideinuse = 1;
7327 }
7328 } else {
7329 res = -1;
7330 }
7331 } else if (!strcasecmp(data, "echocan_mode")) {
7332 if (!strcasecmp(value, "on")) {
7333 ast_mutex_lock(&p->lock);
7334 dahdi_ec_enable(p);
7336 } else if (!strcasecmp(value, "off")) {
7337 ast_mutex_lock(&p->lock);
7340#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7341 } else if (!strcasecmp(value, "fax")) {
7342 int blah = 1;
7343
7344 ast_mutex_lock(&p->lock);
7345 if (!p->echocanon) {
7346 dahdi_ec_enable(p);
7347 }
7348 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7349 ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
7350 }
7352 } else if (!strcasecmp(value, "voice")) {
7353 int blah = 0;
7354
7355 ast_mutex_lock(&p->lock);
7356 if (!p->echocanon) {
7357 dahdi_ec_enable(p);
7358 }
7359 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7360 ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
7361 }
7363#endif
7364 } else {
7365 ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
7366 res = -1;
7367 }
7368 } else if (!strcasecmp(data, "dialmode")) {
7369 struct analog_pvt *analog_p;
7370
7371 ast_mutex_lock(&p->lock);
7372 analog_p = p->sig_pvt;
7373 if (!dahdi_analog_lib_handles(p->sig, 0, 0) || !analog_p) {
7374 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7376 return -1;
7377 }
7378 /* analog pvt is used for pulse dialing, so update both */
7379 if (!strcasecmp(value, "pulse")) {
7380 p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_PULSE;
7381 } else if (!strcasecmp(value, "dtmf") || !strcasecmp(value, "tone")) {
7382 p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_DTMF;
7383 } else if (!strcasecmp(value, "none")) {
7384 p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_NONE;
7385 } else if (!strcasecmp(value, "both")) {
7386 p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_BOTH;
7387 } else {
7388 ast_log(LOG_WARNING, "'%s' is an invalid setting for %s\n", value, data);
7389 res = -1;
7390 }
7392 } else if (!strcasecmp(data, "waitfordialtone")) {
7393 if (ast_strlen_zero(value)) {
7394 ast_log(LOG_WARNING, "waitfordialtone requires a duration in ms\n");
7395 return -1;
7396 }
7397
7398 ast_mutex_lock(&p->lock);
7399 if (!CANPROGRESSDETECT(p)) {
7400 ast_log(LOG_WARNING, "%s only supported on analog trunks\n", data);
7402 return -1;
7403 }
7404 /* Only set the temp waitfordialtone setting, not the permanent one. */
7405 p->waitfordialtonetemp = atoi(value);
7407 } else {
7408 res = -1;
7409 }
7410
7411 return res;
7412}
7413
7414void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
7415{
7416 /* Unlink a specific slave or all slaves/masters from a given master */
7417 int x;
7418 int hasslaves;
7419 if (!master)
7420 return;
7421 if (needlock) {
7422 ast_mutex_lock(&master->lock);
7423 if (slave) {
7424 while (ast_mutex_trylock(&slave->lock)) {
7425 DEADLOCK_AVOIDANCE(&master->lock);
7426 }
7427 }
7428 }
7429 hasslaves = 0;
7430 for (x = 0; x < MAX_SLAVES; x++) {
7431 if (master->slaves[x]) {
7432 if (!slave || (master->slaves[x] == slave)) {
7433 /* Take slave out of the conference */
7434 ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
7435 conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
7436 conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
7437 master->slaves[x]->master = NULL;
7438 master->slaves[x] = NULL;
7439 } else
7440 hasslaves = 1;
7441 }
7442 if (!hasslaves)
7443 master->inconference = 0;
7444 }
7445 if (!slave) {
7446 if (master->master) {
7447 /* Take master out of the conference */
7448 conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
7449 conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
7450 hasslaves = 0;
7451 for (x = 0; x < MAX_SLAVES; x++) {
7452 if (master->master->slaves[x] == master)
7453 master->master->slaves[x] = NULL;
7454 else if (master->master->slaves[x])
7455 hasslaves = 1;
7456 }
7457 if (!hasslaves)
7458 master->master->inconference = 0;
7459 }
7460 master->master = NULL;
7461 }
7462 dahdi_conf_update(master);
7463 if (needlock) {
7464 if (slave)
7465 ast_mutex_unlock(&slave->lock);
7466 ast_mutex_unlock(&master->lock);
7467 }
7468}
7469
7470void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
7471{
7472 int x;
7473 if (!slave || !master) {
7474 ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
7475 return;
7476 }
7477 for (x = 0; x < MAX_SLAVES; x++) {
7478 if (!master->slaves[x]) {
7479 master->slaves[x] = slave;
7480 break;
7481 }
7482 }
7483 if (x >= MAX_SLAVES) {
7484 ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
7485 master->slaves[MAX_SLAVES - 1] = slave;
7486 }
7487 if (slave->master)
7488 ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
7489 slave->master = master;
7490
7491 ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
7492}
7493
7494static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
7495{
7496 struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
7497 int x;
7498
7499 ast_mutex_lock(&p->lock);
7500
7501 ast_debug(1, "New owner for channel %d is %s\n", p->channel, ast_channel_name(newchan));
7502 if (p->owner == oldchan) {
7503 p->owner = newchan;
7504 }
7505 for (x = 0; x < 3; x++) {
7506 if (p->subs[x].owner == oldchan) {
7507 if (!x) {
7509 }
7510 p->subs[x].owner = newchan;
7511 }
7512 }
7513 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
7514 analog_fixup(oldchan, newchan, p->sig_pvt);
7515#if defined(HAVE_PRI)
7516 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
7517 sig_pri_fixup(oldchan, newchan, p->sig_pvt);
7518#endif /* defined(HAVE_PRI) */
7519#if defined(HAVE_SS7)
7520 } else if (p->sig == SIG_SS7) {
7521 sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
7522#endif /* defined(HAVE_SS7) */
7523 }
7525
7527
7528 if (ast_channel_state(newchan) == AST_STATE_RINGING) {
7530 }
7531 return 0;
7532}
7533
7534static int dahdi_ring_phone(struct dahdi_pvt *p)
7535{
7536 int x;
7537 int res;
7538 /* Make sure our transmit state is on hook */
7539 x = 0;
7540 x = DAHDI_ONHOOK;
7541 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7542 do {
7543 x = DAHDI_RING;
7544 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7545 if (res) {
7546 switch (errno) {
7547 case EBUSY:
7548 case EINTR:
7549 /* Wait just in case */
7550 usleep(10000);
7551 continue;
7552 case EINPROGRESS:
7553 res = 0;
7554 break;
7555 default:
7556 ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
7557 res = 0;
7558 }
7559 }
7560 } while (res);
7561 return res;
7562}
7563
7564static void *analog_ss_thread(void *data);
7565
7566/*!
7567 * \internal
7568 * \brief Attempt to transfer 3-way call.
7569 *
7570 * \param p DAHDI private structure.
7571 *
7572 * \note On entry these locks are held: real-call, private, 3-way call.
7573 * \note On exit these locks are held: real-call, private.
7574 *
7575 * \retval 0 on success.
7576 * \retval -1 on error.
7577 */
7578static int attempt_transfer(struct dahdi_pvt *p)
7579{
7580 struct ast_channel *owner_real;
7581 struct ast_channel *owner_3way;
7582 enum ast_transfer_result xfer_res;
7583 int res = 0;
7584
7585 owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
7586 owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
7587
7588 ast_verb(3, "TRANSFERRING %s to %s\n",
7589 ast_channel_name(owner_3way), ast_channel_name(owner_real));
7590
7591 ast_channel_unlock(owner_real);
7592 ast_channel_unlock(owner_3way);
7594
7595 xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
7596 if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
7598 res = -1;
7599 }
7600
7601 /* Must leave with these locked. */
7602 ast_channel_lock(owner_real);
7603 ast_mutex_lock(&p->lock);
7604
7605 ast_channel_unref(owner_real);
7606 ast_channel_unref(owner_3way);
7607
7608 return res;
7609}
7610
7611static int check_for_conference(struct dahdi_pvt *p)
7612{
7613 struct dahdi_confinfo ci;
7614 /* Fine if we already have a master, etc */
7615 if (p->master || (p->confno > -1))
7616 return 0;
7617 memset(&ci, 0, sizeof(ci));
7618 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
7619 ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
7620 return 0;
7621 }
7622 /* If we have no master and don't have a confno, then
7623 if we're in a conference, it's probably a MeetMe room or
7624 some such, so don't let us 3-way out! */
7625 if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
7626 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
7627 return 1;
7628 }
7629 return 0;
7630}
7631
7632/*! Checks channel for alarms
7633 * \param p a channel to check for alarms.
7634 * \returns the alarms on the span to which the channel belongs, or alarms on
7635 * the channel if no span alarms.
7636 */
7637static int get_alarms(struct dahdi_pvt *p)
7638{
7639 int res;
7640 struct dahdi_spaninfo zi;
7641 struct dahdi_params params;
7642
7643 memset(&zi, 0, sizeof(zi));
7644 zi.spanno = p->span;
7645
7646 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
7647 if (zi.alarms != DAHDI_ALARM_NONE)
7648 return zi.alarms;
7649 } else {
7650 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
7651 return 0;
7652 }
7653
7654 /* No alarms on the span. Check for channel alarms. */
7655 memset(&params, 0, sizeof(params));
7656 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
7657 return params.chan_alarms;
7658
7659 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
7660
7661 return DAHDI_ALARM_NONE;
7662}
7663
7664static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
7665{
7666 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7667 struct ast_frame *f = *dest;
7668
7669 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
7670 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
7671 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
7672
7673 if (p->confirmanswer) {
7674 if (f->frametype == AST_FRAME_DTMF_END) {
7675 ast_debug(1, "Confirm answer on %s!\n", ast_channel_name(ast));
7676 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
7677 of a DTMF digit */
7680 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
7681 p->confirmanswer = 0;
7682 } else {
7683 p->subs[idx].f.frametype = AST_FRAME_NULL;
7684 p->subs[idx].f.subclass.integer = 0;
7685 }
7686 *dest = &p->subs[idx].f;
7687 } else if (p->callwaitcas) {
7688 if (f->frametype == AST_FRAME_DTMF_END) {
7689 if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
7690 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
7691 ast_free(p->cidspill);
7692 p->cidspill = NULL;
7693 send_cwcidspill(p);
7694 }
7695 p->callwaitcas = 0;
7696 }
7697 p->subs[idx].f.frametype = AST_FRAME_NULL;
7698 p->subs[idx].f.subclass.integer = 0;
7699 *dest = &p->subs[idx].f;
7700 } else if (f->subclass.integer == 'f') {
7701 if (f->frametype == AST_FRAME_DTMF_END) {
7702 /* Fax tone -- Handle and return NULL */
7703 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
7704 /* If faxbuffers are configured, use them for the fax transmission */
7705 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
7706 struct dahdi_bufferinfo bi = {
7707 .txbufpolicy = p->faxbuf_policy,
7708 .bufsize = p->bufsize,
7709 .numbufs = p->faxbuf_no
7710 };
7711 int res;
7712
7713 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7714 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
7715 } else {
7716 p->bufferoverrideinuse = 1;
7717 }
7718 }
7719 p->faxhandled = 1;
7720 if (p->dsp) {
7721 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7723 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
7724 }
7725 if (strcmp(ast_channel_exten(ast), "fax")) {
7726 const char *target_context = ast_channel_context(ast);
7727
7728 /*
7729 * We need to unlock 'ast' here because ast_exists_extension has the
7730 * potential to start autoservice on the channel. Such action is prone
7731 * to deadlock if the channel is locked.
7732 *
7733 * ast_async_goto() has its own restriction on not holding the
7734 * channel lock.
7735 */
7737 ast_channel_unlock(ast);
7738 if (ast_exists_extension(ast, target_context, "fax", 1,
7739 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
7740 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
7741 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
7742 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
7743 if (ast_async_goto(ast, target_context, "fax", 1))
7744 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
7745 } else {
7746 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
7747 }
7748 ast_channel_lock(ast);
7749 ast_mutex_lock(&p->lock);
7750 } else {
7751 ast_debug(1, "Already in a fax extension, not redirecting\n");
7752 }
7753 } else {
7754 ast_debug(1, "Fax already handled\n");
7755 }
7756 dahdi_confmute(p, 0);
7757 }
7758 p->subs[idx].f.frametype = AST_FRAME_NULL;
7759 p->subs[idx].f.subclass.integer = 0;
7760 *dest = &p->subs[idx].f;
7761 }
7762}
7763
7764static void publish_span_alarm(int span, const char *alarm_txt)
7765{
7766 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7767
7768 body = ast_json_pack("{s: i, s: s}",
7769 "Span", span,
7770 "Alarm", alarm_txt);
7771 if (!body) {
7772 return;
7773 }
7774
7775 ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
7776}
7777
7778static void publish_channel_alarm(int channel, const char *alarm_txt)
7779{
7780 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7781 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
7782 if (!dahdi_chan) {
7783 return;
7784 }
7785
7786 ast_str_set(&dahdi_chan, 0, "%d", channel);
7787 body = ast_json_pack("{s: s, s: s}",
7788 "DAHDIChannel", ast_str_buffer(dahdi_chan),
7789 "Alarm", alarm_txt);
7790 if (!body) {
7791 return;
7792 }
7793
7795}
7796
7797static void handle_alarms(struct dahdi_pvt *p, int alms)
7798{
7799 const char *alarm_str;
7800
7801#if defined(HAVE_PRI)
7803 return;
7804 }
7805#endif /* defined(HAVE_PRI) */
7806
7807 alarm_str = alarm2str(alms);
7809 ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
7810 publish_channel_alarm(p->channel, alarm_str);
7811 }
7812
7814 ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
7815 publish_span_alarm(p->span, alarm_str);
7816 }
7817}
7818
7819static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
7820{
7821 int res, x;
7822 int idx, mysig;
7823 char *c;
7824 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7825 pthread_t threadid;
7826 struct ast_channel *chan;
7827 struct ast_frame *f;
7828
7829 idx = dahdi_get_index(ast, p, 0);
7830 if (idx < 0) {
7831 return &ast_null_frame;
7832 }
7833 mysig = p->sig;
7834 if (p->outsigmod > -1)
7835 mysig = p->outsigmod;
7836 p->subs[idx].f.frametype = AST_FRAME_NULL;
7837 p->subs[idx].f.subclass.integer = 0;
7838 p->subs[idx].f.datalen = 0;
7839 p->subs[idx].f.samples = 0;
7840 p->subs[idx].f.mallocd = 0;
7841 p->subs[idx].f.offset = 0;
7842 p->subs[idx].f.src = "dahdi_handle_event";
7843 p->subs[idx].f.data.ptr = NULL;
7844 f = &p->subs[idx].f;
7845
7846 if (p->fake_event) {
7847 res = p->fake_event;
7848 p->fake_event = 0;
7849 } else
7850 res = dahdi_get_event(p->subs[idx].dfd);
7851
7852 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
7853
7854 if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
7855 p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
7856 ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
7857#if defined(HAVE_PRI)
7859 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7860 && p->pri
7861 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7862 /* absorb event */
7863 } else
7864#endif /* defined(HAVE_PRI) */
7865 {
7866 /* Unmute conference */
7867 dahdi_confmute(p, 0);
7869 p->subs[idx].f.subclass.integer = res & 0xff;
7870 dahdi_handle_dtmf(ast, idx, &f);
7871 }
7872 return f;
7873 }
7874
7875 if (res & DAHDI_EVENT_DTMFDOWN) {
7876 ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
7877#if defined(HAVE_PRI)
7879 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7880 && p->pri
7881 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7882 /* absorb event */
7883 } else
7884#endif /* defined(HAVE_PRI) */
7885 {
7886 /* Mute conference */
7887 dahdi_confmute(p, 1);
7889 p->subs[idx].f.subclass.integer = res & 0xff;
7890 dahdi_handle_dtmf(ast, idx, &f);
7891 }
7892 return &p->subs[idx].f;
7893 }
7894
7895 switch (res) {
7896 case DAHDI_EVENT_EC_DISABLED:
7897 ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
7898 p->echocanon = 0;
7899 break;
7900#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7901 case DAHDI_EVENT_TX_CED_DETECTED:
7902 ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
7903 break;
7904 case DAHDI_EVENT_RX_CED_DETECTED:
7905 ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
7906 break;
7907 case DAHDI_EVENT_EC_NLP_DISABLED:
7908 ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
7909 break;
7910 case DAHDI_EVENT_EC_NLP_ENABLED:
7911 ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
7912 break;
7913#endif
7914 case DAHDI_EVENT_BITSCHANGED:
7915#ifdef HAVE_OPENR2
7916 if (p->sig != SIG_MFCR2) {
7917 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7918 } else {
7919 ast_debug(1, "bits changed in chan %d\n", p->channel);
7920 openr2_chan_handle_cas(p->r2chan);
7921 }
7922#else
7923 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7924#endif
7925 break;
7926 case DAHDI_EVENT_PULSE_START:
7927 /* Stop tone if there's a pulse start and the PBX isn't started */
7928 if (!ast_channel_pbx(ast))
7929 tone_zone_play_tone(p->subs[idx].dfd, -1);
7930 break;
7931 case DAHDI_EVENT_DIALCOMPLETE:
7932 /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
7933#if defined(HAVE_PRI)
7935 if (p->inalarm) {
7936 break;
7937 }
7938 if (ioctl(p->subs[idx].dfd, DAHDI_DIALING, &x) == -1) {
7939 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
7940 ast_channel_name(ast), strerror(errno));
7941 return NULL;
7942 }
7943 if (x) {
7944 /* Still dialing in DAHDI driver */
7945 break;
7946 }
7947 /*
7948 * The ast channel is locked and the private may be locked more
7949 * than once.
7950 */
7952 break;
7953 }
7954#endif /* defined(HAVE_PRI) */
7955#ifdef HAVE_OPENR2
7956 if ((p->sig & SIG_MFCR2) && p->r2chan && ast_channel_state(ast) != AST_STATE_UP) {
7957 /* we don't need to do anything for this event for R2 signaling
7958 if the call is being setup */
7959 break;
7960 }
7961#endif
7962 if (p->inalarm) break;
7963 if ((p->radio || (p->oprmode < 0))) break;
7964 if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
7965 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",ast_channel_name(ast), strerror(errno));
7966 return NULL;
7967 }
7968 if (!x) { /* if not still dialing in driver */
7969 dahdi_ec_enable(p);
7970 if (p->echobreak) {
7971 dahdi_train_ec(p);
7972 ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
7973 p->dop.op = DAHDI_DIAL_OP_REPLACE;
7974 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
7975 p->echobreak = 0;
7976 } else {
7977 p->dialing = 0;
7978 if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
7979 /* if thru with dialing after offhook */
7984 break;
7985 } else { /* if to state wait for offhook to dial rest */
7986 /* we now wait for off hook */
7988 }
7989 }
7991 if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
7992 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
7993 } else if (p->confirmanswer || (!p->dialednone
7994 && ((mysig == SIG_EM) || (mysig == SIG_EM_E1)
7995 || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD)
7996 || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF)
7997 || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA)
7998 || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB)
7999 || (mysig == SIG_SF) || (mysig == SIG_SFWINK)
8000 || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF)
8001 || (mysig == SIG_SF_FEATB)))) {
8003 } else if (!p->answeronpolarityswitch) {
8007 /* If aops=0 and hops=1, this is necessary */
8009 } else {
8010 /* Start clean, so we can catch the change to REV polarity when party answers */
8012 }
8013 }
8014 }
8015 }
8016 break;
8017 case DAHDI_EVENT_ALARM:
8018 switch (p->sig) {
8019#if defined(HAVE_PRI)
8022 break;
8023#endif /* defined(HAVE_PRI) */
8024#if defined(HAVE_SS7)
8025 case SIG_SS7:
8027 break;
8028#endif /* defined(HAVE_SS7) */
8029 default:
8030 p->inalarm = 1;
8031 break;
8032 }
8033 res = get_alarms(p);
8034 handle_alarms(p, res);
8035#ifdef HAVE_PRI
8036 if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
8037 /* fall through intentionally */
8038 } else {
8039 break;
8040 }
8041#endif
8042#if defined(HAVE_SS7)
8043 if (p->sig == SIG_SS7)
8044 break;
8045#endif /* defined(HAVE_SS7) */
8046#ifdef HAVE_OPENR2
8047 if (p->sig == SIG_MFCR2)
8048 break;
8049#endif
8050 case DAHDI_EVENT_ONHOOK:
8051 if (p->radio) {
8054 break;
8055 }
8056 if (p->oprmode < 0)
8057 {
8058 if (p->oprmode != -1) { /* Operator flash recall */
8059 ast_verb(4, "Operator mode enabled on channel %d, holding line for channel %d\n", p->channel, p->oprpeer->channel);
8060 break;
8061 }
8062 /* Otherwise, immediate recall */
8063 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
8064 {
8065 /* Make sure it starts ringing */
8066 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8067 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
8069 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8070 ast_verb(4, "Operator recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8071 }
8072 break;
8073 }
8074 switch (p->sig) {
8075 case SIG_FXOLS:
8076 case SIG_FXOGS:
8077 case SIG_FXOKS:
8078 /* Check for some special conditions regarding call waiting */
8079 if (idx == SUB_REAL) {
8080 /* The normal line was hung up */
8081 if (p->subs[SUB_CALLWAIT].owner) {
8082 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
8084 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
8086#if 0
8087 p->subs[idx].needanswer = 0;
8088 p->subs[idx].needringing = 0;
8089#endif
8090 p->callwaitingrepeat = 0;
8091 p->cidcwexpire = 0;
8092 p->cid_suppress_expire = 0;
8093 p->owner = NULL;
8094 /* Don't start streaming audio yet if the incoming call isn't up yet */
8096 p->dialing = 1;
8098 } else if (p->subs[SUB_THREEWAY].owner) {
8099 unsigned int mssinceflash;
8100 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
8101 the private structure -- not especially easy or clean */
8103 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
8104 DLA_UNLOCK(&p->lock);
8106 /* We can grab ast and p in that order, without worry. We should make sure
8107 nothing seriously bad has happened though like some sort of bizarre double
8108 masquerade! */
8109 DLA_LOCK(&p->lock);
8110 if (p->owner != ast) {
8111 ast_log(LOG_WARNING, "This isn't good...\n");
8112 return NULL;
8113 }
8114 }
8115 if (!p->subs[SUB_THREEWAY].owner) {
8116 ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
8117 return NULL;
8118 }
8119 mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
8120 ast_debug(1, "Last flash was %u ms ago\n", mssinceflash);
8121 if (mssinceflash < MIN_MS_SINCE_FLASH) {
8122 /* It hasn't been long enough since the last flashook. This is probably a bounce on
8123 hanging up. Hangup both channels now */
8124 if (p->subs[SUB_THREEWAY].owner)
8127 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
8129 } else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
8130 if (p->transfer) {
8131 /* In any case this isn't a threeway call anymore */
8132 p->subs[SUB_REAL].inthreeway = 0;
8134 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
8135 if (!p->transfertobusy && ast_channel_state(ast) == AST_STATE_BUSY) {
8137 /* Swap subs and dis-own channel */
8139 p->owner = NULL;
8140 /* Ring the phone */
8142 } else if (!attempt_transfer(p)) {
8143 /*
8144 * Transfer successful. Don't actually hang up at this point.
8145 * Let our channel legs of the calls die off as the transfer
8146 * percolates through the core.
8147 */
8148 break;
8149 }
8150 } else {
8152 if (p->subs[SUB_THREEWAY].owner)
8154 }
8155 } else {
8157 /* Swap subs and dis-own channel */
8159 p->owner = NULL;
8160 /* Ring the phone */
8162 }
8163 }
8164 } else {
8165 ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
8166 }
8167 /* Fall through */
8168 default:
8170 return NULL;
8171 }
8172 break;
8173 case DAHDI_EVENT_RINGOFFHOOK:
8174 if (p->inalarm) break;
8175 if (p->oprmode < 0)
8176 {
8177 if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
8178 {
8179 /* Make sure it stops ringing */
8180 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8181 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
8183 ast_debug(1, "Operator recall by channel %d for channel %d complete\n", p->oprpeer->channel, p->channel);
8184 }
8185 break;
8186 }
8187 if (p->radio)
8188 {
8191 break;
8192 }
8193 /* for E911, its supposed to wait for offhook then dial
8194 the second half of the dial string */
8195 if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast_channel_state(ast) == AST_STATE_DIALING_OFFHOOK)) {
8196 c = strchr(p->dialdest, '/');
8197 if (c)
8198 c++;
8199 else
8200 c = p->dialdest;
8201
8202 if (*c) {
8203 int numchars = snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
8204 if (numchars >= sizeof(p->dop.dialstr)) {
8205 ast_log(LOG_WARNING, "Dial string '%s' truncated\n", c);
8206 }
8207 } else {
8208 ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
8209 }
8210
8211 if (strlen(p->dop.dialstr) > 4) {
8212 memset(p->echorest, 'w', sizeof(p->echorest) - 1);
8213 strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
8214 p->echorest[sizeof(p->echorest) - 1] = '\0';
8215 p->echobreak = 1;
8216 p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
8217 } else
8218 p->echobreak = 0;
8219 if (dahdi_dial_str(p, p->dop.op, p->dop.dialstr)) {
8220 x = DAHDI_ONHOOK;
8221 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
8222 return NULL;
8223 }
8224 p->dialing = 1;
8225 return &p->subs[idx].f;
8226 }
8227 switch (p->sig) {
8228 case SIG_FXOLS:
8229 case SIG_FXOGS:
8230 case SIG_FXOKS:
8231 switch (ast_channel_state(ast)) {
8232 case AST_STATE_RINGING:
8233 dahdi_ec_enable(p);
8234 dahdi_train_ec(p);
8237 /* Make sure it stops ringing */
8238 p->subs[SUB_REAL].needringing = 0;
8239 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8240 ast_debug(1, "channel %d answered\n", p->channel);
8241
8242 /* Cancel any running CallerID spill */
8243 ast_free(p->cidspill);
8244 p->cidspill = NULL;
8246
8247 p->dialing = 0;
8248 p->callwaitcas = 0;
8249 if (p->confirmanswer) {
8250 /* Ignore answer if "confirm answer" is enabled */
8251 p->subs[idx].f.frametype = AST_FRAME_NULL;
8252 p->subs[idx].f.subclass.integer = 0;
8253 } else if (!ast_strlen_zero(p->dop.dialstr)) {
8254 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
8255 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8256 if (res) {
8257 p->dop.dialstr[0] = '\0';
8258 return NULL;
8259 } else {
8260 ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
8261 p->subs[idx].f.frametype = AST_FRAME_NULL;
8262 p->subs[idx].f.subclass.integer = 0;
8263 p->dialing = 1;
8264 }
8265 p->dop.dialstr[0] = '\0';
8267 } else
8269 return &p->subs[idx].f;
8270 case AST_STATE_DOWN:
8272 ast_channel_rings_set(ast, 1);
8275 ast_debug(1, "channel %d picked up\n", p->channel);
8276 return &p->subs[idx].f;
8277 case AST_STATE_UP:
8278 /* Make sure it stops ringing */
8279 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8280 /* Okay -- probably call waiting*/
8282 p->subs[idx].needunhold = 1;
8283 break;
8284 case AST_STATE_RESERVED:
8285 /* Start up dialtone */
8286 if (has_voicemail(p))
8287 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
8288 else
8289 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
8290 break;
8291 default:
8292 ast_log(LOG_WARNING, "FXO phone off hook in weird state %u??\n", ast_channel_state(ast));
8293 }
8294 break;
8295 case SIG_FXSLS:
8296 case SIG_FXSGS:
8297 case SIG_FXSKS:
8298 if (ast_channel_state(ast) == AST_STATE_RING) {
8299 p->ringt = p->ringt_base;
8300 }
8301
8302 /* If we get a ring then we cannot be in
8303 * reversed polarity. So we reset to idle */
8304 ast_debug(1, "Setting IDLE polarity due "
8305 "to ring. Old polarity was %d\n",
8306 p->polarity);
8308
8309 /* Fall through */
8310 case SIG_EM:
8311 case SIG_EM_E1:
8312 case SIG_EMWINK:
8313 case SIG_FEATD:
8314 case SIG_FEATDMF:
8315 case SIG_FEATDMF_TA:
8316 case SIG_E911:
8317 case SIG_FGC_CAMA:
8318 case SIG_FGC_CAMAMF:
8319 case SIG_FEATB:
8320 case SIG_SF:
8321 case SIG_SFWINK:
8322 case SIG_SF_FEATD:
8323 case SIG_SF_FEATDMF:
8324 case SIG_SF_FEATB:
8328 ast_debug(1, "Ring detected\n");
8331 } else if (p->outgoing && ((ast_channel_state(ast) == AST_STATE_RINGING) || (ast_channel_state(ast) == AST_STATE_DIALING))) {
8332 ast_debug(1, "Line answered\n");
8333 if (p->confirmanswer) {
8334 p->subs[idx].f.frametype = AST_FRAME_NULL;
8335 p->subs[idx].f.subclass.integer = 0;
8336 } else {
8340 }
8341 } else if (ast_channel_state(ast) != AST_STATE_RING)
8342 ast_log(LOG_WARNING, "Ring/Off-hook in strange state %u on channel %d\n", ast_channel_state(ast), p->channel);
8343 break;
8344 default:
8345 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8346 }
8347 break;
8348 case DAHDI_EVENT_RINGBEGIN:
8349 switch (p->sig) {
8350 case SIG_FXSLS:
8351 case SIG_FXSGS:
8352 case SIG_FXSKS:
8353 if (ast_channel_state(ast) == AST_STATE_RING) {
8354 p->ringt = p->ringt_base;
8355 }
8356 break;
8357 }
8358 break;
8359 case DAHDI_EVENT_RINGERON:
8360 break;
8361 case DAHDI_EVENT_NOALARM:
8362 switch (p->sig) {
8363#if defined(HAVE_PRI)
8366 break;
8367#endif /* defined(HAVE_PRI) */
8368#if defined(HAVE_SS7)
8369 case SIG_SS7:
8371 break;
8372#endif /* defined(HAVE_SS7) */
8373 default:
8374 p->inalarm = 0;
8375 break;
8376 }
8378 break;
8379 case DAHDI_EVENT_WINKFLASH:
8380 if (p->inalarm) break;
8381 if (p->radio) break;
8382 if (p->oprmode < 0) break;
8383 if (p->oprmode > 1)
8384 {
8385 struct dahdi_params par;
8386
8387 memset(&par, 0, sizeof(par));
8388 if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
8389 {
8390 if (!par.rxisoffhook)
8391 {
8392 /* Make sure it stops ringing */
8393 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8394 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
8395 save_conference(p);
8396 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8397 ast_verb(4, "Operator flash recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8398 }
8399 }
8400 break;
8401 }
8402 /* Remember last time we got a flash-hook */
8403 p->flashtime = ast_tvnow();
8404 switch (mysig) {
8405 case SIG_FXOLS:
8406 case SIG_FXOGS:
8407 case SIG_FXOKS:
8408 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
8410
8411 /* Cancel any running CallerID spill */
8412 ast_free(p->cidspill);
8413 p->cidspill = NULL;
8415 p->callwaitcas = 0;
8416
8417 if (idx != SUB_REAL) {
8418 ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
8419 goto winkflashdone;
8420 }
8421
8422 if (p->subs[SUB_CALLWAIT].owner) {
8423 /* Swap to call-wait */
8425 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
8426 p->owner = p->subs[SUB_REAL].owner;
8427 ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));
8430 p->subs[SUB_REAL].needanswer = 1;
8431 }
8432 p->callwaitingrepeat = 0;
8433 p->cidcwexpire = 0;
8434 p->cid_suppress_expire = 0;
8435 /* Start music on hold if appropriate */
8436 if (!p->subs[SUB_CALLWAIT].inthreeway) {
8438 }
8439 p->subs[SUB_CALLWAIT].needhold = 1;
8441 p->subs[SUB_REAL].needunhold = 1;
8442 } else if (!p->subs[SUB_THREEWAY].owner) {
8443 if (!p->threewaycalling) {
8444 /* Just send a flash if no 3-way calling */
8445 p->subs[SUB_REAL].needflash = 1;
8446 goto winkflashdone;
8447 } else if (!check_for_conference(p)) {
8448 ast_callid callid = 0;
8449 int callid_created;
8450 char cid_num[256];
8451 char cid_name[256];
8452
8453 cid_num[0] = 0;
8454 cid_name[0] = 0;
8455 if (p->dahditrcallerid && p->owner) {
8459 sizeof(cid_num));
8460 }
8464 sizeof(cid_name));
8465 }
8466 }
8467 /* XXX This section needs much more error checking!!! XXX */
8468 /* Start a 3-way call if feasible */
8469 if (!((ast_channel_pbx(ast)) ||
8470 (ast_channel_state(ast) == AST_STATE_UP) ||
8471 (ast_channel_state(ast) == AST_STATE_RING))) {
8472 ast_debug(1, "Flash when call not up or ringing\n");
8473 goto winkflashdone;
8474 }
8475 if (alloc_sub(p, SUB_THREEWAY)) {
8476 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
8477 goto winkflashdone;
8478 }
8479 callid_created = ast_callid_threadstorage_auto(&callid);
8480 /*
8481 * Make new channel
8482 *
8483 * We cannot hold the p or ast locks while creating a new
8484 * channel.
8485 */
8487 ast_channel_unlock(ast);
8488 chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, NULL, callid);
8489 ast_channel_lock(ast);
8490 ast_mutex_lock(&p->lock);
8491 if (p->dahditrcallerid) {
8492 if (!p->origcid_num)
8494 if (!p->origcid_name)
8496 ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
8497 ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
8498 }
8499 /* Swap things around between the three-way and real call */
8501 /* Disable echo canceller for better dialing */
8503 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
8504 if (res)
8505 ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
8506 p->owner = chan;
8507 if (!chan) {
8508 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
8509 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
8510 ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
8511 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
8512 dahdi_ec_enable(p);
8513 ast_hangup(chan);
8514 } else {
8515 ast_verb(3, "Started three way call on channel %d\n", p->channel);
8516
8517 /* Start music on hold */
8519 p->subs[SUB_THREEWAY].needhold = 1;
8520 }
8521 ast_callid_threadstorage_auto_clean(callid, callid_created);
8522 }
8523 } else {
8524 /* Already have a 3 way call */
8525 if (p->subs[SUB_THREEWAY].inthreeway) {
8526 /* Call is already up, drop the last person */
8527 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
8528 /* If the primary call isn't answered yet, use it */
8530 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
8532 p->owner = p->subs[SUB_REAL].owner;
8533 }
8534 /* Drop the last call and stop the conference */
8535 ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8537 p->subs[SUB_REAL].inthreeway = 0;
8539 } else {
8540 /* Lets see what we're up to */
8541 if (((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) &&
8543 int otherindex = SUB_THREEWAY;
8544
8545 ast_verb(3, "Building conference call with %s and %s\n",
8548 /* Put them in the threeway, and flip */
8550 p->subs[SUB_REAL].inthreeway = 1;
8551 if (ast_channel_state(ast) == AST_STATE_UP) {
8553 otherindex = SUB_REAL;
8554 }
8555 if (p->subs[otherindex].owner) {
8556 ast_queue_unhold(p->subs[otherindex].owner);
8557 }
8558 p->subs[otherindex].needunhold = 1;
8559 p->owner = p->subs[SUB_REAL].owner;
8560 } else {
8561 ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8564 p->owner = p->subs[SUB_REAL].owner;
8565 if (p->subs[SUB_REAL].owner) {
8567 }
8568 p->subs[SUB_REAL].needunhold = 1;
8569 dahdi_ec_enable(p);
8570 }
8571 }
8572 }
8573winkflashdone:
8575 break;
8576 case SIG_EM:
8577 case SIG_EM_E1:
8578 case SIG_FEATD:
8579 case SIG_SF:
8580 case SIG_SFWINK:
8581 case SIG_SF_FEATD:
8582 case SIG_FXSLS:
8583 case SIG_FXSGS:
8584 if (p->dialing)
8585 ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
8586 else
8587 ast_debug(1, "Got wink in weird state %u on channel %d\n", ast_channel_state(ast), p->channel);
8588 break;
8589 case SIG_FEATDMF_TA:
8590 switch (p->whichwink) {
8591 case 0:
8592 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p->owner)->ani2,
8595 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#",
8599 break;
8600 case 1:
8601 ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
8602 break;
8603 case 2:
8604 ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
8605 return NULL;
8606 }
8607 p->whichwink++;
8608 /* Fall through */
8609 case SIG_FEATDMF:
8610 case SIG_E911:
8611 case SIG_FGC_CAMAMF:
8612 case SIG_FGC_CAMA:
8613 case SIG_FEATB:
8614 case SIG_SF_FEATDMF:
8615 case SIG_SF_FEATB:
8616 case SIG_EMWINK:
8617 /* FGD MF and EMWINK *Must* wait for wink */
8618 if (!ast_strlen_zero(p->dop.dialstr)) {
8619 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8620 if (res) {
8621 p->dop.dialstr[0] = '\0';
8622 return NULL;
8623 } else
8624 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8625 }
8626 p->dop.dialstr[0] = '\0';
8627 break;
8628 default:
8629 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8630 }
8631 break;
8632 case DAHDI_EVENT_HOOKCOMPLETE:
8633 if (p->inalarm) break;
8634 if ((p->radio || (p->oprmode < 0))) break;
8635 if (p->waitingfordt.tv_sec) break;
8636 switch (mysig) {
8637 case SIG_FXSLS: /* only interesting for FXS */
8638 case SIG_FXSGS:
8639 case SIG_FXSKS:
8640 case SIG_EM:
8641 case SIG_EM_E1:
8642 case SIG_EMWINK:
8643 case SIG_FEATD:
8644 case SIG_SF:
8645 case SIG_SFWINK:
8646 case SIG_SF_FEATD:
8647 if (!ast_strlen_zero(p->dop.dialstr)) {
8648 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8649 if (res) {
8650 p->dop.dialstr[0] = '\0';
8651 return NULL;
8652 } else
8653 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8654 }
8655 p->dop.dialstr[0] = '\0';
8656 p->dop.op = DAHDI_DIAL_OP_REPLACE;
8657 break;
8658 case SIG_FEATDMF:
8659 case SIG_FEATDMF_TA:
8660 case SIG_E911:
8661 case SIG_FGC_CAMA:
8662 case SIG_FGC_CAMAMF:
8663 case SIG_FEATB:
8664 case SIG_SF_FEATDMF:
8665 case SIG_SF_FEATB:
8666 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
8667 break;
8668 default:
8669 break;
8670 }
8671 break;
8672 case DAHDI_EVENT_POLARITY:
8673 /*
8674 * If we get a Polarity Switch event, check to see
8675 * if we should change the polarity state and
8676 * mark the channel as UP or if this is an indication
8677 * of remote end disconnect.
8678 */
8679 if (p->polarity == POLARITY_IDLE) {
8681 if (p->answeronpolarityswitch &&
8684 ast_debug(1, "Answering on polarity switch!\n");
8686 if (p->hanguponpolarityswitch) {
8688 }
8689 } else
8690 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8691 }
8692 /* Removed else statement from here as it was preventing hangups from ever happening*/
8693 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
8694 if (p->hanguponpolarityswitch &&
8695 (p->polarityonanswerdelay > 0) &&
8696 (p->polarity == POLARITY_REV) &&
8698 /* Added log_debug information below to provide a better indication of what is going on */
8699 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) );
8700
8702 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
8705 } else
8706 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));
8707
8708 } else {
8710 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8711 }
8712 /* Added more log_debug information below to provide a better indication of what is going on */
8713 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) );
8714 break;
8715 default:
8716 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
8717 }
8718 return &p->subs[idx].f;
8719}
8720
8721static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
8722{
8723 int res;
8724 int idx;
8725 struct ast_frame *f;
8726 int usedindex = -1;
8727 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8728
8729 if ((idx = dahdi_get_index(ast, p, 0)) < 0) {
8730 idx = SUB_REAL;
8731 }
8732
8733 p->subs[idx].f.frametype = AST_FRAME_NULL;
8734 p->subs[idx].f.datalen = 0;
8735 p->subs[idx].f.samples = 0;
8736 p->subs[idx].f.mallocd = 0;
8737 p->subs[idx].f.offset = 0;
8738 p->subs[idx].f.subclass.integer = 0;
8739 p->subs[idx].f.delivery = ast_tv(0,0);
8740 p->subs[idx].f.src = "dahdi_exception";
8741 p->subs[idx].f.data.ptr = NULL;
8742
8743
8744 if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
8745 /* If nobody owns us, absorb the event appropriately, otherwise
8746 we loop indefinitely. This occurs when, during call waiting, the
8747 other end hangs up our channel so that it no longer exists, but we
8748 have neither FLASH'd nor ONHOOK'd to signify our desire to
8749 change to the other channel. */
8750 if (p->fake_event) {
8751 res = p->fake_event;
8752 p->fake_event = 0;
8753 } else
8754 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
8755 /* Switch to real if there is one and this isn't something really silly... */
8756 if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
8757 (res != DAHDI_EVENT_HOOKCOMPLETE)) {
8758 ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
8759 p->owner = p->subs[SUB_REAL].owner;
8760 if (p->owner) {
8762 }
8763 p->subs[SUB_REAL].needunhold = 1;
8764 }
8765 switch (res) {
8766 case DAHDI_EVENT_ONHOOK:
8768 if (p->owner) {
8769 ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
8771 p->callwaitingrepeat = 0;
8772 p->cidcwexpire = 0;
8773 p->cid_suppress_expire = 0;
8774 } else
8775 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8777 break;
8778 case DAHDI_EVENT_RINGOFFHOOK:
8779 dahdi_ec_enable(p);
8780 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
8781 if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
8782 p->subs[SUB_REAL].needanswer = 1;
8783 p->dialing = 0;
8784 }
8785 break;
8786 case DAHDI_EVENT_HOOKCOMPLETE:
8787 case DAHDI_EVENT_RINGERON:
8788 case DAHDI_EVENT_RINGEROFF:
8789 /* Do nothing */
8790 break;
8791 case DAHDI_EVENT_WINKFLASH:
8792 p->flashtime = ast_tvnow();
8793 if (p->owner) {
8794 ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, ast_channel_name(p->owner));
8796 /* Answer if necessary */
8797 usedindex = dahdi_get_index(p->owner, p, 0);
8798 if (usedindex > -1) {
8799 p->subs[usedindex].needanswer = 1;
8800 }
8802 }
8803 p->callwaitingrepeat = 0;
8804 p->cidcwexpire = 0;
8805 p->cid_suppress_expire = 0;
8807 p->subs[SUB_REAL].needunhold = 1;
8808 } else
8809 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8811 break;
8812 default:
8813 ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
8814 }
8815 f = &p->subs[idx].f;
8816 return f;
8817 }
8818 if (!(p->radio || (p->oprmode < 0)))
8819 ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast, 0), p->channel);
8820 /* If it's not us, return NULL immediately */
8821 if (ast != p->owner) {
8822 if (p->owner) {
8823 ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
8824 }
8825 f = &p->subs[idx].f;
8826 return f;
8827 }
8828
8829 f = dahdi_handle_event(ast);
8830 if (!f) {
8831 const char *name = ast_strdupa(ast_channel_name(ast));
8832
8833 /* Tell the CDR this DAHDI device hung up */
8835 ast_channel_unlock(ast);
8836 ast_set_hangupsource(ast, name, 0);
8837 ast_channel_lock(ast);
8838 ast_mutex_lock(&p->lock);
8839 }
8840 return f;
8841}
8842
8843static struct ast_frame *dahdi_exception(struct ast_channel *ast)
8844{
8845 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8846 struct ast_frame *f;
8847 ast_mutex_lock(&p->lock);
8848 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
8849 struct analog_pvt *analog_p = p->sig_pvt;
8850 f = analog_exception(analog_p, ast);
8851 } else {
8852 f = __dahdi_exception(ast);
8853 }
8855 return f;
8856}
8857
8858static struct ast_frame *dahdi_read(struct ast_channel *ast)
8859{
8860 struct dahdi_pvt *p;
8861 int res;
8862 int idx;
8863 void *readbuf;
8864 struct ast_frame *f;
8865
8866 /*
8867 * For analog channels, we must do deadlock avoidance because
8868 * analog ports can have more than one Asterisk channel using
8869 * the same private structure.
8870 */
8871 p = ast_channel_tech_pvt(ast);
8872 while (ast_mutex_trylock(&p->lock)) {
8874
8875 /*
8876 * Check to see if the channel is still associated with the same
8877 * private structure. While the Asterisk channel was unlocked
8878 * the following events may have occurred:
8879 *
8880 * 1) A masquerade may have associated the channel with another
8881 * technology or private structure.
8882 *
8883 * 2) For PRI calls, call signaling could change the channel
8884 * association to another B channel (private structure).
8885 */
8886 if (ast_channel_tech_pvt(ast) != p) {
8887 /* The channel is no longer associated. Quit gracefully. */
8888 return &ast_null_frame;
8889 }
8890 }
8891
8892 idx = dahdi_get_index(ast, p, 0);
8893
8894 /* Hang up if we don't really exist */
8895 if (idx < 0) {
8896 ast_log(LOG_WARNING, "We don't exist?\n");
8898 return NULL;
8899 }
8900
8901 if ((p->radio || (p->oprmode < 0)) && p->inalarm) {
8903 return NULL;
8904 }
8905
8906 p->subs[idx].f.frametype = AST_FRAME_NULL;
8907 p->subs[idx].f.datalen = 0;
8908 p->subs[idx].f.samples = 0;
8909 p->subs[idx].f.mallocd = 0;
8910 p->subs[idx].f.offset = 0;
8911 p->subs[idx].f.subclass.integer = 0;
8912 p->subs[idx].f.delivery = ast_tv(0,0);
8913 p->subs[idx].f.src = "dahdi_read";
8914 p->subs[idx].f.data.ptr = NULL;
8915
8916 /* make sure it sends initial key state as first frame */
8917 if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
8918 {
8919 struct dahdi_params ps;
8920
8921 memset(&ps, 0, sizeof(ps));
8922 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
8924 return NULL;
8925 }
8926 p->firstradio = 1;
8928 if (ps.rxisoffhook)
8929 {
8931 }
8932 else
8933 {
8935 }
8937 return &p->subs[idx].f;
8938 }
8939 if (p->ringt > 0) {
8940 if (!(--p->ringt)) {
8942 return NULL;
8943 }
8944 }
8945
8946#ifdef HAVE_OPENR2
8947 if (p->mfcr2) {
8948 openr2_chan_process_event(p->r2chan);
8949 if (OR2_DIR_FORWARD == openr2_chan_get_direction(p->r2chan)) {
8951 /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
8952 * now enqueue a progress frame to bridge the media up */
8953 if (p->mfcr2_call_accepted &&
8954 !p->mfcr2_progress_sent &&
8956 ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
8957 ast_queue_frame(p->owner, &fr);
8958 p->mfcr2_progress_sent = 1;
8959 }
8960 }
8961 }
8962#endif
8963
8964 if (p->subs[idx].needringing) {
8965 /* Send ringing frame if requested */
8966 p->subs[idx].needringing = 0;
8971 return &p->subs[idx].f;
8972 }
8973
8974 if (p->subs[idx].needbusy) {
8975 /* Send busy frame if requested */
8976 p->subs[idx].needbusy = 0;
8980 return &p->subs[idx].f;
8981 }
8982
8983 if (p->subs[idx].needcongestion) {
8984 /* Send congestion frame if requested */
8985 p->subs[idx].needcongestion = 0;
8989 return &p->subs[idx].f;
8990 }
8991
8992 if (p->subs[idx].needanswer) {
8993 /* Send answer frame if requested */
8994 p->subs[idx].needanswer = 0;
8998 return &p->subs[idx].f;
8999 }
9000#ifdef HAVE_OPENR2
9001 if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
9002 /* openr2 took care of reading and handling any event
9003 (needanswer, needbusy etc), if we continue we will read()
9004 twice, lets just return a null frame. This should only
9005 happen when openr2 is dialing out */
9007 return &ast_null_frame;
9008 }
9009#endif
9010
9011 if (p->subs[idx].needflash) {
9012 /* Send answer frame if requested */
9013 p->subs[idx].needflash = 0;
9017 return &p->subs[idx].f;
9018 }
9019
9020 if (p->subs[idx].needhold) {
9021 /* Send answer frame if requested */
9022 p->subs[idx].needhold = 0;
9026 ast_debug(1, "Sending hold on '%s'\n", ast_channel_name(ast));
9027 return &p->subs[idx].f;
9028 }
9029
9030 if (p->subs[idx].needunhold) {
9031 /* Send answer frame if requested */
9032 p->subs[idx].needunhold = 0;
9036 ast_debug(1, "Sending unhold on '%s'\n", ast_channel_name(ast));
9037 return &p->subs[idx].f;
9038 }
9039
9040 /*
9041 * If we have a fake_event, fake an exception to handle it only
9042 * if this channel owns the private.
9043 */
9044 if (p->fake_event && p->owner == ast) {
9045 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9046 struct analog_pvt *analog_p = p->sig_pvt;
9047
9048 f = analog_exception(analog_p, ast);
9049 } else {
9050 f = __dahdi_exception(ast);
9051 }
9053 return f;
9054 }
9055
9057 if (!p->subs[idx].linear) {
9058 p->subs[idx].linear = 1;
9059 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9060 if (res)
9061 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
9062 }
9063 } else {
9064 if (p->subs[idx].linear) {
9065 p->subs[idx].linear = 0;
9066 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9067 if (res)
9068 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
9069 }
9070 }
9071 readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
9072 CHECK_BLOCKING(ast);
9073 res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9075 /* Check for hangup */
9076 if (res < 0) {
9077 f = NULL;
9078 if (res == -1) {
9079 if (errno == EAGAIN) {
9080 /* Return "NULL" frame if there is nobody there */
9082 return &p->subs[idx].f;
9083 } else if (errno == ELAST) {
9084 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9085 struct analog_pvt *analog_p = p->sig_pvt;
9086 f = analog_exception(analog_p, ast);
9087 } else {
9088 f = __dahdi_exception(ast);
9089 }
9090 } else
9091 ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
9092 }
9094 return f;
9095 }
9096 if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
9097 ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9098 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9099 struct analog_pvt *analog_p = p->sig_pvt;
9100 f = analog_exception(analog_p, ast);
9101 } else {
9102 f = __dahdi_exception(ast);
9103 }
9105 return f;
9106 }
9107 if (p->tdd) { /* if in TDD mode, see if we receive that */
9108 int c;
9109
9110 c = tdd_feed(p->tdd,readbuf,READ_SIZE);
9111 if (c < 0) {
9112 ast_debug(1,"tdd_feed failed\n");
9114 return NULL;
9115 }
9116 if (c) { /* if a char to return */
9117 p->subs[idx].f.subclass.integer = 0;
9118 p->subs[idx].f.frametype = AST_FRAME_TEXT;
9119 p->subs[idx].f.mallocd = 0;
9120 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9121 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
9122 p->subs[idx].f.datalen = 1;
9123 *((char *) p->subs[idx].f.data.ptr) = c;
9125 return &p->subs[idx].f;
9126 }
9127 }
9128 if (idx == SUB_REAL) {
9129 /* Ensure the CW timers decrement only on a single subchannel */
9130 if (p->cidcwexpire) {
9131 if (!--p->cidcwexpire) {
9132 /* Expired CID/CW */
9133 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
9135 }
9136 }
9137 if (p->cid_suppress_expire) {
9139 }
9140 if (p->callwaitingrepeat) {
9141 if (!--p->callwaitingrepeat) {
9142 /* Expired, Repeat callwaiting tone */
9143 ++p->callwaitrings;
9144 dahdi_callwait(ast);
9145 }
9146 }
9147 }
9148 if (p->subs[idx].linear) {
9149 p->subs[idx].f.datalen = READ_SIZE * 2;
9150 } else
9151 p->subs[idx].f.datalen = READ_SIZE;
9152
9153 /* Handle CallerID Transmission */
9154 if ((p->owner == ast) && p->cidspill) {
9155 send_callerid(p);
9156 }
9157
9158 p->subs[idx].f.frametype = AST_FRAME_VOICE;
9160 p->subs[idx].f.samples = READ_SIZE;
9161 p->subs[idx].f.mallocd = 0;
9162 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9163 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
9164#if 0
9165 ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
9166#endif
9167 if ((p->dialing && !p->waitingfordt.tv_sec) || p->radio || /* Transmitting something */
9168 (idx && (ast_channel_state(ast) != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
9169 ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
9170 ) {
9171 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
9172 don't send anything */
9173 p->subs[idx].f.frametype = AST_FRAME_NULL;
9174 p->subs[idx].f.subclass.integer = 0;
9175 p->subs[idx].f.samples = 0;
9176 p->subs[idx].f.mallocd = 0;
9177 p->subs[idx].f.offset = 0;
9178 p->subs[idx].f.data.ptr = NULL;
9179 p->subs[idx].f.datalen= 0;
9180 }
9181 if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec || p->dialtone_detect) && !idx) {
9182 /* Perform busy detection etc on the dahdi line */
9183 int mute;
9184
9186 && p->faxdetect_timeout
9188 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
9190 ast_debug(1, "Channel driver fax CNG detection timeout on %s\n",
9191 ast_channel_name(ast));
9192 }
9193
9194 f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
9195
9196 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
9197 mute = ast_dsp_was_muted(p->dsp);
9198 if (p->muting != mute) {
9199 p->muting = mute;
9200 dahdi_confmute(p, mute);
9201 }
9202
9203 if (f) {
9205 && !p->outgoing && ast_channel_state(ast) == AST_STATE_UP) {
9207 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9209 }
9210 }
9212 if ((ast_channel_state(ast) == AST_STATE_UP) && !p->outgoing) {
9213 /*
9214 * Treat this as a "hangup" instead of a "busy" on the
9215 * assumption that a busy means the incoming call went away.
9216 */
9217 ast_frfree(f);
9218 f = NULL;
9219 }
9220 } else if (p->dialtone_detect && !p->outgoing && f->frametype == AST_FRAME_VOICE) {
9222 /* Dialtone detected on inbound call; hangup the channel */
9223 ast_frfree(f);
9224 f = NULL;
9225 }
9226 } else if (f->frametype == AST_FRAME_DTMF_BEGIN
9227 || f->frametype == AST_FRAME_DTMF_END) {
9228#ifdef HAVE_PRI
9230 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
9231 && p->pri
9232 && ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING))
9233 || (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
9234 /* Don't accept in-band DTMF when in overlap dial mode */
9235 ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n",
9236 f->frametype == AST_FRAME_DTMF_BEGIN ? "begin" : "end",
9237 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
9238
9240 f->subclass.integer = 0;
9241 }
9242#endif
9243 /* DSP clears us of being pulse */
9244 p->pulsedial = 0;
9245 } else if (p->waitingfordt.tv_sec) {
9247 p->waitingfordt.tv_sec = 0;
9248 ast_log(LOG_NOTICE, "Never saw dialtone on channel %d\n", p->channel);
9249 ast_frfree(f);
9250 f = NULL;
9251 } else if (f->frametype == AST_FRAME_VOICE) {
9253 f->subclass.integer = 0;
9255 p->waitingfordt.tv_sec = 0;
9256 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9258 ast_debug(1, "Got 10 samples of dialtone!\n");
9259 if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */
9260 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
9261 if (res) {
9262 p->dop.dialstr[0] = '\0';
9264 ast_frfree(f);
9265 return NULL;
9266 } else {
9267 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
9268 p->dialing = 1;
9269 p->dop.dialstr[0] = '\0';
9270 p->dop.op = DAHDI_DIAL_OP_REPLACE;
9272 }
9273 }
9274 }
9275 }
9276 }
9277 }
9278 } else
9279 f = &p->subs[idx].f;
9280
9281 if (f) {
9282 switch (f->frametype) {
9284 case AST_FRAME_DTMF_END:
9285 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9286 analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
9287 } else {
9288 dahdi_handle_dtmf(ast, idx, &f);
9289 }
9291 if (f->frametype == AST_FRAME_DTMF_END) { /* only show this message when the key is let go of */
9292 ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f->subclass.integer);
9293 }
9295 f->subclass.integer = 0;
9296 }
9297 break;
9298 case AST_FRAME_VOICE:
9299 if (p->cidspill || p->cid_suppress_expire) {
9300 /* We are/were sending a caller id spill. Suppress any echo. */
9301 p->subs[idx].f.frametype = AST_FRAME_NULL;
9302 p->subs[idx].f.subclass.integer = 0;
9303 p->subs[idx].f.samples = 0;
9304 p->subs[idx].f.mallocd = 0;
9305 p->subs[idx].f.offset = 0;
9306 p->subs[idx].f.data.ptr = NULL;
9307 p->subs[idx].f.datalen= 0;
9308 }
9309 break;
9310 default:
9311 break;
9312 }
9313 }
9314
9316 return f;
9317}
9318
9319static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
9320{
9321 int sent=0;
9322 int size;
9323 int res;
9324 int fd;
9325 fd = p->subs[idx].dfd;
9326 while (len) {
9327 size = len;
9328 if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
9329 size = (linear ? READ_SIZE * 2 : READ_SIZE);
9330 res = write(fd, buf, size);
9331 if (res != size) {
9332 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
9333 return sent;
9334 }
9335 len -= size;
9336 buf += size;
9337 }
9338 return sent;
9339}
9340
9341static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
9342{
9343 struct dahdi_pvt *p;
9344 int res;
9345 int idx;
9346
9347 /* Write a frame of (presumably voice) data */
9348 if (frame->frametype != AST_FRAME_VOICE) {
9349 if (frame->frametype != AST_FRAME_IMAGE) {
9350 ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n",
9351 frame->frametype);
9352 }
9353 return 0;
9354 }
9355
9356 /* Return if it's not valid data */
9357 if (!frame->data.ptr || !frame->datalen) {
9358 return 0;
9359 }
9360
9361 p = ast_channel_tech_pvt(ast);
9362 ast_mutex_lock(&p->lock);
9363
9364 idx = dahdi_get_index(ast, p, 0);
9365 if (idx < 0) {
9367 ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast_channel_name(ast));
9368 return -1;
9369 }
9370
9371 if (p->dialing) {
9373 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9374 ast_channel_name(ast));
9375 return 0;
9376 }
9377 if (!p->owner) {
9379 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9380 ast_channel_name(ast));
9381 return 0;
9382 }
9383 if (p->cidspill) {
9385 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9386 ast_channel_name(ast));
9387 return 0;
9388 }
9389
9391 if (!p->subs[idx].linear) {
9392 p->subs[idx].linear = 1;
9393 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9394 if (res)
9395 ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
9396 }
9397 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
9400 /* x-law already */
9401 if (p->subs[idx].linear) {
9402 p->subs[idx].linear = 0;
9403 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9404 if (res)
9405 ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
9406 }
9407 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
9408 } else {
9410 ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
9412 return -1;
9413 }
9415 if (res < 0) {
9416 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
9417 return -1;
9418 }
9419 return 0;
9420}
9421
9422static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
9423{
9424 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9425 int res=-1;
9426 int idx;
9427 int func = DAHDI_FLASH;
9428
9429 ast_mutex_lock(&p->lock);
9430 ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
9431 switch (p->sig) {
9432#if defined(HAVE_PRI)
9434 res = sig_pri_indicate(p->sig_pvt, chan, condition, data, datalen);
9436 return res;
9437#endif /* defined(HAVE_PRI) */
9438#if defined(HAVE_SS7)
9439 case SIG_SS7:
9440 res = sig_ss7_indicate(p->sig_pvt, chan, condition, data, datalen);
9442 return res;
9443#endif /* defined(HAVE_SS7) */
9444 default:
9445 break;
9446 }
9447#ifdef HAVE_OPENR2
9448 if (p->mfcr2 && !p->mfcr2_call_accepted) {
9450 /* if this is an R2 call and the call is not yet accepted, we don't want the
9451 tone indications to mess up with the MF tones */
9452 return 0;
9453 }
9454#endif
9455 idx = dahdi_get_index(chan, p, 0);
9456 if (idx == SUB_REAL) {
9457 switch (condition) {
9458 case AST_CONTROL_BUSY:
9459 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
9460 break;
9462 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
9463
9464 if (ast_channel_state(chan) != AST_STATE_UP) {
9465 if ((ast_channel_state(chan) != AST_STATE_RING) ||
9466 ((p->sig != SIG_FXSKS) &&
9467 (p->sig != SIG_FXSLS) &&
9468 (p->sig != SIG_FXSGS))) {
9469 /* We're playing audible ringback tone on the channel,
9470 * so set state to AST_STATE_RING, not AST_STATE_RINGING. */
9472 }
9473 }
9474 break;
9476 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan));
9477 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9478 res = 0;
9479 break;
9481 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan));
9482 /* don't continue in ast_indicate */
9483 res = 0;
9484 break;
9486 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan));
9487 /* don't continue in ast_indicate */
9488 res = 0;
9489 break;
9491 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9492 switch (ast_channel_hangupcause(chan)) {
9495 case 0:/* Cause has not been set. */
9496 /* Supply a more appropriate cause. */
9498 break;
9499 default:
9500 break;
9501 }
9502 break;
9503 case AST_CONTROL_HOLD:
9504 ast_moh_start(chan, data, p->mohinterpret);
9505 break;
9506 case AST_CONTROL_UNHOLD:
9507 ast_moh_stop(chan);
9508 break;
9510 if (p->radio)
9511 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
9512 res = 0;
9513 break;
9515 if (p->radio)
9516 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
9517 res = 0;
9518 break;
9519 case AST_CONTROL_FLASH:
9520 /* flash hookswitch */
9521 if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
9522 /* Clear out the dial buffer */
9523 p->dop.dialstr[0] = '\0';
9524 if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
9525 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
9526 ast_channel_name(chan), strerror(errno));
9527 } else
9528 res = 0;
9529 } else
9530 res = 0;
9531 break;
9533 res = 0;
9534 break;
9535 case -1:
9536 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
9537 break;
9538 }
9539 } else {
9540 res = 0;
9541 }
9543 return res;
9544}
9545
9546#if defined(HAVE_PRI)
9547static struct ast_str *create_channel_name(struct dahdi_pvt *i, int is_outgoing, char *address)
9548#else
9549static struct ast_str *create_channel_name(struct dahdi_pvt *i)
9550#endif /* defined(HAVE_PRI) */
9551{
9552 struct ast_str *chan_name;
9553 int x, y;
9554
9555 /* Create the new channel name tail. */
9556 if (!(chan_name = ast_str_create(32))) {
9557 return NULL;
9558 }
9559 if (i->channel == CHAN_PSEUDO) {
9560 ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
9561#if defined(HAVE_PRI)
9562 } else if (i->pri) {
9563 ast_mutex_lock(&i->pri->lock);
9564 y = ++i->pri->new_chan_seq;
9565 if (is_outgoing) {
9566 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, address, (unsigned)y);
9567 address[0] = '\0';
9568 } else if (ast_strlen_zero(i->cid_subaddr)) {
9569 /* Put in caller-id number only since there is no subaddress. */
9570 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, i->cid_num, (unsigned)y);
9571 } else {
9572 /* Put in caller-id number and subaddress. */
9573 ast_str_set(&chan_name, 0, "i%d/%s:%s-%x", i->pri->span, i->cid_num,
9574 i->cid_subaddr, (unsigned)y);
9575 }
9576 ast_mutex_unlock(&i->pri->lock);
9577#endif /* defined(HAVE_PRI) */
9578 } else {
9579 y = 1;
9580 do {
9581 ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
9582 for (x = 0; x < 3; ++x) {
9583 if (i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name),
9584 ast_channel_name(i->subs[x].owner) + 6)) {
9585 break;
9586 }
9587 }
9588 ++y;
9589 } while (x < 3);
9590 }
9591 return chan_name;
9592}
9593
9594static 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)
9595{
9596 struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, assignedids, requestor, callid);
9597
9599
9600 return new_channel;
9601}
9602
9603static 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)
9604{
9605 struct ast_channel *tmp;
9606 struct ast_format_cap *caps;
9607 struct ast_format *deflaw;
9608 int x;
9609 int features;
9610 struct ast_str *chan_name;
9611 struct ast_variable *v;
9612 char *dashptr;
9613 char device_name[AST_CHANNEL_NAME];
9614
9615 if (i->subs[idx].owner) {
9616 ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
9617 return NULL;
9618 }
9619
9620#if defined(HAVE_PRI)
9621 /*
9622 * The dnid has been stuffed with the called-number[:subaddress]
9623 * by dahdi_request() for outgoing calls.
9624 */
9625 chan_name = create_channel_name(i, i->outgoing, i->dnid);
9626#else
9627 chan_name = create_channel_name(i);
9628#endif /* defined(HAVE_PRI) */
9629 if (!chan_name) {
9630 return NULL;
9631 }
9632
9634 if (!caps) {
9635 ast_free(chan_name);
9636 return NULL;
9637 }
9638
9639 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));
9640 ast_free(chan_name);
9641 if (!tmp) {
9642 ao2_ref(caps, -1);
9643 return NULL;
9644 }
9645
9647
9648 if (callid) {
9649 ast_channel_callid_set(tmp, callid);
9650 }
9651
9653#if defined(HAVE_PRI)
9654 if (i->pri) {
9656 }
9657#endif /* defined(HAVE_PRI) */
9659 if (law) {
9660 i->law = law;
9661 if (law == DAHDI_LAW_ALAW) {
9662 deflaw = ast_format_alaw;
9663 } else {
9664 deflaw = ast_format_ulaw;
9665 }
9666 } else {
9667 switch (i->sig) {
9669 /* Make sure companding law is known. */
9670 i->law = (i->law_default == DAHDI_LAW_ALAW)
9671 ? DAHDI_LAW_ALAW : DAHDI_LAW_MULAW;
9672 break;
9673 default:
9674 i->law = i->law_default;
9675 break;
9676 }
9677 if (i->law_default == DAHDI_LAW_ALAW) {
9678 deflaw = ast_format_alaw;
9679 } else {
9680 deflaw = ast_format_ulaw;
9681 }
9682 }
9683 ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
9684 ast_format_cap_append(caps, deflaw, 0);
9686 ao2_ref(caps, -1);
9687 /* Start out assuming ulaw since it's smaller :) */
9688 ast_channel_set_rawreadformat(tmp, deflaw);
9689 ast_channel_set_readformat(tmp, deflaw);
9690 ast_channel_set_rawwriteformat(tmp, deflaw);
9691 ast_channel_set_writeformat(tmp, deflaw);
9692 i->subs[idx].linear = 0;
9693 dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
9694 features = 0;
9695 if (idx == SUB_REAL) {
9696 if (i->busydetect && CANBUSYDETECT(i))
9697 features |= DSP_FEATURE_BUSY_DETECT;
9699 features |= DSP_FEATURE_CALL_PROGRESS;
9701 features |= DSP_FEATURE_WAITDIALTONE;
9702 if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
9704 features |= DSP_FEATURE_FAX_DETECT;
9705 }
9706 x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
9707 if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
9708 i->hardwaredtmf = 0;
9709 features |= DSP_FEATURE_DIGIT_DETECT;
9710 } else if (NEED_MFDETECT(i)) {
9711 i->hardwaredtmf = 1;
9712 features |= DSP_FEATURE_DIGIT_DETECT;
9713 }
9714 }
9715 if (features) {
9716 if (i->dsp) {
9717 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp));
9718 } else {
9719 if (i->channel != CHAN_PSEUDO)
9720 i->dsp = ast_dsp_new();
9721 else
9722 i->dsp = NULL;
9723 if (i->dsp) {
9724 i->dsp_features = features;
9725#if defined(HAVE_PRI) || defined(HAVE_SS7)
9726 /* We cannot do progress detection until receive PROGRESS message */
9727 if (i->outgoing && (dahdi_sig_pri_lib_handles(i->sig) || (i->sig == SIG_SS7))) {
9728 /* Remember requested DSP features, don't treat
9729 talking as ANSWER */
9730 i->dsp_features = features & ~DSP_PROGRESS_TALK;
9731 features = 0;
9732 }
9733#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9734 ast_dsp_set_features(i->dsp, features);
9738 if (i->busydetect && CANBUSYDETECT(i)) {
9741 }
9742 }
9743 }
9744 }
9745
9747
9748 if (state == AST_STATE_RING)
9749 ast_channel_rings_set(tmp, 1);
9751 if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
9752 /* Only FXO signalled stuff can be picked up */
9757 }
9758 if (!ast_strlen_zero(i->parkinglot))
9759 ast_channel_parkinglot_set(tmp, i->parkinglot);
9760 if (!ast_strlen_zero(i->language))
9761 ast_channel_language_set(tmp, i->language);
9762 if (!i->owner)
9763 i->owner = tmp;
9765 ast_channel_accountcode_set(tmp, i->accountcode);
9766 if (i->amaflags)
9768 i->subs[idx].owner = tmp;
9770 if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
9771 ast_channel_call_forward_set(tmp, i->call_forward);
9772 }
9773 /* If we've been told "no ADSI" then enforce it */
9774 if (!i->adsi)
9776 if (!ast_strlen_zero(i->exten))
9778 if (!ast_strlen_zero(i->rdnis)) {
9781 }
9782 if (!ast_strlen_zero(i->dnid)) {
9784 }
9785
9786 /* Don't use ast_set_callerid() here because it will
9787 * generate a needless NewCallerID event */
9788#if defined(HAVE_PRI) || defined(HAVE_SS7)
9789 if (!ast_strlen_zero(i->cid_ani)) {
9791 ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_ani);
9792 } else if (!ast_strlen_zero(i->cid_num)) {
9795 }
9796#else
9797 if (!ast_strlen_zero(i->cid_num)) {
9800 }
9801#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9805 ast_channel_caller(tmp)->ani2 = i->cid_ani2;
9807 /* clear the fake event in case we posted one before we had ast_channel */
9808 i->fake_event = 0;
9809 /* Assure there is no confmute on this channel */
9810 dahdi_confmute(i, 0);
9811 i->muting = 0;
9812 /* Configure the new channel jb */
9814
9815 /* Set initial device state */
9816 ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name));
9817 dashptr = strrchr(device_name, '-');
9818 if (dashptr) {
9819 *dashptr = '\0';
9820 }
9823
9824 for (v = i->vars ; v ; v = v->next)
9826
9828
9829 ast_channel_unlock(tmp);
9830
9832
9834 if (startpbx) {
9835#ifdef HAVE_OPENR2
9836 if (i->mfcr2call) {
9837 pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
9838 }
9839#endif
9840 if (ast_pbx_start(tmp)) {
9841 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
9842 ast_hangup(tmp);
9843 return NULL;
9844 }
9845 }
9846 return tmp;
9847}
9848
9849
9850static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
9851{
9852 char c;
9853
9854 *str = 0; /* start with empty output buffer */
9855 for (;;)
9856 {
9857 /* Wait for the first digit (up to specified ms). */
9858 c = ast_waitfordigit(chan, ms);
9859 /* if timeout, hangup or error, return as such */
9860 if (c < 1)
9861 return c;
9862 *str++ = c;
9863 *str = 0;
9864 if (strchr(term, c))
9865 return 1;
9866 }
9867}
9868
9869static int dahdi_wink(struct dahdi_pvt *p, int idx)
9870{
9871 int j;
9872 dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
9873 for (;;)
9874 {
9875 /* set bits of interest */
9876 j = DAHDI_IOMUX_SIGEVENT;
9877 /* wait for some happening */
9878 if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
9879 /* exit loop if we have it */
9880 if (j & DAHDI_IOMUX_SIGEVENT) break;
9881 }
9882 /* get the event info */
9883 if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
9884 return 0;
9885}
9886
9887static void publish_dnd_state(int channel, const char *status)
9888{
9889 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
9890 RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
9891 if (!dahdichan) {
9892 return;
9893 }
9894
9895 ast_str_set(&dahdichan, 0, "%d", channel);
9896
9897 body = ast_json_pack("{s: s, s: s}",
9898 "DAHDIChannel", ast_str_buffer(dahdichan),
9899 "Status", status);
9900 if (!body) {
9901 return;
9902 }
9903
9905}
9906
9907/*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9908 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9909 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9910 *
9911 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9912 * DAHDI channel). Use this to enable or disable it.
9913 *
9914 * \bug the use of the word "channel" for those dahdichans is really confusing.
9915 */
9916static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
9917{
9918 if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
9919 return analog_dnd(dahdichan->sig_pvt, flag);
9920 }
9921
9922 if (flag == -1) {
9923 return dahdichan->dnd;
9924 }
9925
9926 /* Do not disturb */
9927 dahdichan->dnd = flag;
9928 ast_verb(3, "%s DND on channel %d\n",
9929 flag? "Enabled" : "Disabled",
9930 dahdichan->channel);
9931 publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
9932 return 0;
9933}
9934
9935static int canmatch_featurecode(const char *pickupexten, const char *exten)
9936{
9937 int extlen = strlen(exten);
9938
9939 if (!extlen) {
9940 return 1;
9941 }
9942
9943 if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
9944 return 1;
9945 }
9946 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9947 if (exten[0] == '*' && extlen < 3) {
9948 if (extlen == 1) {
9949 return 1;
9950 }
9951 /* "*0" should be processed before it gets here */
9952 switch (exten[1]) {
9953 case '6':
9954 case '7':
9955 case '8':
9956 return 1;
9957 }
9958 }
9959 return 0;
9960}
9961
9962static void *analog_ss_thread(void *data)
9963{
9964 struct ast_channel *chan = data;
9965 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9966 char exten[AST_MAX_EXTENSION] = "";
9967 char exten2[AST_MAX_EXTENSION] = "";
9968 unsigned char buf[256];
9969 char dtmfcid[300];
9970 char dtmfbuf[300];
9971 struct callerid_state *cs = NULL;
9972 char *name = NULL, *number = NULL;
9973 int distMatches;
9974 int curRingData[3];
9975 int receivedRingT;
9976 int counter1;
9977 int counter;
9978 int samples = 0;
9979 struct ast_smdi_md_message *smdi_msg = NULL;
9980 int flags = 0;
9981 int i;
9982 int timeout;
9983 int getforward = 0;
9984 char *s1, *s2;
9985 int len = 0;
9986 int res;
9987 int idx;
9988 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
9989 const char *pickupexten;
9990
9994 /* in the bizarre case where the channel has become a zombie before we
9995 even get started here, abort safely
9996 */
9997 if (!p) {
9998 ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
9999 ast_hangup(chan);
10000 goto quit;
10001 }
10002 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
10003 idx = dahdi_get_index(chan, p, 1);
10004 if (idx < 0) {
10005 ast_log(LOG_WARNING, "Huh?\n");
10006 ast_hangup(chan);
10007 goto quit;
10008 }
10009
10010 ast_channel_lock(chan);
10011 pickup_cfg = ast_get_chan_features_pickup_config(chan);
10012 if (!pickup_cfg) {
10013 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
10014 pickupexten = "";
10015 } else {
10016 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
10017 }
10018 ast_channel_unlock(chan);
10019
10020 if (p->dsp)
10022 switch (p->sig) {
10023 case SIG_FEATD:
10024 case SIG_FEATDMF:
10025 case SIG_FEATDMF_TA:
10026 case SIG_E911:
10027 case SIG_FGC_CAMAMF:
10028 case SIG_FEATB:
10029 case SIG_EMWINK:
10030 case SIG_SF_FEATD:
10031 case SIG_SF_FEATDMF:
10032 case SIG_SF_FEATB:
10033 case SIG_SFWINK:
10034 if (dahdi_wink(p, idx))
10035 goto quit;
10036 /* Fall through */
10037 case SIG_EM:
10038 case SIG_EM_E1:
10039 case SIG_SF:
10040 case SIG_FGC_CAMA:
10041 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10042 if (p->dsp)
10044 /* set digit mode appropriately */
10045 if (p->dsp) {
10046 if (NEED_MFDETECT(p))
10048 else
10050 }
10051 memset(dtmfbuf, 0, sizeof(dtmfbuf));
10052 /* Wait for the first digit only if immediate=no */
10053 if (!p->immediate)
10054 /* Wait for the first digit (up to 5 seconds). */
10055 res = ast_waitfordigit(chan, 5000);
10056 else
10057 res = 0;
10058 if (res > 0) {
10059 /* save first char */
10060 dtmfbuf[0] = res;
10061 switch (p->sig) {
10062 case SIG_FEATD:
10063 case SIG_SF_FEATD:
10064 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10065 if (res > 0)
10066 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10067 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10068 break;
10069 case SIG_FEATDMF_TA:
10070 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10071 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10072 if (dahdi_wink(p, idx)) goto quit;
10073 dtmfbuf[0] = 0;
10074 /* Wait for the first digit (up to 5 seconds). */
10075 res = ast_waitfordigit(chan, 5000);
10076 if (res <= 0) break;
10077 dtmfbuf[0] = res;
10078 /* fall through intentionally */
10079 case SIG_FEATDMF:
10080 case SIG_E911:
10081 case SIG_FGC_CAMAMF:
10082 case SIG_SF_FEATDMF:
10083 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10084 /* if international caca, do it again to get real ANO */
10085 if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
10086 {
10087 if (dahdi_wink(p, idx)) goto quit;
10088 dtmfbuf[0] = 0;
10089 /* Wait for the first digit (up to 5 seconds). */
10090 res = ast_waitfordigit(chan, 5000);
10091 if (res <= 0) break;
10092 dtmfbuf[0] = res;
10093 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10094 }
10095 if (res > 0) {
10096 /* if E911, take off hook */
10097 if (p->sig == SIG_E911)
10098 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10099 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
10100 }
10101 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10102 break;
10103 case SIG_FEATB:
10104 case SIG_SF_FEATB:
10105 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10106 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10107 break;
10108 case SIG_EMWINK:
10109 /* if we received a '*', we are actually receiving Feature Group D
10110 dial syntax, so use that mode; otherwise, fall through to normal
10111 mode
10112 */
10113 if (res == '*') {
10114 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10115 if (res > 0)
10116 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10117 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10118 break;
10119 }
10120 default:
10121 /* If we got the first digit, get the rest */
10122 len = 1;
10123 dtmfbuf[len] = '\0';
10124 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10125 if (ast_exists_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10126 timeout = p->matchdigit_timeout;
10127 } else {
10128 timeout = p->interdigit_timeout;
10129 }
10130 res = ast_waitfordigit(chan, timeout);
10131 if (res < 0) {
10132 ast_debug(1, "waitfordigit returned < 0...\n");
10133 ast_hangup(chan);
10134 goto quit;
10135 } else if (res) {
10136 dtmfbuf[len++] = res;
10137 dtmfbuf[len] = '\0';
10138 } else {
10139 break;
10140 }
10141 }
10142 break;
10143 }
10144 }
10145 if (res == -1) {
10146 ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
10147 ast_hangup(chan);
10148 goto quit;
10149 } else if (res < 0) {
10150 ast_debug(1, "Got hung up before digits finished\n");
10151 ast_hangup(chan);
10152 goto quit;
10153 }
10154
10155 if (p->sig == SIG_FGC_CAMA) {
10156 char anibuf[100];
10157
10158 if (ast_safe_sleep(chan,1000) == -1) {
10159 ast_hangup(chan);
10160 goto quit;
10161 }
10162 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10164 res = my_getsigstr(chan, anibuf, "#", 10000);
10165 if ((res > 0) && (strlen(anibuf) > 2)) {
10166 if (anibuf[strlen(anibuf) - 1] == '#')
10167 anibuf[strlen(anibuf) - 1] = 0;
10168 ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
10169 }
10171 }
10172
10173 ast_copy_string(exten, dtmfbuf, sizeof(exten));
10174 if (ast_strlen_zero(exten))
10175 ast_copy_string(exten, "s", sizeof(exten));
10176 if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
10177 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10178 if (exten[0] == '*') {
10179 char *stringp=NULL;
10180 ast_copy_string(exten2, exten, sizeof(exten2));
10181 /* Parse out extension and callerid */
10182 stringp=exten2 +1;
10183 s1 = strsep(&stringp, "*");
10184 s2 = strsep(&stringp, "*");
10185 if (s2) {
10186 if (!ast_strlen_zero(p->cid_num))
10187 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10188 else
10189 ast_set_callerid(chan, s1, NULL, s1);
10190 ast_copy_string(exten, s2, sizeof(exten));
10191 } else
10192 ast_copy_string(exten, s1, sizeof(exten));
10193 } else if (p->sig == SIG_FEATD)
10194 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10195 }
10196 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10197 if (exten[0] == '*') {
10198 char *stringp=NULL;
10199 ast_copy_string(exten2, exten, sizeof(exten2));
10200 /* Parse out extension and callerid */
10201 stringp=exten2 +1;
10202 s1 = strsep(&stringp, "#");
10203 s2 = strsep(&stringp, "#");
10204 if (s2) {
10205 if (!ast_strlen_zero(p->cid_num))
10206 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10207 else
10208 if (*(s1 + 2))
10209 ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
10210 ast_copy_string(exten, s2 + 1, sizeof(exten));
10211 } else
10212 ast_copy_string(exten, s1 + 2, sizeof(exten));
10213 } else
10214 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10215 }
10216 if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
10217 if (exten[0] == '*') {
10218 char *stringp=NULL;
10219 ast_copy_string(exten2, exten, sizeof(exten2));
10220 /* Parse out extension and callerid */
10221 stringp=exten2 +1;
10222 s1 = strsep(&stringp, "#");
10223 s2 = strsep(&stringp, "#");
10224 if (s2 && (*(s2 + 1) == '0')) {
10225 if (*(s2 + 2))
10226 ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
10227 }
10228 if (s1) ast_copy_string(exten, s1, sizeof(exten));
10229 else ast_copy_string(exten, "911", sizeof(exten));
10230 } else
10231 ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
10232 }
10233 if (p->sig == SIG_FEATB) {
10234 if (exten[0] == '*') {
10235 char *stringp=NULL;
10236 ast_copy_string(exten2, exten, sizeof(exten2));
10237 /* Parse out extension and callerid */
10238 stringp=exten2 +1;
10239 s1 = strsep(&stringp, "#");
10240 ast_copy_string(exten, exten2 + 1, sizeof(exten));
10241 } else
10242 ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
10243 }
10244 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10245 dahdi_wink(p, idx);
10246 /* some switches require a minimum guard time between
10247 the last FGD wink and something that answers
10248 immediately. This ensures it */
10249 if (ast_safe_sleep(chan, 100)) {
10250 ast_hangup(chan);
10251 goto quit;
10252 }
10253 }
10254 dahdi_ec_enable(p);
10255 if (NEED_MFDETECT(p)) {
10256 if (p->dsp) {
10257 if (!p->hardwaredtmf)
10259 else {
10260 ast_dsp_free(p->dsp);
10261 p->dsp = NULL;
10262 }
10263 }
10264 }
10265
10266 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1,
10267 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10268 ast_channel_exten_set(chan, exten);
10269 if (p->dsp) ast_dsp_digitreset(p->dsp);
10270 res = ast_pbx_run(chan);
10271 if (res) {
10272 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10273 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10274 }
10275 goto quit;
10276 } else {
10277 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, ast_channel_context(chan));
10278 sleep(2);
10279 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
10280 if (res < 0)
10281 ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
10282 else
10283 sleep(1);
10284 res = ast_streamfile(chan, "ss-noservice", ast_channel_language(chan));
10285 if (res >= 0)
10286 ast_waitstream(chan, "");
10287 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10288 ast_hangup(chan);
10289 goto quit;
10290 }
10291 break;
10292 case SIG_FXOLS:
10293 case SIG_FXOGS:
10294 case SIG_FXOKS:
10295 /* Read the first digit */
10296 timeout = p->firstdigit_timeout;
10297 /* If starting a threeway call, never timeout on the first digit so someone
10298 can use flash-hook as a "hold" feature */
10299 if (p->subs[SUB_THREEWAY].owner)
10300 timeout = INT_MAX;
10301 while (len < AST_MAX_EXTENSION-1) {
10302 int is_exten_parking = 0;
10303
10304 /* Read digit unless it's supposed to be immediate, in which case the
10305 only answer is 's' */
10306 if (p->immediate)
10307 res = 's';
10308 else
10309 res = ast_waitfordigit(chan, timeout);
10310 timeout = 0;
10311 if (res < 0) {
10312 ast_debug(1, "waitfordigit returned < 0...\n");
10313 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10314 ast_hangup(chan);
10315 goto quit;
10316 } else if (res) {
10317 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
10318 exten[len++]=res;
10319 exten[len] = '\0';
10320 }
10321 if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
10322 tone_zone_play_tone(p->subs[idx].dfd, -1);
10323 } else {
10324 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10325 }
10327 is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
10328 }
10329 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
10330 if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
10331 if (getforward) {
10332 /* Record this as the forwarding extension */
10333 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
10334 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
10335 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10336 if (res)
10337 break;
10338 usleep(500000);
10339 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10340 sleep(1);
10341 memset(exten, 0, sizeof(exten));
10342 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10343 len = 0;
10344 getforward = 0;
10345 } else {
10346 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10347 ast_channel_lock(chan);
10348 ast_channel_exten_set(chan, exten);
10349 if (!ast_strlen_zero(p->cid_num)) {
10350 if (!p->hidecallerid)
10351 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10352 else
10353 ast_set_callerid(chan, NULL, NULL, p->cid_num);
10354 }
10355 if (!ast_strlen_zero(p->cid_name)) {
10356 if (!p->hidecallerid)
10357 ast_set_callerid(chan, NULL, p->cid_name, NULL);
10358 }
10360 ast_channel_unlock(chan);
10361 dahdi_ec_enable(p);
10362 res = ast_pbx_run(chan);
10363 if (res) {
10364 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10365 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10366 }
10367 goto quit;
10368 }
10369 } else {
10370 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10371 so just set the timeout to matchdigit_timeout and wait some more */
10372 timeout = p->matchdigit_timeout;
10373 }
10374 } else if (res == 0) {
10375 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10376 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10377 dahdi_wait_event(p->subs[idx].dfd);
10378 ast_hangup(chan);
10379 goto quit;
10380 } else if (p->callwaiting && !strcmp(exten, "*70")) {
10381 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
10382 /* Disable call waiting if enabled */
10383 p->callwaiting = 0;
10384 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10385 if (res) {
10386 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10387 ast_channel_name(chan), strerror(errno));
10388 }
10389 len = 0;
10390 ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
10391 memset(exten, 0, sizeof(exten));
10392 timeout = p->firstdigit_timeout;
10393
10394 } else if (!strcmp(exten, pickupexten)) {
10395 /* Scan all channels and see if there are any
10396 * ringing channels that have call groups
10397 * that equal this channels pickup group
10398 */
10399 if (idx == SUB_REAL) {
10400 /* Switch us from Third call to Call Wait */
10401 if (p->subs[SUB_THREEWAY].owner) {
10402 /* If you make a threeway call and the *8# a call, it should actually
10403 look like a callwait */
10407 }
10408 dahdi_ec_enable(p);
10409 if (ast_pickup_call(chan)) {
10410 ast_debug(1, "No call pickup possible...\n");
10411 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10412 dahdi_wait_event(p->subs[idx].dfd);
10413 }
10414 ast_hangup(chan);
10415 goto quit;
10416 } else {
10417 ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
10418 ast_hangup(chan);
10419 goto quit;
10420 }
10421
10422 } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
10423 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
10424 /* Disable Caller*ID if enabled */
10425 p->hidecallerid = 1;
10430 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10431 if (res) {
10432 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10433 ast_channel_name(chan), strerror(errno));
10434 }
10435 len = 0;
10436 memset(exten, 0, sizeof(exten));
10437 timeout = p->firstdigit_timeout;
10438 } else if (p->callreturn && !strcmp(exten, "*69")) {
10439 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10440 break;
10441 } else if (!strcmp(exten, "*78")) {
10442 dahdi_dnd(p, 1);
10443 /* Do not disturb */
10444 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10445 getforward = 0;
10446 memset(exten, 0, sizeof(exten));
10447 len = 0;
10448 } else if (!strcmp(exten, "*79")) {
10449 dahdi_dnd(p, 0);
10450 /* Do not disturb */
10451 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10452 getforward = 0;
10453 memset(exten, 0, sizeof(exten));
10454 len = 0;
10455 } else if (p->cancallforward && !strcmp(exten, "*72")) {
10456 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10457 getforward = 1;
10458 memset(exten, 0, sizeof(exten));
10459 len = 0;
10460 } else if (p->cancallforward && !strcmp(exten, "*73")) {
10461 ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
10462 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10463 memset(p->call_forward, 0, sizeof(p->call_forward));
10464 getforward = 0;
10465 memset(exten, 0, sizeof(exten));
10466 len = 0;
10467 } else if ((p->transfer || p->canpark) && is_exten_parking
10468 && p->subs[SUB_THREEWAY].owner) {
10469 struct ast_bridge_channel *bridge_channel;
10470
10471 /*
10472 * This is a three way call, the main call being a real channel,
10473 * and we're parking the first call.
10474 */
10478 if (bridge_channel) {
10479 if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
10480 /*
10481 * Swap things around between the three-way and real call so we
10482 * can hear where the channel got parked.
10483 */
10484 ast_mutex_lock(&p->lock);
10485 p->owner = p->subs[SUB_THREEWAY].owner;
10488
10489 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
10491 ao2_ref(bridge_channel, -1);
10492 goto quit;
10493 }
10494 ao2_ref(bridge_channel, -1);
10495 }
10496 break;
10497 } else if (p->hidecallerid && !strcmp(exten, "*82")) {
10498 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
10499 /* Enable Caller*ID if enabled */
10500 p->hidecallerid = 0;
10502 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10503 if (res) {
10504 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10505 ast_channel_name(chan), strerror(errno));
10506 }
10507 len = 0;
10508 memset(exten, 0, sizeof(exten));
10509 timeout = p->firstdigit_timeout;
10510 } else if (!strcmp(exten, "*0")) {
10511 struct ast_channel *nbridge =
10513 struct dahdi_pvt *pbridge = NULL;
10514 RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
10515
10516 /* set up the private struct of the bridged one, if any */
10517 if (nbridge && bridged) {
10518 pbridge = ast_channel_tech_pvt(bridged);
10519 }
10520 if (nbridge && pbridge &&
10521 (ast_channel_tech(nbridge) == &dahdi_tech) &&
10522 (ast_channel_tech(bridged) == &dahdi_tech) &&
10523 ISTRUNK(pbridge)) {
10524 int func = DAHDI_FLASH;
10525 /* Clear out the dial buffer */
10526 p->dop.dialstr[0] = '\0';
10527 /* flash hookswitch */
10528 if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
10529 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
10530 ast_channel_name(nbridge), strerror(errno));
10531 }
10534 p->owner = p->subs[SUB_REAL].owner;
10536 ast_hangup(chan);
10537 goto quit;
10538 } else {
10539 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10540 dahdi_wait_event(p->subs[idx].dfd);
10541 tone_zone_play_tone(p->subs[idx].dfd, -1);
10544 p->owner = p->subs[SUB_REAL].owner;
10545 ast_hangup(chan);
10546 goto quit;
10547 }
10548 } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
10549 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
10550 && !canmatch_featurecode(pickupexten, exten)) {
10551 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
10552 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
10553 ast_channel_context(chan));
10554 break;
10555 }
10556 if (!timeout)
10557 timeout = p->interdigit_timeout;
10559 tone_zone_play_tone(p->subs[idx].dfd, -1);
10560 }
10561 break;
10562 case SIG_FXSLS:
10563 case SIG_FXSGS:
10564 case SIG_FXSKS:
10565 /* check for SMDI messages */
10566 if (p->use_smdi && p->smdi_iface) {
10568
10569 if (smdi_msg != NULL) {
10570 ast_channel_exten_set(chan, smdi_msg->fwd_st);
10571
10572 if (smdi_msg->type == 'B')
10573 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
10574 else if (smdi_msg->type == 'N')
10575 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
10576
10577 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan));
10578 } else {
10579 ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
10580 }
10581 }
10582
10583 if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
10584 number = smdi_msg->calling_st;
10585
10586 /* If we want caller id, we're in a prering state due to a polarity reversal
10587 * and we're set to use a polarity reversal to trigger the start of caller id,
10588 * grab the caller id and wait for ringing to start... */
10589 } else if (p->use_callerid && (ast_channel_state(chan) == AST_STATE_PRERING &&
10591 /* If set to use DTMF CID signalling, listen for DTMF */
10592 if (p->cid_signalling == CID_SIG_DTMF) {
10593 int k = 0;
10594 int off_ms;
10595 struct timeval start = ast_tvnow();
10596 int ms;
10597 cs = NULL;
10598 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
10599 dahdi_setlinear(p->subs[idx].dfd, 0);
10600 /*
10601 * We are the only party interested in the Rx stream since
10602 * we have not answered yet. We don't need or even want DTMF
10603 * emulation. The DTMF digits can come so fast that emulation
10604 * can drop some of them.
10605 */
10606 ast_channel_lock(chan);
10608 ast_channel_unlock(chan);
10609 off_ms = 4000;/* This is a typical OFF time between rings. */
10610 for (;;) {
10611 struct ast_frame *f;
10612
10613 ms = ast_remaining_ms(start, off_ms);
10614 res = ast_waitfor(chan, ms);
10615 if (res <= 0) {
10616 /*
10617 * We do not need to restore the dahdi_setlinear()
10618 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10619 * are hanging up the channel.
10620 */
10621 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10622 "Exiting simple switch\n");
10623 ast_hangup(chan);
10624 goto quit;
10625 }
10626 f = ast_read(chan);
10627 if (!f)
10628 break;
10629 if (f->frametype == AST_FRAME_DTMF) {
10630 if (k < ARRAY_LEN(dtmfbuf) - 1) {
10631 dtmfbuf[k++] = f->subclass.integer;
10632 }
10633 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10634 start = ast_tvnow();
10635 }
10636 ast_frfree(f);
10637 if (ast_channel_state(chan) == AST_STATE_RING ||
10639 break; /* Got ring */
10640 }
10641 ast_channel_lock(chan);
10643 ast_channel_unlock(chan);
10644 dtmfbuf[k] = '\0';
10645 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10646 /* Got cid and ring. */
10647 ast_debug(1, "CID got string '%s'\n", dtmfbuf);
10648 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10649 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid, flags);
10650 /* If first byte is NULL, we have no cid */
10651 if (!ast_strlen_zero(dtmfcid))
10652 number = dtmfcid;
10653 else
10654 number = NULL;
10655 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10656 } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
10658 if (cs) {
10659 int off_ms;
10660 struct timeval start;
10661 int ms;
10662 samples = 0;
10663#if 1
10664 bump_gains(p);
10665#endif
10666 /* Take out of linear mode for Caller*ID processing */
10667 dahdi_setlinear(p->subs[idx].dfd, 0);
10668
10669 /* First we wait and listen for the Caller*ID */
10670 for (;;) {
10671 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10672 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10673 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10674 callerid_free(cs);
10675 ast_hangup(chan);
10676 goto quit;
10677 }
10678 if (i & DAHDI_IOMUX_SIGEVENT) {
10679 res = dahdi_get_event(p->subs[idx].dfd);
10680 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10681 if (res == DAHDI_EVENT_NOALARM) {
10682 p->inalarm = 0;
10683 }
10684
10685 if (p->cid_signalling == CID_SIG_V23_JP) {
10686 if (res == DAHDI_EVENT_RINGBEGIN) {
10687 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10688 usleep(1);
10689 }
10690 } else {
10691 res = 0;
10692 break;
10693 }
10694 } else if (i & DAHDI_IOMUX_READ) {
10695 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10696 if (res < 0) {
10697 if (errno != ELAST) {
10698 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10699 callerid_free(cs);
10700 ast_hangup(chan);
10701 goto quit;
10702 }
10703 break;
10704 }
10705 samples += res;
10706
10707 if (p->cid_signalling == CID_SIG_V23_JP) {
10708 res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
10709 } else {
10710 res = callerid_feed(cs, buf, res, AST_LAW(p));
10711 }
10712 if (res < 0) {
10713 /*
10714 * The previous diagnostic message output likely
10715 * explains why it failed.
10716 */
10718 "Failed to decode CallerID on channel '%s'\n",
10719 ast_channel_name(chan));
10720 break;
10721 } else if (res)
10722 break;
10723 else if (samples > (8000 * 10))
10724 break;
10725 }
10726 }
10727 if (res == 1) {
10728 callerid_get(cs, &name, &number, &flags);
10729 ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
10730 }
10731
10732 if (p->cid_signalling == CID_SIG_V23_JP) {
10733 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
10734 usleep(1);
10735 }
10736
10737 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10738 start = ast_tvnow();
10739 off_ms = 4000;/* This is a typical OFF time between rings. */
10740 for (;;) {
10741 struct ast_frame *f;
10742
10743 ms = ast_remaining_ms(start, off_ms);
10744 res = ast_waitfor(chan, ms);
10745 if (res <= 0) {
10746 ast_log(LOG_WARNING, "CID timed out waiting for ring. "
10747 "Exiting simple switch\n");
10748 ast_hangup(chan);
10749 goto quit;
10750 }
10751 if (!(f = ast_read(chan))) {
10752 ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
10753 ast_hangup(chan);
10754 goto quit;
10755 }
10756 ast_frfree(f);
10757 if (ast_channel_state(chan) == AST_STATE_RING ||
10759 break; /* Got ring */
10760 }
10761
10762 /* We must have a ring by now, so, if configured, lets try to listen for
10763 * distinctive ringing */
10765 len = 0;
10766 distMatches = 0;
10767 /* Clear the current ring data array so we don't have old data in it. */
10768 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10769 curRingData[receivedRingT] = 0;
10770 receivedRingT = 0;
10771 counter = 0;
10772 counter1 = 0;
10773 /* Check to see if context is what it should be, if not set to be. */
10774 if (strcmp(p->context,p->defcontext) != 0) {
10775 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10777 }
10778
10779 for (;;) {
10780 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10781 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10782 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10783 callerid_free(cs);
10784 ast_hangup(chan);
10785 goto quit;
10786 }
10787 if (i & DAHDI_IOMUX_SIGEVENT) {
10788 res = dahdi_get_event(p->subs[idx].dfd);
10789 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10790 if (res == DAHDI_EVENT_NOALARM) {
10791 p->inalarm = 0;
10792 }
10793 res = 0;
10794 /* Let us detect distinctive ring */
10795
10796 curRingData[receivedRingT] = p->ringt;
10797
10798 if (p->ringt < p->ringt_base/2)
10799 break;
10800 /* Increment the ringT counter so we can match it against
10801 values in chan_dahdi.conf for distinctive ring */
10802 if (++receivedRingT == ARRAY_LEN(curRingData))
10803 break;
10804 } else if (i & DAHDI_IOMUX_READ) {
10805 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10806 if (res < 0) {
10807 if (errno != ELAST) {
10808 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10809 callerid_free(cs);
10810 ast_hangup(chan);
10811 goto quit;
10812 }
10813 break;
10814 }
10815 if (p->ringt > 0) {
10816 if (!(--p->ringt)) {
10817 res = -1;
10818 break;
10819 }
10820 }
10821 }
10822 }
10823 /* this only shows up if you have n of the dring patterns filled in */
10824 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
10825 for (counter = 0; counter < 3; counter++) {
10826 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10827 channel */
10828 distMatches = 0;
10829 for (counter1 = 0; counter1 < 3; counter1++) {
10830 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
10831 if (p->drings.ringnum[counter].ring[counter1] == -1) {
10832 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10833 curRingData[counter1]);
10834 distMatches++;
10835 } else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
10836 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
10837 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10838 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
10839 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
10840 distMatches++;
10841 }
10842 }
10843
10844 if (distMatches == 3) {
10845 /* The ring matches, set the context to whatever is for distinctive ring.. */
10846 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
10848 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
10849 break;
10850 }
10851 }
10852 }
10853 /* Restore linear mode (if appropriate) for Caller*ID processing */
10854 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10855#if 1
10856 restore_gains(p);
10857#endif
10858 } else
10859 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
10860 } else {
10861 ast_log(LOG_WARNING, "Channel %s in prering "
10862 "state, but I have nothing to do. "
10863 "Terminating simple switch, should be "
10864 "restarted by the actual ring.\n",
10865 ast_channel_name(chan));
10866 ast_hangup(chan);
10867 goto quit;
10868 }
10869 } else if (p->use_callerid && p->cid_start == CID_START_RING) {
10870 if (p->cid_signalling == CID_SIG_DTMF) {
10871 int k = 0;
10872 int off_ms;
10873 struct timeval start;
10874 int ms;
10875 cs = NULL;
10876 dahdi_setlinear(p->subs[idx].dfd, 0);
10877 off_ms = 2000;
10878 start = ast_tvnow();
10879 for (;;) {
10880 struct ast_frame *f;
10881
10882 ms = ast_remaining_ms(start, off_ms);
10883 res = ast_waitfor(chan, ms);
10884 if (res <= 0) {
10885 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10886 "Exiting simple switch\n");
10887 ast_hangup(chan);
10888 goto quit;
10889 }
10890 f = ast_read(chan);
10891 if (!f) {
10892 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10893 ast_hangup(chan);
10894 goto quit;
10895 }
10896 if (f->frametype == AST_FRAME_DTMF) {
10897 dtmfbuf[k++] = f->subclass.integer;
10898 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10899 start = ast_tvnow();
10900 }
10901 ast_frfree(f);
10902
10903 if (p->ringt_base == p->ringt)
10904 break;
10905 }
10906 dtmfbuf[k] = '\0';
10907 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10908 /* Got cid and ring. */
10909 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10910 ast_debug(1, "CID is '%s', flags %d\n",
10911 dtmfcid, flags);
10912 /* If first byte is NULL, we have no cid */
10913 if (!ast_strlen_zero(dtmfcid))
10914 number = dtmfcid;
10915 else
10916 number = NULL;
10917 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10918 } else {
10919 /* FSK Bell202 callerID */
10921 if (cs) {
10922#if 1
10923 bump_gains(p);
10924#endif
10925 samples = 0;
10926 len = 0;
10927 distMatches = 0;
10928 /* Clear the current ring data array so we don't have old data in it. */
10929 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10930 curRingData[receivedRingT] = 0;
10931 receivedRingT = 0;
10932 counter = 0;
10933 counter1 = 0;
10934 /* Check to see if context is what it should be, if not set to be. */
10935 if (strcmp(p->context,p->defcontext) != 0) {
10936 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10938 }
10939
10940 /* Take out of linear mode for Caller*ID processing */
10941 dahdi_setlinear(p->subs[idx].dfd, 0);
10942 for (;;) {
10943 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10944 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10945 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10946 callerid_free(cs);
10947 ast_hangup(chan);
10948 goto quit;
10949 }
10950 if (i & DAHDI_IOMUX_SIGEVENT) {
10951 res = dahdi_get_event(p->subs[idx].dfd);
10952 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10953 if (res == DAHDI_EVENT_NOALARM) {
10954 p->inalarm = 0;
10955 }
10956 /* If we get a PR event, they hung up while processing calerid */
10957 if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
10958 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
10960 callerid_free(cs);
10961 ast_hangup(chan);
10962 goto quit;
10963 }
10964 res = 0;
10965 /* Let us detect callerid when the telco uses distinctive ring */
10966
10967 curRingData[receivedRingT] = p->ringt;
10968
10969 if (p->ringt < p->ringt_base/2)
10970 break;
10971 /* Increment the ringT counter so we can match it against
10972 values in chan_dahdi.conf for distinctive ring */
10973 if (++receivedRingT == ARRAY_LEN(curRingData))
10974 break;
10975 } else if (i & DAHDI_IOMUX_READ) {
10976 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10977 if (res < 0) {
10978 if (errno != ELAST) {
10979 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10980 callerid_free(cs);
10981 ast_hangup(chan);
10982 goto quit;
10983 }
10984 break;
10985 }
10986 if (p->ringt > 0) {
10987 if (!(--p->ringt)) {
10988 res = -1;
10989 break;
10990 }
10991 }
10992 samples += res;
10993 res = callerid_feed(cs, buf, res, AST_LAW(p));
10994 if (res < 0) {
10995 /*
10996 * The previous diagnostic message output likely
10997 * explains why it failed.
10998 */
11000 "Failed to decode CallerID on channel '%s'\n",
11001 ast_channel_name(chan));
11002 break;
11003 } else if (res)
11004 break;
11005 else if (samples > (8000 * 10))
11006 break;
11007 }
11008 }
11009 if (res == 1) {
11010 callerid_get(cs, &name, &number, &flags);
11011 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
11012 }
11013 if (distinctiveringaftercid == 1) {
11014 /* Clear the current ring data array so we don't have old data in it. */
11015 for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
11016 curRingData[receivedRingT] = 0;
11017 }
11018 receivedRingT = 0;
11019 ast_verb(3, "Detecting post-CID distinctive ring\n");
11020 for (;;) {
11021 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11022 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
11023 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11024 callerid_free(cs);
11025 ast_hangup(chan);
11026 goto quit;
11027 }
11028 if (i & DAHDI_IOMUX_SIGEVENT) {
11029 res = dahdi_get_event(p->subs[idx].dfd);
11030 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
11031 if (res == DAHDI_EVENT_NOALARM) {
11032 p->inalarm = 0;
11033 }
11034 res = 0;
11035 /* Let us detect callerid when the telco uses distinctive ring */
11036
11037 curRingData[receivedRingT] = p->ringt;
11038
11039 if (p->ringt < p->ringt_base/2)
11040 break;
11041 /* Increment the ringT counter so we can match it against
11042 values in chan_dahdi.conf for distinctive ring */
11043 if (++receivedRingT == ARRAY_LEN(curRingData))
11044 break;
11045 } else if (i & DAHDI_IOMUX_READ) {
11046 res = read(p->subs[idx].dfd, buf, sizeof(buf));
11047 if (res < 0) {
11048 if (errno != ELAST) {
11049 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11050 callerid_free(cs);
11051 ast_hangup(chan);
11052 goto quit;
11053 }
11054 break;
11055 }
11056 if (p->ringt > 0) {
11057 if (!(--p->ringt)) {
11058 res = -1;
11059 break;
11060 }
11061 }
11062 }
11063 }
11064 }
11066 /* this only shows up if you have n of the dring patterns filled in */
11067 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
11068
11069 for (counter = 0; counter < 3; counter++) {
11070 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
11071 channel */
11072 /* this only shows up if you have n of the dring patterns filled in */
11073 ast_verb(3, "Checking %d,%d,%d\n",
11074 p->drings.ringnum[counter].ring[0],
11075 p->drings.ringnum[counter].ring[1],
11076 p->drings.ringnum[counter].ring[2]);
11077 distMatches = 0;
11078 for (counter1 = 0; counter1 < 3; counter1++) {
11079 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
11080 if (p->drings.ringnum[counter].ring[counter1] == -1) {
11081 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
11082 curRingData[counter1]);
11083 distMatches++;
11084 }
11085 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
11086 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
11087 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
11088 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
11089 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
11090 distMatches++;
11091 }
11092 }
11093 if (distMatches == 3) {
11094 /* The ring matches, set the context to whatever is for distinctive ring.. */
11095 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
11097 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
11098 break;
11099 }
11100 }
11101 }
11102 /* Restore linear mode (if appropriate) for Caller*ID processing */
11103 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
11104#if 1
11105 restore_gains(p);
11106#endif
11107 if (res < 0) {
11108 ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
11109 }
11110 } else
11111 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
11112 }
11113 } else
11114 cs = NULL;
11115
11116 if (number)
11119
11120 ao2_cleanup(smdi_msg);
11121
11122 if (cs)
11123 callerid_free(cs);
11124
11125 my_handle_notify_message(chan, p, flags, -1);
11126
11127 ast_channel_lock(chan);
11129 ast_channel_rings_set(chan, 1);
11130 ast_channel_unlock(chan);
11131 p->ringt = p->ringt_base;
11132 res = ast_pbx_run(chan);
11133 if (res) {
11134 ast_hangup(chan);
11135 ast_log(LOG_WARNING, "PBX exited non-zero\n");
11136 }
11137 goto quit;
11138 default:
11139 ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
11140 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11141 if (res < 0)
11142 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11143 }
11144 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11145 if (res < 0)
11146 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11147 ast_hangup(chan);
11148quit:
11153 return NULL;
11154}
11155
11158 unsigned char buf[READ_SIZE];
11159 size_t len;
11160};
11161
11162static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
11163{
11164 int x;
11165 int sum = 0;
11166
11167 if (!len)
11168 return 0;
11169
11170 for (x = 0; x < len; x++)
11171 sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
11172
11173 return sum / len;
11174}
11175
11176static void *mwi_thread(void *data)
11177{
11178 struct mwi_thread_data *mtd = data;
11179 struct callerid_state *cs;
11180 pthread_t threadid;
11181 int samples = 0;
11182 char *name, *number;
11183 int flags;
11184 int i, res;
11185 unsigned int spill_done = 0;
11186 int spill_result = -1;
11187
11188 if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
11189 goto quit_no_clean;
11190 }
11191
11192 callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
11193
11194 bump_gains(mtd->pvt);
11195
11196 for (;;) {
11197 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11198 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
11199 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11200 goto quit;
11201 }
11202
11203 if (i & DAHDI_IOMUX_SIGEVENT) {
11204 struct ast_channel *chan;
11205 ast_callid callid = 0;
11206 int callid_created;
11207
11208 /* If we get an event, screen out events that we do not act on.
11209 * Otherwise, cancel and go to the simple switch to let it deal with it.
11210 */
11211 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
11212
11213 switch (res) {
11214 case DAHDI_EVENT_NEONMWI_ACTIVE:
11215 case DAHDI_EVENT_NEONMWI_INACTIVE:
11216 case DAHDI_EVENT_NONE:
11217 case DAHDI_EVENT_BITSCHANGED:
11218 break;
11219 case DAHDI_EVENT_NOALARM:
11220 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11221 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11222
11223 analog_p->inalarm = 0;
11224 }
11225 mtd->pvt->inalarm = 0;
11227 break;
11228 case DAHDI_EVENT_ALARM:
11229 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11230 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11231
11232 analog_p->inalarm = 1;
11233 }
11234 mtd->pvt->inalarm = 1;
11235 res = get_alarms(mtd->pvt);
11236 handle_alarms(mtd->pvt, res);
11237 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11238 default:
11239 callid_created = ast_callid_threadstorage_auto(&callid);
11240 ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to analog_ss_thread\n", res, event2str(res));
11241 callerid_free(cs);
11242
11243 restore_gains(mtd->pvt);
11244 mtd->pvt->ringt = mtd->pvt->ringt_base;
11245
11246 if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid))) {
11247 int result;
11248
11249 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11251 } else {
11253 }
11254 if (result) {
11255 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
11256 res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11257 if (res < 0)
11258 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
11259 ast_hangup(chan);
11260 }
11261 } else {
11262 ast_log(LOG_WARNING, "Could not create channel to handle call\n");
11263 }
11264
11265 ast_callid_threadstorage_auto_clean(callid, callid_created);
11266 goto quit_no_clean;
11267 }
11268 } else if (i & DAHDI_IOMUX_READ) {
11269 if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
11270 if (errno != ELAST) {
11271 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11272 goto quit;
11273 }
11274 break;
11275 }
11276 samples += res;
11277 if (!spill_done) {
11278 if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
11279 /*
11280 * The previous diagnostic message output likely
11281 * explains why it failed.
11282 */
11283 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
11284 break;
11285 } else if (spill_result) {
11286 spill_done = 1;
11287 }
11288 } else {
11289 /* keep reading data until the energy level drops below the threshold
11290 so we don't get another 'trigger' on the remaining carrier signal
11291 */
11292 if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
11293 break;
11294 }
11295 if (samples > (8000 * 4)) /*Termination case - time to give up*/
11296 break;
11297 }
11298 }
11299
11300 if (spill_result == 1) {
11301 callerid_get(cs, &name, &number, &flags);
11302 if (flags & CID_MSGWAITING) {
11303 ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
11304 notify_message(mtd->pvt->mailbox, 1);
11305 } else if (flags & CID_NOMSGWAITING) {
11306 ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
11307 notify_message(mtd->pvt->mailbox, 0);
11308 } else {
11309 ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
11310 }
11311 }
11312
11313
11314quit:
11315 callerid_free(cs);
11316
11317 restore_gains(mtd->pvt);
11318
11319quit_no_clean:
11320 mtd->pvt->mwimonitoractive = 0;
11321 ast_free(mtd);
11322
11323 return NULL;
11324}
11325
11326/*
11327* The following three functions (mwi_send_init, mwi_send_process_buffer,
11328* mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11329* that are sent out via FXS port on voicemail state change. The execution of
11330* the mwi send is state driven and can either generate a ring pulse prior to
11331* sending the fsk spill or simply send an fsk spill.
11332*/
11333static int mwi_send_init(struct dahdi_pvt * pvt)
11334{
11335 int x;
11336
11337#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11338 /* Determine how this spill is to be sent */
11339 if (pvt->mwisend_rpas) {
11341 pvt->mwisendactive = 1;
11342 } else if (pvt->mwisend_fsk) {
11344 pvt->mwisendactive = 1;
11345 } else {
11346 pvt->mwisendactive = 0;
11347 return 0;
11348 }
11349#else
11350 if (mwisend_rpas) {
11352 } else {
11354 }
11355 pvt->mwisendactive = 1;
11356#endif
11357
11358 if (pvt->cidspill) {
11359 ast_log(LOG_WARNING, "cidspill already exists when trying to send FSK MWI\n");
11360 ast_free(pvt->cidspill);
11361 pvt->cidspill = NULL;
11362 pvt->cidpos = 0;
11363 pvt->cidlen = 0;
11364 }
11366 if (!pvt->cidspill) {
11367 pvt->mwisendactive = 0;
11368 return -1;
11369 }
11370 x = DAHDI_FLUSH_BOTH;
11371 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
11372 x = 3000;
11373 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
11374#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11375 if (pvt->mwisend_fsk) {
11376#endif
11378 CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
11379 pvt->cidpos = 0;
11380#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11381 }
11382#endif
11383 return 0;
11384}
11385
11386static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
11387{
11388 struct timeval now;
11389 int res;
11390
11391 /* sanity check to catch if this had been interrupted previously
11392 * i.e. state says there is more to do but there is no spill allocated
11393 */
11394 if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) {
11396 } else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
11397 /* Normal processing -- Perform mwi send action */
11398 switch ( pvt->mwisend_data.mwisend_current) {
11399 case MWI_SEND_SA:
11400 /* Send the Ring Pulse Signal Alert */
11401 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
11402 if (res) {
11403 ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
11404 goto quit;
11405 }
11406 res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING);
11408 break;
11409 case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */
11410 break;
11411 case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/
11412#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11413 if (pvt->mwisend_fsk) {
11414#endif
11415 gettimeofday(&now, NULL);
11416 if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) {
11418 }
11419#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11420 } else { /* support for mwisendtype=nofsk */
11422 }
11423#endif
11424 break;
11425 case MWI_SEND_SPILL:
11426 /* We read some number of bytes. Write an equal amount of data */
11427 if (0 < num_read) {
11428 if (num_read > pvt->cidlen - pvt->cidpos) {
11429 num_read = pvt->cidlen - pvt->cidpos;
11430 }
11431 res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
11432 if (res > 0) {
11433 pvt->cidpos += res;
11434 if (pvt->cidpos >= pvt->cidlen) {
11436 }
11437 } else {
11438 ast_log(LOG_WARNING, "MWI FSK Send Write failed: %s\n", strerror(errno));
11439 goto quit;
11440 }
11441 }
11442 break;
11443 case MWI_SEND_CLEANUP:
11444 /* For now, do nothing */
11446 break;
11447 default:
11448 /* Should not get here, punt*/
11449 goto quit;
11450 }
11451 }
11452
11454 if (pvt->cidspill) {
11455 ast_free(pvt->cidspill);
11456 pvt->cidspill = NULL;
11457 pvt->cidpos = 0;
11458 pvt->cidlen = 0;
11459 }
11460 pvt->mwisendactive = 0;
11461 }
11462 return 0;
11463quit:
11464 if (pvt->cidspill) {
11465 ast_free(pvt->cidspill);
11466 pvt->cidspill = NULL;
11467 pvt->cidpos = 0;
11468 pvt->cidlen = 0;
11469 }
11470 pvt->mwisendactive = 0;
11471 return -1;
11472}
11473
11474static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
11475{
11476 int handled = 0;
11477
11479 switch (event) {
11480 case DAHDI_EVENT_RINGEROFF:
11482 handled = 1;
11483
11484 if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
11485 ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
11486 ast_free(pvt->cidspill);
11487 pvt->cidspill = NULL;
11489 pvt->mwisendactive = 0;
11490 } else {
11492 gettimeofday(&pvt->mwisend_data.pause, NULL);
11493 }
11494 }
11495 break;
11496 /* Going off hook, I need to punt this spill */
11497 case DAHDI_EVENT_RINGOFFHOOK:
11498 if (pvt->cidspill) {
11499 ast_free(pvt->cidspill);
11500 pvt->cidspill = NULL;
11501 pvt->cidpos = 0;
11502 pvt->cidlen = 0;
11503 }
11505 pvt->mwisendactive = 0;
11506 break;
11507 case DAHDI_EVENT_RINGERON:
11508 case DAHDI_EVENT_HOOKCOMPLETE:
11509 break;
11510 default:
11511 break;
11512 }
11513 }
11514 return handled;
11515}
11516
11517/* destroy a range DAHDI channels, identified by their number */
11518static void dahdi_destroy_channel_range(int start, int end)
11519{
11520 struct dahdi_pvt *cur;
11521 struct dahdi_pvt *next;
11522 int destroyed_first = 0;
11523 int destroyed_last = 0;
11524
11526 ast_debug(1, "range: %d-%d\n", start, end);
11527 for (cur = iflist; cur; cur = next) {
11528 next = cur->next;
11529 if (cur->channel >= start && cur->channel <= end) {
11530 int x = DAHDI_FLASH;
11531
11532 if (cur->channel > destroyed_last) {
11533 destroyed_last = cur->channel;
11534 }
11535 if (destroyed_first < 1 || cur->channel < destroyed_first) {
11536 destroyed_first = cur->channel;
11537 }
11538 ast_debug(3, "Destroying %d\n", cur->channel);
11539 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11540 ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11541
11542 destroy_channel(cur, 1);
11544 }
11545 }
11547 if (destroyed_first > start || destroyed_last < end) {
11548 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11549 start, end, destroyed_first, destroyed_last);
11550 }
11551}
11552
11553#ifdef HAVE_OPENR2
11554static void dahdi_r2_destroy_nodev(void)
11555{
11556 struct r2link_entry *cur;
11557 AST_LIST_LOCK(&nodev_r2links);
11558 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
11559 int i;
11560 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
11561 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
11562 for (i = 0; i < r2->numchans; i++) {
11563 int channel;
11564 struct dahdi_pvt *pvt = r2->pvts[i];
11565 if (!pvt) {
11566 continue;
11567 }
11568 channel = pvt->channel;
11569 ast_debug(3, "About to destroy B-channel %d.\n", channel);
11571 }
11572 ast_debug(3, "Destroying R2 link\n");
11573 AST_LIST_REMOVE(&nodev_r2links, cur, list);
11574 if (r2->r2master != AST_PTHREADT_NULL) {
11575 pthread_cancel(r2->r2master);
11576 pthread_join(r2->r2master, NULL);
11577 r2->r2master = AST_PTHREADT_NULL;
11578 openr2_context_delete(r2->protocol_context);
11579 }
11580 ast_free(cur);
11581 }
11583 AST_LIST_UNLOCK(&nodev_r2links);
11584}
11585#endif
11586
11587static int setup_dahdi(int reload);
11588static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
11589
11590/*!
11591 * \internal
11592 * \brief create a range of new DAHDI channels
11593 *
11594 * \param start first channel in the range
11595 * \param end last channel in the range
11596 *
11597 * \retval RESULT_SUCCESS on success.
11598 * \retval RESULT_FAILURE on error.
11599 */
11600static int dahdi_create_channel_range(int start, int end)
11601{
11602 struct dahdi_pvt *cur;
11603 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
11604 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
11606 int ret = RESULT_FAILURE; /* be pessimistic */
11607
11608 ast_debug(1, "channel range caps: %d - %d\n", start, end);
11610 for (cur = iflist; cur; cur = cur->next) {
11611 if (cur->channel >= start && cur->channel <= end) {
11613 "channel range %d-%d is occupied\n",
11614 start, end);
11615 goto out;
11616 }
11617 }
11618#ifdef HAVE_PRI
11619 {
11620 int i, x;
11621 for (x = 0; x < NUM_SPANS; x++) {
11622 struct dahdi_pri *pri = pris + x;
11623
11624 if (!pris[x].pri.pvts[0]) {
11625 break;
11626 }
11627 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
11628 int channo = pri->dchannels[i];
11629
11630 if (!channo) {
11631 break;
11632 }
11633 if (!pri->pri.fds[i]) {
11634 break;
11635 }
11636 if (channo >= start && channo <= end) {
11638 "channel range %d-%d is occupied by span %d\n",
11639 start, end, x + 1);
11640 goto out;
11641 }
11642 }
11643 }
11644 }
11645#endif
11646 if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
11647 !conf.chan.cc_params) {
11648 goto out;
11649 }
11650 default_conf.wanted_channels_start = start;
11651 base_conf.wanted_channels_start = start;
11652 conf.wanted_channels_start = start;
11653 default_conf.wanted_channels_end = end;
11654 base_conf.wanted_channels_end = end;
11655 conf.wanted_channels_end = end;
11656 if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
11657 ret = RESULT_SUCCESS;
11658 }
11659out:
11662 ast_cc_config_params_destroy(conf.chan.cc_params);
11664 return ret;
11665}
11666
11667
11668static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
11669{
11670 int res;
11671 pthread_t threadid;
11672 struct ast_channel *chan;
11673 ast_callid callid = 0;
11674 int callid_created;
11675
11676 /* Handle an event on a given channel for the monitor thread. */
11677
11678 switch (event) {
11679 case DAHDI_EVENT_NONE:
11680 case DAHDI_EVENT_BITSCHANGED:
11681 break;
11682 case DAHDI_EVENT_WINKFLASH:
11683 case DAHDI_EVENT_RINGOFFHOOK:
11684 if (i->inalarm) break;
11685 if (i->radio) break;
11686 /* Got a ring/answer. What kind of channel are we? */
11687 switch (i->sig) {
11688 case SIG_FXOLS:
11689 case SIG_FXOGS:
11690 case SIG_FXOKS:
11691 res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11692 if (res && (errno == EBUSY)) {
11693 break;
11694 }
11695
11696 callid_created = ast_callid_threadstorage_auto(&callid);
11697
11698 /* Cancel VMWI spill */
11699 ast_free(i->cidspill);
11700 i->cidspill = NULL;
11702
11703 if (i->immediate) {
11704 dahdi_ec_enable(i);
11705 /* The channel is immediately up. Start right away */
11706 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
11707 chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, NULL, callid);
11708 if (!chan) {
11709 ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
11710 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11711 if (res < 0)
11712 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11713 }
11714 } else {
11715 /* Check for callerid, digits, etc */
11716 chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, NULL, callid);
11717 if (chan) {
11718 if (has_voicemail(i))
11719 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
11720 else
11721 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
11722 if (res < 0)
11723 ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
11724 if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11725 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11726 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11727 if (res < 0)
11728 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11729 ast_hangup(chan);
11730 }
11731 } else
11732 ast_log(LOG_WARNING, "Unable to create channel\n");
11733 }
11734
11736 break;
11737 case SIG_FXSLS:
11738 case SIG_FXSGS:
11739 case SIG_FXSKS:
11740 i->ringt = i->ringt_base;
11741 /* Fall through */
11742 case SIG_EMWINK:
11743 case SIG_FEATD:
11744 case SIG_FEATDMF:
11745 case SIG_FEATDMF_TA:
11746 case SIG_E911:
11747 case SIG_FGC_CAMA:
11748 case SIG_FGC_CAMAMF:
11749 case SIG_FEATB:
11750 case SIG_EM:
11751 case SIG_EM_E1:
11752 case SIG_SFWINK:
11753 case SIG_SF_FEATD:
11754 case SIG_SF_FEATDMF:
11755 case SIG_SF_FEATB:
11756 case SIG_SF:
11757 /* Check for callerid, digits, etc */
11758 callid_created = ast_callid_threadstorage_auto(&callid);
11759 if (i->cid_start == CID_START_POLARITY_IN) {
11760 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11761 } else {
11762 chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid);
11763 }
11764
11765 if (!chan) {
11766 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11767 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11768 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11769 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11770 if (res < 0) {
11771 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11772 }
11773 ast_hangup(chan);
11774 }
11775
11777 break;
11778 default:
11779 ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11780 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11781 if (res < 0)
11782 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11783 return NULL;
11784 }
11785 break;
11786 case DAHDI_EVENT_NOALARM:
11787 switch (i->sig) {
11788#if defined(HAVE_PRI)
11790 ast_mutex_lock(&i->lock);
11793 break;
11794#endif /* defined(HAVE_PRI) */
11795#if defined(HAVE_SS7)
11796 case SIG_SS7:
11798 break;
11799#endif /* defined(HAVE_SS7) */
11800 default:
11801 i->inalarm = 0;
11802 break;
11803 }
11805 break;
11806 case DAHDI_EVENT_ALARM:
11807 switch (i->sig) {
11808#if defined(HAVE_PRI)
11810 ast_mutex_lock(&i->lock);
11813 break;
11814#endif /* defined(HAVE_PRI) */
11815#if defined(HAVE_SS7)
11816 case SIG_SS7:
11818 break;
11819#endif /* defined(HAVE_SS7) */
11820 default:
11821 i->inalarm = 1;
11822 break;
11823 }
11824 res = get_alarms(i);
11825 handle_alarms(i, res);
11826 /* fall thru intentionally */
11827 case DAHDI_EVENT_ONHOOK:
11828 if (i->radio)
11829 break;
11830 /* Back on hook. Hang up. */
11831 switch (i->sig) {
11832 case SIG_FXOLS:
11833 case SIG_FXOGS:
11834 case SIG_FEATD:
11835 case SIG_FEATDMF:
11836 case SIG_FEATDMF_TA:
11837 case SIG_E911:
11838 case SIG_FGC_CAMA:
11839 case SIG_FGC_CAMAMF:
11840 case SIG_FEATB:
11841 case SIG_EM:
11842 case SIG_EM_E1:
11843 case SIG_EMWINK:
11844 case SIG_SF_FEATD:
11845 case SIG_SF_FEATDMF:
11846 case SIG_SF_FEATB:
11847 case SIG_SF:
11848 case SIG_SFWINK:
11849 case SIG_FXSLS:
11850 case SIG_FXSGS:
11851 case SIG_FXSKS:
11852 case SIG_FXOKS:
11854 /* Diddle the battery for the zhone */
11855#ifdef ZHONE_HACK
11856 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11857 usleep(1);
11858#endif
11859 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11860 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
11861 break;
11862 case SIG_SS7:
11865 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11866 break;
11867 default:
11868 ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11869 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11870 return NULL;
11871 }
11872 break;
11873 case DAHDI_EVENT_POLARITY:
11874 switch (i->sig) {
11875 case SIG_FXSLS:
11876 case SIG_FXSKS:
11877 case SIG_FXSGS:
11878 /* We have already got a PR before the channel was
11879 created, but it wasn't handled. We need polarity
11880 to be REV for remote hangup detection to work.
11881 At least in Spain */
11882 callid_created = ast_callid_threadstorage_auto(&callid);
11887 ast_verb(2, "Starting post polarity "
11888 "CID detection on channel %d\n",
11889 i->channel);
11890 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11891 if (!chan) {
11892 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11893 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11894 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11895 ast_hangup(chan);
11896 }
11897 }
11899 break;
11900 default:
11901 ast_log(LOG_WARNING, "handle_init_event detected "
11902 "polarity reversal on non-FXO (SIG_FXS) "
11903 "interface %d\n", i->channel);
11904 }
11905 break;
11906 case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
11908 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11909 i->channel);
11910 return i;
11911 case DAHDI_EVENT_NEONMWI_ACTIVE:
11912 if (i->mwimonitor_neon) {
11913 notify_message(i->mailbox, 1);
11914 ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
11915 }
11916 break;
11917 case DAHDI_EVENT_NEONMWI_INACTIVE:
11918 if (i->mwimonitor_neon) {
11919 notify_message(i->mailbox, 0);
11920 ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
11921 }
11922 break;
11923 }
11924 return NULL;
11925}
11926
11927static void monitor_pfds_clean(void *arg) {
11928 struct pollfd **pfds = arg;
11929 ast_free(*pfds);
11930}
11931
11932static void *do_monitor(void *data)
11933{
11934 int count, res, res2, spoint, pollres=0;
11935 struct dahdi_pvt *i;
11936 struct dahdi_pvt *last = NULL;
11937 struct dahdi_pvt *doomed;
11938 time_t thispass = 0, lastpass = 0;
11939 int found;
11940 char buf[1024];
11941 struct pollfd *pfds=NULL;
11942 int lastalloc = -1;
11943 /* This thread monitors all the frame relay interfaces which are not yet in use
11944 (and thus do not have a separate thread) indefinitely */
11945 /* From here on out, we die whenever asked */
11946#if 0
11947 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
11948 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
11949 return NULL;
11950 }
11951 ast_debug(1, "Monitor starting...\n");
11952#endif
11953 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11954
11955 pthread_cleanup_push(monitor_pfds_clean, &pfds);
11956 for (;;) {
11957 /* Lock the interface list */
11959 if (!pfds || (lastalloc != ifcount)) {
11960 if (pfds) {
11961 ast_free(pfds);
11962 pfds = NULL;
11963 }
11964 if (ifcount) {
11965 if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
11967 return NULL;
11968 }
11969 }
11970 lastalloc = ifcount;
11971 }
11972 /* Build the stuff we're going to poll on, that is the socket of every
11973 dahdi_pvt that does not have an associated owner channel */
11974 count = 0;
11975 for (i = iflist; i; i = i->next) {
11976 ast_mutex_lock(&i->lock);
11977 if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
11978 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
11979 struct analog_pvt *p = i->sig_pvt;
11980
11981 if (!p) {
11982 ast_log(LOG_ERROR, "No sig_pvt?\n");
11983 } else if (!p->owner && !p->subs[SUB_REAL].owner) {
11984 /* This needs to be watched, as it lacks an owner */
11985 pfds[count].fd = i->subs[SUB_REAL].dfd;
11986 pfds[count].events = POLLPRI;
11987 pfds[count].revents = 0;
11988 /* Message waiting or r2 channels also get watched for reading */
11989 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
11990 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
11991 pfds[count].events |= POLLIN;
11992 }
11993 count++;
11994 }
11995 } else {
11996 if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
11997 /* This needs to be watched, as it lacks an owner */
11998 pfds[count].fd = i->subs[SUB_REAL].dfd;
11999 pfds[count].events = POLLPRI;
12000 pfds[count].revents = 0;
12001 /* If we are monitoring for VMWI or sending CID, we need to
12002 read from the channel as well */
12003 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12004 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12005 pfds[count].events |= POLLIN;
12006 }
12007 count++;
12008 }
12009 }
12010 }
12012 }
12013 /* Okay, now that we know what to do, release the interface lock */
12015
12016 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
12017 pthread_testcancel();
12018 /* Wait at least a second for something to happen */
12019 res = poll(pfds, count, 1000);
12020 pthread_testcancel();
12021 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
12022
12023 /* Okay, poll has finished. Let's see what happened. */
12024 if (res < 0) {
12025 if ((errno != EAGAIN) && (errno != EINTR))
12026 ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
12027 continue;
12028 }
12029 /* Alright, lock the interface list again, and let's look and see what has
12030 happened */
12032 found = 0;
12033 spoint = 0;
12034 lastpass = thispass;
12035 thispass = time(NULL);
12036 doomed = NULL;
12037 for (i = iflist;; i = i->next) {
12038 if (doomed) {
12040 doomed = NULL;
12041 }
12042 if (!i) {
12043 break;
12044 }
12045
12046 if (thispass != lastpass) {
12047 if (!found && ((i == last) || ((i == iflist) && !last))) {
12048 last = i;
12049 if (last) {
12050 struct analog_pvt *analog_p = last->sig_pvt;
12051 /* Only allow MWI to be initiated on a quiescent fxs port */
12052 if (analog_p
12053 && !last->mwisendactive
12054 && (last->sig & __DAHDI_SIG_FXO)
12055 && !analog_p->fxsoffhookstate
12056 && !last->owner
12057 && (!ast_strlen_zero(last->mailbox) || last->mwioverride_active)
12058 && !analog_p->subs[SUB_REAL].owner /* could be a recall ring from a flash hook hold */
12059 && (thispass - analog_p->onhooktime > 3)
12060 /* In some cases, all of the above checks will pass even if the line is really off-hook.
12061 * This last check will give the right answer 100% of the time, but is relatively
12062 * "expensive" (it requires an ioctl), so it is last to avoid unnecessary system calls. */
12063 && !my_is_off_hook(last)) {
12064 res = has_voicemail(last);
12065 if (analog_p->msgstate != res) {
12066 /* Set driver resources for signalling VMWI */
12067 res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
12068 if (res2) {
12069 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
12070 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
12071 }
12072 /* If enabled for FSK spill then initiate it */
12073 ast_debug(5, "Initiating MWI FSK spill on channel %d\n", last->channel);
12074 if (mwi_send_init(last)) {
12075 ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
12076 }
12077 analog_p->msgstate = res;
12078 found ++;
12079 }
12080 }
12081 last = last->next;
12082 }
12083 }
12084 }
12085 if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
12086 if (i->radio && !i->owner)
12087 {
12088 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12089 if (res)
12090 {
12091 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
12092 /* Don't hold iflock while handling init events */
12094 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12096 else
12097 doomed = handle_init_event(i, res);
12099 }
12100 continue;
12101 }
12102 pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
12103 if (pollres & POLLIN) {
12104 if (i->owner || i->subs[SUB_REAL].owner) {
12105#ifdef HAVE_PRI
12106 if (!i->pri)
12107#endif
12108 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
12109 continue;
12110 }
12112 ast_log(LOG_WARNING, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
12113 continue;
12114 }
12115 res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
12116 if (res > 0) {
12117 if (i->mwimonitor_fsk) {
12118 if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
12119 pthread_attr_t attr;
12120 pthread_t threadid;
12121 struct mwi_thread_data *mtd;
12122
12123 pthread_attr_init(&attr);
12124 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
12125
12126 ast_debug(1, "Maybe some MWI on port %d!\n", i->channel);
12127 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
12128 mtd->pvt = i;
12129 memcpy(mtd->buf, buf, res);
12130 mtd->len = res;
12131 i->mwimonitoractive = 1;
12132 if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
12133 ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
12134 i->mwimonitoractive = 0;
12135 ast_free(mtd);
12136 }
12137 }
12138 }
12139 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
12140 } else if (i->cid_start == CID_START_DTMF_NOALERT) {
12141 int energy;
12142 struct timeval now;
12143 /* State machine dtmfcid_holdoff_state allows for the line to settle
12144 * before checking again for dtmf energy. Presently waits for 500 mS before checking again
12145 */
12146 if (1 == i->dtmfcid_holdoff_state) {
12147 gettimeofday(&i->dtmfcid_delay, NULL);
12148 i->dtmfcid_holdoff_state = 2;
12149 } else if (2 == i->dtmfcid_holdoff_state) {
12150 gettimeofday(&now, NULL);
12151 if ((int)(now.tv_sec - i->dtmfcid_delay.tv_sec) * 1000000 + (int)now.tv_usec - (int)i->dtmfcid_delay.tv_usec > 500000) {
12152 i->dtmfcid_holdoff_state = 0;
12153 }
12154 } else {
12155 energy = calc_energy((unsigned char *) buf, res, AST_LAW(i));
12156 if (!i->mwisendactive && energy > dtmfcid_level) {
12157 pthread_t threadid;
12158 struct ast_channel *chan;
12160 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12161 /* just in case this event changes or somehow destroys a channel, set doomed here too */
12163 i->dtmfcid_holdoff_state = 1;
12164 } else {
12165 ast_callid callid = 0;
12166 int callid_created = ast_callid_threadstorage_auto(&callid);
12167 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
12168 if (!chan) {
12169 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
12170 } else {
12171 res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
12172 if (res) {
12173 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
12174 ast_hangup(chan);
12175 } else {
12176 i->dtmfcid_holdoff_state = 1;
12177 }
12178 }
12180 }
12182 }
12183 }
12184 }
12185 if (i->mwisendactive) {
12187 }
12188 } else {
12189 ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
12190 }
12191 }
12192 if (pollres & POLLPRI) {
12193 if (i->owner || i->subs[SUB_REAL].owner) {
12194#ifdef HAVE_PRI
12195 if (!i->pri)
12196#endif
12197 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
12198 continue;
12199 }
12200 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12201 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
12202 /* Don't hold iflock while handling init events */
12204 if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
12205 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12207 else
12208 doomed = handle_init_event(i, res);
12209 }
12210 if (i->doreoriginate && res == DAHDI_EVENT_HOOKCOMPLETE) {
12211 /* Actually automatically reoriginate this FXS line, if directed to.
12212 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12213 * doing its thing (one reason why this is for FXOKS only: FXOLS
12214 * hangups don't give us any DAHDI events to piggyback off of)*/
12215 i->doreoriginate = 0;
12216 /* Double check the channel is still off-hook. There's only about a millisecond
12217 * between when doreoriginate is set high and we see that here, but just to be safe. */
12218 if (!my_is_off_hook(i)) {
12219 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i->channel);
12220 } else {
12221 ast_verb(3, "Automatic reorigination on channel %d\n", i->channel);
12222 res = DAHDI_EVENT_RINGOFFHOOK; /* Pretend that the physical channel just went off hook */
12223 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12225 } else {
12226 doomed = handle_init_event(i, res);
12227 }
12228 }
12229 }
12231 }
12232 }
12233 }
12236#ifdef HAVE_OPENR2
12237 dahdi_r2_destroy_nodev();
12238#endif
12239 }
12240 /* Never reached */
12241 pthread_cleanup_pop(1);
12242 return NULL;
12243
12244}
12245
12246static int restart_monitor(void)
12247{
12248 /* If we're supposed to be stopped -- stay stopped */
12250 return 0;
12252 if (monitor_thread == pthread_self()) {
12254 ast_log(LOG_WARNING, "Cannot kill myself\n");
12255 return -1;
12256 }
12258 /* Wake up the thread */
12259 pthread_kill(monitor_thread, SIGURG);
12260 } else {
12261 /* Start a new monitor */
12264 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
12265 return -1;
12266 }
12267 }
12269 return 0;
12270}
12271
12272#if defined(HAVE_PRI)
12273static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
12274{
12275 int x;
12276 int trunkgroup;
12277 /* Get appropriate trunk group if there is one */
12278 trunkgroup = pris[*span].mastertrunkgroup;
12279 if (trunkgroup) {
12280 /* Select a specific trunk group */
12281 for (x = 0; x < NUM_SPANS; x++) {
12282 if (pris[x].pri.trunkgroup == trunkgroup) {
12283 *span = x;
12284 return 0;
12285 }
12286 }
12287 ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
12288 *span = -1;
12289 } else {
12290 if (pris[*span].pri.trunkgroup) {
12291 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);
12292 *span = -1;
12293 } else if (pris[*span].mastertrunkgroup) {
12294 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
12295 *span = -1;
12296 } else {
12297 if (si->totalchans == 31) {
12298 /* E1 */
12299 pris[*span].dchannels[0] = 16 + offset;
12300 } else if (si->totalchans == 24) {
12301 /* T1 or J1 */
12302 pris[*span].dchannels[0] = 24 + offset;
12303 } else if (si->totalchans == 3) {
12304 /* BRI */
12305 pris[*span].dchannels[0] = 3 + offset;
12306 } else {
12307 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);
12308 *span = -1;
12309 return 0;
12310 }
12311 pris[*span].pri.span = *span + 1;
12312 }
12313 }
12314 return 0;
12315}
12316#endif /* defined(HAVE_PRI) */
12317
12318#if defined(HAVE_PRI)
12319static int pri_create_trunkgroup(int trunkgroup, int *channels)
12320{
12321 struct dahdi_spaninfo si;
12322 struct dahdi_params p;
12323 int fd;
12324 int span;
12325 int ospan=0;
12326 int x,y;
12327 for (x = 0; x < NUM_SPANS; x++) {
12328 if (pris[x].pri.trunkgroup == trunkgroup) {
12329 ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
12330 return -1;
12331 }
12332 }
12333 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12334 if (!channels[y])
12335 break;
12336 memset(&si, 0, sizeof(si));
12337 memset(&p, 0, sizeof(p));
12338 fd = open("/dev/dahdi/channel", O_RDWR);
12339 if (fd < 0) {
12340 ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
12341 return -1;
12342 }
12343 x = channels[y];
12344 if (ioctl(fd, DAHDI_SPECIFY, &x)) {
12345 ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
12346 close(fd);
12347 return -1;
12348 }
12349 if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
12350 ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
12351 close(fd);
12352 return -1;
12353 }
12354 if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
12355 ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
12356 close(fd);
12357 return -1;
12358 }
12359 span = p.spanno - 1;
12360 if (pris[span].pri.trunkgroup) {
12361 ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].pri.trunkgroup);
12362 close(fd);
12363 return -1;
12364 }
12365 if (pris[span].pri.pvts[0]) {
12366 ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
12367 close(fd);
12368 return -1;
12369 }
12370 if (!y) {
12371 pris[span].pri.trunkgroup = trunkgroup;
12372 ospan = span;
12373 }
12374 pris[ospan].dchannels[y] = channels[y];
12375 pris[span].pri.span = span + 1;
12376 close(fd);
12377 }
12378 return 0;
12379}
12380#endif /* defined(HAVE_PRI) */
12381
12382#if defined(HAVE_PRI)
12383static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
12384{
12385 if (pris[span].mastertrunkgroup) {
12386 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);
12387 return -1;
12388 }
12389 pris[span].mastertrunkgroup = trunkgroup;
12390 pris[span].prilogicalspan = logicalspan;
12391 return 0;
12392}
12393#endif /* defined(HAVE_PRI) */
12394
12395#if defined(HAVE_SS7)
12396static unsigned int parse_pointcode(const char *pcstring)
12397{
12398 unsigned int code1, code2, code3;
12399 int numvals;
12400
12401 numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
12402 if (numvals == 1)
12403 return code1;
12404 if (numvals == 3)
12405 return (code1 << 16) | (code2 << 8) | code3;
12406
12407 return 0;
12408}
12409#endif /* defined(HAVE_SS7) */
12410
12411#if defined(HAVE_SS7)
12412static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
12413{
12414 if ((linkset < 0) || (linkset >= NUM_SPANS))
12415 return NULL;
12416 else
12417 return &linksets[linkset - 1];
12418}
12419#endif /* defined(HAVE_SS7) */
12420
12421#ifdef HAVE_OPENR2
12422static void dahdi_r2_destroy_links(void)
12423{
12424 struct r2link_entry *cur;
12425
12426 /* Queue everything for removal */
12427 AST_LIST_LOCK(&r2links);
12428 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
12429 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
12430 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
12431 }
12433 AST_LIST_UNLOCK(&r2links);
12434 /* Now destroy properly */
12435 dahdi_r2_destroy_nodev();
12436}
12437
12438/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12439#define R2_LINK_CAPACITY 30
12440static struct r2link_entry *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
12441{
12442 struct r2link_entry *cur = NULL;
12443 /* Only create a new R2 link if
12444 1. This is the first link requested
12445 2. Configuration changed
12446 3. We got more channels than supported per link */
12447 AST_LIST_LOCK(&r2links);
12448 if (! AST_LIST_EMPTY(&r2links)) {
12449 cur = AST_LIST_LAST(&r2links);
12450 if (memcmp(&conf->mfcr2, &cur->mfcr2.conf, sizeof(conf->mfcr2))) {
12451 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12452 cur = NULL;
12453 } else if (cur->mfcr2.numchans == R2_LINK_CAPACITY) {
12454 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY);
12455 cur = NULL;
12456 }
12457 }
12458 if (!cur) {
12459 struct r2link_entry *tmp = NULL;
12460 int new_idx = r2links_count + 1;
12461 int i;
12462 for (i = 1; i <= r2links_count; i++) {
12463 int i_unused = 1;
12464 AST_LIST_TRAVERSE(&r2links, tmp, list) {
12465 if (i == tmp->mfcr2.index) {
12466 i_unused = 0;
12467 break;
12468 }
12469 }
12470 if (i_unused) {
12471 new_idx = i;
12472 break;
12473 }
12474 }
12475 cur = ast_calloc(1, sizeof(*cur));
12476 if (!cur) {
12477 ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
12478 return NULL;
12479 }
12480 cur->mfcr2.index = new_idx;
12481 cur->mfcr2.r2master = AST_PTHREADT_NULL;
12482 r2links_count++;
12483 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx, r2links_count);
12484 AST_LIST_INSERT_TAIL(&r2links, cur, list);
12485 }
12486 AST_LIST_UNLOCK(&r2links);
12487 return cur;
12488}
12489
12490static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_chan_conf *conf)
12491{
12492 char tmplogdir[] = "/tmp";
12493 char logdir[OR2_MAX_PATH];
12494 int threshold = 0;
12495 int snres = 0;
12496 r2_link->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
12497 &dahdi_r2_transcode_iface, conf->mfcr2.variant, conf->mfcr2.max_ani,
12498 conf->mfcr2.max_dnis);
12499 if (!r2_link->protocol_context) {
12500 return -1;
12501 }
12502 openr2_context_set_log_level(r2_link->protocol_context, conf->mfcr2.loglevel);
12503 openr2_context_set_ani_first(r2_link->protocol_context, conf->mfcr2.get_ani_first);
12504#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12505 openr2_context_set_skip_category_request(r2_link->protocol_context, conf->mfcr2.skip_category_request);
12506#endif
12507 openr2_context_set_mf_threshold(r2_link->protocol_context, threshold);
12508 openr2_context_set_mf_back_timeout(r2_link->protocol_context, conf->mfcr2.mfback_timeout);
12509 openr2_context_set_metering_pulse_timeout(r2_link->protocol_context, conf->mfcr2.metering_pulse_timeout);
12510 openr2_context_set_double_answer(r2_link->protocol_context, conf->mfcr2.double_answer);
12511 openr2_context_set_immediate_accept(r2_link->protocol_context, conf->mfcr2.immediate_accept);
12512#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12513 openr2_context_set_dtmf_dialing(r2_link->protocol_context, conf->mfcr2.dtmf_dialing, conf->mfcr2.dtmf_time_on, conf->mfcr2.dtmf_time_off);
12514 openr2_context_set_dtmf_detection(r2_link->protocol_context, conf->mfcr2.dtmf_detection);
12515#endif
12516#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12517 openr2_context_set_dtmf_detection_end_timeout(r2_link->protocol_context, conf->mfcr2.dtmf_end_timeout);
12518#endif
12519 if (ast_strlen_zero(conf->mfcr2.logdir)) {
12520 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12521 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12522 }
12523 } else {
12524 snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", conf->mfcr2.logdir);
12525 if (snres >= sizeof(logdir)) {
12526 ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
12527 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12528 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12529 }
12530 } else {
12531 if (openr2_context_set_log_directory(r2_link->protocol_context, logdir)) {
12532 ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
12533 }
12534 }
12535 }
12536 if (!ast_strlen_zero(conf->mfcr2.r2proto_file)) {
12537 if (openr2_context_configure_from_advanced_file(r2_link->protocol_context, conf->mfcr2.r2proto_file)) {
12538 ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", conf->mfcr2.r2proto_file);
12539 }
12540 }
12541 /* Save the configuration used to setup this link */
12542 memcpy(&r2_link->conf, &conf->mfcr2, sizeof(r2_link->conf));
12543 return 0;
12544}
12545#endif
12546
12547/* converts a DAHDI sigtype to signalling as can be configured from
12548 * chan_dahdi.conf.
12549 * While both have basically the same values, this will later be the
12550 * place to add filters and sanity checks
12551 */
12553{
12554 return sigtype;
12555}
12556
12557/*!
12558 * \internal
12559 * \brief Initialize/create a channel interface.
12560 *
12561 * \param channel Channel interface number to initialize/create.
12562 * \param conf Configuration parameters to initialize interface with.
12563 * \param reloading What we are doing now:
12564 * 0 - initial module load,
12565 * 1 - module reload,
12566 * 2 - module restart
12567 *
12568 * \retval Interface-pointer initialized/created
12569 * \retval NULL if error
12570 */
12571static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
12572{
12573 /* Make a dahdi_pvt structure for this interface */
12574 struct dahdi_pvt *tmp;/*!< Current channel structure initializing */
12575 char fn[80];
12576 struct dahdi_bufferinfo bi;
12577
12578 int res;
12579#if defined(HAVE_PRI)
12580 int span = 0;
12581#endif /* defined(HAVE_PRI) */
12582 int here = 0;/*!< TRUE if the channel interface already exists. */
12583 int x;
12584 struct analog_pvt *analog_p = NULL;
12585 struct dahdi_params p;
12586#if defined(HAVE_PRI)
12587 struct dahdi_spaninfo si;
12588 struct sig_pri_chan *pri_chan = NULL;
12589#endif /* defined(HAVE_PRI) */
12590#if defined(HAVE_SS7)
12591 struct sig_ss7_chan *ss7_chan = NULL;
12592#endif /* defined(HAVE_SS7) */
12593
12594 /* Search channel interface list to see if it already exists. */
12595 for (tmp = iflist; tmp; tmp = tmp->next) {
12596 if (!tmp->destroy) {
12597 if (tmp->channel == channel) {
12598 /* The channel interface already exists. */
12599 here = 1;
12600 break;
12601 }
12602 if (tmp->channel > channel) {
12603 /* No way it can be in the sorted list. */
12604 tmp = NULL;
12605 break;
12606 }
12607 }
12608 }
12609
12610 if (!here && reloading != 1) {
12611 tmp = ast_calloc(1, sizeof(*tmp));
12612 if (!tmp) {
12613 return NULL;
12614 }
12616 if (!tmp->cc_params) {
12617 ast_free(tmp);
12618 return NULL;
12619 }
12620 ast_mutex_init(&tmp->lock);
12621 ifcount++;
12622 for (x = 0; x < 3; x++)
12623 tmp->subs[x].dfd = -1;
12624 tmp->channel = channel;
12625 tmp->priindication_oob = conf->chan.priindication_oob;
12626 }
12627
12628 if (tmp) {
12629 int chan_sig = conf->chan.sig;
12630
12631 /* If there are variables in tmp before it is updated to match the new config, clear them */
12632 if (reloading && tmp->vars) {
12634 tmp->vars = NULL;
12635 }
12636
12637 if (!here) {
12638 /* Can only get here if this is a new channel interface being created. */
12639 if ((channel != CHAN_PSEUDO)) {
12640 int count = 0;
12641
12642 snprintf(fn, sizeof(fn), "%d", channel);
12643 /* Open non-blocking */
12644 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12645 /* Retry open on restarts, but don't keep retrying if the channel doesn't exist (e.g. not configured) */
12646 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 */
12647 usleep(1);
12648 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12649 count++;
12650 }
12651 /* Allocate a DAHDI structure */
12652 if (tmp->subs[SUB_REAL].dfd < 0) {
12653 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);
12654 destroy_dahdi_pvt(tmp);
12655 return NULL;
12656 }
12657 memset(&p, 0, sizeof(p));
12658 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
12659 if (res < 0) {
12660 ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
12661 destroy_dahdi_pvt(tmp);
12662 return NULL;
12663 }
12664 if (conf->is_sig_auto)
12665 chan_sig = sigtype_to_signalling(p.sigtype);
12666 if (p.sigtype != (chan_sig & 0x3ffff)) {
12667 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));
12668 destroy_dahdi_pvt(tmp);
12669 return NULL;
12670 }
12671 tmp->law_default = p.curlaw;
12672 tmp->law = p.curlaw;
12673 tmp->span = p.spanno;
12674#if defined(HAVE_PRI)
12675 span = p.spanno - 1;
12676#endif /* defined(HAVE_PRI) */
12677 } else {
12678 chan_sig = 0;
12679 }
12680 tmp->sig = chan_sig;
12681 tmp->outsigmod = conf->chan.outsigmod;
12682
12683 if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
12684 analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
12685 if (!analog_p) {
12686 destroy_dahdi_pvt(tmp);
12687 return NULL;
12688 }
12689 tmp->sig_pvt = analog_p;
12690 }
12691#if defined(HAVE_SS7)
12692 if (chan_sig == SIG_SS7) {
12693 struct dahdi_ss7 *ss7;
12694 int clear = 0;
12695
12696 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
12697 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12698 destroy_dahdi_pvt(tmp);
12699 return NULL;
12700 }
12701
12702 ss7 = ss7_resolve_linkset(cur_linkset);
12703 if (!ss7) {
12704 ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
12705 destroy_dahdi_pvt(tmp);
12706 return NULL;
12707 }
12708 ss7->ss7.span = cur_linkset;
12709 if (cur_cicbeginswith < 0) {
12710 ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
12711 destroy_dahdi_pvt(tmp);
12712 return NULL;
12713 }
12714 ss7_chan = sig_ss7_chan_new(tmp, &ss7->ss7);
12715 if (!ss7_chan) {
12716 destroy_dahdi_pvt(tmp);
12717 return NULL;
12718 }
12719 tmp->sig_pvt = ss7_chan;
12720 tmp->ss7 = &ss7->ss7;
12721
12722 ss7_chan->channel = tmp->channel;
12723 ss7_chan->cic = cur_cicbeginswith++;
12724
12725 /* DB: Add CIC's DPC information */
12726 ss7_chan->dpc = cur_defaultdpc;
12727
12728 ss7->ss7.pvts[ss7->ss7.numchans++] = ss7_chan;
12729
12730 ast_copy_string(ss7->ss7.internationalprefix, conf->ss7.ss7.internationalprefix, sizeof(ss7->ss7.internationalprefix));
12731 ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
12732 ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
12733 ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
12734 ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
12735
12736 ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
12737 ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
12738 }
12739#endif /* defined(HAVE_SS7) */
12740#ifdef HAVE_OPENR2
12741 if (chan_sig == SIG_MFCR2) {
12742 struct dahdi_mfcr2 *r2_link;
12743 struct r2link_entry *r2_le = dahdi_r2_get_link(conf);
12744 r2_link = &r2_le->mfcr2;
12745 if (!r2_link) {
12746 ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
12747 destroy_dahdi_pvt(tmp);
12748 return NULL;
12749 }
12750 if (!r2_link->protocol_context && dahdi_r2_set_context(r2_link, conf)) {
12751 ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
12752 destroy_dahdi_pvt(tmp);
12753 return NULL;
12754 }
12755 if (r2_link->numchans == ARRAY_LEN(r2_link->pvts)) {
12756 ast_log(LOG_ERROR, "Cannot add more channels to this link!\n");
12757 destroy_dahdi_pvt(tmp);
12758 return NULL;
12759 }
12760 r2_link->pvts[r2_link->numchans++] = tmp;
12761 tmp->r2chan = openr2_chan_new_from_fd(r2_link->protocol_context,
12762 tmp->subs[SUB_REAL].dfd,
12763 NULL, NULL);
12764 if (!tmp->r2chan) {
12765 openr2_liberr_t err = openr2_context_get_last_error(r2_link->protocol_context);
12766 ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
12767 destroy_dahdi_pvt(tmp);
12768 return NULL;
12769 }
12770 r2_link->live_chans++;
12771 tmp->mfcr2 = r2_link;
12772 if (conf->mfcr2.call_files) {
12773 openr2_chan_enable_call_files(tmp->r2chan);
12774 }
12775 openr2_chan_set_client_data(tmp->r2chan, tmp);
12776 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12777 openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
12778 openr2_chan_set_log_level(tmp->r2chan, conf->mfcr2.loglevel);
12779 tmp->mfcr2_category = conf->mfcr2.category;
12780 tmp->mfcr2_charge_calls = conf->mfcr2.charge_calls;
12781 tmp->mfcr2_allow_collect_calls = conf->mfcr2.allow_collect_calls;
12782 tmp->mfcr2_forced_release = conf->mfcr2.forced_release;
12783 tmp->mfcr2_accept_on_offer = conf->mfcr2.accept_on_offer;
12784 tmp->mfcr2call = 0;
12785 tmp->mfcr2_dnis_index = 0;
12786 tmp->mfcr2_ani_index = 0;
12787 }
12788#endif
12789#ifdef HAVE_PRI
12790 if (dahdi_sig_pri_lib_handles(chan_sig)) {
12791 int offset;
12792 int matchesdchan;
12793 int x,y;
12794 int myswitchtype = 0;
12795
12796 offset = 0;
12797 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
12798 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12799 destroy_dahdi_pvt(tmp);
12800 return NULL;
12801 }
12802 if (span >= NUM_SPANS) {
12803 ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
12804 destroy_dahdi_pvt(tmp);
12805 return NULL;
12806 } else {
12807 si.spanno = 0;
12808 if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
12809 ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
12810 destroy_dahdi_pvt(tmp);
12811 return NULL;
12812 }
12813 /* Store the logical span first based upon the real span */
12814 tmp->logicalspan = pris[span].prilogicalspan;
12815 pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
12816 if (span < 0) {
12817 ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
12818 destroy_dahdi_pvt(tmp);
12819 return NULL;
12820 }
12821 myswitchtype = conf->pri.pri.switchtype;
12822 /* Make sure this isn't a d-channel */
12823 matchesdchan=0;
12824 for (x = 0; x < NUM_SPANS; x++) {
12825 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12826 if (pris[x].dchannels[y] == tmp->channel) {
12827 matchesdchan = 1;
12828 break;
12829 }
12830 }
12831 }
12832 if (!matchesdchan) {
12833 if (pris[span].pri.nodetype && (pris[span].pri.nodetype != conf->pri.pri.nodetype)) {
12834 ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].pri.nodetype));
12835 destroy_dahdi_pvt(tmp);
12836 return NULL;
12837 }
12838 if (pris[span].pri.switchtype && (pris[span].pri.switchtype != myswitchtype)) {
12839 ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].pri.switchtype));
12840 destroy_dahdi_pvt(tmp);
12841 return NULL;
12842 }
12843 if ((pris[span].pri.dialplan) && (pris[span].pri.dialplan != conf->pri.pri.dialplan)) {
12844 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));
12845 destroy_dahdi_pvt(tmp);
12846 return NULL;
12847 }
12848 if (!ast_strlen_zero(pris[span].pri.idledial) && strcmp(pris[span].pri.idledial, conf->pri.pri.idledial)) {
12849 ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.pri.idledial);
12850 destroy_dahdi_pvt(tmp);
12851 return NULL;
12852 }
12853 if (!ast_strlen_zero(pris[span].pri.idleext) && strcmp(pris[span].pri.idleext, conf->pri.pri.idleext)) {
12854 ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.pri.idleext);
12855 destroy_dahdi_pvt(tmp);
12856 return NULL;
12857 }
12858 if (pris[span].pri.minunused && (pris[span].pri.minunused != conf->pri.pri.minunused)) {
12859 ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.pri.minunused);
12860 destroy_dahdi_pvt(tmp);
12861 return NULL;
12862 }
12863 if (pris[span].pri.minidle && (pris[span].pri.minidle != conf->pri.pri.minidle)) {
12864 ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.pri.minidle);
12865 destroy_dahdi_pvt(tmp);
12866 return NULL;
12867 }
12868 if (pris[span].pri.numchans >= ARRAY_LEN(pris[span].pri.pvts)) {
12869 ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
12870 pris[span].pri.trunkgroup);
12871 destroy_dahdi_pvt(tmp);
12872 return NULL;
12873 }
12874
12875 pri_chan = sig_pri_chan_new(tmp, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
12876 if (!pri_chan) {
12877 destroy_dahdi_pvt(tmp);
12878 return NULL;
12879 }
12880 tmp->sig_pvt = pri_chan;
12881 tmp->pri = &pris[span].pri;
12882
12883 tmp->priexclusive = conf->chan.priexclusive;
12884
12885 if (!tmp->pri->cc_params) {
12887 if (!tmp->pri->cc_params) {
12888 destroy_dahdi_pvt(tmp);
12889 return NULL;
12890 }
12891 }
12893 conf->chan.cc_params);
12894
12895 pris[span].pri.sig = chan_sig;
12896 pris[span].pri.nodetype = conf->pri.pri.nodetype;
12897 pris[span].pri.switchtype = myswitchtype;
12898 pris[span].pri.nsf = conf->pri.pri.nsf;
12899 pris[span].pri.dialplan = conf->pri.pri.dialplan;
12900 pris[span].pri.localdialplan = conf->pri.pri.localdialplan;
12901 pris[span].pri.cpndialplan = conf->pri.pri.cpndialplan;
12902 pris[span].pri.pvts[pris[span].pri.numchans++] = tmp->sig_pvt;
12903 pris[span].pri.minunused = conf->pri.pri.minunused;
12904 pris[span].pri.minidle = conf->pri.pri.minidle;
12905 pris[span].pri.overlapdial = conf->pri.pri.overlapdial;
12906 pris[span].pri.qsigchannelmapping = conf->pri.pri.qsigchannelmapping;
12907 pris[span].pri.discardremoteholdretrieval = conf->pri.pri.discardremoteholdretrieval;
12908#if defined(HAVE_PRI_SERVICE_MESSAGES)
12909 pris[span].pri.enable_service_message_support = conf->pri.pri.enable_service_message_support;
12910#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12911#ifdef HAVE_PRI_INBANDDISCONNECT
12912 pris[span].pri.inbanddisconnect = conf->pri.pri.inbanddisconnect;
12913#endif
12914#if defined(HAVE_PRI_CALL_HOLD)
12915 pris[span].pri.hold_disconnect_transfer =
12916 conf->pri.pri.hold_disconnect_transfer;
12917#endif /* defined(HAVE_PRI_CALL_HOLD) */
12918#if defined(HAVE_PRI_CCSS)
12919 pris[span].pri.cc_ptmp_recall_mode =
12920 conf->pri.pri.cc_ptmp_recall_mode;
12921 pris[span].pri.cc_qsig_signaling_link_req =
12922 conf->pri.pri.cc_qsig_signaling_link_req;
12923 pris[span].pri.cc_qsig_signaling_link_rsp =
12924 conf->pri.pri.cc_qsig_signaling_link_rsp;
12925#endif /* defined(HAVE_PRI_CCSS) */
12926#if defined(HAVE_PRI_CALL_WAITING)
12927 pris[span].pri.max_call_waiting_calls =
12928 conf->pri.pri.max_call_waiting_calls;
12929 pris[span].pri.allow_call_waiting_calls =
12930 conf->pri.pri.allow_call_waiting_calls;
12931#endif /* defined(HAVE_PRI_CALL_WAITING) */
12932 pris[span].pri.transfer = conf->chan.transfer;
12933 pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
12934#if defined(HAVE_PRI_L2_PERSISTENCE)
12935 pris[span].pri.l2_persistence = conf->pri.pri.l2_persistence;
12936#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12937 pris[span].pri.colp_send = conf->pri.pri.colp_send;
12938#if defined(HAVE_PRI_AOC_EVENTS)
12939 pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
12940 pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
12941#endif /* defined(HAVE_PRI_AOC_EVENTS) */
12942 if (chan_sig == SIG_BRI_PTMP) {
12943 pris[span].pri.layer1_ignored = conf->pri.pri.layer1_ignored;
12944 } else {
12945 /* Option does not apply to this line type. */
12946 pris[span].pri.layer1_ignored = 0;
12947 }
12948 pris[span].pri.append_msn_to_user_tag = conf->pri.pri.append_msn_to_user_tag;
12949 pris[span].pri.inband_on_setup_ack = conf->pri.pri.inband_on_setup_ack;
12950 pris[span].pri.inband_on_proceeding = conf->pri.pri.inband_on_proceeding;
12951 ast_copy_string(pris[span].pri.initial_user_tag, conf->chan.cid_tag, sizeof(pris[span].pri.initial_user_tag));
12952 ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
12953#if defined(HAVE_PRI_MWI)
12954 ast_copy_string(pris[span].pri.mwi_mailboxes,
12955 conf->pri.pri.mwi_mailboxes,
12956 sizeof(pris[span].pri.mwi_mailboxes));
12957 ast_copy_string(pris[span].pri.mwi_vm_boxes,
12958 conf->pri.pri.mwi_vm_boxes,
12959 sizeof(pris[span].pri.mwi_vm_boxes));
12960 ast_copy_string(pris[span].pri.mwi_vm_numbers,
12961 conf->pri.pri.mwi_vm_numbers,
12962 sizeof(pris[span].pri.mwi_vm_numbers));
12963#endif /* defined(HAVE_PRI_MWI) */
12964 ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
12965 ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
12966 ast_copy_string(pris[span].pri.internationalprefix, conf->pri.pri.internationalprefix, sizeof(pris[span].pri.internationalprefix));
12967 ast_copy_string(pris[span].pri.nationalprefix, conf->pri.pri.nationalprefix, sizeof(pris[span].pri.nationalprefix));
12968 ast_copy_string(pris[span].pri.localprefix, conf->pri.pri.localprefix, sizeof(pris[span].pri.localprefix));
12969 ast_copy_string(pris[span].pri.privateprefix, conf->pri.pri.privateprefix, sizeof(pris[span].pri.privateprefix));
12970 ast_copy_string(pris[span].pri.unknownprefix, conf->pri.pri.unknownprefix, sizeof(pris[span].pri.unknownprefix));
12971 pris[span].pri.moh_signaling = conf->pri.pri.moh_signaling;
12972 pris[span].pri.resetinterval = conf->pri.pri.resetinterval;
12973#if defined(HAVE_PRI_DISPLAY_TEXT)
12974 pris[span].pri.display_flags_send = conf->pri.pri.display_flags_send;
12975 pris[span].pri.display_flags_receive = conf->pri.pri.display_flags_receive;
12976#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
12977#if defined(HAVE_PRI_MCID)
12978 pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
12979#endif /* defined(HAVE_PRI_MCID) */
12980 pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
12981#if defined(HAVE_PRI_DATETIME_SEND)
12982 pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
12983#endif /* defined(HAVE_PRI_DATETIME_SEND) */
12984
12985 for (x = 0; x < PRI_MAX_TIMERS; x++) {
12986 pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
12987 }
12988
12989#if defined(HAVE_PRI_CALL_WAITING)
12990 /* Channel initial config parameters. */
12991 pris[span].pri.ch_cfg.stripmsd = conf->chan.stripmsd;
12992 pris[span].pri.ch_cfg.hidecallerid = conf->chan.hidecallerid;
12993 pris[span].pri.ch_cfg.hidecalleridname = conf->chan.hidecalleridname;
12994 pris[span].pri.ch_cfg.immediate = conf->chan.immediate;
12995 pris[span].pri.ch_cfg.priexclusive = conf->chan.priexclusive;
12996 pris[span].pri.ch_cfg.priindication_oob = conf->chan.priindication_oob;
12997 pris[span].pri.ch_cfg.use_callerid = conf->chan.use_callerid;
12998 pris[span].pri.ch_cfg.use_callingpres = conf->chan.use_callingpres;
12999 ast_copy_string(pris[span].pri.ch_cfg.context, conf->chan.context, sizeof(pris[span].pri.ch_cfg.context));
13000 ast_copy_string(pris[span].pri.ch_cfg.mohinterpret, conf->chan.mohinterpret, sizeof(pris[span].pri.ch_cfg.mohinterpret));
13001#endif /* defined(HAVE_PRI_CALL_WAITING) */
13002 } else {
13003 ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", p.chanpos);
13004 destroy_dahdi_pvt(tmp);
13005 return NULL;
13006 }
13007 }
13008 }
13009#endif
13010 } else {
13011 /* already exists in interface list */
13012 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));
13013 chan_sig = tmp->sig;
13014 if (tmp->subs[SUB_REAL].dfd > -1) {
13015 memset(&p, 0, sizeof(p));
13016 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13017 }
13018 }
13019 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
13020 switch (chan_sig) {
13021 case SIG_FXSKS:
13022 case SIG_FXSLS:
13023 case SIG_EM:
13024 case SIG_EM_E1:
13025 case SIG_EMWINK:
13026 case SIG_FEATD:
13027 case SIG_FEATDMF:
13028 case SIG_FEATDMF_TA:
13029 case SIG_FEATB:
13030 case SIG_E911:
13031 case SIG_SF:
13032 case SIG_SFWINK:
13033 case SIG_FGC_CAMA:
13034 case SIG_FGC_CAMAMF:
13035 case SIG_SF_FEATD:
13036 case SIG_SF_FEATDMF:
13037 case SIG_SF_FEATB:
13038 p.starttime = 250;
13039 break;
13040 }
13041
13042 if (tmp->radio) {
13043 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
13044 p.channo = channel;
13045 p.rxwinktime = 1;
13046 p.rxflashtime = 1;
13047 p.starttime = 1;
13048 p.debouncetime = 5;
13049 } else {
13050 p.channo = channel;
13051 /* Override timing settings based on config file */
13052 if (conf->timing.prewinktime >= 0)
13053 p.prewinktime = conf->timing.prewinktime;
13054 if (conf->timing.preflashtime >= 0)
13055 p.preflashtime = conf->timing.preflashtime;
13056 if (conf->timing.winktime >= 0)
13057 p.winktime = conf->timing.winktime;
13058 if (conf->timing.flashtime >= 0)
13059 p.flashtime = conf->timing.flashtime;
13060 if (conf->timing.starttime >= 0)
13061 p.starttime = conf->timing.starttime;
13062 if (conf->timing.rxwinktime >= 0)
13063 p.rxwinktime = conf->timing.rxwinktime;
13064 if (conf->timing.rxflashtime >= 0)
13065 p.rxflashtime = conf->timing.rxflashtime;
13066 if (conf->timing.debouncetime >= 0)
13067 p.debouncetime = conf->timing.debouncetime;
13068 }
13069
13070 /* don't set parms on a pseudo-channel */
13071 if (tmp->subs[SUB_REAL].dfd >= 0)
13072 {
13073 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
13074 if (res < 0) {
13075 ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
13076 destroy_dahdi_pvt(tmp);
13077 return NULL;
13078 }
13079 }
13080#if 1
13081 if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
13082 memset(&bi, 0, sizeof(bi));
13083 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13084 if (!res) {
13085 bi.txbufpolicy = conf->chan.buf_policy;
13086 bi.rxbufpolicy = conf->chan.buf_policy;
13087 bi.numbufs = conf->chan.buf_no;
13088 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13089 if (res < 0) {
13090 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
13091 }
13092 } else {
13093 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
13094 }
13095 tmp->buf_policy = conf->chan.buf_policy;
13096 tmp->buf_no = conf->chan.buf_no;
13097 tmp->usefaxbuffers = conf->chan.usefaxbuffers;
13098 tmp->faxbuf_policy = conf->chan.faxbuf_policy;
13099 tmp->faxbuf_no = conf->chan.faxbuf_no;
13100 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
13101 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
13102 * The reason the ioctl call above failed should to be determined before worrying about the
13103 * faxbuffer-related ioctl calls */
13104 tmp->bufsize = bi.bufsize;
13105 }
13106#endif
13107 tmp->immediate = conf->chan.immediate;
13108 tmp->immediatering = conf->chan.immediatering;
13109 tmp->transfertobusy = conf->chan.transfertobusy;
13110 tmp->dialmode = conf->chan.dialmode;
13111 if (chan_sig & __DAHDI_SIG_FXS) {
13112 tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
13113 tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
13114 tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
13115 }
13116 tmp->ringt_base = ringt_base;
13117 tmp->firstradio = 0;
13118 if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
13119 tmp->permcallwaiting = conf->chan.callwaiting;
13120 else
13121 tmp->permcallwaiting = 0;
13122 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
13123 tmp->destroy = 0;
13124 tmp->drings = conf->chan.drings;
13125
13126 /* 10 is a nice default. */
13127 if (tmp->drings.ringnum[0].range == 0)
13128 tmp->drings.ringnum[0].range = 10;
13129 if (tmp->drings.ringnum[1].range == 0)
13130 tmp->drings.ringnum[1].range = 10;
13131 if (tmp->drings.ringnum[2].range == 0)
13132 tmp->drings.ringnum[2].range = 10;
13133
13135 tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
13136 tmp->threewaycalling = conf->chan.threewaycalling;
13137 tmp->threewaysilenthold = conf->chan.threewaysilenthold;
13138 tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
13139 tmp->adsi = conf->chan.adsi;
13140 tmp->use_smdi = conf->chan.use_smdi;
13141 tmp->permhidecallerid = conf->chan.hidecallerid;
13142 tmp->hidecalleridname = conf->chan.hidecalleridname;
13143 tmp->callreturn = conf->chan.callreturn;
13144 tmp->lastnumredial = conf->chan.lastnumredial; /* Not used in DAHDI pvt, only analog pvt */
13145 tmp->echocancel = conf->chan.echocancel;
13146 tmp->echotraining = conf->chan.echotraining;
13147 tmp->pulse = conf->chan.pulse;
13148 if (tmp->echocancel.head.tap_length) {
13149 tmp->echocanbridged = conf->chan.echocanbridged;
13150 } else {
13151 if (conf->chan.echocanbridged)
13152 ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
13153 tmp->echocanbridged = 0;
13154 }
13155 tmp->busydetect = conf->chan.busydetect;
13156 tmp->busycount = conf->chan.busycount;
13157 tmp->busy_cadence = conf->chan.busy_cadence;
13158 tmp->callprogress = conf->chan.callprogress;
13159 tmp->waitfordialtone = conf->chan.waitfordialtone;
13160 tmp->dialtone_detect = conf->chan.dialtone_detect;
13161 tmp->faxdetect_timeout = conf->chan.faxdetect_timeout;
13162 tmp->firstdigit_timeout = conf->chan.firstdigit_timeout;
13163 tmp->interdigit_timeout = conf->chan.interdigit_timeout;
13164 tmp->matchdigit_timeout = conf->chan.matchdigit_timeout;
13165 tmp->cancallforward = conf->chan.cancallforward;
13166 tmp->dtmfrelax = conf->chan.dtmfrelax;
13167 tmp->callwaiting = tmp->permcallwaiting;
13168 tmp->hidecallerid = tmp->permhidecallerid;
13169 tmp->channel = channel;
13170 tmp->stripmsd = conf->chan.stripmsd;
13171 tmp->use_callerid = conf->chan.use_callerid;
13172 tmp->cid_signalling = conf->chan.cid_signalling;
13173 tmp->cid_start = conf->chan.cid_start;
13174 tmp->dahditrcallerid = conf->chan.dahditrcallerid;
13175 tmp->restrictcid = conf->chan.restrictcid;
13176 tmp->use_callingpres = conf->chan.use_callingpres;
13177 if (tmp->usedistinctiveringdetection) {
13178 if (!tmp->use_callerid) {
13179 ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
13180 tmp->use_callerid = 1;
13181 }
13182 }
13183
13184 if (tmp->cid_signalling == CID_SIG_SMDI) {
13185 if (!tmp->use_smdi) {
13186 ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13187 tmp->use_smdi = 1;
13188 }
13189 }
13190 if (tmp->use_smdi) {
13191 tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
13192 if (!(tmp->smdi_iface)) {
13193 ast_log(LOG_ERROR, "Invalid SMDI port specified, disabling SMDI support\n");
13194 tmp->use_smdi = 0;
13195 }
13196 }
13197
13198 ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
13199 tmp->amaflags = conf->chan.amaflags;
13200 if (!here) {
13201 tmp->confno = -1;
13202 tmp->propconfno = -1;
13203 }
13204 tmp->canpark = conf->chan.canpark;
13205 tmp->transfer = conf->chan.transfer;
13206 ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
13207 ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
13208 ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
13209 ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
13210 ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
13211 ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
13212 ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
13213 tmp->cid_ton = 0;
13214 if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
13215 ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
13216 ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
13217 } else {
13218 tmp->cid_num[0] = '\0';
13219 tmp->cid_name[0] = '\0';
13220 }
13221#if defined(HAVE_PRI)
13222 if (dahdi_sig_pri_lib_handles(tmp->sig)) {
13223 tmp->cid_tag[0] = '\0';
13224 } else
13225#endif /* defined(HAVE_PRI) */
13226 {
13227 ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
13228 }
13229 tmp->cid_subaddr[0] = '\0';
13230 ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
13231 if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
13232 /* This module does not handle MWI in an event-based manner. However, it
13233 * subscribes to MWI for each mailbox that is configured so that the core
13234 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13235 * event cache instead of checking the mailbox directly. */
13237 }
13238#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13239 tmp->mwisend_setting = conf->chan.mwisend_setting;
13240 tmp->mwisend_fsk = conf->chan.mwisend_fsk;
13241 tmp->mwisend_rpas = conf->chan.mwisend_rpas;
13242#endif
13243
13244 tmp->group = conf->chan.group;
13245 tmp->callgroup = conf->chan.callgroup;
13246 tmp->pickupgroup= conf->chan.pickupgroup;
13248 tmp->named_callgroups = ast_ref_namedgroups(conf->chan.named_callgroups);
13250 tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
13251 if (conf->chan.vars) {
13252 struct ast_variable *v, *tmpvar;
13253 for (v = conf->chan.vars ; v ; v = v->next) {
13254 if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
13255 if (ast_variable_list_replace(&tmp->vars, tmpvar)) {
13256 tmpvar->next = tmp->vars;
13257 tmp->vars = tmpvar;
13258 }
13259 }
13260 }
13261 }
13262 tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
13263 tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
13264 tmp->hwrxgain = conf->chan.hwrxgain;
13265 tmp->hwtxgain = conf->chan.hwtxgain;
13266 tmp->cid_rxgain = conf->chan.cid_rxgain;
13267 tmp->rxgain = conf->chan.rxgain;
13268 tmp->txgain = conf->chan.txgain;
13269 tmp->txdrc = conf->chan.txdrc;
13270 tmp->rxdrc = conf->chan.rxdrc;
13271 tmp->tonezone = conf->chan.tonezone;
13272 if (tmp->subs[SUB_REAL].dfd > -1) {
13273 if (tmp->hwrxgain_enabled) {
13274 tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
13275 }
13276 if (tmp->hwtxgain_enabled) {
13277 tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
13278 }
13279 set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
13280 if (tmp->dsp)
13282 dahdi_conf_update(tmp);
13283 if (!here) {
13284 switch (chan_sig) {
13286 case SIG_SS7:
13287 case SIG_MFCR2:
13288 break;
13289 default:
13290 /* Hang it up to be sure it's good */
13291 dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
13292 break;
13293 }
13294 }
13295 ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
13296 if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
13297 /* the dchannel is down so put the channel in alarm */
13298 switch (tmp->sig) {
13299#ifdef HAVE_PRI
13301 sig_pri_set_alarm(tmp->sig_pvt, 1);
13302 break;
13303#endif
13304#if defined(HAVE_SS7)
13305 case SIG_SS7:
13306 sig_ss7_set_alarm(tmp->sig_pvt, 1);
13307 break;
13308#endif /* defined(HAVE_SS7) */
13309 default:
13310 /* The only sig submodule left should be sig_analog. */
13311 analog_p = tmp->sig_pvt;
13312 if (analog_p) {
13313 analog_p->inalarm = 1;
13314 }
13315 tmp->inalarm = 1;
13316 break;
13317 }
13318 handle_alarms(tmp, res);
13319 }
13320 }
13321
13322 tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13323 tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13324 tmp->ani_info_digits = conf->chan.ani_info_digits;
13325 tmp->ani_wink_time = conf->chan.ani_wink_time;
13326 tmp->ani_timeout = conf->chan.ani_timeout;
13327 tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13328 tmp->reoriginate = conf->chan.reoriginate;
13329 tmp->sendcalleridafter = conf->chan.sendcalleridafter;
13330 ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
13331
13332 if (!here) {
13333 tmp->locallyblocked = 0;
13334 tmp->remotelyblocked = 0;
13335 switch (tmp->sig) {
13336#if defined(HAVE_PRI)
13338 tmp->inservice = 1;/* Inservice until actually implemented. */
13339#if defined(HAVE_PRI_SERVICE_MESSAGES)
13340 ((struct sig_pri_chan *) tmp->sig_pvt)->service_status = 0;
13341 if (chan_sig == SIG_PRI) {
13342 char db_chan_name[20];
13343 char db_answer[5];
13344
13345 /*
13346 * Initialize the active out-of-service status
13347 * and delete any record if the feature is not enabled.
13348 */
13349 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, tmp->channel);
13350 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
13351 unsigned *why;
13352
13353 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
13354 if (tmp->pri->enable_service_message_support) {
13355 char state;
13356
13357 sscanf(db_answer, "%1c:%30u", &state, why);
13358
13359 /* Ensure that only the implemented bits could be set.*/
13360 *why &= (SRVST_NEAREND | SRVST_FAREND);
13361 }
13362 if (!*why) {
13363 ast_db_del(db_chan_name, SRVST_DBKEY);
13364 }
13365 }
13366 }
13367#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13368 break;
13369#endif /* defined(HAVE_PRI) */
13370#if defined(HAVE_SS7)
13371 case SIG_SS7:
13372 tmp->inservice = 0;
13373 if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
13375 }
13376 break;
13377#endif /* defined(HAVE_SS7) */
13378 default:
13379 /* We default to in service on protocols that don't have a reset */
13380 tmp->inservice = 1;
13381 break;
13382 }
13383 }
13384
13385 switch (tmp->sig) {
13386#if defined(HAVE_PRI)
13388 if (pri_chan) {
13389 pri_chan->channel = tmp->channel;
13390 pri_chan->hidecallerid = tmp->hidecallerid;
13391 pri_chan->hidecalleridname = tmp->hidecalleridname;
13392 pri_chan->immediate = tmp->immediate;
13393 pri_chan->inalarm = tmp->inalarm;
13394 pri_chan->priexclusive = tmp->priexclusive;
13395 pri_chan->priindication_oob = tmp->priindication_oob;
13396 pri_chan->use_callerid = tmp->use_callerid;
13397 pri_chan->use_callingpres = tmp->use_callingpres;
13398 ast_copy_string(pri_chan->context, tmp->context,
13399 sizeof(pri_chan->context));
13401 sizeof(pri_chan->mohinterpret));
13402 pri_chan->stripmsd = tmp->stripmsd;
13403 }
13404 break;
13405#endif /* defined(HAVE_PRI) */
13406#if defined(HAVE_SS7)
13407 case SIG_SS7:
13408 if (ss7_chan) {
13409 ss7_chan->inalarm = tmp->inalarm;
13410 ss7_chan->inservice = tmp->inservice;
13411
13412 ss7_chan->stripmsd = tmp->stripmsd;
13413 ss7_chan->hidecallerid = tmp->hidecallerid;
13414 ss7_chan->use_callerid = tmp->use_callerid;
13415 ss7_chan->use_callingpres = tmp->use_callingpres;
13416 ss7_chan->immediate = tmp->immediate;
13417 ss7_chan->locallyblocked = tmp->locallyblocked;
13418 ss7_chan->remotelyblocked = tmp->remotelyblocked;
13419 ast_copy_string(ss7_chan->context, tmp->context,
13420 sizeof(ss7_chan->context));
13422 sizeof(ss7_chan->mohinterpret));
13423 }
13424 break;
13425#endif /* defined(HAVE_SS7) */
13426 default:
13427 /* The only sig submodule left should be sig_analog. */
13428 analog_p = tmp->sig_pvt;
13429 if (analog_p) {
13430 analog_p->channel = tmp->channel;
13431 analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13432 analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13433 analog_p->ani_info_digits = conf->chan.ani_info_digits;
13434 analog_p->ani_timeout = conf->chan.ani_timeout;
13435 analog_p->ani_wink_time = conf->chan.ani_wink_time;
13436 analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13437 analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
13438 analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
13439 analog_p->callreturn = conf->chan.callreturn;
13440 analog_p->lastnumredial = conf->chan.lastnumredial; /* Only actually used in analog pvt, not DAHDI pvt */
13441 analog_p->cancallforward = conf->chan.cancallforward;
13442 analog_p->canpark = conf->chan.canpark;
13443 analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
13444 analog_p->immediate = conf->chan.immediate;
13445 analog_p->immediatering = conf->chan.immediatering;
13446 analog_p->permhidecallerid = conf->chan.hidecallerid; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13447 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13448 analog_p->pulse = conf->chan.pulse;
13449 analog_p->threewaycalling = conf->chan.threewaycalling;
13450 analog_p->transfer = conf->chan.transfer;
13451 analog_p->transfertobusy = conf->chan.transfertobusy;
13452 analog_p->dialmode = conf->chan.dialmode;
13453 analog_p->use_callerid = tmp->use_callerid;
13455 analog_p->use_smdi = tmp->use_smdi;
13456 analog_p->smdi_iface = tmp->smdi_iface;
13457 analog_p->outsigmod = ANALOG_SIG_NONE;
13458 analog_p->echotraining = conf->chan.echotraining;
13459 analog_p->cid_signalling = conf->chan.cid_signalling;
13460 analog_p->stripmsd = conf->chan.stripmsd;
13461 switch (conf->chan.cid_start) {
13462 case CID_START_POLARITY:
13464 break;
13467 break;
13470 break;
13471 default:
13472 analog_p->cid_start = ANALOG_CID_START_RING;
13473 break;
13474 }
13475 analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;
13476 analog_p->ringt = conf->chan.ringt;
13477 analog_p->ringt_base = ringt_base;
13478 analog_p->onhooktime = time(NULL);
13479 if (chan_sig & __DAHDI_SIG_FXO) {
13480 memset(&p, 0, sizeof(p));
13481 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13482 if (!res) {
13483 analog_p->fxsoffhookstate = p.rxisoffhook;
13484 }
13485#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13486 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
13487#endif
13488 }
13489 analog_p->msgstate = -1;
13490
13491 ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
13492 ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
13493 ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
13494
13495 analog_config_complete(analog_p);
13496 }
13497 break;
13498 }
13499#if defined(HAVE_PRI)
13500 if (tmp->channel == CHAN_PSEUDO) {
13501 /*
13502 * Save off pseudo channel buffer policy values for dynamic creation of
13503 * no B channel interfaces.
13504 */
13505 dahdi_pseudo_parms.buf_no = tmp->buf_no;
13506 dahdi_pseudo_parms.buf_policy = tmp->buf_policy;
13507 dahdi_pseudo_parms.faxbuf_no = tmp->faxbuf_no;
13508 dahdi_pseudo_parms.faxbuf_policy = tmp->faxbuf_policy;
13509 }
13510#endif /* defined(HAVE_PRI) */
13511 }
13512 if (tmp && !here) {
13513 /* Add the new channel interface to the sorted channel interface list. */
13515 }
13516 return tmp;
13517}
13518
13519static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
13520{
13521#if defined(HAVE_PRI)
13522 if (0 < span) {
13523 /* The channel must be on the specified PRI span. */
13524 if (!p->pri || p->pri->span != span) {
13525 return 0;
13526 }
13527 if (!groupmatch && channelmatch == -1) {
13528 /* Match any group since it only needs to be on the PRI span. */
13529 *groupmatched = 1;
13530 return 1;
13531 }
13532 }
13533#endif /* defined(HAVE_PRI) */
13534 /* check group matching */
13535 if (groupmatch) {
13536 if ((p->group & groupmatch) != groupmatch)
13537 /* Doesn't match the specified group, try the next one */
13538 return 0;
13539 *groupmatched = 1;
13540 }
13541 /* Check to see if we have a channel match */
13542 if (channelmatch != -1) {
13543 if (p->channel != channelmatch)
13544 /* Doesn't match the specified channel, try the next one */
13545 return 0;
13546 *channelmatched = 1;
13547 }
13548
13549 return 1;
13550}
13551
13552static int available(struct dahdi_pvt **pvt, int is_specific_channel)
13553{
13554 struct dahdi_pvt *p = *pvt;
13555
13556 if (p->inalarm)
13557 return 0;
13558
13559 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
13560 return analog_available(p->sig_pvt);
13561
13562 switch (p->sig) {
13563#if defined(HAVE_PRI)
13565 {
13566 struct sig_pri_chan *pvt_chan;
13567 int res;
13568
13569 pvt_chan = p->sig_pvt;
13570 res = sig_pri_available(&pvt_chan, is_specific_channel);
13571 *pvt = pvt_chan->chan_pvt;
13572 return res;
13573 }
13574#endif /* defined(HAVE_PRI) */
13575#if defined(HAVE_SS7)
13576 case SIG_SS7:
13577 return sig_ss7_available(p->sig_pvt);
13578#endif /* defined(HAVE_SS7) */
13579 default:
13580 break;
13581 }
13582
13583 if (p->locallyblocked || p->remotelyblocked) {
13584 return 0;
13585 }
13586
13587 /* If no owner definitely available */
13588 if (!p->owner) {
13589#ifdef HAVE_OPENR2
13590 /* Trust MFC/R2 */
13591 if (p->mfcr2) {
13592 if (p->mfcr2call) {
13593 return 0;
13594 } else {
13595 return 1;
13596 }
13597 }
13598#endif
13599 return 1;
13600 }
13601
13602 return 0;
13603}
13604
13605#if defined(HAVE_PRI)
13606#if defined(HAVE_PRI_CALL_WAITING)
13607/*!
13608 * \internal
13609 * \brief Init the private channel configuration using the span controller.
13610 * \since 1.8
13611 *
13612 * \param priv Channel to init the configuration.
13613 * \param pri sig_pri PRI control structure.
13614 *
13615 * \note Assumes the pri->lock is already obtained.
13616 */
13617static void my_pri_init_config(void *priv, struct sig_pri_span *pri)
13618{
13619 struct dahdi_pvt *pvt = priv;
13620
13621 pvt->stripmsd = pri->ch_cfg.stripmsd;
13622 pvt->hidecallerid = pri->ch_cfg.hidecallerid;
13623 pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
13624 pvt->immediate = pri->ch_cfg.immediate;
13625 pvt->priexclusive = pri->ch_cfg.priexclusive;
13626 pvt->priindication_oob = pri->ch_cfg.priindication_oob;
13627 pvt->use_callerid = pri->ch_cfg.use_callerid;
13628 pvt->use_callingpres = pri->ch_cfg.use_callingpres;
13629 ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
13630 ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
13631}
13632#endif /* defined(HAVE_PRI_CALL_WAITING) */
13633#endif /* defined(HAVE_PRI) */
13634
13635#if defined(HAVE_PRI)
13636/*!
13637 * \internal
13638 * \brief Create a no B channel interface.
13639 * \since 1.8
13640 *
13641 * \param pri sig_pri span controller to add interface.
13642 *
13643 * \note Assumes the pri->lock is already obtained.
13644 *
13645 * \retval array-index into private pointer array on success.
13646 * \retval -1 on error.
13647 */
13648static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri)
13649{
13650 int pvt_idx;
13651 int res;
13652 unsigned idx;
13653 struct dahdi_pvt *pvt;
13654 struct sig_pri_chan *chan;
13655 struct dahdi_bufferinfo bi;
13656
13657 static int nobch_channel = CHAN_PSEUDO;
13658
13659 /* Find spot in the private pointer array for new interface. */
13660 for (pvt_idx = 0; pvt_idx < pri->numchans; ++pvt_idx) {
13661 if (!pri->pvts[pvt_idx]) {
13662 break;
13663 }
13664 }
13665 if (pri->numchans == pvt_idx) {
13666 if (ARRAY_LEN(pri->pvts) <= pvt_idx) {
13667 ast_log(LOG_ERROR, "Unable to add a no-B-channel interface!\n");
13668 return -1;
13669 }
13670
13671 /* Add new spot to the private pointer array. */
13672 pri->pvts[pvt_idx] = NULL;
13673 ++pri->numchans;
13674 }
13675
13676 pvt = ast_calloc(1, sizeof(*pvt));
13677 if (!pvt) {
13678 return -1;
13679 }
13681 if (!pvt->cc_params) {
13682 ast_free(pvt);
13683 return -1;
13684 }
13685 ast_mutex_init(&pvt->lock);
13686 for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
13687 pvt->subs[idx].dfd = -1;
13688 }
13689 pvt->buf_no = dahdi_pseudo_parms.buf_no;
13690 pvt->buf_policy = dahdi_pseudo_parms.buf_policy;
13691 pvt->faxbuf_no = dahdi_pseudo_parms.faxbuf_no;
13692 pvt->faxbuf_policy = dahdi_pseudo_parms.faxbuf_policy;
13693
13694 chan = sig_pri_chan_new(pvt, pri, 0, 0, 0);
13695 if (!chan) {
13696 destroy_dahdi_pvt(pvt);
13697 return -1;
13698 }
13699 chan->no_b_channel = 1;
13700
13701 /*
13702 * Pseudo channel companding law.
13703 * Needed for outgoing call waiting calls.
13704 * XXX May need to make this determined by switchtype or user option.
13705 */
13706 pvt->law_default = DAHDI_LAW_ALAW;
13707
13708 pvt->sig = pri->sig;
13709 pvt->outsigmod = -1;
13710 pvt->pri = pri;
13711 pvt->sig_pvt = chan;
13712 pri->pvts[pvt_idx] = chan;
13713
13714 pvt->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13715 if (pvt->subs[SUB_REAL].dfd < 0) {
13716 ast_log(LOG_ERROR, "Unable to open no B channel interface pseudo channel: %s\n",
13717 strerror(errno));
13718 destroy_dahdi_pvt(pvt);
13719 return -1;
13720 }
13721 memset(&bi, 0, sizeof(bi));
13722 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13723 if (!res) {
13724 pvt->bufsize = bi.bufsize;
13725 bi.txbufpolicy = pvt->buf_policy;
13726 bi.rxbufpolicy = pvt->buf_policy;
13727 bi.numbufs = pvt->buf_no;
13728 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13729 if (res < 0) {
13731 "Unable to set buffer policy on no B channel interface: %s\n",
13732 strerror(errno));
13733 }
13734 } else
13736 "Unable to check buffer policy on no B channel interface: %s\n",
13737 strerror(errno));
13738
13739 --nobch_channel;
13740 if (CHAN_PSEUDO < nobch_channel) {
13741 nobch_channel = CHAN_PSEUDO - 1;
13742 }
13743 pvt->channel = nobch_channel;
13744 pvt->span = pri->span;
13745 chan->channel = pvt->channel;
13746
13747 dahdi_nobch_insert(pri, pvt);
13748
13749 return pvt_idx;
13750}
13751#endif /* defined(HAVE_PRI) */
13752
13753/* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13754 structures; it makes no attempt to safely copy regular channel private
13755 structures that might contain reference-counted object pointers and other
13756 scary bits
13757*/
13758static struct dahdi_pvt *duplicate_pseudo(struct dahdi_pvt *src)
13759{
13760 struct dahdi_pvt *p;
13761 struct dahdi_bufferinfo bi;
13762 int res;
13763
13764 p = ast_malloc(sizeof(*p));
13765 if (!p) {
13766 return NULL;
13767 }
13768 *p = *src;
13769
13770 /* Must deep copy the cc_params. */
13772 if (!p->cc_params) {
13773 ast_free(p);
13774 return NULL;
13775 }
13777
13779 p->next = NULL;
13780 p->prev = NULL;
13781 ast_mutex_init(&p->lock);
13782 p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13783 if (p->subs[SUB_REAL].dfd < 0) {
13784 ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
13786 return NULL;
13787 }
13788 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13789 if (!res) {
13790 bi.txbufpolicy = src->buf_policy;
13791 bi.rxbufpolicy = src->buf_policy;
13792 bi.numbufs = src->buf_no;
13793 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13794 if (res < 0) {
13795 ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
13796 }
13797 } else
13798 ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
13799 p->destroy = 1;
13801 return p;
13802}
13803
13805 /*! Group matching mask. Zero if not specified. */
13807 /*! DAHDI channel to match with. -1 if not specified. */
13809 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13811 /*! ISDN span where channels can be picked (Zero if not specified) */
13812 int span;
13813 /*! Analog channel distinctive ring cadence index. */
13815 /*! Dialing option. c/r/d if present and valid. */
13816 char opt;
13817 /*! TRUE if to search the channel list backwards. */
13819 /*! TRUE if search is done with round robin sequence. */
13821};
13822static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi_starting_point *param)
13823{
13824 char *dest;
13825 char *s;
13826 int x;
13827 int res = 0;
13828 struct dahdi_pvt *p;
13829 char *subdir = NULL;
13831 AST_APP_ARG(group); /* channel/group token */
13832 //AST_APP_ARG(ext); /* extension token */
13833 //AST_APP_ARG(opts); /* options token */
13834 AST_APP_ARG(other); /* Any remaining unused arguments */
13835 );
13836
13837 /*
13838 * data is ---v
13839 * Dial(DAHDI/pseudo[/extension[/options]])
13840 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13841 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13842 * Dial(DAHDI/i<span>[/extension[/options]])
13843 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13844 *
13845 * i - ISDN span channel restriction.
13846 * Used by CC to ensure that the CC recall goes out the same span.
13847 * Also to make ISDN channel names dialable when the sequence number
13848 * is stripped off. (Used by DTMF attended transfer feature.)
13849 *
13850 * g - channel group allocation search forward
13851 * G - channel group allocation search backward
13852 * r - channel group allocation round robin search forward
13853 * R - channel group allocation round robin search backward
13854 *
13855 * c - Wait for DTMF digit to confirm answer
13856 * r<cadence#> - Set distinctive ring cadence number
13857 * d - Force bearer capability for ISDN/SS7 call to digital.
13858 */
13859
13860 if (data) {
13861 dest = ast_strdupa(data);
13862 } else {
13863 ast_log(LOG_WARNING, "Channel requested with no data\n");
13864 return NULL;
13865 }
13866 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
13867 if (!args.argc || ast_strlen_zero(args.group)) {
13868 ast_log(LOG_WARNING, "No channel/group specified\n");
13869 return NULL;
13870 }
13871
13872 /* Initialize the output parameters */
13873 memset(param, 0, sizeof(*param));
13874 param->channelmatch = -1;
13875
13876 if (strchr(args.group, '!') != NULL) {
13877 char *prev = args.group;
13878 while ((s = strchr(prev, '!')) != NULL) {
13879 *s++ = '/';
13880 prev = s;
13881 }
13882 *(prev - 1) = '\0';
13883 subdir = args.group;
13884 args.group = prev;
13885 } else if (args.group[0] == 'i') {
13886 /* Extract the ISDN span channel restriction specifier. */
13887 res = sscanf(args.group + 1, "%30d", &x);
13888 if (res < 1) {
13889 ast_log(LOG_WARNING, "Unable to determine ISDN span for data %s\n", data);
13890 return NULL;
13891 }
13892 param->span = x;
13893
13894 /* Remove the ISDN span channel restriction specifier. */
13895 s = strchr(args.group, '-');
13896 if (!s) {
13897 /* Search all groups since we are ISDN span restricted. */
13898 return iflist;
13899 }
13900 args.group = s + 1;
13901 res = 0;
13902 }
13903 if (toupper(args.group[0]) == 'G' || toupper(args.group[0])=='R') {
13904 /* Retrieve the group number */
13905 s = args.group + 1;
13906 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13907 if (res < 1) {
13908 ast_log(LOG_WARNING, "Unable to determine group for data %s\n", data);
13909 return NULL;
13910 }
13911 param->groupmatch = ((ast_group_t) 1 << x);
13912
13913 if (toupper(args.group[0]) == 'G') {
13914 if (args.group[0] == 'G') {
13915 param->backwards = 1;
13916 p = ifend;
13917 } else
13918 p = iflist;
13919 } else {
13920 if (ARRAY_LEN(round_robin) <= x) {
13921 ast_log(LOG_WARNING, "Round robin index %d out of range for data %s\n",
13922 x, data);
13923 return NULL;
13924 }
13925 if (args.group[0] == 'R') {
13926 param->backwards = 1;
13927 p = round_robin[x] ? round_robin[x]->prev : ifend;
13928 if (!p)
13929 p = ifend;
13930 } else {
13931 p = round_robin[x] ? round_robin[x]->next : iflist;
13932 if (!p)
13933 p = iflist;
13934 }
13935 param->roundrobin = 1;
13936 param->rr_starting_point = x;
13937 }
13938 } else {
13939 s = args.group;
13940 if (!strcasecmp(s, "pseudo")) {
13941 /* Special case for pseudo */
13942 x = CHAN_PSEUDO;
13943 param->channelmatch = x;
13944 } else {
13945 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13946 if (res < 1) {
13947 ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", data);
13948 return NULL;
13949 } else {
13950 param->channelmatch = x;
13951 }
13952 }
13953 if (subdir) {
13954 char path[PATH_MAX];
13955 struct stat stbuf;
13956
13957 snprintf(path, sizeof(path), "/dev/dahdi/%s/%d",
13958 subdir, param->channelmatch);
13959 if (stat(path, &stbuf) < 0) {
13960 ast_log(LOG_WARNING, "stat(%s) failed: %s\n",
13961 path, strerror(errno));
13962 return NULL;
13963 }
13964 if (!S_ISCHR(stbuf.st_mode)) {
13965 ast_log(LOG_ERROR, "%s: Not a character device file\n",
13966 path);
13967 return NULL;
13968 }
13969 param->channelmatch = minor(stbuf.st_rdev);
13970 }
13971
13972 p = iflist;
13973 }
13974
13975 if (param->opt == 'r' && res < 3) {
13976 ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", data);
13977 param->opt = '\0';
13978 }
13979
13980 return p;
13981}
13982
13983static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
13984 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
13985 const char *data, int *cause)
13986{
13987 int callwait = 0;
13988 struct dahdi_pvt *p;
13989 struct ast_channel *tmp = NULL;
13990 struct dahdi_pvt *exitpvt;
13991 int channelmatched = 0;
13992 int foundowner = 0;
13993 int groupmatched = 0;
13994#if defined(HAVE_PRI) || defined(HAVE_SS7)
13995 int transcapdigital = 0;
13996#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
13997 struct dahdi_starting_point start;
13998 ast_callid callid = 0;
13999 int callid_created = ast_callid_threadstorage_auto(&callid);
14000
14002 p = determine_starting_point(data, &start);
14003 if (!p) {
14004 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
14006 ast_callid_threadstorage_auto_clean(callid, callid_created);
14007 return NULL;
14008 }
14009
14010 /* Search for an unowned channel */
14011 exitpvt = p;
14012 while (p && !tmp) {
14013 if (start.roundrobin)
14014 round_robin[start.rr_starting_point] = p;
14015
14016 if (p->owner) {
14017 foundowner++;
14018 }
14019
14020 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
14021 && available(&p, channelmatched)) {
14022 ast_debug(1, "Using channel %d\n", p->channel);
14023
14024 callwait = (p->owner != NULL);
14025#ifdef HAVE_OPENR2
14026 if (p->mfcr2) {
14027 ast_mutex_lock(&p->lock);
14028 if (p->mfcr2call) {
14030 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
14031 goto next;
14032 }
14033 p->mfcr2call = 1;
14035 }
14036#endif
14037 if (p->channel == CHAN_PSEUDO) {
14038 p = duplicate_pseudo(p);
14039 if (!p) {
14040 break;
14041 }
14042 }
14043
14044 p->distinctivering = 0;
14045 /* Make special notes */
14046 switch (start.opt) {
14047 case '\0':
14048 /* No option present. */
14049 break;
14050 case 'c':
14051 /* Confirm answer */
14052 p->confirmanswer = 1;
14053 break;
14054 case 'r':
14055 /* Distinctive ring */
14056 p->distinctivering = start.cadence;
14057 break;
14058 case 'd':
14059#if defined(HAVE_PRI) || defined(HAVE_SS7)
14060 /* If this is an ISDN call, make it digital */
14061 transcapdigital = AST_TRANS_CAP_DIGITAL;
14062#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14063 break;
14064 default:
14065 ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", start.opt, data);
14066 break;
14067 }
14068
14069 p->outgoing = 1;
14070 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
14071 tmp = analog_request(p->sig_pvt, &callwait, requestor);
14072#ifdef HAVE_PRI
14073 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
14074 /*
14075 * We already have the B channel reserved for this call. We
14076 * just need to make sure that dahdi_hangup() has completed
14077 * cleaning up before continuing.
14078 */
14079 ast_mutex_lock(&p->lock);
14081
14083 sizeof(p->dnid));
14084 tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, assignedids, requestor, transcapdigital);
14085#endif
14086#if defined(HAVE_SS7)
14087 } else if (p->sig == SIG_SS7) {
14088 tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, assignedids, requestor, transcapdigital);
14089#endif /* defined(HAVE_SS7) */
14090 } else {
14091 tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, assignedids, requestor, callid);
14092 }
14093 if (!tmp) {
14094 p->outgoing = 0;
14095#if defined(HAVE_PRI)
14096 switch (p->sig) {
14098#if defined(HAVE_PRI_CALL_WAITING)
14099 if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
14100 ((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
14101 ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
14102 }
14103#endif /* defined(HAVE_PRI_CALL_WAITING) */
14104 /*
14105 * This should be the last thing to clear when we are done with
14106 * the channel.
14107 */
14108 ((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
14109 break;
14110 default:
14111 break;
14112 }
14113#endif /* defined(HAVE_PRI) */
14114 } else {
14115 snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", data);
14116 }
14117 break;
14118 }
14119#ifdef HAVE_OPENR2
14120next:
14121#endif
14122 if (start.backwards) {
14123 p = p->prev;
14124 if (!p)
14125 p = ifend;
14126 } else {
14127 p = p->next;
14128 if (!p)
14129 p = iflist;
14130 }
14131 /* stop when you roll to the one that we started from */
14132 if (p == exitpvt)
14133 break;
14134 }
14137 if (cause && !tmp) {
14138 if (callwait || (channelmatched && foundowner)) {
14139 *cause = AST_CAUSE_BUSY;
14140 } else if (groupmatched) {
14141 *cause = AST_CAUSE_CONGESTION;
14142 } else {
14143 /*
14144 * We did not match any channel requested.
14145 * Dialplan error requesting non-existant channel?
14146 */
14147 }
14148 }
14149
14150 ast_callid_threadstorage_auto_clean(callid, callid_created);
14151 return tmp;
14152}
14153
14154/*!
14155 * \internal
14156 * \brief Determine the device state for a given DAHDI device if we can.
14157 * \since 1.8
14158 *
14159 * \param data DAHDI device name after "DAHDI/".
14160 *
14161 * \retval device_state enum ast_device_state value.
14162 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
14163 */
14164static int dahdi_devicestate(const char *data)
14165{
14166#if defined(HAVE_PRI)
14167 const char *device;
14168 unsigned span;
14169 int res;
14170
14171 device = data;
14172
14173 if (*device != 'I') {
14174 /* The request is not for an ISDN span device. */
14175 return AST_DEVICE_UNKNOWN;
14176 }
14177 res = sscanf(device, "I%30u", &span);
14178 if (res != 1 || !span || NUM_SPANS < span) {
14179 /* Bad format for ISDN span device name. */
14180 return AST_DEVICE_UNKNOWN;
14181 }
14182 device = strchr(device, '/');
14183 if (!device) {
14184 /* Bad format for ISDN span device name. */
14185 return AST_DEVICE_UNKNOWN;
14186 }
14187
14188 /*
14189 * Since there are currently no other span devstate's defined,
14190 * it must be congestion.
14191 */
14192#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14193 ++device;
14194 if (!strcmp(device, "congestion"))
14195#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14196 {
14197 return pris[span - 1].pri.congestion_devstate;
14198 }
14199#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14200 else if (!strcmp(device, "threshold")) {
14201 return pris[span - 1].pri.threshold_devstate;
14202 }
14203 return AST_DEVICE_UNKNOWN;
14204#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14205#else
14206 return AST_DEVICE_UNKNOWN;
14207#endif /* defined(HAVE_PRI) */
14208}
14209
14210/*!
14211 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14212 * \since 1.8
14213 *
14214 * \param inbound Incoming asterisk channel.
14215 * \param dest Same dial string passed to dahdi_request().
14216 * \param callback Callback into CC core to announce a busy channel available for CC.
14217 *
14218 * \details
14219 * This callback acts like a forked dial with all prongs of the fork busy.
14220 * Essentially, for each channel that could have taken the call, indicate that
14221 * it is busy.
14222 *
14223 * \retval 0 on success.
14224 * \retval -1 on error.
14225 */
14226static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
14227{
14228 struct dahdi_pvt *p;
14229 struct dahdi_pvt *exitpvt;
14230 struct dahdi_starting_point start;
14231 int groupmatched = 0;
14232 int channelmatched = 0;
14233
14235 p = determine_starting_point(dest, &start);
14236 if (!p) {
14238 return -1;
14239 }
14240 exitpvt = p;
14241 for (;;) {
14242 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)) {
14243 /* We found a potential match. call the callback */
14244 struct ast_str *device_name;
14245 char *dash;
14246 const char *monitor_type;
14247 char dialstring[AST_CHANNEL_NAME];
14248 char full_device_name[AST_CHANNEL_NAME];
14249
14252 break;
14256#if defined(HAVE_PRI)
14258 /*
14259 * ISDN is in a trunk busy condition so we need to monitor
14260 * the span congestion device state.
14261 */
14262 snprintf(full_device_name, sizeof(full_device_name),
14263 "DAHDI/I%d/congestion", p->pri->span);
14264 } else
14265#endif /* defined(HAVE_PRI) */
14266 {
14267#if defined(HAVE_PRI)
14268 device_name = create_channel_name(p, 1, "");
14269#else
14270 device_name = create_channel_name(p);
14271#endif /* defined(HAVE_PRI) */
14272 snprintf(full_device_name, sizeof(full_device_name), "DAHDI/%s",
14273 device_name ? ast_str_buffer(device_name) : "");
14274 ast_free(device_name);
14275 /*
14276 * The portion after the '-' in the channel name is either a random
14277 * number, a sequence number, or a subchannel number. None are
14278 * necessary so strip them off.
14279 */
14280 dash = strrchr(full_device_name, '-');
14281 if (dash) {
14282 *dash = '\0';
14283 }
14284 }
14285 snprintf(dialstring, sizeof(dialstring), "DAHDI/%s", dest);
14286
14287 /*
14288 * Analog can only do generic monitoring.
14289 * ISDN is in a trunk busy condition and any "device" is going
14290 * to be busy until a B channel becomes available. The generic
14291 * monitor can do this task.
14292 */
14293 monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
14294 callback(inbound,
14295#if defined(HAVE_PRI)
14296 p->pri ? p->pri->cc_params : p->cc_params,
14297#else
14298 p->cc_params,
14299#endif /* defined(HAVE_PRI) */
14300 monitor_type, full_device_name, dialstring, NULL);
14301 break;
14302 }
14303 }
14304 p = start.backwards ? p->prev : p->next;
14305 if (!p) {
14306 p = start.backwards ? ifend : iflist;
14307 }
14308 if (p == exitpvt) {
14309 break;
14310 }
14311 }
14313 return 0;
14314}
14315
14316#if defined(HAVE_SS7)
14317static void dahdi_ss7_message(struct ss7 *ss7, char *s)
14318{
14319 int i;
14320
14321 if (ss7) {
14322 for (i = 0; i < NUM_SPANS; i++) {
14323 if (linksets[i].ss7.ss7 == ss7) {
14324 ast_verbose_callid(0, "[%d] %s", i + 1, s);
14325 return;
14326 }
14327 }
14328 }
14329 ast_verbose_callid(0, "%s", s);
14330}
14331#endif /* defined(HAVE_SS7) */
14332
14333#if defined(HAVE_SS7)
14334static void dahdi_ss7_error(struct ss7 *ss7, char *s)
14335{
14336 int i;
14337
14338 if (ss7) {
14339 for (i = 0; i < NUM_SPANS; i++) {
14340 if (linksets[i].ss7.ss7 == ss7) {
14341 ast_log_callid(LOG_ERROR, 0, "[%d] %s", i + 1, s);
14342 return;
14343 }
14344 }
14345 }
14346 ast_log_callid(LOG_ERROR, 0, "%s", s);
14347}
14348#endif /* defined(HAVE_SS7) */
14349
14350#if defined(HAVE_OPENR2)
14351static void *mfcr2_monitor(void *data)
14352{
14353 struct dahdi_mfcr2 *mfcr2 = data;
14354 struct dahdi_pvt *pvt;
14355
14356 /* we should be using pthread_key_create
14357 and allocate pollers dynamically.
14358 I think do_monitor() could be leaking, since it
14359 could be cancelled at any time and is not
14360 using thread keys, why?, */
14361 struct pollfd pollers[ARRAY_LEN(mfcr2->pvts)];
14362 int res = 0;
14363 int i = 0;
14364 int oldstate = 0;
14365 int quit_loop = 0;
14366 int maxsleep = 20;
14367 int was_idle = 0;
14368 int pollsize = 0;
14369 /* now that we're ready to get calls, unblock our side and
14370 get current line state */
14371 for (i = 0; i < mfcr2->numchans; i++) {
14372 pvt = mfcr2->pvts[i];
14373 if (!pvt) {
14374 continue;
14375 }
14376 openr2_chan_set_idle(pvt->r2chan);
14377 openr2_chan_handle_cas(pvt->r2chan);
14378 }
14379 while (1) {
14380 /* we trust here that the mfcr2 channel list will not ever change once
14381 the module is loaded */
14382 pollsize = 0;
14383 for (i = 0; i < mfcr2->numchans; i++) {
14384 pollers[i].revents = 0;
14385 pollers[i].events = 0;
14386 pvt = mfcr2->pvts[i];
14387 if (!pvt) {
14388 continue;
14389 }
14390 if (pvt->owner) {
14391 continue;
14392 }
14393 if (mfcr2->nodev) {
14394 continue;
14395 }
14396 if (!pvt->r2chan) {
14397 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
14398 quit_loop = 1;
14399 break;
14400 }
14401 openr2_chan_enable_read(pvt->r2chan);
14402 pollers[i].events = POLLIN | POLLPRI;
14403 pollers[i].fd = pvt->subs[SUB_REAL].dfd;
14404 pollsize++;
14405 }
14406 if (quit_loop) {
14407 break;
14408 }
14409 if (pollsize == 0) {
14410 if (!was_idle) {
14411 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14412 was_idle = 1;
14413 }
14414 poll(NULL, 0, maxsleep);
14415 continue;
14416 }
14417 was_idle = 0;
14418 /* probably poll() is a valid cancel point, lets just be on the safe side
14419 by calling pthread_testcancel */
14420 pthread_testcancel();
14421 res = poll(pollers, mfcr2->numchans, maxsleep);
14422 pthread_testcancel();
14423 if ((res < 0) && (errno != EINTR)) {
14424 ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
14425 break;
14426 }
14427 /* do we want to allow to cancel while processing events? */
14428 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
14429 for (i = 0; i < mfcr2->numchans; i++) {
14430 pvt = mfcr2->pvts[i];
14431 if (!pvt) {
14432 continue;
14433 }
14434 if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
14435 openr2_chan_process_event(pvt->r2chan);
14436 }
14437 }
14438 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
14439 }
14440 ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
14441 return 0;
14442}
14443#endif /* HAVE_OPENR2 */
14444
14445#if defined(HAVE_PRI)
14446static void dahdi_pri_message(struct pri *pri, char *s)
14447{
14448 int x;
14449 int y;
14450 int dchan = -1;
14451 int span = -1;
14452 int dchancount = 0;
14453
14454 if (pri) {
14455 for (x = 0; x < NUM_SPANS; x++) {
14456 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14457 if (pris[x].pri.dchans[y]) {
14458 dchancount++;
14459 }
14460
14461 if (pris[x].pri.dchans[y] == pri) {
14462 dchan = y;
14463 }
14464 }
14465 if (dchan >= 0) {
14466 span = x;
14467 break;
14468 }
14469 dchancount = 0;
14470 }
14471 if (-1 < span) {
14472 if (1 < dchancount) {
14473 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14474 } else {
14475 ast_verbose_callid(0, "PRI Span: %d %s", span + 1, s);
14476 }
14477 } else {
14478 ast_verbose_callid(0, "PRI Span: ? %s", s);
14479 }
14480 } else {
14481 ast_verbose_callid(0, "PRI Span: ? %s", s);
14482 }
14483
14484 ast_mutex_lock(&pridebugfdlock);
14485
14486 if (pridebugfd >= 0) {
14487 if (write(pridebugfd, s, strlen(s)) < 0) {
14488 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14489 }
14490 }
14491
14492 ast_mutex_unlock(&pridebugfdlock);
14493}
14494#endif /* defined(HAVE_PRI) */
14495
14496#if defined(HAVE_PRI)
14497static void dahdi_pri_error(struct pri *pri, char *s)
14498{
14499 int x;
14500 int y;
14501 int dchan = -1;
14502 int span = -1;
14503 int dchancount = 0;
14504
14505 if (pri) {
14506 for (x = 0; x < NUM_SPANS; x++) {
14507 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14508 if (pris[x].pri.dchans[y]) {
14509 dchancount++;
14510 }
14511
14512 if (pris[x].pri.dchans[y] == pri) {
14513 dchan = y;
14514 }
14515 }
14516 if (dchan >= 0) {
14517 span = x;
14518 break;
14519 }
14520 dchancount = 0;
14521 }
14522 if (-1 < span) {
14523 if (1 < dchancount) {
14524 ast_log_callid(LOG_ERROR, 0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14525 } else {
14526 ast_log_callid(LOG_ERROR, 0, "PRI Span: %d %s", span + 1, s);
14527 }
14528 } else {
14529 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14530 }
14531 } else {
14532 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14533 }
14534
14535 ast_mutex_lock(&pridebugfdlock);
14536
14537 if (pridebugfd >= 0) {
14538 if (write(pridebugfd, s, strlen(s)) < 0) {
14539 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14540 }
14541 }
14542
14543 ast_mutex_unlock(&pridebugfdlock);
14544}
14545#endif /* defined(HAVE_PRI) */
14546
14547#if defined(HAVE_PRI)
14548static int prepare_pri(struct dahdi_pri *pri)
14549{
14550 int i, res, x;
14551 struct dahdi_params p;
14552 struct dahdi_bufferinfo bi;
14553 struct dahdi_spaninfo si;
14554
14555 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
14556 if (!pri->dchannels[i])
14557 break;
14558 if (pri->pri.fds[i] >= 0) {
14559 /* A partial range addition. Not a complete setup. */
14560 break;
14561 }
14562 pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
14563 if ((pri->pri.fds[i] < 0)) {
14564 ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
14565 pri->pri.fds[i], strerror(errno));
14566 return -1;
14567 }
14568 x = pri->dchannels[i];
14569 res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
14570 if (res) {
14571 dahdi_close_pri_fd(pri, i);
14572 ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
14573 return -1;
14574 }
14575 memset(&p, 0, sizeof(p));
14576 res = ioctl(pri->pri.fds[i], DAHDI_GET_PARAMS, &p);
14577 if (res) {
14578 dahdi_close_pri_fd(pri, i);
14579 ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
14580 return -1;
14581 }
14582 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
14583 dahdi_close_pri_fd(pri, i);
14584 ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
14585 return -1;
14586 }
14587 memset(&si, 0, sizeof(si));
14588 res = ioctl(pri->pri.fds[i], DAHDI_SPANSTAT, &si);
14589 if (res) {
14590 dahdi_close_pri_fd(pri, i);
14591 ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
14592 }
14593 if (!si.alarms) {
14594 pri_event_noalarm(&pri->pri, i, 1);
14595 } else {
14596 pri_event_alarm(&pri->pri, i, 1);
14597 }
14598 memset(&bi, 0, sizeof(bi));
14599 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
14600 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
14601 bi.numbufs = 32;
14602 bi.bufsize = 1024;
14603 if (ioctl(pri->pri.fds[i], DAHDI_SET_BUFINFO, &bi)) {
14604 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
14605 dahdi_close_pri_fd(pri, i);
14606 return -1;
14607 }
14608 pri->pri.dchan_logical_span[i] = pris[p.spanno - 1].prilogicalspan;
14609 }
14610 return 0;
14611}
14612#endif /* defined(HAVE_PRI) */
14613
14614#if defined(HAVE_PRI)
14615static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
14616{
14617 int which, span;
14618 char *ret = NULL;
14619
14620 if (pos != rpos)
14621 return ret;
14622
14623 for (which = span = 0; span < NUM_SPANS; span++) {
14624 if (pris[span].pri.pri && ++which > state) {
14625 if (ast_asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
14626 ret = NULL;
14627 }
14628 break;
14629 }
14630 }
14631 return ret;
14632}
14633#endif /* defined(HAVE_PRI) */
14634
14635#if defined(HAVE_PRI)
14636static char *complete_span_4(const char *line, const char *word, int pos, int state)
14637{
14638 return complete_span_helper(line,word,pos,state,3);
14639}
14640#endif /* defined(HAVE_PRI) */
14641
14642#if defined(HAVE_PRI)
14643static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14644{
14645 int myfd;
14646 switch (cmd) {
14647 case CLI_INIT:
14648 e->command = "pri set debug file";
14649 e->usage = "Usage: pri set debug file [output-file]\n"
14650 " Sends PRI debug output to the specified output file\n";
14651 return NULL;
14652 case CLI_GENERATE:
14653 return NULL;
14654 }
14655 if (a->argc < 5)
14656 return CLI_SHOWUSAGE;
14657
14658 if (ast_strlen_zero(a->argv[4]))
14659 return CLI_SHOWUSAGE;
14660
14661 myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
14662 if (myfd < 0) {
14663 ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
14664 return CLI_SUCCESS;
14665 }
14666
14667 ast_mutex_lock(&pridebugfdlock);
14668
14669 if (pridebugfd >= 0)
14670 close(pridebugfd);
14671
14672 pridebugfd = myfd;
14673 ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
14674 ast_mutex_unlock(&pridebugfdlock);
14675 ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
14676 return CLI_SUCCESS;
14677}
14678#endif /* defined(HAVE_PRI) */
14679
14680#if defined(HAVE_PRI)
14681static int action_pri_debug_file_set(struct mansession *s, const struct message *m)
14682{
14683 const char *output_file = astman_get_header(m, "File");
14684 int myfd;
14685
14686 if (ast_strlen_zero(output_file)) {
14687 astman_send_error(s, m, "Action must define a 'File'");
14688 }
14689
14690 myfd = open(output_file, O_CREAT|O_WRONLY, AST_FILE_MODE);
14691 if (myfd < 0) {
14692 astman_send_error(s, m, "Unable to open requested file for writing");
14693 return 0;
14694 }
14695
14696 ast_mutex_lock(&pridebugfdlock);
14697
14698 if (pridebugfd >= 0) {
14699 close(pridebugfd);
14700 }
14701
14702 pridebugfd = myfd;
14703 ast_copy_string(pridebugfilename, output_file, sizeof(pridebugfilename));
14704 ast_mutex_unlock(&pridebugfdlock);
14705 astman_send_ack(s, m, "PRI debug output will now be sent to requested file.");
14706
14707 return 0;
14708}
14709#endif /* defined(HAVE_PRI) */
14710
14711#if defined(HAVE_PRI)
14712static int action_pri_debug_file_unset(struct mansession *s, const struct message *m)
14713{
14714 ast_mutex_lock(&pridebugfdlock);
14715
14716 if (pridebugfd >= 0) {
14717 close(pridebugfd);
14718 }
14719
14720 pridebugfd = -1;
14721
14722 ast_mutex_unlock(&pridebugfdlock);
14723
14724 astman_send_ack(s, m, "PRI Debug output to file disabled");
14725 return 0;
14726}
14727#endif /* defined(HAVE_PRI) */
14728
14729#if defined(HAVE_PRI)
14730static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14731{
14732 int span;
14733 int x;
14734 int debugmask = 0;
14735 int level = 0;
14736 switch (cmd) {
14737 case CLI_INIT:
14738 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";
14739 e->usage =
14740 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14741 " Enables debugging on a given PRI span\n"
14742 " Level is a bitmap of the following values:\n"
14743 " 1 General debugging incl. state changes\n"
14744 " 2 Decoded Q.931 messages\n"
14745 " 4 Decoded Q.921 messages\n"
14746 " 8 Raw hex dumps of Q.921 frames\n"
14747 " on - equivalent to 3\n"
14748 " hex - equivalent to 8\n"
14749 " intense - equivalent to 15\n";
14750 return NULL;
14751 case CLI_GENERATE:
14752 return complete_span_4(a->line, a->word, a->pos, a->n);
14753 }
14754 if (a->argc < 6) {
14755 return CLI_SHOWUSAGE;
14756 }
14757
14758 if (!strcasecmp(a->argv[3], "on")) {
14759 level = 3;
14760 } else if (!strcasecmp(a->argv[3], "off")) {
14761 level = 0;
14762 } else if (!strcasecmp(a->argv[3], "intense")) {
14763 level = 15;
14764 } else if (!strcasecmp(a->argv[3], "hex")) {
14765 level = 8;
14766 } else {
14767 level = atoi(a->argv[3]);
14768 }
14769 span = atoi(a->argv[5]);
14770 if ((span < 1) || (span > NUM_SPANS)) {
14771 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[5], 1, NUM_SPANS);
14772 return CLI_SUCCESS;
14773 }
14774 if (!pris[span-1].pri.pri) {
14775 ast_cli(a->fd, "No PRI running on span %d\n", span);
14776 return CLI_SUCCESS;
14777 }
14778
14779 if (level & 1) debugmask |= SIG_PRI_DEBUG_NORMAL;
14780 if (level & 2) debugmask |= PRI_DEBUG_Q931_DUMP;
14781 if (level & 4) debugmask |= PRI_DEBUG_Q921_DUMP;
14782 if (level & 8) debugmask |= PRI_DEBUG_Q921_RAW;
14783
14784 /* Set debug level in libpri */
14785 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14786 if (pris[span - 1].pri.dchans[x]) {
14787 pri_set_debug(pris[span - 1].pri.dchans[x], debugmask);
14788 }
14789 }
14790 if (level == 0) {
14791 /* Close the debugging file if it's set */
14792 ast_mutex_lock(&pridebugfdlock);
14793 if (0 <= pridebugfd) {
14794 close(pridebugfd);
14795 pridebugfd = -1;
14796 ast_cli(a->fd, "Disabled PRI debug output to file '%s'\n",
14797 pridebugfilename);
14798 }
14799 ast_mutex_unlock(&pridebugfdlock);
14800 }
14801 pris[span - 1].pri.debug = (level) ? 1 : 0;
14802 ast_cli(a->fd, "%s debugging on span %d\n", (level) ? "Enabled" : "Disabled", span);
14803 return CLI_SUCCESS;
14804}
14805#endif /* defined(HAVE_PRI) */
14806
14807#if defined(HAVE_PRI)
14808static int action_pri_debug_set(struct mansession *s, const struct message *m)
14809{
14810 const char *level = astman_get_header(m, "Level");
14811 const char *span = astman_get_header(m, "Span");
14812 int level_val;
14813 int span_val;
14814 int x;
14815 int debugmask = 0;
14816
14817 if (ast_strlen_zero(level)) {
14818 astman_send_error(s, m, "'Level' was not specified");
14819 return 0;
14820 }
14821
14822 if (ast_strlen_zero(span)) {
14823 astman_send_error(s, m, "'Span' was not specified");
14824 return 0;
14825 }
14826
14827 if (!strcasecmp(level, "on")) {
14828 level_val = 3;
14829 } else if (!strcasecmp(level, "off")) {
14830 level_val = 0;
14831 } else if (!strcasecmp(level, "intense")) {
14832 level_val = 15;
14833 } else if (!strcasecmp(level, "hex")) {
14834 level_val = 8;
14835 } else {
14836 if (sscanf(level, "%30d", &level_val) != 1) {
14837 astman_send_error(s, m, "Invalid value for 'Level'");
14838 return 0;
14839 }
14840 }
14841
14842 if (sscanf(span, "%30d", &span_val) != 1) {
14843 astman_send_error(s, m, "Invalid value for 'Span'");
14844 }
14845
14846 if ((span_val < 1) || (span_val > NUM_SPANS)) {
14847 const char *id = astman_get_header(m, "ActionID");
14848 char id_text[256] = "";
14849
14850 if (!ast_strlen_zero(id)) {
14851 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
14852 }
14853
14854 astman_append(s, "Response: Error\r\n"
14855 "%s" /* id_text */
14856 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14857 "\r\n",
14858 id_text,
14859 span, NUM_SPANS);
14860
14861 return 0;
14862 }
14863
14864 if (!pris[span_val-1].pri.pri) {
14865 astman_send_error(s, m, "No PRI running on requested span");
14866 return 0;
14867 }
14868
14869 if (level_val & 1) {
14870 debugmask |= SIG_PRI_DEBUG_NORMAL;
14871 }
14872 if (level_val & 2) {
14873 debugmask |= PRI_DEBUG_Q931_DUMP;
14874 }
14875 if (level_val & 4) {
14876 debugmask |= PRI_DEBUG_Q921_DUMP;
14877 }
14878 if (level_val & 8) {
14879 debugmask |= PRI_DEBUG_Q921_RAW;
14880 }
14881
14882 /* Set debug level in libpri */
14883 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14884 if (pris[span_val - 1].pri.dchans[x]) {
14885 pri_set_debug(pris[span_val - 1].pri.dchans[x], debugmask);
14886 }
14887 }
14888
14889 pris[span_val - 1].pri.debug = (level_val) ? 1 : 0;
14890 astman_send_ack(s, m, "Debug level set for requested span");
14891
14892 return 0;
14893}
14894#endif /* defined(HAVE_PRI) */
14895
14896#if defined(HAVE_PRI)
14897#if defined(HAVE_PRI_SERVICE_MESSAGES)
14898static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
14899{
14900 unsigned *why;
14901 int channel;
14902 int trunkgroup;
14903 int x, y, fd = a->fd;
14904 int interfaceid = 0;
14905 char db_chan_name[20], db_answer[15];
14906 struct dahdi_pvt *tmp;
14907 struct dahdi_pri *pri;
14908
14909 if (a->argc < 5 || a->argc > 6)
14910 return CLI_SHOWUSAGE;
14911 if (strchr(a->argv[4], ':')) {
14912 if (sscanf(a->argv[4], "%30d:%30d", &trunkgroup, &channel) != 2)
14913 return CLI_SHOWUSAGE;
14914 if ((trunkgroup < 1) || (channel < 1))
14915 return CLI_SHOWUSAGE;
14916 pri = NULL;
14917 for (x=0;x<NUM_SPANS;x++) {
14918 if (pris[x].pri.trunkgroup == trunkgroup) {
14919 pri = pris + x;
14920 break;
14921 }
14922 }
14923 if (!pri) {
14924 ast_cli(fd, "No such trunk group %d\n", trunkgroup);
14925 return CLI_FAILURE;
14926 }
14927 } else
14928 channel = atoi(a->argv[4]);
14929
14930 if (a->argc == 6)
14931 interfaceid = atoi(a->argv[5]);
14932
14933 /* either servicing a D-Channel */
14934 for (x = 0; x < NUM_SPANS; x++) {
14935 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14936 if (pris[x].dchannels[y] == channel) {
14937 pri = pris + x;
14938 if (pri->pri.enable_service_message_support) {
14939 ast_mutex_lock(&pri->pri.lock);
14940 pri_maintenance_service(pri->pri.pri, interfaceid, -1, changestatus);
14941 ast_mutex_unlock(&pri->pri.lock);
14942 } else {
14943 ast_cli(fd,
14944 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14945 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14946 }
14947 return CLI_SUCCESS;
14948 }
14949 }
14950 }
14951
14952 /* or servicing a B-Channel */
14954 for (tmp = iflist; tmp; tmp = tmp->next) {
14955 if (tmp->pri && tmp->channel == channel) {
14957 ast_mutex_lock(&tmp->pri->lock);
14958 if (!tmp->pri->enable_service_message_support) {
14959 ast_mutex_unlock(&tmp->pri->lock);
14960 ast_cli(fd,
14961 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14962 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14963 return CLI_SUCCESS;
14964 }
14965 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, channel);
14966 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
14967 switch(changestatus) {
14968 case 0: /* enable */
14969 /* Near end wants to be in service now. */
14970 ast_db_del(db_chan_name, SRVST_DBKEY);
14971 *why &= ~SRVST_NEAREND;
14972 if (*why) {
14973 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
14974 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
14975 } else {
14976 dahdi_pri_update_span_devstate(tmp->pri);
14977 }
14978 break;
14979 /* case 1: -- loop */
14980 case 2: /* disable */
14981 /* Near end wants to be out-of-service now. */
14982 ast_db_del(db_chan_name, SRVST_DBKEY);
14983 *why |= SRVST_NEAREND;
14984 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
14985 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
14986 dahdi_pri_update_span_devstate(tmp->pri);
14987 break;
14988 /* case 3: -- continuity */
14989 /* case 4: -- shutdown */
14990 default:
14991 ast_log(LOG_WARNING, "Unsupported changestatus: '%d'\n", changestatus);
14992 break;
14993 }
14994 pri_maintenance_bservice(tmp->pri->pri, tmp->sig_pvt, changestatus);
14995 ast_mutex_unlock(&tmp->pri->lock);
14996 return CLI_SUCCESS;
14997 }
14998 }
15000
15001 ast_cli(fd, "Unable to find given channel %d, possibly not a PRI\n", channel);
15002 return CLI_FAILURE;
15003}
15004
15005static char *handle_pri_service_enable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15006{
15007 switch (cmd) {
15008 case CLI_INIT:
15009 e->command = "pri service enable channel";
15010 e->usage =
15011 "Usage: pri service enable channel <channel> [<interface id>]\n"
15012 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15013 " to restore a channel to service, with optional interface id\n"
15014 " as agreed upon with remote switch operator\n";
15015 return NULL;
15016 case CLI_GENERATE:
15017 return NULL;
15018 }
15019 return handle_pri_service_generic(e, cmd, a, 0);
15020}
15021
15022static char *handle_pri_service_disable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15023{
15024 switch (cmd) {
15025 case CLI_INIT:
15026 e->command = "pri service disable channel";
15027 e->usage =
15028 "Usage: pri service disable channel <chan num> [<interface id>]\n"
15029 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15030 " to remove a channel from service, with optional interface id\n"
15031 " as agreed upon with remote switch operator\n";
15032 return NULL;
15033 case CLI_GENERATE:
15034 return NULL;
15035 }
15036 return handle_pri_service_generic(e, cmd, a, 2);
15037}
15038#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15039#endif /* defined(HAVE_PRI) */
15040
15041#if defined(HAVE_PRI)
15042static char *handle_pri_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15043{
15044 int span;
15045
15046 switch (cmd) {
15047 case CLI_INIT:
15048 e->command = "pri show channels";
15049 e->usage =
15050 "Usage: pri show channels\n"
15051 " Displays PRI channel information such as the current mapping\n"
15052 " of DAHDI B channels to Asterisk channel names and which calls\n"
15053 " are on hold or call-waiting. Calls on hold or call-waiting\n"
15054 " are not associated with any B channel.\n";
15055 return NULL;
15056 case CLI_GENERATE:
15057 return NULL;
15058 }
15059
15060 if (a->argc != 3)
15061 return CLI_SHOWUSAGE;
15062
15064 for (span = 0; span < NUM_SPANS; ++span) {
15065 if (pris[span].pri.pri) {
15066 sig_pri_cli_show_channels(a->fd, &pris[span].pri);
15067 }
15068 }
15069 return CLI_SUCCESS;
15070}
15071#endif /* defined(HAVE_PRI) */
15072
15073#if defined(HAVE_PRI)
15074static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15075{
15076 int span;
15077
15078 switch (cmd) {
15079 case CLI_INIT:
15080 e->command = "pri show spans";
15081 e->usage =
15082 "Usage: pri show spans\n"
15083 " Displays PRI span information\n";
15084 return NULL;
15085 case CLI_GENERATE:
15086 return NULL;
15087 }
15088
15089 if (a->argc != 3)
15090 return CLI_SHOWUSAGE;
15091
15092 for (span = 0; span < NUM_SPANS; span++) {
15093 if (pris[span].pri.pri) {
15094 sig_pri_cli_show_spans(a->fd, span + 1, &pris[span].pri);
15095 }
15096 }
15097 return CLI_SUCCESS;
15098}
15099#endif /* defined(HAVE_PRI) */
15100
15101#if defined(HAVE_PRI)
15102#define container_of(ptr, type, member) \
15103 ((type *)((char *)(ptr) - offsetof(type, member)))
15104/*!
15105 * \internal
15106 * \brief Destroy a D-Channel of a PRI span
15107 * \since 12
15108 *
15109 * \param pri the pri span
15110 *
15111 * Shuts down a span and destroys its D-Channel. Further destruction
15112 * of the B-channels using dahdi_destroy_channel() would probably be required
15113 * for the B-Channels.
15114 */
15115static void pri_destroy_span(struct sig_pri_span *pri)
15116{
15117 int i;
15118 int res;
15119 int cancel_code;
15120 struct dahdi_pri* dahdi_pri;
15121 pthread_t master = pri->master;
15122
15123 if (!master || (master == AST_PTHREADT_NULL)) {
15124 return;
15125 }
15126 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
15127 for (i = 0; i < pri->numchans; i++) {
15128 int channel;
15129 struct sig_pri_chan *pvt = pri->pvts[i];
15130
15131 if (!pvt) {
15132 continue;
15133 }
15134 channel = pvt->channel;
15135 ast_debug(2, "About to destroy B-channel %d.\n", channel);
15137 }
15138
15139 cancel_code = pthread_cancel(master);
15140 pthread_kill(master, SIGURG);
15141 ast_debug(4,
15142 "Waiting to join thread of span %d "
15143 "with pid=%p cancel_code=%d\n",
15144 pri->span, (void *)master, cancel_code);
15145 res = pthread_join(master, NULL);
15146 if (res != 0) {
15147 ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
15148 }
15150
15151 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
15152 dahdi_pri = container_of(pri, struct dahdi_pri, pri);
15153 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
15154 ast_debug(4, "closing pri_fd %d\n", i);
15155 dahdi_close_pri_fd(dahdi_pri, i);
15156 dahdi_pri->dchannels[i] = 0;
15157 }
15159 ast_debug(1, "PRI span %d destroyed\n", pri->span);
15160}
15161
15162static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
15163 struct ast_cli_args *a)
15164{
15165 int span;
15166 int res;
15167 struct sig_pri_span *pri;
15168
15169 switch (cmd) {
15170 case CLI_INIT:
15171 e->command = "pri destroy span";
15172 e->usage =
15173 "Usage: pri destroy span <span>\n"
15174 " Destroys D-channel of span and its B-channels.\n"
15175 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15176 return NULL;
15177 case CLI_GENERATE:
15178 return complete_span_4(a->line, a->word, a->pos, a->n);
15179 }
15180
15181 if (a->argc < 4) {
15182 return CLI_SHOWUSAGE;
15183 }
15184 res = sscanf(a->argv[3], "%30d", &span);
15185 if ((res != 1) || span < 1 || span > NUM_SPANS) {
15186 ast_cli(a->fd,
15187 "Invalid span '%s'. Should be a number from %d to %d\n",
15188 a->argv[3], 1, NUM_SPANS);
15189 return CLI_SUCCESS;
15190 }
15191 pri = &pris[span - 1].pri;
15192 if (!pri->pri) {
15193 ast_cli(a->fd, "No PRI running on span %d\n", span);
15194 return CLI_SUCCESS;
15195 }
15196
15197 pri_destroy_span(pri);
15198 return CLI_SUCCESS;
15199}
15200
15201#endif /* defined(HAVE_PRI) */
15202
15203#if defined(HAVE_PRI)
15204static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15205{
15206 int span;
15207
15208 switch (cmd) {
15209 case CLI_INIT:
15210 e->command = "pri show span";
15211 e->usage =
15212 "Usage: pri show span <span>\n"
15213 " Displays PRI Information on a given PRI span\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 span = atoi(a->argv[3]);
15222 if ((span < 1) || (span > NUM_SPANS)) {
15223 ast_cli(a->fd, "Invalid span '%s'. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
15224 return CLI_SUCCESS;
15225 }
15226 if (!pris[span-1].pri.pri) {
15227 ast_cli(a->fd, "No PRI running on span %d\n", span);
15228 return CLI_SUCCESS;
15229 }
15230
15231 sig_pri_cli_show_span(a->fd, pris[span-1].dchannels, &pris[span-1].pri);
15232
15233 return CLI_SUCCESS;
15234}
15235#endif /* defined(HAVE_PRI) */
15236
15237#if defined(HAVE_PRI)
15238static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15239{
15240 int x;
15241 int span;
15242 int count=0;
15243 int debug;
15244
15245 switch (cmd) {
15246 case CLI_INIT:
15247 e->command = "pri show debug";
15248 e->usage =
15249 "Usage: pri show debug\n"
15250 " Show the debug state of pri spans\n";
15251 return NULL;
15252 case CLI_GENERATE:
15253 return NULL;
15254 }
15255
15256 for (span = 0; span < NUM_SPANS; span++) {
15257 if (pris[span].pri.pri) {
15258 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
15259 if (pris[span].pri.dchans[x]) {
15260 debug = pri_get_debug(pris[span].pri.dchans[x]);
15261 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" );
15262 count++;
15263 }
15264 }
15265 }
15266
15267 }
15268 ast_mutex_lock(&pridebugfdlock);
15269 if (pridebugfd >= 0)
15270 ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
15271 ast_mutex_unlock(&pridebugfdlock);
15272
15273 if (!count)
15274 ast_cli(a->fd, "No PRI running\n");
15275 return CLI_SUCCESS;
15276}
15277#endif /* defined(HAVE_PRI) */
15278
15279#if defined(HAVE_PRI)
15280static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15281{
15282 switch (cmd) {
15283 case CLI_INIT:
15284 e->command = "pri show version";
15285 e->usage =
15286 "Usage: pri show version\n"
15287 "Show libpri version information\n";
15288 return NULL;
15289 case CLI_GENERATE:
15290 return NULL;
15291 }
15292
15293 ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
15294
15295 return CLI_SUCCESS;
15296}
15297#endif /* defined(HAVE_PRI) */
15298
15299#if defined(HAVE_PRI)
15300static struct ast_cli_entry dahdi_pri_cli[] = {
15301 AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
15302#if defined(HAVE_PRI_SERVICE_MESSAGES)
15303 AST_CLI_DEFINE(handle_pri_service_enable_channel, "Return a channel to service"),
15304 AST_CLI_DEFINE(handle_pri_service_disable_channel, "Remove a channel from service"),
15305#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15306 AST_CLI_DEFINE(handle_pri_show_channels, "Displays PRI channel information"),
15307 AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI span information"),
15308 AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI span information"),
15309 AST_CLI_DEFINE(handle_pri_destroy_span, "Destroy a PRI span"),
15310 AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
15311 AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
15312 AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
15313};
15314#endif /* defined(HAVE_PRI) */
15315
15316#ifdef HAVE_OPENR2
15317
15318static char *handle_mfcr2_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15319{
15320 switch (cmd) {
15321 case CLI_INIT:
15322 e->command = "mfcr2 show version";
15323 e->usage =
15324 "Usage: mfcr2 show version\n"
15325 " Shows the version of the OpenR2 library being used.\n";
15326 return NULL;
15327 case CLI_GENERATE:
15328 return NULL;
15329 }
15330 ast_cli(a->fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15331 return CLI_SUCCESS;
15332}
15333
15334static char *handle_mfcr2_show_variants(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15335{
15336#define FORMAT "%4s %40s\n"
15337 int i = 0;
15338 int numvariants = 0;
15339 const openr2_variant_entry_t *variants;
15340 switch (cmd) {
15341 case CLI_INIT:
15342 e->command = "mfcr2 show variants";
15343 e->usage =
15344 "Usage: mfcr2 show variants\n"
15345 " Shows the list of MFC/R2 variants supported.\n";
15346 return NULL;
15347 case CLI_GENERATE:
15348 return NULL;
15349 }
15350 if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
15351 ast_cli(a->fd, "Failed to get list of variants.\n");
15352 return CLI_FAILURE;
15353 }
15354 ast_cli(a->fd, FORMAT, "Variant Code", "Country");
15355 for (i = 0; i < numvariants; i++) {
15356 ast_cli(a->fd, FORMAT, variants[i].name, variants[i].country);
15357 }
15358 return CLI_SUCCESS;
15359#undef FORMAT
15360}
15361
15362static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15363{
15364#define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15365 int filtertype = 0;
15366 int targetnum = 0;
15367 char channo[5];
15368 char linkno[5];
15369 char anino[5];
15370 char dnisno[5];
15371 struct dahdi_pvt *p;
15372 openr2_context_t *r2context;
15373 openr2_variant_t r2variant;
15374 switch (cmd) {
15375 case CLI_INIT:
15376 e->command = "mfcr2 show channels [group|context]";
15377 e->usage =
15378 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15379 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15380 return NULL;
15381 case CLI_GENERATE:
15382 return NULL;
15383 }
15384 if (!((a->argc == 3) || (a->argc == 5))) {
15385 return CLI_SHOWUSAGE;
15386 }
15387 if (a->argc == 5) {
15388 if (!strcasecmp(a->argv[3], "group")) {
15389 targetnum = atoi(a->argv[4]);
15390 if ((targetnum < 0) || (targetnum > 63))
15391 return CLI_SHOWUSAGE;
15392 targetnum = 1 << targetnum;
15393 filtertype = 1;
15394 } else if (!strcasecmp(a->argv[3], "context")) {
15395 filtertype = 2;
15396 } else {
15397 return CLI_SHOWUSAGE;
15398 }
15399 }
15400 ast_cli(a->fd, FORMAT, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15402 for (p = iflist; p; p = p->next) {
15403 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15404 continue;
15405 }
15406 if (filtertype) {
15407 switch(filtertype) {
15408 case 1: /* mfcr2 show channels group <group> */
15409 if (p->group != targetnum) {
15410 continue;
15411 }
15412 break;
15413 case 2: /* mfcr2 show channels context <context> */
15414 if (strcasecmp(p->context, a->argv[4])) {
15415 continue;
15416 }
15417 break;
15418 default:
15419 ;
15420 }
15421 }
15422 r2context = openr2_chan_get_context(p->r2chan);
15423 r2variant = openr2_context_get_variant(r2context);
15424 snprintf(channo, sizeof(channo), "%d", p->channel);
15425 snprintf(linkno, sizeof(linkno), "%d", p->mfcr2->index);
15426 snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
15427 snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
15428 ast_cli(a->fd, FORMAT, channo, linkno, openr2_proto_get_variant_string(r2variant),
15429 anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
15430 openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
15431 openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
15432 }
15434 return CLI_SUCCESS;
15435#undef FORMAT
15436}
15437
15438static char *handle_mfcr2_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15439{
15440 struct dahdi_pvt *p = NULL;
15441 int channo = 0;
15442 char *toklevel = NULL;
15443 char *saveptr = NULL;
15444 char *logval = NULL;
15445 openr2_log_level_t loglevel = OR2_LOG_NOTHING;
15446 openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
15447 switch (cmd) {
15448 case CLI_INIT:
15449 e->command = "mfcr2 set debug";
15450 e->usage =
15451 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15452 " Set a new logging level for the specified channel.\n"
15453 " If no channel is specified the logging level will be applied to all channels.\n";
15454 return NULL;
15455 case CLI_GENERATE:
15456 return NULL;
15457 }
15458 if (a->argc < 4) {
15459 return CLI_SHOWUSAGE;
15460 }
15461 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15462 logval = ast_strdupa(a->argv[3]);
15463 toklevel = strtok_r(logval, ",", &saveptr);
15464 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15465 ast_cli(a->fd, "Invalid MFC/R2 logging level '%s'.\n", a->argv[3]);
15466 return CLI_FAILURE;
15467 } else if (OR2_LOG_NOTHING == tmplevel) {
15468 loglevel = tmplevel;
15469 } else {
15470 loglevel |= tmplevel;
15471 while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
15472 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15473 ast_cli(a->fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
15474 continue;
15475 }
15476 loglevel |= tmplevel;
15477 }
15478 }
15480 for (p = iflist; p; p = p->next) {
15481 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15482 continue;
15483 }
15484 if ((channo != -1) && (p->channel != channo )) {
15485 continue;
15486 }
15487 openr2_chan_set_log_level(p->r2chan, loglevel);
15488 if (channo != -1) {
15489 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for channel %d.\n", a->argv[3], p->channel);
15490 break;
15491 }
15492 }
15493 if ((channo != -1) && !p) {
15494 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15495 }
15496 if (channo == -1) {
15497 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for all channels.\n", a->argv[3]);
15498 }
15500 return CLI_SUCCESS;
15501}
15502
15503static char *handle_mfcr2_call_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15504{
15505 struct dahdi_pvt *p = NULL;
15506 int channo = 0;
15507 switch (cmd) {
15508 case CLI_INIT:
15509 e->command = "mfcr2 call files [on|off]";
15510 e->usage =
15511 "Usage: mfcr2 call files [on|off] <channel>\n"
15512 " Enable call files creation on the specified channel.\n"
15513 " If no channel is specified call files creation policy will be applied to all channels.\n";
15514 return NULL;
15515 case CLI_GENERATE:
15516 return NULL;
15517 }
15518 if (a->argc < 4) {
15519 return CLI_SHOWUSAGE;
15520 }
15521 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15523 for (p = iflist; p; p = p->next) {
15524 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15525 continue;
15526 }
15527 if ((channo != -1) && (p->channel != channo )) {
15528 continue;
15529 }
15530 if (ast_true(a->argv[3])) {
15531 openr2_chan_enable_call_files(p->r2chan);
15532 } else {
15533 openr2_chan_disable_call_files(p->r2chan);
15534 }
15535 if (channo != -1) {
15536 if (ast_true(a->argv[3])) {
15537 ast_cli(a->fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
15538 } else {
15539 ast_cli(a->fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
15540 }
15541 break;
15542 }
15543 }
15544 if ((channo != -1) && !p) {
15545 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15546 }
15547 if (channo == -1) {
15548 if (ast_true(a->argv[3])) {
15549 ast_cli(a->fd, "MFC/R2 Call files enabled for all channels.\n");
15550 } else {
15551 ast_cli(a->fd, "MFC/R2 Call files disabled for all channels.\n");
15552 }
15553 }
15555 return CLI_SUCCESS;
15556}
15557
15558static char *handle_mfcr2_set_idle(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15559{
15560 struct dahdi_pvt *p = NULL;
15561 int channo = 0;
15562 switch (cmd) {
15563 case CLI_INIT:
15564 e->command = "mfcr2 set idle";
15565 e->usage =
15566 "Usage: mfcr2 set idle <channel>\n"
15567 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15568 " Force the given channel into IDLE state.\n"
15569 " If no channel is specified, all channels will be set to IDLE.\n";
15570 return NULL;
15571 case CLI_GENERATE:
15572 return NULL;
15573 }
15574 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15576 for (p = iflist; p; p = p->next) {
15577 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15578 continue;
15579 }
15580 if ((channo != -1) && (p->channel != channo )) {
15581 continue;
15582 }
15583 openr2_chan_set_idle(p->r2chan);
15584 ast_mutex_lock(&p->lock);
15585 p->locallyblocked = 0;
15586 p->mfcr2call = 0;
15588 if (channo != -1) {
15589 break;
15590 }
15591 }
15592 if ((channo != -1) && !p) {
15593 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15594 }
15596 return CLI_SUCCESS;
15597}
15598
15599static char *handle_mfcr2_set_blocked(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15600{
15601 struct dahdi_pvt *p = NULL;
15602 int channo = 0;
15603 switch (cmd) {
15604 case CLI_INIT:
15605 e->command = "mfcr2 set blocked";
15606 e->usage =
15607 "Usage: mfcr2 set blocked <channel>\n"
15608 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15609 " Force the given channel into BLOCKED state.\n"
15610 " If no channel is specified, all channels will be set to BLOCKED.\n";
15611 return NULL;
15612 case CLI_GENERATE:
15613 return NULL;
15614 }
15615 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15617 for (p = iflist; p; p = p->next) {
15618 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15619 continue;
15620 }
15621 if ((channo != -1) && (p->channel != channo )) {
15622 continue;
15623 }
15624 openr2_chan_set_blocked(p->r2chan);
15625 ast_mutex_lock(&p->lock);
15626 p->locallyblocked = 1;
15628 if (channo != -1) {
15629 break;
15630 }
15631 }
15632 if ((channo != -1) && !p) {
15633 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15634 }
15636 return CLI_SUCCESS;
15637}
15638
15639static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_head, const char *title)
15640{
15641#define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15642 AST_LIST_LOCK(list_head);
15643 if (! AST_LIST_EMPTY(list_head)) {
15644 int x = 0;
15645 char index[5];
15646 char live_chans_str[5];
15647 char channel_list[R2_LINK_CAPACITY * 4];
15648 struct r2link_entry *cur;
15649 ast_cli(a->fd, "%s\n", title);
15650 ast_cli(a->fd, FORMAT, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15651 AST_LIST_TRAVERSE(list_head, cur, list) {
15652 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15653 const char *thread_status = NULL;
15654 int i;
15655 int len;
15656 int inside_range;
15657 int channo;
15658 int prev_channo;
15659 x++;
15660 if (mfcr2->r2master == 0L) {
15661 thread_status = "zero";
15662 } else if (mfcr2->r2master == AST_PTHREADT_NULL) {
15663 thread_status = "none";
15664 } else {
15665 thread_status = "created";
15666 }
15667 snprintf(index, sizeof(index), "%d", mfcr2->index);
15668 snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
15669 channo = 0;
15670 prev_channo = 0;
15671 inside_range = 0;
15672 len = 0;
15673 /* Prepare nice string in channel_list[] */
15674 for (i = 0; i < mfcr2->numchans && len < sizeof(channel_list) - 1; i++) {
15675 struct dahdi_pvt *p = mfcr2->pvts[i];
15676 if (!p) {
15677 continue;
15678 }
15679 channo = p->channel;
15680 /* Don't show a range until we know the last channel number */
15681 if (prev_channo && prev_channo == channo - 1) {
15682 prev_channo = channo;
15683 inside_range = 1;
15684 continue;
15685 }
15686 if (inside_range) {
15687 /* Close range */
15688 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d,%d", prev_channo, channo);
15689 inside_range = 0;
15690 } else if (prev_channo) {
15691 /* Non-sequential channel numbers */
15692 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15693 } else {
15694 /* First channel number */
15695 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "%d", channo);
15696 }
15697 prev_channo = channo;
15698 }
15699 /* Handle leftover channels */
15700 if (inside_range) {
15701 /* Close range */
15702 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d", channo);
15703 inside_range = 0;
15704 } else if (prev_channo) {
15705 /* Non-sequential channel numbers */
15706 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15707 }
15708 // channel_list[len] = '\0';
15709 ast_cli(a->fd, FORMAT,
15710 index,
15711 thread_status,
15712 (mfcr2->nodev) ? "MISSING" : "OK",
15713 live_chans_str,
15714 channel_list);
15715 }
15716 }
15717 AST_LIST_UNLOCK(list_head);
15718#undef FORMAT
15719}
15720
15721static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15722{
15723 switch (cmd) {
15724 case CLI_INIT:
15725 e->command = "mfcr2 show links";
15726 e->usage =
15727 "Usage: mfcr2 show links\n"
15728 " Shows the DAHDI MFC/R2 links.\n";
15729 return NULL;
15730 case CLI_GENERATE:
15731 return NULL;
15732 }
15733 if (a->argc != 3) {
15734 return CLI_SHOWUSAGE;
15735 }
15736 mfcr2_show_links_of(a, &r2links, "Live links\n");
15737 mfcr2_show_links_of(a, &nodev_r2links, "Links to be removed (device missing)\n");
15738 return CLI_SUCCESS;
15739}
15740
15741static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15742{
15743 int res;
15744 int wanted_link_index;
15745 int found_link = 0;
15746 struct r2link_entry *cur = NULL;
15747
15748 switch (cmd) {
15749 case CLI_INIT:
15750 e->command = "mfcr2 destroy link";
15751 e->usage =
15752 "Usage: mfcr2 destroy link <index-number>\n"
15753 " Destroys D-channel of link and its B-channels.\n"
15754 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15755 return NULL;
15756 case CLI_GENERATE:
15757 return NULL;
15758 }
15759 if (a->argc < 4) {
15760 return CLI_SHOWUSAGE;
15761 }
15762 res = sscanf(a->argv[3], "%30d", &wanted_link_index);
15763 if ((res != 1) || wanted_link_index < 1) {
15764 ast_cli(a->fd,
15765 "Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
15766 return CLI_SUCCESS;
15767 }
15768 AST_LIST_LOCK(&r2links);
15769 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
15770 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15771 if (wanted_link_index == mfcr2->index) {
15772 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
15773 r2links_count--;
15774 break;
15775 }
15776 }
15778 AST_LIST_UNLOCK(&r2links);
15779 if (! found_link) {
15780 ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
15781 return CLI_FAILURE;
15782 }
15783 return CLI_SUCCESS;
15784}
15785
15786static struct ast_cli_entry dahdi_mfcr2_cli[] = {
15787 AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
15788 AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
15789 AST_CLI_DEFINE(handle_mfcr2_show_channels, "Show MFC/R2 channels"),
15790 AST_CLI_DEFINE(handle_mfcr2_show_links, "Show MFC/R2 links"),
15791 AST_CLI_DEFINE(handle_mfcr2_set_debug, "Set MFC/R2 channel logging level"),
15792 AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
15793 AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
15794 AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
15795 AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
15796};
15797
15798#endif /* HAVE_OPENR2 */
15799
15800static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15801{
15802 int start;
15803 int end;
15804 switch (cmd) {
15805 case CLI_INIT:
15806 e->command = "dahdi destroy channels";
15807 e->usage =
15808 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15809 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15810 return NULL;
15811 case CLI_GENERATE:
15812 return NULL;
15813 }
15814 if ((a->argc < 4) || a->argc > 5) {
15815 return CLI_SHOWUSAGE;
15816 }
15817 start = atoi(a->argv[3]);
15818 if (start < 1) {
15819 ast_cli(a->fd, "Invalid starting channel number %s.\n",
15820 a->argv[4]);
15821 return CLI_FAILURE;
15822 }
15823 if (a->argc == 5) {
15824 end = atoi(a->argv[4]);
15825 if (end < 1) {
15826 ast_cli(a->fd, "Invalid ending channel number %s.\n",
15827 a->argv[4]);
15828 return CLI_FAILURE;
15829 }
15830 } else {
15831 end = start;
15832 }
15833
15834 if (end < start) {
15835 ast_cli(a->fd,
15836 "range end (%d) is smaller than range start (%d)\n",
15837 end, start);
15838 return CLI_FAILURE;
15839 }
15841 return CLI_SUCCESS;
15842}
15843
15844static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15845{
15846 int start;
15847 int end;
15848 int ret;
15849
15850 switch (cmd) {
15851 case CLI_INIT:
15852 e->command = "dahdi create channels";
15853 e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15854 " dahdi create channels new - add channels not yet created\n"
15855 "For ISDN and SS7 the range should include complete spans.\n";
15856 return NULL;
15857 case CLI_GENERATE:
15858 return NULL;
15859 }
15860 if ((a->argc < 4) || a->argc > 5) {
15861 return CLI_SHOWUSAGE;
15862 }
15863 if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
15864 ret = dahdi_create_channel_range(0, 0);
15865 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15866 }
15867 start = atoi(a->argv[3]);
15868 if (start <= 0) {
15869 ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
15870 a->argv[3]);
15871 return CLI_FAILURE;
15872 }
15873 if (a->argc == 5) {
15874 end = atoi(a->argv[4]);
15875 if (end <= 0) {
15876 ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
15877 a->argv[4]);
15878 return CLI_FAILURE;
15879 }
15880 } else {
15881 end = start;
15882 }
15883 if (end < start) {
15884 ast_cli(a->fd,
15885 "range end (%d) is smaller than range start (%d)\n",
15886 end, start);
15887 return CLI_FAILURE;
15888 }
15889 ret = dahdi_create_channel_range(start, end);
15890 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15891}
15892
15893static void dahdi_softhangup_all(void)
15894{
15895 struct dahdi_pvt *p;
15896retry:
15898 for (p = iflist; p; p = p->next) {
15899 ast_mutex_lock(&p->lock);
15900 if (p->owner && !p->restartpending) {
15901 if (ast_channel_trylock(p->owner)) {
15902 if (DEBUG_ATLEAST(3))
15903 ast_verbose("Avoiding deadlock\n");
15904 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15907 goto retry;
15908 }
15909 if (DEBUG_ATLEAST(3))
15910 ast_verbose("Softhanging up on %s\n", ast_channel_name(p->owner));
15912 p->restartpending = 1;
15915 }
15917 }
15919}
15920
15921static int dahdi_restart(void)
15922{
15923#if defined(HAVE_PRI) || defined(HAVE_SS7)
15924 int i, j;
15925#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15926 int cancel_code;
15927 struct dahdi_pvt *p;
15928
15930 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15932 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15933#ifdef HAVE_OPENR2
15934 dahdi_r2_destroy_links();
15935#endif
15936
15937#if defined(HAVE_PRI)
15938 for (i = 0; i < NUM_SPANS; i++) {
15939 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
15940 cancel_code = pthread_cancel(pris[i].pri.master);
15941 pthread_kill(pris[i].pri.master, SIGURG);
15942 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);
15943 pthread_join(pris[i].pri.master, NULL);
15944 ast_debug(4, "Joined thread of span %d\n", i);
15945 }
15946 }
15947#endif
15948
15949#if defined(HAVE_SS7)
15950 for (i = 0; i < NUM_SPANS; i++) {
15951 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
15952 cancel_code = pthread_cancel(linksets[i].ss7.master);
15953 pthread_kill(linksets[i].ss7.master, SIGURG);
15954 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);
15955 pthread_join(linksets[i].ss7.master, NULL);
15956 ast_debug(4, "Joined thread of span %d\n", i);
15957 }
15958 }
15959#endif /* defined(HAVE_SS7) */
15960
15963 cancel_code = pthread_cancel(monitor_thread);
15964 pthread_kill(monitor_thread, SIGURG);
15965 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
15966 pthread_join(monitor_thread, NULL);
15967 ast_debug(4, "Joined monitor thread\n");
15968 }
15969 monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
15970
15972 while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
15973 int x = DAHDI_FLASH;
15974 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count);
15975
15977 for (p = iflist; p; p = p->next) {
15978 if (p->owner) {
15979 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
15980 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
15981 }
15982 }
15985 }
15986
15987 /* ensure any created channels before monitor threads were stopped are hungup */
15989 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
15991 memset(round_robin, 0, sizeof(round_robin));
15992 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
15993
15995
15996#ifdef HAVE_PRI
15997 for (i = 0; i < NUM_SPANS; i++) {
15998 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++)
15999 dahdi_close_pri_fd(&(pris[i]), j);
16000 }
16001
16002 memset(pris, 0, sizeof(pris));
16003 for (i = 0; i < NUM_SPANS; i++) {
16004 sig_pri_init_pri(&pris[i].pri);
16005 }
16006 pri_set_error(dahdi_pri_error);
16007 pri_set_message(dahdi_pri_message);
16008#endif
16009#if defined(HAVE_SS7)
16010 for (i = 0; i < NUM_SPANS; i++) {
16011 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++)
16012 dahdi_close_ss7_fd(&(linksets[i]), j);
16013 }
16014
16015 memset(linksets, 0, sizeof(linksets));
16016 for (i = 0; i < NUM_SPANS; i++) {
16017 sig_ss7_init_linkset(&linksets[i].ss7);
16018 }
16019 ss7_set_error(dahdi_ss7_error);
16020 ss7_set_message(dahdi_ss7_message);
16021 ss7_set_hangup(sig_ss7_cb_hangup);
16022 ss7_set_notinservice(sig_ss7_cb_notinservice);
16023 ss7_set_call_null(sig_ss7_cb_call_null);
16024#endif /* defined(HAVE_SS7) */
16025
16026 if (setup_dahdi(2) != 0) {
16027 ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
16029 return 1;
16030 }
16033 return 0;
16034}
16035
16036static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16037{
16038 switch (cmd) {
16039 case CLI_INIT:
16040 e->command = "dahdi restart";
16041 e->usage =
16042 "Usage: dahdi restart\n"
16043 " Restarts the DAHDI channels: destroys them all and then\n"
16044 " re-reads them from chan_dahdi.conf.\n"
16045 " Note that this will STOP any running CALL on DAHDI channels.\n"
16046 "";
16047 return NULL;
16048 case CLI_GENERATE:
16049 return NULL;
16050 }
16051 if (a->argc != 2)
16052 return CLI_SHOWUSAGE;
16053
16054 if (dahdi_restart() != 0)
16055 return CLI_FAILURE;
16056 return CLI_SUCCESS;
16057}
16058
16059static int action_dahdirestart(struct mansession *s, const struct message *m)
16060{
16061 if (dahdi_restart() != 0) {
16062 astman_send_error(s, m, "Failed rereading DAHDI configuration");
16063 return 1;
16064 }
16065 astman_send_ack(s, m, "DAHDIRestart: Success");
16066 return 0;
16067}
16068
16069static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16070{
16071#define FORMAT "%7s %4d %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16072#define FORMAT2 "%7s %4s %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16073 ast_group_t targetnum = 0;
16074 int filtertype = 0;
16075 struct dahdi_pvt *tmp = NULL;
16076 char tmps[20];
16077 char blockstr[20];
16078
16079 switch (cmd) {
16080 case CLI_INIT:
16081 e->command = "dahdi show channels [group|context]";
16082 e->usage =
16083 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
16084 " Shows a list of available channels with optional filtering\n"
16085 " <group> must be a number between 0 and 63\n";
16086 return NULL;
16087 case CLI_GENERATE:
16088 return NULL;
16089 }
16090
16091 /* syntax: dahdi show channels [ group <group> | context <context> ] */
16092
16093 if (!((a->argc == 3) || (a->argc == 5))) {
16094 return CLI_SHOWUSAGE;
16095 }
16096
16097 if (a->argc == 5) {
16098 if (!strcasecmp(a->argv[3], "group")) {
16099 targetnum = atoi(a->argv[4]);
16100 if (63 < targetnum) {
16101 return CLI_SHOWUSAGE;
16102 }
16103 targetnum = ((ast_group_t) 1) << targetnum;
16104 filtertype = 1;
16105 } else if (!strcasecmp(a->argv[3], "context")) {
16106 filtertype = 2;
16107 }
16108 }
16109
16110 ast_cli(a->fd, FORMAT2, "Chan", "Span", "Signalling", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Alarms", "Description");
16112 for (tmp = iflist; tmp; tmp = tmp->next) {
16113 int alm = 0;
16114 if (filtertype) {
16115 switch(filtertype) {
16116 case 1: /* dahdi show channels group <group> */
16117 if (!(tmp->group & targetnum)) {
16118 continue;
16119 }
16120 break;
16121 case 2: /* dahdi show channels context <context> */
16122 if (strcasecmp(tmp->context, a->argv[4])) {
16123 continue;
16124 }
16125 break;
16126 default:
16127 break;
16128 }
16129 }
16130 if (tmp->channel > 0) {
16131 snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
16132 alm = get_alarms(tmp);
16133 } else {
16134 ast_copy_string(tmps, "pseudo", sizeof(tmps));
16135 }
16136
16137 blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
16138 blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
16139 blockstr[2] = '\0';
16140
16141 ast_cli(a->fd, FORMAT, tmps, tmp->span, sig2str(tmp->sig), tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No",
16142 alarm2str(alm), tmp->description);
16143 }
16145 return CLI_SUCCESS;
16146#undef FORMAT
16147#undef FORMAT2
16148}
16149
16150static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16151{
16152 int channel;
16153 struct dahdi_pvt *tmp = NULL;
16154 struct dahdi_confinfo ci;
16155 struct dahdi_params ps;
16156 int x;
16157 char hwrxgain[15];
16158 char hwtxgain[15];
16159
16160 switch (cmd) {
16161 case CLI_INIT:
16162 e->command = "dahdi show channel";
16163 e->usage =
16164 "Usage: dahdi show channel <chan num>\n"
16165 " Detailed information about a given channel\n";
16166 return NULL;
16167 case CLI_GENERATE:
16168 return NULL;
16169 }
16170
16171 if (a->argc != 4)
16172 return CLI_SHOWUSAGE;
16173
16174 channel = atoi(a->argv[3]);
16175
16177 for (tmp = iflist; tmp; tmp = tmp->next) {
16178 if (tmp->channel == channel) {
16179 ast_cli(a->fd, "Channel: %d\n", tmp->channel);
16180 ast_cli(a->fd, "Description: %s\n", tmp->description);
16181 ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
16182 ast_cli(a->fd, "Span: %d\n", tmp->span);
16183 ast_cli(a->fd, "Extension: %s\n", tmp->exten);
16184 ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
16185 ast_cli(a->fd, "Context: %s\n", tmp->context);
16186 ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
16187 ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
16188#if defined(HAVE_PRI)
16189#if defined(HAVE_PRI_SUBADDR)
16190 ast_cli(a->fd, "Caller ID subaddress: %s\n", tmp->cid_subaddr);
16191#endif /* defined(HAVE_PRI_SUBADDR) */
16192#endif /* defined(HAVE_PRI) */
16193 ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
16194 ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
16195 if (tmp->vars) {
16196 struct ast_variable *v;
16197 ast_cli(a->fd, "Variables:\n");
16198 for (v = tmp->vars ; v ; v = v->next)
16199 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
16200 }
16201 ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
16202 ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
16203 ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
16204 ast_cli(a->fd, "Radio: %d\n", tmp->radio);
16205 ast_cli(a->fd, "Owner: %s\n", tmp->owner ? ast_channel_name(tmp->owner) : "<None>");
16206 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)" : "");
16207 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)" : "");
16208 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)" : "");
16209 ast_cli(a->fd, "Confno: %d\n", tmp->confno);
16210 ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
16211 ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
16212 ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
16213 ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
16214 if (tmp->busydetect) {
16215#if defined(BUSYDETECT_TONEONLY)
16216 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16217#elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16218 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16219#endif
16220#ifdef BUSYDETECT_DEBUG
16221 ast_cli(a->fd, " Busy Detector Debug: Enabled\n");
16222#endif
16223 ast_cli(a->fd, " Busy Count: %d\n", tmp->busycount);
16224 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);
16225 }
16226 ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
16227 ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
16228 ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
16229 ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
16230 ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
16231 ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
16232 if (tmp->hwrxgain_enabled) {
16233 snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
16234 } else {
16235 ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
16236 }
16237 if (tmp->hwtxgain_enabled) {
16238 snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
16239 } else {
16240 ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
16241 }
16242 ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
16243 ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
16244 ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
16245 ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
16246 ast_cli(a->fd, "Echo Cancellation:\n");
16247
16248 if (tmp->echocancel.head.tap_length) {
16249 ast_cli(a->fd, "\t%u taps\n", tmp->echocancel.head.tap_length);
16250 for (x = 0; x < tmp->echocancel.head.param_count; x++) {
16251 ast_cli(a->fd, "\t\t%s: %dd\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
16252 }
16253 ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
16254 } else {
16255 ast_cli(a->fd, "\tnone\n");
16256 }
16257 ast_cli(a->fd, "Wait for dialtone: %dms\n", tmp->waitfordialtone);
16258 if (tmp->master)
16259 ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
16260 for (x = 0; x < MAX_SLAVES; x++) {
16261 if (tmp->slaves[x])
16262 ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
16263 }
16264#ifdef HAVE_OPENR2
16265 if (tmp->mfcr2) {
16266 char calldir[OR2_MAX_PATH];
16267 openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
16268 openr2_variant_t r2variant = openr2_context_get_variant(r2context);
16269 ast_cli(a->fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
16270 ast_cli(a->fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
16271 ast_cli(a->fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
16272 ast_cli(a->fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
16273 ast_cli(a->fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
16274 ast_cli(a->fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
16275 ast_cli(a->fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
16276 ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
16277#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16278 ast_cli(a->fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
16279 ast_cli(a->fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
16280#endif
16281 ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
16282#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16283 ast_cli(a->fd, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
16284#endif
16285 ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
16286 ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
16287 ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
16288 ast_cli(a->fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
16289 ast_cli(a->fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
16290 ast_cli(a->fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
16291 ast_cli(a->fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
16292 ast_cli(a->fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
16293 ast_cli(a->fd, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
16294 ast_cli(a->fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
16295 ast_cli(a->fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
16296 ast_cli(a->fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
16297 }
16298#endif
16299#if defined(HAVE_SS7)
16300 if (tmp->ss7) {
16301 struct sig_ss7_chan *chan = tmp->sig_pvt;
16302
16303 ast_cli(a->fd, "CIC: %d\n", chan->cic);
16304 }
16305#endif /* defined(HAVE_SS7) */
16306#ifdef HAVE_PRI
16307 if (tmp->pri) {
16308 struct sig_pri_chan *chan = tmp->sig_pvt;
16309
16310 ast_cli(a->fd, "PRI Flags: ");
16311 if (chan->resetting != SIG_PRI_RESET_IDLE) {
16312 ast_cli(a->fd, "Resetting=%u ", chan->resetting);
16313 }
16314 if (chan->call)
16315 ast_cli(a->fd, "Call ");
16316 if (chan->allocated) {
16317 ast_cli(a->fd, "Allocated ");
16318 }
16319 ast_cli(a->fd, "\n");
16320 if (tmp->logicalspan)
16321 ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
16322 else
16323 ast_cli(a->fd, "PRI Logical Span: Implicit\n");
16324 }
16325#endif
16326 memset(&ci, 0, sizeof(ci));
16327 ps.channo = tmp->channel;
16328 if (tmp->subs[SUB_REAL].dfd > -1) {
16329 memset(&ci, 0, sizeof(ci));
16330 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
16331 ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, (unsigned)ci.confmode);
16332 }
16333 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
16334 ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
16335 }
16336 memset(&ps, 0, sizeof(ps));
16337 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
16338 ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
16339 } else {
16340 ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
16341 }
16342 }
16344 return CLI_SUCCESS;
16345 }
16346 }
16348
16349 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16350 return CLI_FAILURE;
16351}
16352
16353static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16354{
16355 int i, j;
16356 switch (cmd) {
16357 case CLI_INIT:
16358 e->command = "dahdi show cadences";
16359 e->usage =
16360 "Usage: dahdi show cadences\n"
16361 " Shows all cadences currently defined\n";
16362 return NULL;
16363 case CLI_GENERATE:
16364 return NULL;
16365 }
16366 for (i = 0; i < num_cadence; i++) {
16367 char output[1024];
16368 char tmp[16], tmp2[64];
16369 snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
16370 term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
16371
16372 for (j = 0; j < 16; j++) {
16373 if (cadences[i].ringcadence[j] == 0)
16374 break;
16375 snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
16376 if (cidrings[i] * 2 - 1 == j)
16377 term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
16378 else
16379 term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
16380 if (j != 0)
16381 strncat(output, ",", sizeof(output) - strlen(output) - 1);
16382 strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
16383 }
16384 ast_cli(a->fd,"%s\n",output);
16385 }
16386 return CLI_SUCCESS;
16387}
16388
16389static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
16390{
16391 alarmstr[0] = '\0';
16392 if (spaninfo->alarms > 0) {
16393 if (spaninfo->alarms & DAHDI_ALARM_BLUE) {
16394 strcat(alarmstr, "BLU/");
16395 }
16396 if (spaninfo->alarms & DAHDI_ALARM_YELLOW) {
16397 strcat(alarmstr, "YEL/");
16398 }
16399 if (spaninfo->alarms & DAHDI_ALARM_RED) {
16400 strcat(alarmstr, "RED/");
16401 }
16402 if (spaninfo->alarms & DAHDI_ALARM_LOOPBACK) {
16403 strcat(alarmstr, "LB/");
16404 }
16405 if (spaninfo->alarms & DAHDI_ALARM_RECOVER) {
16406 strcat(alarmstr, "REC/");
16407 }
16408 if (spaninfo->alarms & DAHDI_ALARM_NOTOPEN) {
16409 strcat(alarmstr, "NOP/");
16410 }
16411 if (!strlen(alarmstr)) {
16412 strcat(alarmstr, "UUU/");
16413 }
16414 if (strlen(alarmstr)) {
16415 /* Strip trailing / */
16416 alarmstr[strlen(alarmstr) - 1] = '\0';
16417 }
16418 } else {
16419 if (spaninfo->numchans) {
16420 strcpy(alarmstr, "OK");
16421 } else {
16422 strcpy(alarmstr, "UNCONFIGURED");
16423 }
16424 }
16425}
16426
16427/* Based on irqmiss.c */
16428static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16429{
16430 #define FORMAT "%4d %-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16431 #define FORMAT2 "%4s %-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16432 int span;
16433 int res;
16434 char alarmstr[50];
16435
16436 int ctl;
16437 struct dahdi_spaninfo s;
16438
16439 switch (cmd) {
16440 case CLI_INIT:
16441 e->command = "dahdi show status";
16442 e->usage =
16443 "Usage: dahdi show status\n"
16444 " Shows a list of DAHDI cards with status\n";
16445 return NULL;
16446 case CLI_GENERATE:
16447 return NULL;
16448 }
16449 ctl = open("/dev/dahdi/ctl", O_RDWR);
16450 if (ctl < 0) {
16451 ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
16452 return CLI_FAILURE;
16453 }
16454 ast_cli(a->fd, FORMAT2, "Span", "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16455
16456 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
16457 s.spanno = span;
16458 res = ioctl(ctl, DAHDI_SPANSTAT, &s);
16459 if (res) {
16460 continue;
16461 }
16462 build_alarm_info(alarmstr, &s);
16463 ast_cli(a->fd, FORMAT, span, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count,
16464 s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
16465 s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
16466 s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
16467 "CAS",
16468 s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
16469 s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
16470 s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
16471 "Unknown",
16472 s.lineconfig & DAHDI_CONFIG_CRC4 ?
16473 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
16474 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
16475 lbostr[s.lbo]
16476 );
16477 }
16478 close(ctl);
16479
16480 return CLI_SUCCESS;
16481#undef FORMAT
16482#undef FORMAT2
16483}
16484
16485static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16486{
16487 int pseudo_fd = -1;
16488 struct dahdi_versioninfo vi;
16489
16490 switch (cmd) {
16491 case CLI_INIT:
16492 e->command = "dahdi show version";
16493 e->usage =
16494 "Usage: dahdi show version\n"
16495 " Shows the DAHDI version in use\n";
16496 return NULL;
16497 case CLI_GENERATE:
16498 return NULL;
16499 }
16500 if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
16501 ast_cli(a->fd, "Failed to open control file to get version.\n");
16502 return CLI_SUCCESS;
16503 }
16504
16505 strcpy(vi.version, "Unknown");
16506 strcpy(vi.echo_canceller, "Unknown");
16507
16508 if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
16509 ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
16510 else
16511 ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
16512
16513 close(pseudo_fd);
16514
16515 return CLI_SUCCESS;
16516}
16517
16518static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16519{
16520 int channel;
16521 float gain;
16522 int tx;
16523 struct dahdi_pvt *tmp = NULL;
16524
16525 switch (cmd) {
16526 case CLI_INIT:
16527 e->command = "dahdi set hwgain {rx|tx}";
16528 e->usage =
16529 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16530 " Sets the hardware gain on a given channel and overrides the\n"
16531 " value provided at module loadtime. Changes take effect\n"
16532 " immediately whether the channel is in use or not.\n"
16533 "\n"
16534 " <rx|tx> which direction do you want to change (relative to our module)\n"
16535 " <chan num> is the channel number relative to the device\n"
16536 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16537 "\n"
16538 " Please note:\n"
16539 " * hwgain is only supportable by hardware with analog ports because\n"
16540 " hwgain works on the analog side of an analog-digital conversion.\n";
16541 return NULL;
16542 case CLI_GENERATE:
16543 return NULL;
16544 }
16545
16546 if (a->argc != 6)
16547 return CLI_SHOWUSAGE;
16548
16549 if (!strcasecmp("rx", a->argv[3]))
16550 tx = 0; /* rx */
16551 else if (!strcasecmp("tx", a->argv[3]))
16552 tx = 1; /* tx */
16553 else
16554 return CLI_SHOWUSAGE;
16555
16556 channel = atoi(a->argv[4]);
16557 gain = atof(a->argv[5]);
16558
16560
16561 for (tmp = iflist; tmp; tmp = tmp->next) {
16562
16563 if (tmp->channel != channel)
16564 continue;
16565
16566 if (tmp->subs[SUB_REAL].dfd == -1)
16567 break;
16568
16569 if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
16570 ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
16572 return CLI_FAILURE;
16573 }
16574 ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
16575 tx ? "tx" : "rx", gain, channel);
16576
16577 if (tx) {
16578 tmp->hwtxgain_enabled = 1;
16579 tmp->hwtxgain = gain;
16580 } else {
16581 tmp->hwrxgain_enabled = 1;
16582 tmp->hwrxgain = gain;
16583 }
16584 break;
16585 }
16586
16588
16589 if (tmp)
16590 return CLI_SUCCESS;
16591
16592 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16593 return CLI_FAILURE;
16594
16595}
16596
16597static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16598{
16599 int channel;
16600 float gain;
16601 int tx;
16602 int res;
16603 struct dahdi_pvt *tmp = NULL;
16604
16605 switch (cmd) {
16606 case CLI_INIT:
16607 e->command = "dahdi set swgain {rx|tx}";
16608 e->usage =
16609 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16610 " Sets the software gain on a given channel and overrides the\n"
16611 " value provided at module loadtime. Changes take effect\n"
16612 " immediately whether the channel is in use or not.\n"
16613 "\n"
16614 " <rx|tx> which direction do you want to change (relative to our module)\n"
16615 " <chan num> is the channel number relative to the device\n"
16616 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16617 return NULL;
16618 case CLI_GENERATE:
16619 return NULL;
16620 }
16621
16622 if (a->argc != 6)
16623 return CLI_SHOWUSAGE;
16624
16625 if (!strcasecmp("rx", a->argv[3]))
16626 tx = 0; /* rx */
16627 else if (!strcasecmp("tx", a->argv[3]))
16628 tx = 1; /* tx */
16629 else
16630 return CLI_SHOWUSAGE;
16631
16632 channel = atoi(a->argv[4]);
16633 gain = atof(a->argv[5]);
16634
16636 for (tmp = iflist; tmp; tmp = tmp->next) {
16637
16638 if (tmp->channel != channel)
16639 continue;
16640
16641 if (tmp->subs[SUB_REAL].dfd == -1)
16642 break;
16643
16644 if (tx)
16645 res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, gain, tmp->txdrc, tmp->law);
16646 else
16647 res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, gain, tmp->rxdrc, tmp->law);
16648
16649 if (res) {
16650 ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
16652 return CLI_FAILURE;
16653 }
16654
16655 ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
16656 tx ? "tx" : "rx", gain, channel);
16657
16658 if (tx) {
16659 tmp->txgain = gain;
16660 } else {
16661 tmp->rxgain = gain;
16662 }
16663 break;
16664 }
16666
16667 if (tmp)
16668 return CLI_SUCCESS;
16669
16670 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16671 return CLI_FAILURE;
16672
16673}
16674
16675static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16676{
16677 int channel;
16678 int on;
16679 struct dahdi_pvt *dahdi_chan = NULL;
16680
16681 switch (cmd) {
16682 case CLI_INIT:
16683 e->command = "dahdi set dnd";
16684 e->usage =
16685 "Usage: dahdi set dnd <chan#> <on|off>\n"
16686 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16687 " Changes take effect immediately.\n"
16688 " <chan num> is the channel number\n"
16689 " <on|off> Enable or disable DND mode?\n"
16690 ;
16691 return NULL;
16692 case CLI_GENERATE:
16693 return NULL;
16694 }
16695
16696 if (a->argc != 5)
16697 return CLI_SHOWUSAGE;
16698
16699 if ((channel = atoi(a->argv[3])) <= 0) {
16700 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16701 return CLI_SHOWUSAGE;
16702 }
16703
16704 if (ast_true(a->argv[4]))
16705 on = 1;
16706 else if (ast_false(a->argv[4]))
16707 on = 0;
16708 else {
16709 ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
16710 return CLI_SHOWUSAGE;
16711 }
16712
16714 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16715 if (dahdi_chan->channel != channel)
16716 continue;
16717
16718 /* Found the channel. Actually set it */
16719 dahdi_dnd(dahdi_chan, on);
16720 break;
16721 }
16723
16724 if (!dahdi_chan) {
16725 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16726 return CLI_FAILURE;
16727 }
16728
16729 return CLI_SUCCESS;
16730}
16731
16732static char *dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16733{
16734 int channel;
16735 int on;
16736 int override = 1;
16737 struct dahdi_pvt *dahdi_chan = NULL;
16738
16739 switch (cmd) {
16740 case CLI_INIT:
16741 e->command = "dahdi set mwi";
16742 e->usage =
16743 "Usage: dahdi set mwi <chan#> <on|off|reset>\n"
16744 " Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
16745 " This may be used regardless of whether the channel is assigned any mailboxes.\n"
16746 " When active, this setting will override the voicemail status to set MWI.\n"
16747 " Once cleared, the voicemail status will resume control of MWI.\n"
16748 " Changes are queued for when the channel is idle and persist until cleared.\n"
16749 " <chan num> is the channel number\n"
16750 " <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
16751 ;
16752 return NULL;
16753 case CLI_GENERATE:
16754 return NULL;
16755 }
16756
16757 if (a->argc != 5)
16758 return CLI_SHOWUSAGE;
16759
16760 if ((channel = atoi(a->argv[3])) <= 0) {
16761 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16762 return CLI_SHOWUSAGE;
16763 }
16764
16765 if (ast_true(a->argv[4])) {
16766 on = 1;
16767 } else if (ast_false(a->argv[4])) {
16768 on = 0;
16769 } else if (!strcmp(a->argv[4], "reset")) {
16770 override = 0;
16771 } else {
16772 ast_cli(a->fd, "Expected 'on' or 'off' or 'reset', got '%s'\n", a->argv[4]);
16773 return CLI_SHOWUSAGE;
16774 }
16775
16777 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16778 if (dahdi_chan->channel != channel)
16779 continue;
16780
16781 /* Found the channel. Actually set it */
16782 if (override) {
16783 dahdi_chan->mwioverride_disposition = on;
16784 ast_cli(a->fd, "MWI '%s' queued for channel %d\n", on ? "enable" : "disable", channel);
16785 }
16786 dahdi_chan->mwioverride_active = override;
16787 /* The do_monitor thread will take care of actually sending the MWI
16788 * at an appropriate time for the channel. */
16789 break;
16790 }
16792
16793 if (!dahdi_chan) {
16794 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16795 return CLI_FAILURE;
16796 }
16797
16798 return CLI_SUCCESS;
16799}
16800
16801static struct ast_cli_entry dahdi_cli[] = {
16803 AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
16804 AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
16805 AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
16806 AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
16807 AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
16808 AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
16809 AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
16810 AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
16811 AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
16812 AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16813 AST_CLI_DEFINE(dahdi_set_mwi, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
16814};
16815
16816#define TRANSFER 0
16817#define HANGUP 1
16818
16819static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
16820{
16821 if (p) {
16822 switch (mode) {
16823 case TRANSFER:
16824 p->fake_event = DAHDI_EVENT_WINKFLASH;
16825 break;
16826 case HANGUP:
16827 p->fake_event = DAHDI_EVENT_ONHOOK;
16828 break;
16829 default:
16830 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));
16831 }
16832 }
16833 return 0;
16834}
16835static struct dahdi_pvt *find_channel(int channel)
16836{
16837 struct dahdi_pvt *p;
16838
16840 for (p = iflist; p; p = p->next) {
16841 if (p->channel == channel) {
16842 break;
16843 }
16844 }
16846 return p;
16847}
16848
16849/*!
16850 * \internal
16851 * \brief Get private struct using given numeric channel string.
16852 *
16853 * \param channel Numeric channel number string get private struct.
16854 *
16855 * \retval pvt on success.
16856 * \retval NULL on error.
16857 */
16858static struct dahdi_pvt *find_channel_from_str(const char *channel)
16859{
16860 int chan_num;
16861
16862 if (sscanf(channel, "%30d", &chan_num) != 1) {
16863 /* Not numeric string. */
16864 return NULL;
16865 }
16866
16867 return find_channel(chan_num);
16868}
16869
16870static int action_dahdidndon(struct mansession *s, const struct message *m)
16871{
16872 struct dahdi_pvt *p;
16873 const char *channel = astman_get_header(m, "DAHDIChannel");
16874
16875 if (ast_strlen_zero(channel)) {
16876 astman_send_error(s, m, "No channel specified");
16877 return 0;
16878 }
16880 if (!p) {
16881 astman_send_error(s, m, "No such channel");
16882 return 0;
16883 }
16884 dahdi_dnd(p, 1);
16885 astman_send_ack(s, m, "DND Enabled");
16886 return 0;
16887}
16888
16889static int action_dahdidndoff(struct mansession *s, const struct message *m)
16890{
16891 struct dahdi_pvt *p;
16892 const char *channel = astman_get_header(m, "DAHDIChannel");
16893
16894 if (ast_strlen_zero(channel)) {
16895 astman_send_error(s, m, "No channel specified");
16896 return 0;
16897 }
16899 if (!p) {
16900 astman_send_error(s, m, "No such channel");
16901 return 0;
16902 }
16903 dahdi_dnd(p, 0);
16904 astman_send_ack(s, m, "DND Disabled");
16905 return 0;
16906}
16907
16908static int action_transfer(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 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
16923 astman_send_error(s, m, "Channel signaling is not analog");
16924 return 0;
16925 }
16927 astman_send_ack(s, m, "DAHDITransfer");
16928 return 0;
16929}
16930
16931static int action_transferhangup(struct mansession *s, const struct message *m)
16932{
16933 struct dahdi_pvt *p;
16934 const char *channel = astman_get_header(m, "DAHDIChannel");
16935
16936 if (ast_strlen_zero(channel)) {
16937 astman_send_error(s, m, "No channel specified");
16938 return 0;
16939 }
16941 if (!p) {
16942 astman_send_error(s, m, "No such channel");
16943 return 0;
16944 }
16945 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
16946 astman_send_error(s, m, "Channel signaling is not analog");
16947 return 0;
16948 }
16950 astman_send_ack(s, m, "DAHDIHangup");
16951 return 0;
16952}
16953
16954static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
16955{
16956 struct dahdi_pvt *p;
16957 const char *channel = astman_get_header(m, "DAHDIChannel");
16958 const char *number = astman_get_header(m, "Number");
16959 int i;
16960
16961 if (ast_strlen_zero(channel)) {
16962 astman_send_error(s, m, "No channel specified");
16963 return 0;
16964 }
16965 if (ast_strlen_zero(number)) {
16966 astman_send_error(s, m, "No number specified");
16967 return 0;
16968 }
16970 if (!p) {
16971 astman_send_error(s, m, "No such channel");
16972 return 0;
16973 }
16974 if (!p->owner) {
16975 astman_send_error(s, m, "Channel does not have it's owner");
16976 return 0;
16977 }
16978 for (i = 0; i < strlen(number); i++) {
16979 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = number[i] };
16980 dahdi_queue_frame(p, &f);
16981 }
16982 astman_send_ack(s, m, "DAHDIDialOffhook");
16983 return 0;
16984}
16985
16986static int action_dahdishowchannels(struct mansession *s, const struct message *m)
16987{
16988 struct dahdi_pvt *tmp = NULL;
16989 const char *id = astman_get_header(m, "ActionID");
16990 const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
16991 char idText[256];
16992 int channels = 0;
16993 int dahdichanquery;
16994
16995 if (!dahdichannel || sscanf(dahdichannel, "%30d", &dahdichanquery) != 1) {
16996 /* Not numeric string. */
16997 dahdichanquery = -1;
16998 }
16999
17000 idText[0] = '\0';
17001 if (!ast_strlen_zero(id)) {
17002 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17003 }
17004
17005 astman_send_listack(s, m, "DAHDI channel status will follow", "start");
17006
17008
17009 for (tmp = iflist; tmp; tmp = tmp->next) {
17010 if (tmp->channel > 0) {
17011 int alm;
17012
17013 /* If a specific channel is queried for, only deliver status for that channel */
17014 if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
17015 continue;
17016
17017 alm = get_alarms(tmp);
17018 channels++;
17019 if (tmp->owner) {
17020 /* Add data if we have a current call */
17021 astman_append(s,
17022 "Event: DAHDIShowChannels\r\n"
17023 "DAHDIChannel: %d\r\n"
17024 "Channel: %s\r\n"
17025 "Uniqueid: %s\r\n"
17026 "AccountCode: %s\r\n"
17027 "Signalling: %s\r\n"
17028 "SignallingCode: %d\r\n"
17029 "Context: %s\r\n"
17030 "DND: %s\r\n"
17031 "Alarm: %s\r\n"
17032 "Description: %s\r\n"
17033 "%s"
17034 "\r\n",
17035 tmp->channel,
17036 ast_channel_name(tmp->owner),
17039 sig2str(tmp->sig),
17040 tmp->sig,
17041 tmp->context,
17042 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17043 alarm2str(alm),
17044 tmp->description, idText);
17045 } else {
17046 astman_append(s,
17047 "Event: DAHDIShowChannels\r\n"
17048 "DAHDIChannel: %d\r\n"
17049 "Signalling: %s\r\n"
17050 "SignallingCode: %d\r\n"
17051 "Context: %s\r\n"
17052 "DND: %s\r\n"
17053 "Alarm: %s\r\n"
17054 "Description: %s\r\n"
17055 "%s"
17056 "\r\n",
17057 tmp->channel, sig2str(tmp->sig), tmp->sig,
17058 tmp->context,
17059 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17060 alarm2str(alm),
17061 tmp->description, idText);
17062 }
17063 }
17064 }
17065
17067
17068 astman_send_list_complete_start(s, m, "DAHDIShowChannelsComplete", channels);
17069 astman_append(s, "Items: %d\r\n", channels);
17071 return 0;
17072}
17073
17074static int action_dahdishowstatus(struct mansession *s, const struct message *m)
17075{
17076 const char *id = astman_get_header(m, "ActionID");
17077 int span;
17078 int res;
17079 char alarmstr[50];
17080 int ctl;
17081 char idText[256];
17082 int numspans = 0;
17083 struct dahdi_spaninfo spaninfo;
17084
17085 ctl = open("/dev/dahdi/ctl", O_RDWR);
17086 if (ctl < 0) {
17087 astman_send_error(s, m, "No DAHDI detected");
17088 return 0;
17089 }
17090
17091 idText[0] = '\0';
17092 if (!ast_strlen_zero(id)) {
17093 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17094 }
17095 astman_send_listack(s, m, "DAHDI span statuses will follow", "start");
17096
17097 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
17098 spaninfo.spanno = span;
17099 res = ioctl(ctl, DAHDI_SPANSTAT, &spaninfo);
17100 if (res) {
17101 continue;
17102 }
17103 numspans++;
17104 build_alarm_info(alarmstr, &spaninfo);
17105 astman_append(s,
17106 "Event: DAHDIShowStatus\r\n"
17107 "Span: %d\r\n"
17108 "Description: %s\r\n"
17109 "Alarms: %s\r\n"
17110 "IRQ: %d\r\n"
17111 "bpviol: %d\r\n"
17112 "CRC: %d\r\n"
17113 "Framing: %s\r\n"
17114 "Coding: %s\r\n"
17115 "Options: %s\r\n"
17116 "LBO: %s\r\n"
17117 "%s"
17118 "\r\n",
17119 span, spaninfo.desc, alarmstr, spaninfo.irqmisses, spaninfo.bpvcount, spaninfo.crc4count,
17120 spaninfo.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
17121 spaninfo.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
17122 spaninfo.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
17123 "CAS",
17124 spaninfo.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
17125 spaninfo.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
17126 spaninfo.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
17127 "Unk",
17128 spaninfo.lineconfig & DAHDI_CONFIG_CRC4 ?
17129 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
17130 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
17131 lbostr[spaninfo.lbo],
17132 idText);
17133 }
17134 close(ctl);
17135
17136 astman_send_list_complete_start(s, m, "DAHDIShowStatusComplete", numspans);
17137 astman_append(s, "Items: %d\r\n", numspans);
17139 return 0;
17140}
17141
17142#if defined(HAVE_PRI)
17143static int action_prishowspans(struct mansession *s, const struct message *m)
17144{
17145 int count;
17146 int idx;
17147 int span_query;
17148 struct dahdi_pri *dspan;
17149 const char *id = astman_get_header(m, "ActionID");
17150 const char *span_str = astman_get_header(m, "Span");
17151 char action_id[256];
17152 const char *show_cmd = "PRIShowSpans";
17153
17154 /* NOTE: Asking for span 0 gets all spans. */
17155 if (!ast_strlen_zero(span_str)) {
17156 span_query = atoi(span_str);
17157 } else {
17158 span_query = 0;
17159 }
17160
17161 if (!ast_strlen_zero(id)) {
17162 snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
17163 } else {
17164 action_id[0] = '\0';
17165 }
17166
17167 astman_send_listack(s, m, "Span status will follow", "start");
17168
17169 count = 0;
17170 for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
17171 dspan = &pris[idx];
17172
17173 /* If a specific span is asked for, only deliver status for that span. */
17174 if (0 < span_query && dspan->pri.span != span_query) {
17175 continue;
17176 }
17177
17178 if (dspan->pri.pri) {
17179 count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
17180 action_id);
17181 }
17182 }
17183
17184 astman_send_list_complete_start(s, m, "PRIShowSpansComplete", count);
17185 astman_append(s, "Items: %d\r\n", count);
17187 return 0;
17188}
17189#endif /* defined(HAVE_PRI) */
17190
17191#if defined(HAVE_SS7)
17192static int linkset_addsigchan(int sigchan)
17193{
17194 struct dahdi_ss7 *link;
17195 int res;
17196 int curfd;
17197 struct dahdi_params params;
17198 struct dahdi_bufferinfo bi;
17199 struct dahdi_spaninfo si;
17200
17201 if (sigchan < 0) {
17202 ast_log(LOG_ERROR, "Invalid sigchan!\n");
17203 return -1;
17204 }
17205 if (cur_ss7type < 0) {
17206 ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
17207 return -1;
17208 }
17209 if (cur_pointcode < 0) {
17210 ast_log(LOG_ERROR, "Unspecified pointcode!\n");
17211 return -1;
17212 }
17213 if (cur_adjpointcode < 0) {
17214 ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
17215 return -1;
17216 }
17217 if (cur_defaultdpc < 0) {
17218 ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
17219 return -1;
17220 }
17221 if (cur_networkindicator < 0) {
17222 ast_log(LOG_ERROR, "Invalid networkindicator!\n");
17223 return -1;
17224 }
17225 link = ss7_resolve_linkset(cur_linkset);
17226 if (!link) {
17227 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
17228 return -1;
17229 }
17230 if (link->ss7.numsigchans >= SIG_SS7_NUM_DCHANS) {
17231 ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
17232 return -1;
17233 }
17234
17235 curfd = link->ss7.numsigchans;
17236
17237 /* Open signaling channel */
17238 link->ss7.fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
17239 if (link->ss7.fds[curfd] < 0) {
17240 ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan,
17241 strerror(errno));
17242 return -1;
17243 }
17244 if (ioctl(link->ss7.fds[curfd], DAHDI_SPECIFY, &sigchan) == -1) {
17245 dahdi_close_ss7_fd(link, curfd);
17246 ast_log(LOG_ERROR, "Unable to specify SS7 sigchan %d (%s)\n", sigchan,
17247 strerror(errno));
17248 return -1;
17249 }
17250
17251 /* Get signaling channel parameters */
17252 memset(&params, 0, sizeof(params));
17253 res = ioctl(link->ss7.fds[curfd], DAHDI_GET_PARAMS, &params);
17254 if (res) {
17255 dahdi_close_ss7_fd(link, curfd);
17256 ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan,
17257 strerror(errno));
17258 return -1;
17259 }
17260 if (params.sigtype != DAHDI_SIG_HDLCFCS
17261 && params.sigtype != DAHDI_SIG_HARDHDLC
17262 && params.sigtype != DAHDI_SIG_MTP2) {
17263 dahdi_close_ss7_fd(link, curfd);
17264 ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
17265 return -1;
17266 }
17267
17268 /* Set signaling channel buffer policy. */
17269 memset(&bi, 0, sizeof(bi));
17270 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
17271 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
17272 bi.numbufs = 32;
17273 bi.bufsize = 512;
17274 if (ioctl(link->ss7.fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
17275 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n",
17276 sigchan, strerror(errno));
17277 dahdi_close_ss7_fd(link, curfd);
17278 return -1;
17279 }
17280
17281 /* Get current signaling channel alarm status. */
17282 memset(&si, 0, sizeof(si));
17283 res = ioctl(link->ss7.fds[curfd], DAHDI_SPANSTAT, &si);
17284 if (res) {
17285 dahdi_close_ss7_fd(link, curfd);
17286 ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan,
17287 strerror(errno));
17288 }
17289
17290 res = sig_ss7_add_sigchan(&link->ss7, curfd, cur_ss7type,
17291 (params.sigtype == DAHDI_SIG_MTP2)
17292 ? SS7_TRANSPORT_DAHDIMTP2
17293 : SS7_TRANSPORT_DAHDIDCHAN,
17294 si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
17295 if (res) {
17296 dahdi_close_ss7_fd(link, curfd);
17297 return -1;
17298 }
17299
17300 ++link->ss7.numsigchans;
17301
17302 return 0;
17303}
17304#endif /* defined(HAVE_SS7) */
17305
17306#if defined(HAVE_SS7)
17307static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17308{
17309 int span;
17310 switch (cmd) {
17311 case CLI_INIT:
17312 e->command = "ss7 set debug {on|off} linkset";
17313 e->usage =
17314 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
17315 " Enables debugging on a given SS7 linkset\n";
17316 return NULL;
17317 case CLI_GENERATE:
17318 return NULL;
17319 }
17320
17321 if (a->argc < 6) {
17322 return CLI_SHOWUSAGE;
17323 }
17324
17325 span = atoi(a->argv[5]);
17326 if ((span < 1) || (span > NUM_SPANS)) {
17327 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
17328 return CLI_SUCCESS;
17329 }
17330 if (!linksets[span-1].ss7.ss7) {
17331 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
17332 } else {
17333 if (!strcasecmp(a->argv[3], "on")) {
17334 linksets[span - 1].ss7.debug = 1;
17335 ss7_set_debug(linksets[span-1].ss7.ss7, SIG_SS7_DEBUG);
17336 ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
17337 } else {
17338 linksets[span - 1].ss7.debug = 0;
17339 ss7_set_debug(linksets[span-1].ss7.ss7, 0);
17340 ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
17341 }
17342 }
17343
17344 return CLI_SUCCESS;
17345}
17346#endif /* defined(HAVE_SS7) */
17347
17348#if defined(HAVE_SS7)
17349static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17350{
17351 int linkset, cic;
17352 int blocked, i;
17353 int do_block = 0;
17354 unsigned int dpc;
17355
17356 switch (cmd) {
17357 case CLI_INIT:
17358 e->command = "ss7 {block|unblock} cic";
17359 e->usage =
17360 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17361 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17362 return NULL;
17363 case CLI_GENERATE:
17364 return NULL;
17365 }
17366
17367 if (a->argc == 6) {
17368 linkset = atoi(a->argv[3]);
17369 } else {
17370 return CLI_SHOWUSAGE;
17371 }
17372
17373 if (!strcasecmp(a->argv[1], "block")) {
17374 do_block = 1;
17375 } else if (strcasecmp(a->argv[1], "unblock")) {
17376 return CLI_SHOWUSAGE;
17377 }
17378
17379 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17380 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17381 return CLI_SUCCESS;
17382 }
17383
17384 if (!linksets[linkset-1].ss7.ss7) {
17385 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17386 return CLI_SUCCESS;
17387 }
17388
17389 cic = atoi(a->argv[5]);
17390 if (cic < 1) {
17391 ast_cli(a->fd, "Invalid CIC specified!\n");
17392 return CLI_SUCCESS;
17393 }
17394
17395 dpc = atoi(a->argv[4]);
17396 if (dpc < 1) {
17397 ast_cli(a->fd, "Invalid DPC specified!\n");
17398 return CLI_SUCCESS;
17399 }
17400
17401 for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
17402 if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
17403 blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
17404 if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
17405 if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
17406 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17407 } else {
17408 ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
17409 }
17410 } else if (!do_block && blocked) {
17411 ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
17412 } else {
17413 ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
17414 }
17415 return CLI_SUCCESS;
17416 }
17417 }
17418
17419 ast_cli(a->fd, "Invalid CIC specified!\n");
17420 return CLI_SUCCESS;
17421}
17422#endif /* defined(HAVE_SS7) */
17423
17424#if defined(HAVE_SS7)
17425static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17426{
17427 int linkset, i;
17428 enum {
17429 DO_BLOCK,
17430 DO_UNBLOCK,
17431 DO_RESET,
17432 } do_what;
17433
17434 switch (cmd) {
17435 case CLI_INIT:
17436 e->command = "ss7 {reset|block|unblock} linkset";
17437 e->usage =
17438 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17439 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17440 return NULL;
17441 case CLI_GENERATE:
17442 return NULL;
17443 }
17444
17445 if (a->argc == 4) {
17446 linkset = atoi(a->argv[3]);
17447 } else {
17448 return CLI_SHOWUSAGE;
17449 }
17450
17451 if (!strcasecmp(a->argv[1], "block")) {
17452 do_what = DO_BLOCK;
17453 } else if (!strcasecmp(a->argv[1], "unblock")) {
17454 do_what = DO_UNBLOCK;
17455 } else if (!strcasecmp(a->argv[1], "reset")) {
17456 do_what = DO_RESET;
17457 } else {
17458 return CLI_SHOWUSAGE;
17459 }
17460
17461 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17462 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17463 return CLI_SUCCESS;
17464 }
17465
17466 if (!linksets[linkset - 1].ss7.ss7) {
17467 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17468 return CLI_SUCCESS;
17469 }
17470
17471 for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
17472 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17473 if (linksets[linkset - 1].ss7.pvts[i]) {
17474 switch (do_what) {
17475 case DO_BLOCK:
17476 case DO_UNBLOCK:
17477 if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
17478 ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
17479 (do_what == DO_BLOCK) ? "blocking" : "unblocking",
17480 linksets[linkset - 1].ss7.pvts[i]->cic);
17481 }
17482 break;
17483 case DO_RESET:
17484 if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
17485 linksets[linkset - 1].ss7.pvts[i]->cic,
17486 linksets[linkset - 1].ss7.pvts[i]->dpc)) {
17487 ast_cli(a->fd, "Sent reset request on CIC %d\n",
17488 linksets[linkset - 1].ss7.pvts[i]->cic);
17489 }
17490 break;
17491 }
17492 }
17493 }
17494
17495 return CLI_SUCCESS;
17496}
17497#endif /* defined(HAVE_SS7) */
17498
17499#if defined(HAVE_SS7)
17500static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17501{
17502 int linkset, cic, range, chanpos;
17503 int i, dpc, orient = 0;
17504 int do_block = 0;
17505 unsigned char state[255];
17506
17507 switch (cmd) {
17508 case CLI_INIT:
17509 e->command = "ss7 {block|unblock} group";
17510 e->usage =
17511 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17512 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17513 return NULL;
17514 case CLI_GENERATE:
17515 return NULL;
17516 }
17517
17518 if (a->argc == 7 || a->argc == 8) {
17519 linkset = atoi(a->argv[3]);
17520 } else {
17521 return CLI_SHOWUSAGE;
17522 }
17523
17524 if (!strcasecmp(a->argv[1], "block")) {
17525 do_block = 1;
17526 } else if (strcasecmp(a->argv[1], "unblock")) {
17527 return CLI_SHOWUSAGE;
17528 }
17529
17530 if (a->argc == 8) {
17531 if (!strcasecmp(a->argv[7], "H")) {
17532 orient = 1;
17533 } else {
17534 return CLI_SHOWUSAGE;
17535 }
17536 }
17537
17538 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17539 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17540 return CLI_SUCCESS;
17541 }
17542
17543 if (!linksets[linkset-1].ss7.ss7) {
17544 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17545 return CLI_SUCCESS;
17546 }
17547
17548 cic = atoi(a->argv[5]);
17549 if (cic < 1) {
17550 ast_cli(a->fd, "Invalid CIC specified!\n");
17551 return CLI_SUCCESS;
17552 }
17553
17554 range = atoi(a->argv[6]);
17555 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17556 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17557 ast_cli(a->fd, "Invalid range specified!\n");
17558 return CLI_SUCCESS;
17559 }
17560
17561 dpc = atoi(a->argv[4]);
17562 if (dpc < 1) {
17563 ast_cli(a->fd, "Invalid DPC specified!\n");
17564 return CLI_SUCCESS;
17565 }
17566
17567 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17568 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17569 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17570 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17571 return CLI_SHOWUSAGE;
17572 }
17573
17574 memset(state, 0, sizeof(state));
17575 for (i = 0; i <= range; ++i) {
17576 state[i] = 1;
17577 }
17578
17579 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17580 chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
17581 if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
17582 ast_cli(a->fd, "Unable allocate new ss7call\n");
17583 } else {
17584 ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17585 orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
17586 }
17587
17588 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17589
17590 /* Break poll on the linkset so it sends our messages */
17591 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17592 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17593 }
17594 return CLI_SUCCESS;
17595}
17596#endif /* defined(HAVE_SS7) */
17597
17598#if defined(HAVE_SS7)
17599static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17600{
17601 int linkset, cic, range;
17602 unsigned int dpc;
17603
17604 switch (cmd) {
17605 case CLI_INIT:
17606 e->command = "ss7 reset group";
17607 e->usage =
17608 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17609 " Send a GRS for the given CIC range on the specified linkset\n";
17610 return NULL;
17611 case CLI_GENERATE:
17612 return NULL;
17613 }
17614
17615 if (a->argc == 7) {
17616 linkset = atoi(a->argv[3]);
17617 } else {
17618 return CLI_SHOWUSAGE;
17619 }
17620
17621 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17622 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17623 return CLI_SUCCESS;
17624 }
17625
17626 if (!linksets[linkset-1].ss7.ss7) {
17627 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17628 return CLI_SUCCESS;
17629 }
17630
17631 cic = atoi(a->argv[5]);
17632
17633 if (cic < 1) {
17634 ast_cli(a->fd, "Invalid CIC specified!\n");
17635 return CLI_SUCCESS;
17636 }
17637
17638 range = atoi(a->argv[6]);
17639 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17640 ast_cli(a->fd, "Invalid range specified!\n");
17641 return CLI_SUCCESS;
17642 }
17643
17644 dpc = atoi(a->argv[4]);
17645 if (dpc < 1) {
17646 ast_cli(a->fd, "Invalid DPC specified!\n");
17647 return CLI_SUCCESS;
17648 }
17649
17650 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17651 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17652 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17653 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17654 return CLI_SHOWUSAGE;
17655 }
17656
17657 if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
17658 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17659 } else {
17660 ast_cli(a->fd, "GRS sent ... \n");
17661 }
17662
17663 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17664
17665 /* Break poll on the linkset so it sends our messages */
17666 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17667 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17668 }
17669 return CLI_SUCCESS;
17670}
17671#endif /* defined(HAVE_SS7) */
17672
17673#if defined(HAVE_SS7)
17674static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17675{
17676 int linkset;
17677
17678 switch (cmd) {
17679 case CLI_INIT:
17680 e->command = "ss7 show calls";
17681 e->usage =
17682 "Usage: ss7 show calls <linkset>\n"
17683 " Show SS7 calls on the specified linkset\n";
17684 return NULL;
17685 case CLI_GENERATE:
17686 return NULL;
17687 }
17688
17689 if (a->argc == 4) {
17690 linkset = atoi(a->argv[3]);
17691 } else {
17692 return CLI_SHOWUSAGE;
17693 }
17694
17695 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17696 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17697 return CLI_SUCCESS;
17698 }
17699
17700 if (!linksets[linkset-1].ss7.ss7) {
17701 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17702 return CLI_SUCCESS;
17703 }
17704
17705 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17706 isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
17707 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17708
17709 return CLI_SUCCESS;
17710}
17711#endif /* defined(HAVE_SS7) */
17712
17713#if defined(HAVE_SS7)
17714static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17715{
17716 int linkset, cic, res;
17717 unsigned int dpc;
17718
17719 switch (cmd) {
17720 case CLI_INIT:
17721 e->command = "ss7 reset cic";
17722 e->usage =
17723 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17724 " Send a RSC for the given CIC on the specified linkset\n";
17725 return NULL;
17726 case CLI_GENERATE:
17727 return NULL;
17728 }
17729
17730 if (a->argc == 6) {
17731 linkset = atoi(a->argv[3]);
17732 } else {
17733 return CLI_SHOWUSAGE;
17734 }
17735
17736 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17737 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17738 return CLI_SUCCESS;
17739 }
17740
17741 if (!linksets[linkset-1].ss7.ss7) {
17742 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17743 return CLI_SUCCESS;
17744 }
17745
17746 cic = atoi(a->argv[5]);
17747
17748 if (cic < 1) {
17749 ast_cli(a->fd, "Invalid CIC specified!\n");
17750 return CLI_SUCCESS;
17751 }
17752
17753 dpc = atoi(a->argv[4]);
17754 if (dpc < 1) {
17755 ast_cli(a->fd, "Invalid DPC specified!\n");
17756 return CLI_SUCCESS;
17757 }
17758
17759 res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
17760
17761 ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
17762
17763 return CLI_SUCCESS;
17764}
17765#endif /* defined(HAVE_SS7) */
17766
17767#if defined(HAVE_SS7)
17768static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17769{
17770 int linkset;
17771 unsigned int slc;
17772 unsigned int arg = 0;
17773 const char *res;
17774
17775 switch (cmd) {
17776 case CLI_INIT:
17777 e->command = "ss7 mtp3";
17778 e->usage =
17779 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
17780 " Send a NET MNG message\n"
17781 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
17782 return NULL;
17783 case CLI_GENERATE:
17784 return NULL;
17785 }
17786
17787 if (a->argc < 5) {
17788 return CLI_SHOWUSAGE;
17789 }
17790
17791 linkset = atoi(a->argv[2]);
17792 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17793 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
17794 return CLI_SUCCESS;
17795 }
17796 if (!linksets[linkset-1].ss7.ss7) {
17797 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17798 return CLI_SUCCESS;
17799 }
17800
17801 slc = atoi(a->argv[3]);
17802
17803 if (a->argc == 6) {
17804 arg = atoi(a->argv[5]);
17805 }
17806
17807 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17808 res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
17809 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17810
17811 /* Break poll on the linkset so it sends our messages */
17812 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17813 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17814 }
17815
17816 ast_cli(a->fd, "%s", res);
17817
17818 return CLI_SUCCESS;
17819}
17820#endif /* defined(HAVE_SS7) */
17821
17822#if defined(HAVE_SS7)
17823static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17824{
17825 int linkset;
17826 unsigned int slc = 0;
17827
17828 switch (cmd) {
17829 case CLI_INIT:
17830 e->command = "ss7 restart mtp3";
17831 e->usage =
17832 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
17833 " Restart link\n";
17834 return NULL;
17835 case CLI_GENERATE:
17836 return NULL;
17837 }
17838
17839 if (a->argc < 5) {
17840 return CLI_SHOWUSAGE;
17841 }
17842
17843 linkset = atoi(a->argv[3]);
17844 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17845 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
17846 return CLI_SUCCESS;
17847 }
17848 if (!linksets[linkset-1].ss7.ss7) {
17849 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17850 return CLI_SUCCESS;
17851 }
17852
17853 slc = atoi(a->argv[4]);
17854
17855 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17856 mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
17857 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17858
17859 /* Break poll on the linkset so it sends our messages */
17860 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17861 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17862 }
17863
17864 return CLI_SUCCESS;
17865}
17866#endif /* defined(HAVE_SS7) */
17867
17868#if defined(HAVE_SS7)
17869static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17870{
17871 int linkset;
17872 struct sig_ss7_linkset *ss7;
17873 switch (cmd) {
17874 case CLI_INIT:
17875 e->command = "ss7 show linkset";
17876 e->usage =
17877 "Usage: ss7 show linkset <span>\n"
17878 " Shows the status of an SS7 linkset.\n";
17879 return NULL;
17880 case CLI_GENERATE:
17881 return NULL;
17882 }
17883
17884 if (a->argc < 4) {
17885 return CLI_SHOWUSAGE;
17886 }
17887
17888 linkset = atoi(a->argv[3]);
17889 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17890 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17891 return CLI_SUCCESS;
17892 }
17893 ss7 = &linksets[linkset - 1].ss7;
17894 if (!ss7->ss7) {
17895 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17896 return CLI_SUCCESS;
17897 }
17898
17899 ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
17900 ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
17901 ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
17902 ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
17903 ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
17904 ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
17905 ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
17906 ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
17907 ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
17908 ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
17909
17910 return CLI_SUCCESS;
17911}
17912#endif /* defined(HAVE_SS7) */
17913
17914#if defined(HAVE_SS7)
17915static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17916{
17917 int linkset;
17918
17919 switch (cmd) {
17920 case CLI_INIT:
17921 e->command = "ss7 show channels";
17922 e->usage =
17923 "Usage: ss7 show channels\n"
17924 " Displays SS7 channel information at a glance.\n";
17925 return NULL;
17926 case CLI_GENERATE:
17927 return NULL;
17928 }
17929
17930 if (a->argc != 3) {
17931 return CLI_SHOWUSAGE;
17932 }
17933
17935 for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
17936 if (linksets[linkset].ss7.ss7) {
17937 sig_ss7_cli_show_channels(a->fd, &linksets[linkset].ss7);
17938 }
17939 }
17940 return CLI_SUCCESS;
17941}
17942#endif /* defined(HAVE_SS7) */
17943
17944#if defined(HAVE_SS7)
17945static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17946{
17947#define FORMAT "%5s %5s %6s %12s %-12s\n"
17948#define FORMAT2 "%5i %5i %6i %12s %-12s\n"
17949 int i, linkset, dpc = 0;
17950 struct sig_ss7_linkset *ss7;
17951 char *state;
17952 char blocking[12];
17953
17954 switch (cmd) {
17955 case CLI_INIT:
17956 e->command = "ss7 show cics";
17957 e->usage =
17958 "Usage: ss7 show cics <linkset> [dpc]\n"
17959 " Shows the cics of an SS7 linkset.\n";
17960 return NULL;
17961 case CLI_GENERATE:
17962 return NULL;
17963 }
17964
17965 if (a->argc < 4 || a->argc > 5) {
17966 return CLI_SHOWUSAGE;
17967 }
17968
17969 linkset = atoi(a->argv[3]);
17970
17971 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17972 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17973 return CLI_SUCCESS;
17974 }
17975
17976 if (!linksets[linkset-1].ss7.ss7) {
17977 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17978 return CLI_SUCCESS;
17979 }
17980 ss7 = &linksets[linkset-1].ss7;
17981
17982 if (a->argc == 5) {
17983 dpc = atoi(a->argv[4]);
17984 if (dpc < 1) {
17985 ast_cli(a->fd, "Invalid DPC specified!\n");
17986 return CLI_SUCCESS;
17987 }
17988 }
17989
17990 ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
17991
17992 for (i = 0; i < ss7->numchans; i++) {
17993 if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
17994 struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
17995
17996 if (ss7->pvts[i]->owner) {
17997 state = "Used";
17998 } else if (ss7->pvts[i]->ss7call) {
17999 state = "Pending";
18000 } else if (!p->inservice) {
18001 state = "NotInServ";
18002 } else {
18003 state = "Idle";
18004 }
18005
18006 if (p->locallyblocked) {
18007 strcpy(blocking, "L:");
18009 strcat(blocking, "M");
18010 } else {
18011 strcat(blocking, " ");
18012 }
18013
18015 strcat(blocking, "H");
18016 } else {
18017 strcat(blocking, " ");
18018 }
18019 } else {
18020 strcpy(blocking, " ");
18021 }
18022
18023 if (p->remotelyblocked) {
18024 strcat(blocking, " R:");
18026 strcat(blocking, "M");
18027 } else {
18028 strcat(blocking, " ");
18029 }
18030
18032 strcat(blocking, "H");
18033 } else {
18034 strcat(blocking, " ");
18035 }
18036 }
18037
18038 ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
18039 }
18040 }
18041
18042 return CLI_SUCCESS;
18043#undef FORMAT
18044#undef FORMAT2
18045}
18046#endif /* defined(HAVE_SS7) */
18047
18048#if defined(HAVE_SS7)
18049static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18050{
18051 switch (cmd) {
18052 case CLI_INIT:
18053 e->command = "ss7 show version";
18054 e->usage =
18055 "Usage: ss7 show version\n"
18056 " Show the libss7 version\n";
18057 return NULL;
18058 case CLI_GENERATE:
18059 return NULL;
18060 }
18061
18062 ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
18063
18064 return CLI_SUCCESS;
18065}
18066#endif /* defined(HAVE_SS7) */
18067
18068#if defined(HAVE_SS7)
18069static struct ast_cli_entry dahdi_ss7_cli[] = {
18070 AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
18071 AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
18072 AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
18073 AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
18074 AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
18075 AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
18076 AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
18077 AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
18078 AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
18079 AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
18080 AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
18081 AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
18082 AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
18083};
18084#endif /* defined(HAVE_SS7) */
18085
18086#if defined(HAVE_PRI)
18087#if defined(HAVE_PRI_CCSS)
18088/*!
18089 * \internal
18090 * \brief CC agent initialization.
18091 * \since 1.8
18092 *
18093 * \param agent CC core agent control.
18094 * \param chan Original channel the agent will attempt to recall.
18095 *
18096 * \details
18097 * This callback is called when the CC core is initialized. Agents should allocate
18098 * any private data necessary for the call and assign it to the private_data
18099 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
18100 * specific agent type, they should be set in this function as well.
18101 *
18102 * \retval 0 on success.
18103 * \retval -1 on error.
18104 */
18105static int dahdi_pri_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
18106{
18107 struct dahdi_pvt *pvt;
18108 struct sig_pri_chan *pvt_chan;
18109 int res;
18110
18111 ast_assert(!strcmp(ast_channel_tech(chan)->type, "DAHDI"));
18112
18113 pvt = ast_channel_tech_pvt(chan);
18114 if (dahdi_sig_pri_lib_handles(pvt->sig)) {
18115 pvt_chan = pvt->sig_pvt;
18116 } else {
18117 pvt_chan = NULL;
18118 }
18119 if (!pvt_chan) {
18120 return -1;
18121 }
18122
18124
18125 res = sig_pri_cc_agent_init(agent, pvt_chan);
18126 if (res) {
18128 }
18129 return res;
18130}
18131#endif /* defined(HAVE_PRI_CCSS) */
18132#endif /* defined(HAVE_PRI) */
18133
18134#if defined(HAVE_PRI)
18135#if defined(HAVE_PRI_CCSS)
18136/*!
18137 * \internal
18138 * \brief Destroy private data on the agent.
18139 * \since 1.8
18140 *
18141 * \param agent CC core agent control.
18142 *
18143 * \details
18144 * The core will call this function upon completion
18145 * or failure of CC.
18146 */
18147static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent *agent)
18148{
18150
18152}
18153#endif /* defined(HAVE_PRI_CCSS) */
18154#endif /* defined(HAVE_PRI) */
18155
18156#if defined(HAVE_PRI)
18157#if defined(HAVE_PRI_CCSS)
18158static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = {
18159 .type = dahdi_pri_cc_type,
18160 .init = dahdi_pri_cc_agent_init,
18161 .start_offer_timer = sig_pri_cc_agent_start_offer_timer,
18162 .stop_offer_timer = sig_pri_cc_agent_stop_offer_timer,
18163 .respond = sig_pri_cc_agent_req_rsp,
18164 .status_request = sig_pri_cc_agent_status_req,
18165 .stop_ringing = sig_pri_cc_agent_stop_ringing,
18166 .party_b_free = sig_pri_cc_agent_party_b_free,
18167 .start_monitoring = sig_pri_cc_agent_start_monitoring,
18168 .callee_available = sig_pri_cc_agent_callee_available,
18169 .destructor = dahdi_pri_cc_agent_destructor,
18170};
18171#endif /* defined(HAVE_PRI_CCSS) */
18172#endif /* defined(HAVE_PRI) */
18173
18174#if defined(HAVE_PRI)
18175#if defined(HAVE_PRI_CCSS)
18176static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks = {
18177 .type = dahdi_pri_cc_type,
18178 .request_cc = sig_pri_cc_monitor_req_cc,
18179 .suspend = sig_pri_cc_monitor_suspend,
18180 .unsuspend = sig_pri_cc_monitor_unsuspend,
18181 .status_response = sig_pri_cc_monitor_status_rsp,
18182 .cancel_available_timer = sig_pri_cc_monitor_cancel_available_timer,
18183 .destructor = sig_pri_cc_monitor_destructor,
18184};
18185#endif /* defined(HAVE_PRI_CCSS) */
18186#endif /* defined(HAVE_PRI) */
18187
18188static int __unload_module(void)
18189{
18190 struct dahdi_pvt *p;
18191#if defined(HAVE_PRI) || defined(HAVE_SS7)
18192 int i, j;
18193#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18194
18195#ifdef HAVE_PRI
18196 for (i = 0; i < NUM_SPANS; i++) {
18197 if (pris[i].pri.master != AST_PTHREADT_NULL) {
18198 pthread_cancel(pris[i].pri.master);
18199 pthread_kill(pris[i].pri.master, SIGURG);
18200 }
18201 }
18202 ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
18203 ast_unregister_application(dahdi_send_keypad_facility_app);
18204#ifdef HAVE_PRI_PROG_W_CAUSE
18205 ast_unregister_application(dahdi_send_callrerouting_facility_app);
18206#endif
18207#endif
18208#if defined(HAVE_SS7)
18209 for (i = 0; i < NUM_SPANS; i++) {
18210 if (linksets[i].ss7.master != AST_PTHREADT_NULL) {
18211 pthread_cancel(linksets[i].ss7.master);
18212 pthread_kill(linksets[i].ss7.master, SIGURG);
18213 }
18214 }
18215 ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
18216#endif /* defined(HAVE_SS7) */
18217#if defined(HAVE_OPENR2)
18218 dahdi_r2_destroy_links();
18219 ast_cli_unregister_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
18220 ast_unregister_application(dahdi_accept_r2_call_app);
18221#endif
18222
18224
18226 ast_manager_unregister("DAHDIDialOffhook");
18227 ast_manager_unregister("DAHDIHangup");
18228 ast_manager_unregister("DAHDITransfer");
18229 ast_manager_unregister("DAHDIDNDoff");
18230 ast_manager_unregister("DAHDIDNDon");
18231 ast_manager_unregister("DAHDIShowChannels");
18232 ast_manager_unregister("DAHDIShowStatus");
18233 ast_manager_unregister("DAHDIRestart");
18234#if defined(HAVE_PRI)
18235 ast_manager_unregister("PRIShowSpans");
18236 ast_manager_unregister("PRIDebugSet");
18237 ast_manager_unregister("PRIDebugFileSet");
18238 ast_manager_unregister("PRIDebugFileUnset");
18239#endif /* defined(HAVE_PRI) */
18241
18242 /* Hangup all interfaces if they have an owner */
18244 for (p = iflist; p; p = p->next) {
18245 if (p->owner)
18247 }
18249
18252 pthread_cancel(monitor_thread);
18253 pthread_kill(monitor_thread, SIGURG);
18254 pthread_join(monitor_thread, NULL);
18255 }
18258
18260
18261#if defined(HAVE_PRI)
18262 for (i = 0; i < NUM_SPANS; i++) {
18263 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
18264 pthread_join(pris[i].pri.master, NULL);
18265 }
18266 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) {
18267 dahdi_close_pri_fd(&(pris[i]), j);
18268 }
18269 sig_pri_stop_pri(&pris[i].pri);
18270 }
18271#if defined(HAVE_PRI_CCSS)
18272 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks);
18273 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks);
18274#endif /* defined(HAVE_PRI_CCSS) */
18276#endif
18277
18278#if defined(HAVE_SS7)
18279 for (i = 0; i < NUM_SPANS; i++) {
18280 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
18281 pthread_join(linksets[i].ss7.master, NULL);
18282 }
18283 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
18284 dahdi_close_ss7_fd(&(linksets[i]), j);
18285 }
18286 if (linksets[i].ss7.ss7) {
18287 ss7_destroy(linksets[i].ss7.ss7);
18288 linksets[i].ss7.ss7 = NULL;
18289 }
18290 }
18291#endif /* defined(HAVE_SS7) */
18293
18295
18298 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
18299 return 0;
18300}
18301
18302static int unload_module(void)
18303{
18304#if defined(HAVE_PRI) || defined(HAVE_SS7)
18305 int y;
18306#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18307#ifdef HAVE_PRI
18308 for (y = 0; y < NUM_SPANS; y++)
18309 ast_mutex_destroy(&pris[y].pri.lock);
18310#endif
18311#if defined(HAVE_SS7)
18312 for (y = 0; y < NUM_SPANS; y++)
18313 ast_mutex_destroy(&linksets[y].ss7.lock);
18314#endif /* defined(HAVE_SS7) */
18315 return __unload_module();
18316}
18317
18318static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
18319{
18320 char *c, *chan;
18321 int x, start, finish;
18322 struct dahdi_pvt *tmp;
18323
18324 if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
18325 ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
18326 return -1;
18327 }
18328
18329 c = ast_strdupa(value);
18330
18331 while ((chan = strsep(&c, ","))) {
18332 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
18333 /* Range */
18334 } else if (sscanf(chan, "%30d", &start)) {
18335 /* Just one */
18336 finish = start;
18337 } else if (!strcasecmp(chan, "pseudo")) {
18338 finish = start = CHAN_PSEUDO;
18339 } else {
18340 ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
18341 return -1;
18342 }
18343 if (finish < start) {
18344 ast_log(LOG_WARNING, "Silliness: %d < %d\n", start, finish);
18345 x = finish;
18346 finish = start;
18347 start = x;
18348 }
18349
18350 for (x = start; x <= finish; x++) {
18351 if (conf->wanted_channels_start &&
18352 (x < conf->wanted_channels_start ||
18353 x > conf->wanted_channels_end)
18354 ) {
18355 continue;
18356 }
18357 tmp = mkintf(x, conf, reload);
18358
18359 if (tmp) {
18360 ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
18361 } else {
18362 ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
18363 (reload == 1) ? "reconfigure" : "register", value);
18364 return -1;
18365 }
18366 if (x == CHAN_PSEUDO) {
18367 has_pseudo = 1;
18368 }
18369 }
18370 }
18371
18372 return 0;
18373}
18374
18375/** The length of the parameters list of 'dahdichan'.
18376 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18377#define MAX_CHANLIST_LEN 80
18378
18379static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
18380{
18381 char *parse = ast_strdupa(data);
18382 char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
18383 unsigned int param_count;
18384 unsigned int x;
18385
18386 if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
18387 return;
18388
18389 memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
18390
18391 /* first parameter is tap length, process it here */
18392
18393 x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
18394
18395 if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
18396 confp->chan.echocancel.head.tap_length = x;
18397 else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
18398 confp->chan.echocancel.head.tap_length = 128;
18399
18400 /* now process any remaining parameters */
18401
18402 for (x = 1; x < param_count; x++) {
18403 struct {
18404 char *name;
18405 char *value;
18406 } param;
18407
18408 if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
18409 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, params[x]);
18410 continue;
18411 }
18412
18413 if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
18414 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, param.name);
18415 continue;
18416 }
18417
18418 strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
18419
18420 if (param.value) {
18421 if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
18422 ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line, param.value);
18423 continue;
18424 }
18425 }
18426 confp->chan.echocancel.head.param_count++;
18427 }
18428}
18429
18430#if defined(HAVE_PRI)
18431#if defined(HAVE_PRI_DISPLAY_TEXT)
18432/*!
18433 * \internal
18434 * \brief Determine the configured display text options.
18435 * \since 10.0
18436 *
18437 * \param value Configuration value string.
18438 *
18439 * \return Configured display text option flags.
18440 */
18441static unsigned long dahdi_display_text_option(const char *value)
18442{
18443 char *val_str;
18444 char *opt_str;
18445 unsigned long options;
18446
18447 options = 0;
18448 val_str = ast_strdupa(value);
18449
18450 for (;;) {
18451 opt_str = strsep(&val_str, ",");
18452 if (!opt_str) {
18453 break;
18454 }
18455 opt_str = ast_strip(opt_str);
18456 if (!*opt_str) {
18457 continue;
18458 }
18459
18460 if (!strcasecmp(opt_str, "block")) {
18461 options |= PRI_DISPLAY_OPTION_BLOCK;
18462 } else if (!strcasecmp(opt_str, "name_initial")) {
18463 options |= PRI_DISPLAY_OPTION_NAME_INITIAL;
18464 } else if (!strcasecmp(opt_str, "name_update")) {
18465 options |= PRI_DISPLAY_OPTION_NAME_UPDATE;
18466 } else if (!strcasecmp(opt_str, "name")) {
18467 options |= (PRI_DISPLAY_OPTION_NAME_INITIAL | PRI_DISPLAY_OPTION_NAME_UPDATE);
18468 } else if (!strcasecmp(opt_str, "text")) {
18469 options |= PRI_DISPLAY_OPTION_TEXT;
18470 }
18471 }
18472 return options;
18473}
18474#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18475#endif /* defined(HAVE_PRI) */
18476
18477#if defined(HAVE_PRI)
18478#if defined(HAVE_PRI_DATETIME_SEND)
18479/*!
18480 * \internal
18481 * \brief Determine the configured date/time send policy option.
18482 * \since 10.0
18483 *
18484 * \param value Configuration value string.
18485 *
18486 * \return Configured date/time send policy option.
18487 */
18488static int dahdi_datetime_send_option(const char *value)
18489{
18490 int option;
18491
18492 option = PRI_DATE_TIME_SEND_DEFAULT;
18493
18494 if (ast_false(value)) {
18495 option = PRI_DATE_TIME_SEND_NO;
18496 } else if (!strcasecmp(value, "date")) {
18497 option = PRI_DATE_TIME_SEND_DATE;
18498 } else if (!strcasecmp(value, "date_hh")) {
18499 option = PRI_DATE_TIME_SEND_DATE_HH;
18500 } else if (!strcasecmp(value, "date_hhmm")) {
18501 option = PRI_DATE_TIME_SEND_DATE_HHMM;
18502 } else if (!strcasecmp(value, "date_hhmmss")) {
18503 option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
18504 }
18505
18506 return option;
18507}
18508#endif /* defined(HAVE_PRI_DATETIME_SEND) */
18509#endif /* defined(HAVE_PRI) */
18510
18511/*! process_dahdi() - ignore keyword 'channel' and similar */
18512#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18513/*! process_dahdi() - No warnings on non-existing configuration keywords */
18514#define PROC_DAHDI_OPT_NOWARN (1 << 1)
18515
18516static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
18517{
18518 int count_pattern = 0;
18519 int norval = 0;
18520 char *temp = NULL;
18521
18522 for (; ;) {
18523 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18524 if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
18525 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18526 break;
18527 }
18528
18529 busy_cadence->pattern[count_pattern] = norval;
18530
18531 count_pattern++;
18532 if (count_pattern == 4) {
18533 break;
18534 }
18535
18536 temp = strchr(v->value, ',');
18537 if (temp == NULL) {
18538 break;
18539 }
18540 v->value = temp + 1;
18541 }
18542 busy_cadence->length = count_pattern;
18543
18544 if (count_pattern % 2 != 0) {
18545 /* The pattern length must be divisible by two */
18546 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18547 }
18548
18549}
18550
18551static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
18552{
18553 struct dahdi_pvt *tmp;
18554 int y;
18555 struct ast_variable *dahdichan = NULL;
18556
18557 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18559
18560 for (; v; v = v->next) {
18562 continue;
18563
18564 /* Create the interface list */
18565 if (!strcasecmp(v->name, "channel") || !strcasecmp(v->name, "channels")) {
18567 ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
18568 continue;
18569 }
18570 if (build_channels(confp, v->value, reload, v->lineno)) {
18571 if (confp->ignore_failed_channels) {
18572 ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
18573 continue;
18574 } else {
18575 return -1;
18576 }
18577 }
18578 ast_debug(1, "Channel '%s' configured.\n", v->value);
18579 } else if (!strcasecmp(v->name, "ignore_failed_channels")) {
18581 } else if (!strcasecmp(v->name, "buffers")) {
18582 if (parse_buffers_policy(v->value, &confp->chan.buf_no, &confp->chan.buf_policy)) {
18583 ast_log(LOG_WARNING, "Using default buffer policy.\n");
18584 confp->chan.buf_no = numbufs;
18585 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
18586 }
18587 } else if (!strcasecmp(v->name, "faxbuffers")) {
18588 if (!parse_buffers_policy(v->value, &confp->chan.faxbuf_no, &confp->chan.faxbuf_policy)) {
18589 confp->chan.usefaxbuffers = 1;
18590 }
18591 } else if (!strcasecmp(v->name, "dahdichan")) {
18592 /* Only process the last dahdichan value. */
18593 dahdichan = v;
18594 } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
18596 } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
18598 } else if (!strcasecmp(v->name, "dring1context")) {
18600 } else if (!strcasecmp(v->name, "dring2context")) {
18602 } else if (!strcasecmp(v->name, "dring3context")) {
18604 } else if (!strcasecmp(v->name, "dring1range")) {
18605 confp->chan.drings.ringnum[0].range = atoi(v->value);
18606 } else if (!strcasecmp(v->name, "dring2range")) {
18607 confp->chan.drings.ringnum[1].range = atoi(v->value);
18608 } else if (!strcasecmp(v->name, "dring3range")) {
18609 confp->chan.drings.ringnum[2].range = atoi(v->value);
18610 } else if (!strcasecmp(v->name, "dring1")) {
18611 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]);
18612 } else if (!strcasecmp(v->name, "dring2")) {
18613 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]);
18614 } else if (!strcasecmp(v->name, "dring3")) {
18615 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]);
18616 } else if (!strcasecmp(v->name, "usecallerid")) {
18617 confp->chan.use_callerid = ast_true(v->value);
18618 } else if (!strcasecmp(v->name, "cidsignalling")) {
18619 if (!strcasecmp(v->value, "bell"))
18621 else if (!strcasecmp(v->value, "v23"))
18623 else if (!strcasecmp(v->value, "dtmf"))
18625 else if (!strcasecmp(v->value, "smdi"))
18627 else if (!strcasecmp(v->value, "v23_jp"))
18629 else if (ast_true(v->value))
18631 } else if (!strcasecmp(v->name, "cidstart")) {
18632 if (!strcasecmp(v->value, "ring"))
18633 confp->chan.cid_start = CID_START_RING;
18634 else if (!strcasecmp(v->value, "polarity_in"))
18636 else if (!strcasecmp(v->value, "polarity"))
18638 else if (!strcasecmp(v->value, "dtmf"))
18640 else if (ast_true(v->value))
18641 confp->chan.cid_start = CID_START_RING;
18642 } else if (!strcasecmp(v->name, "threewaycalling")) {
18643 confp->chan.threewaycalling = ast_true(v->value);
18644 } else if (!strcasecmp(v->name, "threewaysilenthold")) {
18646 } else if (!strcasecmp(v->name, "cancallforward")) {
18647 confp->chan.cancallforward = ast_true(v->value);
18648 } else if (!strcasecmp(v->name, "relaxdtmf")) {
18649 if (ast_true(v->value))
18651 else
18652 confp->chan.dtmfrelax = 0;
18653 } else if (!strcasecmp(v->name, "mailbox")) {
18654 ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
18655 } else if (!strcasecmp(v->name, "description")) {
18656 ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
18657 } else if (!strcasecmp(v->name, "hasvoicemail")) {
18658 if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
18659 /*
18660 * hasvoicemail is a users.conf legacy voicemail enable method.
18661 * hasvoicemail is only going to work for app_voicemail mailboxes.
18662 */
18663 if (strchr(cat, '@')) {
18664 ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
18665 } else {
18666 snprintf(confp->chan.mailbox, sizeof(confp->chan.mailbox),
18667 "%s@default", cat);
18668 }
18669 }
18670 } else if (!strcasecmp(v->name, "adsi")) {
18671 confp->chan.adsi = ast_true(v->value);
18672 } else if (!strcasecmp(v->name, "usesmdi")) {
18673 confp->chan.use_smdi = ast_true(v->value);
18674 } else if (!strcasecmp(v->name, "smdiport")) {
18675 ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
18676 } else if (!strcasecmp(v->name, "transfer")) {
18677 confp->chan.transfer = ast_true(v->value);
18678 } else if (!strcasecmp(v->name, "canpark")) {
18679 confp->chan.canpark = ast_true(v->value);
18680 } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
18681 confp->chan.echocanbridged = ast_true(v->value);
18682 } else if (!strcasecmp(v->name, "busydetect")) {
18683 confp->chan.busydetect = ast_true(v->value);
18684 } else if (!strcasecmp(v->name, "busycount")) {
18685 confp->chan.busycount = atoi(v->value);
18686 } else if (!strcasecmp(v->name, "busypattern")) {
18688 } else if (!strcasecmp(v->name, "calledsubscriberheld")) {
18690 } else if (!strcasecmp(v->name, "lastnumredial")) {
18691 confp->chan.lastnumredial = ast_true(v->value);
18692 } else if (!strcasecmp(v->name, "callprogress")) {
18693 confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
18694 if (ast_true(v->value))
18696 } else if (!strcasecmp(v->name, "waitfordialtone")) {
18697 confp->chan.waitfordialtone = atoi(v->value);
18698 } else if (!strcasecmp(v->name, "dialtone_detect")) {
18699 if (!strcasecmp(v->value, "always")) {
18700 confp->chan.dialtone_detect = -1;
18701 } else if (ast_true(v->value)) {
18703 } else if (ast_false(v->value)) {
18704 confp->chan.dialtone_detect = 0;
18705 } else {
18706 confp->chan.dialtone_detect = ast_strlen_zero(v->value) ? 0 : (8 * atoi(v->value)) / READ_SIZE;
18707 }
18708 } else if (!strcasecmp(v->name, "faxdetect")) {
18709 confp->chan.callprogress &= ~CALLPROGRESS_FAX;
18710 if (!strcasecmp(v->value, "incoming")) {
18712 } else if (!strcasecmp(v->value, "outgoing")) {
18714 } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
18716 } else if (!strcasecmp(v->name, "faxdetect_timeout")) {
18717 if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) {
18718 confp->chan.faxdetect_timeout = 0;
18719 }
18720 } else if (!strcasecmp(v->name, "firstdigit_timeout")) {
18721 if (sscanf(v->value, "%30d", &confp->chan.firstdigit_timeout) != 1
18722 || confp->chan.firstdigit_timeout <= 0) {
18724 }
18725 } else if (!strcasecmp(v->name, "interdigit_timeout")) {
18726 if (sscanf(v->value, "%30d", &confp->chan.interdigit_timeout) != 1
18727 || confp->chan.interdigit_timeout <= 0) {
18729 }
18730 } else if (!strcasecmp(v->name, "matchdigit_timeout")) {
18731 if (sscanf(v->value, "%30d", &confp->chan.matchdigit_timeout) != 1
18732 || confp->chan.matchdigit_timeout <= 0) {
18734 }
18735 } else if (!strcasecmp(v->name, "echocancel")) {
18736 process_echocancel(confp, v->value, v->lineno);
18737 } else if (!strcasecmp(v->name, "echotraining")) {
18738 if (sscanf(v->value, "%30d", &y) == 1) {
18739 if ((y < 10) || (y > 4000)) {
18740 ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);
18741 } else {
18742 confp->chan.echotraining = y;
18743 }
18744 } else if (ast_true(v->value)) {
18745 confp->chan.echotraining = 400;
18746 } else
18747 confp->chan.echotraining = 0;
18748 } else if (!strcasecmp(v->name, "hidecallerid")) {
18749 confp->chan.hidecallerid = ast_true(v->value);
18750 } else if (!strcasecmp(v->name, "hidecalleridname")) {
18751 confp->chan.hidecalleridname = ast_true(v->value);
18752 } else if (!strcasecmp(v->name, "pulsedial")) {
18753 confp->chan.pulse = ast_true(v->value);
18754 } else if (!strcasecmp(v->name, "callreturn")) {
18755 confp->chan.callreturn = ast_true(v->value);
18756 } else if (!strcasecmp(v->name, "callwaiting")) {
18757 confp->chan.callwaiting = ast_true(v->value);
18758 } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
18760 } else if (!strcasecmp(v->name, "context")) {
18761 ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
18762 } else if (!strcasecmp(v->name, "language")) {
18763 ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
18764 } else if (!strcasecmp(v->name, "progzone")) {
18765 ast_copy_string(progzone, v->value, sizeof(progzone));
18766 } else if (!strcasecmp(v->name, "mohinterpret")
18767 ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
18768 ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
18769 } else if (!strcasecmp(v->name, "mohsuggest")) {
18770 ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
18771 } else if (!strcasecmp(v->name, "parkinglot")) {
18772 ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
18773 } else if (!strcasecmp(v->name, "stripmsd")) {
18774 ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
18775 confp->chan.stripmsd = atoi(v->value);
18776 } else if (!strcasecmp(v->name, "jitterbuffers")) {
18777 numbufs = atoi(v->value);
18778 } else if (!strcasecmp(v->name, "group")) {
18779 confp->chan.group = ast_get_group(v->value);
18780 } else if (!strcasecmp(v->name, "callgroup")) {
18781 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18782 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a call group\n");
18783 }
18784 if (!strcasecmp(v->value, "none"))
18785 confp->chan.callgroup = 0;
18786 else
18787 confp->chan.callgroup = ast_get_group(v->value);
18788 } else if (!strcasecmp(v->name, "pickupgroup")) {
18789 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18790 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a pickup group\n");
18791 }
18792 if (!strcasecmp(v->value, "none"))
18793 confp->chan.pickupgroup = 0;
18794 else
18795 confp->chan.pickupgroup = ast_get_group(v->value);
18796 } else if (!strcasecmp(v->name, "namedcallgroup")) {
18797 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18798 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named call group\n");
18799 }
18801 } else if (!strcasecmp(v->name, "namedpickupgroup")) {
18802 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18803 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named pickup group\n");
18804 }
18806 } else if (!strcasecmp(v->name, "setvar")) {
18807 if (v->value) {
18808 char *varval = NULL;
18809 struct ast_variable *tmpvar;
18810 char varname[strlen(v->value) + 1];
18811 strcpy(varname, v->value); /* safe */
18812 if ((varval = strchr(varname, '='))) {
18813 *varval++ = '\0';
18814 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
18815 if (ast_variable_list_replace(&confp->chan.vars, tmpvar)) {
18816 tmpvar->next = confp->chan.vars;
18817 confp->chan.vars = tmpvar;
18818 }
18819 }
18820 }
18821 }
18822 } else if (!strcasecmp(v->name, "immediate")) {
18823 confp->chan.immediate = ast_true(v->value);
18824 } else if (!strcasecmp(v->name, "immediatering")) {
18825 confp->chan.immediatering = ast_true(v->value);
18826 } else if (!strcasecmp(v->name, "transfertobusy")) {
18827 confp->chan.transfertobusy = ast_true(v->value);
18828 } else if (!strcasecmp(v->name, "dialmode")) {
18829 if (!strcasecmp(v->value, "pulse")) {
18831 } else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
18833 } else if (!strcasecmp(v->value, "none")) {
18835 } else {
18837 }
18838 } else if (!strcasecmp(v->name, "mwimonitor")) {
18839 confp->chan.mwimonitor_neon = 0;
18840 confp->chan.mwimonitor_fsk = 0;
18841 confp->chan.mwimonitor_rpas = 0;
18842 if (strcasestr(v->value, "fsk")) {
18843 confp->chan.mwimonitor_fsk = 1;
18844 }
18845 if (strcasestr(v->value, "rpas")) {
18846 confp->chan.mwimonitor_rpas = 1;
18847 }
18848 if (strcasestr(v->value, "neon")) {
18849 confp->chan.mwimonitor_neon = 1;
18850 }
18851 /* If set to true or yes, assume that simple fsk is desired */
18852 if (ast_true(v->value)) {
18853 confp->chan.mwimonitor_fsk = 1;
18854 }
18855 } else if (!strcasecmp(v->name, "hwrxgain")) {
18856 confp->chan.hwrxgain_enabled = 0;
18857 if (strcasecmp(v->value, "disabled")) {
18858 if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
18859 confp->chan.hwrxgain_enabled = 1;
18860 } else {
18861 ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
18862 }
18863 }
18864 } else if (!strcasecmp(v->name, "hwtxgain")) {
18865 confp->chan.hwtxgain_enabled = 0;
18866 if (strcasecmp(v->value, "disabled")) {
18867 if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
18868 confp->chan.hwtxgain_enabled = 1;
18869 } else {
18870 ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
18871 }
18872 }
18873 } else if (!strcasecmp(v->name, "cid_rxgain")) {
18874 if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
18875 ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
18876 }
18877 } else if (!strcasecmp(v->name, "rxgain")) {
18878 if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
18879 ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
18880 }
18881 } else if (!strcasecmp(v->name, "txgain")) {
18882 if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
18883 ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
18884 }
18885 } else if (!strcasecmp(v->name, "txdrc")) {
18886 if (sscanf(v->value, "%f", &confp->chan.txdrc) != 1) {
18887 ast_log(LOG_WARNING, "Invalid txdrc: %s\n", v->value);
18888 }
18889 } else if (!strcasecmp(v->name, "rxdrc")) {
18890 if (sscanf(v->value, "%f", &confp->chan.rxdrc) != 1) {
18891 ast_log(LOG_WARNING, "Invalid rxdrc: %s\n", v->value);
18892 }
18893 } else if (!strcasecmp(v->name, "tonezone")) {
18894 if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
18895 ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
18896 }
18897 } else if (!strcasecmp(v->name, "callerid")) {
18898 if (!strcasecmp(v->value, "asreceived")) {
18899 confp->chan.cid_num[0] = '\0';
18900 confp->chan.cid_name[0] = '\0';
18901 } else {
18902 ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
18903 }
18904 } else if (!strcasecmp(v->name, "fullname")) {
18905 ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
18906 } else if (!strcasecmp(v->name, "cid_number")) {
18907 ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
18908 } else if (!strcasecmp(v->name, "cid_tag")) {
18909 ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
18910 } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
18911 confp->chan.dahditrcallerid = ast_true(v->value);
18912 } else if (!strcasecmp(v->name, "restrictcid")) {
18913 confp->chan.restrictcid = ast_true(v->value);
18914 } else if (!strcasecmp(v->name, "usecallingpres")) {
18915 confp->chan.use_callingpres = ast_true(v->value);
18916 } else if (!strcasecmp(v->name, "accountcode")) {
18917 ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
18918 } else if (!strcasecmp(v->name, "amaflags")) {
18920 if (y < 0)
18921 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
18922 else
18923 confp->chan.amaflags = y;
18924 } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
18925 confp->chan.polarityonanswerdelay = atoi(v->value);
18926 } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
18928 } else if (!strcasecmp(v->name, "ani_info_digits")) {
18929 confp->chan.ani_info_digits = atoi(v->value);
18930 } else if (!strcasecmp(v->name, "ani_wink_time")) {
18931 confp->chan.ani_wink_time = atoi(v->value);
18932 } else if (!strcasecmp(v->name, "ani_timeout")) {
18933 confp->chan.ani_timeout = atoi(v->value);
18934 } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
18936 } else if (!strcasecmp(v->name, "autoreoriginate")) {
18937 confp->chan.reoriginate = ast_true(v->value);
18938 } else if (!strcasecmp(v->name, "sendcalleridafter")) {
18939 confp->chan.sendcalleridafter = atoi(v->value);
18940 } else if (!strcasecmp(v->name, "mwimonitornotify")) {
18942 } else if (ast_cc_is_config_param(v->name)) {
18943 ast_cc_set_param(confp->chan.cc_params, v->name, v->value);
18944 } else if (!strcasecmp(v->name, "mwisendtype")) {
18945#ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
18946 if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
18947 mwisend_rpas = 1;
18948 } else {
18949 mwisend_rpas = 0;
18950 }
18951#else
18952 /* Default is fsk, to turn it off you must specify nofsk */
18953 memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
18954 if (strcasestr(v->value, "nofsk")) { /* NoFSK */
18955 confp->chan.mwisend_fsk = 0;
18956 } else { /* Default FSK */
18957 confp->chan.mwisend_fsk = 1;
18958 }
18959 if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
18960 confp->chan.mwisend_rpas = 1;
18961 } else {
18962 confp->chan.mwisend_rpas = 0;
18963 }
18964 if (strcasestr(v->value, "lrev")) { /* Line Reversal */
18965 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
18966 }
18967 if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
18968 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
18969 }
18970 if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) { /* 90V DC pulses */
18971 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
18972 }
18973#endif
18974 } else if (reload != 1) {
18975 if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
18976 int orig_radio = confp->chan.radio;
18977 int orig_outsigmod = confp->chan.outsigmod;
18978 int orig_auto = confp->is_sig_auto;
18979
18980 confp->chan.radio = 0;
18981 confp->chan.outsigmod = -1;
18982 confp->is_sig_auto = 0;
18983 if (!strcasecmp(v->value, "em")) {
18984 confp->chan.sig = SIG_EM;
18985 } else if (!strcasecmp(v->value, "em_e1")) {
18986 confp->chan.sig = SIG_EM_E1;
18987 } else if (!strcasecmp(v->value, "em_w")) {
18988 confp->chan.sig = SIG_EMWINK;
18989 } else if (!strcasecmp(v->value, "fxs_ls")) {
18990 confp->chan.sig = SIG_FXSLS;
18991 } else if (!strcasecmp(v->value, "fxs_gs")) {
18992 confp->chan.sig = SIG_FXSGS;
18993 } else if (!strcasecmp(v->value, "fxs_ks")) {
18994 confp->chan.sig = SIG_FXSKS;
18995 } else if (!strcasecmp(v->value, "fxo_ls")) {
18996 confp->chan.sig = SIG_FXOLS;
18997 } else if (!strcasecmp(v->value, "fxo_gs")) {
18998 confp->chan.sig = SIG_FXOGS;
18999 } else if (!strcasecmp(v->value, "fxo_ks")) {
19000 confp->chan.sig = SIG_FXOKS;
19001 } else if (!strcasecmp(v->value, "fxs_rx")) {
19002 confp->chan.sig = SIG_FXSKS;
19003 confp->chan.radio = 1;
19004 } else if (!strcasecmp(v->value, "fxo_rx")) {
19005 confp->chan.sig = SIG_FXOLS;
19006 confp->chan.radio = 1;
19007 } else if (!strcasecmp(v->value, "fxs_tx")) {
19008 confp->chan.sig = SIG_FXSLS;
19009 confp->chan.radio = 1;
19010 } else if (!strcasecmp(v->value, "fxo_tx")) {
19011 confp->chan.sig = SIG_FXOGS;
19012 confp->chan.radio = 1;
19013 } else if (!strcasecmp(v->value, "em_rx")) {
19014 confp->chan.sig = SIG_EM;
19015 confp->chan.radio = 1;
19016 } else if (!strcasecmp(v->value, "em_tx")) {
19017 confp->chan.sig = SIG_EM;
19018 confp->chan.radio = 1;
19019 } else if (!strcasecmp(v->value, "em_rxtx")) {
19020 confp->chan.sig = SIG_EM;
19021 confp->chan.radio = 2;
19022 } else if (!strcasecmp(v->value, "em_txrx")) {
19023 confp->chan.sig = SIG_EM;
19024 confp->chan.radio = 2;
19025 } else if (!strcasecmp(v->value, "sf")) {
19026 confp->chan.sig = SIG_SF;
19027 } else if (!strcasecmp(v->value, "sf_w")) {
19028 confp->chan.sig = SIG_SFWINK;
19029 } else if (!strcasecmp(v->value, "sf_featd")) {
19030 confp->chan.sig = SIG_FEATD;
19031 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19032 confp->chan.sig = SIG_FEATDMF;
19033 } else if (!strcasecmp(v->value, "sf_featb")) {
19034 confp->chan.sig = SIG_SF_FEATB;
19035 } else if (!strcasecmp(v->value, "sf")) {
19036 confp->chan.sig = SIG_SF;
19037 } else if (!strcasecmp(v->value, "sf_rx")) {
19038 confp->chan.sig = SIG_SF;
19039 confp->chan.radio = 1;
19040 } else if (!strcasecmp(v->value, "sf_tx")) {
19041 confp->chan.sig = SIG_SF;
19042 confp->chan.radio = 1;
19043 } else if (!strcasecmp(v->value, "sf_rxtx")) {
19044 confp->chan.sig = SIG_SF;
19045 confp->chan.radio = 2;
19046 } else if (!strcasecmp(v->value, "sf_txrx")) {
19047 confp->chan.sig = SIG_SF;
19048 confp->chan.radio = 2;
19049 } else if (!strcasecmp(v->value, "featd")) {
19050 confp->chan.sig = SIG_FEATD;
19051 } else if (!strcasecmp(v->value, "featdmf")) {
19052 confp->chan.sig = SIG_FEATDMF;
19053 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19054 confp->chan.sig = SIG_FEATDMF_TA;
19055 } else if (!strcasecmp(v->value, "e911")) {
19056 confp->chan.sig = SIG_E911;
19057 } else if (!strcasecmp(v->value, "fgccama")) {
19058 confp->chan.sig = SIG_FGC_CAMA;
19059 } else if (!strcasecmp(v->value, "fgccamamf")) {
19060 confp->chan.sig = SIG_FGC_CAMAMF;
19061 } else if (!strcasecmp(v->value, "featb")) {
19062 confp->chan.sig = SIG_FEATB;
19063#ifdef HAVE_PRI
19064 } else if (!strcasecmp(v->value, "pri_net")) {
19065 confp->chan.sig = SIG_PRI;
19066 confp->pri.pri.nodetype = PRI_NETWORK;
19067 } else if (!strcasecmp(v->value, "pri_cpe")) {
19068 confp->chan.sig = SIG_PRI;
19069 confp->pri.pri.nodetype = PRI_CPE;
19070 } else if (!strcasecmp(v->value, "bri_cpe")) {
19071 confp->chan.sig = SIG_BRI;
19072 confp->pri.pri.nodetype = PRI_CPE;
19073 } else if (!strcasecmp(v->value, "bri_net")) {
19074 confp->chan.sig = SIG_BRI;
19075 confp->pri.pri.nodetype = PRI_NETWORK;
19076 } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
19077 confp->chan.sig = SIG_BRI_PTMP;
19078 confp->pri.pri.nodetype = PRI_CPE;
19079 } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
19080#if defined(HAVE_PRI_CALL_HOLD)
19081 confp->chan.sig = SIG_BRI_PTMP;
19082 confp->pri.pri.nodetype = PRI_NETWORK;
19083#else
19084 ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v->lineno);
19085#endif /* !defined(HAVE_PRI_CALL_HOLD) */
19086#endif
19087#if defined(HAVE_SS7)
19088 } else if (!strcasecmp(v->value, "ss7")) {
19089 confp->chan.sig = SIG_SS7;
19090#endif /* defined(HAVE_SS7) */
19091#ifdef HAVE_OPENR2
19092 } else if (!strcasecmp(v->value, "mfcr2")) {
19093 confp->chan.sig = SIG_MFCR2;
19094#endif
19095 } else if (!strcasecmp(v->value, "auto")) {
19096 confp->is_sig_auto = 1;
19097 } else {
19098 confp->chan.outsigmod = orig_outsigmod;
19099 confp->chan.radio = orig_radio;
19100 confp->is_sig_auto = orig_auto;
19101 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19102 }
19103 } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
19104 if (!strcasecmp(v->value, "em")) {
19105 confp->chan.outsigmod = SIG_EM;
19106 } else if (!strcasecmp(v->value, "em_e1")) {
19107 confp->chan.outsigmod = SIG_EM_E1;
19108 } else if (!strcasecmp(v->value, "em_w")) {
19109 confp->chan.outsigmod = SIG_EMWINK;
19110 } else if (!strcasecmp(v->value, "sf")) {
19111 confp->chan.outsigmod = SIG_SF;
19112 } else if (!strcasecmp(v->value, "sf_w")) {
19113 confp->chan.outsigmod = SIG_SFWINK;
19114 } else if (!strcasecmp(v->value, "sf_featd")) {
19115 confp->chan.outsigmod = SIG_FEATD;
19116 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19117 confp->chan.outsigmod = SIG_FEATDMF;
19118 } else if (!strcasecmp(v->value, "sf_featb")) {
19119 confp->chan.outsigmod = SIG_SF_FEATB;
19120 } else if (!strcasecmp(v->value, "sf")) {
19121 confp->chan.outsigmod = SIG_SF;
19122 } else if (!strcasecmp(v->value, "featd")) {
19123 confp->chan.outsigmod = SIG_FEATD;
19124 } else if (!strcasecmp(v->value, "featdmf")) {
19125 confp->chan.outsigmod = SIG_FEATDMF;
19126 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19127 confp->chan.outsigmod = SIG_FEATDMF_TA;
19128 } else if (!strcasecmp(v->value, "e911")) {
19129 confp->chan.outsigmod = SIG_E911;
19130 } else if (!strcasecmp(v->value, "fgccama")) {
19131 confp->chan.outsigmod = SIG_FGC_CAMA;
19132 } else if (!strcasecmp(v->value, "fgccamamf")) {
19133 confp->chan.outsigmod = SIG_FGC_CAMAMF;
19134 } else if (!strcasecmp(v->value, "featb")) {
19135 confp->chan.outsigmod = SIG_FEATB;
19136 } else {
19137 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19138 }
19139#ifdef HAVE_PRI
19140 } else if (!strcasecmp(v->name, "pridialplan")) {
19141 if (!strcasecmp(v->value, "national")) {
19142 confp->pri.pri.dialplan = PRI_NATIONAL_ISDN + 1;
19143 } else if (!strcasecmp(v->value, "unknown")) {
19144 confp->pri.pri.dialplan = PRI_UNKNOWN + 1;
19145 } else if (!strcasecmp(v->value, "private")) {
19146 confp->pri.pri.dialplan = PRI_PRIVATE + 1;
19147 } else if (!strcasecmp(v->value, "international")) {
19148 confp->pri.pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
19149 } else if (!strcasecmp(v->value, "local")) {
19150 confp->pri.pri.dialplan = PRI_LOCAL_ISDN + 1;
19151 } else if (!strcasecmp(v->value, "dynamic")) {
19152 confp->pri.pri.dialplan = -1;
19153 } else if (!strcasecmp(v->value, "redundant")) {
19154 confp->pri.pri.dialplan = -2;
19155 } else {
19156 ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
19157 }
19158 } else if (!strcasecmp(v->name, "prilocaldialplan")) {
19159 if (!strcasecmp(v->value, "national")) {
19160 confp->pri.pri.localdialplan = PRI_NATIONAL_ISDN + 1;
19161 } else if (!strcasecmp(v->value, "unknown")) {
19162 confp->pri.pri.localdialplan = PRI_UNKNOWN + 1;
19163 } else if (!strcasecmp(v->value, "private")) {
19164 confp->pri.pri.localdialplan = PRI_PRIVATE + 1;
19165 } else if (!strcasecmp(v->value, "international")) {
19166 confp->pri.pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
19167 } else if (!strcasecmp(v->value, "local")) {
19168 confp->pri.pri.localdialplan = PRI_LOCAL_ISDN + 1;
19169 } else if (!strcasecmp(v->value, "from_channel")) {
19170 confp->pri.pri.localdialplan = 0;
19171 } else if (!strcasecmp(v->value, "dynamic")) {
19172 confp->pri.pri.localdialplan = -1;
19173 } else if (!strcasecmp(v->value, "redundant")) {
19174 confp->pri.pri.localdialplan = -2;
19175 } else {
19176 ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
19177 }
19178 } else if (!strcasecmp(v->name, "pricpndialplan")) {
19179 if (!strcasecmp(v->value, "national")) {
19180 confp->pri.pri.cpndialplan = PRI_NATIONAL_ISDN + 1;
19181 } else if (!strcasecmp(v->value, "unknown")) {
19182 confp->pri.pri.cpndialplan = PRI_UNKNOWN + 1;
19183 } else if (!strcasecmp(v->value, "private")) {
19184 confp->pri.pri.cpndialplan = PRI_PRIVATE + 1;
19185 } else if (!strcasecmp(v->value, "international")) {
19186 confp->pri.pri.cpndialplan = PRI_INTERNATIONAL_ISDN + 1;
19187 } else if (!strcasecmp(v->value, "local")) {
19188 confp->pri.pri.cpndialplan = PRI_LOCAL_ISDN + 1;
19189 } else if (!strcasecmp(v->value, "from_channel")) {
19190 confp->pri.pri.cpndialplan = 0;
19191 } else if (!strcasecmp(v->value, "dynamic")) {
19192 confp->pri.pri.cpndialplan = -1;
19193 } else if (!strcasecmp(v->value, "redundant")) {
19194 confp->pri.pri.cpndialplan = -2;
19195 } else {
19196 ast_log(LOG_WARNING, "Unknown PRI cpndialplan '%s' at line %d.\n", v->value, v->lineno);
19197 }
19198 } else if (!strcasecmp(v->name, "switchtype")) {
19199 if (!strcasecmp(v->value, "national"))
19200 confp->pri.pri.switchtype = PRI_SWITCH_NI2;
19201 else if (!strcasecmp(v->value, "ni1"))
19202 confp->pri.pri.switchtype = PRI_SWITCH_NI1;
19203 else if (!strcasecmp(v->value, "dms100"))
19204 confp->pri.pri.switchtype = PRI_SWITCH_DMS100;
19205 else if (!strcasecmp(v->value, "4ess"))
19206 confp->pri.pri.switchtype = PRI_SWITCH_ATT4ESS;
19207 else if (!strcasecmp(v->value, "5ess"))
19208 confp->pri.pri.switchtype = PRI_SWITCH_LUCENT5E;
19209 else if (!strcasecmp(v->value, "euroisdn"))
19210 confp->pri.pri.switchtype = PRI_SWITCH_EUROISDN_E1;
19211 else if (!strcasecmp(v->value, "qsig"))
19212 confp->pri.pri.switchtype = PRI_SWITCH_QSIG;
19213 else {
19214 ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
19215 return -1;
19216 }
19217 } else if (!strcasecmp(v->name, "msn")) {
19218 ast_copy_string(confp->pri.pri.msn_list, v->value,
19219 sizeof(confp->pri.pri.msn_list));
19220 } else if (!strcasecmp(v->name, "nsf")) {
19221 if (!strcasecmp(v->value, "sdn"))
19222 confp->pri.pri.nsf = PRI_NSF_SDN;
19223 else if (!strcasecmp(v->value, "megacom"))
19224 confp->pri.pri.nsf = PRI_NSF_MEGACOM;
19225 else if (!strcasecmp(v->value, "tollfreemegacom"))
19226 confp->pri.pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
19227 else if (!strcasecmp(v->value, "accunet"))
19228 confp->pri.pri.nsf = PRI_NSF_ACCUNET;
19229 else if (!strcasecmp(v->value, "none"))
19230 confp->pri.pri.nsf = PRI_NSF_NONE;
19231 else {
19232 ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
19233 confp->pri.pri.nsf = PRI_NSF_NONE;
19234 }
19235 } else if (!strcasecmp(v->name, "priindication")) {
19236 if (!strcasecmp(v->value, "outofband"))
19237 confp->chan.priindication_oob = 1;
19238 else if (!strcasecmp(v->value, "inband"))
19239 confp->chan.priindication_oob = 0;
19240 else
19241 ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
19242 v->value, v->lineno);
19243 } else if (!strcasecmp(v->name, "priexclusive")) {
19244 confp->chan.priexclusive = ast_true(v->value);
19245 } else if (!strcasecmp(v->name, "internationalprefix")) {
19246 ast_copy_string(confp->pri.pri.internationalprefix, v->value, sizeof(confp->pri.pri.internationalprefix));
19247 } else if (!strcasecmp(v->name, "nationalprefix")) {
19248 ast_copy_string(confp->pri.pri.nationalprefix, v->value, sizeof(confp->pri.pri.nationalprefix));
19249 } else if (!strcasecmp(v->name, "localprefix")) {
19250 ast_copy_string(confp->pri.pri.localprefix, v->value, sizeof(confp->pri.pri.localprefix));
19251 } else if (!strcasecmp(v->name, "privateprefix")) {
19252 ast_copy_string(confp->pri.pri.privateprefix, v->value, sizeof(confp->pri.pri.privateprefix));
19253 } else if (!strcasecmp(v->name, "unknownprefix")) {
19254 ast_copy_string(confp->pri.pri.unknownprefix, v->value, sizeof(confp->pri.pri.unknownprefix));
19255 } else if (!strcasecmp(v->name, "resetinterval")) {
19256 if (!strcasecmp(v->value, "never"))
19257 confp->pri.pri.resetinterval = -1;
19258 else if (atoi(v->value) >= 60)
19259 confp->pri.pri.resetinterval = atoi(v->value);
19260 else
19261 ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
19262 v->value, v->lineno);
19263 } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
19264 confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
19265 } else if (!strcasecmp(v->name, "minunused")) {
19266 confp->pri.pri.minunused = atoi(v->value);
19267 } else if (!strcasecmp(v->name, "minidle")) {
19268 confp->pri.pri.minidle = atoi(v->value);
19269 } else if (!strcasecmp(v->name, "idleext")) {
19270 ast_copy_string(confp->pri.pri.idleext, v->value, sizeof(confp->pri.pri.idleext));
19271 } else if (!strcasecmp(v->name, "idledial")) {
19272 ast_copy_string(confp->pri.pri.idledial, v->value, sizeof(confp->pri.pri.idledial));
19273 } else if (!strcasecmp(v->name, "overlapdial")) {
19274 if (ast_true(v->value)) {
19275 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19276 } else if (!strcasecmp(v->value, "incoming")) {
19277 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
19278 } else if (!strcasecmp(v->value, "outgoing")) {
19279 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
19280 } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
19281 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19282 } else {
19283 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
19284 }
19285#ifdef HAVE_PRI_PROG_W_CAUSE
19286 } else if (!strcasecmp(v->name, "qsigchannelmapping")) {
19287 if (!strcasecmp(v->value, "logical")) {
19288 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_LOGICAL;
19289 } else if (!strcasecmp(v->value, "physical")) {
19290 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19291 } else {
19292 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19293 }
19294#endif
19295 } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) {
19296 confp->pri.pri.discardremoteholdretrieval = ast_true(v->value);
19297#if defined(HAVE_PRI_SERVICE_MESSAGES)
19298 } else if (!strcasecmp(v->name, "service_message_support")) {
19299 /* assuming switchtype for this channel group has been configured already */
19300 if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
19301 || confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
19302 || confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
19303 confp->pri.pri.enable_service_message_support = 1;
19304 } else {
19305 confp->pri.pri.enable_service_message_support = 0;
19306 }
19307#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
19308#ifdef HAVE_PRI_INBANDDISCONNECT
19309 } else if (!strcasecmp(v->name, "inbanddisconnect")) {
19310 confp->pri.pri.inbanddisconnect = ast_true(v->value);
19311#endif
19312 } else if (!strcasecmp(v->name, "pritimer")) {
19313#ifdef PRI_GETSET_TIMERS
19314 char tmp[20];
19315 char *timerc;
19316 char *c;
19317 int timer;
19318 int timeridx;
19319
19320 ast_copy_string(tmp, v->value, sizeof(tmp));
19321 c = tmp;
19322 timerc = strsep(&c, ",");
19323 if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
19324 timeridx = pri_timer2idx(timerc);
19325 timer = atoi(c);
19326 if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
19328 "'%s' is not a valid ISDN timer at line %d.\n", timerc,
19329 v->lineno);
19330 } else if (!timer) {
19332 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19333 c, timerc, v->lineno);
19334 } else {
19335 confp->pri.pri.pritimers[timeridx] = timer;
19336 }
19337 } else {
19339 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19340 v->value, v->lineno);
19341 }
19342#endif /* PRI_GETSET_TIMERS */
19343 } else if (!strcasecmp(v->name, "facilityenable")) {
19344 confp->pri.pri.facilityenable = ast_true(v->value);
19345#if defined(HAVE_PRI_AOC_EVENTS)
19346 } else if (!strcasecmp(v->name, "aoc_enable")) {
19347 confp->pri.pri.aoc_passthrough_flag = 0;
19348 if (strchr(v->value, 's') || strchr(v->value, 'S')) {
19349 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_S;
19350 }
19351 if (strchr(v->value, 'd') || strchr(v->value, 'D')) {
19352 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_D;
19353 }
19354 if (strchr(v->value, 'e') || strchr(v->value, 'E')) {
19355 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_E;
19356 }
19357 } else if (!strcasecmp(v->name, "aoce_delayhangup")) {
19358 confp->pri.pri.aoce_delayhangup = ast_true(v->value);
19359#endif /* defined(HAVE_PRI_AOC_EVENTS) */
19360#if defined(HAVE_PRI_CALL_HOLD)
19361 } else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
19362 confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
19363#endif /* defined(HAVE_PRI_CALL_HOLD) */
19364 } else if (!strcasecmp(v->name, "moh_signaling")
19365 || !strcasecmp(v->name, "moh_signalling")) {
19366 if (!strcasecmp(v->value, "moh")) {
19367 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19368 } else if (!strcasecmp(v->value, "notify")) {
19369 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_NOTIFY;
19370#if defined(HAVE_PRI_CALL_HOLD)
19371 } else if (!strcasecmp(v->value, "hold")) {
19372 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_HOLD;
19373#endif /* defined(HAVE_PRI_CALL_HOLD) */
19374 } else {
19375 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19376 }
19377#if defined(HAVE_PRI_CCSS)
19378 } else if (!strcasecmp(v->name, "cc_ptmp_recall_mode")) {
19379 if (!strcasecmp(v->value, "global")) {
19380 confp->pri.pri.cc_ptmp_recall_mode = 0;/* globalRecall */
19381 } else if (!strcasecmp(v->value, "specific")) {
19382 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19383 } else {
19384 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19385 }
19386 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_req")) {
19387 if (!strcasecmp(v->value, "release")) {
19388 confp->pri.pri.cc_qsig_signaling_link_req = 0;/* release */
19389 } else if (!strcasecmp(v->value, "retain")) {
19390 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19391 } else if (!strcasecmp(v->value, "do_not_care")) {
19392 confp->pri.pri.cc_qsig_signaling_link_req = 2;/* do-not-care */
19393 } else {
19394 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19395 }
19396 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_rsp")) {
19397 if (!strcasecmp(v->value, "release")) {
19398 confp->pri.pri.cc_qsig_signaling_link_rsp = 0;/* release */
19399 } else if (!strcasecmp(v->value, "retain")) {
19400 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19401 } else {
19402 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19403 }
19404#endif /* defined(HAVE_PRI_CCSS) */
19405#if defined(HAVE_PRI_CALL_WAITING)
19406 } else if (!strcasecmp(v->name, "max_call_waiting_calls")) {
19407 confp->pri.pri.max_call_waiting_calls = atoi(v->value);
19408 if (confp->pri.pri.max_call_waiting_calls < 0) {
19409 /* Negative values are not allowed. */
19410 confp->pri.pri.max_call_waiting_calls = 0;
19411 }
19412 } else if (!strcasecmp(v->name, "allow_call_waiting_calls")) {
19413 confp->pri.pri.allow_call_waiting_calls = ast_true(v->value);
19414#endif /* defined(HAVE_PRI_CALL_WAITING) */
19415#if defined(HAVE_PRI_MWI)
19416 } else if (!strcasecmp(v->name, "mwi_mailboxes")) {
19417 ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
19418 sizeof(confp->pri.pri.mwi_mailboxes));
19419 } else if (!strcasecmp(v->name, "mwi_vm_boxes")) {
19420 ast_copy_string(confp->pri.pri.mwi_vm_boxes, v->value,
19421 sizeof(confp->pri.pri.mwi_vm_boxes));
19422 } else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
19423 ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
19424 sizeof(confp->pri.pri.mwi_vm_numbers));
19425#endif /* defined(HAVE_PRI_MWI) */
19426 } else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
19427 confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
19428 } else if (!strcasecmp(v->name, "inband_on_setup_ack")) {
19429 confp->pri.pri.inband_on_setup_ack = ast_true(v->value);
19430 } else if (!strcasecmp(v->name, "inband_on_proceeding")) {
19431 confp->pri.pri.inband_on_proceeding = ast_true(v->value);
19432#if defined(HAVE_PRI_DISPLAY_TEXT)
19433 } else if (!strcasecmp(v->name, "display_send")) {
19434 confp->pri.pri.display_flags_send = dahdi_display_text_option(v->value);
19435 } else if (!strcasecmp(v->name, "display_receive")) {
19436 confp->pri.pri.display_flags_receive = dahdi_display_text_option(v->value);
19437#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19438#if defined(HAVE_PRI_MCID)
19439 } else if (!strcasecmp(v->name, "mcid_send")) {
19440 confp->pri.pri.mcid_send = ast_true(v->value);
19441#endif /* defined(HAVE_PRI_MCID) */
19442#if defined(HAVE_PRI_DATETIME_SEND)
19443 } else if (!strcasecmp(v->name, "datetime_send")) {
19444 confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
19445#endif /* defined(HAVE_PRI_DATETIME_SEND) */
19446 } else if (!strcasecmp(v->name, "layer1_presence")) {
19447 if (!strcasecmp(v->value, "required")) {
19448 confp->pri.pri.layer1_ignored = 0;
19449 } else if (!strcasecmp(v->value, "ignore")) {
19450 confp->pri.pri.layer1_ignored = 1;
19451 } else {
19452 /* Default */
19453 confp->pri.pri.layer1_ignored = 0;
19454 }
19455#if defined(HAVE_PRI_L2_PERSISTENCE)
19456 } else if (!strcasecmp(v->name, "layer2_persistence")) {
19457 if (!strcasecmp(v->value, "keep_up")) {
19458 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_KEEP_UP;
19459 } else if (!strcasecmp(v->value, "leave_down")) {
19460 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_LEAVE_DOWN;
19461 } else {
19462 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_DEFAULT;
19463 }
19464#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19465 } else if (!strcasecmp(v->name, "colp_send")) {
19466 if (!strcasecmp(v->value, "block")) {
19467 confp->pri.pri.colp_send = SIG_PRI_COLP_BLOCK;
19468 } else if (!strcasecmp(v->value, "connect")) {
19469 confp->pri.pri.colp_send = SIG_PRI_COLP_CONNECT;
19470 } else if (!strcasecmp(v->value, "update")) {
19471 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19472 } else {
19473 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19474 }
19475#endif /* HAVE_PRI */
19476#if defined(HAVE_SS7)
19477 } else if (!strcasecmp(v->name, "ss7type")) {
19478 if (!strcasecmp(v->value, "itu")) {
19479 cur_ss7type = SS7_ITU;
19480 } else if (!strcasecmp(v->value, "ansi")) {
19481 cur_ss7type = SS7_ANSI;
19482 } else {
19483 ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
19484 }
19485 } else if (!strcasecmp(v->name, "slc")) {
19486 cur_slc = atoi(v->value);
19487 } else if (!strcasecmp(v->name, "linkset")) {
19488 cur_linkset = atoi(v->value);
19489 } else if (!strcasecmp(v->name, "pointcode")) {
19490 cur_pointcode = parse_pointcode(v->value);
19491 } else if (!strcasecmp(v->name, "adjpointcode")) {
19492 cur_adjpointcode = parse_pointcode(v->value);
19493 } else if (!strcasecmp(v->name, "defaultdpc")) {
19494 cur_defaultdpc = parse_pointcode(v->value);
19495 } else if (!strcasecmp(v->name, "cicbeginswith")) {
19496 cur_cicbeginswith = atoi(v->value);
19497 } else if (!strcasecmp(v->name, "networkindicator")) {
19498 if (!strcasecmp(v->value, "national")) {
19499 cur_networkindicator = SS7_NI_NAT;
19500 } else if (!strcasecmp(v->value, "national_spare")) {
19501 cur_networkindicator = SS7_NI_NAT_SPARE;
19502 } else if (!strcasecmp(v->value, "international")) {
19503 cur_networkindicator = SS7_NI_INT;
19504 } else if (!strcasecmp(v->value, "international_spare")) {
19505 cur_networkindicator = SS7_NI_INT_SPARE;
19506 } else {
19507 cur_networkindicator = -1;
19508 }
19509 } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
19510 ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
19511 } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
19512 ast_copy_string(confp->ss7.ss7.nationalprefix, v->value, sizeof(confp->ss7.ss7.nationalprefix));
19513 } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
19514 ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
19515 } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
19516 ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
19517 } else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
19518 ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
19519 } else if (!strcasecmp(v->name, "ss7_called_nai")) {
19520 if (!strcasecmp(v->value, "national")) {
19521 confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
19522 } else if (!strcasecmp(v->value, "international")) {
19523 confp->ss7.ss7.called_nai = SS7_NAI_INTERNATIONAL;
19524 } else if (!strcasecmp(v->value, "subscriber")) {
19525 confp->ss7.ss7.called_nai = SS7_NAI_SUBSCRIBER;
19526 } else if (!strcasecmp(v->value, "unknown")) {
19527 confp->ss7.ss7.called_nai = SS7_NAI_UNKNOWN;
19528 } else if (!strcasecmp(v->value, "dynamic")) {
19529 confp->ss7.ss7.called_nai = SS7_NAI_DYNAMIC;
19530 } else {
19531 ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
19532 }
19533 } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
19534 if (!strcasecmp(v->value, "national")) {
19535 confp->ss7.ss7.calling_nai = SS7_NAI_NATIONAL;
19536 } else if (!strcasecmp(v->value, "international")) {
19537 confp->ss7.ss7.calling_nai = SS7_NAI_INTERNATIONAL;
19538 } else if (!strcasecmp(v->value, "subscriber")) {
19539 confp->ss7.ss7.calling_nai = SS7_NAI_SUBSCRIBER;
19540 } else if (!strcasecmp(v->value, "unknown")) {
19541 confp->ss7.ss7.calling_nai = SS7_NAI_UNKNOWN;
19542 } else if (!strcasecmp(v->value, "dynamic")) {
19543 confp->ss7.ss7.calling_nai = SS7_NAI_DYNAMIC;
19544 } else {
19545 ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
19546 }
19547 } else if (!strcasecmp(v->name, "sigchan")) {
19548 int sigchan, res;
19549 sigchan = atoi(v->value);
19550 res = linkset_addsigchan(sigchan);
19551 if (res < 0) {
19552 return -1;
19553 }
19554 } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
19555 struct dahdi_ss7 *link;
19556 link = ss7_resolve_linkset(cur_linkset);
19557 if (!link) {
19558 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19559 return -1;
19560 }
19561 if (ast_true(v->value)) {
19562 link->ss7.flags |= LINKSET_FLAG_EXPLICITACM;
19563 } else {
19564 link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
19565 }
19566 } else if (!strcasecmp(v->name, "ss7_autoacm")) {
19567 struct dahdi_ss7 *link;
19568 link = ss7_resolve_linkset(cur_linkset);
19569 if (!link) {
19570 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19571 return -1;
19572 }
19573 if (ast_true(v->value)) {
19574 link->ss7.flags |= LINKSET_FLAG_AUTOACM;
19575 } else {
19576 link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
19577 }
19578 } else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
19579 struct dahdi_ss7 *link;
19580 link = ss7_resolve_linkset(cur_linkset);
19581 if (!link) {
19582 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19583 return -1;
19584 }
19585 if (ast_true(v->value)) {
19586 link->ss7.flags |= LINKSET_FLAG_INITIALHWBLO;
19587 } else {
19588 link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
19589 }
19590 } else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
19591 struct dahdi_ss7 *link;
19592 link = ss7_resolve_linkset(cur_linkset);
19593 if (!link) {
19594 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19595 return -1;
19596 }
19597 if (ast_true(v->value)) {
19598 link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
19599 } else {
19600 link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
19601 }
19602 } else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
19603 struct dahdi_ss7 *link;
19604 link = ss7_resolve_linkset(cur_linkset);
19605 if (!link) {
19606 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19607 return -1;
19608 }
19609 if (ast_true(v->value)) {
19610 link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
19611 } else {
19612 link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
19613 }
19614 } else if (!strncasecmp(v->name, "isup_timer.", 11)) {
19615 struct dahdi_ss7 *link;
19616 link = ss7_resolve_linkset(cur_linkset);
19617 if (!link) {
19618 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19619 return -1;
19620 }
19621 if (!link->ss7.ss7) {
19622 ast_log(LOG_ERROR, "Please specify isup timers after sigchan!\n");
19623 } else if (!ss7_set_isup_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19624 ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
19625 }
19626 } else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
19627 struct dahdi_ss7 *link;
19628 link = ss7_resolve_linkset(cur_linkset);
19629 if (!link) {
19630 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19631 return -1;
19632 }
19633 if (!link->ss7.ss7) {
19634 ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
19635 } else if (!ss7_set_mtp3_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19636 ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
19637 }
19638 } else if (!strcasecmp(v->name, "inr_if_no_calling")) {
19639 struct dahdi_ss7 *link;
19640 link = ss7_resolve_linkset(cur_linkset);
19641 if (!link) {
19642 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19643 return -1;
19644 }
19645 if (!link->ss7.ss7) {
19646 ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
19647 } else if (ast_true(v->value)) {
19648 ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19649 } else {
19650 ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19651 }
19652 } else if (!strcasecmp(v->name, "non_isdn_access")) {
19653 struct dahdi_ss7 *link;
19654 link = ss7_resolve_linkset(cur_linkset);
19655 if (!link) {
19656 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19657 return -1;
19658 }
19659 if (!link->ss7.ss7) {
19660 ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
19661 } else if (ast_true(v->value)) {
19662 ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19663 } else {
19664 ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19665 }
19666 } else if (!strcasecmp(v->name, "sls_shift")) {
19667 struct dahdi_ss7 *link;
19668 int sls_shift = atoi(v->value);
19669
19670 if (sls_shift < 0 || sls_shift > 7) {
19671 ast_log(LOG_ERROR, "Invalid sls_shift value. Must be between 0 and 7\n");
19672 return -1;
19673 }
19674
19675 link = ss7_resolve_linkset(cur_linkset);
19676 if (!link) {
19677 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19678 return -1;
19679 }
19680 if (!link->ss7.ss7) {
19681 ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
19682 } else {
19683 ss7_set_sls_shift(link->ss7.ss7, sls_shift);
19684 }
19685 } else if (!strcasecmp(v->name, "cause_location")) {
19686 struct dahdi_ss7 *link;
19687 int cause_location = atoi(v->value);
19688
19689 if (cause_location < 0 || cause_location > 15) {
19690 ast_log(LOG_ERROR, "Invalid cause_location value. Must be between 0 and 15\n");
19691 return -1;
19692 }
19693 link = ss7_resolve_linkset(cur_linkset);
19694 if (!link) {
19695 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19696 return -1;
19697 }
19698 if (!link->ss7.ss7) {
19699 ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
19700 } else {
19701 ss7_set_cause_location(link->ss7.ss7, cause_location);
19702 }
19703#endif /* defined(HAVE_SS7) */
19704#ifdef HAVE_OPENR2
19705 } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
19706 ast_copy_string(confp->mfcr2.r2proto_file, v->value, sizeof(confp->mfcr2.r2proto_file));
19707 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);
19708 } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
19709 ast_copy_string(confp->mfcr2.logdir, v->value, sizeof(confp->mfcr2.logdir));
19710 } else if (!strcasecmp(v->name, "mfcr2_variant")) {
19711 confp->mfcr2.variant = openr2_proto_get_variant(v->value);
19712 if (OR2_VAR_UNKNOWN == confp->mfcr2.variant) {
19713 ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v->value, v->lineno);
19714 confp->mfcr2.variant = OR2_VAR_ITU;
19715 }
19716 } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
19717 confp->mfcr2.mfback_timeout = atoi(v->value);
19718 if (!confp->mfcr2.mfback_timeout) {
19719 ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19720 confp->mfcr2.mfback_timeout = -1;
19721 } else if (confp->mfcr2.mfback_timeout > 0 && confp->mfcr2.mfback_timeout < 500) {
19722 ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19723 }
19724 } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
19725 confp->mfcr2.metering_pulse_timeout = atoi(v->value);
19726 if (confp->mfcr2.metering_pulse_timeout > 500) {
19727 ast_log(LOG_WARNING, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19728 }
19729#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19730 } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
19731 confp->mfcr2.dtmf_detection = ast_true(v->value) ? 1 : 0;
19732 } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
19733 confp->mfcr2.dtmf_dialing = ast_true(v->value) ? 1 : 0;
19734 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
19735 confp->mfcr2.dtmf_time_on = atoi(v->value);
19736 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
19737 confp->mfcr2.dtmf_time_off = atoi(v->value);
19738#endif
19739#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19740 } else if (!strcasecmp(v->name, "mfcr2_dtmf_end_timeout")) {
19741 confp->mfcr2.dtmf_end_timeout = atoi(v->value);
19742#endif
19743 } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
19744 confp->mfcr2.get_ani_first = ast_true(v->value) ? 1 : 0;
19745 } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
19746 confp->mfcr2.double_answer = ast_true(v->value) ? 1 : 0;
19747 } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
19748 confp->mfcr2.charge_calls = ast_true(v->value) ? 1 : 0;
19749 } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
19750 confp->mfcr2.accept_on_offer = ast_true(v->value) ? 1 : 0;
19751 } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
19752 confp->mfcr2.allow_collect_calls = ast_true(v->value) ? 1 : 0;
19753 } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
19754 confp->mfcr2.forced_release = ast_true(v->value) ? 1 : 0;
19755 } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
19756 confp->mfcr2.immediate_accept = ast_true(v->value) ? 1 : 0;
19757#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19758 } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
19759 confp->mfcr2.skip_category_request = ast_true(v->value) ? 1 : 0;
19760#endif
19761 } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
19762 confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
19763 } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
19764 confp->mfcr2.max_ani = atoi(v->value);
19765 if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
19766 confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
19767 }
19768 } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
19769 confp->mfcr2.max_dnis = atoi(v->value);
19770 if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
19771 confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
19772 }
19773 } else if (!strcasecmp(v->name, "mfcr2_category")) {
19774 confp->mfcr2.category = openr2_proto_get_category(v->value);
19775 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == confp->mfcr2.category) {
19776 confp->mfcr2.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
19777 ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19778 v->value, v->lineno);
19779 }
19780 } else if (!strcasecmp(v->name, "mfcr2_logging")) {
19781 openr2_log_level_t tmplevel;
19782 char *clevel;
19783 char *logval;
19784 char copy[strlen(v->value) + 1];
19785 strcpy(copy, v->value); /* safe */
19786 logval = copy;
19787 while (logval) {
19788 clevel = strsep(&logval,",");
19789 if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
19790 ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", clevel, v->lineno);
19791 continue;
19792 }
19793 confp->mfcr2.loglevel |= tmplevel;
19794 }
19795#endif /* HAVE_OPENR2 */
19796 } else if (!strcasecmp(v->name, "cadence")) {
19797 /* setup to scan our argument */
19798 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
19799 int i;
19800 struct dahdi_ring_cadence new_cadence;
19801 int cid_location = -1;
19802 int firstcadencepos = 0;
19803 char original_args[80];
19804 int cadence_is_ok = 1;
19805
19806 ast_copy_string(original_args, v->value, sizeof(original_args));
19807 /* 16 cadences allowed (8 pairs) */
19808 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]);
19809
19810 /* Cadence must be even (on/off) */
19811 if (element_count % 2 == 1) {
19812 ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
19813 cadence_is_ok = 0;
19814 }
19815
19816 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
19817 if (element_count > ARRAY_LEN(c)) {
19818 element_count = ARRAY_LEN(c);
19819 }
19820
19821 /* Ring cadences cannot be negative */
19822 for (i = 0; i < element_count; i++) {
19823 if (c[i] == 0) {
19824 ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
19825 cadence_is_ok = 0;
19826 break;
19827 } else if (c[i] < 0) {
19828 if (i % 2 == 1) {
19829 /* Silence duration, negative possibly okay */
19830 if (cid_location == -1) {
19831 cid_location = i;
19832 c[i] *= -1;
19833 } else {
19834 ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
19835 cadence_is_ok = 0;
19836 break;
19837 }
19838 } else {
19839 if (firstcadencepos == 0) {
19840 firstcadencepos = i; /* only recorded to avoid duplicate specification */
19841 /* duration will be passed negative to the DAHDI driver */
19842 } else {
19843 ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
19844 cadence_is_ok = 0;
19845 break;
19846 }
19847 }
19848 }
19849 }
19850
19851 /* Substitute our scanned cadence */
19852 for (i = 0; i < 16; i++) {
19853 new_cadence.ringcadence[i] = c[i];
19854 }
19855
19856 if (cadence_is_ok) {
19857 /* ---we scanned it without getting annoyed; now some sanity checks--- */
19858 if (element_count < 2) {
19859 ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
19860 } else {
19861 if (cid_location == -1) {
19862 /* user didn't say; default to first pause */
19863 cid_location = 1;
19864 } else {
19865 /* convert element_index to cidrings value */
19866 cid_location = (cid_location + 1) / 2;
19867 }
19868 /* ---we like their cadence; try to install it--- */
19870 /* this is the first user-defined cadence; clear the default user cadences */
19871 num_cadence = 0;
19872 if ((num_cadence+1) >= NUM_CADENCE_MAX)
19873 ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
19874 else {
19875 cadences[num_cadence] = new_cadence;
19876 cidrings[num_cadence++] = cid_location;
19877 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
19878 }
19879 }
19880 }
19881 } else if (!strcasecmp(v->name, "ringtimeout")) {
19882 ringt_base = (atoi(v->value) * 8) / READ_SIZE;
19883 } else if (!strcasecmp(v->name, "prewink")) {
19884 confp->timing.prewinktime = atoi(v->value);
19885 } else if (!strcasecmp(v->name, "preflash")) {
19886 confp->timing.preflashtime = atoi(v->value);
19887 } else if (!strcasecmp(v->name, "wink")) {
19888 confp->timing.winktime = atoi(v->value);
19889 } else if (!strcasecmp(v->name, "flash")) {
19890 confp->timing.flashtime = atoi(v->value);
19891 } else if (!strcasecmp(v->name, "start")) {
19892 confp->timing.starttime = atoi(v->value);
19893 } else if (!strcasecmp(v->name, "rxwink")) {
19894 confp->timing.rxwinktime = atoi(v->value);
19895 } else if (!strcasecmp(v->name, "rxflash")) {
19896 confp->timing.rxflashtime = atoi(v->value);
19897 } else if (!strcasecmp(v->name, "debounce")) {
19898 confp->timing.debouncetime = atoi(v->value);
19899 } else if (!strcasecmp(v->name, "toneduration")) {
19900 int toneduration;
19901 int ctlfd;
19902 int res;
19903 struct dahdi_dialparams dps;
19904
19905 ctlfd = open("/dev/dahdi/ctl", O_RDWR);
19906 if (ctlfd == -1) {
19907 ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
19908 return -1;
19909 }
19910
19911 toneduration = atoi(v->value);
19912 if (toneduration > -1) {
19913 memset(&dps, 0, sizeof(dps));
19914
19915 dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
19916 res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
19917 if (res < 0) {
19918 ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
19919 close(ctlfd);
19920 return -1;
19921 }
19922 }
19923 close(ctlfd);
19924 } else if (!strcasecmp(v->name, "defaultcic")) {
19926 } else if (!strcasecmp(v->name, "defaultozz")) {
19928 } else if (!strcasecmp(v->name, "mwilevel")) {
19929 mwilevel = atoi(v->value);
19930 } else if (!strcasecmp(v->name, "dtmfcidlevel")) {
19931 dtmfcid_level = atoi(v->value);
19932 } else if (!strcasecmp(v->name, "reportalarms")) {
19933 if (!strcasecmp(v->value, "all"))
19935 if (!strcasecmp(v->value, "none"))
19936 report_alarms = 0;
19937 else if (!strcasecmp(v->value, "channels"))
19939 else if (!strcasecmp(v->value, "spans"))
19941 }
19942 } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
19943 ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
19944 }
19945
19946 if (dahdichan) {
19947 /* Process the deferred dahdichan value. */
19948 if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
19949 if (confp->ignore_failed_channels) {
19951 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
19952 dahdichan->value);
19953 } else {
19954 return -1;
19955 }
19956 }
19957 }
19958
19959 /*
19960 * Since confp has already filled individual dahdi_pvt objects with channels
19961 * at this point, clear the variables in confp's pvt.
19962 */
19963 if (confp->chan.vars) {
19965 confp->chan.vars = NULL;
19966 }
19967
19968 /* mark the first channels of each DAHDI span to watch for their span alarms */
19969 for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
19970 if (!tmp->destroy && tmp->span != y) {
19971 tmp->manages_span_alarms = 1;
19972 y = tmp->span;
19973 } else {
19974 tmp->manages_span_alarms = 0;
19975 }
19976 }
19977
19978 /*< \todo why check for the pseudo in the per-channel section.
19979 * Any actual use for manual setup of the pseudo channel? */
19980 if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
19981 /* use the default configuration for a channel, so
19982 that any settings from real configured channels
19983 don't "leak" into the pseudo channel config
19984 */
19986
19987 if (conf.chan.cc_params) {
19988 tmp = mkintf(CHAN_PSEUDO, &conf, reload);
19989 } else {
19990 tmp = NULL;
19991 }
19992 if (tmp) {
19993 ast_verb(3, "Automatically generated pseudo channel\n");
19994 has_pseudo = 1;
19995 } else {
19996 ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
19997 }
19998 ast_cc_config_params_destroy(conf.chan.cc_params);
19999 }
20000
20001 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
20004
20005 return 0;
20006}
20007
20008/*!
20009 * \internal
20010 * \brief Deep copy struct dahdi_chan_conf.
20011 * \since 1.8
20012 *
20013 * \param dest Destination.
20014 * \param src Source.
20015 */
20016static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
20017{
20018 struct ast_cc_config_params *cc_params;
20019
20020 cc_params = dest->chan.cc_params;
20021 *dest = *src;
20022 dest->chan.cc_params = cc_params;
20024}
20025
20026/*!
20027 * \internal
20028 * \brief Setup DAHDI channel driver.
20029 *
20030 * \param reload enum: load_module(0), reload(1), restart(2).
20031 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
20032 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
20033 * \param conf Local config parameters. So cc_params can be properly destroyed.
20034 *
20035 * \retval 0 on success.
20036 * \retval -1 on error.
20037 */
20038static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
20039{
20040 struct ast_config *cfg;
20041 struct ast_config *ucfg;
20042 struct ast_variable *v;
20043 struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
20044 const char *chans;
20045 const char *cat;
20046 int res;
20047
20048#ifdef HAVE_PRI
20049 char *c;
20050 int spanno;
20051 int i;
20052 int logicalspan;
20053 int trunkgroup;
20054 int dchannels[SIG_PRI_NUM_DCHANS];
20055#endif
20056 int have_cfg_now;
20057 static int had_cfg_before = 1;/* So initial load will complain if we don't have cfg. */
20058
20059 cfg = ast_config_load(config, config_flags);
20060 have_cfg_now = !!cfg;
20061 if (!cfg) {
20062 /* Error if we have no config file */
20063 if (had_cfg_before) {
20064 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
20066 }
20067 cfg = ast_config_new();/* Dummy config */
20068 if (!cfg) {
20069 return 0;
20070 }
20071 ucfg = ast_config_load("users.conf", config_flags);
20072 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
20073 ast_config_destroy(cfg);
20074 return 0;
20075 }
20076 if (ucfg == CONFIG_STATUS_FILEINVALID) {
20077 ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n");
20078 ast_config_destroy(cfg);
20079 return 0;
20080 }
20081 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
20082 ucfg = ast_config_load("users.conf", config_flags);
20083 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
20084 return 0;
20085 }
20086 if (ucfg == CONFIG_STATUS_FILEINVALID) {
20087 ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n");
20088 return 0;
20089 }
20091 cfg = ast_config_load(config, config_flags);
20092 have_cfg_now = !!cfg;
20093 if (!cfg) {
20094 if (had_cfg_before) {
20095 /* We should have been able to load the config. */
20096 ast_log(LOG_ERROR, "Bad. Unable to load config %s\n", config);
20097 ast_config_destroy(ucfg);
20098 return 0;
20099 }
20100 cfg = ast_config_new();/* Dummy config */
20101 if (!cfg) {
20102 ast_config_destroy(ucfg);
20103 return 0;
20104 }
20105 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20106 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20107 ast_config_destroy(ucfg);
20108 return 0;
20109 }
20110 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20111 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20112 return 0;
20113 } else {
20115 ucfg = ast_config_load("users.conf", config_flags);
20116 if (ucfg == CONFIG_STATUS_FILEINVALID) {
20117 ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n");
20118 ast_config_destroy(cfg);
20119 return 0;
20120 }
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 if (ucfg) {
20199 ast_config_destroy(ucfg);
20200 }
20201 return res;
20202 }
20203
20204 /* Now get configuration from all normal sections in chan_dahdi.conf: */
20205 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
20206 /* [channels] and [trunkgroups] are used. Let's also reserve
20207 * [globals] and [general] for future use
20208 */
20209 if (!strcasecmp(cat, "general") ||
20210 !strcasecmp(cat, "trunkgroups") ||
20211 !strcasecmp(cat, "globals") ||
20212 !strcasecmp(cat, "channels")) {
20213 continue;
20214 }
20215
20216 chans = ast_variable_retrieve(cfg, cat, "dahdichan");
20217 if (ast_strlen_zero(chans)) {
20218 /* Section is useless without a dahdichan value present. */
20219 continue;
20220 }
20221
20222 /* Copy base_conf to conf. */
20223 deep_copy_dahdi_chan_conf(conf, base_conf);
20224
20225 if ((res = process_dahdi(conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
20227 ast_config_destroy(cfg);
20228 if (ucfg) {
20229 ast_config_destroy(ucfg);
20230 }
20231 return res;
20232 }
20233 }
20234
20235 ast_config_destroy(cfg);
20236
20237 if (ucfg) {
20238 /* Reset base_conf, so things don't leak from chan_dahdi.conf */
20239 deep_copy_dahdi_chan_conf(base_conf, default_conf);
20240 process_dahdi(base_conf,
20241 "" /* Must be empty for the general category. Silly voicemail mailbox. */,
20242 ast_variable_browse(ucfg, "general"), 1, 0);
20243
20244 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
20245 if (!strcasecmp(cat, "general")) {
20246 continue;
20247 }
20248
20249 chans = ast_variable_retrieve(ucfg, cat, "dahdichan");
20250 if (ast_strlen_zero(chans)) {
20251 /* Section is useless without a dahdichan value present. */
20252 continue;
20253 }
20254
20255 /* Copy base_conf to conf. */
20256 deep_copy_dahdi_chan_conf(conf, base_conf);
20257
20259 ast_config_destroy(ucfg);
20261 return res;
20262 }
20263 }
20264 ast_config_destroy(ucfg);
20265 }
20267
20268#ifdef HAVE_PRI
20269 if (reload != 1) {
20270 int x;
20271 for (x = 0; x < NUM_SPANS; x++) {
20272 if (pris[x].pri.pvts[0] &&
20273 pris[x].pri.master == AST_PTHREADT_NULL) {
20274 prepare_pri(pris + x);
20275 if (sig_pri_start_pri(&pris[x].pri)) {
20276 ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
20277 return -1;
20278 } else
20279 ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
20280 }
20281 }
20282 }
20283#endif
20284#if defined(HAVE_SS7)
20285 if (reload != 1) {
20286 int x;
20287 for (x = 0; x < NUM_SPANS; x++) {
20288 if (linksets[x].ss7.ss7) {
20289 if (ast_pthread_create(&linksets[x].ss7.master, NULL, ss7_linkset, &linksets[x].ss7)) {
20290 ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
20291 return -1;
20292 } else
20293 ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
20294 }
20295 }
20296 }
20297#endif /* defined(HAVE_SS7) */
20298#ifdef HAVE_OPENR2
20299 if (reload != 1) {
20300 struct r2link_entry *cur;
20301 int x = 0;
20302 AST_LIST_LOCK(&r2links);
20303 AST_LIST_TRAVERSE(&r2links, cur, list) {
20304 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
20305 if (r2->r2master == AST_PTHREADT_NULL) {
20306 if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
20307 ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
20308 return -1;
20309 } else {
20310 ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
20311 }
20312 x++;
20313 }
20314 }
20315 AST_LIST_UNLOCK(&r2links);
20316 }
20317#endif
20318 /* And start the monitor for the first time */
20320 return 0;
20321}
20322
20323/*!
20324 * \internal
20325 * \brief Setup DAHDI channel driver.
20326 *
20327 * \param reload enum: load_module(0), reload(1), restart(2).
20328 *
20329 * \retval 0 on success.
20330 * \retval -1 on error.
20331 */
20332static int setup_dahdi(int reload)
20333{
20334 int res;
20335 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
20336 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
20338
20339 if (default_conf.chan.cc_params && base_conf.chan.cc_params && conf.chan.cc_params) {
20340 res = setup_dahdi_int(reload, &default_conf, &base_conf, &conf);
20341 } else {
20342 res = -1;
20343 }
20346 ast_cc_config_params_destroy(conf.chan.cc_params);
20347
20348 return res;
20349}
20350
20351/*!
20352 * \brief Load the module
20353 *
20354 * Module loading including tests for configuration or dependencies.
20355 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20356 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20357 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20358 * configuration file or other non-critical problem return
20359 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20360 */
20361static int load_module(void)
20362{
20363 int res;
20364#if defined(HAVE_PRI) || defined(HAVE_SS7)
20365 int y;
20366#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20367
20368 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
20370 }
20371
20374 }
20378
20382 }
20383
20384#ifdef HAVE_PRI
20385 memset(pris, 0, sizeof(pris));
20386 for (y = 0; y < NUM_SPANS; y++) {
20387 sig_pri_init_pri(&pris[y].pri);
20388 }
20389 pri_set_error(dahdi_pri_error);
20390 pri_set_message(dahdi_pri_message);
20391 ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec);
20392#ifdef HAVE_PRI_PROG_W_CAUSE
20393 ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
20394#endif
20395#if defined(HAVE_PRI_CCSS)
20396 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks)
20397 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) {
20400 }
20401#endif /* defined(HAVE_PRI_CCSS) */
20402 if (sig_pri_load(
20403#if defined(HAVE_PRI_CCSS)
20404 dahdi_pri_cc_type
20405#else
20406 NULL
20407#endif /* defined(HAVE_PRI_CCSS) */
20408 )) {
20411 }
20412#endif
20413#if defined(HAVE_SS7)
20414 memset(linksets, 0, sizeof(linksets));
20415 for (y = 0; y < NUM_SPANS; y++) {
20416 sig_ss7_init_linkset(&linksets[y].ss7);
20417 }
20418 ss7_set_error(dahdi_ss7_error);
20419 ss7_set_message(dahdi_ss7_message);
20420 ss7_set_hangup(sig_ss7_cb_hangup);
20421 ss7_set_notinservice(sig_ss7_cb_notinservice);
20422 ss7_set_call_null(sig_ss7_cb_call_null);
20423#endif /* defined(HAVE_SS7) */
20424 res = setup_dahdi(0);
20425 /* Make sure we can register our DAHDI channel type */
20426 if (res) {
20429 }
20431 ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
20434 }
20435#ifdef HAVE_PRI
20436 ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
20437#endif
20438#if defined(HAVE_SS7)
20439 ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
20440#endif /* defined(HAVE_SS7) */
20441#ifdef HAVE_OPENR2
20442 ast_cli_register_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
20443 ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
20444#endif
20445
20447
20449 memset(round_robin, 0, sizeof(round_robin));
20450 ast_manager_register_xml("DAHDITransfer", 0, action_transfer);
20452 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook);
20455 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
20456 ast_manager_register_xml("DAHDIShowStatus", 0, action_dahdishowstatus);
20458#if defined(HAVE_PRI)
20459 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
20460 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
20461 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM, action_pri_debug_file_set);
20462 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset);
20463#endif /* defined(HAVE_PRI) */
20464
20466
20467 return res;
20468}
20469
20470static int dahdi_sendtext(struct ast_channel *c, const char *text)
20471{
20472#define END_SILENCE_LEN 400
20473#define HEADER_MS 50
20474#define TRAILER_MS 5
20475#define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20476#define ASCII_BYTES_PER_CHAR 80
20477
20478 unsigned char *buf,*mybuf;
20479 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
20480 struct pollfd fds[1];
20481 int size,res,fd,len,x;
20482 int bytes=0;
20483 int idx;
20484
20485 /*
20486 * Initial carrier (imaginary)
20487 *
20488 * Note: The following float variables are used by the
20489 * PUT_CLID_MARKMS and PUT_CLID() macros.
20490 */
20491 float cr = 1.0;
20492 float ci = 0.0;
20493 float scont = 0.0;
20494
20495 if (!text[0]) {
20496 return(0); /* if nothing to send, don't */
20497 }
20498 idx = dahdi_get_index(c, p, 0);
20499 if (idx < 0) {
20500 ast_log(LOG_WARNING, "Huh? I don't exist?\n");
20501 return -1;
20502 }
20503 if ((!p->tdd) && (!p->mate)) {
20504#if defined(HAVE_PRI)
20505#if defined(HAVE_PRI_DISPLAY_TEXT)
20506 ast_mutex_lock(&p->lock);
20508 sig_pri_sendtext(p->sig_pvt, text);
20509 }
20511#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20512#endif /* defined(HAVE_PRI) */
20513 return(0); /* if not in TDD mode, just return */
20514 }
20515 if (p->mate)
20517 else
20518 buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
20519 if (!buf)
20520 return -1;
20521 mybuf = buf;
20522 if (p->mate) {
20523 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20524 struct ast_format *codec = AST_LAW(p);
20525
20526 for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
20528 }
20529 /* Put actual message */
20530 for (x = 0; text[x]; x++) {
20531 PUT_CLID(text[x]);
20532 }
20533 for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
20535 }
20536 len = bytes;
20537 buf = mybuf;
20538 } else {
20539 len = tdd_generate(p->tdd, buf, text);
20540 if (len < 1) {
20541 ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
20542 ast_free(mybuf);
20543 return -1;
20544 }
20545 }
20546 memset(buf + len, 0x7f, END_SILENCE_LEN);
20548 fd = p->subs[idx].dfd;
20549 while (len) {
20550 if (ast_check_hangup(c)) {
20551 ast_free(mybuf);
20552 return -1;
20553 }
20554 size = len;
20555 if (size > READ_SIZE)
20556 size = READ_SIZE;
20557 fds[0].fd = fd;
20558 fds[0].events = POLLOUT | POLLPRI;
20559 fds[0].revents = 0;
20560 res = poll(fds, 1, -1);
20561 if (!res) {
20562 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
20563 continue;
20564 }
20565 /* if got exception */
20566 if (fds[0].revents & POLLPRI) {
20567 ast_free(mybuf);
20568 return -1;
20569 }
20570 if (!(fds[0].revents & POLLOUT)) {
20571 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
20572 continue;
20573 }
20574 res = write(fd, buf, size);
20575 if (res != size) {
20576 if (res == -1) {
20577 ast_free(mybuf);
20578 return -1;
20579 }
20580 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
20581 break;
20582 }
20583 len -= size;
20584 buf += size;
20585 }
20586 ast_free(mybuf);
20587 return(0);
20588}
20589
20590
20591static int reload(void)
20592{
20593 int res = 0;
20594
20595 res = setup_dahdi(1);
20596 if (res) {
20597 ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
20598 return -1;
20599 }
20600 return 0;
20601}
20602
20603/* This is a workaround so that menuselect displays a proper description
20604 * AST_MODULE_INFO(, , "DAHDI Telephony"
20605 */
20606
20608 .support_level = AST_MODULE_SUPPORT_CORE,
20609 .load = load_module,
20610 .unload = unload_module,
20611 .reload = reload,
20612 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
20613 .requires = "ccss",
20614 .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:1809
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:4746
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:751
static int dahdi_create_channel_range(int start, int end)
Definition: chan_dahdi.c:11600
static int dahdi_confmute(struct dahdi_pvt *p, int muted)
Definition: chan_dahdi.c:5269
static ast_mutex_t ss_thread_lock
Definition: chan_dahdi.c:833
static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
Definition: chan_dahdi.c:11162
#define CALLWAITING_SUPPRESS_SAMPLES
Definition: chan_dahdi.c:871
static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
Definition: chan_dahdi.c:4825
static void release_doomed_pris(void)
Definition: chan_dahdi.c:1353
static struct dahdi_pvt * round_robin[64]
Definition: chan_dahdi.c:3760
#define HANGUP
Definition: chan_dahdi.c:16817
static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
Definition: chan_dahdi.c:2304
static int restore_gains(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5239
static void publish_channel_alarm_clear(int channel)
Definition: chan_dahdi.c:3835
static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index)
Definition: chan_dahdi.c:4836
static char * dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16069
static void my_set_confirmanswer(void *pvt, int flag)
Definition: chan_dahdi.c:2260
#define CIDCW_EXPIRE_SAMPLES
Definition: chan_dahdi.c:872
static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
Definition: chan_dahdi.c:9319
static int my_callwait(void *pvt)
Definition: chan_dahdi.c:1734
static int restore_conference(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5332
static void publish_span_alarm_clear(int span)
Definition: chan_dahdi.c:3853
static ast_mutex_t iflock
Protect the interface list (of dahdi_pvt's)
Definition: chan_dahdi.c:816
static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Definition: chan_dahdi.c:9422
static void notify_message(char *mailbox, int thereornot)
Send MWI state change.
Definition: chan_dahdi.c:3623
static struct dahdi_pvt * mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
Definition: chan_dahdi.c:12571
static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel)
Definition: chan_dahdi.c:4787
static int unalloc_sub(struct dahdi_pvt *p, int x)
Definition: chan_dahdi.c:4534
static int my_check_confirmanswer(void *pvt)
Definition: chan_dahdi.c:2266
static const char *const events[]
Definition: chan_dahdi.c:4667
static int reset_conf(struct dahdi_pvt *p)
Definition: chan_dahdi.c:4899
static int my_is_dialing(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:3028
static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
Definition: chan_dahdi.c:2999
static struct ast_manager_event_blob * dahdichannel_to_ami(struct stasis_message *msg)
Definition: chan_dahdi.c:1980
static void my_cancel_cidspill(void *pvt)
Definition: chan_dahdi.c:2283
static int numbufs
Definition: chan_dahdi.c:801
static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
Definition: chan_dahdi.c:4855
static int my_set_echocanceller(void *pvt, int enable)
Definition: chan_dahdi.c:2823
static int dahdi_wink(struct dahdi_pvt *p, int index)
Definition: chan_dahdi.c:9869
static char mwimonitornotify[PATH_MAX]
Definition: chan_dahdi.c:791
static char * alarm2str(int alm)
Definition: chan_dahdi.c:4702
static void my_hangup_polarityswitch(void *pvt)
Definition: chan_dahdi.c:2896
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:13519
static int dahdi_ring_phone(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7534
static char * dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16428
#define CALLWAITING_REPEAT_SAMPLES
Definition: chan_dahdi.c:870
static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
Definition: chan_dahdi.c:3794
#define DEFAULT_RINGT
Definition: chan_dahdi.c:874
#define CALLPROGRESS_FAX_OUTGOING
Definition: chan_dahdi.c:750
static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
Definition: chan_dahdi.c:5463
static int my_stop_cid_detect(void *pvt)
Definition: chan_dahdi.c:1483
static int my_get_sub_fd(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:2120
static void my_set_needringing(void *pvt, int value)
Definition: chan_dahdi.c:2859
static char * dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:15800
static struct ast_jb_conf default_jbconf
Definition: chan_dahdi.c:688
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:14226
static struct dahdi_pvt * find_channel_from_str(const char *channel)
Definition: chan_dahdi.c:16858
static int __unload_module(void)
Definition: chan_dahdi.c:18188
static void dahdi_softhangup_all(void)
Definition: chan_dahdi.c:15893
static void dahdi_train_ec(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5023
static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
Definition: chan_dahdi.c:18318
static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
Definition: chan_dahdi.c:9341
static enum analog_event dahdievent_to_analogevent(int event)
Definition: chan_dahdi.c:2676
static int dahdi_digit_begin(struct ast_channel *ast, char digit)
Definition: chan_dahdi.c:4567
static void my_unlock_private(void *pvt)
Definition: chan_dahdi.c:1967
#define HEADER_MS
#define TRANSFER
Definition: chan_dahdi.c:16816
static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_dahdi.c:7494
static void my_set_dialing(void *pvt, int is_dialing)
Definition: chan_dahdi.c:2153
static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
Definition: chan_dahdi.c:1887
static struct dahdi_pvt * fxo_pvt(struct ast_channel *chan)
Return DAHDI pivot if channel is FXO signalled.
Definition: chan_dahdi.c:2912
static int mwisend_rpas
Definition: chan_dahdi.c:793
static void publish_dnd_state(int channel, const char *status)
Definition: chan_dahdi.c:9887
static int my_on_hook(void *pvt)
Definition: chan_dahdi.c:3044
static int attempt_transfer(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7578
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:771
static void my_set_pulsedial(void *pvt, int flag)
Definition: chan_dahdi.c:2298
static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_dahdi.c:4629
static char * dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16518
static int dahdi_wait_event(int fd)
Avoid the silly dahdi_waitevent which ignores a bunch of events.
Definition: chan_dahdi.c:852
static void publish_channel_alarm(int channel, const char *alarm_txt)
Definition: chan_dahdi.c:7778
static int canmatch_featurecode(const char *pickupexten, const char *exten)
Definition: chan_dahdi.c:9935
static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
Definition: chan_dahdi.c:3819
static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
Definition: chan_dahdi.c:5220
struct analog_callback analog_callbacks
Definition: chan_dahdi.c:3686
static void dahdi_destroy_channel_range(int start, int end)
Definition: chan_dahdi.c:11518
static char * dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16150
static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
Definition: chan_dahdi.c:2641
static void my_set_alarm(void *pvt, int in_alarm)
Definition: chan_dahdi.c:2146
static int num_restart_pending
Definition: chan_dahdi.c:836
static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
Definition: chan_dahdi.c:1830
static int my_get_event(void *pvt)
Definition: chan_dahdi.c:2780
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13552
static int dahdi_devicestate(const char *data)
Definition: chan_dahdi.c:14164
static int user_has_defined_cadences
Definition: chan_dahdi.c:756
static int dahdi_callwait(struct ast_channel *ast)
Definition: chan_dahdi.c:5429
static void wakeup_sub(struct dahdi_pvt *p, int a)
Definition: chan_dahdi.c:3810
static void my_set_callwaiting(void *pvt, int callwaiting_enable)
Definition: chan_dahdi.c:2276
static int distinctiveringaftercid
Definition: chan_dahdi.c:799
static int my_is_off_hook(void *pvt)
Definition: chan_dahdi.c:2794
char * name
Definition: chan_dahdi.c:4691
#define END_SILENCE_LEN
static int mwi_send_init(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:11333
static int dahdi_open(char *fn)
Definition: chan_dahdi.c:4416
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:2011
static int my_check_waitingfordt(void *pvt)
Definition: chan_dahdi.c:2249
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:20038
static void publish_span_alarm(int span, const char *alarm_txt)
Definition: chan_dahdi.c:7764
static void my_set_outgoing(void *pvt, int is_outgoing)
Definition: chan_dahdi.c:2160
static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
Definition: chan_dahdi.c:16819
static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
Definition: chan_dahdi.c:2087
static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:5897
static int dahdi_hangup(struct ast_channel *ast)
Definition: chan_dahdi.c:6320
static void * analog_ss_thread(void *data)
Definition: chan_dahdi.c:9962
static int dahdi_sendtext(struct ast_channel *c, const char *text)
Definition: chan_dahdi.c:20470
static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
Definition: chan_dahdi.c:2038
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:2449
#define PROC_DAHDI_OPT_NOCHAN
Definition: chan_dahdi.c:18512
static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
Definition: chan_dahdi.c:18516
static int analogsub_to_dahdisub(enum analog_sub analogsub)
Definition: chan_dahdi.c:1323
static void my_get_and_handle_alarms(void *pvt)
Definition: chan_dahdi.c:2097
static void my_lock_private(void *pvt)
Definition: chan_dahdi.c:1961
static int dahdi_answer(struct ast_channel *ast)
Definition: chan_dahdi.c:6769
static const char tdesc[]
Definition: chan_dahdi.c:718
static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
Definition: chan_dahdi.c:5088
static int dahdi_restart(void)
Definition: chan_dahdi.c:15921
static int action_transfer(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16908
static int bump_gains(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5225
static void * do_monitor(void *data)
Definition: chan_dahdi.c:11932
static int save_conference(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5306
static char * dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16675
static void handle_clear_alarms(struct dahdi_pvt *p)
Definition: chan_dahdi.c:3866
static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
Definition: chan_dahdi.c:6864
static char * dahdi_sig2str(int sig)
Definition: chan_dahdi.c:4721
static int dahdi_set_hook(int fd, int hs)
Definition: chan_dahdi.c:5252
static int my_stop_callwait(void *pvt)
Definition: chan_dahdi.c:1720
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:9594
static int check_for_conference(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7611
static struct dahdi_ring_cadence AS_RP_cadence
Definition: chan_dahdi.c:779
static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
Definition: chan_dahdi.c:1596
#define NUM_SPANS
Definition: chan_dahdi.c:744
void dahdi_ec_enable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:4968
#define AST_LAW(p)
Definition: chan_dahdi.c:712
static int dahdi_setlinear(int dfd, int linear)
Definition: chan_dahdi.c:4491
static int restart_monitor(void)
Definition: chan_dahdi.c:12246
static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
Definition: chan_dahdi.c:3638
static int my_confmute(void *pvt, int mute)
Definition: chan_dahdi.c:2292
#define READ_SIZE
Definition: chan_dahdi.c:864
static void * mwi_thread(void *data)
Definition: chan_dahdi.c:11176
#define CALLPROGRESS_FAX
Definition: chan_dahdi.c:752
static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
Definition: chan_dahdi.c:1768
static int sigtype_to_signalling(int sigtype)
Definition: chan_dahdi.c:12552
static void my_decrease_ss_count(void)
Definition: chan_dahdi.c:2325
static char * handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16353
static int has_voicemail(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5363
static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:5670
void dahdi_conf_update(struct dahdi_pvt *p)
Definition: chan_dahdi.c:4913
static int alloc_sub(struct dahdi_pvt *p, int x)
Definition: chan_dahdi.c:4497
static void my_start_polarityswitch(void *pvt)
Definition: chan_dahdi.c:2876
static int digit_to_dtmfindex(char digit)
Definition: chan_dahdi.c:4551
static int setup_dahdi(int reload)
Definition: chan_dahdi.c:20332
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:16732
static int action_dahdidndon(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16870
static int report_alarms
Definition: chan_dahdi.c:808
#define GET_CHANNEL(p)
Definition: chan_dahdi.c:1250
static int mwilevel
Definition: chan_dahdi.c:803
static struct dahdi_pvt * iflist
Definition: chan_dahdi.c:992
#define NEED_MFDETECT(p)
Signaling types that need to use MF detection should be placed in this macro.
Definition: chan_dahdi.c:716
static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: chan_dahdi.c:6913
static int set_actual_txgain(int fd, float gain, float drc, int law)
Definition: chan_dahdi.c:5186
static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
Definition: chan_dahdi.c:7301
static int my_wait_event(void *pvt)
Definition: chan_dahdi.c:2773
static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
Definition: chan_dahdi.c:9850
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:2493
static int analog_tone_to_dahditone(enum analog_tone tone)
Definition: chan_dahdi.c:1303
static struct ast_str * create_channel_name(struct dahdi_pvt *i)
Definition: chan_dahdi.c:9549
static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
Definition: chan_dahdi.c:1499
#define TRAILER_MS
static int set_actual_rxgain(int fd, float gain, float drc, int law)
Definition: chan_dahdi.c:5203
static int my_start(void *pvt)
Definition: chan_dahdi.c:2991
static ast_mutex_t restart_lock
Definition: chan_dahdi.c:834
static struct ast_frame * dahdi_handle_event(struct ast_channel *ast)
Definition: chan_dahdi.c:7819
static char defaultcic[64]
Definition: chan_dahdi.c:787
int alarm
Definition: chan_dahdi.c:4690
static const char config[]
Definition: chan_dahdi.c:739
static int action_dahdishowchannels(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16986
void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:6847
static struct dahdi_pvt * find_next_iface_in_span(struct dahdi_pvt *cur)
Definition: chan_dahdi.c:5886
static ast_cond_t ss_thread_complete
Definition: chan_dahdi.c:832
static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
Definition: chan_dahdi.c:18379
static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
Definition: chan_dahdi.c:5622
static struct ast_frame * dahdi_exception(struct ast_channel *ast)
Definition: chan_dahdi.c:8843
static void my_answer_polarityswitch(void *pvt)
Definition: chan_dahdi.c:2885
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:13983
#define SMDI_MD_WAIT_TIMEOUT
Definition: chan_dahdi.c:673
static int my_have_progressdetect(void *pvt)
Definition: chan_dahdi.c:3660
static char * dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16597
static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Definition: chan_dahdi.c:7132
#define CANPROGRESSDETECT(p)
Definition: chan_dahdi.c:785
static char * dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:15844
static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
Definition: chan_dahdi.c:5138
static int my_train_echocanceller(void *pvt)
Definition: chan_dahdi.c:3019
static const char * event2str(int event)
Definition: chan_dahdi.c:4712
#define CALLPROGRESS_PROGRESS
Definition: chan_dahdi.c:749
static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
Definition: chan_dahdi.c:4469
static void my_set_polarity(void *pvt, int value)
Definition: chan_dahdi.c:2865
void dahdi_ec_disable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5040
static struct ast_frame * __dahdi_exception(struct ast_channel *ast)
Definition: chan_dahdi.c:8721
static void handle_alarms(struct dahdi_pvt *p, int alms)
Definition: chan_dahdi.c:7797
static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
Definition: chan_dahdi.c:7664
static struct dahdi_chan_conf dahdi_chan_conf_default(void)
Definition: chan_dahdi.c:1060
static struct dahdi_pvt * duplicate_pseudo(struct dahdi_pvt *src)
Definition: chan_dahdi.c:13758
static void swap_subs(struct dahdi_pvt *p, int a, int b)
Definition: chan_dahdi.c:4388
#define ISTRUNK(p)
Definition: chan_dahdi.c:781
static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
Definition: chan_dahdi.c:2075
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:9916
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:9603
static int drc_sample(int sample, float drc)
Definition: chan_dahdi.c:5068
static int dahdi_get_event(int fd)
Avoid the silly dahdi_getevent which ignores a bunch of events.
Definition: chan_dahdi.c:843
static int ringt_base
Configured ring timeout base.
Definition: chan_dahdi.c:881
void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
Definition: chan_dahdi.c:7414
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:827
#define ASCII_BYTES_PER_CHAR
static void my_all_subchannels_hungup(void *pvt)
Definition: chan_dahdi.c:2333
static int my_ring(void *pvt)
Definition: chan_dahdi.c:2837
static int my_start_cid_detect(void *pvt, int cid_signalling)
Definition: chan_dahdi.c:1466
static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
Definition: chan_dahdi.c:7272
static struct dahdi_pvt * ifend
Definition: chan_dahdi.c:993
static char * dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16485
static int my_complete_conference_update(void *pvt, int needconference)
Definition: chan_dahdi.c:2393
static struct @114 alarms[]
#define DEFAULT_DIALTONE_DETECT_TIMEOUT
Definition: chan_dahdi.c:875
static int mwi_send_process_buffer(struct dahdi_pvt *pvt, int num_read)
Definition: chan_dahdi.c:11386
#define HEADER_LEN
static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
Definition: chan_dahdi.c:2127
static void my_increase_ss_count(void)
Definition: chan_dahdi.c:2318
#define REPORT_CHANNEL_ALARMS
Definition: chan_dahdi.c:806
static int has_pseudo
Definition: chan_dahdi.c:758
static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
Definition: chan_dahdi.c:2666
static int my_wink(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:1871
static struct ast_channel_tech dahdi_tech
Definition: chan_dahdi.c:1227
static struct ast_jb_conf global_jbconf
Definition: chan_dahdi.c:696
static int my_conf_add(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:2383
static int my_dsp_reset_and_flush_digits(void *pvt)
Definition: chan_dahdi.c:1821
void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
Definition: chan_dahdi.c:6833
#define PROC_DAHDI_OPT_NOWARN
Definition: chan_dahdi.c:18514
#define MIN_MS_SINCE_FLASH
Definition: chan_dahdi.c:873
static int my_has_voicemail(void *pvt)
Definition: chan_dahdi.c:2659
static char progzone[10]
Definition: chan_dahdi.c:796
static int load_module(void)
Load the module.
Definition: chan_dahdi.c:20361
#define sig2str
Definition: chan_dahdi.c:4785
static struct ast_frame * dahdi_read(struct ast_channel *ast)
Definition: chan_dahdi.c:8858
#define FORMAT
static const char * my_get_orig_dialstring(void *pvt)
Definition: chan_dahdi.c:2311
static int action_dahdirestart(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16059
static struct ast_custom_function polarity_function
Definition: chan_dahdi.c:2985
static int get_alarms(struct dahdi_pvt *p)
Definition: chan_dahdi.c:7637
static struct dahdi_pvt * determine_starting_point(const char *data, struct dahdi_starting_point *param)
Definition: chan_dahdi.c:13822
#define gen_pvt_field_callback(type, field)
Definition: chan_dahdi.c:3673
static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
Definition: chan_dahdi.c:2944
static int send_cwcidspill(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5347
static int my_conf_del(void *pvt, enum analog_sub sub)
Definition: chan_dahdi.c:2373
#define FORMAT2
static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX]
Definition: chan_dahdi.c:760
static int action_dahdidndoff(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16889
static int unload_module(void)
Definition: chan_dahdi.c:18302
static int reload(void)
Definition: chan_dahdi.c:20591
static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
Definition: chan_dahdi.c:18551
static struct ast_cli_entry dahdi_cli[]
Definition: chan_dahdi.c:16801
#define POLARITY_IDLE
Definition: chan_dahdi.c:983
#define DEFAULT_CIDRINGS
Typically, how many rings before we should send Caller*ID.
Definition: chan_dahdi.c:710
static int num_cadence
Definition: chan_dahdi.c:755
static enum analog_sigtype dahdisig_to_analogsig(int sig)
Definition: chan_dahdi.c:1252
static void dahdi_close(int fd)
Definition: chan_dahdi.c:4463
static char defaultozz[64]
Definition: chan_dahdi.c:788
void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
Definition: chan_dahdi.c:7470
static int dtmfcid_level
Definition: chan_dahdi.c:804
#define CHAN_PSEUDO
Definition: chan_dahdi.c:747
static int my_off_hook(void *pvt)
Definition: chan_dahdi.c:2853
const char *const subnames[]
Definition: chan_dahdi.c:986
static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
Definition: chan_dahdi.c:2650
static int usedistinctiveringdetection
Definition: chan_dahdi.c:798
static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: chan_dahdi.c:2958
static char * dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16036
static struct dahdi_pvt * find_channel(int channel)
Definition: chan_dahdi.c:16835
static void * my_get_sigpvt_bridged_channel(struct ast_channel *chan)
Definition: chan_dahdi.c:2106
static int send_callerid(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5393
static int set_hwgain(int fd, float gain, int tx_direction)
Definition: chan_dahdi.c:5058
static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
Definition: chan_dahdi.c:2209
static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
Definition: chan_dahdi.c:16389
static int my_check_for_conference(void *pvt)
Definition: chan_dahdi.c:2443
static int mwi_send_process_event(struct dahdi_pvt *pvt, int event)
Definition: chan_dahdi.c:11474
static int my_flash(void *pvt)
Definition: chan_dahdi.c:2844
#define POLARITY_REV
Definition: chan_dahdi.c:984
static int ss_thread_count
Definition: chan_dahdi.c:835
static const char *const lbostr[]
Definition: chan_dahdi.c:675
int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
Definition: chan_dahdi.c:3762
#define REPORT_SPAN_ALARMS
Definition: chan_dahdi.c:807
static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
Definition: chan_dahdi.c:20016
static void my_deadlock_avoidance_private(void *pvt)
Definition: chan_dahdi.c:1973
static struct dahdi_pvt * handle_init_event(struct dahdi_pvt *i, int event)
Definition: chan_dahdi.c:11668
static void destroy_channel(struct dahdi_pvt *cur, int now)
Definition: chan_dahdi.c:5977
static void my_set_ringtimeout(void *pvt, int ringt)
Definition: chan_dahdi.c:2203
static void monitor_pfds_clean(void *arg)
Definition: chan_dahdi.c:11927
static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16954
static int ifcount
Definition: chan_dahdi.c:819
#define NUM_CADENCE_MAX
Definition: chan_dahdi.c:754
static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
Definition: chan_dahdi.c:1420
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:831
static int action_transferhangup(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16931
#define CANBUSYDETECT(p)
Definition: chan_dahdi.c:784
static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
Definition: chan_dahdi.c:6298
static void destroy_all_channels(void)
Definition: chan_dahdi.c:5995
static int action_dahdishowstatus(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:17074
DAHDI internal API definitions.
#define SIG_FEATB
Definition: chan_dahdi.h:783
#define SIG_FGC_CAMA
Definition: chan_dahdi.h:786
#define SIG_SFWINK
Definition: chan_dahdi.h:795
#define SIG_EMWINK
Definition: chan_dahdi.h:780
#define SIG_MFCR2
Definition: chan_dahdi.h:810
#define SIG_FXSLS
Definition: chan_dahdi.h:788
#define MAX_SLAVES
Definition: chan_dahdi.h:95
static int dahdi_sig_pri_lib_handles(int signaling)
Definition: chan_dahdi.h:827
#define SIG_SF_FEATB
Definition: chan_dahdi.h:798
#define SIG_FXSKS
Definition: chan_dahdi.h:790
#define SIG_FXOGS
Definition: chan_dahdi.h:792
#define SUB_REAL
Definition: chan_dahdi.h:57
#define SIG_SF_FEATDMF
Definition: chan_dahdi.h:797
static int dahdi_analog_lib_handles(int signalling, int radio, int oprmode)
Definition: chan_dahdi.h:843
#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:813
#define SIG_FXOKS
Definition: chan_dahdi.h:793
#define SIG_FGC_CAMAMF
Definition: chan_dahdi.h:787
#define SIG_FXSGS
Definition: chan_dahdi.h:789
#define SIG_FEATDMF
Definition: chan_dahdi.h:782
#define SIG_EM_E1
Definition: chan_dahdi.h:799
#define SIG_SF_FEATD
Definition: chan_dahdi.h:796
#define SIG_SS7
Definition: chan_dahdi.h:807
#define SIG_BRI
Definition: chan_dahdi.h:803
@ DAHDI_IFLIST_NONE
Definition: chan_dahdi.h:117
@ DAHDI_IFLIST_MAIN
Definition: chan_dahdi.h:118
#define SIG_FEATD
Definition: chan_dahdi.h:781
#define SIG_BRI_PTMP
Definition: chan_dahdi.h:804
#define SIG_FEATDMF_TA
Definition: chan_dahdi.h:785
@ 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:791
#define SIG_E911
Definition: chan_dahdi.h:784
#define SIG_PRI
Definition: chan_dahdi.h:802
#define SIG_EM
Definition: chan_dahdi.h:779
#define SIG_SF
Definition: chan_dahdi.h:794
#define dahdi_get_index(ast, p, nullok)
Definition: chan_dahdi.h:884
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:3203
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:2875
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:1618
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:1671
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
#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:10590
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1848
#define CHECK_BLOCKING(c)
Set the blocking indication on the channel.
Definition: channel.h:2919
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition: channel.h:2970
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:7759
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3190
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:10477
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:2995
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1158
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:2034
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
#define ast_channel_trylock(chan)
Definition: channel.h:2972
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:1265
@ 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:2026
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition: channel.c:1665
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:7355
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:1193
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:2042
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:7696
void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_channel_hangupcause(const struct ast_channel *chan)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Definition: channel.c:2528
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2500
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:4363
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1243
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition: channel.c:1218
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:3006
@ AST_FLAG_DISABLE_DEVSTATE_CACHE
Definition: channel.h:1049
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1027
@ AST_FLAG_BLOCKING
Definition: channel.h:1005
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1718
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition: channel.c:2874
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:10608
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:2455
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2487
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition: channel.c:4377
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:7753
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:7443
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:3017
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:7639
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:1601
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define AST_MAX_EXTENSION
Definition: channel.h:134
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
@ AST_SOFTHANGUP_DEV
Definition: channel.h:1141
@ AST_SOFTHANGUP_APPUNLOAD
Definition: channel.h:1163
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:7407
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:1783
int ast_dsp_get_tcount(struct ast_dsp *dsp)
Get tcount (Threshold counter)
Definition: dsp.c:1916
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:1810
#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:1804
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:1499
#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:1857
#define DSP_DIGITMODE_MUTECONF
Definition: dsp.h:35
int ast_dsp_get_tstate(struct ast_dsp *dsp)
Get tstate (Tone State)
Definition: dsp.c:1911
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:1906
#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:1793
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
#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:1758
#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:1892
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:2206
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:1301
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
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:2028
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition: manager.c:638
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:2064
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
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:829
#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:3326
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
@ CONFIG_FLAG_FILEUNCHANGED
#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:1289
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:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
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:2353
#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:2331
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:2476
#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:496
#define DLA_UNLOCK(lock)
Definition: lock.h:494
#define ast_cond_destroy(cond)
Definition: lock.h:206
#define ast_cond_wait(cond, mutex)
Definition: lock.h:209
#define AST_PTHREADT_NULL
Definition: lock.h:70
#define ast_cond_init(cond, attr)
Definition: lock.h:205
#define ast_mutex_init(pmutex)
Definition: lock.h:190
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition: lock.h:478
#define DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:483
#define AST_PTHREADT_STOP
Definition: lock.h:71
#define ast_mutex_unlock(a)
Definition: lock.h:194
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:761
#define ast_mutex_trylock(a)
Definition: lock.h:195
pthread_cond_t ast_cond_t
Definition: lock.h:182
#define ast_mutex_destroy(a)
Definition: lock.h:192
#define ast_mutex_lock(a)
Definition: lock.h:193
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:524
#define ast_cond_signal(cond)
Definition: lock.h:207
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:10237
#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:7787
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7797
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:159
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:4770
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:4190
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:1559
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:4205
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:4723
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:6894
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:4210
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:6984
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:1277
int analog_available(struct analog_pvt *p)
Definition: sig_analog.c:793
struct ast_frame * analog_exception(struct analog_pvt *p, struct ast_channel *ast)
Definition: sig_analog.c:3699
int analog_dnd(struct analog_pvt *p, int flag)
Definition: sig_analog.c:4191
int analog_config_complete(struct analog_pvt *p)
Definition: sig_analog.c:4135
void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
Definition: sig_analog.c:1593
int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest, int timeout)
Definition: sig_analog.c:990
void analog_delete(struct analog_pvt *doomed)
Delete the analog private structure.
Definition: sig_analog.c:4130
struct analog_pvt * analog_new(enum analog_sigtype signallingtype, void *private_data)
Definition: sig_analog.c:4102
int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
Definition: sig_analog.c:4153
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:770
void * analog_handle_init_event(struct analog_pvt *i, int event)
Definition: sig_analog.c:3819
int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
Definition: sig_analog.c:1490
int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
Definition: sig_analog.c:2778
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:2199
#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:2216
#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 canpark
Definition: sig_analog.h:295
unsigned int dahditrcallerid
Definition: sig_analog.h:296
int polarityonanswerdelay
Definition: sig_analog.h:325
char cid_num[AST_MAX_EXTENSION]
Definition: sig_analog.h:329
int redirecting_reason
Definition: sig_analog.h:358
unsigned int permhidecallerid
Definition: sig_analog.h:302
unsigned int callwaitingcallerid
Definition: sig_analog.h:310
unsigned int ani_wink_time
Definition: sig_analog.h:289
enum analog_sigtype outsigmod
Definition: sig_analog.h:321
unsigned int usedistinctiveringdetection
Definition: sig_analog.h:309
unsigned int answeronpolarityswitch
Definition: sig_analog.h:291
unsigned int threewaycalling
Definition: sig_analog.h:304
unsigned int pulse
Definition: sig_analog.h:303
int echotraining
Definition: sig_analog.h:323
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_cid_start cid_start
Definition: sig_analog.h:327
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:314
unsigned int call_qualifier
Definition: sig_analog.h:350
unsigned int ani_timeout
Definition: sig_analog.h:288
unsigned int lastnumredial
Definition: sig_analog.h:300
int ringt_base
Definition: sig_analog.h:378
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:322
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:324
unsigned int transfer
Definition: sig_analog.h:306
unsigned int transfertobusy
Definition: sig_analog.h:307
unsigned int inalarm
Definition: sig_analog.h:342
char cid_name[AST_MAX_EXTENSION]
Definition: sig_analog.h:330
int stripmsd
Definition: sig_analog.h:326
unsigned int calledsubscriberheld
Definition: sig_analog.h:292
char mohsuggest[MAX_MUSICCLASS]
Definition: sig_analog.h:328
unsigned int use_callerid
Definition: sig_analog.h:308
struct ast_channel * ss_astchan
Definition: sig_analog.h:374
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition: sig_analog.h:316
struct ast_party_caller caller
Definition: sig_analog.h:357
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.
char exten[AST_MAX_EXTENSION]
const char * data
char x
Definition: extconf.c:81
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
const ast_string_field name
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:199
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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
struct timeval delivery
enum ast_frame_type frametype
unsigned int flags
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
struct ast_party_dialed::@210 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
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:1022
char smdi_port[SMDI_MAX_FILENAME_LEN]
The serial port to listen for SMDI data on.
Definition: chan_dahdi.c:1044
int ignore_failed_channels
Definition: chan_dahdi.c:1038
struct dahdi_params timing
Definition: chan_dahdi.c:1035
int wanted_channels_end
Don't create channels above this number (infinity by default)
Definition: chan_dahdi.c:1056
struct dahdi_pvt chan
Definition: chan_dahdi.c:1023
int wanted_channels_start
Don't create channels below this number.
Definition: chan_dahdi.c:1050
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:715
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:373
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:487
struct ast_variable * vars
Channel variable list with associated values to set when a channel is created.
Definition: chan_dahdi.h:586
char cid_subaddr[AST_MAX_EXTENSION]
Caller ID subaddress from an incoming call.
Definition: chan_dahdi.h:539
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:558
int bufsize
Definition: chan_dahdi.h:138
unsigned int hwtxgain_enabled
TRUE if hardware Tx gain set by Asterisk.
Definition: chan_dahdi.h:471
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:698
struct timeval dtmfcid_delay
Definition: chan_dahdi.h:593
unsigned int dahditrcallerid
TRUE if we should use the callerid from incoming call on dahdi transfer.
Definition: chan_dahdi.h:408
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:599
struct tdd_state * tdd
Definition: chan_dahdi.h:704
int waitfordialtonetemp
Transient variable. Same as waitfordialtone, but temporarily set for a specific call,...
Definition: chan_dahdi.h:662
int cidlen
Length of the cidspill buffer containing samples.
Definition: chan_dahdi.h:603
int polarityonanswerdelay
Minimal time period (ms) between the answer polarity switch and hangup polarity switch.
Definition: chan_dahdi.h:729
int busycount
Number of times to see "busy" tone before hanging up.
Definition: chan_dahdi.h:643
char cid_num[AST_MAX_EXTENSION]
Caller ID number from an incoming call.
Definition: chan_dahdi.h:528
int ringt
Ring timeout timer??
Definition: chan_dahdi.h:605
struct ast_mwi_subscriber * mwi_event_sub
Opaque event subscription parameters for message waiting indication support.
Definition: chan_dahdi.h:713
ast_group_t group
Bitmapped groups this belongs to.
Definition: chan_dahdi.h:554
int sendcalleridafter
Send caller ID on FXS after this many rings. Set to 1 for US.
Definition: chan_dahdi.h:736
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:339
unsigned int mwisendactive
TRUE if a MWI message sending thread is active.
Definition: chan_dahdi.h:433
char * origcid_name
Definition: chan_dahdi.h:541
struct mwisend_info mwisend_data
Definition: chan_dahdi.h:482
int cid_suppress_expire
Definition: chan_dahdi.h:597
struct timeval flashtime
Definition: chan_dahdi.h:694
int oprmode
Definition: chan_dahdi.h:151
int interdigit_timeout
Time (ms) to detect following digits (in an analog phone)
Definition: chan_dahdi.h:687
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:429
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:357
unsigned int mwimonitoractive
TRUE if an MWI monitor thread is currently active.
Definition: chan_dahdi.h:431
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:677
int whichwink
Definition: chan_dahdi.h:699
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:540
unsigned int manages_span_alarms
TRUE if the channel alarms will be managed also as Span ones.
Definition: chan_dahdi.h:467
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:658
unsigned int locallyblocked
Bitmask for the channel being locally blocked.
Definition: chan_dahdi.h:453
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:403
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:368
struct dahdi_subchannel subs[3]
Definition: chan_dahdi.h:131
int distinctivering
Definition: chan_dahdi.h:721
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:397
int dtmfrelax
Definition: chan_dahdi.h:722
unsigned int pulse
TRUE if we will pulse dial.
Definition: chan_dahdi.h:354
int dialtone_scanning_time_elapsed
Definition: chan_dahdi.h:672
unsigned int priexclusive
TRUE if PRI B channels are always exclusively selected.
Definition: chan_dahdi.h:349
char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Voice mailbox location.
Definition: chan_dahdi.h:711
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:636
int tonezone
Definition: chan_dahdi.h:167
char callwait_num[AST_MAX_EXTENSION]
Call waiting number.
Definition: chan_dahdi.h:543
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:666
int dsp_features
DSP feature flags: DSP_FEATURE_xxx.
Definition: chan_dahdi.h:740
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:504
int callprogress
Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
Definition: chan_dahdi.h:653
int callwaitcas
TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
Definition: chan_dahdi.h:624
time_t guardtime
Definition: chan_dahdi.h:589
struct timeval polaritydelaytv
Start delay time if polarityonanswerdelay is nonzero.
Definition: chan_dahdi.h:731
unsigned int hanguponpolarityswitch
TRUE if the call will be considered "hung up" on a polarity reversal.
Definition: chan_dahdi.h:285
char dnid[AST_MAX_EXTENSION]
Dialed Number Identifier.
Definition: chan_dahdi.h:549
char dialstring[AST_CHANNEL_NAME]
Definition: chan_dahdi.h:774
char call_forward[AST_MAX_EXTENSION]
Accumulated call forwarding number.
Definition: chan_dahdi.h:706
char description[32]
A description for the channel configuration.
Definition: chan_dahdi.h:498
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:462
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:630
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:581
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:547
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:481
struct callerid_state * cs
Definition: chan_dahdi.h:126
int cid_ani2
Automatic Number Identification code from PRI.
Definition: chan_dahdi.h:526
struct ast_namedgroups * named_callgroups
Named call groups this belongs to.
Definition: chan_dahdi.h:576
int callwaitrings
Number of call waiting rings.
Definition: chan_dahdi.h:626
unsigned int mwimonitor_neon
TRUE if the FXO port monitors for neon type MWI indications from the other end.
Definition: chan_dahdi.h:418
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:469
int law_default
Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition: chan_dahdi.h:556
int fake_event
Holding place for event injected from outside normal operation.
Definition: chan_dahdi.h:724
unsigned int didtdd
Definition: chan_dahdi.h:251
char echorest[20]
Filled with 'w'. XXX Purpose??
Definition: chan_dahdi.h:638
struct dahdi_pvt * slaves[MAX_SLAVES]
Definition: chan_dahdi.h:134
void * sig_pvt
Definition: chan_dahdi.h:766
int confno
Definition: chan_dahdi.h:559
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:592
unsigned int lastnumredial
TRUE if last number redial enabled.
Definition: chan_dahdi.h:444
unsigned int mwioverride_active
TRUE if a manual MWI override is active for a channel.
Definition: chan_dahdi.h:435
unsigned int mwimonitor_fsk
TRUE if the FXO port monitors for fsk type MWI indications from the other end.
Definition: chan_dahdi.h:423
int ringt_base
Ring timeout base.
Definition: chan_dahdi.h:610
int cid_start
Definition: chan_dahdi.h:591
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:363
char defcontext[AST_MAX_CONTEXT]
Default distinctive ring context.
Definition: chan_dahdi.h:502
unsigned int priindication_oob
TRUE if PRI congestion/busy indications are sent out-of-band.
Definition: chan_dahdi.h:344
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:693
struct ast_dsp * dsp
Opaque DSP configuration structure.
Definition: chan_dahdi.h:696
struct dahdi_pvt * prev
Definition: chan_dahdi.h:170
ast_group_t pickupgroup
Bitmapped pickup groups this belongs to.
Definition: chan_dahdi.h:571
int callingpres
Definition: chan_dahdi.h:594
int dialmode
Definition: chan_dahdi.h:149
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:601
char context[AST_MAX_CONTEXT]
The configured context for incoming calls.
Definition: chan_dahdi.h:493
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:520
int cidcwexpire
Definition: chan_dahdi.h:596
unsigned int hardwaredtmf
TRUE if DTMF detection needs to be done by hardware.
Definition: chan_dahdi.h:295
int callwaitingrepeat
Definition: chan_dahdi.h:595
char begindigit
DTMF digit in progress. 0 when no digit in progress.
Definition: chan_dahdi.h:763
struct ast_cc_config_params * cc_params
Definition: chan_dahdi.h:767
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:682
int amaflags
Definition: chan_dahdi.h:703
struct dahdi_echocanparams head
Definition: chan_dahdi.h:629
unsigned int echocanbridged
TRUE if echo cancellation enabled when bridged.
Definition: chan_dahdi.h:270
int cid_signalling
Definition: chan_dahdi.h:590
char finaldial[64]
Second part of SIG_FEATDMF_TA wink operation.
Definition: chan_dahdi.h:701
unsigned int transfer
TRUE if call transfer is enabled.
Definition: chan_dahdi.h:382
unsigned int transfertobusy
TRUE if allowed to flash-transfer to busy channels.
Definition: chan_dahdi.h:413
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:537
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:442
char language[MAX_LANGUAGE]
Language configured for calls.
Definition: chan_dahdi.h:509
unsigned int digital
TRUE if the transfer capability of the call is digital.
Definition: chan_dahdi.h:260
int channel
Definition: chan_dahdi.h:587
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_dahdi.h:702
unsigned int mwioverride_disposition
Manual MWI disposition (on/off)
Definition: chan_dahdi.h:437
struct ast_dsp_busy_pattern busy_cadence
Busy cadence pattern description.
Definition: chan_dahdi.h:648
int stripmsd
Number of most significant digits/characters to strip from the dialed number.
Definition: chan_dahdi.h:617
unsigned int pulsedial
TRUE if a pulsed digit was detected. (Pulse dial phone detected)
Definition: chan_dahdi.h:356
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:765
char cid_tag[AST_MAX_EXTENSION]
Caller ID tag from incoming call.
Definition: chan_dahdi.h:533
int matchdigit_timeout
Time (ms) to wait, in case of ambiguous match (in an analog phone)
Definition: chan_dahdi.h:692
char mohsuggest[MAX_MUSICCLASS]
Suggested music-on-hold class for peer channel to use for calls.
Definition: chan_dahdi.h:519
unsigned int use_callerid
TRUE if caller ID is used on this channel.
Definition: chan_dahdi.h:390
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:738
ast_group_t callgroup
Bitmapped call groups this belongs to.
Definition: chan_dahdi.h:566
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:545
char mohinterpret[MAX_MUSICCLASS]
The configured music-on-hold class to use for calls.
Definition: chan_dahdi.h:514
int dialtone_detect
Number of frames to watch for dialtone in incoming calls.
Definition: chan_dahdi.h:671
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition: chan_dahdi.h:484
int propconfno
Definition: chan_dahdi.h:561
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:535
ast_group_t groupmatch
Definition: chan_dahdi.c:13806
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:327
struct dahdi_pvt * pvt
Definition: chan_dahdi.c:11157
unsigned char buf[READ_SIZE]
Definition: chan_dahdi.c:11158
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:2281
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:941
#define ast_assert(a)
Definition: utils.h:739
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:584
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
#define ast_clear_flag(p, flag)
Definition: utils.h:77
long int ast_random(void)
Definition: utils.c:2312
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:588
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666